Architecture Foundations stage summary
The Architecture Foundations stage builds the working vocabulary that the rest of the course spends its time applying. It sets out what makes a decision architectural rather than a matter of taste, what a component and an interface and a boundary actually are, how a quality attribute is written so that a test can decide whether it was met, how a decision is recorded so that it survives the person who made it, what the layered dependency rule protects and what breaks when it is bent, how a request travels between a client and a server and where its time is spent, how to draw a diagram at the zoom level the reader needs, how threats enter a design rather than an audit, and why the pipeline that puts a change in front of users is an architectural concern in its own right.
One argument runs through all nine modules. An architectural decision is one you cannot cheaply undo, so the discipline is to notice it before it is made, state what it makes easy and what it makes hard, attach a measure that can produce evidence rather than opinion, and write the reasoning down while the context is still in the room. Everything else in the stage is machinery for that habit: cohesion and coupling tell you where the expensive-to-undo lines are, quality attribute scenarios tell you what evidence looks like, decision records preserve the reasoning, and the C4 levels and the pipeline give you the two places where architecture becomes visible to people who were not in the room.
The sections follow the stage's teaching order, so you can read straight through to rebuild the stage in your head, or jump to the concept you need. Each section links back to its module for the full treatment.
What you carry out of this stage
- Apply the reversibility test to a live decision and say whether it is architectural or an implementation detail, using three signals: whether it reaches beyond one team or component, whether it would be expensive to reverse once six months of work sit on top of it, and whether it constrains the options open to other teams
- Name the interface of a component in full, meaning its operations, its data types, its error semantics and its ordering constraints, and explain why a signature that is unchanged can still be a broken contract
- Place a coupling on the spectrum from content coupling through common and control coupling to data coupling, and explain why two services sharing a database table is the most damaging form
- Rewrite a vague requirement such as the system should be fast as a six-part quality attribute scenario with a source, a stimulus, an environment, an artefact, a response and a response measure
- State a trade-off between two competing quality attributes explicitly, and say which one you are choosing to weaken and on what evidence
- Decide whether a decision earns an Architecture Decision Record using Nygard's significance test of structure, non-functional characteristics, dependencies, interfaces and construction techniques, write the record with context, decision, alternatives and consequences, and supersede an accepted record correctly instead of editing its decision
- Identify a layer violation in a dependency graph, explain what it costs in testability and replaceability, and choose between strict and relaxed layering for a given system
- Trace a request from client to response, name the point at which each timeout and retry budget applies, and choose between request-response, Server-Sent Events and WebSockets for a real-time requirement
- Choose the C4 level that answers a given audience's question, and say what belongs in a Container diagram that does not belong in a System Context diagram
- Apply STRIDE to a data flow, pair each threat with a design control and the evidence that the control works, and explain what a Software Bill of Materials makes possible after a new vulnerability is published
- Distinguish continuous integration, continuous delivery and continuous deployment precisely enough to hold the conversation with a change approval board
Architecture is the set of decisions you cannot cheaply undo
Most people meet architecture as diagrams: boxes, arrows, layers, technology names. The diagrams are communication artefacts, not the architecture. The architecture is the set of decisions that shape the structure of a system and constrain what can be built on top of it, and the practical test for whether a decision belongs in that set is reversibility. If undoing the choice next quarter would mean rebuilding significant parts of the system, it is architectural. Choosing a code formatter is not. Choosing whether services share one database or own their own is.
Module 1 turns that test into three signals you can check in a meeting rather than a vague feeling of importance. Does the decision reach beyond one team or component? Would it be expensive to reverse after six months of building on top of it? Does it constrain the options open to other teams later? The module draws no scoring threshold across them, and none is needed: a decision that reaches other teams, outlives the release and is expensive to unpick once built on is architectural, and one that stays inside a component and can be changed without touching anything outside it is an implementation decision. That is why microservices or a monolith, one shared database or a database per service, and synchronous or asynchronous communication clear the threshold, and the choice of object-relational mapper, test framework or code formatter does not. Architecture, design and implementation are nested rather than synonymous: architecture fixes the major parts and how they communicate, design fixes how one component is organised internally, and implementation fixes how a particular piece of logic works. ISO/IEC/IEEE 42010:2022, the international standard for architecture description, formalises the same idea as the fundamental organisation of a system, which is a statement about how concerns are separated and how parts relate rather than about which framework was chosen. The sharper filter for which of these decisions earns a written record is Nygard's significance test, and it arrives in Module 4.
The reason this matters is that the cost of an architectural decision is not paid when it is made. It is paid every time the system has to change afterwards, which is why architectural debt compounds faster than any other kind. A naming convention can be fixed with a search and replace. A coupling that has propagated through forty modules cannot. So the working habit to take from this module is small and cheap: before any decision that clears the threshold, write down what it makes easy and what it makes hard. If you cannot answer both halves, you do not yet understand the decision well enough to make it.
Architectural decisions are hard to reverse and wide in effect
The 2 by 2 runs reversibility across and blast radius down, so the cost of a choice is set by the cell it lands in: the system-wide, one-way cell holds the persistence store and the tenancy model, reversed only by a migration.
Most pull-request choices live in the top-left cell; architectural decisions live in the bottom-right. Source: Bezos 1997; Fairbanks, Just Enough Software Architecture, 2010; Bass et al. 2021.
A component is a responsibility, a hidden implementation and an explicit interface
Size does not make something a component. A microservice, a library, a module inside a monolith and a function in a pipeline can all be components, and what qualifies them is a set of three properties held together: one clear responsibility, an implementation that nobody outside can see, and an interface through which every interaction passes. A class named UserService that handles accounts, orders and billing fails the first property, because it has three independent reasons to change. A module named Utils fails all three, because a component with no responsibility has no owner, no interface and no reason to keep anything inside it together.
The interface is the contract, and the contract is larger than the signature. It covers the operations offered, the data types accepted and returned, the error conditions that can occur, and the behavioural constraints such as ordering and concurrency. This is the part teams get wrong most often. A function that keeps its parameters but starts returning a null where it previously raised an error has broken its contract even though nothing a type checker looks at has changed, which is why consumer-driven contract tests catch a class of break that types alone cannot. A well-designed interface is minimal, so it exposes only what callers need; stable, because every change breaks every caller; explicit about valid inputs and possible errors; and free of implementation detail, so that a method named findById survives a change of datastore that a method named getUserFromDatabase would not.
David Parnas set out the mechanism in 1972: each module should hide a design decision from the rest of the system. That is the whole point of an interface. When a decision is hidden behind one, changing it does not break anything outside, because nothing outside knew about it. So the check to run on any boundary you are about to draw is whether you can name four things about it: who owns it, what its interface is, who owns the data behind it, and what compatibility promise it makes. A line on a diagram that cannot answer those four questions is a drawing, not a boundary.
A boundary is the AND of four named parts; remove any one and it leaks
A boundary holds only where all four parts meet: component, interface, owner and contract each reach the hub through a badge reading AND, and a component with an interface but no named owner is not yet a boundary anyone can be held to.
Lose any spoke and the boundary leaks; the AND badges make the conjunction visible. Source: Parnas 1972; Bass, Clements, Kazman 2021 ch. 7.
Cohesion and coupling decide how far a change can travel
Two measures tell you whether a set of boundaries is doing any work. Cohesion asks how well the things inside one component belong together, and a component with high cohesion has a single reason to change. Coupling asks how dependent components are on one another, and low coupling means one can change without dragging the others with it. The goal is high cohesion with low coupling, and the two are related rather than independent: boundaries drawn along the right lines produce both at once, which is why arguing about them separately is usually a sign that the boundary itself is in the wrong place.
Coupling is a spectrum, not a binary, and naming the point on it is what makes a review actionable. Content coupling is the worst: one component reaches directly into another's internal state, and the standard example is one service reading and writing another service's database tables. There is no contract to protect either side, so the owning team cannot add an index, split a table or change a type without breaking a consumer it may not know about. Common coupling means shared global mutable state. Control coupling means one component passes a flag that steers another's internal branching, so the caller now has to understand the callee's logic. Data coupling, where two components exchange well-defined parameters through a declared interface, is the form to aim for.
Where the lines go is decided by four kinds of difference: different rates of change, different deployment needs, different team ownership, and different trust levels. Conway's observation from 1968 is the reason the third one is not optional; a system tends to mirror the communication structure of the organisation that built it, so two teams sharing a table with no boundary between them will argue about schema changes indefinitely. Dependency direction is the last control: when high-level policy defines the interface and low-level infrastructure implements it, the business rules can be tested with no database at all. The consequence to carry forward is that a good boundary makes the blast radius of a change predictable, and predictable blast radius is the thing you are actually buying.
Coupling failures cascade along five named stages
Tight change, Latency creeps in, Circuit trips, Cascade, Wider outage: each stage names the change and the effect it triggers, so a shared field added upstream and a status page showing red are the same incident read five stages apart.
Tight coupling turns a small change into a wider outage; break it at any step you can name. Source: Nygard 2018 Release It! 2nd ed.; Beyer et al. 2016 SRE ch.22.
A quality attribute is not real until something can produce evidence about it
Functional requirements say what a system does. Quality attributes, also called non-functional requirements, say how well it does it, and they are what constrain the design space. The user can log in is functional. Login succeeds within 200 milliseconds for 99 percent of requests is a quality attribute, and only the second one rules any architecture in or out. A system can satisfy every functional requirement and still destroy the organisation that owns it: the Knight Capital trading incident of 1 August 2012 involved a deployment that activated dormant code, and every order the system placed was executed exactly as instructed. Nothing functional failed. What was missing were reliability, safety and observability properties that nobody had specified.
The fix for vagueness is a template rather than more adjectives. The Software Engineering Institute's quality attribute scenario has six parts, and all six have to be present: the source of the stimulus, the stimulus itself, the environment the system is in at the time, the artefact affected, the response, and the response measure. The system should handle peak load names only the artefact, which is why it can be neither designed for nor tested. When 500 customers request account balances simultaneously during normal business hours, the balance API returns correct data within 150 milliseconds at the 99th percentile is the same requirement with the other five parts supplied, and it can now be failed by a load test.
ISO/IEC 25010 supplies the shared taxonomy that keeps these conversations from becoming arguments about the word quality, grouping product quality into top-level characteristics such as performance efficiency, reliability, security and maintainability, each with sub-characteristics beneath it. The standard was revised in 2023 and the revision changed the model, so cite the edition you are working from rather than a remembered list. The habit that follows is the one the figure in this section makes explicit: every stated quality requirement needs a threshold, a test or observation that can produce proof, and a signal that a release decision can actually be made on. A requirement with none of those three is a wish.
Every non-functional requirement needs evidence in every cell
Reliability, performance, security and maintainability each carry a target, the test that produces the evidence, the operational signal and the source, so p95 latency under 200 ms becomes a k6 run in CI rather than a number in a document.
A target without a test, a signal, and a source is a wish; the row is the contract. Source: ISO/IEC 25010:2023; Bass, Clements, Kazman 2021 ch. 4; Google SRE 2018.
Every architectural decision weakens something, and the skill is saying which
Quality attributes are not free and they pull against each other. Strong consistency competes with availability once a network partition is possible. Every authentication check and validation step buys security and spends latency. A single server is simple to operate and cannot scale horizontally. Shipping sooner costs maintainability later. None of these pairs has a correct answer in the abstract, which is exactly why they are architectural: the answer depends on measured requirements for this system, and once chosen it is expensive to revisit.
The Architecture Trade-off Analysis Method, developed at the Software Engineering Institute, is the structured version of this conversation, and its value is the vocabulary it gives you even when you never run the full method. A sensitivity point is a decision that strongly affects one quality attribute. A trade-off point is a decision that affects two or more in conflicting directions. A risk is a decision that may not support a stated requirement under some conditions. A utility tree ranks candidate scenarios by business importance and by architectural difficulty, and the scenarios that score high on both are the risks worth designing against first.
Work an example through and the mechanism becomes obvious. Adding a cache improves read latency, weakens consistency because the cached copy can be stale, adds an operational component that has to be monitored and configured, and increases cost. That is not a reason to avoid caches. It is the shape of the record you owe the next engineer: the attribute you improved, the attribute you knowingly weakened, and the measured requirement that made the exchange acceptable. An architecture where nobody can say which quality attribute was traded away has not made the trade-off; it has just absorbed it.
Quality attributes trade against each other in four named pairs
The map runs speed down the side and cost against reliability across the top, makes every cell surrender something, and prices the fast and safe cell as predictable latency bought with hot replicas that are expensive to run.
Pick the cell that matches the operating reality; no system lives in all four cells. Source: Bass, Clements, Kazman 2021 ch.4; ISO/IEC 25010:2023.
Layering buys nothing unless the dependencies all point one way
A layered architecture organises code into horizontal tiers with defined responsibilities, commonly presentation, application services, domain and data access. The tiers are not the point. The dependency rule is: arrows run downward only, and no layer imports from a layer above it. Where a lower layer genuinely needs to notify a higher one, it does so indirectly, through an event or a callback that the higher layer subscribes to, so the import still never goes upward. Strip that rule out and you have four folders, not four layers.
What the rule buys is separation of change, independent testability and replaceability. Each layer has one reason to change, so a change to the API contract does not force a retest of business rules. A domain layer that imports nothing external can be unit tested with no database and no HTTP server, which is why domain tests in a properly layered system are fast and stable. And because the presentation layer knows nothing about persistence, either end can be replaced without touching the other. A layer violation, whether it is a lower layer importing upward or a controller reaching past the service layer straight into a repository, removes all three benefits at once. Erosion is gradual and starts with a single pragmatic shortcut, which is why teams enforce the rule with static analysis in the pipeline rather than in code review, using tools such as ArchUnit, Dependency Cruiser or NetArchTest.
Two calibrations stop this becoming dogma. Strict layering allows a layer to call only the layer immediately below it and is the right choice when the domain layer holds certified, audited or safety-critical logic that must be insulated from infrastructure change; relaxed layering allows a layer to call any layer below it and is the pragmatic choice in thin, data-entry-heavy applications. And the layer count is not sacred: a three-layer split of presentation, domain logic and data source is a complete architecture, and adding an application services layer to a system with no use-case orchestration produces boilerplate and nothing else. The failure to watch for is the anaemic domain model, named by Martin Fowler in 2003, where entities hold only getters and setters and all the rules migrate into service classes. The diagram still shows layers. The domain layer is isolating nothing, because it contains nothing to isolate.
Layering protects change only when dependencies all point one way
Three downward arrows are allowed and the one running upward from L1 Infrastructure into the L2 Domain carries a crossed badge. Once infrastructure code calls a domain rule directly, the layering has stopped protecting change, whatever the folder names still say.
The forbidden arrow is reversed only by an Anti-Corruption Layer, never by a quick patch. Source: Fowler PoEAA 2002; Martin Clean Architecture 2017; Evans DDD 2003.
A request path is a chain of time budgets and failure decisions, not one call
Client-server is the shape of nearly everything on the web: a client sends a request, a server processes it and sends a response, and the cycle closes. HTTP, which governs the exchange, is stateless by design. RFC 9110, the current Internet Standard for HTTP semantics, states that each request message's semantics can be understood in isolation. That constraint is what allows any server in a pool to serve any request without session affinity, and it is also the source of a persistent confusion: sessions, cookies and tokens are stateful mechanisms built on top of a stateless protocol, so an application can be stateful while the protocol underneath it remains stateless.
A production request does not go from browser to application code in one hop, and latency is additive along the chain: name resolution, an edge cache, a load balancer at layer 4 or layer 7, the application server, and the datastore behind it. Treating that chain as one opaque call is how teams end up unable to say where time went. Each hop needs a timeout that bounds how long the caller waits, a retry budget rather than unlimited retries, and backoff with jitter so that a struggling dependency is not hit by every client at the same instant. Retries without a budget turn a slow dependency into an outage, because the load that arrives while it is recovering is larger than the load that broke it.
Synchronous request-response fits work that finishes inside a tolerable response time. Work that does not fit is acknowledged immediately and completed in the background, with the client polling a status endpoint or receiving a callback, because holding an HTTP connection open for twenty minutes loses to the first proxy timeout in the path. When the server needs to push rather than answer, three options sit at different costs: long polling needs no new infrastructure but reintroduces waiting; Server-Sent Events give native one-way streaming with automatic reconnection through the browser's EventSource interface; WebSockets give a full-duplex channel and add connection state, reconnection logic and load balancer stickiness to your operational burden. The decision rule is simple and often ignored: use WebSockets only when the client genuinely needs to send frequent messages back over the same channel.
A single HTTP request crosses five steps, each with its own failure signature
DNS, TCP, TLS, HTTP and the application each split into what they succeed with above the rule and what they fail with below, so NXDOMAIN and an expired certificate are different faults that no amount of application logging will tell apart.
Debug by finding the first step whose success evidence is missing; each step fails on its own signature. Source: RFC 9110 HTTP semantics; RFC 9293 TCP; RFC 8446 TLS 1.3; RFC 1034 DNS.
C4 is a zoom control, and the wrong zoom makes a correct diagram useless
The C4 model gives four hierarchical views, each answering a different question for a different reader. System Context shows the system as one box among its users and the external systems it depends on, carries no technology names, and is written for people who do not read architecture diagrams for a living. Container zooms inside the system boundary and shows the separately deployable and runnable things, a web application, an API, a database, a queue, each annotated with the technology it uses and each relationship labelled with the protocol and the data exchanged. Component zooms inside one container to its internal building blocks. Code is optional, and modern tooling generates it on demand, so it is very rarely worth maintaining by hand.
Most teams need only the first two, and the Container diagram is the one that repays maintenance. It is concrete enough to drive deployment and technology conversations and abstract enough to stay true while implementation details churn underneath it. The notation demands little: every element carries a name, a type and a short description, every relationship carries the intent rather than just an arrowhead, and elements outside the system boundary are visually distinguished so that the places where integration risk lives are obvious at a glance. C4 does not replace UML, because it cannot express message ordering or state transitions; a sequence diagram is still the right tool when the question is what happens when X occurs and in what order.
The failure mode is not drawing the wrong boxes, it is drawing them once. A diagram that described the system accurately eighteen months ago is worse than no diagram at all, because it produces confident wrong decisions. The teams whose diagrams stay useful treat them as generated outputs rather than hand-drawn documents, writing them in a text DSL such as Structurizr or the C4 macros for PlantUML, keeping them in version control beside the code, reviewing them in pull requests and rendering them in the pipeline. That is the consequence to act on: if a diagram cannot be regenerated by a build, assume it is already wrong.
C4 model: four nested levels, each answering a different question
Each row pairs a level with the question it answers and the audience that asks it, and each card below holds the elements that level absorbs, so a diagram drawn at the wrong level answers a question nobody brought.
Pick the level that matches the audience; most diagram failures are wrong level, not wrong notation. Source: Brown, c4model.com.
Security is a property of the design, so it has to be an input to it
Security that is retrofitted is consistently weaker and more expensive than security that was designed in, because the properties that matter most are structural: where the trust boundaries sit, which data crosses them, and where identity is established. The NCSC's secure design principles organise the guidance into five groups that make useful headings for a design review: establish the context, make compromise difficult, make disruption difficult, make the detection of compromise easier, and reduce the impact of compromise. The first is the one teams skip and the one everything else depends on, because a control chosen without knowing what is being protected and from whom is decoration.
STRIDE turns that into a systematic pass over a data flow. Spoofing is claiming an identity you do not have, and it is answered with strong authentication. Tampering is unauthorised modification, answered with integrity controls and parameterised queries. Repudiation is denying an action, answered with signed and timestamped audit records. Information disclosure is exposure to the wrong party, answered with access control, encryption and restraint about what goes into logs and error responses. Denial of service is answered with rate limits, circuit breakers and edge protection. Elevation of privilege is answered with server-side authorisation checks on every request and least privilege everywhere. The critical distinction the module drives at is that authentication establishes who is calling and authorisation decides what that caller may do; a system that checks the first and assumes the second is how one customer reads another customer's account by changing an identifier.
Two habits follow. First, defence in depth, meaning no single control is the only thing standing between an attacker and the data: network controls, application controls, data controls and operational detection each limit the blast radius when the layer outside them fails, and egress restrictions on application containers are the specific control that would have blunted the Log4j vulnerability published on 10 December 2021 as CVE-2021-44228, which scored 10.0 and reached organisations through transitive dependencies they did not know they had. Second, a Software Bill of Materials produced at build time, listing every component including transitive ones, so that the question which of our services contains this library has an answer within minutes of the next advisory rather than within weeks. A threat model that ends in a list of risks has not done its job; each threat should end in a control, a test and evidence a reviewer can look at.
Security as four nested boundaries: Network, Identity, Data, Trust
Each ring carries its own mechanism, firewalls at the network, single sign-on at identity, encryption at data and authorisation at trust, so a perimeter held by the outer ring alone leaves the three inner rings unguarded.
Identity is the ring that ties the others together; trust sits at the centre because the others all defer to it. Source: NIST SP 800-207 Zero Trust; OWASP ASVS 4.0; NCSC Cyber Assessment Framework.
The pipeline is architecture, because it decides how safely change reaches users
The three terms hidden inside the abbreviation CI/CD are distinct and the distinction matters in any conversation with a change approval board. Continuous integration means changes are merged into a shared branch at least daily and tested automatically on every merge, so integration problems surface within hours rather than on a painful integration day. Continuous delivery means every build that passes is in a state where it could be deployed, with a deliberate human decision about when. Continuous deployment removes that gate, so every passing build goes to production automatically. Most regulated organisations practise continuous delivery, and a required approval gate does not stop them doing so.
A pipeline is an ordered set of stages arranged fast to slow, so that cheap checks fail early: a commit stage of unit tests, linting, type checks, static security analysis and a build, aiming to finish inside a few minutes; an integration stage with integration and contract tests and a deterministically tagged image; a security stage scanning dependencies and the built image; a staging deployment with smoke tests and a performance baseline against an environment that genuinely mirrors production; and a production deployment using a rolling, blue-green or canary strategy with health checks watching error rate and latency. Rollback has to be a button, not a fresh run of the pipeline, because a rollback that takes as long as a deployment is not a rollback.
Two practices make the rest work. Feature flags separate deployment from release, so code can ship disabled, be enabled for a small ring of users, and be switched off instantly without a redeploy; the cost is flag debt, since every live flag is another branch in production behaviour, so temporary flags need an owner and a removal date. Trunk-based development keeps batches small by integrating every change immediately and hiding unfinished work behind flags rather than in long-lived branches that accumulate integration debt for every day they stay open. The measurement frame to use is DORA's, which now publishes five metrics rather than the four many teams still quote: change lead time, deployment frequency and failed deployment recovery time on the throughput side, with change fail rate and deployment rework rate on the instability side. The counterintuitive finding these support is the one to carry into Stage 2: deploying more often makes each deployment safer, because smaller batches are easier to diagnose.
CI/CD as a control surface: five stages, five gates, five signals
Each stage pairs the gate that lets a change pass with the signal that gate produces, so weakening a gate costs you its signal too, and the pipeline still runs green while reporting less than it did before.
Weaken any gate and you weaken the control surface; the Test gate is the one teams most often weaken. Source: Humble and Farley 2010 Continuous Delivery; Forsgren et al. 2018 Accelerate; DORA 2023.
The traps this stage warns against
Treating the diagram as the architecture, so that redrawing the boxes feels like architectural work.
Instead: The architecture is the set of decisions that are expensive to reverse, so the work is naming those decisions rather than rearranging the picture of them. Ask whether a candidate reaches beyond one team or component, whether it would be costly to undo after six months of building on it, and whether it narrows what other teams can do later. Nygard's significance test in Module 4, covering structure, non-functional characteristics, dependencies, interfaces and construction techniques, is the sharper filter for which of them earn a written record. A diagram is a view onto those decisions for a particular audience, which is why C4 asks you to choose the zoom level before you draw anything.
Writing a non-functional requirement as an adjective, such as the system should be fast or the system should be available.
Instead: Use all six parts of the SEI quality attribute scenario: source, stimulus, environment, artefact, response and response measure. Available can mean 99 percent, which is days of downtime a year, or 99.999 percent, which is minutes, and those two numbers buy entirely different architectures. Without a response measure, no test can fail the requirement and any design can claim to have met it.
Letting one service read another service's database tables because it is faster than adding an endpoint.
Instead: That is content coupling, the most damaging point on the spectrum, and it removes the owning team's freedom to add an index, split a table or change a type. Move the access behind a declared interface so the two sides are only data coupled, and enforce the rule in the pipeline rather than hoping code review catches the next instance.
Editing an accepted Architecture Decision Record so that it states the decision the team has now reached.
Instead: Never rewrite the decision or consequences of an accepted record. Change only its status to superseded and add a forward pointer, then write a new record that states the new decision and explains what changed in the context. The chain from the old record to the new one is the institutional memory the practice exists to preserve.
Quoting an OWASP Top 10 category number from memory, without the edition it came from.
Instead: The numbering is a ranking that is re-derived each cycle rather than a stable identifier, so a category can move between releases. In the current OWASP Top 10:2025, Insecure Design is A06:2025 and Software Supply Chain Failures enters at A03:2025. Carry the edition with the number every time, and check the current release before you take a rank into a design review.
Treating the DORA metrics as a fixed set of four keys, and reporting recovery time under the old name MTTR.
Instead: DORA has shifted from the original four keys to a five-metric model: change lead time, deployment frequency and failed deployment recovery time as throughput measures, with change fail rate and deployment rework rate as instability measures. Failed deployment recovery time is the current name for what many teams still call mean time to recover. Name all five and the year of the research you are citing, because the model has been revised and a stale list undermines an otherwise sound argument.
Referring to RFC 7231 as the specification for HTTP semantics.
Instead: RFC 9110 obsoletes RFC 7231 and is the current Internet Standard, STD 97. It is also the citation to use for the stateless constraint, since it states directly that each request message's semantics can be understood in isolation.
Declaring a system layered because the folders are named presentation, domain and data.
Instead: Layering only pays when dependencies point one way. Enforce the rule with static analysis in the pipeline, and check that the domain layer actually holds behaviour: entities that carry only getters and setters while every rule lives in a service class are the anaemic domain model Fowler named in 2003, and they deliver the ceremony of layering with none of the isolation.
Core distinctions
- Architecture versus design versus implementation: architecture fixes the major parts, how they communicate and what constrains their evolution; design fixes how one component is organised internally; implementation fixes how a specific piece of logic works. Only the first is expensive to reverse
- Functional requirement versus quality attribute: the first says what the system does and the second says how well it does it. A system can satisfy every functional requirement and still fail catastrophically, which is what the Knight Capital incident of 1 August 2012 demonstrated
- Cohesion versus coupling: cohesion measures whether the things inside a component belong together, coupling measures how dependent components are on each other. Well-placed boundaries improve both simultaneously, and a boundary that improves only one is usually in the wrong place
- Content coupling versus data coupling: content coupling reaches into another component's internal state and leaves no contract to protect either side; data coupling passes well-defined parameters through a declared interface and is the form to aim for
- Strict versus relaxed layering: strict layering permits a call only to the layer immediately below and suits certified or safety-critical domain logic; relaxed layering permits a call to any layer below and suits thin, data-entry-heavy applications. Both keep the downward dependency rule
- Authentication versus authorisation: authentication establishes who is calling, authorisation decides what that caller may do. Checking the first and inferring the second is how elevation of privilege happens on a fully encrypted connection
- Continuous delivery versus continuous deployment: continuous delivery means every passing build could be deployed and a human decides when; continuous deployment means every passing build goes to production automatically. A change approval gate is compatible with the first and not the second
- Deployment versus release: deployment puts code on the production estate, release exposes it to users. Feature flags separate the two, which is what makes a kill switch faster than a rollback
- C4 container versus component: a container is something separately deployable and runnable, such as an API or a database; a component is a logical building block inside one container. Technology names belong at container level and never at system context level
- A protocol being stateless versus an application being stateful: HTTP is stateless because each request can be understood in isolation, while sessions and tokens add application state on top. Both statements can be true of the same system at once
- Proposed, accepted, deprecated and superseded: a record's status is the lifecycle, and superseding is a new record with a forward link rather than an edit to the old one
That is the Architecture Foundations stage in one place. Architectural decisions identified by whether they can be cheaply undone, components defined by responsibility and hidden implementation behind a full interface contract, coupling named precisely enough to act on, quality attributes written in six parts so that evidence can exist, trade-offs stated rather than absorbed, decisions recorded and superseded rather than edited, a dependency rule that only pays when it is enforced, a request path made of time budgets, diagrams chosen by audience and regenerated by a build, threats paired with controls and evidence, and a pipeline treated as part of the system it delivers. The foundations scenario practice now puts that vocabulary under pressure with realistic situations, so the confusions surface here rather than in Stage 2, where microservices, event-driven communication, CQRS, domain-driven boundaries, resilience patterns and scaling all assume you can already name a boundary, a quality attribute and a trade-off without reaching for a dictionary.
Sources and further reading
- Bass, L., Clements, P. and Kazman, R. Software Architecture in Practice, 4th edition (Addison-Wesley, 2021)The standard treatment of architecture as significant decisions, which Module 1 uses for its definition, and the source of the six-part quality attribute scenario and the trade-off analysis vocabulary in Module 3.
- ISO/IEC/IEEE 42010:2022, Software, systems and enterprise: Architecture descriptionThe international standard cited in Module 1. It governs how an architecture is DESCRIBED and is explicit that architectures themselves are not its subject, so it is the wrong citation to reach for when you want a definition of architecture. The 2022 edition supersedes the 2011 one and carries a different title, so quote the year alongside the number.
- ISO/IEC 25010, Systems and software quality models (SQuaRE)The taxonomy of product quality characteristics used in Module 3. The 2023 revision changed the model, so quote the edition you are working from rather than a remembered list of characteristics.
- Parnas, D. L. On the Criteria To Be Used in Decomposing Systems into Modules, Communications of the ACM 15(12), 1972The origin of information hiding, and the reason an interface exists at all: a decision hidden behind a boundary can change without breaking anything outside it. Underpins Module 2.
- Architectural Decision Records community siteCollects the ADR templates and tooling, and records that the practice was popularised by Michael Nygard's 2011 post Documenting Architecture Decisions. The reference point for the format and lifecycle in Module 4.
- Fowler, M. AnemicDomainModel, martinfowler.com, 25 November 2003The named anti-pattern behind the warning in Module 5: entities that hold data and no behaviour incur the cost of a domain model while yielding none of its benefits.
- RFC 9110, HTTP Semantics (Internet Standard, STD 97)The current normative specification for HTTP semantics, obsoleting RFC 7231. The source for the stateless constraint discussed in Module 6.
- Brown, S. The C4 model for visualising software architectureThe official reference for the four zoom levels, the notation conventions and the diagrams-as-code tooling covered in Module 7, maintained by the model's creator.
- NCSC secure design principlesThe UK guidance grouped as establish the context, make compromise difficult, make disruption difficult, make the detection of compromise easier, and reduce the impact of compromise. The design-review structure used in Module 8.
- OWASP Top 10The current edition is the OWASP Top 10:2025, in which Insecure Design is A06:2025 and Software Supply Chain Failures enters at A03:2025. Cite the edition with the category number, since the ranking is re-derived each cycle.
- NIST National Vulnerability Database, CVE-2021-44228The record for the Log4j JNDI vulnerability published on 10 December 2021 with a CVSS v3.1 base score of 10.0, used in Module 8 as the supply chain and defence in depth example.
- DORA research and the DORA metricsThe longitudinal software delivery research behind Module 9, and the source for the current five metrics: change lead time, deployment frequency, failed deployment recovery time, change fail rate and deployment rework rate.
- US Securities and Exchange Commission administrative proceeding against Knight Capital Americas LLC, 2013The regulatory findings on the trading incident of 1 August 2012 used in Module 3 to show that a functionally correct system can still fail on unspecified reliability and safety properties.