Skip to content

Complexity Cheat Sheet

The central challenge of software engineering.

TypeSourceReducible?Example
EssentialProblem domainNo — only redistributable”Users need 30 features”
AccidentalImplementation choicesYes — through better designSpaghetti code, poor abstractions

Essential complexity is the enemy you respect. Accidental complexity is the enemy you created.

— Fred Brooks, “No Silver Bullet” (1986)

SymptomDescriptionYou notice when…
Change amplificationSimple change touches many places”I just wanted to rename this field”
Cognitive loadMust know too much to proceed”Let me read 12 files first”
Unknown unknownsUnclear what to do or if it’ll work”I have no idea what this will break”
  1. Dependencies — You can’t understand or change code in isolation
  2. Obscurity — Important information isn’t obvious
SimpleEasy
Not intertwinedFamiliar, at hand
Objective propertyRelative to you
Opposite of complexOpposite of hard
Sustainable velocityFast start, slowing later

The trap: Choosing easy over simple feels productive but accumulates complexity.

Week 1: Easy choice → ship fast
Week 10: Easy choices → slower
Week 50: Easy choices → grinding halt

— Rich Hickey, “Simple Made Easy” (2011)

One module, one responsibility. Each piece should do one thing well.

Test: Can you describe what this module does without using “and”?

Hide details, expose essentials. Users of a module shouldn’t need to know how it works.

Test: Can you change the implementation without changing callers?

Self-contained pieces with clear boundaries.

Test: Can you understand this module without reading others?

Deep ModuleShallow Module
Simple interfaceComplex interface
Powerful functionalityLittle functionality
Hides complexityExposes complexity
Worth the abstraction costAbstraction adds overhead

“The best modules provide powerful functionality with simple interfaces.” — John Ousterhout

MetricGoalMeaning
CouplingLowModules don’t depend on each other’s internals
CohesionHighRelated things stay together

Loose coupling: Change one module without changing others.

High cohesion: Everything in a module serves the same purpose.

  • Classes: < 100 lines
  • Methods: < 5 lines
  • Parameters: ≤ 4
  • Controllers: instantiate one object

Rules are for breaking — but know when and why.

PrincipleMeaning
KISSKeep It Simple, Stupid
YAGNIYou Aren’t Gonna Need It
DRYDon’t Repeat Yourself (but don’t over-abstract either)
  • “Let me explain how this works…”
  • “Don’t touch that, it’s fragile”
  • “Only Alice understands that code”
  • “We’ll clean it up later”
  • Deep inheritance hierarchies
  • God objects / god functions
  • Circular dependencies
  1. Can I extend without modifying? (Open-Closed)
  2. Where does this naturally belong?
  3. Am I adding dependencies?
  4. Will future-me understand this?
  1. What changed recently?
  2. Can I isolate the problem?
  3. What are the dependencies?
  4. What assumptions am I making?
  1. What’s the smallest useful change?
  2. Can I add tests first?
  3. Am I solving a real problem or a hypothetical one?
  4. Is now the right time? (Boy Scout Rule vs. Yak Shaving)

Every system has a complexity budget. Spend it on essential complexity.

Spend onAvoid spending on
Domain modelingClever abstractions
Error handling that mattersHandling impossible cases
Performance where measuredPremature optimization
Flexibility where neededFlexibility “just in case”
  • Is this complexity essential or accidental?
  • Am I solving today’s problem or tomorrow’s maybe-problem?
  • Would a junior engineer understand this?
  • What’s the cost of simplifying later vs. now?

Fighting complexity requires effort. That effort can itself introduce complexity.

Traps:

  • Over-engineering simple things
  • Abstracting too early
  • DRY at the cost of clarity
  • Frameworks for 100-line scripts

Resolution: Bias toward simplicity. The cost of adding flexibility later is usually less than the cost of maintaining unused flexibility now.

“Controlling complexity is the essence of computer programming.” — Brian Kernighan

“Simplicity is prerequisite for reliability.” — Edsger Dijkstra

“There are two ways of constructing software: One way is to make it so simple that there are obviously no deficiencies. The other way is to make it so complicated that there are no obvious deficiencies.” — C.A.R. Hoare

“The purpose of software engineering is to control complexity, not to create it.” — Pamela Zave

  • Reasoning — Cognitive biases that create accidental complexity
  • Orchestration — Complexity in agent coordination
  • Thinking — Systems thinking helps manage complexity
  • Specification — Specification defines abstraction boundaries
  • Testing — Testing as complexity management
  • Fred Brooks — No Silver Bullet (1986)
  • John Ousterhout — A Philosophy of Software Design (2018)
  • Rich Hickey — Simple Made Easy (2011 talk)
  • Sandi Metz — Practical Object-Oriented Design (2012)
  • Dave Farley — Modern Software Engineering (2021)