Why I Default to Simple Tools and Boring Architecture

By Ramde 3 min read (536 words)
A practical look at minimizing accidental complexity in software architecture, choosing boring technology, and why simpler systems yield higher uptime and happiness.

Early in my engineering career, I often equated sophistication with competence. If a problem could be solved with a simple relational database table and an index, I wondered whether we should instead reach for an event-sourced stream, a distributed graph store, and multi-region replication.

Over time, having operated production infrastructure across peak traffic spikes, network partitions, and 3 AM alerts, my perspective inverted completely:

The best code is the code you never had to write, and the best infrastructure is the one that has so few moving parts that failure modes are self-evident.

The Cost of Accidental Complexity

Fred Brooks introduced the distinction between essential complexity (the inherent difficulty of the domain problem itself) and accidental complexity (the friction introduced by our chosen solutions and tools).

Every distributed system you introduce extracts a compounding tax:

  1. Cognitive overhead: Engineers must understand quorum mechanics, consensus edge cases, and consistency boundaries.
  2. Operational friction: Backups, observability, log aggregation, and upgrades become multi-step rituals rather than turnkey automation.
  3. Failure amplification: More network boundaries mean more timeouts, cascading retries, and thundering herd possibilities.

Choosing Boring Technology

Dan McKinley’s seminal essay Choose Boring Technology introduced the concept of “innovation tokens.” Every engineering organization only has a handful of these tokens to spend. Spending them on your database layer or messaging broker when your actual business domain is e-commerce or logistics is usually a misallocation of risk.

Boring technology has superpowers:

  • Known unknowns: The failure modes are well-documented on Stack Overflow and in 15-year-old mailing list archives.
  • Battle-tested tooling: Profilers, backup scripts, and metrics collectors are mature and rock-solid.
  • Predictable runtime characteristics: Memory footprints and GC pauses are well-understood.

Pragmatic Principles for High Leverage

When architecting a new service or refactoring an existing system:

  1. Start with SQLite or Postgres. You can scale remarkably far on a single vertical Postgres instance with proper indexing, connection pooling, and read replicas before needing horizontal sharding.
  2. Prefer explicit interfaces over magical frameworks. Code is read ten times more often than it is written. Magic saves minutes during scaffolding but costs days during incident triage.
  3. Keep the client lean. Moving state machines and business logic to the server reduces latency variance across heterogeneous mobile devices and slow cellular networks.
  4. Make observability a first-class citizen. Structured logs with correlation IDs, clean metrics histograms, and minimal distributed tracing will save you countless hours.

Simplicity is not a lack of ambition; it is the ultimate expression of craft.