The Philosophy of Error-Aware Design

Published:
Translations:Русский
Comments:Telegram

The Teapot That Punishes You

A masochist’s teapot has the spout and handle on the same side:

You will burn yourself because it makes errors inevitable.

This is the software equivalent of masochist’s teapot:

function formatName(user) {
  // What if user is undefined? 
  // What if firstName is null?
  // What if lastName is empty string?
  return user.firstName + ' ' + user.lastName;
}

It invites mistakes. And just like with the teapot, the fault lies not with the user, but with the design.

So I propose a new type of design thinking: error-aware design.

Error-Aware ≠ Error-Handling

Most engineers think about errors like this:

  1. Write code
  2. Add error handling
  3. Document edge cases

Error-aware design flips this:

  1. Design out preventable errors
  2. Make remaining errors obvious
  3. Handle what’s left gracefully

The Cost of Bad Design

That innocent-looking API is costing you:

  1. Debugging time: “Why did this succeed but fail later?”
  2. Integration headaches: “But the docs said…”
  3. Production fires: “We didn’t know that could happen”

Core Principle: The Error That Never Was

The best error handling is eliminating entire classes of errors:

  1. Make invalid states unrepresentable. Like a teapot that physically can’t burn you.
  2. Fail fast and loud. Like a teapot that screams when overfilled.
  3. Guide users to success. Like a teapot with an obvious fill line.
// This is Typescript instead of JavaScript
interface User {
  firstName: string;
  lastName: string;
}

function formatName(user: User): string {
  return `${user.firstName} ${user.lastName}`;
}

Up Next: The Toolkit

The next post arms you with concrete patterns of error-aware design. In good design, the right way should be the only way.

Challenge: Look at your last production incident. Could it have been designed away at the API level?

  1. The Philosophy of Error-Aware Design