See It Flow

Architecture

What Is Software Architecture?

Software architecture is the significant structure of a system — its boundaries, responsibilities, relationships, constraints, and the decisions that are expensive to change. Make those decisions explicitly, reason about trade-offs deliberately, and document why.

Mangesh MandlikLast updated:

What Is Architecture? Software Architecture Patterns in Context

"Architecture is the set of decisions that are expensive to change" is a useful working mental model — not a complete definition. It is memorable because it tells you where to spend your reasoning effort, but it leaves out what those decisions are actually about.

Concretely, architecture is the significant structure of a system: its boundaries (what is one deployable/ownable unit vs another), the responsibilities assigned to each part, the relationships and dependencies between those parts, the constraints it operates under, the quality attributes it must satisfy, and the consequential decisions that follow from all of the above — plus how easily that structure can evolve as requirements change.

Those decisions are driven by four distinct kinds of input, which are easy to blur together but answer different questions:

Requirements vs quality attributes vs constraints vs assumptions

Functional requirements
What must the system do? The features and behaviors users and other systems depend on.
Quality attributes (non-functional)
How must it behave while doing that? Latency, availability, durability, security, cost, operability.
Constraints
Hard limits you do not get to choose: budget, team size, deadline, existing systems, compliance.
Assumptions
Things taken as true without proof — traffic shape, growth rate, a dependency's uptime. Wrong assumptions are a common source of later rework, so name them.

Software architecture patterns, such as a monolith or microservices, are reusable answers to these structural decisions. The visual story below follows one system from a simple start, through growth-driven bottlenecks, to selective decomposition.

Visual Story

The architectural reasoning cycle — applied

Architecture Fundamentals

Architecture Fundamentals
Day One
0 / 0
📋Up nextRequirements

⤢ Expand for synchronized narration timeline

Scene 6 shows why architecture must be intentionally evolvable. The change trigger in the ADR (Scene 4) is what makes Scene 6 a planned transition rather than a surprise rework.

Problem It Solves

Why explicit architectural reasoning matters

A recurring, costly pattern is architectural decisions made implicitly — without naming the requirements they had to satisfy, the alternatives that existed, or the conditions under which they should be revisited. Not every failure traces back to this, but when a system's architecture quietly stops fitting its requirements, an undocumented decision is a frequent contributor.

When architecture is undocumented, every new engineer re-evaluates every decision from scratch — often re-selecting options that were already rejected for reasons no longer visible. Explicit architectural reasoning creates a shared understanding that survives team changes and organisational growth.

Architecture Models

The fundamental architectural reasoning loop

  1. 1
    Identify requirements — What must the system do? What are the quality attributes (availability, latency, consistency, cost)?
  2. 2
    Identify constraints — Team size, budget, deadline, existing systems, compliance requirements — hard limits that rule out options.
  3. 3
    Enumerate options — List all viable approaches before evaluating any. Do not collapse the option space prematurely.
  4. 4
    Evaluate trade-offs — Score each option against the agreed criteria derived from requirements and constraints.
  5. 5
    Decide — and document why — Record the decision, the rejected alternatives, and why they were rejected. Include a change trigger.
  6. 6
    Acknowledge consequences — Every decision introduces new constraints. Name them explicitly so they can be planned for.
Architecture Decision Record (ADR): The document that captures context, options, decision, rejections, and change trigger. The rejected-options section is often what ages best — it is what stops a future engineer from silently re-opening a question the team already closed for a reason that no longer shows up in the code.

How Architects Think

What experienced engineers know

The best architecture is not the most sophisticated one. It is the one that satisfies the current requirements with the least unnecessary complexity — while remaining evolvable when requirements change.

Principal engineers ask: "What would change my decision?" — this is the mark of conditional reasoning. A cache is right when stale data is acceptable. A queue is right when async processing is tolerable. Multi-region is right when the cost of downtime exceeds the cost of operational complexity.

Architecture is not about knowing the answer. It is about knowing which questions to ask and which constraints matter most.

Illustrative Scenario

A startup grows — and its architecture must evolve (illustrative scenario; the figures are assumed, not measured)

Stage 1: A small team launches a product. A single application server, a single PostgreSQL database. Deploys happen from a laptop. Response time is under 50ms (an assumed figure for this illustration). Life is simple.

Stage 2 — the database is under pressure, but pressure from what? Users grow 10× (also assumed), and the database is visibly struggling. Before reaching for a fix, the first question is which specific resource actually saturated: CPU, read throughput, write throughput, connection count, lock contention, or an inefficient query/missing index that only shows up at this volume. Each has a different correct intervention, and picking the wrong one wastes the migration without relieving the actual pressure.

If the saturation is genuinely read throughput, a read replica helps — but only the read traffic that can tolerate it: replica reads lag behind the primary by a variable amount, so anything that needs to read its own very recent write (e.g. "show the order I just placed") still has to go to the primary or account for that lag explicitly. A read replica does nothing for write pressure, lock contention, or a query missing an index — those need a different fix (see Scalability & Capacity for the full measure-first method).

Stage 3: Traffic becomes globally distributed. Users far from the single region experience materially higher latency. A CDN meaningfully helps static, cacheable assets — but it does not reduce the latency of dynamic API calls or database round-trips, which still cross the same distance. Closing that gap is what multi-region deployment is for, and it is justified by an explicit business or technical requirement (a latency SLA, a data-residency rule, a disaster-recovery target) — not by "users are far away" on its own, because multi-region also introduces real data-consistency and operational cost (see Multi-Region Architecture for when that trade-off is worth making).

The question: Is multi-region justified at this stage? What requirement would make it necessary? What constraint makes it premature today?

Trade-offs

Every architectural decision has consequences

Simplicity vs Independent Scaling

A monolith is simpler to operate but scales as one unit. Microservices let you scale and deploy each boundary independently — but that benefit is not automatic: it only materializes if the split follows real load/ownership boundaries, and it is paid for with distributed-systems and operational cost (network calls, partial failure, more deployables to run).

Consistency vs Availability — under partition

The classic tension only applies while a network partition is actually happening: a distributed system must then choose between serving a request with possibly-stale data (favoring availability) or refusing/delaying it until it can be answered correctly (favoring consistency). Outside of a partition, most systems can and do offer both. See Distributed Architecture for the precise (per-operation, not per-database) version of this trade-off.

Performance vs Cost

More replicas, more caches, more regions improve performance — but each adds infrastructure cost and operational complexity.

Flexibility vs Commitment

Delaying architectural decisions preserves options but can accumulate tech debt. Committing early enables optimization but reduces future adaptability.

What Can Go Wrong

Common architectural failure modes

🔇Implicit decisions

A choice was made without documentation. Six months later nobody knows why — and it gets reversed, re-introducing the problem it was meant to solve.

🎯Solution-first framing

The conversation starts from a favourite technology rather than the requirement it must meet, so alternatives are never compared and the wrong fit gets built.

⏰No change trigger

The single-database design that fit the startup stage is still in place after traffic, teams, and data volume have changed, and no one wrote down what signal should reopen the choice. The old architecture quietly becomes the constraint.

⚙️Over-engineering early

Microservices chosen for a 3-person team because "we will need it later." Operational complexity consumes the entire engineering capacity.

🚧Ignoring constraints

Team picks the technically superior option that requires Kafka expertise they do not have. The correct choice on paper becomes the wrong choice in practice.

🗳️Architecture by committee

Every decision requires full consensus. Reversible choices get treated like irreversible ones. Velocity collapses.

"No change trigger" is usually not a one-time mistake to fix — it is an ongoing risk every time a system changes under live traffic. See Architecture Evolution & Migration for how to change a decision safely once it no longer fits.

When To Use Formal Architectural Reasoning

Match the rigour to the reversibility

✓ Apply full rigour when
  • → Choosing a primary datastore or data model
  • → Defining a public API contract
  • → Committing to a platform-level technology
  • → Making a decision that affects multiple teams
  • → The cost of changing course later is high
⚡ Move fast when
  • → Choosing an internal library or caching strategy
  • → Deciding internal API shapes within a service
  • → Making decisions reversible in hours or days
  • → The blast radius is bounded to a single team
  • → You can validate the choice with a quick spike
Architect's Challenge

A startup's monolith is slowing down feature delivery. A senior engineer proposes a full microservices rewrite. What is the most important question to ask first?

Remember· 30-second mental model

Architecture is the set of decisions that are expensive to change. Make them explicitly, with documented reasoning.

  • 1Every architectural decision should be traceable to a requirement or constraint — not a preference.
  • 2The reasoning behind a decision matters as much as the decision itself.
  • 3Classify decisions as reversible or irreversible before deciding how much analysis they deserve.
  • 4Record the change trigger: the condition under which this decision should be revisited.
  • 5Good architecture is not the most sophisticated — it is the best fit for this stage.

Key lesson

The most useful sentence in any architecture decision is: 'Revisit this if...' — it makes evolution intentional rather than accidental.