Build for Humans
Design APIs, tools and docs around the people who use them.
Overview
Software is a human interface first. APIs, error messages, tooling and documentation are designed for the humans who depend on them, not for the machine.
Why
The people who depend on what you build leave evidence about how well it serves them, and most of that evidence is never filed as feedback. It shows up as a workaround in their code, a name they had to explain to a colleague, or three round trips to fix three problems that could have been reported together. So designing for humans is partly a matter of taste and mostly a matter of reading those signals. A workaround in a consumer's codebase is a bug report you never received, and the most useful thing you can do with it is treat the thing they worked around as the defect.
Standard
Return the complete set of problems rather than stopping at the first. Reserve throwing for a caller that asked for it, and make the asserting form a thin wrapper so the two can never disagree. A failure message names the thing, its valid values, and why the answer could not be guessed. Name things after what they do, and check whether the surrounding framework has already claimed the word. Treat a route-around as a diagnostic: when a consumer reimplements what you shipped, the thing you shipped goes on trial. Support partial adoption permanently. A consumer must always be able to take one piece and write ordinary code for everything else.
What This Forbids
- Validation that stops at the first error
- Names that describe how something was composed rather than what it does
- Reusing a core noun the host framework has already claimed
- Treating a consumer's workaround as non-compliance rather than as evidence
- All-or-nothing adoption, where taking one piece requires taking the rest
Examples
- Validation that returns every problem at once, so a check, an editor or a person sees them together, with a one-line asserting wrapper for callers that prefer an exception.
- A declaration file renamed after it collided with the host framework's own core noun: the same filename, two unrelated concepts. Fixed with a naming convention so it cannot recur.
- A consumer's three-line compensating branch, carrying a comment explaining that the shared answer was wrong for its case. It had been sitting there unreported; reading it settled the fix and reversed a default.
Counter Examples
- A component named for how it was assembled rather than what it did. Its real value was detecting which fields had actually changed, probably the most reusable piece of frontend code in the family, and the name concealed that for four months across three codebases.
- A shared package that could not be adopted in part, so taking one test helper meant declaring dependencies on vocabulary the consumer did not use anywhere. Of its fourteen files, eight imported nothing from the framework at all.
- A failure that reported the first missing credential and stopped, so an operator discovered three missing values across three attempts instead of one.
Lessons Learned
- A workaround in a consumer's codebase is a bug report you never received. Go looking for them; they are the highest-quality feedback available and nobody sends it.
- A name is an API. Checking whether the surrounding framework already owns a word costs a minute; renaming later costs a migration.
- The unit of adoption should equal the unit of dependency. Where it does not, the cost falls on exactly the people you were trying to help.
- Reporting problems in aggregate is not a convenience. It is the difference between one round trip and three, every time, for everyone.
Learned From
- ZothKitA naming collision with a host framework, a blocked adoption quantified file by file, and a consumer's compensating branch read as the defect report it was.
- DentraValidation that returns problems rather than throwing, and startup failures that name the setting, the valid values and the reason.
Related Principles· 1
Related Documents· 2
Referenced By· 4
Version History
- v0.1.0
Principle established with placeholder content.
- v0.2.0strengthened
Written from real experience. Added route-arounds as diagnostics, names as API, aggregate problem reporting, and permanent partial adoption.