Designing a data-heavy enterprise application — Part 1

A brief comparison and a practical guide on loading and displaying data or handling errors in enterprise vs consumer applications.

Ovidiu Boc
Bootcamp

--

An excerpt of requirements for enterprise readiness: security, scalability, SSO, RBAC, compliance, cost control, efficiency, accessibility
Excerpt of requirements for enterprise readiness

Having spent quite a few years designing and reviewing data-heavy enterprise applications, I realised there are some specific guidelines we need to consider when designing enterprise products compared to mainstream consumer products.

And I don’t mean technical design guidelines, although there is a small overlap that might be interesting for technical people.

But, if you are a product designer who is already working on an enterprise application 👋 or you’re thinking about joining an enterprise team, you might find the pointers in this guide useful to take into account.

Understanding the context

So… what exactly is an enterprise application, what makes it so special to design for and why is the amount of information so important?

Well, for starters, Wikipedia defines an enterprise application as being a computer software used to satisfy the needs of an organization rather than those of individual users. It might be obvious, but this is actually one of the key differences between enterprise and consumer applications as the needs of an organization can easily span across multiple verticals that have little in common with the needs of individual users (e.g. security, compliance, cost control, scalability — across multiple divisions, integrations — with their existing services, and the list goes on).

Enterprise apps you might have used or heard of: hubspot, mixpanel, salesforce, zendesk, stripe, intuit, jira, aws
Enterprise apps you might have used or heard of

Another key difference is the amount of information they are designed to work with. As a rule of thumb, most enterprise products ingest and / or manage incredible volumes of data:

Think of a HRMS processing millions of job applications per year (i.e. McDonald’s receives around 20 million job applications and makes around 2 million hires per year world wide) or an ITMS analyzing billions of events each month (i.e. Microsoft processes on average 600 billion security events on a monthly basis) and so on.

This alone increases the level of complexity we need to design for as we need to take into account the performance of the entire ecosystem the application is part of.

Let’s highlight a few more (relevant) differences between enterprise and B2C products before we jump into the “solution” space — don’t worry, we’re not deep diving into this topic right now 😅, but we do have to understand the “specifics” of these applications. I’ve attached some useful resources at the end if you’re interested in more details.

Consumer products

  • Most consumer products are solving a particular problem for one user group and they are mainly focused on retention, engagement, loyalty and conversion.
  • A typical user journey for a mainstream consumer product consists of a few linear steps, with limited entry points, and a few optional side quests (e.g. set up your account details on your way to the checkout).
  • Last but not least, a consumer product is, in most cases, used in a (very) personal context — e.g. using your own smartphone to look for an Uber, on your way to meet your friends, making your own decisions about the cost you are willing to pay for the ride (come on, take that Uber Black, you deserve it 😬). You want to use that application right there and then, but it’s also in your power to put it aside or replace it with something else at anytime.

Enterprise products

  • Enterprise products on the other hand are “one-size-fits-all” solutions for various user roles, with different permissions, responsibilities and levels of expertise. They primarily focus on efficiency, fault tolerance and repetitive use — in other words, their purpose is to help employees get their (repetitive) tasks done as fast, cheap and error free as possible.
  • A single user journey can easily include over 100 screens, spread across 2–3 tools or more, with non-linear tasks and various entry points.
  • Often times, the environment in which an enterprise product is used in can be highly regulated (think of banks and governmental institutions for example), stressful and impersonal, ranging from outdated hardware used by an employee in a crowded open space, to uncalibrated beamers with poor contrast or a matrix of high quality displays covering an entire wall in a decision making room.

Let’s end this comparison with one last key difference: unlike B2C users, enterprise users don’t have the luxury of choosing whether or not they want to use a particular product — they have to use the one the company agreed on using and finish up the tasks assigned to them within their deadlines.

Now that we’ve built some empathy for the enterprise users, let’s dive into it and see how we can make their life easier. Or at least try 😃

Loading data

Considering the large volumes of data being ingested, processed and managed by an enterprise application, chances are you’ll be running into quite a few challenges. Here’s how you can overcome some of them.

Downsize on purpose

Loading large, unstructured data sets usually doesn’t serve any purpose — it doesn’t help the user and it certainly doesn’t help the performance of the system. Furthermore, if the data you are trying to load does NOT support pagination or virtualization (e.g. an IT infrastructure map), you will most probably hit a hard limit set in place by the engineering team to protect the rest of the ecosystem. To overcome this, use a tailored data segmentation or a guided user flow for each user profile — think about the most relevant and / or the most used criteria to have as an implicit filter and build on that.

For example, instead of displaying a list of all the job applications in the system, you can start by asking the user to do a preliminary filtering on the geographic region and the department he/she is interested in, or you can start directly with the newly received applications sent in the user’s attention as a default view and take it from there.

“Divide and conquer” when possible

You should also try to avoid loading an entire screen at once as this might lead to long(er) waiting times for the user. Instead, you can break down the screen into multiple areas or sections, each of them with its own independent loading state. This way, if the process of loading the data in a particular section fails, it will not affect the other areas, thus the user can still use the rest of interface and investigate or report that specific issue.

For example, instead of loading an entire dashboard at once with an overall loading state for the whole page, you can break it down into individual loading states for each widget (most probably they are using different APIs anyway).

Manage the expectations

If the expectation is that a certain operation should take a short period of time to load or to process (e.g. searching for an item), it might be a good idea to set up a reasonable timeout limit. If the operation has NOT finished loading or processing within its dedicated time frame, it might be helpful to display the partial results (i.e. found items) and inform the user that the requested operation took longer than expected. On one hand, the partial results might be enough for the user to be able to continue his journey. And, on the other hand, this might also help identify certain technical issues within the system worth reporting and / or investigating (e.g. unresponsive APIs, faulty integrations, bandwidth allocation, etc).

If the expectation is that a certain operation could take a long period of time to load or to process (e.g. generating a report), it would be nice to inform the user in advance about the expected waiting times — you can use a generic formula for this, it doesn’t have to be exact (e.g. “this might take a few minutes”). If the user decides to go ahead and execute that operation, he/she should NOT be forced to wait on that page until the operation is completed — use a global background process indicator (make sure it’s easily visible and accessible from anywhere in the application) to keep the user informed on all his pending operations and send him/her a notification when one of them has finished loading or processing (similar to a browser download manager).

Don’t interrupt…

From an efficiency point of view, exposing an enterprise user to loading states regardless of the task at hand is not really ideal — it creates friction and it adds up to a fragmented experience, not to mention the frustration and the (costly) implications of having to wait for every system response when you are trying to fix an urgent issue.

To bypass these and create a fluid workflow, use a contextual approach at every step and ask yourself: is this operation something that the user must wait for?

If the answer is negative (e.g. adding / deleting a record or sending out a message should not force the user to wait for a system response before moving on to his/her next action), consider using the optimistic UI principles¹ to increase the user’s perception of speed and efficiency: if an action has a 97–99% success rate, skip the loading / processing state, show the end result immediately, execute the action in the background and alert the user if there was an error or something else went wrong.

A child is kicking away the loading state that was previously inserted between the action trigger and the action confirmation
Credit: Denys Mishunov / Smashing Magazine

If the user must wait for the operation to be completed before moving on, manage the expectations as described previously and choose the appropriate loading state for short waiting times:

  • If it’s absolutely necessary to block the interface whilst the new content is loading, use a “skeleton” to give an idea about the content being loaded, or another loading animation — aim for consistency though;
  • If you can load the new content asynchronously and let the user continue his work by not blocking the entire screen, go for a loading bar somewhere visible.

Error handling

I know, often times this falls at the end of our “to do” list, or we skip this entirely and rely on the engineering team to handle it 😅 , but it doesn’t have to be this way if we keep in mind a few pointers.

Jenni Nadler has a wonderful take on what makes a good error message² (see the example below) — both the structure and the reasoning behind the message are spot on.

The structure of a good error message: say what happened, provide reassurance, say why it happened, help them fix it, give them a way out.
Credit: Jenni Nadler / Medium

And it works out nicely for consumer products but, when dealing with errors in enterprise applications, it all comes down to the user’s role, permissions and the context of his actions.

For instance, does the user have the permission to see the error in the first place? There might be (rare) cases when the user has specific rights to an integration or a part of the system that only allows him/her access to certain information, which may or may not include errors (for security or compliance reasons). But, even if the user does not have enough clearance to see the errors, we still have to inform him/her that an error has occurred. In this case, we have to be generic on purpose — “Something went wrong …” is THE most representative example if you don’t want to give away any details about an error, but you should definitely change this to fit the context and level of details you are allowed to provide for that user.

Assuming the user has enough permissions to see a particular error, is he/she allowed to also see the details of that error (e.g. error code, server response, reason, etc.)? And if so, are these details relevant for him/her in any way? For example, you might want to display the error code and the server response to a power user, an administrator or even to an entire organization (e.g. IT Operations) so they can start troubleshooting the issue at hand or pass it on to the appropriate department, but there is no point in bothering an entry level user or the members of non-technical departments with these details.

The actions and indications you provide in the error messages should also follow the same pattern: match the follow-up items with the user profile and their permissions. Building on the previous example, you could include relevant links depending on the error type to “report the issue”, “check the system status” or “view documentation” for power users and administrators. For entry level users or non-technical employees, you could use more friendly actions, as seen in Jenni Nadler’s example above: “retry” / “reload”, “contact admin ” / “contact support”, etc.

Display data

“How do we display data?” has to be the most generic question out there and it usually comes together with the most generic answer of all times: “it depends”. Things are no different when it comes to enterprise products, but we can definitely consider a few general use cases you should take into account.

No data

There are a number of scenarios that can lead to an empty state, depending on the context the user is in. Regardless, you should always aim to offer him/her a way out.

  • Is the empty state a result of a lookup process? Then offer the user a shortcut to go back or move forward. For example, it can be that he/she used a combination of filters that resulted in no matching items — in this case, offer an “undo” option that would allow him/her to go back and automatically revert the last applied filters. Or, it can be that the user searched for a particular item but misspelled the keyword(s) — in this case, offer a few similar alternatives (based on the soundex or other relevant criteria) and allow him/her to move forward.
  • Does the user have enough permissions to add items for example? Then offer him/her an extra option to do so. Following the previous example, if the user is searching for a particular item with no results, you can offer an option to add a new item using the keywords he/she was searching for, in addition to providing the aforementioned alternatives.
  • Lastly, the empty state could be the result of a human or a system error — in this case, follow the “error handling” pointers. Avoid using the empty state as a substitute for an error message or a lack of permissions — we’ll handle the latter case in a moment.

Too little data

(White) Space… the final frontier, the holy grail of any data-heavy product. It happens so rarely to be able to use it properly that you might be tempted to jump on your first idea and design something before stakeholders come up with more requirements you have to squeeze in 😈.

The challenge lies in delivering a good solution considering the medium or device used by the target persona. In this case, when there’s too little data to be shown, you have to keep an eye on large screen resolutions ranging from 4K monitors to muti-monitor setups. Depending on the type of content you need to display, consider Fitts’s law³ at all times:

“The time to acquire a target is a function of the distance to and size of the target” — in other words, the smaller the target and the further it’s placed, the harder it is to hit.

For example, if you have a table with just a few columns and contextual actions on each row, placed at the right side of the table, it’s going to affect the ergonomics of using these actions properly if the table stretches for the entire width of the viewport. The same goes for a dashboard using a couple of widgets spread across the entire screen. In most cases, it might work to set up some boundaries or limits for widths, gaps, margins, etc. In other cases, you might need to rethink the way you design the same screen for multiple breaking points with higher values than usual.

Too much data

Opposite from the previous corner case, you might also be faced with the challenge of displaying too much data on a tiny screen resolution (you’d be amazed to find out the manufacturing date on the equipment used in some enterprises).

With limited real estate you have a few options: wrap content, horizontal scroll, content truncation with a touch of progressive disclosure, or a combination of these. Choosing the right method depends on the context, but let’s break them down using a table as an example:

  • wrapping the content will generate too much vertical scroll (e.g. long descriptions for each item);
  • horizontal scroll will probably require a lot of going back and forth to get all the details of a single item;
  • truncation works in some cases, but it requires an additional action to see or be able to copy the content (e.g. using the “hover” or “click” events to uncover it, maybe a contextual menu to copy it, and so on);
  • a combination of wrapping and horizontal scroll where the least important columns are pushed towards the end of the table might work in some scenarios, whereas a combination of wrapping and truncation (to a maximum number of lines) might work well in some other cases.

Bottom line: always use real data in your designs to easily uncover all these cases, especially the best and the worst scenarios. Whatever method you choose, don’t forget you should design for the majority and treat the minority separately — pick your methods accordingly.

Protected data

Don’t forget that different users reading the same piece of information might have different permissions — in this case, consider obfuscating the parts that they don’t have access to (instead of hiding them) and add a brief note that explains the reason. If you do hide them, you might break the context and generate confusion. For example, Slack does this with the private channels (see how it looks like below) — if you take out the “private channel” part, it doesn’t make any sense anymore.

A private channel being obfuscated in Slack and a tooltip expalining the possible causes.

Format data

Somehow similar to the previous case, users from different locations might understand different things looking at the same data. Always format the data you’re showing based on the user’s preference — keep in mind that if a user works from a particular country, it doesn’t necessarily mean he/she will automatically adopt the standard formatting used in that country.

For example, I might be an European employee temporary working from the U.S. — it doesn’t mean I want to transition automatically to miles instead of kilometers or using the `mm/dd/yyyy` date format instead of `dd/mm/yyyy`.

Different date time formats used across the world: USA/Philippines, Australia/India, parts of Spain, east Asia, the rest of the world and ISO 8601

Sneak peek at Part 2

  • Take accessibility seriously;
  • Design for speed and repetitive use;
  • Plan for scalability;
  • Match the learning curve.

👉 Designing a data-heavy enterprise application — Part 2

References

  1. True Lies Of Optimistic User Interfaces
  2. When life gives you lemons, write better error messages
  3. Fitts’s Law

If you found this article helpful, please consider giving it a few claps 👏 . You can also ping me on LinkedIn if you have any questions, I’d be glad to help.

--

--

Experienced product designer on a mission to humanize enterprise and B2B applications... https://www.ovidiuboc.ro/