Less but better

Dieter Rams said it about industrial design. But it applies perfectly to backend architecture.

Every additional service, every extra queue, every new database - they all add cognitive load. The system becomes harder to reason about, harder to debug, harder to operate. The aesthetics of a system are not separate from its function. A beautiful system is one you can hold in your head.

I’ve been thinking about this a lot while working on distributed architectures. The pressure is always to add: add a cache layer, add a message queue, add a service mesh, add observability tooling. Each addition solves a real problem. But the accumulation creates a new problem - complexity.

The shape of good systems

Good systems have a shape you can draw on a whiteboard in under two minutes. If you can’t sketch your architecture quickly, it’s too complex. Not necessarily wrong - but worth questioning.

The best systems I’ve worked with share common traits:

  • Few moving parts - each component earns its place
  • Clear data flow - you can trace a request from entry to response without getting lost
  • Obvious failure modes - when something breaks, you know where to look
  • Boring technology - Postgres, Redis, Go, nginx. Proven, well-understood, well-documented

This doesn’t mean simple systems. It means systems where the complexity is essential, not accidental. Every piece of complexity should be traceable to a real requirement.

Against premature abstraction

The impulse to abstract early is strong. We see two similar things and immediately reach for a common interface. But premature abstraction is worse than duplication.

Three similar functions are better than one function with three boolean parameters. Duplication is local and obvious. Bad abstractions are global and hidden. You can always extract a pattern later when you truly understand it. You can rarely undo a bad abstraction without rewriting everything that depends on it.

Build concrete things first. Abstract only when the pattern is clear and stable.