Chapter 9: Foundations of Architecture Styles

fsa architecture-styles foundations

Status: Notes complete


Overview

Architecture styles are the named, recognized large-scale structures that define how an entire system is organized — they are the vocabulary architects use when discussing system shape. Unlike design patterns (which solve recurring local problems within a component), styles address the top-level structure of a whole system. Chapter 9 establishes the vocabulary and foundational concepts required before diving into individual styles: how styles differ from patterns, the fundamental “anti-styles,” the critical choice between technical and domain partitioning, the monolith vs. distributed spectrum, and the eight fallacies of distributed computing that every architect must internalize.


Styles vs. Patterns

Architecture styles define the overall shape and organization of an entire system — they name recognized macro-structures such as layered, microservices, event-driven, or pipeline. A style imposes structural constraints at the system level: how components communicate, how data flows, how the system is deployed.

Architecture patterns are reusable solutions to locally recurring design problems within a component or subsystem — examples include CQRS, Saga, Circuit Breaker, Event Sourcing. Patterns operate at a finer granularity than styles and are often used inside a style (e.g., using the Saga pattern inside a microservices style).

Key distinction: styles answer “what does the whole system look like?”; patterns answer “how do I solve this specific structural problem here?”


Fundamental Patterns (Anti-Styles and Base Styles)

Big Ball of Mud

The Big Ball of Mud (coined by Brian Foote and Joseph Yoder) describes a system with no discernible architecture — components couple to each other arbitrarily, structure has eroded over time, and change in one place causes unpredictable ripples everywhere. It is arguably the most common architecture in the industry, because systems naturally drift toward it without active governance.

Why it happens:

  • Initial velocity-over-structure decisions that were never revisited
  • Team turnover — tribal knowledge lost
  • Shortcuts that became permanent
  • Absence of fitness functions or architectural tests

Why it is dangerous: high coupling makes any change expensive, testing is difficult, onboarding is slow, and the system resists evolution. The Big Ball of Mud is not a style to choose — it is a failure state to avoid.

Unitary Architecture

A Unitary Architecture is a single, monolithic deployment unit — everything runs in one process on one machine. This is the earliest form of software architecture (think mainframe applications). It is not the same as a layered monolith; it implies a complete absence of logical separation into tiers or layers. Appropriate only for very small, embedded, or single-purpose systems where distribution overhead is unjustifiable.

Client/Server (2-Tier)

The Client/Server style divides a system into exactly two tiers:

+------------------+         +------------------+
|     Client       |  <--->  |     Server       |
| (UI / Frontend)  |  HTTP   | (Logic + Data)   |
+------------------+         +------------------+

The client handles presentation and user interaction; the server handles data storage and (often) business logic. The 2-tier model was dominant in the 1990s (thick-client desktop apps talking directly to a database). Its limitations — tight coupling between presentation and data, poor scalability — drove evolution to 3-tier and n-tier styles.


Architecture Partitioning

Partitioning describes how components within an architecture are grouped and organized. It is one of the most consequential early decisions an architect makes, because it shapes team structure, deployment, coupling, and evolvability.

Technical Partitioning

Components are grouped by their technical role — all UI code lives together, all business logic lives together, all persistence code lives together.

+---------------------------+
|    Presentation Layer     |  (all UI components across all domains)
+---------------------------+
|    Business Logic Layer   |  (all domain logic across all domains)
+---------------------------+
|    Persistence Layer      |  (all data access across all domains)
+---------------------------+
|        Database           |
+---------------------------+
  • Typical in: Layered architecture, MVC frameworks
  • Coupling: Low technical coupling within a layer; high across-layer coupling for a single domain feature
  • Change cost: A new feature (e.g., “add order tracking”) requires changes in every layer
  • Team alignment: Teams organized by technical skill (frontend, backend, DBA)

Domain Partitioning

Components are grouped by business capability — all code for “Orders” (its UI, logic, data) lives together; all code for “Inventory” lives together.

+------------+  +-------------+  +------------------+
|   Orders   |  |  Inventory  |  | User Management  |
|  (UI+BL+DB)|  |  (UI+BL+DB) |  |    (UI+BL+DB)    |
+------------+  +-------------+  +------------------+
  • Typical in: Microservices, modular monolith, service-based architecture
  • Coupling: Low cross-domain coupling; high cohesion within a domain
  • Change cost: A new feature requires changes only within the relevant domain component
  • Team alignment: Cross-functional teams organized by business domain

Comparison Table: Technical vs. Domain Partitioning

DimensionTechnical PartitioningDomain Partitioning
Organization principleTechnical role (UI, BL, Data)Business capability (Order, Inventory)
Typical styleLayered architectureMicroservices, modular monolith
Cross-cutting changeRequires changes in every layerContained within one domain
Team structureSkill-based (frontend/backend)Cross-functional, domain-aligned
Conway’s Law fitGood for siloed technical teamsGood for autonomous product teams
Initial simplicityHigh — easy to understandModerate — requires domain knowledge
Long-term agilityLowHigh
Code duplication riskLow (shared layers)Moderate (each domain may duplicate)
ScalabilityLimited — scale entire layersGood — scale individual domains

Kata: Silicon Sandwiches — Partitioning

Problem: Silicon Sandwiches is a regional sandwich shop chain building a new online ordering system. Should it use technical or domain partitioning?

Analysis:

  • The business has distinct capabilities: Menu Management, Order Placement, Payment Processing, Customer Loyalty, Store Inventory, Delivery Tracking
  • The team is a small startup team with tight budget; they want to ship quickly
  • Future growth may require independent scaling of the Order and Delivery components

Recommendation: Domain partitioning — even if initially built as a modular monolith. The business capabilities map cleanly to domains, enabling future extraction to services without rewriting. Technical partitioning would create horizontal slice friction every time a new menu item type or loyalty feature is added.


Monolithic vs. Distributed Architectures

Monolithic Architectures

A monolith is a system deployed as a single unit, regardless of how its internal code is organized. All components run in the same process and share the same memory space.

  • Architecture quantum = 1 — the entire system is one independently deployable unit
  • Advantages: simple deployment, no network latency within the system, easy local transactions (ACID), straightforward debugging
  • Disadvantages: scaling the whole system when only one part needs scale, slow deployment pipelines as system grows, team coordination overhead in large codebases

Examples of monolithic styles: Layered, Modular Monolith, Pipeline, Microkernel

Distributed Architectures

A distributed architecture decomposes the system into multiple independently deployable units that communicate over a network.

  • Architecture quantum > 1 — multiple independently deployable units
  • Advantages: independent scaling, independent deployment, technology heterogeneity, fault isolation
  • Disadvantages: network becomes a first-class concern (latency, reliability, security), distributed transactions are hard, operational complexity explodes

Examples of distributed styles: Microservices, Event-Driven, Service-Based, Space-Based

Architecture Quantum

An architecture quantum is the smallest independently deployable artifact that has high functional cohesion and high static coupling. In a monolith, quantum = 1. In microservices, quantum = number of services. The quantum concept helps reason about deployment granularity and independent operability.


The 8 Fallacies of Distributed Computing

Originally articulated by Peter Deutsch (and extended by James Gosling) at Sun Microsystems, the 8 Fallacies of Distributed Computing are false assumptions that developers and architects make when building distributed systems. Each fallacy, when violated in production, produces real failures.

Fallacy 1: The Network Is Reliable

The assumption: Calls over the network will succeed.

The reality: Networks drop packets, routers fail, cables are cut, switches reboot. Any network call can and will fail. Services must implement retries (with exponential backoff and jitter), circuit breakers, timeouts, and graceful degradation. Designing distributed systems without handling network failure is designing for failure.

Fallacy 2: Latency Is Zero

The assumption: A remote call costs the same as a local function call.

The reality: Even within a data center, a network round-trip takes microseconds to milliseconds — orders of magnitude slower than in-process calls (nanoseconds). Across data centers or the internet, latency increases dramatically. Architects must measure average latency AND tail latency (p95, p99). Chatty communication patterns (many small calls) that work locally become bottlenecks when distributed. Prefer coarse-grained APIs and data batching in distributed contexts.

Fallacy 3: Bandwidth Is Infinite

The assumption: You can send as much data as you want over the network.

The reality: Bandwidth is finite and shared. Large payloads, high-frequency polling, and naive data replication can saturate links. Architects must consider payload sizes, compression, pagination, event-driven patterns that only send deltas, and careful API design that avoids over-fetching.

Fallacy 4: The Network Is Secure

The assumption: Data sent over the network is safe from interception or tampering.

The reality: Networks are hostile environments. Data in transit can be intercepted, man-in-the-middle attacked, or replayed. Distributed systems require TLS/mTLS for service-to-service communication, proper secret management, zero-trust network design, and threat modeling of all network surfaces. Security cannot be an afterthought in distributed systems.

Fallacy 5: The Topology Never Changes

The assumption: The network configuration — IP addresses, routes, firewall rules — stays constant.

The reality: Cloud environments are ephemeral. VMs are replaced, IPs change, load balancers are reconfigured, services scale in and out. Hardcoding IP addresses or assuming fixed topology causes brittle systems. Solutions: service discovery, DNS-based resolution, service meshes, configuration-as-code for infrastructure. Architects must design for topological change, not against it.

Fallacy 6: There Is Only One Administrator

The assumption: A single person or team controls the entire infrastructure.

The reality: In real enterprises, different teams own different infrastructure layers — network team, cloud team, DBA team, security team, application team. In distributed systems, multiple services may be owned by different teams entirely. Coordination across teams for a deployment, incident, or configuration change is the norm. Architects must account for organizational friction, multi-team ownership, and clear operational contracts between services.

Fallacy 7: Transport Cost Is Zero

The assumption: Sending data over the network has no cost.

The reality: Transport has two costs — (1) the financial cost of bandwidth, especially in cloud environments where egress traffic is metered, and (2) the computational cost of serialization/deserialization (marshalling objects to bytes and back). Both costs are non-trivial at scale. Architects must choose serialization formats (JSON vs. Protobuf vs. Avro) with awareness of payload size and processing overhead.

Fallacy 8: The Network Is Homogeneous

The assumption: All network participants use the same technology, protocol, and data format.

The reality: Modern systems span multiple clouds, on-premise infrastructure, legacy systems, third-party APIs, IoT devices, and mobile clients — each potentially using different protocols, encodings, and capabilities. Architects must design for interoperability: API gateways, protocol translation, schema registries, and defensive parsing that tolerates version differences.


Trade-offs and Decision Framework

OptionProsConsWhen to Choose
Technical partitioningSimple mental model; good tooling support; easy for skill-based teamsCross-cutting features span all layers; low agility over timeSmall teams, simple CRUD-heavy domains, when speed-to-market > long-term agility
Domain partitioningHigh cohesion per domain; teams can work independently; scales wellRequires clear domain boundaries; risk of code duplication; harder initiallyGrowing teams, complex business logic, domains with distinct scaling needs
Monolithic deploymentSimple ops, easy local transactions, cheapSingle point of failure, scales as a unit, coordination overhead at scaleSmall teams, early-stage products, budget/time constrained
Distributed deploymentIndependent scale, deploy, fault isolationNetwork fallacies apply, distributed transactions, operational complexityLarge teams, high scalability needs, domains with very different SLAs

Common Antipatterns

Big Ball of Mud: The absence of any deliberate architecture. Systems drift toward this without active governance (fitness functions, code reviews, architecture decision records). Most dangerous because it feels “fast” in the short term but becomes catastrophic debt.

Unintentional Monolith: Building a “microservices” system where all services share a single database and call each other synchronously — it has distributed system costs with none of the independence benefits.

Accidental Technical Partitioning in Domain-Intended Systems: Starting with the intention of domain partitioning but having each domain contain a presentation class, a business class, and a data class that are not co-located — achieving neither cohesion nor modularity.

Ignoring the Fallacies: Building distributed systems as if they were local — no timeouts, no circuit breakers, synchronous chains of 10 service calls — guaranteeing cascading failures.


Team Topologies and Architecture

Conway’s Law

Conway’s Law (Melvin Conway, 1968): “Organizations which design systems are constrained to produce designs which are a copy of the communication structures of those organizations.”

In practice: if you have separate frontend, backend, and DBA teams, you will naturally produce a layered (technically partitioned) architecture. The team boundaries become the architectural boundaries.

Inverse Conway Maneuver

The Inverse Conway Maneuver flips the causality: instead of letting team structure dictate architecture, deliberately restructure teams to match the desired architecture. If you want a microservices architecture with domain-aligned services, create cross-functional teams aligned to those domains first. The architecture follows.

Team Cognitive Load

Team Topology (Skelton & Pais) introduces the concept of cognitive load — the mental effort required for a team to understand and effectively own their system. Distributed architectures require teams that have a bounded, well-understood domain. Overloading a team with too large a domain (or with infrastructure responsibilities it shouldn’t own) degrades productivity and quality. Architects must design system boundaries with team cognitive load explicitly in mind.

Stream-aligned teams (own a domain end-to-end), platform teams (provide infrastructure as a product), enabling teams (temporary specialist help), and complicated-subsystem teams (own highly specialized components) are the four fundamental types that align with well-partitioned architectures.


Key Takeaways

  1. Architecture Style vs. Pattern: Styles define the whole-system shape; patterns solve recurring local design problems — both are needed but at different granularities.
  2. Big Ball of Mud: The most common real-world architecture — no deliberate structure, high coupling, high debt. It is not chosen; it happens by default without governance.
  3. Technical Partitioning: Organizing by technical role (UI/BL/data) suits skill-based teams but creates cross-cutting change friction as the system grows.
  4. Domain Partitioning: Organizing by business capability suits autonomous cross-functional teams, maximizes cohesion, and enables independent evolution — at the cost of initial complexity.
  5. Architecture Quantum: The smallest independently deployable unit with high cohesion; monoliths have a quantum of 1, distributed systems have quantum > 1.
  6. The 8 Fallacies: Every distributed system architect must internalize that the network is unreliable, has non-zero latency, finite bandwidth, security concerns, changing topology, multiple administrators, non-zero cost, and heterogeneous participants.
  7. Conway’s Law: Team structure and system architecture mirror each other; use the Inverse Conway Maneuver to shape teams toward the target architecture.
  8. Cognitive Load: System partitioning must account for team cognitive load — each team must be able to fully understand and own its domain without being overwhelmed.
  9. Monolith vs. Distributed Trade-off: Distributed systems offer independent scalability and deployment at the cost of operational complexity and exposure to all 8 fallacies; choose deliberately, not by default.
  10. Partitioning is Foundational: The choice between technical and domain partitioning is one of the most consequential early architectural decisions — it shapes team structure, deployment strategy, and long-term agility.

Last Updated: 2026-05-29