Leer en español · Lire en français · Auf Deutsch lesen
Section 5.1 of 5.8 · Intermediate · 22 min read
Architectural styles, patterns and tactics
Video lesson
5 min · narrated, with captionsListen only (audio)
Read the transcript
In this lesson you'll learn the vocabulary that Chapters five and six rely on: what a style is, how it differs from a pattern and a tactic, and how to count the truly independent parts of a system.
Think of house types: a terrace, a bungalow, a tower block. Each name tells a builder a lot before any drawing exists: how many floors, how the rooms connect, what it costs, and where it works well. Software has its own named shapes, called architectural styles: a layered application, a set of modules in one program, a chain of processing steps, a group of separate services. Knowing them, and what each is good and bad at, lets a team pick a sensible shape quickly and describe it in a few words.
David Garlan and Mary Shaw described an architectural style as a vocabulary of component and connector types, together with constraints on how they can be combined. Pipes and filters, for example, forbids filters from sharing state or knowing their neighbours. Follow that rule, and you get filters that can be tested, reused and rearranged on their own. That's not luck; it's a consequence of the rule. So a style is not a picture to copy. It's a set of rules that buy specific qualities, at a price. Adopt the vocabulary without the rules, and you pay the price without the benefits.
Four related terms are often used loosely. A style describes the overall shape: which parts and connections are allowed, and under what rules. A pattern is a proven solution to a recurring structural problem in a stated context, such as Broker or Model View Controller. A tactic is smaller: one design decision that moves one quality attribute, such as a cache to cut latency. Patterns usually package several tactics. And a reference architecture is a template for a whole domain, such as AUTOSAR for the electronics in cars. Experts disagree about where style ends and pattern begins; spend your energy on the constraints instead.
The first big decision is how to divide the system at the top level. Technical partitioning groups code by technical role: presentation, business logic and persistence. Suppose a food-delivery company lets customers tip the courier. That needs a new field on a screen, a new rule and a new database column. One change touches every layer. Domain partitioning groups code by business capability instead: orders, payment, delivery and menus, each with its own interface, logic and data. Here, the same change lands almost entirely in the delivery module. Most business changes are phrased in domain terms, so domain partitioning tends to keep them in one place. Technical partitioning is simpler, and suits small systems built by one team.
The second distinction is deployment. A monolith is deployed as one unit. A distributed system is several units cooperating over a network, with all the network's costs. A sharper idea is the architecture quantum. A quantum is a part that can be deployed independently, does one coherent business job, and includes everything it needs, its database in particular. A monolith is, by definition, one quantum. Three services that share one database are still one quantum. None can change the schema or be restored on its own, so they rise and fall together. Only when each service owns its data, and they exchange events, do you get three quanta. This matters because architecture characteristics apply per quantum. Parts with very different needs must be separate quanta.
Let's classify four designs for the food-delivery platform. Design one is a single application with folders for views, services and models. Technical partitioning, one unit, one quantum. Every feature crosses all three folders. Design two has packages for orders, payments, delivery and menus, each with its own tables. Still one quantum, but changes stay local, and the modules could later be separated. Design three makes them four services sharing the same tables. Four deployment units, but one quantum: a schema change or a database outage hits all four. All the costs of distribution, few of its benefits. Design four gives each service its own database. Now there are four quanta, each released on its own, at the price of network failures and eventual consistency.
Carry three points forward. Monolith describes deployment, not quality. Split a big ball of mud into services and you get a distributed ball of mud, which is worse. Real systems are hybrids. A modular monolith may be layered inside each module, and run a nightly pipes and filters job. And a style is not a goal in itself. Start from your architecturally significant requirements, pick the simplest style that meets them, record the choice, and enforce its rules.
The full section has a table of every style in Chapters five and six, and more on quanta. Next, in Section five point two, we look at the most familiar style of all: layered architecture. See you there.
What you need to know
- An architectural style is a named set of element types, connector types and constraints on how they combine (Garlan and Shaw); the constraints are what give a style its predictable qualities.
- An architectural pattern, in the tradition of Pattern-Oriented Software Architecture (Buschmann et al., 1996), is a proven solution to a recurring structural problem in a stated context; a tactic is a single design decision aimed at one quality attribute; a reference architecture is a domain template.
- Technical partitioning divides a system by technical role (presentation, logic, data); domain partitioning divides it by business capability (orders, payments, delivery). The choice decides how far a typical feature change spreads and how teams can be organised.
- A monolithic style is deployed as one unit; a distributed style is deployed as several units that cooperate over a network and inherits all the costs of the network.
- An architecture quantum is an independently deployable part with high functional cohesion, data included; one set of architecture characteristics applies per quantum, so parts with very different needs must be separate quanta.
- Each style is a trade-off with characteristic strengths and weaknesses; real systems combine styles, and the ratings in this course are relative judgements for typical implementations, not laws.
Why architects name shapes
Most systems are not designed from nothing. Experienced architects recognise that a new problem resembles one they have seen before and reach for a shape that is known to work: a few layers for a straightforward business application, a chain of processing steps for a data feed, a core with plug-ins for a product that customers extend. Naming those shapes gives a team a shared vocabulary. Saying it is a modular monolith with event-based communication between modules
conveys in ten words what would otherwise take a page of diagrams, and it brings with it a body of knowledge about what tends to go right and wrong.
David Garlan and Mary Shaw put this on a firm footing in An Introduction to Software Architecture (Carnegie Mellon technical report, 1994) and in their book Software Architecture: Perspectives on an Emerging Discipline (1996). They described an architectural style as a vocabulary of component and connector types together with a set of constraints on how they can be combined. Pipes and filters, for example, has one kind of component (a filter that transforms data) and one kind of connector (a pipe that carries it one way), and it constrains filters not to share state or know who their neighbours are. Roy Fielding, whose dissertation (2000) defined REST as a style, made the same point more sharply: a style is a coordinated set of constraints, and it is the constraints that produce the properties. Forbid filters from sharing state and you get filters that can be tested, reused and rearranged independently; that is not luck, it is a consequence of the rule.
This is the most useful way to read every style in this chapter and the next. A style is not a picture to copy. It is a set of rules you agree to follow, chosen because following them buys specific architecture characteristics, the quality attributes of Chapter 2, at a price. A team that adopts the vocabulary of a style but not its rules gets the price without the benefits.
Styles, patterns, tactics and reference architectures
Four related terms are used, often loosely, for reusable design knowledge. They differ mainly in scope and in how much they prescribe.
An architectural pattern describes a proven solution to a recurring structural problem in a stated context. The idea of patterns came from the building architect Christopher Alexander and entered software through the design patterns of Gamma, Helm, Johnson and Vlissides (1994), which work at the scale of a few classes. Pattern-Oriented Software Architecture, Volume 1: A System of Patterns by Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad and Michael Stal (1996), usually called POSA, catalogued patterns at the scale of whole systems: Layers, Pipes and Filters and Blackboard (grouped as getting from mud to structure), Broker for distributed systems, Model-View-Controller and Presentation-Abstraction-Control for interactive systems, and Microkernel and Reflection for adaptable systems. Each POSA pattern is written as context, problem, forces and solution, with consequences, which makes the trade-offs explicit.
A tactic, in the sense used by Len Bass, Paul Clements and Rick Kazman in Software Architecture in Practice, is smaller: one design decision that influences one quality attribute response, such as adding a heartbeat to detect a failed server or a cache to cut latency. Section 2.6 used modifiability tactics such as encapsulation and using an intermediary. Patterns package several tactics: the Layers pattern combines encapsulation, restricting dependencies and using an intermediary.
A reference architecture is a template for a whole domain or platform: it names the typical building blocks and how they connect, so that projects adapt it rather than start from a blank page. AUTOSAR, the layered software architecture used for electronic control units in cars, is a well-known example; the architecture centres published by cloud providers offer many smaller ones. A reference architecture is usually built from several styles and patterns at once.
Practitioners do not agree on where the line between style and pattern falls. POSA calls Layers a pattern; Garlan and Shaw call layered systems a style; Mark Richards and Neal Ford, in Fundamentals of Software Architecture, reserve style
for the overall topology of a system and pattern
for lower-level, reusable structures that can appear inside many styles. This course follows the common usage: style for the overall shape of a system or of a large part of it, pattern for a reusable solution that can sit at any level. Do not spend energy on the boundary; spend it on the constraints and their consequences.
Four kinds of reusable design knowledge
| Term | Scope | Example | Question it answers |
|---|---|---|---|
| Architectural style | Whole system or a large part | Layered, pipes and filters, microservices | What kinds of parts and connections are allowed, and under what rules? |
| Architectural pattern | Any structural level | Broker, Model-View-Controller, Microkernel | What is a proven solution to this recurring structural problem, and what does it cost? |
| Tactic | One design decision | Heartbeat, cache, encapsulation, retry with back-off | Which single decision moves this quality attribute in the direction we need? |
| Reference architecture | A domain or platform | AUTOSAR for car electronics; cloud providers' published architectures | What do systems of this kind usually contain, and how is it usually arranged? |
Two ways to cut a system: technical or domain partitioning
The first structural decision in any style is how to divide the system at the top level. There are two basic answers. Technical partitioning groups code by technical role: everything to do with the user interface in one place, all business rules in another, all database access in a third. Domain partitioning groups code by business capability: everything to do with orders in one place, payments in another, delivery in a third, each containing whatever user interface, logic and data access it needs.
The difference shows up the moment a feature changes. Suppose a food-delivery company lets customers add a tip for the courier. In a technically partitioned system that change needs a new field on a screen (presentation), a new rule for tip limits and payouts (business logic) and a new column and query (persistence): three parts, often owned by three different people or teams. In a domain-partitioned system the same change lands almost entirely in the delivery module. Most business change requests are phrased in domain terms, so domain partitioning tends to keep a change in one place. Technical partitioning keeps a technical change in one place, such as replacing the database access library, but those changes are rarer.
The choice also shapes the organisation. By Conway's law, a technically partitioned system tends to be built by a front-end team, a back-end team and a database team, and every feature needs a hand-off between them. A domain-partitioned system can be built by teams that each own a business capability end to end. Martin Fowler made the same recommendation in 2015: presentation, domain and data layers are a good way to organise a small piece of software, but a larger system's top level should be split into domain-oriented modules, each layered inside if that helps.
Neither is wrong. Technical partitioning is simple, familiar and supported by almost every web framework's default folder structure, and it suits small systems where one team does everything. Domain partitioning costs more thought up front, because someone has to find good domain boundaries (the subject of Section 5.7), but it scales better with the size of the system and the number of teams.
The same feature under two partitionings
Monolithic and distributed styles
The second top-level distinction is about deployment. A deployment unit is the thing that is built, released and started as one piece: a single executable, a container image, a web archive. In a monolithic architecture the whole application is one deployment unit, usually with one database. It can run as many identical copies behind a load balancer, but every copy contains all the code, and releasing any change means releasing all of it. In a distributed architecture the system is several deployment units that cooperate by sending messages over a network, and each can be released and scaled separately.
Two clarifications avoid much confusion. First, monolith
describes deployment, not quality. A monolith can be beautifully modular or a big ball of mud (Brian Foote and Joseph Yoder's name for a system with no discernible structure), and so can a distributed system: many teams have learned that splitting a ball of mud into services gives a distributed ball of mud, which is worse. Second, being distributed is not a free upgrade. Every call that crosses a network can be slow, fail halfway or arrive twice, data can no longer be changed in one local transaction, and the system needs monitoring, deployment automation and on-call skills that a monolith can manage without. Chapter 6 covers those costs in detail. This chapter covers the styles that avoid them: everything runs in one deployment unit, and the architecture lives in how the code inside it is organised.
The architecture quantum
Monolithic and distributed is a useful first cut but too coarse for real decisions. Neal Ford, Rebecca Parsons and Patrick Kua introduced a sharper idea in Building Evolutionary Architectures (2017), refined by Ford, Richards, Sadalage and Dehghani in Software Architecture: The Hard Parts (2021): the architecture quantum. A quantum is a part of the system that can be deployed independently, has high functional cohesion (it does one coherent job for the business) and includes everything it needs to work, its database in particular. The later definition adds that the parts of a quantum are statically coupled (they share code, schemas or infrastructure that must be deployed together) and that synchronous calls bind quanta together operationally for as long as the call lasts.
Why does this matter? Because architecture characteristics apply per quantum. A quantum is scaled, deployed, secured and recovered as a whole, so it has one level of scalability, one level of availability, one release cadence. If two parts of a system need very different characteristics, for example a courier-location feed that must absorb thousands of updates per second and a monthly restaurant-invoicing job, they can only get them by being in different quanta. Conversely, splitting code into several services does not create several quanta if they still share one database: none of them can change the schema or be restored on its own, so they rise and fall together. A monolith is, by definition, one quantum.
Counting quanta
Worked example
Worked example: classifying four designs
A food-delivery company is reviewing four candidate designs for its platform. For each, the architect asks three questions: how is the top level partitioned, how many deployment units are there, and how many quanta?
Design 1: one Django application with folders views, services and models, one PostgreSQL database | Technical partitioning; one deployment unit; one quantum. Simple, but every feature crosses all three folders. |
|---|---|
Design 2: one application with packages orders, payments, delivery and menus, each with its own tables, one database server | Domain partitioning; one deployment unit; one quantum. Changes stay local, and the modules could later be separated. |
| Design 3: four services (orders, payments, delivery, menus) that all read and write the same database tables | Domain partitioning in name; four deployment units but one quantum, because a schema change or a database outage affects all four. All the costs of distribution, few of its benefits. |
| Design 4: the same four services, each with its own database, exchanging events through a message broker | Domain partitioning; four deployment units; four quanta. Each can be scaled and released independently, at the price of network failures and eventual consistency between them. |
Designs 1 and 2 cost the same to run, but design 2 makes typical changes cheaper and keeps future options open.
Design 3 is the warning case: the number of deployment units says little; the number of quanta, which depends on data and coupling, says what can really evolve independently.
How to read the style sections that follow
Sections 5.2 to 5.5 and most of Chapter 6 describe one style each, always in the same order, so that styles can be compared: a definition and where the style came from; a diagram; how it works; a concrete example system; a table rating its main characteristics; when to use it and when not to; common anti-patterns; and how to enforce it in code, because a style that is not checked erodes, as Section 1.7 described.
The characteristic ratings (Low, Medium, High, each with a reason) follow the approach of Richards and Ford's style comparisons, but they are this course's own judgements. Read them as relative and typical: they compare styles as they are usually built, by a competent team, for a typical business system. A disciplined team can make a layered monolith that deploys many times a day, and a careless one can build microservices that cannot be deployed at all. The ratings tell you where the style helps and where you will have to work against it.
Two sections in this chapter are not deployment styles. Hexagonal, onion and clean architecture (Section 5.6) describe how to organise the inside of an application or service so that business logic does not depend on technology. Domain-driven design (Section 5.7) is a way of finding the domain boundaries that modular monoliths and microservices rely on. Both apply equally inside a monolith or a distributed system.
The styles in Chapters 5 and 6 at a glance
| Style | Main partitioning | Deployment | Typical fit |
|---|---|---|---|
| Layered (5.2) | Technical | Monolithic | Small to medium business applications built by one team |
| Modular monolith (5.3) | Domain | Monolithic | Growing products with several teams that want one deployment |
| Pipes and filters (5.4) | Technical (processing steps) | Monolithic or distributed | Data processing: ETL, media, logs, compilers |
| Microkernel (5.5) | Technical core, plug-ins often by domain | Usually monolithic | Products extended by customers or third parties; rules engines |
| Hexagonal, onion, clean (5.6) | Inner structure: domain at the centre | Either | Any application whose logic must outlive its frameworks |
| Service-based (6.2) | Domain | Distributed, few coarse services | A pragmatic step beyond a monolith, often sharing a database |
| Service-oriented architecture (6.2) | Technical (orchestration, enterprise services) | Distributed | Enterprise integration, now largely historical |
| Microservices (6.3) | Domain | Distributed, many fine-grained services | Many teams that must release independently at scale |
| Event-driven (6.4) | Technical (event processing) | Distributed | Highly responsive, decoupled reactions to business events |
| Serverless and space-based (6.8) | Varies | Distributed | Spiky or extreme load; pay-per-use workloads |
Styles combine, and they are not goals
Real systems are hybrids. A modular monolith may be layered inside each module; one of its modules may run a nightly pipes-and-filters job; a microservice may be built in hexagonal style; an event-driven system may use a microkernel to let customers add their own rules. Naming the style of each part is still useful, because each part then inherits a known set of rules and trade-offs.
The common mistake is to treat a style as an aim in itself: we are moving to microservices
as a strategy, rather than as a means to a stated quality such as independent deployment for twelve teams. Start from the architecturally significant requirements of Chapter 2, pick the simplest style whose characteristics meet them, write the choice down as a decision record and enforce its rules. Section 5.8 gives a decision guide for the styles in this chapter.
Check your understanding
According to Garlan and Shaw, what two things define an architectural style?
A vocabulary of component and connector types, and a set of constraints on how they may be combined. The constraints are what produce the style's characteristic qualities.
What is the difference between a tactic and a pattern?
A tactic is one design decision aimed at one quality attribute response, such as a heartbeat or a cache. A pattern is a larger, documented solution that typically combines several tactics.
Why might four services that share one database count as a single architecture quantum?
Because none of them can change the shared schema, be restored or be scaled at the data level without affecting the others; they are deployed and fail together in practice, so they share one set of operational characteristics.
Which kind of change does technical partitioning keep in one place?
A technical change, such as replacing the database access library or the user-interface framework. Typical business changes, by contrast, cut across all the technical layers.
Sources and further reading
Have a question about this section? ArchitectBot, the course’s AI study assistant, answers from the course first.
Ask: “Our four services all use the same PostgreSQL database. Is that really a problem, or just a theoretical one?”