Writing · 5 min read
What does a developer need from an interface on a bad day?
The same things anyone needs when the work has stopped: what broke, what it affects, what changed, and what they can safely do next, in that order, on a screen that assumes they are in a hurry. A developer’s tools are opened most when something has failed, so the error message, the empty state, the log and the first ten minutes are the product rather than its edges. Every incident below happened to this site, and its build write-up has each one.
Key idea 1 of 7
The screens a developer opens most are the ones that open when something broke
A developer does not open the dashboard when the deploy works. They get a green line in a chat window and go back to the editor. They open it when the deploy fails, when the build is red, when the service is returning errors at two in the afternoon, or when the bill doubled. Traffic to the interface runs opposite to how well things are going, which is a strange property for a product to have and the one that decides its design.
The screens that get the most attention are the ones a person arrives at already stressed, short on time and short on patience, and they have to be designed for that person rather than for the demo. Every posting for a designer on a developer product says a version of this, and the version I keep is that failure is a first-class state, not an edge case. This site is small, and it has taught me the same thing three times.
Key idea 2 of 7
An error message is an interface, and most are written by the thing that failed
The error message is the interface the developer actually reads, and most of them are written by the thing that failed, at the moment it failed, by the engineer who was handling the exception rather than the person who would read it. “Deploy failed” is a status. “The artifact could not be built because one tracked path is a symbolic link the runner cannot follow; here is the path, and here is the check that would have caught it before the push” is an interface.
The second one is what this site’s deploy says now, after I wrote it. The first one is what it said the day the deploy failed fourteen seconds in, on a tree that had passed every check, because a folder on one Mac had been committed as a link to itself.
A status
- Says that something happened
- In the words the machine used
- Written where the exception was caught
- Ends the conversation
An interface
- Says what happened, to what, and why
- In the words the person uses
- Written by the person who designs the product
- Ends on the one thing to do next
An error is a state of the product, and every state gets a decision, so the error gets one too: what does the person know, what do they need, and what is the one thing to do next. The place that decision gets made is a design review of the strings, with the engineer who owns the code that throws them in the room, because they are the only person who can change it.
Key idea 3 of 7
Silence is the worst failure, so nothing should look like nothing
Worse than a bad error is no error. The build that produces one of this site’s stylesheets emits only the classes it has seen a page use, so a class named in the markup that the build never saw is not an error. It is nothing at all: the type measures wrong at every width and the console says nothing. A merge that passed every check and never deployed did not look broken. It looked unchanged, which is indistinguishable from a change nobody made.
Silence is the failure a developer cannot work with, because there is nothing to search for. So the rule is to make nothing look like something. An empty list says why it is empty and what would fill it. A step that was skipped says it was skipped. A deploy that did not run is a row that says it did not run, not an absence in a list. The empty state is not a placeholder. It is the product telling the truth about a moment when it has nothing to show, and the truth is almost always a reason.
Key idea 4 of 7
The first ten minutes decide whether the tool is believed
A developer arrives with a repository and a deadline. Sign up, connect the repository, first deploy. Everything the product will ever be believed about is decided in those minutes, and not by whether the first deploy works. It is decided by what happens when it does not. If the first failure explains itself, the person has learned that this tool tells the truth, and every later green line is read as true. If the first failure is a status, they have learned the opposite, and they will keep a terminal open beside the product for as long as they use it.
That is the same calibration the AI articles on this site are about, arrived at from the other side. Trust in a tool is not a feeling about the brand. It is a record of whether the thing said what it was doing, kept by the person from the first ten minutes on.
Key idea 5 of 7
The log is the interface of last resort, so design it as one
Most of what a developer’s tools tell them, they tell them in a log: a plain record of what ran, in order, with what result. It is the least designed surface in software and the most honest one, and when the screen is calm and the answer is in the record, the developer reads the record. Two things follow for the designer.
The first is that the log is read at the worst moment and should be designed as an interface: the failing line found first, the noise folded, the step names and the timestamps in a column the eye can run down. The second is that the screen above the log should be built from the same record rather than from a summary that can disagree with it. Every browser check on this site prints the path, the page count and the commit it measured before it does anything else, because two of them once measured the wrong tree under the right name. A summary can be wrong about the record, and the record cannot be wrong about itself, so the summary has to say where it came from.
Key idea 6 of 7
Density is a kindness when attention is short
A developer under pressure is short on attention, not on data, the same as a dispatcher with a load to place. So the page has a hierarchy for scanning: what failed, at the top, in one line; what it affects, next; the detail, folded under it. Progressive disclosure is not hiding. It is order. And the page runs at two densities, comfortable and compact, because the floor is denser than the demo.
- 14
- seconds into the deploy that a green tree failed, on one file the runner could not follow
- 0
- errors the stylesheet build printed for a class it had never seen, while the type measured wrong at every width
- 10
- minutes the host keeps serving the old page after a deploy, so a fetch straight after one proves nothing
The dispatch cockpit’s fleet is 1,200 pixels wide because seven trucks and five factors staying in reach at once is the whole claim. A deploy list with every service, its last deploy, its state and its errors in reach at once is the same screen for a different person, and it wants the same things: every column sorts, every row opens, and nothing is collapsed behind a summary that might be wrong.
Key idea 7 of 7
Developers ask the same five questions, in the same order
Ship through a developer’s tools for a season and a pattern shows. Whatever went wrong, the questions are the same, and they come in the same order: What is live right now? What failed? What changed since it last worked? What depends on the thing that changed? Can I put it back safely? Each tool exists to answer one of them. The deploy log answers the first, the check the second, the diff the third, the history the fourth, and the branch the fifth, because a change that lives on one commit is a change you can revert with one.
That order is an information architecture, and the interface for a bad day should be arranged in it, top to bottom. It is also the order an operations floor asks in when a transaction stalls: what happened, what it affects, what can I safely do next. The person is different; the questions are not. Knowing the questions in order, from having asked them yourself, is the qualification for designing the answer.
The honest map, because a team finds it out either way: the branch, the commit, the pull request, the checks and a static deploy I run daily, on this site, and every incident above is mine. Containers, cloud infrastructure and observability across many services are the part I have read and not run, and the way in is the same as it was for the rest: ship something through it, and read what the log says.