Architecture Style Diagrams

Last updated:

Technical Versus Domain Partitioning

Structure

Where one checkout change lands under each partitioning.

Technical partitioning versus domain partitioning On the left, a technically partitioned system has three layers: presentation, business logic, and persistence. A single checkout change touches code in every layer. On the right, a domain-partitioned system has three partitions, checkout, inventory, and shipping, each containing its own UI, logic, and data. The same checkout change stays inside the checkout partition. TECHNICAL PARTITIONING Presentation Business logic Persistence checkout checkout checkout A checkout change cuts across every layer DOMAIN PARTITIONING Checkout UI Logic Data Inventory UI Logic Data Shipping UI Logic Data The same change stays inside one partition code that one checkout change touches

Afferent and Efferent Coupling

Dependency graph

Dependencies pointing in versus out, and the instability they give.

Afferent and efferent coupling of one component Three components depend on the component in the middle, so its afferent coupling Ca is 3. The component depends on two others, so its efferent coupling Ce is 2. Instability is Ce divided by Ce plus Ca, which is 2 over 5, or 0.4. AFFERENT: DEPEND ON IT EFFERENT: IT DEPENDS ON Dependent uses the component Dependent uses the component Dependent uses the component The component Ca = 3 arrows in Ce = 2 arrows out Dependency the component uses it Dependency the component uses it I = Ce / (Ce + Ca) = 2 / (2 + 3) = 0.4 near 0: stable. near 1: free to change. depends on

The Main Sequence

Chart

Abstractness against instability, with the two zones to avoid.

Abstractness plotted against instability, with the main sequence A square chart with instability I on the horizontal axis and abstractness A on the vertical axis, both from 0 to 1. The main sequence is the diagonal line A plus I equals 1, running from the top left to the bottom right, and components on or near it are balanced. The bottom-left corner, concrete and heavily depended on, is the zone of pain. The top-right corner, abstract with nothing depending on it, is the zone of uselessness. A component off the line sits a distance D from it, measured as the vertical gap, which equals the absolute value of A plus I minus 1. Zone of pain concrete, heavily used Zone of uselessness abstract, nothing uses it main sequence: A + I = 1 a component D 0 1 0 1 Instability (I) stable unstable Abstractness (A) D = |A + I − 1| the vertical gap between a component and the line. Near zero is healthy. A = 0: purely concrete A = 1: purely abstract I = 0: others depend on it, it depends on nothing I = 1: it depends on others, nothing depends on it components balanced near the line a component off the line

Characteristics per Architecture Quantum

Structure

One deployable unit meets the stricter set everywhere; separate quanta do not.

Architecture characteristics scoped to one unit versus separate quanta On the left, checkout and monthly reporting share one deployable unit. Checkout needs high availability and elastic scalability, so the whole unit has to meet them, including reporting, which needs neither. On the right, checkout and reporting are separate quanta. Checkout carries high availability and elastic scalability, and reporting carries neither. ONE DEPLOYABLE UNIT must meet: high availability, elastic scalability Checkout needs high availability and elastic scalability Monthly reporting needs neither, and has to meet both anyway SEPARATE QUANTA own set: high availability, elastic scalability Checkout quantum own set: neither Monthly reporting quantum Differing characteristics are one of the strongest signals that a system should be split into separate quanta.

Where the Quantum Boundary Falls

Structure

A synchronous call, a queued message, and a shared database.

Where the architecture quantum boundary falls in three cases Three cases. A synchronous call from Order to Payment binds them into one quantum: if Payment is down, orders stop. An asynchronous message through a queue leaves Order and Payment as two quanta: if Payment is down, orders wait in the queue and are paid later. Three services that deploy separately but share one database form one quantum, because none can run correctly without the shared database. SYNCHRONOUS CALL one quantum Order Payment request response Payment down: orders stop. ASYNCHRONOUS MESSAGE Order quantum queue Payment quantum Payment down: orders wait in the queue and are paid later. SHARED DATABASE Svc A Svc B Svc C One database one quantum Deploy separately, but none runs without the shared piece. quantum boundary call, message, or data access

Strict and Relaxed Layering

Layering

Requests normally pass down one layer at a time, and a documented relaxed path may skip one.

Strict and relaxed layering in a layered architecture Presentation, business, persistence, and database layers are stacked. On the strict path, a request passes down one layer at a time, from presentation to business to persistence to the database. On a relaxed path, reporting reads go from presentation straight to persistence, skipping the business layer. Each relaxed path is a dependency that crosses a layer boundary. Presentation user interaction and API endpoints Business domain rules and workflows Persistence data access behind interfaces Database relaxed path: reporting reads skip the business layer Each relaxed path is a dependency that crosses a layer boundary. strict path: one layer at a time relaxed path

Pipeline Topology Variations

Flow

Branching, convergent, and parallel pipelines.

Branching, convergent, and parallel pipeline topologies Three pipeline shapes. Branching: read, parse, and validate, then valid records go to enrich and store while invalid records go to an error file. Convergent: CRM, billing, and web signup exports all feed normalize, deduplicate, and a customer store. Parallel: read and split, then three instances of a costly transform share the load before store. BRANCHING: A VALIDATION FILTER ROUTES RECORDS BY CONTENT Read Parse Validate Enrich Store Error file valid invalid CONVERGENT: SEVERAL SOURCES FEED ONE PIPELINE CRM export Billing export Web signups Normalize Deduplicate Customer store PARALLEL: INSTANCES OF A COSTLY FILTER SHARE THE LOAD Read Split Transform (instance 1) Transform (instance 2) Transform (instance 3) Store

Microkernel Core and Plug-ins

C4 · Component

A core that looks up the right plug-in and calls it through a contract.

Microkernel architecture: a core that finds plug-ins and calls them through contracts A core runs the workflow every customer shares and keeps a registry of plug-ins. It reaches three country e-invoicing plug-ins, Italy, Germany, and France, each through a contract. Plug-ins talk to the core through contracts and never to each other. Core [workflow every customer shares] looks up the right plug-in, then invokes it through its contract Registry which plug-ins exist and what each handles Plug-in [Italy e-invoicing] contract Plug-in [Germany e-invoicing] contract Plug-in [France e-invoicing] contract ✗ ✗ Plug-ins talk to the core through contracts, never to each other. call through a contract not allowed

Modules in One Deployable Application

C4 · Component

Modules call through public interfaces and each owns its schema.

Modular monolith: modules, public interfaces, and module-owned schemas One deployable application holds a Checkout module and an Inventory module. Each exposes a public interface and hides its domain model, logic, and data access. Checkout calls Inventory only through IInventoryService. Each module owns its own schema, and Checkout reaching into the inventory schema directly is not allowed. ONE DEPLOYABLE APPLICATION Checkout module public: ICheckoutService internal domain model, logic, data access Inventory module public: IInventoryService internal domain model, logic, data access calls checkout schema inventory schema ✗ reaching into another module’s tables Modules reach each other only through public interfaces, and each owns its own data. call or data access not allowed

Direct and Mediated Module Calls

Flow

A direct interface call versus a command and event through a mediator.

Direct calls through interfaces versus mediated commands and events On the left, Checkout calls ReserveStock on IInventoryService directly, and Inventory supplies the implementation. On the right, Checkout sends a ReserveStockCommand to an in-process mediator, which routes it to the Inventory handler. Inventory publishes a StockReservedEvent through the mediator, and interested modules handle it. Checkout and Inventory never reference each other. DIRECT CALLS Checkout Inventory supplies the implementation IInventoryService .ReserveStock() MEDIATED COMMANDS AND EVENTS Checkout Mediator [in-process] Inventory handler Interested modules ReserveStockCommand StockReservedEvent On the right, the two modules never reference each other, and control flow is harder to trace. call or command event

Service-Based Topology

C4 · Container

A few coarse domain services behind one UI, sharing a database.

Service-based architecture topology A user interface routes requests to four separately deployed, coarse-grained domain services: catalog, checkout, inventory, and fulfillment. Each service has its own API, business logic, and persistence. All four share one database, with tables grouped by domain: catalog, orders, stock, and shipping. User interface routes each request to the service that owns it Catalog service [separately deployed] API business logic persistence Checkout service [separately deployed] API business logic persistence Inventory service [separately deployed] API business logic persistence Fulfillment service [separately deployed] API business logic persistence Shared database, tables grouped by domain catalog tables orders tables stock tables ship tables

How Much of the Database Services Share

Structure

One shared database, one per domain, or one per service.

Shared, domain, and service-owned databases in service-based architecture The same six services under three data topologies. With a shared database, all six use one database. With domain databases, catalog and search share a catalog database, cart and checkout share an orders database, and inventory and fulfillment share a logistics database. With service-owned databases, each service has its own. SHARED DATABASE Catalog Search Cart Checkout Inventory Fulfillment one database transactions stay simple, and services are coupled through the schema DOMAIN DATABASES Catalog Search Cart Checkout Inventory Fulfillment catalog database orders database logistics database transactions within a domain, and sagas or eventual consistency across domains SERVICE-OWNED DATABASES Catalog Search Cart Checkout Inventory Fulfillment own database own database own database own database own database own database services fully independent at the data level, and no transaction spans them

Choreographed and Orchestrated Workflows

Flow

Components reacting on their own versus steps directed by a coordinator.

Choreographed versus orchestrated workflows in event-driven architecture In the choreographed workflow, an order placed event reaches inventory, payment, and notification at once, with no coordinator. Inventory publishes inventory reserved and payment publishes payment captured, and those events set off further reactions. In the orchestrated workflow, the order placed event goes to a coordinator, which sends step 1 to inventory, step 2 to payment after step 1 succeeds, and step 3 to notification after step 2 succeeds. CHOREOGRAPHED: NO COORDINATOR, COMPONENTS REACT Order Inventory Payment Notification order placed Further reactions inventory reserved payment captured ORCHESTRATED: A COORDINATOR DIRECTS THE STEPS Order Coordinator tracks the workflow order placed Inventory step 1 Payment step 2 after step 1 succeeds Notification step 3 after step 2 succeeds event directed step

Full-State and Identifier-Only Events

Flow

A full payload versus an identifier the subscriber has to look up.

Full-state events versus identifier-only events On the left, an OrderPlaced event carrying full state carries customer details, items, prices, and the shipping address, and the subscriber acts on it without querying anything. On the right, an OrderPlaced event carrying an identifier carries only the order ID, and the subscriber queries the order service for the details it needs. That query needs the source to be available at runtime, and it returns the data as it is at query time, which may differ from its state when the event occurred. FULL STATE IN THE EVENT Order service publisher Subscriber IDENTIFIER ONLY Order service publisher Subscriber OrderPlaced customer details, items, prices, shipping address OrderPlaced orderId only query for details acts immediately, with no query needs the source available at runtime, and sees data as it is now, not at the event event extra call back to the source

Microservices Topology

C4 · Container

Fine-grained services, each owning its data, linked by events.

Microservices topology An API gateway or user interface calls the order, payment, and catalog services. Each service owns its own data store, which no other service reads or writes. The order service publishes an order placed event to an event channel, and the payment service receives it. API gateway / user interface Order service [deploys independently] orders data Payment service [deploys independently] payments data Catalog service [deploys independently] catalog data event channel order placed Each service owns its data. No other service reads or writes it directly. call event

Orchestration-Driven SOA

Layering

Process services composed from shared services, with the orchestration engine and bus in the middle.

Orchestration-driven service-oriented architecture Consumers such as applications, partners, and user interfaces call coarse-grained process services such as Submit loan application. Process services run through the orchestration engine and enterprise service bus, which handle process flow, routing, transformation, and protocol mediation. The bus calls shared services such as Validate customer and Calculate credit score, and application-specific services that are not shared. Utility services for logging and security sit beneath everything. All communication flows through the bus, which makes it the central coupling point. Consumers: applications, partners, user interfaces Process services coarse-grained entry points for whole processes "Submit loan application" Orchestration engine and enterprise service bus process flow, routing, transformation, protocol mediation Shared service [shared, reused] Validate customer Shared service [shared, reused] Calculate credit score Application-specific service [not shared] single application only Utility services: logging, monitoring, authentication, authorization All communication flows through the bus, which makes it the central coupling point.

Space-Based Topology

C4 · Container

Requests served from memory, with the database off the request path.

Space-based architecture topology A router sends each request to a processing unit holding application code and in-memory data. An autoscaler starts and stops units as load changes. An in-memory data grid replicates changes between units asynchronously. Changes queue behind the requests, and a writer applies them to the database later. A loader fills units that start empty from the database. No request waits on the database. Requests Request router sends each request to a unit Autoscaler starts and stops units on load Processing unit code + in-memory data Processing unit code + in-memory data More units added as load rises in-memory data grid: replicates changes between units, asynchronously write-behind queue (asynchronous) Database writer Database durable storage Cold-start loader fills units that start empty No request waits on the database. request or data access asynchronous control

Replicated and Distributed Caching

Structure

A full local copy in every unit versus one remote cache cluster.

Replicated caching versus distributed caching in space-based architecture With replicated caching, every processing unit holds a full copy of the cached data and changes replicate between units, so reads are local. With distributed caching, the data lives in a separate cache cluster, and every unit reads and writes it over the network, keeping one authoritative copy. REPLICATED CACHING Processing unit full copy Processing unit full copy Processing unit full copy replicate changes reads are local, and the whole cache fits in every unit DISTRIBUTED CACHING Processing unit no local copy Processing unit no local copy Processing unit no local copy Cache cluster holds one authoritative copy every access crosses the network replication network read or write

Found this useful? Share it:

Share on LinkedIn