Reference document · canonical vocabulary
Glossary
The canonical language of this course. Every lesson uses these terms in these senses; when a term is used loosely elsewhere, the resolution chosen here wins. Each entry carries the lesson that teaches it, and an Avoid line naming the words that blur it.
Structure and complexity
The vocabulary for talking about shape: what makes code hard to change, and how you measure it.
Coupling
How much one module depends on the internals or behavior of another. Low coupling means a module can change without forcing changes in its neighbors.
Avoid: tight coupling, entanglement, "spaghetti"
Taught in: lesson 0001
Cohesion
How strongly the elements inside one module belong together — whether they serve one purpose. High cohesion means a module has one reason to exist.
Avoid: god class, grab-bag module, "utils" folder
Taught in: lesson 0001
SRP — Single Responsibility Principle
A module should have one reason to change. The reason, not the responsibility, is the unit of design.
Avoid: "does one thing" (too vague), "one method" (too literal)
Reason to change
The concrete force (a new requirement, a new technology, a new policy) that would make you edit a module. Design units of code around single reasons to change.
Avoid: "responsibility" (fuzzier), "feature" (too coarse)
Taught in: lesson 0006
Change amplification
The number of places you must edit to make one logical change. It is the most direct measurement of design debt.
Avoid: "shotgun surgery" (the smell it produces)
DRY — Don't Repeat Yourself
Every piece of knowledge should have a single, unambiguous representation in the system. DRY targets knowledge, not text: two identical lines can encode different knowledge.
Avoid: copy-paste, WET ("write everything twice")
False DRY
Deduplication of text that encodes two different pieces of knowledge. The two copies look identical today because the facts happen to coincide; merging them couples parties that will diverge, and the first divergence has to be bent into the shared shape.
Avoid: “removing duplication” (when the duplication was never knowledge)
Rule of three
Wait for the third occurrence before extracting an abstraction. At one occurrence there is no pattern; at two the shape is a guess; by three the variation is visible and the change-rent of the copies is real.
Avoid: “don't repeat yourself” read as “never type it twice”
KISS — Keep It Simple
Prefer the solution with the least complexity that meets the requirement. Simplicity is a design target, not a default.
Avoid: cleverness, over-engineering, speculative generality
Taught in: lesson 0002
YAGNI — You Ain't Gonna Need It
Do not build capability you have no current evidence of needing. Unused generality is paid for forever and used never.
Avoid: speculative features, "just in case" hooks
Speculative generality
Parameters, hooks and layers built for cases that do not exist. It is paid for on every read of the current code and used by nobody. The counter-test: does the generality make today's case simpler? (Ousterhout)
Avoid: “future-proofing”, “extensible by design”
Taught in: lesson 0030
Abstraction
A simplified interface that hides the complexity of what lies behind it. A good abstraction is deeper than the sum of its parts.
Avoid: leaky abstraction, façade without substance
Deep module
A module with a small, simple interface hiding substantial implementation. The opposite of a shallow module, which exposes most of its work through the interface. (Ousterhout)
Avoid: "thin layer" (a shallow module by another name)
Information hiding
Keeping design decisions that are likely to change inside a module, invisible to its users.
Avoid: encapsulation (usually used for the same idea, but includes runtime state protection)
Boundary
The edge of a module where one set of concerns hands off to another. Boundaries are where you enforce invariants, translate representations, and choose failure behavior.
Avoid: "layer" (a boundary is a seam, a layer is a convention)
Seam
A place where you can alter behavior without editing the code in question — a hook, an interface, a dependency-injection point. Seams make change and testing possible.
Avoid: "extension point" (a seam with a designed-for purpose)
Objects and the domain
The words for the things the software is actually about, and the shapes that protect them.
Domain
The problem space the software exists to serve: the rules, entities, and workflows that are true regardless of technology.
Avoid: "business logic" (if you must, mean the same thing)
Taught in: lesson 0011
Domain invariant
A rule the domain cannot violate, enforced by the domain itself — not by callers' good behavior. Example: an order can never be confirmed twice.
Avoid: business rule (weaker: often means "policy")
Taught in: lesson 0011
Value object
An immutable object whose identity is its value: two instances with equal fields are interchangeable. Safe to share, trivial to test.
Avoid: mutable DTOs, "entity-lite"
Taught in: lesson 0012
Entity
An object with a continuous identity across changes, tracked over time.
Avoid: "model" (overloaded), "record"
Taught in: lesson 0012
Aggregate
A cluster of domain objects treated as one unit for changes, with a single root that guards the invariants of the whole cluster.
Avoid: aggregate root (the root is one part; the aggregate is the cluster)
Taught in: lesson 0012
Repository
A domain-facing collection-like interface for retrieving and persisting aggregates, hiding the storage technology behind it.
Avoid: "DAO" (data-oriented, leaks storage thinking), repository leaking query APIs
Taught in: lesson 0013
Unit of work
The object that owns a transaction's boundary: what is written together, committed together, and rolled back together. Repositories operate inside it; the domain never sees it.
Avoid: save() scattered through the domain, autocommit-per-call
Taught in: lesson 0013
Law of Demeter
A method should only talk to its immediate neighbors: itself, its own fields, its arguments, objects it creates, and the direct members of its own collection. No chain-walking into strangers.
Avoid: "train wrecks" like a.b().c().d(), the principle of least knowledge
Taught in: lesson 0003
Tell, Don't Ask
Ask an object to do something for you instead of interrogating its state and doing it yourself. The natural companion of the Law of Demeter.
Avoid: getter chains, "ask, then act" sequences
Taught in: lesson 0003
Train wreck
A chain of calls that walks through objects the caller does not own — order.customer.address.city. The caller now depends on the internal geography of three objects, and any restructuring of them breaks it.
Avoid: “fluent interface” (a builder returning self is not a wreck)
Taught in: lesson 0003
Composition
Building behavior by holding objects and delegating to them, rather than inheriting from them.
Avoid: "has-a" (shorthand only); composition does not mean "put everything in one class"
Taught in: lesson 0007
Strategy pattern
Extracting a varying behavior behind an interface so the behavior can be swapped at runtime without touching its caller.
Avoid: "policy" (same shape, different name)
Higher-order function
A function that takes or returns a function. In Python it is the cheapest strategy interface there is: no protocol, no class, no registration.
Avoid: a one-method class used once
Taught in: lesson 0016
Protocol
A structural interface in Python: an object conforms to it by having the right methods, no inheritance required.
Avoid: "duck typing" (untyped protocols), abstract base class (nominal, heavier)
Taught in: lesson 0017
Dependencies and boundaries
Who is allowed to know about whom, and where that rule is written down.
Dependency direction
Which way arrows point between modules. Well-directed dependencies point inward: domain code depends on nothing; infrastructure depends on domain.
Avoid: upward dependencies, dependency cycles
Taught in: lesson 0009
Port
An interface on the edge of a module that defines what the module needs from the world (driven port) or offers to it (driving port). The domain defines the ports; the world provides the adapters.
Avoid: interface owned by the infrastructure
Adapter
Code that translates between a port (our interface) and a concrete external thing — a database, an API, a file format — so the external thing never touches the domain.
Avoid: wrapper (when the translation is cosmetic), leaky adapter
Composition root
The single place — usually one function near the program's entry point — where every concrete adapter is constructed and injected. Nothing else in the system names a technology.
Avoid: service locator, ambient container, “wiring everywhere”
Anti-corruption layer
An adapter at the edge of a bounded context that translates another context's vocabulary into this one's, so a foreign model never leaks inward. (Evans)
Avoid: “just import their types”, a shared DTO package
Taught in: lesson 0036
Bounded context
The boundary within which one model and one vocabulary are consistent. The same word may mean different things in two contexts — and that is the signal to keep them apart.
Avoid: “the one true model”, a global schema
Taught in: lesson 0036
Shared kernel
The small, stable set of concepts two contexts genuinely share and agree to change together. Integration chosen on purpose, not integration by accident.
Avoid: a “core” or “common” package that only grows
Taught in: lesson 0036
Control coupling
One module steering another's internal path with a flag or mode argument, so the caller must understand the callee's branches. The usual fix is to inject the behaviour instead.
Avoid: boolean parameters, mode="..." strings
Taught in: lesson 0016
Global coupling
Dependence on shared, reachable-from-anywhere state or services (singletons, module globals, ambient context). Changes to one consumer affect all consumers — silently.
Avoid: "ambient state", hidden global dependencies
Taught in: lesson 0019
Shared state
State that more than one component reads or writes. The owner is whoever is responsible for its correctness; unowned shared state is the source of most concurrency bugs.
Avoid: "global state" (a species, not the genus)
Taught in: lesson 0020
Fitness function
An automated check that an architectural property still holds — a test that fails the build when a dependency arrow, a layer rule, or a latency budget is violated. (Ford, Parsons & Kua)
Avoid: a README rule, a convention nobody enforces
Taught in: lesson 0022
Runtime, failure and evolution
What the system does when the world misbehaves, and how it changes without stopping.
Fail-fast
Failing as close to the cause as possible, loudly and immediately, instead of letting a bad value travel and corrupt far from its origin.
Avoid: silent None, ignored errors, deferred exceptions
Event-driven architecture
Components communicate by publishing and consuming events rather than by calling each other directly, so producers don't know their consumers.
Avoid: "event-based" (fine), "message-driven" (a sibling, not the same)
Taught in: lesson 0025
Message bus
A channel that routes events or commands from publishers to subscribers, decoupling the two sides.
Avoid: "event bus" (a species of message bus)
Taught in: lesson 0025
Idempotent
An operation that produces the same end state whether it runs once or five times. Idempotence is what makes at-least-once delivery survivable and retries safe.
Avoid: “safe to retry” (true only once the operation is idempotent)
Idempotency key
A caller-generated identifier for one intent, reused across every retry of that intent, so the receiver can return the first answer instead of acting twice.
Avoid: a fresh id per attempt (which buys nothing)
Taught in: lesson 0032
Dead-letter queue
Where a message goes after its handler has failed its allotted attempts. It only counts as a design if a human actually watches it.
Avoid: infinite retries, silent drops
Taught in: lesson 0031
Correlation id
An identifier attached to an event and to every log line produced while handling it, so one workflow can be followed across handlers that share no call stack.
Avoid: “grep the timestamps”
Taught in: lesson 0031
Eventual consistency
A guarantee that replicas converge if writes stop — with no promise about what a read sees in the meantime. Useful when a stale answer is cheap; dangerous when the reader will act on it as if it were current.
Avoid: “inconsistent” (it is a guarantee, not the absence of one)
Taught in: lesson 0032
Tolerant reader
A consumer that requires only the fields it uses and ignores everything else, so producers can add fields without a coordinated release.
Avoid: strict schema validation on inbound events
Taught in: lesson 0033
Characterization test
A test that records what code currently does, not what it should do — written to lock behaviour before restructuring unfamiliar or AI-generated code. (Feathers)
Avoid: “I'll refactor first and test after”
Strangler fig
A pattern for replacing a system incrementally: route new behavior around the old implementation, growing the new one until the old one can be deleted.
Avoid: "big bang rewrite" (the anti-pattern)
Taught in: lesson 0035
Branch by abstraction
A safe transition technique: insert an abstraction over a component, migrate all users to it, then swap the implementation behind it.
Avoid: long-lived feature branches (the coordination cost is the point)
Taught in: lesson 0035
Expand / contract
A four-step data migration — add the new field and write both, backfill, switch reads, then stop writing and drop the old — so a rename becomes four reversible deploys instead of one irreversible one. Also called parallel change.
Avoid: the one-step rename, the “quick” migration
Taught in: lesson 0035
Feature flag
A runtime switch that separates deploying code from releasing behaviour, so rollback is a flip rather than a revert. A flag that outlives its transition becomes configuration debt.
Avoid: permanent flags, flags used as a state model
Taught in: lesson 0035
Config graveyard
The accumulated settings nobody has ever varied: knobs added “just in case”, each one documented, validated, tested and combinatorially possible — for no measured variation at all.
Avoid: “configurable”, “flexible” (as unexamined virtues)
Taught in: lesson 0029
Trade-off
A decision between forces that cannot both be maximized. The craft is making the trade-off explicit, deliberate, and reversible — not avoiding it.
Avoid: "best practice" (implies no cost), "silver bullet"
Initiative leadership
The vocabulary for turning an ambiguous brief into measurable system and team decisions.
Product outcome
An observable change in user or business behaviour, stated with a baseline, target, cohort, and time boundary. It preserves freedom to change the solution while holding the initiative accountable for its effect.
Avoid: feature, deliverable, launch date, “ship the portal”
Taught in: lesson 0039
Assumption map
A map of beliefs by impact if false and strength of evidence, often grouped as value, usability, feasibility, and viability. The high-impact, weak-evidence corner becomes the discovery priority.
Avoid: risk list with no evidence axis, brainstorm vote
Taught in: lesson 0040
User story
A placeholder for a conversation about one user's need and the behaviour that may satisfy it. The sentence alone is not a requirement; examples provide confirmation.
Avoid: mini-specification, task disguised as user value
Taught in: lesson 0042
Story map
A two-dimensional product map: user activities run left to right as a journey, while alternatives and detail run downward. Horizontal lines cut coherent release or learning slices across the journey.
Avoid: flat backlog, dependency graph, feature inventory
Taught in: lesson 0042
Vertical slice
A narrow piece of observable behaviour that crosses the necessary technical layers end to end. It is small by cohort, rule, variation, or quality threshold—not hollowed into disconnected component tasks.
Avoid: “backend story”, schema-only milestone, horizontal layer
Taught in: lesson 0042
Architecture driver
A functional need, quality attribute, constraint, or risk important enough to shape system structure. It distinguishes between plausible designs; most requirements do not.
Avoid: every requirement, technology preference, generic “best practice”
Taught in: lesson 0043
Quality-attribute scenario
A measurable statement of how a system must respond: source, stimulus, environment, affected artifact, response, and response measure. It turns “fast” or “available” into design and test input.
Avoid: vague non-functional requirement, unmeasured “-ility”
Taught in: lesson 0043
Blast radius
The people, operations, data, components, or requests exposed when a change or failure goes wrong. Reducing blast radius makes learning and reversal cheaper.
Avoid: impact (too vague), server count alone
Architecture Decision Record
A short, durable record of one consequential decision: context, forces, credible options, decision, consequences, dissent, and a revisit trigger. A later decision supersedes rather than edits it.
Avoid: architecture novel, meeting transcript, rewritten history
Taught in: lesson 0046
Walking skeleton
The thinnest production-shaped end-to-end implementation: real build and deployment, representative boundaries and storage, telemetry, and tiny behaviour. It proves the delivery path before behavior fills it.
Avoid: throwaway prototype, complete infrastructure phase
Taught in: lesson 0047
Decision rights
An explicit statement of who makes the final call in a decision domain and whose advice they must seek. It enables broad collaboration without turning consensus into a veto.
Avoid: RACI for every task, authority left implicit
Work in progress
Work the team has started but not finished into evidence. Limiting it reduces queues, context switching, and elapsed time; swarming values system flow over individual utilization.
Avoid: everyone must stay busy, one item per specialist
Taught in: lesson 0048
Rollout gate
A decision boundary between exposure stages with explicit entry evidence, observation window, advance threshold, stop threshold, decider, and reversal. It turns launch into a controlled sequence.
Avoid: “looks good”, arbitrary percentage ramp, calendar-only gate
Taught in: lesson 0049