Most problems in interfaces are not difficult to solve. The difficult part is to see them at all. The fix is usually a few lines of CSS, a state that nobody handled or another transition value. So the skill this lesson is about is noticing - — and writing the problem down in a way that will still be clear to you days later, when you already forgot which screen it even was.
The easiest way to debug things is by asking questions to yourself.
Go through some action in the product. If at any point you paused for half a second or got confused - — there is a problem in that place.
You paused because the screen did something you didn't expect. A button reacted strangely, a menu appeared in a wrong place or suddenly you weren't sure what the next click will do, while the rest of the app was perfectly clear.
These moments are easy to ignore - — your mind writes them off as distraction. Every single one points at something real.
The second click. You clicked a button, nothing changed on the screen and you clicked one more time. In most cases the interface simply didn't confirm the first click fast enough - — the loading state is missing or the transition starts too late. The worst case is when the hit target sits a few pixels away from the visible button and your first click hit nothing at all. The user has no way to know if anything registered, so they keep clicking until the screen finally reacts.
Cursor drift. Your mouse moves around the screen, hovers over things but never actually lands. Sometimes it's a hit target problem - — the clickable area is too small or it's not clear what's clickable. Sometimes it's a recognition problem - — you're scanning a context menu for an option you know exists but your eyes can't find it.
Undoes that are reflexive. You performed an action, either toggling a switch, moving a row or deleting something and then right after you performed the undo key stroke ⌘ZCtrl+Z or undo button click. Not because there was anything wrong with the action, but rather because there wasn't really any feedback on what had been done and you were just slightly concerned that something might be off.
Re-reading. Read a label, then read it again. The first pass didn't land. Almost always a wording problem. Easy to dismiss this stuff as your own quirks. It isn't. If you hesitated in a spot, real users hesitate in the same spot - — they just won't tell you about it, ever.
Not everything catches your attention. There are subtle cues that say to you that everything seems all right but something is a little off. You can't put your finger on what that is, but you know it when you see it. And most of the time it's an issue of precision, which, in this case, doesn't have anything to do with being absolutely precise with every pixel.
Alignment. The icons in the sidebar are not precisely aligned vertically; a label is one pixel above another. The spacing between a few controls is inconsistent. Nothing's broken, but no one cared enough to check.
Spacing. Buttons where padding looks incorrect since text alignment is technically aligned correctly, but doesn't look visually aligned. Grid of cards where spacing between cards is different from internal padding. Modals with uneven padding - — tight at the top and loose at the bottom.
Hidden problems of defaults. Selectable text where you shouldn't be able to select it, such as drag handles, button texts and icons used only for decoration. Phone fields that pop up the complete keyboard, as opposed to the numeric one. A scrollable list without an indication that there is more underneath it.
None of these problems will be noticeable when you use the product under normal circumstances. You must deliberately slow down. Check out the layout space. Attempt to select the text you shouldn't be able to select. Resize the browser window and observe which elements fail first. Go to the bottom of a list and find out whether there is anything at all there.
Testing interfaces in ideal situations is what leads to this problem. Fast WIFI. Minimal content. The straightforward journey. A mouse and a 27-inch screen with test data in three rows.
It's the testing in isolation, but reality is different from this, very different. People copy and paste. They type on their keyboards. They access the application on a moving train, an old phone and even on poor internet connection.
The components that fail in such stressful scenarios happen to be the critical ones, but this only comes up when you intentionally put things into stress, which most people don't since it is tedious and time-consuming.
Make them even harder on purpose.
Introduce delay. Make your network slower, so that it works at a 3G level or add some artificial delay to your API requests. All the states missing in loading animations become instantly apparent.
A button not doing anything for around 800ms after being clicked by the user. As you can tell, if your app responds with a delay, users will experience it much more intensely because they're trying to get something done, and you're getting in their way.
Go for long content. Change all those placeholders for realistic texts. A 40-character-long username without any spaces. Text in a language with words larger than those of English. An eight-digit number instead of three digits you assumed it would be.
Such actions would easily uncover all the issues related to truncations or anything else. Layouts and content placement would become problematic, too.
And who can say that the use of dummy content for testing did not do a lot of damage?
Clean the place out. Get rid of all content. Nothing should be on the screen - — no items, no search results, no notifications, nothing.
What do you see now? The screen is intentionally blank? Or did the site simply crash? An empty screen without any text seems broken. An empty screen with one line and a button on it seems intentional.
Make things fall apart. Fail an API request. Return a 500 error. Disconnect from the WebSocket connection. Observe carefully what happens to the user interaction with your interface in such circumstances. In particular, observe how well the application is informing users about problems and whether the application is trying to cover up problems at all costs.
Pay special attention to forms because any bugs with clearing the form in case of failed submission result in actual support requests from frustrated users who entered a very long message and then lost it.
It's like the 150-question test which you almost completed and on the last question you accidentally refreshed the page and now you need to start over. Not fun, right?
Leave the mouse alone. Interact with your product only via the keyboard. Activate dropdowns. Select buttons. Cancel operations. Close any opened panels. Focus problems, hidden focus navigation and focus traps can be found easily here. Remember that not all of your users will be able to use mouse for interactions.
Narrow the page down. Resize your browser window down to phone dimensions. Don't check mobile as a concept, check how stuff intended to be used on a desktop behaves in a mobile viewport. I disagree that you should build responsive only for exact screen queries (like sm, md, lg, xl), what if your user has weird screen size between md and lg? Fully responsive design is very time consuming, but in that case you can be sure that every possible screen size is covered.
Test it on a physical device. The mobile preview of Chrome Developer Tools is not your best bet. A touch target optimized for preview works differently when you walk around with your mobile phone. A form input that resizes text to 16 pixels to avoid zooming-in on iOS Safari. A video which plays automatically and takes over the whole page. There's more between a responsive preview and your mobile device than meets the eye.
Copy-paste rather than type. Try copying a phone number with spaces into a phone field. Copy an RGB code into a color input which accepts only hex codes. Try copying a URL with utm parameters into a URL input field. It will soon become clear whether your form fields are forgiving or punishing toward the end-user.
The first step is noticing. The second step is making use of it correctly. Observation typically fails between the two because once you stop looking at the friction, that exact form disappears, leaving you with just "this sidebar is not right" information that is meaningless after three weeks when you don't remember which sidebar.
You notice something odd, take note of the following three items:
Break - — what happened: "I entered an RGB value and it was refused by the picker. I had to enter it as hex code for it to take the value." It's critical to be specific in your observation about what part of the UI failed to live up to your expectations.
Expectation - — what you thought should have happened: "I expected the picker to accept a color value of rgb(0,0,0) even if it stores its values in hex behind the scenes." This is the important bit that most people overlook. It is the part that specifies the proper response and not simply a list of flaws.
Direction fix - — the general sense of the fix. It's not a specification. One line only: "Accept any common color format and normalize it to hex." You'll be able to work with it later, even if you can't remember the context.
The format is irrelevant. It could be an email, ticket, document or voicemail. But the structure is crucial. The issue, the intended outcome, and the location of the fix are key. Lose one of those and your note will be too vague for implementation. I personally use Slack DMs with myself to keep track of these things and this list is always growing.
With experience, you notice what works instead of what fails. You see a sidebar whose icons, labels and controls are aligned identically across every section. You spot a table that uses tabular numbers for consistent alignment. You discover a scrollable menu in which the last item is deliberately clipped, allowing you to see there are more options underneath.
Patterns like these deserve to be collected.
However, you must only collect what deserves being collected - — the easy move is to collect screenshots. Screenshots capture the look of something, which will not translate.
What you need to note is the rule, the idea underlying a component.
Describe components' function, not their appearance.
Also, pay attention to minor patterns, such as tabular-nums in tables' data columns, user-select: none for decorative items, touch targets bigger than the visible icon, text-wrap: pretty for headings or non-breaking spaces between numbers and units. These rules are so subtle that no one ever thinks of putting them into a list.
Keep the list small. Patterns do not have to be stored in a huge Notion database or a set of well-tagged Figma files. A few notes with screenshots can be sufficient here. All you really need is something to refer to in case of doubt. Update the library from time to time, some patterns that seemed innovative to you back then might become obsolete over time and get pruned from your library.
Choose an application you admire for its quality and use extensively. Use it slowly and deliberately, not for productivity but just to observe. For me, it is Linear. I love them. I can play with their small things for hours.
The moment you notice such details in applications created by other developers, you will start observing such features in yours.
The friction is the lesson.