Glossary
- Adapter
- The code that implements a port for one technology: local disk, S3, Google Cloud Storage. The adapter depends on the port, and the core does not know which adapters exist.
- Ports and adapters: one core, many backends
- Adapter
- A wrapper that makes an object fit an interface it was not written for. A decorator keeps the interface and adds behavior; an adapter changes the interface.
- Design patterns: named shapes you already use
- ADR
- Architecture Decision Record: a short file with Title, Status, Context, Decision and Consequences (Michael Nygard, 2011).
- Architecture decision records: writing down the why
- Aggregate
- A cluster of objects changed as one unit, through one root. Its invariants, the rules that must always hold, are checked inside it.
- DDD building blocks: inside one context
- Allowlist
- A rule that forbids everything except what it names. Known exceptions are listed one by one, so a new violation cannot slip in unnoticed.
- Fitness functions: decisions that check themselves
- Anti-corruption layer
- A translation layer in the downstream context that rewrites the upstream model in its own terms, so the rest of its code never sees the foreign words.
- Bounded contexts and context maps
- Architect Elevator
- Hohpe's image: the architect rides between the IT engine room and the executive penthouse, and keeps the two connected.
- One decision, three audiences
- Architecture
- The decisions that are hard to change later and shape everything else: how the system is split, where state lives, how parts talk.
- Software architecture: the decisions that are expensive to change
- Assumption
- The rules allow assumptions about technologies you do not know well, as long as you define them clearly when you present. Bad assumptions, never checked with the customer, earn a thumbs down.
- Your first kata: a whole design in 15 minutes
- Asynchronous job
- The caller gets an answer before the work is done. The work runs later, from a queue such as Sidekiq's in Redis, and its errors arrive by another path or not at all.
- Sync calls vs async jobs
- At-least-once
- A message is never lost once the broker accepts it, but may arrive twice. The consumer confirms only after the work is done, and dedupes.
- Messaging: queues, delivery guarantees and dead letters
- Authentication
- Checking who the caller is: a password once, then a token on each request.
- Gateways, tokens and SSO
- Authorization
- Deciding what this caller may do on this data. It needs the data's rules, so the owner of the data does it.
- Gateways, tokens and SSO
- Backfill
- Filling the new shape for rows written before it existed. Inside the migration, as a background job in batches, or not at all if the code reads "empty" safely.
- Schema and data migrations
- Backward-compatible change
- Old consumers keep working without a change on their side: a new endpoint, a new optional field. Removing, renaming or retyping a field, or giving it a new meaning, is a breaking change.
- API design and versioning
- Blocking question
- A question that must be answered before the design is accepted. Mark it, so the author finds it among the small ones.
- Reviewing a design: scenarios, doors, failures
- Boundary
- The line between what your team owns and what others own. You can change what is inside it, and you have to agree with another team or company to change what is outside.
- The context diagram: your system as one box
- Bounded context
- A boundary inside which every term has exactly one meaning. Often one service or one team.
- Bounded contexts and context maps
- Bulkhead
- Separate pools, queues or limits per kind of work, so one kind can fill up without starving the others. Named after the walls in a ship's hull.
- Resilience: stop one failure from spreading
- C4
- Four zoom levels for diagrams: Context, Containers, Components, Code. You rarely need to draw the fourth.
- The context diagram: your system as one box
- Capability negotiation
- The server lists what it supports, and the client checks the list before it uses a feature. One client then works with servers of different ages.
- API design and versioning
- Chain of responsibility
- A request passes through a list of handlers in order. Each may change it, pass it on, or stop it.
- Design patterns: named shapes you already use
- Characteristic
- A quality the system must have that is not a feature: latency, throughput, availability, security… Often called an "-ility".
- Architecture characteristics: choosing the top three
- Circuit breaker
- After too many failures, stop calling a dependency for a while and fail at once. Then let a few trial calls through to see if it healed.
- Resilience: stop one failure from spreading
- Cohesion
- How closely the parts of one module belong to the same job. Low cohesion: a module that does two unrelated things.
- Coupling and cohesion in a checkout service
- Compensating action
- A new action that undoes the effect of an earlier one: release the stock, refund the card. It differs from a rollback because other services may already have seen the first step.
- Outbox and sagas: when one change spans two systems
- Competing consumers
- Several consumers read from one queue, and each message goes to only one of them. More consumers handle more messages per second, but messages can finish out of order.
- Messaging: queues, delivery guarantees and dead letters
- Composition root
- The one place allowed to know both an interface and its implementation, to wire them together. Here, the Hilt
DataModule. - Layers: imports only go one way
- Conformist
- The downstream context (the one that receives) adopts the upstream model as it is, because it has no say or translating costs too much.
- Bounded contexts and context maps
- Consequences
- Everything that follows from the decision, the good and the bad. If you listed no downside, look again (first law).
- Architecture decision records: writing down the why
- Consumer-driven contract
- Each consumer writes down the part of a message or API it actually reads, and the producer runs those expectations in its own CI. The Pact tool implements this pattern.
- Testing strategy
- Container (C4)
- Something that must be running for the system to work, as one process or one data store: a server app, a database, a browser app, a worker.
- Containers: what actually runs
- Container diagram
- C4 level 2. The containers inside your system, what technology each one is, and how they talk.
- Containers: what actually runs
- Contract test
- A test that checks a double against the real thing it stands for. Fowler: "These check that all the calls against your test doubles return the same results as a call to the external service would."
- Testing strategy
- Copy
- Data you keep but do not own. It can go stale, so you must know who updates it, and you never edit it yourself.
- Who owns the data
- Core
- What makes you different from competitors. It is complex and changes often, so you build it in-house with your best people.
- Core, supporting and generic subdomains
- Coupling
- How much a module must know about another to work. More coupling means a change in one forces a change in the other.
- Coupling and cohesion in a checkout service
- CQRS
- Command Query Responsibility Segregation: one model to change data, another to read it. Martin Fowler credits Greg Young with describing it. It does not require event sourcing.
- CQRS and event sourcing
- Data flow diagram
- Boxes for processes and stores, arrows for data, outside parties drawn apart. The map a threat model is done on.
- Threat modeling
- Dead set
- Where Sidekiq keeps a job after its last failed retry, so a person can look at it. A job can opt out and be dropped instead.
- Sync calls vs async jobs
- Dead-letter queue (DLQ)
- The queue where the broker puts messages that failed too many times. Someone must get an alert, read each message, and decide what to do with it.
- Messaging: queues, delivery guarantees and dead letters
- Decorator
- A class that implements the port and wraps other implementations of the same port, adding one behavior such as copying every upload to a second store.
- Ports and adapters: one core, many backends
- Dependency rule
- Here: UI depends on domain, and domain depends on data. No import points up, so the lowest layer knows least about the others.
- Layers: imports only go one way
- Deployment diagram
- Where container instances run, on which machines or clusters, for one environment.
- Deployment: boxes on machines
- Deprecation
- Saying that something will go away while it still works. Then count who still calls it, and remove it on a date (the sunset).
- API design and versioning
- Design review
- Reading a proposal to find the decisions that are expensive to change, like a default behavior other teams build on.
- Reviewing a design: scenarios, doors, failures
- Directory placement
- A lookup table records where each key lives, instead of computing it from a hash. Easy to add a node to, but the table itself must always be readable.
- Scaling data
- Drift
- The code slowly moving away from a decision, one reasonable-looking change at a time.
- Fitness functions: decisions that check themselves
- Driving
- The few characteristics that shape the design. Keep this list as short as you can, three at most.
- Architecture characteristics: choosing the top three
- Dual write
- Your code writes to two stores one after the other, with nothing making both succeed or both fail.
- Consistency across several stores
- Dynamic coupling
- Happens at run time: a gRPC call, a message on a queue. No import links the two sides, so grep cannot see it.
- Coupling and cohesion in a checkout service
- Dynamic diagram
- A C4 view of one use case at runtime: the same boxes as the static diagrams, with numbered steps.
- Following one request end to end
- End-to-end test
- The built system, driven the way a user would. Slow and broad, so keep a few that prove the pieces are wired together.
- Testing strategy
- Engine room
- The floor where code and infrastructure live. People there need the mechanism, so they can build on it.
- One decision, three audiences
- Entity
- An object with an identity that lasts while its attributes change. Leo stays the same pet when his name is corrected or his birth date fixed.
- DDD building blocks: inside one context
- Event
- A fact that happened, named in the past tense and never edited:
OrderCancelled. The store keeps events in order and numbers them per stream. - CQRS and event sourcing
- Event store
- An append-only log of events, one stream per aggregate. Replaying a stream gives the aggregate's current state.
- CQRS and event sourcing
- Event-driven
- Parts react to events instead of calling each other directly. Good for decoupling, harder to trace and test.
- Architecture styles
- Expand / contract
- Also called parallel change. Add the new shape next to the old one, move readers and writers over, remove the old shape last. The three steps often ship in three releases.
- Schema and data migrations
- External system
- A system you talk to but don't own or run: an SSO provider, a mail server, another organization's server.
- The context diagram: your system as one box
- Fail open, fail closed
- What a check does when it cannot run. Fail open lets the request through. Fail closed refuses it.
- Quality scenarios: making "secure" testable
- Failure mode
- One specific way it breaks: what fails, what the user sees, how it recovers.
- Reviewing a design: scenarios, doors, failures
- Fan-out
- One event that starts many jobs: one post copied into every follower's feed, and sent to every follower's server.
- Following one request end to end
- Fan-out
- Turning one job into many: here, one delivery job per remote inbox instead of one for the whole post.
- Sync calls vs async jobs
- Feature flag
- A switch that turns behavior on per deployment or per tenant. It lets you undo a rollout, as long as turning it off leaves no new data behind.
- Reversible decisions: one-way and two-way doors
- Fitness function
- An objective check of one architecture characteristic. Most are automated and pass or fail the build. The book also allows manual ones, which need a human.
- Fitness functions: decisions that check themselves
- Generic
- A problem everyone has and someone already solved well. You buy it or adopt open source.
- Core, supporting and generic subdomains
- Graceful degradation
- The app keeps serving what still works and leaves out what does not. The page shows no recommendations, and checkout still works.
- Resilience: stop one failure from spreading
- Hit / miss
- A hit finds the answer in the cache. A miss pays for the slow call, then usually stores the result.
- Caching
- Hop
- One step where the request crosses into another part: another layer of code, or another container over the network, which is slower and can fail.
- Following one request end to end
- Hot path
- The code every request runs before it can answer. A slow call there makes the user wait.
- Following one request end to end
- Idempotency key
- A unique value the client sends with a request, and sends again with every retry of it, so the server can spot the repeat.
- Failure: timeouts, retries, idempotency
- Idempotent
- Doing it twice has the same effect as doing it once. Setting a status to deleted twice leaves it deleted. Adding 10 € to a balance twice adds 20 €.
- Failure: timeouts, retries, idempotency
- Image
- A packaged build, like
ghcr.io/mastodon/mastodon. The same image can start several different processes, so one image can give several containers. - Containers: what actually runs
- Interface segregation (I)
- A caller should not depend on methods it does not use. A wide interface forces every implementation to fill in methods nobody calls.
- SOLID: five principles, read on real code
- Invalidation
- Removing or refreshing an entry because the source changed. Someone has to know that it changed.
- Caching
- Isolation level
- What tenants share: same tables, same server but own databases, or own deployment. More isolation costs more to run.
- Multi-tenancy: whose data is this?
- Kata
- A practice brief: a description, the users, the requirements, some extra context. Small enough to sketch in one sitting.
- Your first kata: a whole design in 15 minutes
- KEP
- Kubernetes Enhancement Proposal: the design doc a change to Kubernetes goes through, with a fixed template and a status (provisional, implementable, implemented).
- Reviewing a design: scenarios, doors, failures
- Layer
- A group of code with one kind of job: draw the screen, apply the rules of the app, store and fetch the data.
- Layers: imports only go one way
- Liskov substitution (L)
- Any implementation of an interface must work wherever the interface is expected. If one implementation throws where others work, callers have to know which one they got.
- SOLID: five principles, read on real code
- Liveness vs readiness
- A failed liveness probe makes Kubernetes restart the container. A failed readiness probe only stops traffic to the pod. A readiness problem checked in the liveness probe restarts healthy pods.
- Resilience: stop one failure from spreading
- Microkernel
- A small core plus plug-ins that add features. Also called plug-in architecture.
- Architecture styles
- Mixed versions
- During a rolling deploy, old and new code run at the same time against one database. Every state of the schema must work for both.
- Schema and data migrations
- Moderator
- Answers your questions as the customer, the boss and ops. Alone, you write the questions down instead.
- Your first kata: a whole design in 15 minutes
- Multi-tenancy
- One running system serving many tenants, instead of one copy per tenant.
- Multi-tenancy: whose data is this?
- Noisy neighbour
- One tenant's load slowing down the others, because they share CPU, workers or a database.
- Multi-tenancy: whose data is this?
- One-way door
- A decision that is hard or impossible to undo: deleted data, a public contract, data you never recorded. Slow down and write an ADR.
- Reversible decisions: one-way and two-way doors
- Open layer
- A layer the one above may skip, to call the layer under it directly. Every call has to go through a closed layer.
- Layers: imports only go one way
- Open/closed (O)
- You add behavior by adding code, and you leave working code unedited. Java's
BufferedInputStreamadds buffering to anyInputStreamby wrapping it, without touching the file or socket streams. - SOLID: five principles, read on real code
- Owner
- The one service allowed to write a piece of data. It keeps the rules (invariants) about that data true.
- Who owns the data
- Page cache
- Memory the operating system uses to keep recently read and written file data. Kafka leans on it instead of building its own cache.
- Architecture characteristics: choosing the top three
- Partition (shard)
- A slice of the data, held by one node or one cluster. Each row lives in exactly one partition, and sharding puts the partitions on different machines.
- Scaling data
- Partition key
- The field that decides which partition a row goes to. A query that names it reads one partition. A query that does not must ask them all.
- Scaling data
- Peer vote
- Thumbs up, "meh" or down. Up does not need finished diagrams, only the confidence you could produce them given time.
- Your first kata: a whole design in 15 minutes
- Penthouse
- The floor where people decide strategy, budget and risk. They need the consequence, so they can decide.
- One decision, three audiences
- Point of no return
- The step after which you can only fix forward, because rolling back needs a new migration. Good migrations make it one small step, as late as possible.
- Evolving a live system without stopping it
- Poison message
- A message that fails on every retry, because of bad data, a bug or a missing field. Left in the queue, it blocks it or loops forever.
- Messaging: queues, delivery guarantees and dead letters
- Port
- An interface owned by the core, written in the core's words:
upload,download,delete. It says nothing about which technology sits behind it. - Ports and adapters: one core, many backends
- Post-deployment migration
- A migration that runs only after every server runs the new code. The contract step goes there.
- Schema and data migrations
- Process boundary
- Code on the two sides of it cannot share memory. They talk over a network, a queue or a file, and either side can crash alone.
- Containers: what actually runs
- Projection (read model)
- Data derived from the writes, shaped for one kind of read. You can delete it and rebuild it from the source of truth.
- CQRS and event sourcing
- Published event
- A message the owner sends after a change ("price changed"), so others can react without reading its database.
- Who owns the data
- Published language
- A shared, documented format that several contexts agree to speak at the border, like one message shape every server sends.
- Bounded contexts and context maps
- Reconciliation
- A job that compares the copies later and repairs what differs.
- Consistency across several stores
- RED metrics
- For a service: Rate (requests per second), Errors (how many fail), Duration (how long they take).
- Observability: logs, metrics, traces
- Redundancy
- Two or more copies, so that one can die and the others keep working. The copies must not depend on one shared box that can also die.
- Deployment: boxes on machines
- Reference
- Only the id of someone else's data. There is nothing to keep in step, but you must ask the owner to see the content.
- Who owns the data
- Relay
- The code that reads new outbox rows and publishes them. It can poll the table, or tail the database's log. A crash after a publish can send a row twice, so the relay gives at-least-once.
- Outbox and sagas: when one change spans two systems
- Replica
- A copy of a partition on another node. It adds read capacity and survives a node loss. It adds no write capacity: every write goes to every copy.
- Scaling data
- Repository
- An interface that looks like a collection of aggregates: add, find, remove whole ones. The database code sits behind it.
- DDD building blocks: inside one context
- Response measure
- The number that decides pass or fail, like "at most 25 attempts per IP in 5 minutes".
- Quality scenarios: making "secure" testable
- Retry with backoff
- Try again, waiting longer after each failure, so a struggling service gets room to recover. Jitter adds a random bit to each wait, so a thousand clients that failed together do not all retry in the same second.
- Failure: timeouts, retries, idempotency
- Saga
- A process across several services, where each step is a local transaction of its own. If a later step fails, earlier steps are undone by compensating actions.
- Outbox and sagas: when one change spans two systems
- Scenario
- One testable sentence: who does what to which part, in which situation, what the system must do, and how you measure it.
- Quality scenarios: making "secure" testable
- Seam
- The one place that decides "old or new" for a request or a piece of data. You need it before you can move anything.
- Evolving a live system without stopping it
- Single point of failure (SPOF)
- One box that, if it dies, takes the whole service down with it.
- Deployment: boxes on machines
- Single responsibility (S)
- A module has one reason to change: one group of people or one feature that asks for changes. The test is the number of sources of change, and a class can do several things for one source.
- SOLID: five principles, read on real code
- Singleton
- A box that must run as exactly one copy, so you cannot make it redundant by adding a second one.
- Deployment: boxes on machines
- SLO
- A target for what users feel, over a window. "99.5% of payments succeed over 28 days." The 0.5% left is your error budget.
- Observability: logs, metrics, traces
- Soft delete
- Marking a row as deleted (a timestamp column) instead of removing it. Users no longer see it, and staff can still restore it.
- Reversible decisions: one-way and two-way doors
- SSO / identity provider
- One login for many apps. It issues tokens that other services trust. Keycloak is a widely used open source identity provider.
- Gateways, tokens and SSO
- SSRF
- Server-side request forgery. The attacker makes your server fetch a URL for them, and so reaches what only your server can reach.
- Threat modeling
- Stale
- The cached answer no longer matches the owner's data. Every cache is stale sometimes, so you need to know for how long and what it breaks.
- Caching
- Stateless
- A server that keeps nothing between requests. Any copy can answer any request because the state lives in another store.
- Software architecture: the decisions that are expensive to change
- Static coupling
- Visible in the code or build: imports, shared libraries, generated code. A compiler or a grep finds it.
- Coupling and cohesion in a checkout service
- Stimulus
- The event that reaches the system: a burst of logins, a crash, a traffic spike.
- Quality scenarios: making "secure" testable
- Store of truth
- The store whose data you keep when copies disagree. You write it first and rebuild the other copies from it.
- Consistency across several stores
- Strangler fig
- Replace a system gradually: new code grows around the old, takes over piece by piece, and you delete each old part when nothing uses it (Fowler).
- Evolving a live system without stopping it
- Strategy
- Several interchangeable implementations of one interface. The caller picks one, or tries them in turn, without knowing their classes.
- Design patterns: named shapes you already use
- STRIDE
- Six kinds of threat to ask about at each crossing: Spoofing, Tampering, Repudiation, Information disclosure, Denial of service, Elevation of privilege.
- Threat modeling
- Style
- The overall shape of a system: its split, its communication and its deployment units. A style has typical trade-offs you can look up.
- Architecture styles
- Subdomain
- One area of what the business does: delivering posts to followers, logging users in, letting admins tune settings.
- Core, supporting and generic subdomains
- Superseded
- The status of an ADR that a newer ADR replaced. You never edit an accepted ADR to change the decision: you write a new one and link the two.
- Architecture decision records: writing down the why
- Supporting
- Needed by the business but gives no edge over competitors. It is usually simple, so you build it cheaply or outsource it.
- Core, supporting and generic subdomains
- Symptom alert
- Page a human when users are hurting (errors, slowness), not when a cause might hurt them later (CPU at 80%).
- Observability: logs, metrics, traces
- Synchronous call
- The caller waits for the answer. It gets the result, or the error, right now.
- Sync calls vs async jobs
- System context
- Level 1. Your system as one box, plus the people and external systems around it.
- The context diagram: your system as one box
- Technical vs domain partitioning
- Split the code by layer (controllers, models, jobs) or by business area (topics, polls, chat). It is how you tell a layered monolith from a modular one.
- Architecture styles
- Template method
- A base class fixes the steps of an algorithm and leaves one or more steps abstract. Subclasses fill in the steps, never the order.
- Design patterns: named shapes you already use
- Tenant
- One customer whose data must stay separate from the others. In Discourse multisite, one tenant is one site, found by its host name.
- Multi-tenancy: whose data is this?
- Test double
- A stand-in for something your code talks to: an in-memory store, a stub payment API, a hand-written message. It makes tests fast, and it is only as true as the last time someone compared it with the real thing.
- Testing strategy
- Timeout
- How long you wait before giving up. It frees you. It tells you nothing about what happened on the other side.
- Failure: timeouts, retries, idempotency
- Token
- A signed proof the caller sends on every request. A JWT carries its own claims, such as who issued it, for which audience, and until when.
- Gateways, tokens and SSO
- Tolerant reader
- A consumer that reads only the fields it needs and ignores the rest. It lets the provider add fields without asking anyone.
- API design and versioning
- Trace and span
- A trace records the path of one request through every service. A span is one step in it, with a start, a duration, a parent and attributes.
- Observability: logs, metrics, traces
- Trade-off
- What you give up to get what you want. The first law of software architecture says every decision has one: "Everything in software architecture is a trade-off."
- Software architecture: the decisions that are expensive to change
- Transactional outbox
- Save the message in the same database write as the data. A separate relay reads it and publishes it to the broker.
- Consistency across several stores
- Transactional outbox
- The service writes the outgoing message to a table in the same database transaction as the change, so both commit or neither does. A relay publishes the row later.
- Outbox and sagas: when one change spans two systems
- Transitional architecture
- Code that lets old and new run side by side, and that you plan to delete. Fowler: "code that will go away once the modernization is complete".
- Evolving a live system without stopping it
- Triggered vs continual
- Triggered checks run on an event (a commit, a release, a manual run). Continual ones run all the time, like production monitoring.
- Fitness functions: decisions that check themselves
- Trust boundary
- A line on that map where data passes from someone you trust less to someone you trust more, or the other way. Every arrow that crosses one is a place to look.
- Threat modeling
- TTL
- Time to live: how long an entry is trusted before it is thrown away. With a TTL, nobody has to remove the entry, the clock does.
- Caching
- Two-way door
- A decision that is cheap to undo: a config flag, a state column, a library behind an interface. Decide and move on.
- Reversible decisions: one-way and two-way doors
- Value object
- An object defined only by its value. It is immutable, compared by content, and checks itself when built. Two dates that both say 2026-03-14 are the same date.
- DDD building blocks: inside one context
- Wiring
- The one place that picks an adapter and hands it to the core. To change the backend, you change the choice there.
- Ports and adapters: one core, many backends
- Y-statement
- A one-sentence ADR: "In the context of…, facing…, we decided for… and neglected…, to achieve…, accepting…"
- Architecture decision records: writing down the why