Why styles matter more than frameworks
Frameworks change every three years. Architecture styles have barely changed in thirty, because they are not about technology — they are about how you cut a system into pieces, how those pieces talk, and what happens when one of them fails. Pick the wrong cut and no amount of Kubernetes, Kafka or Rust will save the delivery timeline.
Every style below is an answer to a pressure: a team that cannot ship without stepping on each other, a latency budget that a network hop breaks, a failure that must not spread, a cost curve that must follow traffic. Learn the pressure and the style becomes obvious.
The map: coupling vs distribution
Moving right buys independent scaling and deployment, and charges you in network failure modes, observability and data consistency. Moving up buys evolvability and charges you in indirection. Most bad architectures are teams that paid the right axis and got neither.
1. Monolithic architecture
One deployable unit containing the whole application: UI, business logic, data access. One build, one process, one database, in-process function calls between everything.
- Solves: speed. There is no network, no versioning, no distributed transaction, no service discovery. Refactoring across the whole domain is one commit.
- Costs: the whole thing scales, deploys and fails together. Above roughly 20–30 engineers, merge and release contention becomes the dominant tax.
- Right when: early product, unknown domain boundaries, small team.
2. Modular monolith
The same single deployable, but internally partitioned into modules with explicit public interfaces and enforced import rules; ideally each module owns its own tables and no other module reads them directly.
This is the answer for most teams that think they want microservices. You get the boundaries — which is the hard part — without the distributed systems bill. When a module genuinely needs independent scaling, you extract it, and the interface already exists.
3. Layered (n-tier) architecture
Presentation → application/business → persistence → database, with each layer only calling the one beneath it. It is the default architecture of the industry, usually chosen by accident.
Its strength is that everyone understands it instantly. Its weakness is that layers are a technical partition, not a domain one: a single feature change touches all four layers, and "sinkhole" layers that just pass calls through add cost without value.
4. Client-server architecture
Two tiers: many clients holding presentation and some logic, one shared server holding data and authoritative rules. Every web app, mobile app and database driver is client-server at heart.
The interesting design work is the split: what the client may decide alone (optimistic UI, caching, offline queues) versus what only the server may confirm (money, inventory, auth). Getting that boundary wrong produces either a chatty, slow client or an untrustworthy one.
5. Service-oriented architecture (SOA)
Coarse-grained, reusable business services (Billing, Customer, Order) exposed over standard contracts and often mediated by an enterprise service bus that handles routing, transformation and protocol bridging.
SOA is microservices' older, more centralised sibling: fewer, larger services, shared infrastructure, shared data stores are permitted. It shines in enterprises integrating heterogeneous, long-lived systems. Its classic failure is the ESB turning into a bottleneck and a place where business logic quietly accumulates.
6. Microservices architecture
Many small services, each owning its data, deployed independently, communicating over the network. The organising principle is not size — it is independent deployability aligned to team ownership.
- Buys: independent scaling, fault isolation, per-service tech choices, parallel team throughput.
- Charges: eventual consistency, distributed tracing, network partial failure, contract versioning, and a platform team you did not previously need.
7. Event-driven architecture
Components publish facts about what happened; other components react. Producers do not know their consumers. Adding a new behaviour means adding a subscriber, not editing the producer.
This gives extreme decoupling and natural buffering under load, at the price of a system whose behaviour is not visible in any single call graph. Debugging becomes a correlation-ID exercise. Ordering, duplicate delivery and replay all become explicit design decisions.
8. Microkernel (plugin) architecture
A minimal core provides the invariant machinery — lifecycle, registry, dispatch — and all variable behaviour lives in plugins loaded against a stable extension contract. VS Code, Eclipse, Kubernetes controllers, browsers and most CI systems are microkernels.
Choose it when the requirement is "the same core, endlessly varied by customer, country, or rule set". The hard part is the contract: too narrow and plugins hack around it, too broad and the core cannot evolve.
9. Serverless architecture
Functions and managed services, invoked per request or per event, with no long-lived server the team operates. Capacity, patching and scale-to-zero are the provider's problem.
Superb for spiky, event-shaped, embarrassingly parallel work. Awkward for latency-critical paths (cold starts), long-running jobs, heavy connection pooling to relational databases and cost predictability at sustained high throughput.
10. Peer-to-peer architecture
No privileged server: every node is both client and server, discovering peers and exchanging data directly. BitTorrent, blockchains, IPFS, WebRTC calls and many CDN edge fabrics use it.
You get resilience with no single point of failure and capacity that grows with the user base. You pay in consistency, discovery complexity, NAT traversal and the trust problem: peers can lie, so protocols need hashes, signatures or consensus.
11. Space-based architecture
Remove the database from the hot path. Processing units hold data in a replicated in-memory grid (the "tuple space"), a messaging grid routes requests, and a data pump asynchronously persists to durable storage.
This is the answer to extreme, unpredictable concurrency — ticketing on-sale, betting during a match — where the database is the ceiling. The cost is memory footprint, cache coherence and the operational sophistication of a distributed grid.
12. Pipe-and-filter architecture
Independent filters transform a stream, connected by pipes; each filter knows only its input and output contract. Unix pipelines, compilers, ETL/ELT jobs, media transcoders and stream processors are all pipe-and-filter.
It excels at composability and parallelism — any filter can be scaled or replaced independently. It struggles with interactive, low-latency workloads and with anything that needs a global view of state mid-stream.
13. Hexagonal (ports and adapters)
Domain logic sits in the centre and defines ports (interfaces) for everything it needs. Databases, HTTP handlers, queues and third-party APIs are adapters that plug into those ports. All dependencies point inward.
Unlike the others, this is an internal style — it composes with monoliths, microservices and serverless alike. It buys testability (the domain runs with in-memory adapters) and infrastructure replaceability, and charges an indirection tax that small CRUD apps rarely recoup.
Side-by-side comparison
| Style | Deploy unit | Best at | Main failure mode |
|---|---|---|---|
| Monolith | One | Speed at small scale | Release contention |
| Modular monolith | One | Boundaries without distribution | Rules erode without enforcement |
| Layered | One | Familiarity | Technical, not domain, boundaries |
| Client-server | Two tiers | Shared authoritative state | Chatty or over-trusted client |
| SOA | Few services | Enterprise integration | ESB bottleneck |
| Microservices | Many services | Team autonomy, scale | Distributed complexity |
| Event-driven | Many + broker | Decoupling, bursty load | Invisible control flow |
| Microkernel | Core + plugins | Variability | Wrong extension contract |
| Serverless | Functions | Spiky, event work | Cold starts, cost at scale |
| Peer-to-peer | Nodes | Resilience, free capacity | Consistency and trust |
| Space-based | Grid units | Extreme concurrency | Cache coherence, memory cost |
| Pipe-and-filter | Stages | Stream transformation | Poor for interactive work |
| Hexagonal | Any | Testability | Indirection overhead |
How to actually choose
- Write the top three quality attributes first. "Deploy 20 times a day", "p99 under 80 ms", "a bad plugin must not crash the core". Architecture follows from these, not from a blog post.
- Count the teams. Conway's law is not optional. Service boundaries that do not match ownership boundaries create constant cross-team coordination.
- Find the ceiling. If the database is the ceiling, distribution alone will not help — space-based or CQRS will.
- Prefer the reversible choice. A modular monolith can become services. A premature 40-service estate rarely becomes anything.
- Mix deliberately. Real systems are hybrids: a modular monolith core, a few event-driven side flows, serverless for image processing, hexagonal on the inside.
Interview framing
When an interviewer asks "which architecture would you use?", the weak answer names a style. The strong answer names the forces, then the style, then the price:
"Three teams, unclear domain boundaries, and a hard requirement to ship weekly — I'd start with a modular monolith with enforced module boundaries and its own schema per module. The read-heavy catalogue is the first thing that will need independent scaling, so I'd design that module's interface to be network-ready. I accept that a single bad deploy affects everything, and I mitigate with feature flags and canaries rather than by splitting into services we cannot yet operate."
Follow-ups you should expect
- How would you decide the first service to extract, and how would you verify it helped?
- Where does data consistency break when you split, and what do you do about it?
- What operational capability must exist before microservices are safe?
Each architecture in this list has its own deep dive below — the individual articles cover the internal structure, real systems that use it, and the specific failure modes.