Minimizing complexity
Principle · Chapter 6
Why complexity matters
Section titled “Why complexity matters”High complexity in software:
- Causes schedule delays and cost overruns.
- Leads to unintended behavior or unanticipated application states.
- Creates security loopholes or hides security issues.
- Predicts lower quality attributes — worse maintainability, extensibility, reusability.
Essential vs. accidental difficulty (Fred Brooks)
Section titled “Essential vs. accidental difficulty (Fred Brooks)”- Essential difficulties are the core problems you are actually trying to solve — they cannot simply be removed. Teams spend most of their time here.
- Accidental difficulties are incidental to producing software and can be reduced — better languages, frameworks, design patterns, IDEs, and methodologies chip away at them.
- Architects work to minimize both. Key tools: KISS, DRY, information hiding, YAGNI, and SoC.
KISS — “Keep It Simple, Stupid”
Section titled “KISS — “Keep It Simple, Stupid””- Systems generally work best kept simple; don’t overcomplicate solutions. (Coined by aeronautical engineer Kelly Johnson; “Stupid” was never about a person.)
- Ways to apply KISS: eliminate duplication (DRY), remove unnecessary features (YAGNI), hide complexity and design decisions (information hiding), follow known standards and minimize surprises, refactor toward simpler methods/classes when you get the chance.
- Caveat — don’t oversimplify: if simplicity starts hurting required functionality or quality attributes, you’ve gone too far. “As simple as possible, but not simpler.”
DRY — “Don’t Repeat Yourself”
Section titled “DRY — “Don’t Repeat Yourself””- Reduce duplication in the codebase; duplication bloats the code, complicates maintenance, and risks inconsistent edits (the anti-pattern is a WET — “Write Everything Twice” — solution).
- Copy-and-paste programming is a common source of duplication. (Small reusable snippets are fine; wholesale copying of application logic is not.)
- Magic strings (literals duplicated across code — cache keys, messages, paths, URLs) are a classic violation; centralize them in a constant (or a resource file when translation/i18n matters).
- Eliminate duplication via the abstraction principle: pull shared logic into one place and route callers through it. Duplicated processes can be removed via automation (e.g. automating tests/builds — see DevOps practices).
- Don’t over-DRY: values or constants that are only coincidentally identical but represent distinct concepts should stay separate.
Information hiding
Section titled “Information hiding”- Modules should hide their implementation details from the rest of the system (D.L. Parnas, 1972). Callers interact only with a public interface and are shielded from internals.
- Benefits:
- Reduces complexity → improves maintainability (you don’t have to understand internals to use a module).
- Hides design decisions (API choice, data representation, algorithm) so that if a decision changes, the modifications stay localized.
- Forces you to deliberately decide what to expose vs. hide, rather than lazily exposing most of a class. The public interface is a contract; the implementation decides how it’s fulfilled. Supports the Law of Demeter (see orthogonal systems).
YAGNI — “You Aren’t Gonna Need It”
Section titled “YAGNI — “You Aren’t Gonna Need It””- From Extreme Programming. Implement functionality only when you actually need it, never because you foresee you might (Ron Jeffries).
- Avoids over-engineering — speculative features often end up unneeded or their requirements change; unwritten code is time and money saved for what you do need.
- Where YAGNI does not apply: it targets presumptive features, not work that keeps the system maintainable/modifiable later. A good, maintainable design is exactly what lets you add features later cheaply. Architecture decisions are made early and are costly to change, so experienced architects learn to spot the exceptions where a change should be made before it’s strictly needed.
Separation of Concerns (SoC)
Section titled “Separation of Concerns (SoC)”- A concern is an aspect of functionality the system provides. SoC partitions the system so each partition owns a separate concern, minimizing overlap.
- Decompose a big problem into smaller, manageable concerns → less complexity, less change effort, higher quality. Following DRY tends to produce SoC naturally.
- Applies at multiple levels:
- Architecture: separate UI, business, and infrastructure logic — e.g. the Model-View-Controller pattern.
- Class: distinct concerns (e.g. validating a credit card vs. updating inventory) shouldn’t live together — this ties into the Single Responsibility Principle.
- Language: HTML (content), CSS (presentation), JavaScript (behavior).
Citations
Section titled “Citations”- Software Architect’s Handbook (Packt, 2018), Ch.6 “Minimizing complexity”, pp. 418-436.