Patterns of Practice

The recurring shapes of software, what they cost, and when not to reach for them.

Patterns are the vocabulary of engineering judgment. Once you can name the shape of a problem, you can argue about whether to reach for it. Without the names, you reinvent the same five solutions every year and never learn which one paid back. A working index of patterns at every scope: code, architecture, discipline, plus the anti-patterns worth refusing on purpose.

Every entry names what the pattern costs, not just what it gives you. Every entry says when not to reach for it. The Foundations section anchors the lineage. The Patterns by Category section is the working index. The new shapes emerging with LLM-driven agents live in their own directory now: Patterns for the Age of Agents.

Foundations

The lineage. Books and essays the rest of this directory is in conversation with — some load-bearing today, some worth knowing as the argument behind a pattern, some kept for historical orientation.

The Timeless Way of Building

Tutorial Christopher Alexander · Oxford University Press

Alexander's argument that patterns are the language a living system uses to describe itself — the philosophical root the rest sits on.

A Pattern Language

Tutorial Alexander, Ishikawa, Silverstein · Oxford University Press

253 architectural patterns at every scale; the structural model every software pattern book has imitated since.

Implementation Patterns

Tutorial Kent Beck · Addison-Wesley

Beck on the small daily moves that make code communicate: naming, control flow, classes, methods — the line-level patterns.

Working Effectively with Legacy Code

Tutorial Michael Feathers · Prentice Hall

Feathers on the seam-and-test techniques for changing code you didn't write and don't fully trust — the toolkit of careful change.

Simple Made Easy

Talk Rich Hickey · Strange Loop / InfoQ

Hickey's distinction between simple (one fold) and easy (familiar), and why we keep choosing easy and paying for it later.

Hammock Driven Development

Talk Rich Hickey · Clojure Conj

Hickey on solving by thinking: the case for slowing down before the keyboard and the case against optimizing typing speed.

Life Beyond Distributed Transactions

Discussion Pat Helland · CIDR 2007

Helland's argument that scalable systems must compose around idempotent messages and entities, not global transactions.

Database in Depth

Tutorial C. J. Date · O'Reilly

Date's relational primer, the through-line back to Codd's 1970 paper that still shapes how we think about data shape.

Symmathesy: A Word in Progress

Discussion Nora Bateson

Bateson's coinage for a system that learns together with its parts — Jessica Kerr's frame for living software teams.

Hints for Computer System Design

Best Practices Butler Lampson · ACM

Lampson's 1983 pattern-shaped collection of design hints — separation of concerns, end-to-end principle, get it working first.

How to Solve It

Tutorial George Pólya · Princeton University Press

Pólya's 1945 method for problem-solving — understand the problem, plan, execute, review — the meta-pattern under every pattern below.

Patterns by Category

Patterns grouped by where they live in the system. Each category intro names the scope. Click a pattern name for its canonical reference, then read the per-pattern resources below for what it costs and when not to use it.

Code Patterns

Composition & Construction

Code Patterns. How objects and modules come together. Builder, Fluent Interface, Dependency Injection, Factory variants, and Newtype — the moves that decide whether a system feels assembled or merely concatenated. Useful when construction logic is obscuring the thing being constructed.

  • Builder Step-by-step construction of a complex object that separates the recipe from the result.
  • Fluent Interface Method chaining that reads like a sentence describing the operation rather than commanding it.
  • Dependency Injection Hand a component its collaborators instead of letting it build them, so its seams are visible.
  • Factory Variants Replace a constructor with a function that names the variant being made and hides the constructor's noise.
  • Newtype Wrap a primitive in a single-field type so the type system can stop you from mixing UserId and OrderId.

FluentInterface

Discussion Martin Fowler

Fowler's bliki entry on chained methods that read like a sentence — the canonical naming of the pattern.

Builder Pattern

Tutorial refactoring.guru

Step-by-step explanation of Builder with structural diagrams and language-specific examples.

Dependency Injection Demystified

Discussion James Shore

Shore's short, plain-language piece that strips DI down to what it actually is — handing collaborators in, by name.

Factory Method Pattern

Tutorial refactoring.guru

Walkthrough of Factory Method vs. Abstract Factory with code in multiple languages.

New Type Idiom

Tutorial Rust by Example

Rust's canonical demonstration of wrapping a primitive in a tuple struct to gain compile-time distinction.

Parse, don't validate

Discussion Alexis King

King's foundational essay: lift validation to the type level so invalid states cannot be represented.

Control Flow

Code Patterns. How the next step is chosen. Strategy, Command, Pipeline/Chain of Responsibility, Middleware, Visitor, and State Machines turn nested conditionals into named operations. Reach for them when the if-tree has grown its own gravitational pull.

  • Strategy Swap an algorithm at runtime by hiding the family of behaviors behind a single interface.
  • Command Wrap an operation as an object so it can be queued, logged, undone, or shipped across a network.
  • Pipeline / Chain of Responsibility Hand a request down a sequence of handlers until one accepts it, instead of branching on type.
  • Middleware Compose request-handling concerns as a stack of functions that each get a turn before and after the next.
  • Visitor Separate an operation from the data structure it walks, so new operations don't perturb the structure.
  • State Machines Make legal states and transitions explicit, so impossible states stop being a defensive-coding problem.

Strategy Pattern

Tutorial refactoring.guru

Diagrammed walkthrough of swappable algorithms behind a single interface, with multi-language examples.

Command Pattern

Tutorial refactoring.guru

Encapsulating a request as an object so it can be parameterized, queued, logged, and undone.

DecoratedCommand

Discussion Martin Fowler

Fowler on stacking concerns (logging, auth, retry) onto Command objects via decoration.

Pipeline pattern in Go

Tutorial Go Blog

The Go team's reference text on composing concurrent stages with channels, including fan-out and cancellation.

Using Express middleware

Tutorial Express docs

Canonical worked example of a middleware stack: each function gets next(), runs code before and after, composes.

Architecture: Middleware

Tutorial Django docs

Django's framework-side view of middleware as ordered request/response hooks with explicit lifecycle.

Visitor Pattern

Tutorial refactoring.guru

Double-dispatch walkthrough of separating an operation from the data structure it traverses.

The Expression Problem

Discussion Philip Wadler

Wadler's framing of the design tension Visitor addresses — adding cases vs. adding operations.

Statecharts.dev

Tutorial statecharts.dev

Living catalog of statechart concepts with examples, used by XState and other practical libraries.

Boundaries & Abstraction

Code Patterns. Where one model ends and another begins. Adapter, Facade, Anti-Corruption Layer, Ports and Adapters, and Repository are the load-bearing options for keeping a clean core from being infected by whatever shape the outside world arrived in.

  • Adapter Translate between an interface your code wants and one that an existing component provides.
  • Facade Put a simple front door on a complicated subsystem so callers don't pay for everything inside.
  • Anti-Corruption Layer Translate between bounded contexts so a foreign model can't quietly contaminate yours.
  • Ports and Adapters Talk to the outside world through narrow interfaces (ports) implemented by swappable adapters.
  • Repository Hide persistence behind a collection-like interface so domain code can pretend storage doesn't exist.

Gateway

Discussion Martin Fowler

Fowler's PoEAA catalog entry for the gateway role — the architectural sibling of the Adapter pattern.

Façade Pattern

Tutorial refactoring.guru

Walkthrough of presenting a single, simpler interface in front of a tangled subsystem.

Anti-Corruption Layer pattern

Best Practices Microsoft Learn

Microsoft's pattern catalog entry: when to insert a translation layer between legacy and new bounded contexts.

Hexagonal Architecture

Discussion Alistair Cockburn

Cockburn's original Hexagonal Architecture essay — the source paper for Ports and Adapters.

Repository

Discussion Martin Fowler · PoEAA

Fowler's PoEAA catalog entry: a collection-like interface mediating between the domain and the data mapping layer.

Error Handling & Resilience

Code Patterns. How failure is named and recovered from at the function and module level. Result/Either, errors-as-values, Retry with Backoff, and code-level Circuit Breaker and Bulkhead are about making partial failure a thing the program can reason about instead of a thing that escapes upward.

  • Result / Either Return success or a typed error so callers must acknowledge failure instead of inheriting an exception.
  • Errors as Values Treat failures as ordinary return values, making error flow as legible as success flow.
  • Retry with Backoff Re-attempt a failed call with exponentially growing delays and jitter so a thundering herd doesn't form.
  • Circuit Breaker (code-level) Stop calling a dependency that's clearly broken, fail fast for a window, then probe before reopening.
  • Bulkhead (code-level) Partition resources so a runaway caller can drain its own pool without sinking everything else.

std::result — Result type

Tutorial Rust std docs

Rust's reference treatment of Result<T, E> — the canonical typed-error API in mainstream programming.

Railway Oriented Programming

Tutorial Scott Wlaschin · F# for Fun and Profit

Wlaschin's diagrams-and-prose argument for chaining Result-returning functions — the strongest accessible essay on the model.

Error handling and Go

Discussion Go Blog

The Go team's defense of returning errors as values — the foundational case for the style outside Haskell/ML.

Errors are values

Discussion Rob Pike · Go Blog

Pike's follow-up post on actually using error values as ordinary data, not as a try/catch substitute.

Exponential Backoff And Jitter

Tutorial AWS Architecture Blog

Simulator-driven walkthrough of full jitter vs. decorrelated jitter and why naive exponential backoff isn't enough.

CircuitBreaker

Discussion Martin Fowler · bliki

Fowler's bliki entry codifying Michael Nygard's circuit breaker into the cross-language pattern vocabulary.

Release It! Second Edition

Tutorial Michael T. Nygard · Pragmatic Bookshelf

The original source for Circuit Breaker, Bulkhead, and most operational resilience patterns now in common use.

Bulkhead pattern

Best Practices Microsoft Learn

Microsoft's pattern catalog entry on isolating workloads so one runaway can't sink the others.

Concurrency

Code Patterns. How parallel work is structured and survived. Actor model, Producer/Consumer, Fan-out/Fan-in, Supervisor Trees, and the Borrow-checker discipline are the patterns that turn concurrency from a bug source into a working assumption.

  • Actor Model Independent units of state and behavior that communicate only by messages, never by shared memory.
  • Producer / Consumer Decouple work generation from work execution with a queue, so each side can scale on its own pace.
  • Fan-out / Fan-in Split a job across many parallel workers and merge their results back into a single ordered stream.
  • Supervisor Trees Organize processes into a tree where parents restart failing children, letting one die to keep the rest alive.
  • Borrow Checker as Pattern Encode ownership and aliasing in the type system so concurrent access becomes a compile-time error.

Pipeline pattern in Go

Tutorial Go Blog

The Go team's reference text on composing concurrent stages with channels, including fan-out and cancellation.

The Actor Model in 10 Minutes

Tutorial Brian Storti

Compact introduction to actors, mailboxes, and supervision — the lightest accessible primer in print.

Erlang/OTP Design Principles

Tutorial Erlang docs

The canonical reference for actors and supervision trees — what every later actor framework is reimplementing.

Channels in Go

Tutorial Go by Example

Hello-world treatment of channels as queues between producer and consumer goroutines.

Supervision Principles

Tutorial Erlang docs

Erlang's documentation of supervisor strategies (one_for_one, rest_for_one, etc.) — the source of the vocabulary.

References and Borrowing

Tutorial The Rust Programming Language

The reference chapter on Rust's ownership and borrowing rules — the move that turned data races into compile errors.

Fearless Concurrency

Tutorial The Rust Programming Language

How Send/Sync and the borrow checker compose into the 'fearless concurrency' guarantee Rust advertises.

Architecture Patterns

Data & State

Architecture Patterns. How a system holds memory and tells the truth about it. Event Sourcing, CQRS, Outbox, Saga, Materialized Views, and OLTP/OLAP separation are the moves that decide whether your data model can evolve once it has users.

  • Event Sourcing Persist the sequence of events that produced state instead of just the latest state.
  • CQRS Split the read model from the write model so each can be optimized for its own access pattern.
  • Outbox Pattern Write the event into the same transaction as the state change, then ship it from the table later.
  • Saga Coordinate a long-running transaction as a sequence of local steps with compensations instead of a global commit.
  • Materialized Views Precompute the result of an expensive query and refresh it on a schedule or on demand.
  • OLTP / OLAP Separation Run transactions and analytics in different stores, replicating between them, so neither starves the other.

Event Sourcing

Discussion Martin Fowler

Fowler's foundational essay defining event sourcing as the persistence model for the audit-as-truth approach.

CQRS

Discussion Martin Fowler

Fowler's bliki entry — the warning label as much as the definition, naming when CQRS is a load-bearing choice.

CQRS Documents

Discussion Greg Young

Young's original collected writings on CQRS — the source the rest of the literature footnotes.

Pattern: Transactional outbox

Best Practices microservices.io

Richardson's canonical catalog entry: write the event in the same DB transaction, then relay it.

Pattern: Saga

Best Practices microservices.io

Richardson on coordinating long-running cross-service transactions with local steps and compensations.

Sagas

Discussion Garcia-Molina & Salem · 1987

The original 1987 paper introducing the Saga as a model for long-lived transactions.

Materialized Views

Tutorial PostgreSQL docs

Postgres reference for declaring, populating, and refreshing materialized views — the no-frills mechanism reference.

OLTP vs. OLAP

Discussion Snowflake

Clear vendor-side primer on transactional vs. analytical workloads and why they want different stores.

Messaging & Coordination

Architecture Patterns. How services agree on what happened. Request/Response, Work Queues, Dead Letter Queues, Idempotency Keys, and Choreography vs. Orchestration are the wiring decisions behind any system that crosses a network and still needs to be reasoned about.

  • Request / Response The synchronous backbone of distributed systems: send a message, block until the answer arrives.
  • Work Queues Decouple producers from consumers with a queue and competing-consumer workers, so load and rate are separate.
  • Dead Letter Queue Move messages that keep failing into a side queue so the main queue keeps draining and you can investigate later.
  • Idempotency Keys Let callers safely retry by tagging each attempt with a key the server uses to deduplicate effects.
  • Choreography vs. Orchestration Decide whether services react to events on their own (choreography) or follow a conductor (orchestration).

Pattern: Saga

Best Practices microservices.io

Richardson on coordinating long-running cross-service transactions with local steps and compensations.

Request-Reply

Discussion Hohpe & Woolf · Enterprise Integration Patterns

The canonical EIP catalog entry — synchronous request/response in messaging terms, including correlation IDs.

Work Queues

Tutorial RabbitMQ docs

Reference tutorial on competing-consumer worker pools backed by a durable queue.

API Idempotency

Best Practices Stripe API docs

Stripe's public API documentation on idempotency keys — the de facto reference clients are built against.

Choreography vs Orchestration

Best Practices microservices.io

Richardson's framing of the two saga coordination styles, the trade-offs, and when each one collapses under load.

Topology

Architecture Patterns. The shape of the deployment. Monolith, Microservices, Modular Monolith, Backends for Frontends, Strangler Fig boundary, Service Mesh, and Sidecar are about where the seams between teams and runtimes actually live.

  • Monolith One deployable for the whole system; the default that earns its critics only at certain sizes of team and traffic.
  • Microservices Independently deployable services drawn around team boundaries, paid for with operational overhead.
  • Modular Monolith One deployable, hard module boundaries inside it: the alternative most teams should try before splitting.
  • Backends for Frontends A thin per-client backend that shapes APIs for one frontend instead of forcing one API to serve all.
  • Strangler Fig (boundary tactic) Wrap the old system behind a façade and grow the new one inside it until the old can be deleted.
  • Service Mesh Move retries, mTLS, and routing into a sidecar layer so application code stops re-implementing them per service.
  • Sidecar Run a helper process next to your service to add capabilities (proxying, telemetry) without changing the service.

MonolithFirst

Discussion Martin Fowler

Fowler's case for starting with a monolith and only splitting once the domain has been understood.

Microservices

Discussion Lewis & Fowler

The 2014 article that named and characterized the style — still the most-cited definitional reference.

Modular Monolith: A Primer

Tutorial Kamil Grzybek

Grzybek's canonical primer with worked example showing module boundaries enforced inside one deployable.

StranglerFigApplication

Discussion Martin Fowler

Fowler's bliki entry naming the pattern after Alexander's strangler fig — wrap, replace, delete.

What is Istio?

Discussion Istio docs

Istio's own framing of the service-mesh problem and how a control plane plus sidecars solve it.

Linkerd Overview

Tutorial Linkerd docs

Linkerd's overview — the lighter, Rust-based alternative to Istio with the same shape.

Sidecar pattern

Best Practices Microsoft Learn

Microsoft's catalog entry on the sidecar deployment pattern, with concrete examples and trade-offs.

Resilience at Scale

Architecture Patterns. How a system bends without breaking when things go sideways. Bulkhead between services, Circuit Breaker across services, Back-pressure, Load Shedding, and Graceful Degradation are the moves that turn partial failure into a user-acceptable outcome.

  • Bulkhead (service-level) Isolate workloads across deployments or pools so one tenant or workload can't sink the others.
  • Circuit Breaker (between services) Stop sending traffic to a downstream that's clearly hurting, then probe before declaring it healthy again.
  • Back-pressure Tell upstream callers to slow down when you're full, instead of silently absorbing or dropping.
  • Load Shedding Drop or reject low-priority work near capacity so the critical path stays inside its latency budget.
  • Graceful Degradation Decide in advance what features get turned off when dependencies fail, so 'works' has a defined floor.

CircuitBreaker

Discussion Martin Fowler · bliki

Fowler's bliki entry codifying Michael Nygard's circuit breaker into the cross-language pattern vocabulary.

Release It! Second Edition

Tutorial Michael T. Nygard · Pragmatic Bookshelf

The original source for Circuit Breaker, Bulkhead, and most operational resilience patterns now in common use.

Bulkhead pattern

Best Practices Microsoft Learn

Microsoft's pattern catalog entry on isolating workloads so one runaway can't sink the others.

Bulkhead architectures

Best Practices AWS Well-Architected Framework

AWS Well-Architected guidance on partitioning so a failure in one cell doesn't take down the others.

Cell-based Architecture

Best Practices AWS Well-Architected Framework

AWS's whitepaper on cell-based architecture — the scaled version of the bulkhead pattern at AWS itself.

Circuit Breaker pattern

Best Practices Microsoft Learn

Microsoft's reference for circuit breaker at the service level, with state diagram and trade-offs.

Reactive Manifesto: Back-Pressure

Discussion Reactive Manifesto

The reactive-systems glossary's definition of back-pressure — the place the term entered the working vocabulary.

Handling overload

Best Practices David Yanacek · AWS Builders' Library

Yanacek on load shedding: pick what to drop near capacity so the critical path stays inside its budget.

Evolution & Migration

Architecture Patterns. How a system changes shape without stopping. Strangler Fig at the system level, Expand/Contract Schema, Parallel Run, Dark Launches, and Feature Flags as architecture are the patterns of taking a running system from one shape to a better one without an outage.

  • Strangler Fig (system migration) Replace a legacy system incrementally by routing traffic to the new implementation feature by feature.
  • Expand / Contract Schema Add the new shape, dual-write, migrate readers, then remove the old shape — never with all four at once.
  • Parallel Run Run the old and new implementations side by side against real traffic until results agree, then switch.
  • Dark Launches Ship the new code into production behind a flag and exercise it with real traffic before any user sees it.
  • Feature Flags (as architecture) Use long-lived flags to keep architectural choices reversible, not just to gate user-visible features.

StranglerFigApplication

Discussion Martin Fowler

Fowler's bliki entry naming the pattern after Alexander's strangler fig — wrap, replace, delete.

Evolutionary Database Design

Discussion Sadalage & Fowler

Sadalage and Fowler's foundational article on evolving schemas alongside code via expand/contract.

Refactoring Databases

Tutorial Scott Ambler & Pramod Sadalage

Companion catalog to the Refactoring Databases book — concrete database-level refactorings with steps.

ParallelChange

Discussion Danilo Sato (on Fowler's bliki)

The definitional entry: expand, migrate, contract — making breaking changes a three-step backward-compatible process.

Feature Toggles (aka Feature Flags)

Tutorial Pete Hodgson · Fowler's site

Hodgson's reference taxonomy — release, ops, experiment, and permission toggles, and how their lifetimes differ.

Patterns of Discipline

Change Patterns

Patterns of Discipline. How big changes ship in small, reversible steps. Branch by Abstraction, Expand/Contract Schema+API, Parallel Change, and Feature Toggles are about keeping main shippable while a multi-week refactor or migration is in flight.

  • Branch by Abstraction Hide the thing being replaced behind an interface, swap implementations behind it, then collapse the seam.
  • Expand / Contract (Schema & API) A discipline for changing schemas and APIs without downtime: add the new shape, migrate, then remove the old.
  • Parallel Change Make a breaking change in three steps — expand, migrate callers, contract — so the tree always compiles.
  • Feature Toggles (as discipline) Keep work-in-progress in main behind toggles, separating deploy from release and shortening branch lifetimes.

Evolutionary Database Design

Discussion Sadalage & Fowler

Sadalage and Fowler's foundational article on evolving schemas alongside code via expand/contract.

Refactoring Databases

Tutorial Scott Ambler & Pramod Sadalage

Companion catalog to the Refactoring Databases book — concrete database-level refactorings with steps.

ParallelChange

Discussion Danilo Sato (on Fowler's bliki)

The definitional entry: expand, migrate, contract — making breaking changes a three-step backward-compatible process.

Feature Toggles (aka Feature Flags)

Tutorial Pete Hodgson · Fowler's site

Hodgson's reference taxonomy — release, ops, experiment, and permission toggles, and how their lifetimes differ.

BranchByAbstraction

Discussion Paul Hammant (on Fowler's bliki)

The bliki entry codifying the technique — hide what's being replaced, swap, then collapse the seam.

Continuous Delivery

Tutorial Humble & Farley · Addison-Wesley

The book that put trunk-based development, feature toggles, and branch by abstraction into the mainstream.

Expand and Contract

Tutorial Tim Evans

Working-engineer walkthrough of the discipline as a three-step ritual for schema and API changes.

API Versioning at Stripe

Discussion Brandur Leach · Stripe

Stripe's approach to additive API versioning and deprecation windows — the API-layer expression of expand/contract.

Feature Toggles in Practice

Best Practices Split.io blog

Working-engineer guide to keeping flags healthy in production: ownership, retirement, and limits.

Review & Verification

Patterns of Discipline. How a team agrees the work is done. Review-as-Conversation, Characterization Tests, Golden/Snapshot tests, Property-Based Testing, and Mutation Testing are about raising the floor of trust without lengthening the queue.

  • Review-as-Conversation vs. Review-as-Gate Treat review as the moment a second engineer understands the change, not as the moment correctness is decided.
  • Characterization Tests Pin down the actual behavior of legacy code with tests before you change anything, so a regression is detectable.
  • Golden / Snapshot Tests Record the current output as truth and fail when it changes, useful when the spec is 'whatever it does today.'
  • Property-Based Testing State invariants and let the runner generate inputs to break them, instead of guessing the edge cases yourself.
  • Mutation Testing Modify the program in small ways and check that some test fails, measuring how much your suite actually catches.

Code Review Developer Guide

Best Practices Google Engineering Practices

Google's published guidance on review as a fast, collaborative pass that's primarily about understanding.

On Being a Senior Engineer

Discussion Dan Slimmon

Slimmon on the reviewer's job as shared understanding, not gatekeeping — the texture beneath 'review-as-conversation.'

Snapshot Testing

Tutorial Jest docs

Jest's documentation — the working-engineer reference for snapshot tests in mainstream JavaScript projects.

Approval Testing

Tutorial ApprovalTests.com

Cross-language site for approval/golden testing as a refactoring scaffold — the form Emily Bache popularized.

What is Property Based Testing?

Tutorial Hypothesis blog

Hypothesis project's working-engineer essay on what property-based testing actually is and why it pays off.

Property Testing Like AFL

Discussion Hillel Wayne

Wayne on PBT as a design tool — writing the property is the work that pays off whether or not a bug is caught.

Operational Patterns

Patterns of Discipline. How a team keeps the running system trustworthy. Runbooks as Code, the Four Golden Signals, Error Budgets, Blameless Postmortems, and On-Call as Pattern are the small habits that compound into operational excellence.

  • Runbooks as Code Version, review, and execute runbooks alongside the code they describe, so they age with the system.
  • Four Golden Signals Latency, traffic, errors, and saturation: the minimum monitoring vocabulary every service should publish.
  • Error Budgets Turn 'how reliable' into a budget the team spends on changes versus burns on outages, with a written policy.
  • Blameless Postmortems Investigate incidents by asking how each action made sense to the operator in the moment, then fix the system.
  • On-Call as Pattern Treat the rotation, alert quality, and follow-up as the artifact, not just the schedule of who's paged.

Runbook Template

Tutorial Skelton & Thatcher

Skelton & Thatcher's open-source runbook template — the working starting point for codifying ops knowledge.

Monitoring Distributed Systems

Best Practices Google · SRE book

The chapter that introduced 'four golden signals' as the minimum monitoring vocabulary for any service.

Implementing SLOs

Tutorial Google · SRE workbook

The canonical step-by-step for defining SLIs, SLOs, and burn-rate alerts that translate into error budgets.

Error Budget Policies

Best Practices Google · SRE workbook

The follow-up chapter — what to actually do when the budget is gone, written as a policy template.

Being On-Call

Best Practices Google · SRE book

The SRE book chapter on on-call as a designed practice — page quality, rotations, and follow-up as artifacts.

Distributed Systems Observability

Discussion Cindy Sridharan · O'Reilly

Sridharan's working-engineer treatment of what good observability buys an on-call rotation: alerts you can act on.

PagerDuty Incident Response

Best Practices PagerDuty

PagerDuty's open-source incident-response training — IC roles, communications, and handoff as a working artifact.

Anti-Patterns

Anti-Patterns

Anti-Patterns. The shapes worth naming so you can refuse them. Each entry below is something that solved a real problem at first and then quietly went toxic. Recognizing the shape is the whole point — the cure is usually one of the patterns above.

  • Distributed Monolith Microservices that must be deployed together: you've paid the cost of distribution and kept the coupling of a monolith.
  • God Object One class that knows everything and is touched by every change — the gravitational center the rest of the system orbits.
  • Primitive Obsession Modeling domain concepts with bare strings, ints, and dicts so the type system can't help catch a misuse.
  • Anemic Domain Model Domain objects with no behavior, just getters and setters, with business logic scattered across service classes instead.
  • Microservices Too Early Drawing service boundaries before you know the domain, locking in coupling that later proves expensive to move.
  • Premature Abstraction Pulling out an interface before the second concrete case exists, freezing a guess as if it were a constraint.
  • DRY at All Costs Deduplicating code that only looks alike, gluing unrelated concepts together so changes in one place break the other.
  • Configuration-Driven Development A homegrown DSL in YAML or JSON that grows control flow until it's a language with no compiler, debugger, or tests.
  • Big Ball of Mud The system shape that emerges when no shape is enforced: tangled, unstructured, and somehow still in production.
  • Singleton-as-Global-State Hidden shared mutable state dressed up as a design pattern, so dependencies stop showing up in signatures.
  • Stringly-Typed Code Encoding meaning into strings the compiler can't see, so misspellings and confusions only show up at runtime.
  • Speculative Generality Hooks, parameters, and indirection added for a case that never arrives, paid for in confusion by every reader since.

MonolithFirst

Discussion Martin Fowler

Fowler's case for starting with a monolith and only splitting once the domain has been understood.

Microservices

Discussion Lewis & Fowler

The original article — read with hindsight, contains the warnings about premature service boundaries baked in.

God Class

Discussion WikiWikiWeb / c2.com

The original portland-pattern-repository entry naming the anti-pattern of one omniscient class.

Primitive Obsession

Tutorial refactoring.guru

Smell catalog entry on modeling domain concepts with raw primitives, with refactoring moves to escape it.

AnemicDomainModel

Discussion Martin Fowler

Fowler's bliki entry naming the anti-pattern: domain objects reduced to data bags with logic scattered into services.

The Wrong Abstraction

Discussion Sandi Metz

Metz's essay: duplication is far cheaper than the wrong abstraction — the working-engineer answer to over-DRY.

DRY is about Knowledge

Discussion Mathias Verraes

Verraes restating DRY in terms of knowledge — the case that 'two pieces of code look alike' isn't a reason to merge them.

Code is Data

Discussion Ned Batchelder

Batchelder's essay arguing that 'just config' is just code without the tooling that makes code maintainable.

Big Ball of Mud

Discussion Foote & Yoder

The 1997 paper that named the most common production architecture — emergent, unstructured, somehow still shipping.

Singletons are Evil

Discussion WikiWikiWeb / c2.com

Long-running c2 wiki thread cataloguing why singletons end up being global state by another name.

Stringly Typed

Discussion WikiWikiWeb / c2.com

The naming of the anti-pattern: encoding meaning into strings the compiler can't see — joke and warning at once.

Speculative Generality

Tutorial refactoring.guru

Smell catalog entry — hooks and indirection added 'just in case' that arrives only as confusion for later readers.

Creators to follow

Writers consistently publishing substantive material on patterns, design, and the discipline of software. The bench this directory leans on.

Martin Fowler blog · @martinfowler The reference voice on enterprise patterns, refactoring, and the bliki that names half this directory. Marc Brooker blog · @MarcJBrooker AWS distinguished engineer. The canonical working-voice on retries, jitter, queues, and resilience trade-offs. Brandur Leach blog · @brandur Ex-Stripe engineer writing concrete walkthroughs of idempotency, API versioning, and database-shaped reliability. Pete Hodgson blog · @ph1 Independent consultant; author of the canonical feature toggles taxonomy and writer on incremental change. Jessica Kerr blog · @jessitron Systems-thinker and Honeycomb dev advocate. Symmathesy, socio-technical patterns, and code-as-conversation. Hillel Wayne blog · @hillelogram Formal-methods working engineer writing accessibly about TLA+, property testing, and types-as-fences. Will Larson blog · @lethain Engineering leader writing concrete frameworks for tech-debt strategy, on-call, and platform investment. Sam Newman blog · @samnewman Author of Building Microservices and Monolith to Microservices; the working reference on service boundaries. Cindy Sridharan blog · @copyconstruct Distributed-systems and observability writing; essays on testing in production and reliability patterns. Pat Helland blog · @phelland Amazon Distinguished Engineer; canonical papers on data-on-the-outside, distributed transactions, and idempotency. Michael Feathers blog · @mfeathers Author of Working Effectively with Legacy Code; the working-engineer voice on safe change in untrusted code. Kent Beck blog · @KentBeck Author of Implementation Patterns and XP. Writing now at Tidy First on small structural moves that compound.

Frequently Asked Questions

Short answers to the questions that recur about how to read this directory and how to use patterns honestly.

How do I choose a pattern instead of writing one from scratch?

The honest version: read the catalog before you start, then ignore it while you write the obvious solution, then come back when the obvious solution starts to hurt. Patterns are most useful as names for a shape you've already drawn at least once — they shorten the next conversation about it, they don't replace the first attempt. Fowler's Patterns of Enterprise Application Architecture is the best 'read once, refer back forever' starting place.

Source: Martin Fowler: Patterns of Enterprise Application Architecture

When is a 'microservice' actually a distributed monolith in disguise?

When changing one service requires deploying others in lockstep, you're paying the operational cost of distribution and keeping the coupling of a monolith. The diagnostic: if every release ships more than one service, or if your release notes are organized by 'changes in services A, B, and C this week,' the seams are wrong. Fowler's MonolithFirst remains the cleanest argument for delaying the split until you've actually learned where the boundaries are.

Source: Martin Fowler: MonolithFirst

How do I migrate a schema without an outage?

Expand and contract: add the new shape, dual-write to both, migrate readers, then remove the old. Each step is a deploy in its own right; you never do more than one shape-changing step at a time. The same dance applies to APIs (parallel change) and to system-level rewrites (strangler fig). Sadalage and Fowler's evolutionary database design essay is the reference, and Tim Evans' walkthrough is the cleanest working-engineer post on the discipline.

Source: Evolutionary Database Design (Sadalage & Fowler)

Are feature flags worth the complexity they add?

If you treat them as code with a lifecycle, yes; if you treat them as runtime configuration with no expiry, no. The flags that pay off are short-lived release toggles that come out within a release or two, and a small handful of long-lived ops toggles that you actually exercise. Pete Hodgson's reference taxonomy separates the four kinds and is the right place to start. The anti-pattern is a flag graveyard where nobody knows which branches are live in production.

Source: Pete Hodgson: Feature Toggles

When should I reach for property-based testing instead of examples?

When you can state an invariant — a sentence of the form 'for any input that looks like X, the output must satisfy Y' — and the cost of finding the edge cases yourself is too high. PBT is especially good for parsers, serializers, and pure functions on domain types; less good when the function's behavior is irreducibly example-shaped. The Hypothesis project's intro essay is the working-engineer entry point, and Wlaschin's railway oriented programming pieces compose well with it.

Source: What is Property Based Testing?

Why does refactoring legacy code keep producing regressions?

Because you're changing behavior without a harness, and you don't yet have a definition of what 'unchanged' means. The answer Michael Feathers gave twenty years ago still holds: characterize the current behavior with tests before you change anything, even when those tests pin down behavior nobody likes. Then change the system in seams the tests cover. The Working Effectively with Legacy Code chapters on characterization tests and seams are the canonical reference.

Source: Working Effectively with Legacy Code

Where does an anti-pattern stop being a smell and start being a crisis?

When the cost of moving away from it exceeds the cost of anything else you'd do this quarter, and when each new feature is paying interest on the same structural debt. Anti-patterns rarely cause incidents; they cause slowdown that's invisible until you compare your delivery cadence to a peer team's. The Big Ball of Mud paper is the most honest description of how the shape arrives — by no decision, by every decision being local and time-pressured. The cure is always a sequence of small, named patterns above, applied with patience.

Source: Foote & Yoder: Big Ball of Mud

How do I structure a codebase so an agent can be useful in it?

Three things compound: naming that an agent's index can rely on, modules small enough to fit in a context window, and a machine-readable file (AGENTS.md is the emerging convention) that tells the agent the conventions, commands, and tests it should respect. The verification layer matters as much — property tests, snapshot tests, and type checks become the fences an agent must clear before merge. None of this is specific to agents; agents just punish the codebases that didn't already do it.

Source: AGENTS.md

From Smarter Dev

Original writing coming.

Smarter Dev essays, walkthroughs, and short courses on naming the shapes you're already working with — and arguing about whether to reach for them — will land here as they're written.

Join the Discord to be notified

Last updated