What is Software Architecture?
The high-level decisions about how a codebase is organized and how its pieces fit together — decided before a single function gets written.
What is it?
Imagine you're about to build a house. Before anyone picks a paint color or a doorknob, someone has to decide much bigger things first: how many floors, where the plumbing runs, which walls are load-bearing, where the electrical panel lives. Get those wrong, and no amount of nice paint fixes it later — you'd have to tear out walls.
Building software has the same two levels. There's the moment-to-moment work of writing a function, naming a variable, fixing a bug — that's like picking the paint color. And then there's a bigger, earlier set of decisions: How is the codebase split into folders and modules? Which parts are allowed to talk to which other parts? Where does data enter the system, and where does it get stored? How do we add a new feature next year without rewriting everything?
Those big, structural decisions — the ones that are expensive to change later and that shape everything built on top of them — are what software architecture is about. It's not a single tool or a diagram; it's the set of choices about how a system is organized so that it can be built, understood, changed, and grown over time.
A useful way to tell architecture apart from ordinary coding: a coding decision is usually easy to undo (rename a variable, refactor one function). An architectural decision is expensive to undo (switch your whole app from one big codebase to many services, or restructure how every feature is laid out). Architecture is about the decisions that are hard to walk back.
Explain like I'm 10
A city planner deciding where roads, water lines, and zoning districts go is doing 'architecture' for the city. A homeowner deciding where to put a bookshelf is not — even though both are decisions about the same city.
Examples
A structural decision vs. a coding decision
// Coding decision: easy to change later, low risk
function formatPrice(cents) {
return "quot; + (cents / 100).toFixed(2);
}
// Architectural decision: hard to change later, high risk
// "All database access goes through a data-access layer.
// No other part of the app is allowed to write SQL directly."Renaming formatPrice or tweaking its formatting is a five-minute change. Reversing the rule about database access — after fifty files have started writing their own SQL — could take weeks.
The same feature, two different structures
// Structure A: everything in one file
// order.js handles validation, pricing, saving to DB, and sending email
// Structure B: split by responsibility
// validateOrder.js
// calculatePrice.js
// saveOrder.js
// sendConfirmationEmail.jsBoth structures can implement the exact same feature. The choice between them is an architectural one — it doesn't change what the app does, only how easy it is to change, test, and understand later.
How it works
Architecture isn't a single artifact you produce once — it shows up as a set of ongoing decisions and constraints:
- Boundaries: which parts of the code are allowed to know about which other parts. - Structure: how the codebase is split into folders, modules, or services. - Data flow: where information enters the system, how it moves through it, and where it ends up. - Consistency: the shared conventions that let any engineer predict where a piece of logic will live before they even open the folder.
None of these decisions are visible in any single function. You only see them by looking at the codebase as a whole — which is exactly why architecture is a separate skill from writing individual pieces of code.
Why does it exist?
Without any structural decisions, a codebase tends to grow into whatever shape is fastest at each individual moment — and that shape is rarely the one that's easiest to work with a year later. Architecture exists because the cost of a codebase isn't just "does it work today," it's "how much does every future change cost." Good architectural decisions made early keep that future cost low; bad ones (or none at all) compound into a codebase where every small feature requires understanding — and risks breaking — everything else.
When to use it
Every piece of software has some architecture, even if nobody chose it deliberately — even a single 200-line script has an implicit structure. The real question isn't "should I do architecture," it's "should I make these structural decisions on purpose." Do that deliberately as soon as a codebase is going to be worked on by more than one person, live longer than a few weeks, or grow past the size you can hold entirely in your head.
When not to use it
For a genuine one-off script or a weekend prototype you'll throw away, spending time designing layers and boundaries is wasted effort — you're optimizing for a future the code will never have. It's fine, even correct, to write something quick and messy when you know it's disposable. The skill is recognizing which situation you're in.
Common mistakes
Treating architecture as something only 'senior' engineers or a diagram tool produce, rather than a set of decisions every contributor makes and reinforces daily.
Confusing architecture with technology choices ("we use React") — the framework you pick is a detail; how you organize logic around it is the architecture.
Over-architecting a throwaway script, or under-architecting a system that's clearly going to grow — both come from not asking 'how long will this live, and who else will touch it?'
Practice exercises
- Easy:
Write two sentences distinguishing a 'coding decision' from an 'architectural decision', using an example from a project you've worked on for each.
- Medium:
Take a small script you've written (or imagine one that reads a CSV, transforms it, and writes a report). List three structural decisions you made, even if you didn't realize you were making them at the time.
- Hard:
Describe a real or hypothetical situation where a codebase had no deliberate architecture, and explain concretely what went wrong as a result (e.g., a change that should have taken an hour took a week).
Interview questions
How would you explain software architecture to someone new to the field?
It's the set of high-level, structural decisions about how a codebase is organized and how its parts interact — decisions that are expensive to change later, as opposed to routine coding decisions that are cheap to change.
Does every piece of software have an architecture, even a small script?
Yes — even an unstructured script has an implicit structure (e.g., everything in one file, in one order). Architecture as a discipline is about making those structural decisions deliberately rather than by accident.
How is an architectural decision different from an everyday coding decision?
An architectural decision is expensive and risky to reverse once other code depends on it (e.g., how modules are allowed to talk to each other); a coding decision, like a variable name or a single function's implementation, is cheap and low-risk to change.
What actually makes an architectural decision 'expensive' to reverse, mechanically?
The number of other things that have come to depend on it. A variable name is depended on by nothing but its own function. A rule like 'all database access goes through one layer' gets depended on by every feature written after it, so undoing it means finding and rewriting every place that assumed it held.
Is software architecture the same thing as choosing a framework or technology stack?
No. Picking React or Postgres is a technology choice, and it's often reversible with enough effort. Architecture is how you organize logic around whatever technology you picked — the boundaries, layers, and data flow — and a bad architecture built on a great framework is still a bad architecture.
What's a practical heuristic for telling whether a decision you're about to make is architectural?
Ask how many other parts of the system would need to change if you reversed this decision next month. If the answer is 'just this function,' it's a coding decision. If the answer is 'every feature that touched this area since,' it's architectural.
Is architecture something you decide once at the start of a project and then move on from?
No — it's an ongoing set of decisions and constraints that get reinforced (or eroded) with every pull request. A codebase's architecture at year two is the sum of every structural choice made along the way, not just whatever was drawn on a whiteboard on day one.
What goes wrong when a team treats architecture as something only senior engineers do?
Every contributor is still making structural decisions daily — where to put a new module, whether to call another layer directly — whether or not they're labeled as 'architecture.' If only seniors are expected to think about it, those everyday decisions get made without the discipline that keeps the system coherent, and the architecture erodes one convenient shortcut at a time.
Can you give an example of over-architecting, and explain why it's a real cost even if the code works?
Building a plugin system with multiple abstraction layers for a script that will only ever have one, fixed way of running is over-architecting. It works, but every future reader has to trace through interfaces and indirection that exist for a flexibility the project will never use — that's ongoing comprehension cost paid for a benefit that never arrives.
Can you give an example of under-architecting, and what symptom would show up in the codebase?
A growing app where every screen's component directly queries the database is under-architected. The symptom is that a single schema change requires touching dozens of unrelated UI files, and no one can safely predict what a change will break, because there's no boundary containing the effect.
How would you decide whether a two-week prototype needs deliberate architecture?
Ask whether it will be thrown away or whether it's likely to become the actual product. If it's genuinely disposable, spending time on layers and boundaries optimizes for a future the code will never have; if there's real risk it becomes long-lived (which prototypes often do), it's worth at least the cheapest structural decisions — like keeping concerns separated — from the start.
Two teams build the exact same feature with different internal structures. Are both making architectural decisions?
Yes. Architecture isn't about what the software does — both teams shipped identical behavior — it's about how the code is organized to produce that behavior. The structural choice itself, even if invisible to the end user, is the architecture.
What's the relationship between architecture and the total cost of a system over its lifetime?
Architecture determines how much every future change costs, not just how much the initial build costs. A system built quickly with no structural thought might look cheaper on day one, but if every subsequent feature requires understanding and risking the entire codebase, the cumulative cost over years is far higher than a system with deliberate boundaries.
Why do boundaries — who's allowed to call whom — matter more than which specific technologies are used?
Because boundaries control blast radius: they determine how far the effect of a change can spread. Technology choices are usually swappable behind those boundaries without touching the rest of the system, but if the boundaries themselves don't exist, no technology choice will contain the damage of a bad change.
How does architecture show up differently in a 200-line script versus a codebase worked on by 50 engineers?
In a 200-line script, the 'architecture' might just be the order statements run in — implicit and low-stakes, since one person holds it all in their head. At 50-engineer scale, the same lack of deliberate structure means no one can hold the whole system in their head, so explicit boundaries and conventions become the only way multiple people can predict where logic lives and change it safely.
What's a red flag in a pull request that suggests an architectural decision is being made informally?
A change that quietly introduces a new way for one part of the system to reach into another — like a UI component importing a database client directly for 'just this one case.' It looks like a small, local fix, but it sets a structural precedent that other changes will copy.
If you joined a new team, how would you go about learning the architecture of an existing codebase?
Look for the boundaries in practice rather than a diagram: which folders or modules only get imported in one direction, where business rules actually live versus where they're supposed to live, and where a typical feature touches code across the system. Reading a few real pull requests often reveals the actual, lived architecture faster than any document.
Why might a technically correct implementation still represent bad architecture?
Because 'correct' usually only measures whether the output matches the requirement today. Architecture is judged by how well the system can absorb the next change — a correct feature built by copy-pasting business logic into five files is bad architecture even though it currently works, because the next change to that logic now has to be made five times.