Errors don't have to be boring

This is part 7 in the chronicles of building HR Partner, our latest web app.

A short one today.  I was designing the 404 and 500 error screens for our Ruby framework, and decided to go outside the box a little.

Usually, the 404 error page is a fairly boring affair, telling the user that they have tried to load an invalid page.  I thought to make it more interesting, I would incorporate an ever changing background for the error pages.

I am using a dynamic CSS background for the error pages, which links to to load up a random grayscale image as the background.

This way, every time that a user hits an error page, they will still get the large '404' or '500' error number, but overlaid on a different background each time.  I have no control over what image gets shown, but I find myself just hitting invalid pages every now and then during my development routine - just to see what pretty landscapes show up.

The body style tag looks something like the following:

<body class='black-bg' style='height: 100%; background:url( no-repeat fixed center center;'>
  ... rest of 404 error info

So as I said - error message certainly do not have to be boring!

How I rolled my own explainer video, in a weekend, for under $100

Being totally boot strapped, and non funded, I have to market my web app HR Partner, on the smell of an oily rag, plus do all the marketing and other promotional tasks to keep the costs down.

I’ve been told many times that I basically have to have an ‘explainer video’ to introduce people to my app, because it is the quickest and most effective way to get people interested and signing up.

Well, I hunted around and spoke to several companies that specialises in making these explainer videos. I gave them my specifications, and received back quotes ranging from $2000 up to $6000 to make a 60 to 120 second video.

I debated going to or, but in the end, decided against it because every time I began a conversation on those platforms, I always felt that the price wasn’t as concrete as the other firms I spoke to. It was always along the lines of “Well, we have a starting price of $x, but if you need this, then it will be $y extra, and if you wanted that, it will be $z more…” etc.

So I thought I would throw caution to the wind and look at doing the video myself, over the past weekend. I started on Saturday morning.

The first thing I did was to go to Envato, where I have an account, and search on their VideoHive sub site for an Explainer video template. I found one there for around $40 which I quite liked. Then, I went across to theirAudioJungle sub site to find a background ambient music track to suit the video. Found one. Total time searching and evaluating on Envato was around 2 hours.

Next issue was that the explainer template required Adobe After Effects to modify, so I signed up for a one month subscription for JUST After Effects on the Adobe Creative Cloud — total cost, approx. $20.

I had never used After Effects before, so while the app was downloading, I viewed a couple of 30 minute introduction and tutorial videos on Youtube. It didn’t seem too hard. I figured that I had managed to self learn other Adobe products before, and with my development background, I felt confident I could get to grips with it.

Once installed, I spent the better part of Sunday afternoon tweaking and customising the AE template, and wrote up a short script. Well, I thought it was short, but it ended up being around 3 minutes long.

Then came time to do the voiceover. I hate the sound of my own voice, but luckily my wife has a really nice speaking voice (she has actually been asked to be a voiceover artist on a few occasions). So she did the voiceover for me. One take, 5 minutes, and we were done.

I guess the other good part is that I am a musician as well, so I have some fairly good quality studio equipment which ensured that the recording sounded decent. I did some post processing in Logic using compressor and reverb plugins to tidy up the audio, and mix in the backing music I had grabbed from Audio Jungle.

I managed to complete the post processing on Sunday night, and uploaded to Vimeo on Monday morning, ready to embed the video on my website, which I will do later today after I have a break.

I think I spent a total of around 10 hours of my own time over the weekend doing the editing and audio post processing. After Effects turned out to be fairly simple to learn and use in the end.

So, my total costs (approx) were:

  • VideoHive explainer template — $40
  • AudioJungle backing track — $20
  • Adobe After Effects subscription — $20 (one month)
  • Voiceover artist — $0 (thanks to wifey)
  • Audio production — $0
  • Template customisation — $0

GOOD BITS: Having a voice over artist ready to hand. This is an important part of a video, and I can appreciate it is difficult to find a voice that fits. I consider myself lucky. Also, the explainer templates on Envato were REALLY good. Better than I expected.

TEDIOUS BITS: Learning After Effects from scratch. But the hardest bit was syncing up the explainer animations to the voiceover. I came close, but had to do a fair bit of chop and checking on both the explainer template and the audio file to get things to line up.

No disrespect at all to the companies who charge the prices they do for the production of these videos. It is definitely a taxing process, and my efforts are going to be very amateurish compared to theirs. If I had the funding available, I would have definitely engaged one of them to do this for me, but in this case, I had to work within my means.

Final results on Vimeo here:

Dogfooding 101

dogfooding (computing - informal) - to use a product or service developed by that company so as to test it before it is made available to customers.

We have now got to the stage where we have launched our latest web app, HR Partner.  Though we have reached launch stage, there are still a few things about the development of it that I'd like to share with you.

One of the things that we deemed was important to have from the outset, was an API (Application Programming Interface) that our users could use to query their employee data in HR Partner and integrate it with other systems.  This was slated as a 'Phase 3' project, which was to be commenced well after initial launch and we had a solid base of customers on board already.

However, one of the other things that we wanted to have in HR Partner was an extremely flexible reporting system.  Basically, we wanted our users to be able to query their data and filter (and sort) the data by any database column, including custom fields that the user can create within HR Partner.

When designing the architecture of the reporting engine, we realised that it would have to be quite complex, with a ton of checks and meta programming to enable the user to specify just about any query they wanted across the main employee file, plus the related lookup files.

We realised that we would essentially be duplicating the 'engine' for the reporting side, along with the engine that would drive the API later.  So we decided, why not kill two birds with one stone here - and we temporarily shelved the reporting engine development to sit down and build version 1 of our API engine.

Version 1 was basically purely a 'read only' API engine that allowed us to query the database tables and return the results as a JSON data stream.

THEN, we went ahead and started building the front end for the reporting engine, which directly used our API engine to pull and sort the data we needed for the reports.  All transparent, and invisible to the end user.

As you can imagine, this was a major change to our development timelines, but at the end of the day, it actually saved us time later on down the track.  The bonus is that we get to see our API being used under real world stress conditions.  We still haven't released the API specs publicly, but plan to do so in the coming months once we have completed stress testing and built the read/write components.

Building the API first also allowed us to start writing other apps for integrating various legacy payroll systems to HR Partner.  One of the payroll systems we support is Attache, which is a 30 year old Windows based system that uses the old Microsoft ODBC method to extract data.  We have designed a 'gateway' Windows app which uses a combination of ODBC and JSON API to pull data from Attache and upload to HR Partner in the background.

We used the Padrino framework to build HR Partner, which is based around Ruby/Sinatra.  Padrino allows us to mount separate apps within the same server easily, so we essentially have one app for the main HR Partner app, and another separately loaded app for the API, which allows us to still host on one AWS Elastic Beanstalk instance, yet be able to separately upgrade and take apps online/offline.

I am glad we made the design decision to shift our build targets around and get the API built first.  I can appreciate now what a lot of other startups are trying to do, by building the API, then designing their app around the API.  It makes for a far more robust and solid system.


Don't hide the delete button

Welcome to part 6 of our series on designing HR Partner, our latest web app that is slated for release in 2016.

This episode, I'd like to go through a design consideration that I had with the file upload library module in our app.  In this module, the user can create 'categories' for their files, and upload an unlimited number of files to that category.

They also have the option to delete a category if it is not needed any more.  The problem is, we won't allow them to delete while they still have files allocated to that category.

The question was how do we deal with this restriction?  On our early Alpha version, we simply hid the delete button if there were still files within the category.  However, this gave the user no indication that they COULD delete the category, at least unless the category was already empty, in which case they would see the button.

We thought that this was counter intuitive.  We wanted the give the user an indication that they could delete, as long as they deleted the files first.

So in the second iteration, we put the delete button back, but disabled it when there were active files in the category.  This still wasn't optimal, because there was no explanation as to WHY the button was disabled.

So we went to the next level, and made the button active.  If the user presses it while there are still active files, they will get a popup telling them why they cannot yet delete.  If there are no active files, then they will see the usual delete confirmation dialog.

We hope that this method means we don't clutter the interface with too much extra text, yet still gives the user an idea of what they can and cannot do within a particular screen.

When your hard work becomes invisible

In my latest project, I have been working very hard on getting the UX right.  I want the interface of my web app to NOT fight the user every step of the way, and to make some semi-intelligent guesses as to what they want to do.  Wherever part of the interface looks clickable, I want the user to be able to click on it and get the result they expected.

That sort of precognition takes hard work - LOTS of hard work.  Just today I spent pretty much ALL day on one small piece of functionality, that at the end of the day, my users will probably never really notice.

Come to think of it, *I* pretty much don't notice it now that it is finished, but I know it is there, and it is making my movements through my web app a lot smoother and logical.  

Just this evening I was thinking about it, and I was a little sad that all my work was essentially invisible to the end user - after all, they only usually notice things when they DON'T work.

But I was reassured by something a wise man once told me - "Character is what you do when no one is watching".  I like to think that my app has good character.

Don't change that menu

We are rolling along with Part 5 of my blog series that I am writing while building our latest web app HR Partner.  The earlier posts can be found on this site, and I will shortly put together an index page, so all the posts can eventually be cross referenced in the one place.

Today is a short post, and it is to do with a tiny design decision that we made today.

Clutter, specifically screen clutter, is a pet peeve of mine.  I dislike having more than is necessary on my app screens.  This must be a habit going back to my flying days.  Most aircraft cockpits have been designed by ergonomic and efficiency engineers to make the capturing of information as easy as possible.  Under IFR (instrument flight rules), the pilot has to minimise moving his whole head to avoid disorientation that can occur with no external frame of reference.

I try to always abide by these rules when designing my interfaces.  No extra clutter that will distract.  On the left hand side of the HR Partner page, is a menu showing the different HR 'modules' that the user can work with, i.e. Employee Training, Document Attachments, Absence Details, Assets on Loan etc.

I wanted to have the module menu so that whenever the user clicked on a module, it would disappear from the menu.  After all, if you were in the 'Absence' area, it would make no sense to have the 'Absence' menu option still available to click, was there?  It was another line in an already long list.  Removing it would make the list shorter and easier to scan for the user.

Or so I thought.

 The module menu in question, on the left.

The module menu in question, on the left.

It turned out, that having the module list change (even subtly) via the removal of a single line tended to throw our test users off.  It turns out that most users will subconsciously memorise the placement of menus and clickable areas on the screen - even if they scroll up and down!  They tended to keep a mental map of where everything was, and had already calculated the minimum distances required to reach those spots.

Moving them by one line or so tended to throw out their entire frame of reference and result in confusion and pauses when trying to find where they wanted to go.

In the end, we decided to leave the module list exactly 'as is'.  I would appreciate any thought anyone out there might have on this.  Also, if you have any scientific research that would back up my theory about users mapping the screen layout subconciously, I would appreciate a heads up.

Making deletion non-automatic

This is now part four of my ongoing blog posts on writing our latest web app HR Partner.  Parts one, two and three are here.

One of the things that we have realised from previous web apps we have written, is that the process of deleting critical data is almost automatic for most of our users.  Even putting the usual "stop and confirm" dialog box in front of them to make the absolutely sure they want to delete a piece of data becomes an automated response after doing it a few times.

For minor data like lookup files etc., this is not really a problem.  However, in HR Partner, the most critical data we have is the employees themselves.  We wanted to make the process of deleting an employee a tad difficult - to be absolutely sure that they could not do it accidentally.

To this end, we came up with the idea of the user having to type in a short deletion code, very similar to a Captcha code, each time they wanted to delete an employee.  Thankfully deleting employees is not a task done regularly, so we hope that the added thinking and stopgaps involved will not irritate users too much, but instead that they may be grateful for it.

When generating these codes, we also discovered that users could easily get confused between the letter O and the number 0 etc., so we decided to 'borrow' an algorithm that we spotted on StackOverflow to generate a non confusing code.  There should not be any guessing between the characters.  Here is the short helper code to generate the deletion code:

def generate_activation_code(size = 6)
  charset = %w{ 2 3 4 6 7 9 A C D E F G H J K M N P Q R T V W X Y Z}
  (0...size).map{ charset.to_a[rand(charset.size)] }.join

Have we gone overboard with this?  Would love to hear from other programmers and designers out there as to what you think about our approach.

Making user onboarding a smooth and pleasurable experience

This is part three of my regular blog posts describing the building of our new web app product, HR Partner.  Previous posts are available here and here.

In part one, I explained about the sign on methodology used - more specifically, how we would separate the user authentication system from the company databases.  This was to facilitate one user being able to work across multiple companies easily.

This workflow also meant that is user Bob wanted to work with company Acme Industries, then Bob would have to request an invitation to join Acme Industries as a user.  To do this, Bob simply clicks a link on the login screen and fills out his name and email address.

This information is then sent to the Acme Industries company admin user.  They can then log in to HR Partner and in 2 clicks, approve Bob's application to join (or ignore it).

In our early Alpha testing, whenever the company admin approved a user's request, the requesting user (Bob in this case) would automatically have an account created for him, and be sent back a generic congratulatory email telling them that they could now log into the system and begin working with Acme Industries.

But wait - we have an edge case here that needs to be looked at more closely.

We have to consider whether Bob is a brand new user to the HR Partner ecosystem, or whether he has been around for a while and already has an active logon account.

If he already has an account, then he does not need to do anything more than to click on the custom company HR Partner URL to log in immediately.

If he is a NEW user, then his account would have been created automatically when he was approved, and now he has to create his password before he can log in.

TWO distinct paths of action, depending on their initial status.  However, our initial version of the invitation process had only ONE generic email back to the invitee, asking him or her to either login or go through the password reset process.

Actually, to be honest, the initial version was clunkier than that.  We actually sent back the congratulatory email, and added a proviso that if they were a new user, they were to expect a SECOND email shortly with the password reset instructions, upon which we would generate and send them a password reset email (the same password resent email as if the user had asked for one on the site).

I thought that it was ridiculous - getting one, sometimes two emails back from us depending on their status.  I resolved to make this easier by only sending back ONE email to the user, and changing the content according to their initial status.

So now, the user gets back a nice congratulatory email, and within the email, they are EITHER shown a link to the company sign up page, OR they are given a link to the password reset page (our app now generates the password reset token before sending then the email, if they are a new user).

 User already has an account with HR Partner and was approved to join a company.

User already has an account with HR Partner and was approved to join a company.

 User is new and has had their account auto created.

User is new and has had their account auto created.

The end result is much less email clutter, and (hopefully) less confusion for the end user as part of his or her onboarding process.

NB: Upon further consideration, we are now working on the change password screen a little more too.  We want to customise this screen a little more so that when the app detects that it is a new user changing their password for the first time, that it shows up a little welcome message in there too - just to make the screen a little more friendly than the usual stark password reset form.

 Normal password reset screen.

Normal password reset screen.

 Password setup screen for new users.

Password setup screen for new users.

Both the above screen are actually exactly the same - it is just the wording that has been changed depending on the context - whether they are a brand new user, or an existing user wanting a reset.


Reducing 'browser detritus'

In part two of my notes and observations about designing our new web app, HR Partner, (part one here) I would like to talk about 'browser detritus'.  What is it?  Well, consider the following scenario.

In most web apps, if you forget your password, there is usually a handy little button or link on the login page somewhere that the user can click.  Usually, this will present him or her with a simple form where they enter their username or email address, and a password reset email will be sent to them post haste.

It is what happens after this that concerns me.  You see, in nearly all cases, the user is sent back to the original login form, along with some sort of notice to check their email for further instructions on resetting their password.

Now, most users would then either switch tabs or apps to their favourite email client, and check their email.  Naturally, most of these reset emails have a special link to click on which will ask the user to reset their password.


Clicking on this link always, always, always opens up a NEW browser window with the reset form on it.  Meaning that the old login screen is still sitting, waiting, in the back there somewhere - now lost among a sea of browser tabs (in MY case, those tabs are spread across 3 different browsers usually).

Invariably, after going through this scenario myself, I will go to do some 'tab housekeeping' at the end of the day, and I will come across sign on screens still waiting for me like a faithful puppy at a train station.  Some days I cannot remember if I indeed reset that password yet, or if it was still something I had to do?

But look - I am as guilty as the next programmer/designer.  Our own web apps to date follow this same paradigm.

I decided to change that with HR Partner though.

At the risk of incurring the wrath of UX specialists everywhere, I actually introduced 'dead ends' in our web app sign on procedure.  When you tell HR Partner that you have lost your password, you will still get that form asking for your email address, but then, you will see a screen that tells you to check your email, and nothing else.  The screen does not even link back to any other screens in HR Partner, but instead asks you to close that browser window down now.

 Our normal sign on screen - Whoops, I have forgotten my password. &nbsp;No problems, click on the link...

Our normal sign on screen - Whoops, I have forgotten my password.  No problems, click on the link...

 This is easy - I'll just type in my email address here...

This is easy - I'll just type in my email address here...

 Aaaand - dead end! No going back, no going forward. Just close the browser window and wait to open another one automatically when you get the email...

Aaaand - dead end! No going back, no going forward. Just close the browser window and wait to open another one automatically when you get the email...

Is this too regimented? I think it is a step towards avoiding tabmageddon myself.  We are still in development with our web app, so might change this later, but for now, we have introduced these dead ends in a few spots during the onboarding process, including:

1. When the user asks for a password reset. [We have a password reset link in the email]

2. When the user asks for a reminder email with their company specific sign on link. [We have links in the email which take them straight to their required company link]

3. When the user reaches out to a company admin to be invited to join an existing HR Partner company. [We have to wait for the request to be approved by an admin, after which an email will be sent out with a link to complete their sign on process]

I must admit that deliberately designing this many 'dead ends' in an app made me pause at first, but I think at the end of the day it might be a good thing for the end user experience.  What are you thoughts?

Company hopping - the new work culture

Well, we are busy building our latest web app project, and this particular one is interesting in that it has clearly demonstrated how this niche target industry has changed in the last decade.

Backstory: We design an HR management app call HR Partner a long time ago in 2004.  Back then, it was a Windows based app, and was tied in very specifically to a particular legacy payroll system.  We did very well out of that application, but lack of support from the legacy payroll vendor and other reasons meant that we let that project slowly die on the vine.

However, we have had a solid core of users still using that system to this day, and who keep asking us when we are going to update it and add more to it.

Well, that lead me to decide to take up the mantle again, but this time, we are doing it differently.  While the core of the product will be similar, we will now be (a) building it as a purely web based application, rather than Windows, and (b) we will not be locking it into one vendor, but instead be able to integrate with several other more modern payroll systems out there.

In talking to existing users though, one point that I had never considered became more apparent.

Back in 2004, it was quite normal for most medium to large companies to have an internal HR manager on the staff.  Quite frequently, the Payroll manager also acted as the HR manager, instead of having a complete separation of duties.  In any case, it was really easy to just have internal team members working on their own isolated HR system, and everyone seemed happy.

However, the current batch of users that we have been talking to are painting a completely different picture.  Nowadays, it seems that more and more of the HR work is being outsourced to external consultants who are not attached directly to the company.

When we spoke to some of these consultants, they in turn gave us a look at their typical work patterns; which was to provide services to multiple companies, either in the same or totally different fields.  They explained that a lot of the times, internal staff and managers wanted to have complete control of the data, but they would look to external agencies to analyse that data and tell them how they could actually make better use of it.

This threw our design specs off kilter a bit.  In all our other web apps, building the sign on and authentication systems was easy.  You had one company, that all the data belonged to.  And within that company, you have one or more users who could create accounts directly attached to that company so they could work on the data.  If a user wanted to do work on another company, they would have to create a new sign on account for the other company to do work there.

We looked at our audience, and figured that this old method would not work.  The considerations we had were:

  • We would have users that would still want to only work on their own company, and are not interested in working in others, and
  • We would have users who would not 'belong' to any one specific company, but instead would be working on several and jumping back and forth on a regular basis.

Trying to cover all these bases proved to be quite tricky.  There were a lot of edge cases where we were not sure that things would flow well.  Maintaining security and privacy in this industry is quite critical, but at the same time, we didn't want that to put up too many roadblocks to people onboarding and using the system.

What we decided to do was to divorce the user authentication system from the company database system.  

How it works is - Users could still sign on and create a new company.  They would then become the 'owners' of that company.

Other users could then apply to be invited to a company.  The company owners would have to approve them joining up.  Other users could apply to join multiple companies if they liked, and use a single sign on to interact with all the companies they belong to.

I know this is not new ground, and that plenty of other systems utilise this methodology, but it was a new thing for us to tackle in our own design and development work.

Technologically, it was quite simple to manage.  What really had us stuck was the UX factors.  We wanted to make the process as easy and seamless as possible.  As I mentioned, I was surprised at the number of edge cases we came across with this new paradigm.  Problems that we had to think through were:

1. The new user conundrum

What happens when a completely new user wants to join a company?  Should we make them go through the whole process to set up their account details first, verify their account, then shoot a request to the company to see if they will be allowed to join?  

Our answer to this one was NO.  We would simply collect their name and email address on the request form and send it to the company admin.  IF the company admin approved them joining, then we would quietly create their account in our system using this information, and send the invitee an email asking them to click a link to set a password on their newly created account and log in straight away.

BONUS - As part of the '2 click' approval steps the company admin has to do, they are presented with a screen where they can customise the security parameters for the applicant.  They can, for instance, opt to lock the new applicant out of certain sensitive screens or prevent them from editing employee information etc.  That way, when the applicant first logs in, they are already preconfigured for what they are allowed/not allowed to see.

2. The old user failing to remember

To enable quicker sign ons, we give every company on HR Partner their own custom sign on URL link.  The problem with a consultant who signs on to a dozen companies is remembering these links.

To solve this, we make it easy from the sign on screen for the user to get an email from us listing all the companies that they have been approved to work with, and a 'one click' sign on link for each company.  No need for them to write it down or save it.  If they move to another machine (or mobile device) without the bookmarks, they can easily get another list sent to them within seconds.

BONUS - The user does not have to remember different passwords.  Just the URL, which is actually just the subdomain of the company, in the form of [company id]

3. Dealing with bad users

One problem we are still working on is - what do we do with users who are removed from a company because of bad behaviour?  Say someone did something naughty in Company A, and were booted out by the admin.  Do we then have an obligation to tell Company B and C (if the user is authorised to use those companies as well)?

At this stage, we don't collect any information as to WHY the user was dissociated from a company.  We simply let the admin 'deauthorise' them.  Perhaps later we can collect reasons, and look at a process for vetting out problematic users to protect all our customers.

4. Handing over admin control

At present, we allocate the first company who created a company as the site administrator, who is responsible for approving new users who want to join.  We have not yet built in a mechanism for handing over control of a company to another user, but given the transient nature of so many people's jobs these days, I am thinking this is something we will have to do.

Once again, this will have to be carefully managed, as the company admin is essentially 'god', with many powers over the data and privacy of information.  We will have to build in safety checks with respect to the handover, but once again without affecting the UX negatively.


I would appreciate some feedback from anyone else out there who has tackled these sorts of issues in the past, or who could offer some tips and suggestions as to how we handle further development.  I intend to post a few more posts like this as we come across design issues on HR Partner.  Hopefully it will prove useful to the design and development community.