Application Architecture Styles
An application architecture style is the blueprint for how the code within a single, cohesive application is organised into modules or layers to manage its internal dependencies. In practice I rarely pick one style for a whole application. I start from a default outer shape and choose what goes inside each part based on what that part needs.
Modular Monolith Architecture
Section titled “Modular Monolith Architecture”My starting point is a modular monolith: a single deployable unit, organised into well-defined, loosely coupled modules that each own their own domain logic and data access, with boundaries enforced through code structure rather than network calls. I extract a module into a separate service only when a specific team or scaling boundary demands it, not up front (see Ways of Working).
The reasoning is the distinction between logical and physical coupling covered in Key Concepts. Loosely coupled modules at the logical level give you most of the benefit of microservices in managing complexity, without the operational cost of decoupling them at runtime. A modular monolith is not a “big ball of mud”: the difference is that the boundaries are designed, and enforced by the compiler.
Vertical-slice Architecture
Section titled “Vertical-slice Architecture”Within the monolith, I organise the code by feature or logical module rather than by technical layer. That’s the part of Jimmy Bogard’s Vertical Slice Architecture I value most, along with the idea that each slice or module should be tailored to its own needs. A simple module can stay simple. One with real business complexity gets a proper domain model: the choice Martin Fowler describes in Patterns of Enterprise Application Architecture between Transaction Script and Domain Model.
The part I don’t insist on is keeping all of a slice’s code in one place. Once a module has a shared domain model, its logic naturally lives outside any single slice, and that’s fine. This is also a good example of not being too rigid: there’s no need for every slice to follow the same internal architecture.
Clean (Concentric / Hexagonal / Onion) Architecture
Section titled “Clean (Concentric / Hexagonal / Onion) Architecture”Where a module does have a domain model, that’s where the patterns of Clean Architecture come in. Clean, Hexagonal and Onion architectures differ in detail, but share one idea: the core business logic sits at the centre, and all code dependencies point inwards, so the core is independent of databases, user interfaces and external frameworks. In practice I structure this as separate projects with clean contracts between them, and let the build enforce the dependency direction.
Traditional layered architecture is effectively legacy for me. With the data layer at the bottom, the business logic ends up depending on the database. Clean and Hexagonal architectures invert that dependency, so the core depends on nothing.
CQRS (Command Query Responsibility Segregation)
Section titled “CQRS (Command Query Responsibility Segregation)”CQRS separates the models used to update state (commands) from the models used to read it (queries), so each can be shaped for its own job. I’d apply it in its lightest form first: separate read and write models within the same application and database, before reaching for a separate read database or event-driven synchronisation between them.
Serverless (FaaS) Architecture
Section titled “Serverless (FaaS) Architecture”I use serverless functions (Azure Functions) as a supporting technology rather than the core style. On SERPsketch we used what Microsoft’s Azure Architecture Center calls the Web-Queue-Worker style: a web front end hands work to a queue, and functions process it in the background.
I don’t favour FaaS as the core style, with all of an application’s compute as serverless functions. Cold starts are one issue, but the bigger one for me is granularity: a single function is microservices taken to the extreme, and I’ve found the operating model too fine-grained to keep under control. In my experience, functions work best as focused background workers alongside a containerised core.
It’s also worth separating “serverless” from “FaaS”. Azure Container Apps is a serverless platform too, running ordinary containers without managing servers. It’s the platform I lean towards most: a sweet spot that gives you containers and a cloud-native model without the operational overhead of AKS. For lighter-weight scenarios, Azure App Service (Web Apps) is still a perfectly good choice.
Client-Server Architecture
Section titled “Client-Server Architecture”Client-server is less a style I choose than a foundation almost everything else sits on: separating the client that asks from the server that provides. It’s also the first of the constraints Roy Fielding set out for REST in his 2000 dissertation.
Other Styles
Section titled “Other Styles”A few other styles are worth knowing, although they rarely shape how I organise an application:
- Pipe-and-Filter — processing structured as a series of independent filters, each transforming data and passing it along a pipe to the next stage, so stages can be composed, reordered or replaced.
- Component-Based — a codebase organised into self-contained, reusable components with well-defined interfaces, each encapsulating its own behaviour and state.
- Microkernel (Plug-in) — a minimal core system containing only what’s needed to run, extended by independent plug-in modules.
References
Section titled “References”- Jimmy Bogard — “Vertical Slice Architecture” (2018).
- Alistair Cockburn — Hexagonal Architecture (ports and adapters, 2005).
- Roy Fielding — “Architectural Styles and the Design of Network-based Software Architectures”, PhD dissertation, University of California, Irvine (2000).
- Martin Fowler — Patterns of Enterprise Application Architecture (2002).
- Robert C. Martin — “The Clean Architecture” (2012).
- Microsoft — “Web-Queue-Worker architecture style”, Azure Architecture Center.
- Jeffrey Palermo — “The Onion Architecture” (2008).
