Be Software Architecture Wise
Be Wise Apps

Leer en español · Lire en français · Auf Deutsch lesen

Chapter 5 of 12 · Intermediate

Architectural Styles I: Monoliths and Modular Designs

Most software, including some of the largest and most successful products, runs as a single deployable application. This chapter explains how such applications should be structured inside. It introduces the vocabulary of architectural styles, patterns, tactics and the architecture quantum, then covers layered architecture, the modular monolith, pipes and filters, microkernel and plug-in architecture, hexagonal, onion and clean architecture, and strategic domain-driven design, and ends with when a monolith is the right answer. It is for developers and architects who design or maintain business applications and want to choose and enforce a structure deliberately.

Video introduction to Chapter 5

6 min · narrated, with captions
Listen only (audio)
Read the transcript

Welcome to Chapter 5: Architectural Styles, part one, Monoliths and Modular Designs. Most software, including some of the largest and most successful products, runs as a single deployable application. This chapter explains how such applications should be structured inside, and when a single application is the right answer.

Chapters 3 and 4 gave you the principles of good structure, and the tools for describing it. This chapter and the next turn those principles into the recurring shapes that real systems take. Knowing the main styles lets you start from a shape that is known to work for a given set of qualities, explain it in a sentence, and recognise early when a system is drifting away from it. This chapter covers styles where the whole application is one deployment unit: one build, one release, usually one database. That does not make monoliths primitive. Whether a monolith is a pleasure or a misery to work on depends almost entirely on how it is divided inside.

The chapter is for developers and architects who design or maintain business applications, and want to choose and enforce a structure deliberately. It builds on Chapters 3 and 4, especially modularity, coupling and cohesion, dependencies and layering, and the C4 model. Chapter 2's quality attributes are used throughout. And it leads into Chapter 6, which takes the same questions across a network, where things get harder. A monolith avoids the network failures, partial outages and consistency problems of distributed systems. Chapter 6 takes those on.

First, a definition. An architectural style is a named set of constraints on the kinds of parts a system has, and how they may connect. The constraints are the point. Forbid one business module from touching another's tables, for example, and you get predictable benefits, at a predictable price.

The chapter has eight sections. Section five point one sets up the vocabulary used for every style in Chapters 5 and 6: styles, patterns, tactics and reference architectures. It explains the difference between technical partitioning, by layer, and domain partitioning, by business capability. And it introduces the architecture quantum: an independently deployable part, data included, to which one set of qualities applies.

Here is why partitioning matters. Suppose a food-delivery company lets customers add a tip for the courier. With technical partitioning, that one change touches the presentation layer, the business logic and the persistence layer. With domain partitioning, the same change lands almost entirely in the delivery module, which may still be layered inside. Most business change requests are phrased in domain terms, so domain partitioning tends to keep a change in one place. And it lets each team own a business capability end to end.

Sections five point two to five point five describe four styles in the same format, with a diagram, an example, a table of characteristics, when to use it, and how to enforce it in code. Layered architecture is the familiar stack of presentation, business and persistence layers. The modular monolith divides one deployable application by business domain, with explicit module interfaces and clear data ownership, illustrated by Shopify's experience. Pipes and filters arranges processing as a chain of independent steps, from Unix pipes to data pipelines. And the microkernel builds a minimal core that plug-ins extend, as in development tools, browsers and rules engines.

This diagram from Section five point three shows a modular monolith inside. The dashed boundary is one deployment unit: the food-delivery application. Each module, here Ordering and Payments, has a small public API. Ordering may use Payments only by calling that API. Everything else in a module is internal. Reaching from one module's internals into another's is forbidden. And each module owns its own schema, with no joins across schemas. Keep to these rules, and any module can later be extracted into a service with modest effort.

Section five point six covers hexagonal, onion and clean architecture. They put the business logic at the centre, and make databases, user interfaces and external services depend on it, never the other way round. Section five point seven, on strategic domain-driven design, supplies the method for finding good boundaries: subdomains, bounded contexts, and the relationships between them in a context map. Finally, Section five point eight asks when a monolith is the right answer, how far it can scale, and which signs say it is time to split. It ends with a decision guide and a comparison table for all of the chapter's styles.

If you remember one thing, make it this: the boundaries inside a system matter more than the boundaries between deployment units. A set of services that share a database and call each other's internals is still one tangled system, now with network failures added. Two habits follow. First, choose the simplest style whose characteristics meet the system's architecturally significant requirements, and record the choice and its trade-offs in a decision record. Second, enforce the style's rules with architecture tests in the build, because every style erodes when its constraints live only in people's heads.

Read Section five point one first, because every later section uses its vocabulary. After that, you can take the styles in order or dip into the one you need. The chapter takes about three hours to read. Follow the food-delivery platform as it runs through the chapter. Comparing the styles on one familiar system is far easier than on unrelated toy examples. Each section ends with a few self-check questions. Answer them in your head before you look. When you are ready, take the optional chapter test: twenty multiple-choice questions and two written answers, in about forty five minutes. The pass mark is eighty per cent.

That is the map of Chapter 5. Start with Section five point one, where we set up the vocabulary of styles, patterns and tactics that the next two chapters rely on. See you there.

Download chapter (PDF)Read in the app

At a glance

You will learn to

  • Distinguish architectural styles, patterns, tactics and reference architectures, and explain why a style's constraints produce its qualities.
  • Compare technical and domain partitioning and predict how each affects the cost of a typical change and the organisation of teams.
  • Identify the architecture quanta in a design and explain why shared databases bind services into one quantum.
  • Describe layered, modular monolith, pipes-and-filters and microkernel styles, rate their characteristics and recognise their anti-patterns.
  • Apply hexagonal, onion or clean architecture to keep business logic independent of frameworks and infrastructure.
  • Use strategic domain-driven design to find bounded contexts and describe their relationships in a context map.
  • Enforce structural rules in code with architecture tests and module tooling such as import-linter, ArchUnit and Spring Modulith.
  • Decide when a monolith is the right choice, how to scale it and which signs indicate it is time to extract services.

Before you start

Chapter 3, especially modularity, coupling and cohesion, and dependencies and layering; Chapter 4, especially the C4 model. Chapter 2's quality attributes are used throughout.

Time

About 3 hours to read; 45 minutes for the test.

Key terms

architectural style · architectural pattern · tactic · technical partitioning · domain partitioning · architecture quantum · closed and open layers · architecture sinkhole · modular monolith · pipes and filters · back pressure · microkernel · ports and adapters · bounded context

Why styles matter

Chapters 3 and 4 gave you the principles of good structure (modularity, coupling and cohesion, dependency direction) and the tools for describing it. This chapter and the next turn those principles into the recurring shapes that real systems take. An architectural style is a named set of constraints on the kinds of parts a system has and how they may connect. The constraints are the point: forbid the parts of a pipeline from sharing state, or forbid one business module from touching another's tables, and you get predictable benefits, at a predictable price. Knowing the main styles lets an architect start from a shape that is known to work for a given set of qualities, explain it in a sentence, and recognise early when a system is drifting away from it.

This chapter covers styles in which the whole application is a single deployment unit: one build, one release, usually one database, with parts calling each other in memory. Such a monolithic architecture avoids the network failures, partial outages and consistency problems of distributed systems, which Chapter 6 takes on. That does not make monoliths primitive. Whether a monolith is a pleasure or a misery to work on depends almost entirely on how it is divided inside, and that is what this chapter is about.

How the chapter fits together

Section 5.1 sets up the vocabulary used for every style in Chapters 5 and 6: styles, patterns, tactics and reference architectures; the difference between technical partitioning (by layer) and domain partitioning (by business capability); monolithic versus distributed deployment; and the architecture quantum, the independently deployable unit to which one set of qualities applies. It ends with a summary table of all the styles in the two chapters.

Sections 5.2 to 5.5 then describe four styles in a consistent format: definition and origin, a diagram, how it works, an example, a table of characteristics, when to use it and when not, anti-patterns, and how to enforce it in code. Layered architecture (5.2) is the familiar presentation, business and persistence stack, with closed and open layers and the sinkhole anti-pattern. The modular monolith (5.3) divides one deployable application by business domain, with explicit module APIs and data ownership, illustrated by Shopify's experience and a module map of a food-delivery platform. Pipes and filters (5.4) arranges processing as a chain of independent steps, from Unix pipes to data pipelines. The microkernel (5.5) builds a minimal core that plug-ins extend, as in IDEs, browsers and rules engines.

Sections 5.6 and 5.7 are about structure inside and between modules rather than about deployment. Hexagonal, onion and clean architecture (5.6) put the business logic at the centre and make databases, user interfaces and external services depend on it, never the other way round, which makes the core testable and its infrastructure replaceable. Strategic domain-driven design (5.7) supplies the method for finding good boundaries: subdomains, bounded contexts and the relationships between them in a context map. Finally, Section 5.8 asks when a monolith is the right answer, how far it can scale, which signs say it is time to split, and offers a decision guide and comparison table for the chapter's styles.

A running example

As in earlier chapters, a food-delivery platform appears throughout: customers order from restaurants, couriers deliver, payments go through an external provider. In Section 5.1 it is classified under four candidate designs; in 5.2 it is a classic layered web application; in 5.3 it becomes eight modules with a dependency rule checked in the build; in 5.4 its order events flow through a pipeline into a warehouse, where finding the bottleneck is a worked calculation. Later sections return to the same platform, most fully in the context map of Section 5.7, so that the styles can be compared on one familiar system rather than on unrelated toy examples.

The idea to take away

If you remember one thing from this chapter, make it this: the boundaries inside a system matter more than the boundaries between deployment units. A monolith divided by domain, with explicit module APIs, one owner for every table and dependency rules checked automatically, can be changed safely by several teams for many years, and any module can later become a service if it truly needs to. A set of services that share a database and call each other's internals is still one tangled system, now with network failures added. Styles are tools for creating and keeping good boundaries; none of them is a goal in itself.

Two habits follow. First, choose the simplest style whose characteristics meet the system's architecturally significant requirements, and record the choice and its trade-offs in a decision record. Second, enforce the style's rules with architecture tests in the build, because every style erodes when its constraints live only in people's heads.

The 8 sections

5.1 · Intermediate · 22 minStyles and patternsThe vocabulary for the next two chapters: styles, patterns, tactics and reference architectures, technical versus domain partitioning, monolithic versus distributed deployment, and the architecture quantum.Read →5.2 · Intermediate · 24 minLayeredThe most familiar style: presentation, business, persistence and database layers. Closed and open layers, layers of isolation, the sinkhole anti-pattern, why every feature touches every layer, and how to enforce the rules.Read →5.3 · Intermediate · 26 minModular monolithOne deployable application divided by business domain into modules with explicit APIs and their own data. How to enforce the boundaries, how modules communicate, what Shopify learned, and how it keeps the option of extracting services later.Read →5.4 · Intermediate · 23 minPipes and filtersData flowing through a chain of independent steps: producers, transformers, testers and consumers joined by pipes. From Unix pipes to ETL, compilers and stream processing, with throughput, back pressure and error handling.Read →5.5 · Intermediate · 24 minMicrokernelHow a small core system plus independent plug-ins delivers extensibility: registries, contracts, isolation and versioning, real examples from IDEs and browsers, and a worked plug-in contract for country-specific tax rules.Read →5.6 · Intermediate · 25 minHexagonal and cleanPorts and adapters, onion and clean architecture: keeping business logic at the centre with dependencies pointing inwards, driving and driven ports, a Python example with a real adapter and a test double, and the costs.Read →5.7 · Intermediate · 26 minDomain-driven designFinding boundaries in the business domain: ubiquitous language, core, supporting and generic subdomains, bounded contexts, context-map relationships, event storming, aggregates, and a context map of the food-delivery platform.Read →5.8 · Intermediate · 24 minChoosing a monolithMonolithFirst, the microservice premium and the majestic monolith; when one deployment unit is the right choice, how far a monolith scales, the signs that it is time to split, and a decision guide for the Chapter 5 styles.Read →

Chapter test

Test your understanding of Chapter 5

Optional: 20 multiple-choice questions and 2 short written answers, drawn afresh from a bank of 72 questions. Pass mark 80%. Passing every chapter test, then the final assessment, earns the Be Wise Certificate of Completion.

Take the Chapter 5 test in the app

Further reading