# Software Architecture
Software architecture is the set of decisions that are expensive to reverse. Not the diagrams, not the folder structure, not the framework list. The decisions.
That definition does the most work of any I know, because it gives you a test. If you can change it in an afternoon, it is not architecture, it is implementation, and you should stop holding meetings about it. If getting it wrong means six months of migration, it is architecture, and it deserves the meeting you are avoiding.
Ralph Johnson's version says the same thing socially: architecture is the shared understanding the expert developers have of the system. Martin Fowler's compresses it further, and it is the one worth remembering: [[Architecture is about the important stuff. Whatever that may be]].
## There is no best design
The single most useful reframe, and the one juniors resist longest:
> [[Don't try to find the best design in software architecture. Instead, strive for the least worst combination of trade-offs|Don't try to find the best design in software architecture. Instead, strive for the least worst combination of trade-offs]]
Every architectural property you want costs you another one. Consistency costs availability. Flexibility costs simplicity. Performance costs readability. Decoupling costs a network hop and a debugging session. You are not choosing a good design over a bad one, you are choosing which pain you would rather have, on purpose, in advance.
Which is why the honest question in a design review is never "is this right?" It is **"what does this cost us, and are we willing to pay it?"** Any proposal presented without a cost is a proposal that has not been thought about yet.
The corollary, also worth keeping: [[There are no wrong answers in architecture, only expensive ones]].
## The forces you are actually balancing
Almost every architectural decision reduces to managing these, and they pull against each other:
- **[[Loose Coupling|Coupling]]**: how much one part must know about another. Low coupling means you can change one thing without changing five. It also means indirection, and indirection is where bugs hide
- **[[High Cohesion|Cohesion]]**: how much the things inside one boundary belong together. High cohesion is what makes a module explainable in one sentence
- **[[Cognitive complexity|Cognitive load]]**: how much a person must hold in their head to change something safely. The real budget, and the one nobody measures
- **Change locality**: when a requirement changes, how many places do you touch? Good architecture makes likely changes cheap and unlikely changes possible
- **Reversibility**: how hard is it to undo? Prefer decisions you can walk back, and spend your caution on the ones you cannot
Notice that four of the five are about **change**, not about the system as it exists today. Architecture is a bet on what will change and what will not. That is why it is hard: you are designing against a future you cannot see.
## Boundaries are the whole game
If architecture is one skill, it is drawing boundaries in the right places and being honest about what crosses them.
A good boundary hides a decision. Everything on the inside can change freely; everything on the outside depends only on the contract. That is what makes a module *deep*: a simple interface concealing substantial machinery. A shallow module, one whose interface is nearly as complicated as its implementation, is worse than no module at all, because you pay the abstraction cost and get nothing back.
The failure mode to watch: boundaries drawn by **technical layer** (controllers, services, repositories) rather than by **domain concept**. Layered boundaries feel tidy and mean that every real feature cuts across all of them, so every change touches every layer. Domain boundaries feel messier on a diagram and let a whole feature live in one place.
And [[Domain Specific Languages (DSLs)|DSLs]] are what a boundary looks like when you push it all the way: a contract so constrained that violating it is not expressible.
## Boring is a strategy
> [[Stick to boring architecture for as long as possible, and spend the majority of your time, and resources, building something your customers are willing to pay for]]
Most systems do not fail because the architecture was too simple. They fail because a team spent its innovation budget on infrastructure nobody was paying for, and ran out of runway before the product worked.
**Innovation tokens are finite.** Pick the two or three places where being different is the point, and be aggressively conventional everywhere else. A Postgres database and a monolith will carry you much further than anyone selling you something else wants to admit, and you can always split later. Splitting a monolith you understand is a known problem. Reassembling a distributed system you no longer understand is not.
This is the same instinct as [[Simple scales. Fancy fails]].
## Where architecture actually comes from
Two uncomfortable truths that predict more real systems than any principle:
**Conway's Law.** Your system's structure will mirror your organization's communication structure, whether you plan it or not. Four teams produce four components. If you want a different architecture, you may need a different org chart first. Fighting this with diagrams does not work.
**The second system effect.** The rewrite is where architects put every feature they wished they had built the first time. Brooks named it in 1975 and it has not stopped happening. The first system is too simple because you did not know the domain; the second is too complex because now you do, and you overcorrect.
## The architect's actual job
> [[Architects aren’t the smartest people in the room. Their primary job is to make everyone else smarter, for example, by getting folks to see more dimensions]]
That is the whole role, and it is why the "ivory tower architect" fails. Architecture that is not understood by the people writing the code is not architecture, it is documentation of an intention. If the team cannot explain why the boundaries are where they are, they will erode them within a quarter, correctly, because they will be solving real problems and your reasons will be invisible.
Practical consequences:
- **Write the decisions down, with the alternatives you rejected and why.** The reasoning is the durable part; the decision is just the conclusion. Architecture Decision Records exist for this
- **Design at the last responsible moment.** Not the last possible moment (too late), not the first (you know least then). Decide when you have the most information and still have a choice
- **Make the architecture visible in the code.** If the boundaries only exist in a diagram, they do not exist
- **Prefer removing a constraint to adding a component.** Most complexity is accumulated, not designed
## Why it matters more with AI in the loop
Something changed here recently and it is worth naming.
Coding agents make writing code cheap. They do not make *understanding* systems cheap. When generation cost collapses, the bottleneck moves entirely to comprehension and verification, which means the value of clean boundaries goes UP, not down. An agent working inside a well-bounded module with a defined contract can be trusted with a lot. The same agent loose in a codebase with no boundaries produces exactly the mess [[Cursor Agent Swarms|Cursor documented]]: 64,000 lines where 10,000 would do.
Architecture used to be about what humans could hold in their heads. It is now also about what fits in a context window, and about what a verifier can check independently. Those turn out to want the same thing: small, deep, well-named modules with explicit contracts. The old advice was right; the reason to follow it just got more expensive to ignore.
## References
**Books**
- Neal Ford & Mark Richards, *Software Architecture: The Hard Parts* (O'Reilly, 2021). The trade-off analysis book. Source of the "least worst" framing
- Mark Richards & Neal Ford, *Fundamentals of Software Architecture* (O'Reilly, 2020). The best single starting point. Characteristics, styles, and the soft skills
- John Ousterhout, *A Philosophy of Software Design* (2018). Short, opinionated, and the clearest treatment of deep modules and complexity anywhere
- Eric Evans, *Domain-Driven Design* (Addison-Wesley, 2003). Boundaries by domain, ubiquitous language, bounded contexts
- Gregor Hohpe, *The Software Architect Elevator* (O'Reilly, 2020). Architecture as an organizational role, riding between the boardroom and the engine room
- Michael Nygard, *Release It!* (Pragmatic Bookshelf, 2nd ed. 2018). What architecture looks like when it meets production
- Fred Brooks, *The Mythical Man-Month* (1975). The second system effect, and still right about almost everything else
- Sam Newman, *Building Microservices* (O'Reilly, 2nd ed. 2021). Honest about the costs, which is rarer than it should be
- [[Robert C. Martin]], *Clean Architecture* (Prentice Hall, 2017). Strong opinions, useful even where you disagree
**Articles**
- Martin Fowler, "Who Needs an Architect?" — https://martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf
- Martin Fowler's software architecture guide — https://martinfowler.com/architecture/
- Dan McKinley, "Choose Boring Technology" — https://mcfunley.com/choose-boring-technology
## Related
- [[SOLID Principles]]
- [[Loose Coupling]]
- [[High Cohesion]]
- [[Cognitive complexity]]
- [[Domain Specific Languages (DSLs)]]
- [[Information Architecture (IA)]]
- [[Systems thinking]]
- [[Software Design Patterns for AI Skills and Agents]]
- [[Martin Fowler]]
- [[Robert C. Martin]]
- [[Kent Beck]]
- [[Ward Cunningham]]
- [[Cursor Agent Swarms]]
- [[Graph Engineering]]
- [[Agentic Engineering]]
- [[Architecture is about the important stuff. Whatever that may be]]
- [[There are no wrong answers in architecture, only expensive ones]]
- [[Don't try to find the best design in software architecture. Instead, strive for the least worst combination of trade-offs]]
- [[Stick to boring architecture for as long as possible, and spend the majority of your time, and resources, building something your customers are willing to pay for]]
- [[Simple scales. Fancy fails]]
- [[Architects aren’t the smartest people in the room. Their primary job is to make everyone else smarter, for example, by getting folks to see more dimensions]]