Software Architecture
Concept
A design settled before any code is written, covering which chunks a system gets cut into and how those chunks talk to each other.
Why it exists
Pagedeck's first service was a handful of files. The code that saved a document, the code that added a comment, and the code that sent notification mail all sat in the same place, and with three people building, that really was the fastest arrangement. You checked out loud who was editing what, and whatever got edited shipped the same evening.
At forty-five people the same structure behaved differently. Theo changed the notification mail code, and the next morning document saving stopped working. The two features looked entirely unrelated, but underneath they read the same configuration value, and the only person who knew that was the one who wrote the code in the first place. Half a day to find the cause, an hour to undo it.
After that happens a few times, the way a team talks changes. "Is it safe to touch this?" comes up several times a day, nobody can answer with any confidence, and the habit hardens into not touching things. Code that everyone knows would be better if fixed gets left alone because nobody can predict what breaks next to it. Adding a feature took two days at the start; a year later the same size of work takes two weeks.
The problem wasn't wrong code. It was that nobody had decided what is allowed to reach what. Without a line, you can't tell when a line has been crossed. Every rush creates one more shortcut that reaches straight into the insides of a neighboring feature, and those shortcuts aren't on any map, so the next person finds them by stepping on them. For anyone who joins later, every one of those shortcuts is a trap. The code itself takes three days to read, but which part reaches into which takes a couple of months of living with it, and the mistakes made during those months tend to repeat in exactly the same spots.
Software architecture is the proposal to draw those lines before building rather than after. Whether payments, notifications, and document storage live in one chunk or three, and if three, what each one hands the others and through which opening — all of it gets decided before the code exists. Changing one feature costs a day; recutting the chunks costs a quarter, which is why postponing this decision only raises its price.
How this field breaks down
The terms grouped here fall into four branches: the structures you choose between, the quality attributes that measure whether the cut went well, the risk that appears when it didn't, and the design knowledge earlier engineers wrote down about how to cut. The first branch holds the options; the other three judge and support the choice.
The structure branch has seven terms, and they split again along two questions. One is how many deployment units to keep, the other is how to divide the inside of a single unit into layers. A deployment unit is the bundle that goes onto the server in one shot.
- Monolith — everything in one chunk, shipped together. Payments, notifications, and document storage sit inside the same program and can call each other's functions directly, which makes it the fastest thing to build first. The cost is that one changed line in notifications sends payments back out with it.
- Microservices — cut by feature and deployed separately. The payment service and the notification service run as different programs and talk over the network. You can change notifications and ship only notifications, and scale up only the part under load, but running five services means five sets of deployment and monitoring.
- Modular monolith — ships as one chunk while the inside is split into modules that may only call each other through declared openings. If the notification module reads the document module's internal data directly, it fails at the code level. This is the middle ground a forty-five person company often picks.
- Serverless — instead of renting and managing servers, you upload code as individual functions that run only when a request arrives. You pay for what runs, and the trade is that a function idle for a while takes a moment to warm up on the first request.
- Layered architecture — stacks one chunk into presentation, business, and data layers, with each layer calling only the one below it. A request from the screen passes through the business rules and down to the database, in one direction. It's the oldest and most widely used arrangement.
- Hexagonal architecture — puts the business rules in the center and pushes outside technology like the database or the payment provider to the edge as swappable parts. The goal is that switching payment providers leaves the discount rules untouched.
- Event-driven architecture — rather than calling each other directly, chunks publish facts like "a document was saved" and whoever cares picks them up. Notifications can be down for a minute and document saving still completes, and when a new feature starts consuming the same event later, the publishing side doesn't change.
The quality attribute branch is three gauges for checking whether the chosen structure stands up. Gauges are what turn a taste argument into an evidence one.
- Coupling — how tangled components are in each other. If notification code reads the internal shape of document storage, coupling is high; if the two exchange everything through one declared opening, it's low. Lower coupling means changing one side breaks the other side less often.
- Cohesion — how much the code inside one module is about a single job. A payment module that also holds marketing mail delivery has low cohesion. Higher cohesion makes it obvious which file to open when you want to change something.
- Scalability — whether the system can be grown to absorb more use. If going from 100 concurrent users to 10,000 is handled by adding machines, the system scales; if it means rewriting the code, it doesn't.
The risk branch holds one term, single point of failure (SPOF): the spot whose failure stops everything. Split a service into five chunks and point all five at the same single database, and that database is the single point of failure. Cutting things apart doesn't make them safe by itself, so the parts carrying everything alone have to be hunted down separately.
The design knowledge branch is three bodies of accumulated experience. They exist so nobody has to reason from scratch every time.
- Design pattern — a named, worked-out solution to a problem that keeps recurring in design, such as the standard way to keep exactly one instance of a value for a whole program. The practical value is that saying the name puts the same picture in everyone's head.
- SOLID principles — five rules worth following in object-oriented design, like the one saying a chunk should have only one reason to change. They compress the coupling and cohesion ideas above into five sentences that apply at the level of individual code.
- Domain-driven design (DDD) — drawing boundaries in the language of the business rather than the technology. Payments and documents get separated because the business talks about them as different things, not because of how database tables happen to look. It answers where to cut, so it travels with the structure branch.
The four branches aren't a checklist worked through once. A monolith whose coupling keeps climbing gets split into modules, where to put the module boundaries is a question domain-driven design answers, and when the shared database left behind turns out to be a single point of failure, that piece gets cut again. There is also a usual order to the choices. Look first at how many people are on the team and how often they deploy in a week, settle the deployment unit from that, and only then decide the layers inside a chunk. Fix the layers first and they all end up misaligned once the chunks get recut.
How it sounds at work
"That's an architecture decision, so we can't settle it inside this sprint. Let's book time next week."
It's not a few lines of code — undoing it later is expensive, so it deserves its own session.
"We can't scale payments on its own with the current structure. When traffic spikes, everything goes up together."
There's a single deployment unit, so the part under load can't be grown by itself.
"That's a coupling problem. Notifications are reading straight into the internals of document storage."
The symptom looks like a bug, but the cause is a missing opening between two chunks.
At Pagedeck the phrase came up most during the quarter the team added features for enterprise customers. Each contract needed different permission rules, and putting those rules inside the document saving code as conditionals would take two weeks, while pulling them out into their own piece would take six. Theo argued that the conditional route adds one more branch in the same spot every time a new customer arrives, until six months later nobody can safely change that file at all.
Grace put the two options side by side and asked what undoing each would cost. The two-week option, once it needed unpicking, came out at three months rather than six weeks, and the decision went to the six-week route. Mia wrote the reasoning down, so that when a similar request arrived four months later, the same argument wouldn't have to start from zero.
What people get wrong
The most common mistake is treating architecture as the act of picking technology. Which language, which database — those are the first topics in any kickoff meeting, so the confusion is natural. But the question architecture answers is not what you use, it's where you cut and how the pieces connect. The same language and the same database can produce one chunk or five. Teams that conflate the two spend their time choosing fashionable tools while nobody draws a boundary, and six months later the old problem is back, built out of new tools.
The second is reading microservices as the more advanced form. Large companies talk about running them, so a monolith starts to look like a phase you pass through. In practice the two are a trade, not a ranking. Cutting finely buys independent deployment, and it charges for it: calls that used to finish in-process now cross a network, and five chunks need people and tooling to deploy and watch. A team of ten that splits into twelve services spends more time reconciling services than building features, and when something breaks, just finding which chunk it started in eats half a day. The deciding factor is not what's fashionable but how much operational work the team can carry right now. The question that comes before whether to split is which part currently hurts. If the fear is that unrelated features ship together on every deploy, drawing module boundaries handles most of it; if one particular feature can't absorb its load, pull that one out. Splitting everything at once answers neither.
Easily confused with
| Term | What it decides | How it differs |
|---|---|---|
| Design pattern | A standard solution to a recurring design problem | Different scale. A pattern is a solution across a handful of classes; this is the decision about which chunks the whole system is cut into |
| Information architecture | How content gets grouped, labeled, and linked | A different thing gets cut. Information architecture shapes the menus and screens a user sees; this shapes the code and servers behind them |
Where to go next
- Engineering
see from above where architecture sits among the thirteen branches and how it connects to deployment, quality, and operations
- Monolith
almost every service starts here, so knowing its strengths and limits explains what the other six structures were trying to change
Sub-terms
Last updated 2026-09-16