Tao of Software Engineering

Tao

The Tao that can be told is not the eternal Tao. The name that can be named is not the eternal name.

Every engineer accumulates principles over time. Some are learned through failure, others through observation. This is a collection of mine.

These are not rules. They are heuristics shaped by experience, and they evolve as the craft evolves. What holds true today may shift tomorrow.

Principles

These principles guide how I think about systems, code, and the craft of software engineering.

Simplicity

Complexity is the default state of software. Simplicity requires deliberate effort and constant defence.

The simplest solution that meets the constraints is almost always the right starting point. Add complexity only when it earns its place.

In practice:

  • Avoid premature abstraction
  • Prefer obvious code over clever code
  • Reduce surface area
  • Question every dependency
  • Small modules, clear boundaries

Clarity

Code is read far more often than it is written. Clear code communicates intent without requiring comments.

Names matter. Structure matters. Consistency matters. If a system is hard to understand, it will be hard to maintain.

In practice:

  • Meaningful naming over brevity
  • Explicit over implicit
  • Consistent patterns across codebases
  • Document decisions, not mechanics
  • Predictable control flow

Resilience

Software fails. Resilient systems are designed to fail gracefully, recover predictably, and degrade without cascading.

Plan for failure at every boundary: network calls, user input, third-party services, and state mutations.

In practice:

  • Fail gracefully, not silently
  • Defensive boundaries at system edges
  • Observability over guesswork
  • Graceful degradation
  • Recovery without data loss

Intentionality

Every line of code is a decision. Every dependency is a liability. Every abstraction is a bet.

Build with purpose. Know why a pattern exists before adopting it, and be ready to remove it when it no longer earns its keep.

In practice:

  • Architecture as deliberate choice
  • Dependencies as liabilities
  • Prefer buying over building — until you must build
  • Remove what no longer earns its place
  • Technical debt as tracked decisions

Consistency

Consistent systems are predictable systems. When developers can anticipate how a codebase behaves, they make fewer mistakes.

Convention over configuration, standardised patterns, and clear interfaces reduce cognitive load across teams.

In practice:

  • One way to do things
  • Standardised interfaces and patterns
  • Convention over configuration
  • Consistent error handling
  • Uniform code style and structure

Modularity

Systems decompose along natural boundaries. Each module has a single responsibility and a well-defined interface.

Modular design enables parallel work, independent testing, and the ability to replace components without rewriting everything.

In practice:

  • Separation of concerns
  • Cohesion within, loose coupling between
  • Well-defined API surfaces
  • Replaceable components
  • Independent testability

Long-Term Thinking

Production systems outlive frameworks, teams, and original requirements. Design for the system you will have in three years, not just today.

Short-term speed often creates long-term drag. Invest in architecture, testing, and documentation proportionally to the system's expected lifetime.

In practice:

  • Architectural runway
  • Evolutionary design over upfront perfection
  • Testing as investment, not cost
  • Documentation for future maintainers
  • Deprecation and migration strategies