# Software Architect: mindset, language, practice

A full course for a senior engineer who wants to think and talk like an architect: trade-offs, boundaries, data, distributed systems, quality, communication, and AI-native work. 52 concepts — each with its English term, a diagram, and a card (what it is → example → cost → related); a cheat sheet of every concept at the end.

- **Author:** Fedor Chishchin
- **Level:** advanced
- **Reading time:** ~7 hour read
- **Published:** 2026-05-23
- **Source:** https://fedorthinks.com/learn/software-architect

---

#### Detailed modules

- [01. Who the architect is](./software-architect-01-role)
- [02. Trade-offs](./software-architect-02-tradeoffs)
- [03. Technical debt](./software-architect-03-technical-debt)
- [04. Cognitive load](./software-architect-04-cognitive-load)
- [05. Decomposition](./software-architect-05-decomposition)
- [06. Layers and dependencies](./software-architect-06-layers)
- [07. APIs and contracts](./software-architect-07-api-contracts)
- [08. Data model](./software-architect-08-data-model)
- [09. State](./software-architect-09-state)
- [10. Distributed systems](./software-architect-10-distributed-systems)
- [ 11. Monolith and microservices
  ](./software-architect-11-monolith-microservices)
- [12. Sync and async](./software-architect-12-sync-async)
- [13. Performance](./software-architect-13-performance)
- [14. Scalability](./software-architect-14-scalability)
- [15. Reliability](./software-architect-15-reliability)
- [16. Security](./software-architect-16-security)
- [17. Observability](./software-architect-17-observability)
- [18. Documentation](./software-architect-18-documentation)
- [19. Communication](./software-architect-19-communication)
- [20. Leadership without authority](./software-architect-20-leadership)
- [21. Business and product](./software-architect-21-business-product)
- [22. AI-native architect](./software-architect-22-ai-native)
- [23. Anti-patterns](./software-architect-23-antipatterns)
- [24. Continuous growth](./software-architect-24-growth)

## 1. Who the architect is

An architect differs from a senior engineer not because they know more technologies. They own the consequences of decisions over time.

### Course map — 24 modules in six parts

> A subway map: first you see all the lines at once, then you ride station by station.

The course goes from mindset to practice. First, how an architect thinks (**mindset**). Then how a system is built inside (**structure**) and what changes when it spreads across a network (**distribution**). After that come the quality properties (**quality attributes**), working with people (**people**), and where the profession is heading (**future**).

_Diagram: The 24 modules in six parts: mindset → structure → distribution → quality → people → future._

How to read it: every concept gets its **English term** (the one you'll search docs for and hear in interviews), an everyday image, a **diagram**, and a **card** with "what it is / example / cost / related" fields. At the end of the course there's a cheat sheet with every concept on one page.

### Long-term thinking — the architect thinks in years

> An engineer builds a bridge that a car will drive across tomorrow. The architect asks what happens when trucks start using it, when a new district goes up next door, and when repairs cost more than the bridge itself.

An engineer usually solves the problem **as posed**. The architect first checks whether the problem was posed correctly. That isn't snobbery or a wish to "talk about the deep stuff." An architectural decision is just usually more expensive to change than a line of code.

The main shift in the head: you stop asking only "how do I do X" and start asking **"why do we need X, what are the alternatives, what will we lose, and what will this look like in three years"**.

_Diagram: The engineer looks at the task as posed. The architect stretches the same question over years._

#### Long-term Thinking (thinking in years)

- **What it is:** Judging a decision not only by "works tomorrow" but by how it behaves in one to three years.
- **How it works:** Before "how do I build X" — "why X", what the alternatives are, what we lose.
- **Example:** The bridge: will it carry trucks, a new district next door, repairs that cost more than the bridge?
- **Catch:** It's not a licence to build "for growth" — just a question you must ask.
- **Related:** **Reversible decisions**, **trade-offs**, **technical debt**.

### Reversible vs irreversible decisions — owning the shape of the system

> If a carpenter hangs a shelf wrong, you can move it. If the designer puts a load-bearing wall in the wrong place, the house lives with that mistake for decades.

The architect isn't obliged to personally make every technical decision. But they are obliged to own the decisions that set the shape of the system: service boundaries, the data model, integration protocols, the scaling strategy, security, observability, the migration path.

The useful distinction here is between **reversible decisions** and **irreversible decisions**. A reversible decision can be changed in a day or a week: a logging library, a button colour, the internal structure of a small module. An irreversible or expensive-to-reverse decision changes the trajectory of the system: the database, the tenancy model, an API contract, the way events are stored, service boundaries.

_Diagram: Make reversible decisions fast. Irreversible ones set the shape of the system — the architect owns them._

#### Reversible vs Irreversible (two kinds of decisions)

- **What it is:** Sorting decisions by the cost of undoing them: days or weeks vs months or years.
- **How it works:** Reversible ones: decide fast, don't argue long. Irreversible ones: slowly, with alternatives and a written record.
- **Example:** A logging library is reversible. The tenancy model or an API contract nearly isn't.
- **Catch:** A week of debate over a reversible detail is as bad as deciding an irreversible one in an hour.
- **Related:** **Data model**, **API contract**, **service boundaries**.

> **The main question:** If this decision turns out wrong in a year, how many people and how many systems will pay for it?

#### The architect's questions

- What problem are we actually solving?
- What changes if load grows 10x?
- Which decisions here are reversible, and which are nearly not?
- Who's going to be maintaining this a year from now?

> The architect doesn't build "the most correct system" — they build a system that survives reality.

## 2. Trade-offs and decisions

There are no free decisions in architecture. Every choice buys one property at the cost of another.

### Trade-off — best practice without context is bad advice

> An SUV beats a sedan on a muddy road. The sedan beats the SUV in the city. A bicycle beats both if you need to go three blocks and there's nowhere to park.

You can't evaluate an architectural decision outside its context. REST, GraphQL, Kafka, PostgreSQL, Kubernetes, microservices, monolith — all of these are tools with a price. A **trade-off** is a deliberate exchange: latency vs. throughput, consistency vs. availability, time-to-market vs. maintainability, simplicity vs. flexibility.

The architect doesn't say "Kafka is better than RabbitMQ." They say: "we need per-key event ordering, high throughput, replay, and a durable log; in exchange we pay the operational complexity of Kafka." That's what professional language sounds like.

_Diagram: Every decision is a point on several axes at once. Move toward one end and you give something up at the other._

#### Trade-offs (a deliberate exchange)

- **What it is:** A choice that buys one property at the cost of another — made out loud.
- **How it works:** Name what you gain, what you lose, and why that price is acceptable now.
- **Example:** "Per-key ordering, throughput, replay, a durable log — paid for with Kafka's operational complexity."
- **Catch:** "X is better than Y" without context isn't an argument, it's taste.
- **Related:** **CAP / PACELC**, **over-engineering**, **sync vs async**.

### Over-engineering vs under-engineering — complexity is a tax

> Every new abstraction is like another room in the house. The room can be useful, but it has to be cleaned, heated, repaired, and explained to guests.

Complexity is useful when it buys an important property: failure isolation, independent release, security, scaling, testability. But complexity "for the future" usually becomes a permanent tax.

The terms **over-engineering** and **under-engineering** are only useful together. Over-engineering: complexity showed up before the real pain. Under-engineering: the system has already hit limits, and the architecture left no room to grow. The architect's job isn't to pick an extreme — it's to hold the middle.

_Diagram: Two mistakes at the edges, the right zone in the middle: complexity is justified only when it buys a specific property._

#### Over- / Under-engineering (too much vs too little)

- **What it is:** Over: complexity before the real pain. Under: the system hit its limits with no path to grow.
- **How it works:** Every new layer or service has to name the property it buys.
- **Example:** Microservices and Kafka at launch for 200 users — over. One table with no indexes when load grows 10x — under.
- **Catch:** Complexity "for the future" doesn't go away — you pay for it every day.
- **Related:** **Trade-off**, **technical debt**, **cognitive load**.

> **The question for every decision:** What do we gain, what do we lose, and why is that price acceptable now?

#### Further reading

- Architecture: The Hard Parts — Ford, Richards, Sadalage, Dehghani
- Software Architecture in Practice — Bass, Clements, Kazman
- Martin Fowler: Is Design Dead?

## 3. Technical debt

Technical debt isn't always bad. What's bad is debt taken on by accident, not written down, and never meant to be repaid.

### Technical debt — a loan, not garbage

> A loan on equipment can accelerate a business. A loan for a party just leaves a hangover and interest.

**Technical debt** is a decision that speeds us up now but creates a future cost of change. Sometimes that's right: you need to test the market, hit a deadline, keep a customer. The problem starts when the team labels everything as debt: bad code, missing tests, chaotic dependencies, outdated libraries.

A useful model is **Martin Fowler's Technical Debt Quadrant**: deliberate / inadvertent and prudent / reckless. Deliberate-prudent debt: "we're skipping multi-region for now because we have 200 users and one market." Inadvertent-reckless debt: "we didn't know we needed transactions."

_Diagram: Fowler's quadrant: debt can be taken deliberately and prudently (top right). The left-hand cells are the dangerous ones._

#### Technical Debt (borrowing against future change)

- **What it is:** A decision that speeds us up now but creates a future cost of change.
- **How it works:** Take it on deliberately, write down what and why, set a trigger for revisiting.
- **Example:** "No multi-region yet: 200 users, one market" — deliberate and prudent.
- **Catch:** If everything is called debt — bad code, no tests, old libraries — the word stops meaning anything.
- **Related:** **Debt interest**, **ADR** (recording the decision), **trade-off**.

### Debt interest — debt charges interest

> If the road is broken, every trip takes five minutes longer. A month later it's no longer a pothole — it's a tax on the whole city.

The interest on technical debt is the slowdown of every next change. The more often the team touches an area, the more expensive the debt. That's why debt in the hot domain is more dangerous than debt in a rarely-used admin panel.

The architect negotiates a repayment strategy: what exactly counts as debt, what risk it creates, when we revisit the decision, what signal says "time to pay." Without that, "technical debt" becomes an emotional argument, not a managed instrument.

_Diagram: The same debt: in the hot domain interest is charged on every change, in the admin panel almost never._

#### Debt Interest (the running cost of debt)

- **What it is:** The slowdown of every next change in code that carries debt.
- **How it works:** Interest ≈ slowdown × how often the team touches that area.
- **Example:** Debt in payments, changed weekly, costs more than debt in an admin panel opened once a quarter.
- **Catch:** Without a repayment strategy, "tech debt" becomes an emotional argument.
- **Related:** **Technical debt**, **cognitive load**.

> **The key question:** Is this debt buying us time, or is it just masking a bad decision?

#### Questions for a debt review

- Where is it written down why we took this compromise?
- What interest are we paying each sprint?
- What would have to happen for this debt to become a blocker?
- Is there a repayment plan, or at least a trigger for revisiting?

## 4. Cognitive load

A system nobody can hold in their head will break even with strong engineers.

### Cognitive load — architecture has to fit in a human head

> A subway map is useful not because it shows every bolt in the tunnel. It shows lines, transfers, and direction of travel. That's enough to make a decision.

**Cognitive load** is the mental effort a system demands from an engineer. There's **intrinsic load**: the complexity of the domain itself. There's **extraneous load**: extra complexity from bad architecture, non-obvious links, accidental exceptions, and magic. The architect can't remove business complexity, but they're obliged to reduce accidental complexity.

A good module can be understood on its own. A good bounded context has its own language and its own invariants. A good team owns an area that fits in its head.

_Diagram: Domain complexity (intrinsic) is always there. Architecture decides how much extra (extraneous) gets piled on top — and whether it all fits in a head._

#### Cognitive Load (mental effort)

- **What it is:** How much context an engineer has to hold in their head to change something safely.
- **How it works:** Intrinsic is the domain's own complexity — it stays. Extraneous is accidental — cut it.
- **Example:** A module you can understand on its own vs one where nothing makes sense without the "magic" and exceptions.
- **Catch:** Strong engineers can't save a system that doesn't fit in a head.
- **Related:** **Bounded context**, **Conway's Law**, **decomposition**.

### Conway's Law — team structure becomes system structure

> If three departments don't talk to each other, their product almost always looks like three products glued together in one menu.

**Conway's Law** says: an organisation designs systems that mirror the structure of communication inside the organisation. If architectural boundaries don't match team boundaries, the team will keep crossing someone else's turf.

**Team Topologies** introduces useful labels: stream-aligned team, platform team, enabling team, complicated-subsystem team. That isn't HR fashion — it's an architectural tool. Sometimes the right decomposition of the system starts with the right decomposition of responsibility.

_Diagram: Conway's Law: the system mirrors how teams communicate. Team Topologies gives four team types for cutting it on purpose._

#### Conway's Law (plus Team Topologies)

- **What it is:** A system mirrors the communication structure of the organisation that builds it.
- **How it works:** Align team boundaries with system boundaries: each team owns its own area.
- **Example:** Three departments that don't talk ship "three products in one menu".
- **Catch:** If the boundaries don't match, teams keep stepping on each other's turf.
- **Related:** **Team Topologies** (stream-aligned, platform, enabling, complicated-subsystem), **bounded context**.

> **The key question:** How much context does an engineer need to load to safely change this component?

## 5. System decomposition

A big system becomes manageable only when you can cut it along the right boundaries.

### Cohesion & coupling — cut by layers, by domains, or by data flow

> A butcher doesn't cut a carcass at random — they cut at the joints. Good decomposition also looks for natural break points.

Decomposition isn't "sort into folders." It's choosing where responsibility ends. **High cohesion** means everything inside a component is about one thing. **Low coupling** means the component knows little about other components.

A horizontal cut gives you **layers**: UI, application, domain, infrastructure. A vertical cut gives you features or **bounded contexts**: billing, identity, catalog, comments. Real systems need both, but mixing one for the other is dangerous.

_Diagram: A horizontal cut gives layers, a vertical one gives features and contexts. A real system is a grid of both._

#### Cohesion & Coupling (tight inside, loose between)

- **What it is:** Everything inside a component is about one thing (cohesion); it knows little about others (coupling).
- **How it works:** Cut horizontally (layers) and vertically (features / contexts) — and don't confuse the two.
- **Example:** A `billing` module with its own UI → application → domain → infra layers.
- **Catch:** "Sorting into folders" isn't decomposition yet.
- **Related:** **Bounded context**, **layers**, **modular monolith**.

### Bounded context — a bad boundary gives itself away through change

> If replacing the kitchen tap means tearing the bedroom apart, the problem isn't the tap.

A sign of bad decomposition: a small change ripples across five modules. Another sign: one module changes for different reasons — today because of product, tomorrow because of the database, the day after because of an integration.

The DDD term **bounded context** is useful precisely here. It's a boundary inside which words have a single meaning. "Customer" in billing and "Customer" in support can be different models. Forcing them into one often creates a brittle "universal" model.

_Diagram: One word, two models: Customer in billing and Customer in support mean different things — and that's fine._

#### Bounded Context (a DDD boundary of meaning)

- **Problem:** A small change ripples across five modules; one module changes for different reasons.
- **Idea:** A boundary inside which every word has one meaning and one model.
- **Example:** "Customer" in billing and "Customer" in support are different models.
- **Cost:** Models have to be mapped at the boundaries; translation between contexts.
- **When to use:** When one concept means different things to different parts of the business.
- **Related:** **Cohesion / coupling**, **Conway's Law**, **microservices**.

> **Decomposition test:** Can I explain this component without telling you half the system?

## 6. Layers and the direction of dependencies

Business logic should depend on business rules, not on the framework, the database, or HTTP.

### Dependency Rule and DIP — dependencies flow toward the centre

> The foundation shouldn't depend on the colour of the curtains. If it does, the house was designed backwards.

**Clean Architecture**, **Hexagonal Architecture**, and **Onion Architecture** all say the same thing: the important logic belongs at the centre, the details on the outside. HTTP, SQLAlchemy, Next.js, Kafka, Redis, Stripe — these are details. They matter, but they shouldn't define business rules.

The **Dependency Inversion Principle** says: high-level logic depends on abstractions, and implementations get plugged in from outside. In code that looks like ports and adapters: the service receives a `PaymentGatewayProtocol`, it doesn't construct a `StripeClient` inside itself.

_Diagram: The domain at the centre depends only on a port. StripeClient, HTTP, and the database are details outside; every arrow points inward._

#### Dependency Inversion (DIP, the dependency rule)

- **Problem:** Business rules have grown into the framework and the database — you can't test or replace them.
- **Idea:** High-level logic depends on abstractions; implementations plug in from outside.
- **Example:** The service receives a `PaymentGatewayProtocol` instead of constructing a `StripeClient`.
- **Cost:** More interfaces and files.
- **When to use:** There are real business rules that must outlive technology changes.
- **Related:** **Clean / Hexagonal / Onion Architecture**, **ports and adapters**.

### Abstraction — it exists to absorb change, not to look nice

> An adapter belongs where the plugs are actually different. If you put an adapter in every socket just because you like adapters, the house gets less safe.

Not every class needs an interface. But anything touching the outside world, time, randomness, the network, the file system, or the database should be replaceable in tests. Otherwise you're not testing business logic — you're booting a small production system inside a unit test.

The price of a layer is more files and more words. The payoff is testability, infrastructure that can be swapped, clean boundaries. If there's no payoff, the layer is dead weight.

_Diagram: Hide the outside world (time, randomness, network, files, database) behind a port and swap in a fake for tests. Pure logic needs no interface._

#### Abstraction (interfaces where change pushes)

- **What it is:** An interface goes where the implementation really changes or blocks tests.
- **How it works:** Time, randomness, network, files, database → behind a port; a fake in tests, the real adapter in production.
- **Example:** A business rule is tested without a database, HTTP, or real time — in milliseconds.
- **Catch:** A layer with no payoff is extra files and words, not architecture.
- **Related:** **DIP**, **testability**, **over-engineering**.

> **The key question:** Can I test this business rule without a database, HTTP, or real time?

## 7. APIs and contracts

An API is a promise. Breaking a promise is easy; rebuilding client trust is hard.

### API contract — the contract matters more than the transport

> Passport control doesn't care about the brand of the door. What matters is which documents are accepted, which rules apply, and what happens when something is wrong.

**REST**, **GraphQL**, **gRPC**, and **WebSocket** are different ways to talk. REST suits resource-oriented APIs and simple caching. GraphQL helps when different clients need different shapes of read. gRPC is good for typed service-to-service communication. WebSocket is for real-time two-way events.

The transport choice is secondary. The **API contract** is what matters: schema, errors, idempotency, versioning, **backward compatibility**, **deprecation policy**.

_Diagram: The transport on the left can change. The contract on the right is a promise to clients — and expensive to break._

#### API Contract (the promise to clients)

- **What it is:** A promise: schema, errors, idempotency, versions, compatibility, rules for retiring the old.
- **How it works:** Agree on the contract first, then pick the transport for the job.
- **Example:** REST for resources and caching; GraphQL for varied reads; gRPC for typed service-to-service; WebSocket for real time.
- **Catch:** Breaking a promise is easy; rebuilding client trust is hard.
- **Related:** **Idempotency**, **versioning**, **reversible vs irreversible**.

### Idempotency — it saves you from the real world

> If you press the elevator button ten times, the elevator shouldn't arrive and leave ten times. It should understand the intent is one.

**Idempotency** means a repeated operation produces the same final effect. In networked systems, retries are inevitable: timeouts, retries, duplicate webhooks, worker restarts. If creating a payment, order, or message isn't idempotent, the system will eventually do something extra.

The architect designs idempotency at the contract level: **idempotency key**, unique constraints, safe retries, clear statuses.

_Diagram: The client sent the request three times with one key — the server recognised the key and created one payment._

#### Idempotency (repeat-safe operations)

- **What it is:** Repeating an operation gives the same final effect as the first call.
- **How it works:** An idempotency key in the request + a unique constraint in the database + clear statuses.
- **Example:** A payment times out → the client repeats `POST /payments` with the same key → charged once.
- **Catch:** Without it, repeats (retries, duplicate webhooks, worker restarts) eventually do something extra.
- **Related:** **At-least-once delivery**, **API contract**, **retries**.

> **The key question:** What happens if the client repeats this request three times?

## 8. The data model

Code gets rewritten. Data migrates for years. That's why the data model is one of the most expensive architectural decisions.

### Data model — data lives longer than applications

> You can repaint a facade in a week. A foundation poured wrong reminds you of itself for the lifetime of the building.

The language, the framework, the UI may change several times. But tables, events, keys, relations, and historical records stay. A mistake in the data model often becomes a mistake in every future version of the product.

**Normalization** reduces duplication and the risk of drift. **Denormalization** speeds up reads and simplifies the read model. **OLTP** systems are optimised for transactions, **OLAP** for analytics. You can't design one model as if it will perfectly serve both classes of work.

_Diagram: The app was rewritten three times; the data stayed. Below: two different kinds of work — transactions (OLTP) and analytics (OLAP)._

#### Data Model (plus OLTP / OLAP)

- **What it is:** Tables, events, keys, relations, and history — what survives every rewrite of the code.
- **How it works:** Normalization means fewer duplicates and less drift; denormalization means faster reads.
- **Example:** An OLTP database for orders and a separate OLAP store for reports.
- **Catch:** A mistake in the data model becomes a mistake in every future version of the product.
- **Related:** **Irreversible decisions**, **event sourcing**, **CQRS**.

### Event sourcing and CQRS — a strong tool, not a religion

> A bank statement doesn't just store the current balance — it stores the history of operations. That's what lets you explain where the balance came from.

**Event sourcing** stores changes as a sequence of events and reconstructs current state from them. It's useful when history, audit, state recovery, and replay matter. The price is high: event schema evolution, query complexity, eventual consistency, demanding tooling.

**CQRS** separates the write model from the read model. It can dramatically simplify complex read systems, but it adds synchronisation and lag. Introducing CQRS just because "it sounds architectural" is an expensive way to turn one problem into two.

_Diagram: A command writes events to the log; a projection builds a read model from them, and queries read that._

#### Event Sourcing (state as a log of events)

- **Problem:** Current state doesn't explain how we got there.
- **Idea:** Store changes as an event log; state = replaying them.
- **Example:** A bank statement: the balance is the sum of operations.
- **Cost:** Event schema evolution, harder queries, eventual consistency, demanding tooling.
- **When to use:** History, audit, state recovery, and replay matter.
- **Related:** Often paired with **CQRS**.

#### CQRS (Command Query Responsibility Segregation)

- **Problem:** One model serves both writes and complex reads badly.
- **Idea:** Split the write model from the read model.
- **Example:** Orders are written to a normalized model; the reports screen reads a ready-made view.
- **Cost:** Synchronisation and lag between the models.
- **When to use:** When reads are genuinely complex — not because "it sounds architectural".
- **Related:** **Event sourcing**, **denormalization**, **eventual consistency**.

> **The key question:** Which facts in this system have to survive three rewrites of the application?

## 9. State and the source of truth

State is complexity that lives somewhere. The more copies of the truth, the more ways to be wrong.

### Single source of truth — doesn't mean single database

> A company can have many reports, but there has to be one official payroll register. Otherwise payday turns into theatre.

**Single source of truth** means that for every important fact, you know where the authoritative version lives. A cache, a search index, a read replica, a materialized view — these are derived copies. They can be useful, but they shouldn't pretend to be the primary truth.

**Stateful** components hold state and demand care: transactions, locking, recovery, backup. **Stateless** components are easier to scale and replace, but they still depend on state living somewhere else.

_Diagram: Stateless apps on the left, one authoritative database in the middle, derived copies on the right — which are not the truth._

#### Single Source of Truth (one owner per fact)

- **What it is:** For every important fact, it's clear where its authoritative version lives.
- **How it works:** One primary record; the cache, index, replica, and view are derived copies.
- **Example:** Many reports, but one official payroll register.
- **Catch:** It doesn't mean "one database for everything" — it means "one owner per fact".
- **Related:** **Stateful / stateless**, **cache**, **CQRS**.

### Cache and locking — a second truth that sometimes lies

> The schedule on the fridge is convenient, until someone moves the meeting in the phone calendar.

A **cache** buys speed at the cost of freshness. The hardest cache question isn't "how to put things in," it's "when to invalidate." **TTL**, **explicit invalidation**, **write-through**, **write-behind**, **cache-aside** — these are different compromises between complexity, freshness, and load.

_Diagram: Cache-aside: read the cache, on a miss go to the database and put the answer in the cache. On the right: invalidation strategies._

A **race condition** appears when two operations compete for state. **Optimistic locking** says: "conflicts are rare, we'll check the version at write time." **Pessimistic locking** says: "conflicts are dangerous, we'll lock up front." Both are right under different conditions.

_Diagram: On the left, optimistic locking catches the conflict by version at write time. On the right, pessimistic locking makes the second writer wait._

#### Cache Invalidation (the cache and keeping it fresh)

- **What it is:** A copy of data closer to the reader: speed in exchange for freshness.
- **How it works:** TTL, explicit invalidation, write-through, write-behind, cache-aside — different compromises.
- **Example:** The schedule on the fridge vs the calendar on the phone.
- **Catch:** The main question isn't "how to put it in" but "when to throw it out".
- **Related:** **Single source of truth**, **eventual consistency**.

#### Optimistic vs Pessimistic Locking (two ways to handle races)

- **What it is:** Two ways to stop two operations from corrupting shared state (a race condition).
- **How it works:** Optimistic: check the version at write time. Pessimistic: lock up front.
- **Example:** Two managers edit the same record: the second one gets a conflict and re-reads the data.
- **Catch:** Optimistic struggles with frequent conflicts; pessimistic struggles with heavy lock contention.
- **Related:** **Transactions**, **stateful components**.

> **The key question:** Where does the truth about each fact live, and what happens if the copies diverge?

## 10. Distributed systems

Distribution solves problems of scale, but creates problems of time, order, and trust in the network.

### CAP and PACELC — the network is a source of uncertainty

> A monolith is a conversation in one room. A distributed system is correspondence between people in different time zones — letters sometimes get lost, arrive twice, or run late.

In a distributed system, you can't just "call a function." Between services there's a network, timeouts, retries, **partial failure**, different clocks, different versions of code. What was a local transaction in the monolith becomes a coordination protocol.

The **CAP theorem** is often summarised badly. The practically useful version: during a **network partition**, you choose between consistency and availability. **PACELC** adds: even without a partition, you still choose between latency and consistency.

_Diagram: The link between nodes is cut — choose consistency or availability. No cut — you still choose: latency or consistency._

#### CAP / PACELC (the choices of distributed systems)

- **What it is:** During a partition: C or A (CAP). Without one: L or C (PACELC).
- **How it works:** Each store and each scenario states explicitly what it gives up.
- **Example:** A node cut off from its peer: refuse (C) or answer, possibly stale (A).
- **Catch:** "We chose CA" doesn't exist on a network: partitions happen; the only question is what you do then.
- **Related:** **Consistency models**, **trade-off**, **partial failure**.

### Consistency models and Saga — consistency comes in flavours

> Two people looking at the same Google Doc see the same thing almost instantly. Two people looking at a bank transfer can't settle for "almost."

**Strong consistency** gives you fresh truth, but costs latency and availability. **Eventual consistency** tolerates temporary drift, but often scales better. **Causal consistency** preserves cause-and-effect: if event B depends on A, B shouldn't become visible before A.

_Diagram: The consistency scale: from eventual (scales, tolerates drift) to strong (fresh, but more expensive)._

The **saga pattern** breaks a long business transaction into steps with **compensating actions**. **Two-phase commit** gives atomicity across resources, but is expensive and fragile in real distributed systems. The architect picks not "the strictest" model but the one sufficient for the risk.

_Diagram: Saga: step 3 failed — compensating actions undo the completed steps 2 and 1 in reverse order._

#### Consistency Models (strong · causal · eventual)

- **What it is:** How fast, and in what order, everyone sees the same truth.
- **How it works:** Strong: always fresh. Causal: keeps cause-and-effect order. Eventual: catches up later.
- **Example:** A shared doc: "almost instantly" is fine. A bank transfer: it isn't.
- **Catch:** Strong pays in latency and availability; eventual pays in temporary drift.
- **Related:** **CAP / PACELC**, **cache**, **CQRS**.

#### Saga (a long transaction with compensations)

- **Problem:** A business operation spans several services; there's no shared transaction.
- **Idea:** A chain of steps; if one fails, compensating actions undo what was done.
- **Example:** Reserve stock → charge → shipping fails → refund → release the reservation.
- **Cost:** Every step needs a compensation; intermediate states are visible.
- **When to use:** Instead of **two-phase commit**, which is costly and fragile across a network.
- **Related:** **Eventual consistency**, **idempotency**, **microservices**.

> **The key question:** What exactly has to be consistent immediately, and what is allowed to catch up later?

## 11. Monolith and microservices

Microservices don't fix bad design. They turn local problems into distributed ones.

### Modular monolith — an often underrated start

> One well-organised warehouse is faster than ten small ones if the same courier is driving between them anyway.

A monolith isn't an insult. A bad monolith is a tangle of dirty dependencies. A good **modular monolith** has strict internal boundaries, separate domains, explicit interfaces, and a single **deployment unit**. For a small team, it's often the best starting point.

**Microservices** help when you need independent releases, autonomous teams, different scaling profiles, failure isolation, or different technology stacks. The price: network calls, observability, distributed transactions, DevOps overhead, versioning, security between services.

_Diagram: On the left, one deploy unit with strong walls inside. On the right, separate services with their own databases and a bill for the network._

#### Modular Monolith (one deploy, strong walls)

- **Problem:** The monolith turns into a tangle of dirty dependencies.
- **Idea:** Strict internal boundaries and explicit interfaces — but one deployment unit.
- **Example:** Billing, identity, and catalog modules in one app, talking through module APIs.
- **Cost:** Needs boundary discipline; scales and releases as a whole.
- **When to use:** A small team, an early product. **Microservices** — when you need independent releases, autonomous teams, different load profiles, failure isolation.
- **Related:** **Bounded context**, **microservices**, **Strangler Fig**.

### Distributed monolith and Strangler Fig — the worst of both worlds, and the way out

> It's like living in separate apartments but walking next door for every spoon.

A **distributed monolith** looks like microservices, but the services aren't autonomous: shared database schema, synchronous call chains, releases that only ship together, changes that require touching everyone. The team pays the cost of distribution without getting the independence.

_Diagram: Distributed monolith: services tied by a synchronous chain and a shared schema — no independence._

The **Strangler Fig pattern** lets you migrate carefully: wrap the old system, gradually extract capabilities, cut along real business boundaries, not along tables.

_Diagram: Strangler Fig: a facade in front of the old system moves capabilities out to new services one by one, until the old one is gone._

#### Distributed Monolith (microservices in name only)

- **Signs:** Shared database schema, synchronous call chains, releases only together, every change touches everyone.
- **Why it hurts:** You pay for distribution and get no independence.
- **Example:** Separate apartments, but next door for every spoon.
- **Way out:** Own data per service, async links, boundaries by business meaning — or back to a modular monolith.
- **Related:** **Modular monolith**, **bounded context**, **sync vs async**.

#### Strangler Fig (gradual replacement)

- **Problem:** The old system can't be rewritten in one go.
- **Idea:** Wrap it in a facade and gradually move capabilities out into new services.
- **Example:** Extract billing first, then catalog — the facade routes the requests.
- **Cost:** Two systems live side by side for a long time.
- **When to use:** Migrating a live system without a "big rewrite".
- **Related:** Cut along **bounded contexts**, not along tables.

> **The key question:** What pain are we treating with microservices: load, teams, releases, fault tolerance — or just boredom?

## 12. Sync and async

Sync couples systems in time. Async breaks that coupling, but brings delays, duplicates, and ordering complexity.

### Queue and pub/sub — a queue isn't just "later"

> A phone call requires both sides to be free now. A letter can be read later — but it can get lost, run late, or demand a reply.

A **synchronous (sync)** call is easy to reason about: send, get an answer. But if the receiver is slow or unavailable, the sender suffers. **Async** via a **queue** or **pub/sub** lets you ride out failures and load spikes, but it demands a different mental model.

A queue usually distributes work across consumers. Pub/sub broadcasts an event to many subscribers. Kafka, RabbitMQ, SQS, Redis Streams — different tools with different ordering, durability, replay, and operational models.

_Diagram: Sync: the sender waits. Queue: each message goes to one worker. Pub/sub: each event reaches every subscriber._

#### Queue vs Pub/Sub (work distribution vs broadcast)

- **Problem:** A sync call couples systems in time: the receiver goes down, the sender suffers.
- **Idea:** A queue splits work across consumers; pub/sub sends an event to every subscriber.
- **Example:** Kafka, RabbitMQ, SQS, Redis Streams — different ordering, durability, replay.
- **Cost:** Delays, duplicates, ordering complexity.
- **When to use:** The sender doesn't need the result right now; you must ride out failures and spikes.
- **Related:** **At-least-once delivery**, **backpressure**, **idempotency**.

### At-least-once delivery — exactly-once is almost always marketing

> If a letter is sent twice, decent accounting shouldn't pay the salary twice.

In practice you design for **at-least-once delivery** plus an **idempotent consumer**. A message can arrive twice; the handler has to survive it. A **dead letter queue** is for messages that couldn't be processed after a reasonable number of attempts.

**Backpressure** is the signal "the receiver can't keep up." Without it, the system gracefully accepts everything and then dies on the inside.

_Diagram: A message may arrive twice — the consumer drops duplicates by id. After N failures it goes to the DLQ. Backpressure asks the sender to slow down._

#### At-least-once Delivery (plus DLQ and backpressure)

- **What it is:** A message is guaranteed to arrive, but maybe more than once.
- **How it works:** An idempotent consumer drops duplicates; a dead letter queue collects messages after N failures; backpressure says "I can't keep up".
- **Example:** A duplicate "pay the salary" message doesn't pay it twice.
- **Catch:** "Exactly-once" is almost always marketing; without backpressure the system accepts everything and dies inside.
- **Related:** **Idempotency**, **queue / pub/sub**, **reliability**.

> **The key question:** Does the sender need to know the result right now, or is it enough to put the work into the pipeline reliably?

## 13. Performance and measurement

"Make it fast" isn't a requirement. A requirement sounds like latency, throughput, percentiles, and a load profile.

### Tail Latency — average response time almost always lies

> If nine people got their food in a minute and the tenth waited an hour, the average looks tolerable. The tenth disagrees.

This is the concept of **tail latency**. First, three words. **Latency** is the delay of a single operation. **Throughput** is how many operations the system handles per unit of time. **Percentiles** show the distribution: **p50** is the median, **p95** means 95% of requests are faster than that value, **p99** is the tail.

The user doesn't feel the average — they feel the tail. Tail latency matters especially in systems where one screen depends on several backend calls: the probability of a slow response stacks up.

_Diagram: Most requests are fast, but the tail (p95, p99) is long. The average hides it; the user feels it._

#### Tail Latency (p95 / p99)

- **Problem:** The average response time looks fine while some users wait a very long time.
- **Idea:** Look at percentiles: p50 is the median, p95 and p99 are the tail.
- **Example:** A screen is built from five backend calls: if any one of them lands in the tail, the whole screen is slow.
- **Cost:** You collect a distribution, not one number; you need histograms in your metrics.
- **When to use:** Every time you turn "fast" into a requirement or build an SLO.
- **Related:** The basis for **SLOs**; grows during a **retry storm**; visible through **observability**.

### Profiling — profile before you optimise

> Fixing performance without a profile is like treating a patient from a photo of their shoes.

This is the practice of **profiling**: measure first, optimise second. N+1 queries, extra round trips, a bad index, serialisation, lock contention, GC pause, cold cache — they all look like "slow," but they're cured differently.

**Amdahl's Law** reminds you: speedup is bounded by the part of the system you actually optimise. **Little's Law** helps you think about queues: more latency at the same throughput means more work-in-progress sitting inside the system.

_Diagram: The loop: measure → profile → find the hotspot → fix one thing → measure again. Below, two laws that bound your expectations._

#### Profiling (measure before you optimise)

- **Problem:** The team "speeds up" the wrong place: a week spent, and the system is no faster.
- **Idea:** A profile shows where the time really goes. Fix only the hotspot.
- **Example:** The "slow page" turns out to be an N+1 query, not a slow language — fixed with one query and a join.
- **Cost:** Time for measuring and tooling; you need a reproducible load profile.
- **When to use:** Before any optimisation. No profile, no optimisation.
- **Related:** **Amdahl's Law** is the speedup ceiling; **Little's Law** links latency, throughput, and queues.

> **The key question:** Which metric goes red first under real load?

## 14. Scalability without a rewrite

Scalability is the ability to grow in load and in features without rebuilding the system from scratch.

### Vertical vs Horizontal Scaling — they buy different things

> You can buy one big truck. You can buy ten small ones. The first is simpler, the second is more flexible — but requires a dispatcher.

**Vertical scaling** (scale up) means making one machine stronger. Simple, while there's headroom. **Horizontal scaling** (scale out) means adding more instances. More flexible, but requires a stateless application layer, load balancing, a shared state strategy, and observability.

Databases scale harder than applications. **Read replicas** help reads, not writes. **Sharding** splits data but forces you to pick a shard key. A bad shard key turns scaling into a load imbalance.

_Diagram: Left: one machine grows until it hits the hardware ceiling. Right: a load balancer and many identical stateless copies. Below: two ways to scale the database._

#### Vertical vs Horizontal Scaling (scale up / scale out)

- **Problem:** Load is growing, and one machine will soon not be enough.
- **Idea:** Vertical: make the machine stronger. Horizontal: put more machines behind a load balancer.
- **Example:** A stateless app is easy to multiply; the database is harder: read replicas for reads, sharding by a shard key for writes.
- **Cost:** Vertical hits a ceiling. Horizontal needs a stateless layer, load balancing, a shared state strategy, and observability.
- **When to use:** Vertical while there's headroom. Horizontal when you need to grow past it.
- **Related:** The X-axis of the **Scale Cube**; **stateless** components from the state module; **Single Source of Truth**.

### Scale Cube — scaling features matters as much as scaling load

> A city doesn't grow only by population. It grows by schools, hospitals, roads, and rules.

The system has to absorb not just more traffic but more product surface. If every new feature requires rewriting a shared God-service, the system doesn't scale organisationally.

The useful model here is the **scaling cube**: **X-axis** is cloning, **Y-axis** is splitting by function, **Z-axis** is partitioning by data or tenants.

_Diagram: Three axes of growth: X — copies of one app, Y — different functions in different parts, Z — data or customers split into partitions._

#### Scale Cube (X / Y / Z axes)

- **Problem:** People only think about traffic, but the system breaks from feature growth: everything lives in one God-service.
- **Idea:** Grow along three axes: X — clone, Y — split by function, Z — split by data or tenants.
- **Example:** X: three copies of the app. Y: billing, catalog, identity apart. Z: tenants A–H on one shard, I–P on another.
- **Cost:** Every axis adds boundaries you have to hold and observe.
- **When to use:** When you ask "what breaks first" — and the answer isn't only CPU.
- **Related:** The Y-axis is **Bounded Context** and microservices; the Z-axis is sharding; mind **Conway's Law**.

> **The key question:** What breaks first: CPU, the database, the team, releases, or the data model?

## 15. Reliability under failure

A reliable system isn't one where nothing breaks. A reliable system knows what to do when it does.

### Retry, Circuit Breaker, Bulkhead — retry without a strategy is an attack on yourself

> If a door doesn't open, knocking once is reasonable. Knocking a thousand times a second is now a problem for the door and the neighbours.

**Retry** is for transient failures. But retries need a limit, a timeout, **exponential backoff**, and **jitter**. Otherwise a partial outage turns into a **retry storm**.

A **circuit breaker** temporarily stops calls to a stuck dependency. The **bulkhead pattern** isolates resources: if one downstream dies, it doesn't take all your worker threads and connection pools with it.

_Diagram: Top: retries with a growing pause and a random offset. Bottom: separate pools (bulkheads) and a circuit breaker — a stuck Payments API doesn't drag search down with it._

#### Retry + Circuit Breaker + Bulkhead (resilience to failing dependencies)

- **Problem:** A dependency slows down or dies; mindless retries finish it off and eat all of the service's resources.
- **Idea:** Retry with a limit, timeout, backoff, and jitter. Circuit breaker: stop calling the dead. Bulkhead: separate pools so a failure doesn't spread.
- **Example:** The payments API hangs: the breaker opens and fails fast, while the search pool keeps working.
- **Cost:** More settings and states; you have to decide how the system degrades when a dependency is down.
- **When to use:** Any network call to something that can hang.
- **Related:** Retries are only safe with **Idempotency**; linked to **at-least-once** and **backpressure**.

### SLI / SLO / SLA — SLOs turn reliability into a contract

> "We'll try our best" isn't a train schedule. A schedule says what counts as normal and what counts as a failure.

**SLI** is what you measure: success rate, latency, freshness. **SLO** is the target: 99.9% successful requests over 30 days. **SLA** is a promise to the customer with consequences attached.

The **error budget** tells you how much unreliability you're allowed to spend. If the budget is burned, the team stops chasing features and fixes reliability. That's the business-language version of engineering quality.

_Diagram: SLI is the measurement, SLO the target, SLA the promise to the customer. With a 99.9% SLO the error budget is 0.1% — about 43 minutes per 30 days._

#### SLI / SLO / SLA (error budget)

- **Problem:** Nobody measured "reliable," so the features-vs-quality argument never ends.
- **Idea:** Measure (SLI), agree on a target (SLO), keep the customer promise separate (SLA). The gap to 100% is the error budget.
- **Example:** SLO: 99.9% successful requests over 30 days. Budget burned — features pause.
- **Cost:** You must honestly pick what to measure and keep the rule when the budget runs out.
- **When to use:** When reliability has to be discussed with the business in one language.
- **Related:** SLIs are often built on **Tail Latency**; alerts fire on **symptoms**; it's an **NFR** in numbers.

> **The key question:** How does the system degrade when a dependency is unavailable?

## 16. Security as a way of life

You can't add security right before release. It has to be built into the access model, the data, the infrastructure, and the processes.

### Authentication vs Authorization — different things

> A passport proves who you are. A ticket proves where you're allowed to go. One doesn't replace the other.

**Authentication** (AuthN) answers "who is this?". **Authorization** (AuthZ) answers "what are they allowed to do?". Confusing them is dangerous: a user can be correctly logged in and still have no right to read someone else's invoice.

**RBAC** grants permissions through roles. **ABAC** considers attributes: resource owner, tenant, region, object state. Session-based auth is easier to revoke; **JWT** is easier to verify without a database, but harder to revoke. The choice depends on threats and lifecycle.

_Diagram: A request passes two different steps: authentication (“who are you?” — the passport) and authorization (“what may you do?” — the ticket). Logged in doesn't mean allowed._

#### Authentication vs Authorization (AuthN / AuthZ)

- **Problem:** "The user is logged in" gets confused with "the user is allowed" — and they read someone else's data.
- **Idea:** Two separate steps: AuthN establishes identity, AuthZ checks the right to a specific resource.
- **Example:** A logged-in customer requests another customer's invoice #42 — AuthZ must answer 403.
- **Cost:** Choosing a model: RBAC is simpler, ABAC more precise; sessions are easy to revoke, JWTs easy to verify but hard to revoke.
- **When to use:** In any system where data has an owner.
- **Related:** One layer of **defense in depth**; the spoofing and elevation-of-privilege threats from **STRIDE**.

### Threat Modeling — professional paranoia

> A good architect thinks like an attacker not because they distrust people, but because they trust reality.

**Threat modeling** is a systematic search for threats before an attack. **STRIDE** helps you look for them: spoofing, tampering, repudiation, information disclosure, denial of service, elevation of privilege. **Defense in depth** means several layers of protection: input validation, authz, encryption, audit log, rate limiting, least privilege.

**Secrets management** isn't "put the key in env and forget." You need to understand rotation, access, audit, blast radius, and what happens during a leak.

_Diagram: Left: the six STRIDE threat classes to walk every component through. Right: protection in layers — if one layer is breached, the others remain._

#### Threat Modeling (STRIDE, defense in depth)

- **Problem:** Security gets remembered right before release, when the access model is too late to change.
- **Idea:** Walk the component through STRIDE and put up several layers of protection, not one "main" lock.
- **Example:** A leaked key: what it opens (blast radius), how fast you can rotate it, where it shows up in the audit.
- **Cost:** Time for the review and discipline in secrets management.
- **When to use:** At design time for every new component and integration.
- **Related:** **AuthN vs AuthZ** is a layer of protection; **observability** and the audit log let you spot an attack.

> **The key question:** What can an attacker do if they get access to this component?

## 17. Observability and operations

You can't fix what you can't see. The system has to explain its own state without archaeology in the code.

### Observability — monitoring tells you what's wrong, observability helps you understand why

> A "check engine" light is useful, but the mechanic still needs gauges, history, and diagnostic tools.

**Monitoring** answers "something is wrong." **Observability** answers "why." The three pillars of observability: **logs**, **metrics**, **traces**. Structured logging makes logs queryable. Metrics show aggregates. **Distributed tracing** follows a request's path through services.

A **correlation ID** is a small thing that saves nights: one request ID flows through gateway, service, queue, worker, and downstream.

_Diagram: Three pillars — logs, metrics, traces. One correlation ID passes through every hop, so the whole request path can be put back together._

#### Observability (logs · metrics · traces, correlation ID)

- **Problem:** Something broke at night, and the cause is hunted by archaeology in the code.
- **Idea:** The system explains its own state: structured logs, aggregate metrics, traces of the request path.
- **Example:** With request id `req-7f3a` you find the request in the gateway, the queue, and the worker — and see where it got stuck.
- **Cost:** Tooling, data storage, and the discipline to pass the ID everywhere.
- **When to use:** From day one, especially in a distributed system with queues.
- **Related:** The data source for **SLIs** and **Symptom-based Alerting**; without it, **Profiling** is blind.

### Symptom-based Alerting — alert on symptoms

> The user doesn't care that CPU is at 92%. They care that checkout doesn't work.

A good alert speaks user pain — this is **symptom-based alerting**: error rate, latency, failed payments, stale data. A bad alert speaks of a cause that can be perfectly normal. If alerts are noisy, the team stops trusting them.

A **runbook** answers "what to do at 3 a.m." A **post-mortem** answers "how do we make sure this doesn't happen again." **Blameless**; the goal is to improve the system, not to find the guilty party.

_Diagram: Causes like CPU are often normal and make noise. Alerts are built on symptoms of user pain, followed by a runbook and a blameless post-mortem._

#### Symptom-based Alerting (runbook, blameless post-mortem)

- **Problem:** Alerts fire on causes, the team gets used to the noise and misses a real outage.
- **Idea:** Wake a human only for user pain; every alert gets a runbook.
- **Example:** Not "CPU 92%," but "failed payments went up" — plus a runbook: what to check first.
- **Cost:** You need to know your symptoms and keep runbooks up to date.
- **When to use:** For everything the on-call engineer has to fix at night.
- **Related:** Symptoms are **SLIs**; the post-mortem is the same written culture as **ADRs** and **RFCs**.

> **The key question:** If this breaks at night, what data will help find the cause in ten minutes?

## 18. Documentation that lives

An unrecorded architectural decision disappears together with the context of its author.

### ADR — an Architecture Decision Record beats memory

> An oral agreement is good until the first vacation, the first resignation, or the first argument six months later.

An **Architecture Decision Record** captures context, decision, alternatives, and consequences. An ADR doesn't have to be a novel. A good ADR answers: what problem were we solving, what did we choose, why didn't we choose the alternatives, when do we revisit.

Documentation isn't there for the audit — it's there for the next change. A new engineer has to understand not just "how" but "why."

_Diagram: One ADR, one decision: context, choice, alternatives, consequences, and when to revisit. Six months later a new person learns the “why.”_

#### ADR (Architecture Decision Record)

- **Problem:** The decision lived in the author's head; the author left, and nobody knows why it was done this way.
- **Idea:** A short record per decision: context, decision, alternatives, consequences.
- **Example:** "We take PostgreSQL, not MongoDB: we need transactions; revisit if document-style workloads appear."
- **Cost:** Half an hour to write. Cheaper than the argument six months later.
- **When to use:** For decisions that are expensive to reverse.
- **Related:** Records **Trade-offs** and debt; sits next to the **RFC**; part of **Learning in Public**.

### C4 Model — a diagram is a working tool, not a decoration

> A subway map doesn't show the wires or the bolts. It shows lines and transfers. That's enough not to get lost.

The **C4 model** gives you four levels: **Context**, **Container**, **Component**, **Code**. The first three are usually enough. A **sequence diagram** is useful when the order of interactions matters. Full UML is rarely needed; individual diagrams, yes.

**Living documentation** lives next to the code, updates in the PR, and gets reviewed. A document in a forgotten wiki quickly turns into historical fiction.

_Diagram: The four C4 zoom levels — three are usually enough. Living docs sit next to the code; a forgotten wiki turns into fiction._

#### C4 Model (living documentation)

- **Problem:** Diagrams are drawn for looks: everything on one picture, and a month later it lies.
- **Idea:** Draw by zoom level: Context → Container → Component (→ Code, rarely).
- **Example:** Context: the system, users, external services. Container: web, API, database, queue.
- **Cost:** Diagrams have to be updated in the same PR as the code.
- **When to use:** When the system has to be explained to a new person or another team.
- **Related:** Shows **Bounded Contexts** and boundaries; a sequence diagram covers the order of calls.

> **The key question:** Will a new person, six months from now, be able to understand why we did it this way?

## 19. Communication and persuasion

The architect talks to engineers, product, business, security, and legal. Each audience hears a different language.

### Risk Translation — translate risk into the audience's language

> A doctor doesn't only use Latin names with the patient. They explain what will hurt, how long the treatment is, and what to avoid.

This is the practice of **risk translation**. You can say to an engineer: "we have no idempotency on the payment callback." The business needs to hear: "if the webhook retries, we may charge twice or ship the product twice; that's a financial and reputational risk."

**Stakeholder mapping** helps you see who cares about what: product wants time-to-market, security wants risk reduction, finance wants predictable cost, support wants understandable behaviour, engineering wants maintainability.

_Diagram: The same risk sounds different to engineers and to the business. The stakeholder map shows what matters to each._

#### Risk Translation (stakeholder mapping)

- **Problem:** A technical risk sounds like jargon, and the business doesn't hear it.
- **Idea:** Translate the risk into consequences that matter to this particular audience.
- **Example:** "No idempotency on the callback" → "we may charge twice — a financial and reputational risk."
- **Cost:** You need to know what each stakeholder cares about and speak their language.
- **When to use:** Every time a decision depends on people outside engineering.
- **Related:** The example is **Idempotency**; the business side is **NFRs** and **cost of delay**.

### RFC — a written proposal lowers the temperature of an argument

> An argument at the whiteboard is often won by the loudest voice. A written proposal forces the arguments to stand apart from the voice.

An **RFC** (Request for Comments) describes the problem, the constraints, the options, the chosen solution, the risks, and the rollout plan. A good RFC invites criticism before the decision becomes policy.

**Disagree and commit** works only after an honest discussion. If the team wasn't heard, that isn't commit — that's suppression.

_Diagram: The sections of an RFC and the path of a decision: draft → review with criticism → decide → disagree and commit, but only if everyone was heard._

#### RFC (Request for Comments, disagree and commit)

- **Problem:** The whiteboard argument is won by the loudest, not the most right.
- **Idea:** In writing: problem, constraints, options, decision, risks, rollout. Criticism comes before the decision.
- **Example:** Before moving to a new queue: an RFC, a week of comments, then a decision and an ADR.
- **Cost:** Slower than "deciding on a call"; needs an owner who drives it to a decision.
- **When to use:** For decisions that touch several teams or are expensive to reverse.
- **Related:** The outcome goes into an **ADR**; a tool of **Influence without Authority**.

> **The key question:** How do I explain this decision to someone who doesn't share my technical priorities?

## 20. Leadership without authority

The architect is often still an individual contributor. Their authority comes from clarity of thinking, trust, and the ability to make the team stronger.

### Influence without Authority

> A conductor doesn't play every instrument, but without one the orchestra quickly becomes a set of talented people playing different pieces.

This is the concept of **influence without authority**. The architect shouldn't become a bottleneck on every decision. Their job is to set principles, explain boundaries, grow people, and step in where the cost of a mistake is high.

Architect **mentoring** isn't "do as I do." It's teaching the questions: what alternatives have you seen, what did you give up, how will you test the risk, where does the responsibility end.

_Diagram: Left: the architect as a bottleneck — every decision waits in line. Right: a multiplier — principles, boundaries, and questions, while the teams decide._

#### Influence without Authority (mentoring through questions)

- **Problem:** The architect decides everything personally and becomes a queue for every team.
- **Idea:** Influence through principles, boundaries, and questions, not orders.
- **Example:** Instead of "do it this way": "what alternatives did you see, and how will you test the risk?"
- **Cost:** Slower in the moment; it needs trust that takes years to build.
- **When to use:** Whenever you have no direct reports but decisions still need to happen.
- **Related:** Works through **RFCs** and **ADRs**; the opposite is the **Ivory Tower Architect**.

### Delegation with Guardrails — delegating doesn't mean transferring ownership

> A captain can hand off the wheel, but they can't say the course of the ship is no longer their problem.

Part of architectural decisions should be made by the teams. Otherwise the architect becomes a queue. But there have to be **guardrails**: principles, review, ADRs, platform constraints, quality gates.

The architect steps in when a decision is irreversible, breaks system invariants, creates security risk, or affects several teams.

_Diagram: The team decides on its own inside the guardrails. The architect steps in only on the four signals on the right._

#### Delegation with Guardrails (ownership stays)

- **Problem:** Either everything goes through the architect (a queue), or nobody owns the course.
- **Idea:** Teams decide on their own inside guardrails; the architect owns the course and steps in on clear signals.
- **Example:** The team picks its logging library itself; changing the tenancy model happens only with the architect.
- **Cost:** Guardrails have to be formulated, written down, and checked automatically where possible.
- **When to use:** When there's more than one team and one architect.
- **Related:** The "irreversible" signal comes from **Reversible vs Irreversible**; guardrails are **ADRs** and quality gates.

> **The key question:** Am I amplifying the team's ability to make decisions, or am I substituting myself for the team?

## 21. Business and product

Architecture only makes sense in the context of a business goal. Otherwise it's expensive engineering aesthetics.

### Non-functional Requirements — business requirements too

> For a shop, "checkout works on Black Friday" isn't a technical detail — it's money.

**Non-functional requirements** (NFRs) — performance, availability, security, compliance, operability — aren't "technical wants." They're product properties. The architect translates them into business impact: lost revenue, regulatory risk, support cost, speed of market launches.

**Cost of delay** helps you discuss not just the cost of doing the work, but the cost of waiting. Sometimes an architectural investment without immediate ROI is needed, because without it the next features start getting more expensive.

_Diagram: Left: non-functional requirements. Right: what they turn into for the business. The architect is the translator in the middle._

#### Non-functional Requirements (NFRs, cost of delay)

- **Problem:** System quality is treated as a "technical want" and keeps being postponed.
- **Idea:** NFRs are product properties; talk about them in revenue, risk, and cost.
- **Example:** "Checkout survives Black Friday" is money, not a detail.
- **Cost:** You need to estimate the impact in numbers, at least roughly.
- **When to use:** When architectural work competes with features for time.
- **Related:** In numbers: **SLOs**; postponed work: **Technical Debt**; the language: **Risk Translation**.

### Build vs Buy — not a matter of pride

> Not every company should build its own power station just to turn the lights on.

**Building** gives you control and differentiation. **Buying** gives you speed and lowers operational load. **Vendor lock-in** is a real risk, but on its own it isn't an argument against buying. The question: how expensive is the exit if the vendor changes price, API, or quality?

The architect helps product see the **capability map**: which capabilities are the core of the business, and which are better bought.

_Diagram: Build the core customers pay you for; buy the commodity. For anything bought, the key question is the exit cost._

#### Build vs Buy (capability map, vendor lock-in)

- **Problem:** People build their own out of pride, or buy everything with no exit plan.
- **Idea:** Build what differentiates the business; buy the commodity. For anything bought, estimate the exit cost.
- **Example:** Your own domain engine — build; email delivery or payments — usually buy.
- **Cost:** Build: time and maintenance forever. Buy: dependence on the vendor's price, API, and quality.
- **When to use:** Before every "let's write our own."
- **Related:** The trap is **NIH syndrome**; **Dependency Inversion** helps isolate the vendor.

> **The key question:** How does this architectural decision change the speed, the risk, or the cost of the business?

## 22. The AI-native architect

When code is written by agents, the architect's value moves into specification, architectural thinking, and quality control.

### Specification-driven Development — spec quality becomes the bottleneck

> If the construction crew gets ten times faster, the binding constraint stops being the speed of bricks. It becomes the quality of the blueprints.

AI agents speed up implementation, but they don't remove architecture. A poorly framed task just turns into bad code faster. **Specification-driven development** means the primary artifact is the specification of behaviour, boundaries, invariants, tests, and acceptance criteria.

In an AI-native process, the architect writes less low-level code and more precise prose. They review the diff, the tests, the architectural boundaries, and the alignment with the spec.

_Diagram: The spec is the main artifact. The agent quickly turns it into code; the architect checks the code against the spec and, on a miss, fixes the spec._

#### Specification-driven Development (the spec as the main artifact)

- **Problem:** An agent writes code ten times faster — and builds the wrong thing just as fast.
- **Idea:** The main artifact is the spec: behaviour, boundaries, invariants, tests, acceptance criteria.
- **Example:** Instead of "build payments": scenarios, errors, the invariant "one payment per order," and tests for it.
- **Cost:** The architect writes more precise prose and less code.
- **When to use:** Whenever an AI agent does the implementation.
- **Related:** Checked by **Agent Output Review**; invariants come from the **API Contract** and the **Bounded Context**.

### Agent Output Review — agent code deserves the same discipline as a human PR

> A fast junior who writes a thousand lines an hour still needs review. Speed doesn't make code correct.

You can't accept agent code because it compiles. You need tests, evals, import boundaries, type checks, security review. **Scenario evaluations** matter especially: the system has to pass real cases, not just the happy path.

An AI-native organisation wins not where "everyone is vibe-coding," but where there are strong specifications, small iterations, automated checks, and architectural ownership.

_Diagram: An agent's PR passes the same quality gates as a human's: tests, scenario evals, import boundaries, types, security review._

#### Agent Output Review (quality gates for AI code)

- **Problem:** Agent code gets accepted because it compiles and looks confident.
- **Idea:** The same automated quality gates and the same review as for a human.
- **Example:** Scenario evals catch that the agent handled only the happy path and forgot the repeated payment.
- **Cost:** The automated checks and import boundaries have to be built in advance.
- **When to use:** Every PR from an agent, no exceptions.
- **Related:** Checks alignment with **Specification-driven Development**; boundaries come from **Dependency Inversion**.

> **The key question:** Is the specification precise enough that a fast executor won't build the wrong thing?

## 23. The architect's anti-patterns

The architect can be dangerous precisely because they sound convincing. Knowing the traps saves years.

### Ivory Tower Architect

> Someone draws a perfect city up on the hill but never walks down to see where people actually go.

This is the **ivory tower architect** anti-pattern: decisions made far from the code, the operations, and the team. The diagrams are beautiful, but the implementation suffers. The cure is simple: read PRs, watch incidents, talk to engineers, walk the change path yourself.

_Diagram: The tower is far from the ground: from the code, incidents, and engineers. The cure is to come down — read PRs, watch incidents, talk, walk the change path._

#### Ivory Tower Architect (architecture from the hill)

- **Symptom:** Beautiful diagrams the team can't implement.
- **Why it hurts:** Decisions ignore the real code, operations, and people.
- **Cure:** Read PRs, watch incidents, talk to engineers, walk the change path yourself.
- **Related:** The opposite of **Influence without Authority**; form over reality is also **Cargo Cult**.

### Resume-driven Development and Cargo Cult

> Buying a fire truck because it impresses the neighbours is strange if you don't have water or firefighters.

**Resume-driven development** picks technologies for a line on the CV. **Cargo cult engineering** copies the shape of someone else's decision without the reason. **NIH syndrome** (Not Invented Here) forces you to write your own where a mature external tool would do better.

Another trap is **technical perfectionism**. The perfect architecture that never reached the user loses to a good-enough system that ships and can evolve.

_Diagram: Four traps that pull you away from the real problem: tech for the CV, copying the form, “let's build our own,” and endless polishing._

#### Resume-driven Development (cargo cult, NIH, perfectionism)

- **Symptom:** The decision is justified by fashion, someone else's example, or beauty — not by a problem.
- **Why it hurts:** You pay the price of a complex technology without its benefit, or never reach the user.
- **Example:** Kubernetes and microservices for a team of three, "because Netflix does it."
- **Cure:** Start from the problem and honestly name the price of every option.
- **Related:** Cured by **Trade-offs** and **Build vs Buy**; often produces a **Distributed Monolith**.

> **The key question:** Am I picking this decision for the problem, or for the feeling of architectural beauty?

## 24. Continuous growth

Architecture is an infinite game. Technologies change, but the ability to ask the right questions only gets stronger.

### T-shaped / M-shaped Skills — learn from systems, not from hype

> A cook grows not from watching knife ads, but from understanding ingredients, heat, time, and taste.

New technologies are worth studying through questions: what problem do they solve, what price do they introduce, where have they already failed, what are the alternatives, what has to be true for them to become useful.

_Diagram: Five filter questions for any new technology. After them, you decide: adopt now or wait._

**T-shaped skills** give you depth in one area and breadth across the neighbours. **M-shaped skills** appear in a mature architect: several deep pillars — data, distribution, security, product, AI tools.

_Diagram: T: one deep area plus breadth. M: several deep pillars in a mature architect._

#### T-shaped / M-shaped Skills (learn from systems, not hype)

- **Problem:** People learn every trendy technology, yet gain no depth or judgement.
- **Idea:** Study technologies through questions about problem and price; grow several deep pillars.
- **Example:** A new database: what problem it solves, where it has already failed, what must be true for it to help us.
- **Cost:** Slower than reading announcements; depth takes years.
- **When to use:** With every new technology on the radar.
- **Related:** A guard against **Resume-driven Development**; the pillars are this course's topics.

### Learning in Public — accelerates maturity

> When you explain a decision in writing, the gaps in your thinking show up before production finds them.

**Learning in public** means learning openly, in writing. Write ADRs, RFCs, engineering notes, post-mortems, short breakdowns of decisions. Learn from architects stronger than you — not just what they chose, but how they reasoned.

The architect people imitate usually isn't the one who knows the most terms. It's the person next to whom the team starts asking better questions.

_Diagram: The loop: decide → write it down → get feedback → ask better questions. Gaps in your thinking show up before production._

#### Learning in Public (learning in writing)

- **Problem:** Production finds the flaws in your reasoning before your colleagues do.
- **Idea:** Write down decisions and breakdowns, share them, learn from the feedback.
- **Example:** ADRs, RFCs, engineering notes, post-mortems, short decision breakdowns.
- **Cost:** Time to write, and the nerve to show unfinished thinking.
- **When to use:** All the time — this is how an architect grows.
- **Related:** Uses **ADRs**, **RFCs**, and **post-mortems**; makes the team stronger, like **Influence without Authority**.

> **The final question:** What questions am I now asking before I open the editor?

#### Final self-check

- I can name the trade-offs of a decision without ego defence.
- I understand where the source of truth lives in the system.
- I tell reversible decisions from irreversible ones.
- I can explain the architecture to engineering, product, and business in different words.
- I write decisions so they can still be understood a year from now.
- I don't hide complexity behind the words "best practice."

### The course map: how it all connects

> A subway map at the end of the trip: now you see where the lines cross.

Mindset shapes the structure, the data, and the quality. Structure gets recorded in documents, quality gets verified by security and operations, and documents and risks convince the business. Together it all scales into AI-native work and personal growth.

_Diagram: The course's eight concept groups and how they connect: from mindset to structure, data, and quality, then on to documents, business, operations, and growth._

## Cheat sheet: all 52 concepts of the course

### The architect's mindset (1–4)

- **Long-term Thinking** (thinking in years): First check whether the problem is posed right, and how the decision will live in three years.
- **Reversible vs Irreversible** (two kinds of decisions): Decide fast on what's easy to undo; slowly on what changes the system's trajectory.
- **Trade-offs** (a deliberate exchange): Every choice buys one property at the cost of another. Best practice without context is bad advice.
- **Over- / Under-engineering** (complexity is a tax): Complexity is justified only when it buys an important property. Hold the middle.
- **Technical Debt** (a loan, not garbage): A decision that speeds you up now and costs more later.
- **Debt Interest** (the slowdown): The slowdown of every next change. Debt in the hot zone costs the most.
- **Cognitive Load** (fits in a head): How much context you need to change a component safely. Remove accidental complexity.
- **Conway's Law** (org shape = system shape): A system mirrors the communication structure of the organisation.

### System structure (5–7, 11)

- **Cohesion & Coupling** (one thing inside, little outside): Inside a component — about one thing; outside — know as little about others as possible.
- **Bounded Context** (DDD boundary): A boundary inside which words have a single meaning.
- **Dependency Inversion** (dependencies point inward): Business logic depends on abstractions; details plug in from outside (ports and adapters).
- **Abstraction** (exists to absorb change): A layer earns its keep by absorbing change and testing without the outside world, not by looking nice.
- **API Contract** (contract over transport): Schema, errors, versioning, and compatibility matter more than REST vs GraphQL vs gRPC.
- **Idempotency** (safe to repeat): Repeating an operation gives the same final effect. Protection from retries and duplicates.
- **Modular Monolith** (one deploy, strong walls): One application with strict internal boundaries. Often the best start.
- **Distributed Monolith** (worst of both worlds): Services that only ship together. The cost of distribution without the independence.
- **Strangler Fig** (migrate piece by piece): Grow the new system around the old one and move traffic over gradually, instead of a big-bang rewrite.

### Data and distribution (8–10, 12)

- **Data Model** (data outlives code): The most expensive decision: normalisation, OLTP vs OLAP.
- **Event Sourcing** (the log of events is the truth): State is rebuilt from events: full history and audit, but expensive to run and evolve.
- **CQRS** (separate write and read models): Commands and queries get their own models; useful when reads and writes differ a lot.
- **Single Source of Truth** (one authoritative version): For every fact you know where the primary version lives; the rest are derived copies.
- **Cache Invalidation** (a second truth that lies): Speed at the cost of freshness; the hard question is when to invalidate.
- **Optimistic vs Pessimistic Locking** (check on write vs lock first): Two ways to stop concurrent edits from overwriting each other.
- **CAP / PACELC** (the network is uncertainty): During a partition: consistency or availability; otherwise: latency or consistency.
- **Consistency Models** (strong, eventual, causal): Not the strictest model — the one sufficient for the risk.
- **Saga** (a chain of steps with compensations): A long transaction across services, where each step has an undo instead of a global lock.
- **Queue vs Pub/Sub** (not just "later"): Async decouples in time, but brings delays, duplicates, and ordering.
- **At-least-once Delivery** (exactly-once is marketing): A message can arrive twice; the consumer must be idempotent. DLQ, backpressure.

### System quality (13–15)

- **Tail Latency** (p95 / p99): Users feel the tail, not the average.
- **Profiling** (measure first): Optimise only the hotspot you found; Amdahl and Little set the limits.
- **Vertical vs Horizontal Scaling** (scale up / scale out): One big machine, or many identical ones behind a load balancer.
- **Scale Cube** (X / Y / Z): Clone, split by function, split by data.
- **Retry + Circuit Breaker + Bulkhead** (resilience): Retries with backoff and jitter, a breaker for dead dependencies, isolated pools.
- **SLI / SLO / SLA** (error budget): Measurement, target, and promise; the error budget decides features vs reliability.

### Security and operations (16–17)

- **Authentication vs Authorization** (AuthN / AuthZ): "Who are you?" and "what may you do?" are two different steps.
- **Threat Modeling** (STRIDE, defense in depth): Find threats before the attack and defend in layers.
- **Observability** (logs · metrics · traces): The system explains "why"; a correlation ID ties the whole path together.
- **Symptom-based Alerting** (runbook, post-mortem): Alert on user pain; a runbook says what to do; post-mortems are blameless.

### Documents and communication (18–19)

- **ADR** (Architecture Decision Record): Context, decision, alternatives, consequences — one per decision.
- **C4 Model** (living documentation): Diagrams by zoom level that live next to the code.
- **Risk Translation** (stakeholder mapping): One risk, different words for engineers and for the business.
- **RFC** (disagree and commit): A written proposal, with criticism before the decision.

### Leadership and business (20–21)

- **Influence without Authority** (mentoring): Principles, boundaries, and questions instead of orders.
- **Delegation with Guardrails** (ownership stays): Teams decide; the architect steps in on irreversibility, invariants, security, and multi-team impact.
- **Non-functional Requirements** (NFRs, cost of delay): Product properties expressed in revenue, risk, and cost.
- **Build vs Buy** (capability map): Build the core, buy the commodity, know the exit cost.

### AI-native, traps, and growth (22–24)

- **Specification-driven Development** (the spec as artifact): The faster the executor, the more the spec's precision matters.
- **Agent Output Review** (quality gates): Agent code passes the same checks as a human PR.
- **Ivory Tower Architect** (architecture from the hill): Decisions made far from the code, operations, and team.
- **Resume-driven Development** (cargo cult, NIH, perfectionism): Tech for the CV, copying the form, building what you should buy, endless polishing.
- **T-shaped / M-shaped Skills** (learn from systems): Depth plus breadth; a mature architect has several deep pillars.
- **Learning in Public** (learning in writing): Write decisions down and see the gaps in your thinking before production does.

> An architect is an engineer who learned to see the consequences before they became an incident.

End of course · 24 modules · practice starts here.

Re-read this course not as a reference but as a set of questions. Architecture begins where you stop in front of a decision and honestly name the price of every option.
