Topic domain
Software Architecture
Structure, boundaries, and the cost of coupling.
- Articles
- 80
- Clusters
- 8
- Foundational
- 24
- Intermediate
- 31
- Advanced
- 25
Modularity
10Cohesion, coupling, and information hiding.
- Coupling and Cohesion as Independent Structural Axes
- Information Hiding and the Parnas Decomposition Criterion
- Interface Contracts and the Limits of Substitutability
- Cycles in Module Dependency Graphs and How to Break Them
- Package Encapsulation and the Leak of Internal Types
- Instability, Abstractness, and the Main Sequence Metric
Layered, event-driven, and plugin designs.
- Layered Architecture and the Cost of Strict Layer Isolation
- Ports and Adapters and the Direction of the Dependency Arrow
- Event Notification and Event-Carried State Transfer Compared
- Microkernel Architecture and the Stability of Plugin Extension Points
- Pipes and Filters and the Contract Between Stages
- CQRS and the Consistency Window Between Writes and Read Models
API Design
10Contracts, evolution, and compatibility.
- Where an API Contract Ends and the Implementation Begins
- Idempotency Keys and the Retry Window for Writes
- Pagination Contracts and Why Cursors Drift Less Than Offsets
- Versioning Strategies and What a Version Number Promises
- Tolerant Readers, Unknown Fields, and the Cost of Strict Decoding
- Deprecation Windows and the Gates That Must Close Before Removal
Boundaries, invariants, and ubiquitous language.
- Value Objects and Entities: Deciding What Has Identity
- Invariants and Illegal States: Making Invalid Combinations Unrepresentable
- Ubiquitous Language: Keeping One Term for One Concept in Code
- Aggregate Boundaries and Transaction Scope
- Bounded Contexts and the Cost of a Shared Model
- Domain Events: Publishing State Transitions Without Losing Them
Service boundaries and failure domains.
- Availability Multiplication in Synchronous Service Graphs
- Drawing Service Boundaries Around Consistency Requirements
- Blast Radius and Cell-Based Isolation
- Temporal Coupling Between Services
- Idempotency Keys and Duplicate Suppression at Service Boundaries
- The Dual-Write Problem and the Transactional Outbox
Tradeoff analysis and fitness functions.
- Quality-Attribute Scenarios as the Unit of Architectural Evaluation
- Dependency Structure Matrices and the Cost of a Cycle
- Instability, Abstractness, and Distance from the Main Sequence
- Fitness Functions as Build-Time Architectural Constraints
- Utility Trees, Sensitivity Points, and Tradeoff Points
- How Deep to Evaluate: Analysis Cost Against Rework Cost
Interest, principal, and repayment strategy.
- Principal, Interest, and Upkeep in the Technical Debt Model
- Change Amplification: How Coupling Sets the Price of an Edit
- Divergent Duplicates and the Cost of Two Truths
- Measuring Debt Without Inventing Numbers
- Feedback Latency as Compounding Interest
- Compatibility Promises as Borrowed Time
Strangler patterns and incremental replacement.
- Finding Seams in Legacy Code That Was Never Built to Have Them
- Mapping Runtime Dependencies from Traffic and Query Logs
- Characterization Tests: Pinning Behaviour Nobody Designed
- Routing Requests Between Old and New with a Strangler Facade
- Anti-Corruption Layers and the Cost of Model Translation
- Dual Writes and the Divergence They Inevitably Produce
All Software Architecture articles
- Oct 9, 2026 Availability Multiplication in Synchronous Service Graphs Why end-to-end availability is the product of every dependency on the request path, how fan-out changes that product, and which edges can be removed or made optional.
- Sep 30, 2026 Error Contracts: Problem Details, Stable Codes, and Retry Semantics How to design an error payload that machines can branch on and humans can act on, and why retryability belongs in the contract rather than in the status code alone.
- Sep 20, 2026 Aggregate Boundaries and Transaction Scope How to decide what loads and changes together in one transaction, why object references across those boundaries cause trouble, and how conflicts are detected.
- Sep 7, 2026 Schema Evolution and Wire Compatibility Across Formats Why a field number rather than a name is a message field identity, how wire types constrain which retyping is safe, and how Avro resolution differs from Protobuf evolution.
- Sep 3, 2026 Sequencing Repayment Under a Fixed Capacity With more debt than capacity, the order of repayment determines the total benefit. Ranking by interest eliminated per week of work, subject to deadlines and prerequisites.
- Aug 30, 2026 Dependency Structure Matrices and the Cost of a Cycle How a square matrix over modules exposes layering and reachability at a glance, how partitioning recovers a build order, and what a cycle costs once it is found.
- Aug 22, 2026 Temporal Coupling Between Services What a synchronous call forces on two services, how message passing changes the coupling without removing it, and where each style breaks under load.
- Aug 8, 2026 Modeling Validity Over Time and Retroactive Correction Separating the time a fact was true from the time the system learned it, and the interval and constraint mechanics that keep an as-of query honest.
- Aug 6, 2026 Ports and Adapters and the Direction of the Dependency Arrow Why a hexagonal boundary is an interface owned by the application core rather than by the framework, and how driving and driven adapters differ in who initiates the call.
- Aug 5, 2026 Cycles in Module Dependency Graphs and How to Break Them Why a dependency cycle collapses independent modules into one release unit, how strongly connected components expose the real structure, and which refactorings remove a cycle without adding another.
- Jun 27, 2026 Layered Architecture and the Cost of Strict Layer Isolation How an allowed-to-use relation constrains a layered system to one dependency direction, what sink layers permit, and what every pass-through boundary charges in mapping code.
- Jun 15, 2026 Tolerant Readers, Unknown Fields, and the Cost of Strict Decoding How clients should handle members and enum values they do not recognise, why strict decoding turns every addition into a breaking change, and where tolerance turns into silent corruption.
- Jun 10, 2026 Reliability Block Diagrams and Markov Availability Models Composing availability through series and parallel blocks, translating nines into downtime, and using a small state model where repair and degradation matter more than independence.
- Jun 9, 2026 Blast Radius and Cell-Based Isolation How failure propagates through shared pools and control planes, how cells bound the damage to a fraction of traffic, and what the routing layer costs in exchange.
- Jun 7, 2026 Value Objects and Entities: Deciding What Has Identity Why some domain types are defined by their attributes and others by a lifecycle, and how equality, mutation, and identifier choice all follow from that one decision.
- Jun 2, 2026 Routing Requests Between Old and New with a Strangler Facade How a routing layer in front of a legacy application lets capabilities move to a replacement one slice at a time, what the routing key must capture, and why session and data ownership decide the order.
- May 12, 2026 How Deep to Evaluate: Analysis Cost Against Rework Cost Choosing the depth of an evaluation from the reversibility of the decision, the cost of undoing it, and whether the answer would change what anyone does next.
- May 5, 2026 Pareto Frontiers and Cost-Benefit Ranking of Architecture Options Filtering design options by dominance before anyone assigns weights, then comparing the surviving few on marginal cost per unit of quality gained.
- May 1, 2026 Reversibility as the Currency of Architectural Decisions Decisions differ less in how good they are than in what it costs to undo them. How to classify one-way doors, what preserving an option costs, and how to test a rollback path.
- Apr 4, 2026 Compensating Transactions in Multi-Service Workflows How a saga replaces an impossible distributed commit with local steps and explicit undo actions, why the undo is not a rollback, and what becomes visible while the workflow is in flight.
- Apr 2, 2026 Tacit Design Knowledge and the Cost of Unwritten Decisions Code records what the system does and discards why, so the constraints behind each structure survive only in memory. What decays, what it costs, and which artifacts carry rationale.
- Mar 4, 2026 Ubiquitous Language: Keeping One Term for One Concept in Code How naming drift between speech and source produces defects that survive testing, and what it takes to make the code use the same words the domain does.
- Feb 16, 2026 Actor Mailboxes, Supervision, and the Limits of Location Transparency An actor owns its state and processes one message at a time, which removes data races but not unbounded queues. How supervision trees, delivery guarantees, and selective receive shape real behaviour.
- Feb 1, 2026 Switching the Write Path: Cutover, Rollback, and the Point of No Return How to move writes to a replacement store without a window of two writers, what rollback actually requires after new-only data exists, and how to decide when reversal stops being possible.
- Jan 22, 2026 Evolving a Persistent Domain Model Without Downtime The expand-migrate-contract sequence, batched backfills, and event upcasting, for model changes that must survive mixed application versions and a rollback.
- Nov 21, 2025 Connascence: Coupling Measured by Strength and Distance A finer taxonomy than fan-in and fan-out: nine kinds of change-propagating relationship, why strength only matters relative to locality, and how to trade one kind for another.
- Oct 20, 2025 Serverless Execution and the Per-Event Invocation Model When the unit of deployment is a single event handler, lifecycle, concurrency, and retries stop being operational details and become the architecture. What the invocation model gives and what it takes away.
- Oct 15, 2025 Dual Writes and the Divergence They Inevitably Produce Why writing to two stores from application code cannot be made atomic, how partial failure and reordering corrupt one side, and which log-based alternative removes the window.
- Sep 15, 2025 Differential Testing Between a Legacy System and Its Replacement How to run old and new implementations on the same inputs, normalise what is legitimately different, and classify divergences without an external specification to appeal to.
- Sep 13, 2025 Instability, Abstractness, and Distance from the Main Sequence How afferent and efferent coupling produce two ratios per package, why their sum locates a package in a zone of pain or uselessness, and where the arithmetic stops being informative.
- Sep 4, 2025 Event Notification and Event-Carried State Transfer Compared Two events can carry the same name and different obligations: one says a fact changed and leaves the state behind, the other carries the state. The choice sets coupling, ordering needs, and deduplication cost.
- Aug 23, 2025 Domain Events: Publishing State Transitions Without Losing Them Why the database commit and the event publish are two writes that can disagree, how an outbox closes the gap, and what ordering and duplication guarantees consumers actually get.
- Aug 18, 2025 Breaking Change Detection in API Descriptions Which schema-diff findings are genuinely breaking, which are noise, and why the baseline has to be the released description rather than the previous commit.
- Aug 13, 2025 Fitness Functions as Build-Time Architectural Constraints How an architectural decision becomes a check that runs on every commit: dependency rules, thresholds with baselines, and the ratchet that stops drift instead of freezing it.
- Aug 13, 2025 Microkernel Architecture and the Stability of Plugin Extension Points A plugin system is a contract that outlives the code on both sides of it. Extension-point shape, discovery, lifecycle ordering, and isolation determine what can change without breaking installed extensions.
- Aug 11, 2025 Interface Contracts and the Limits of Substitutability What a module boundary promises beyond its signature, why behavioural subtyping is stricter than type compatibility, and which contract clauses callers silently depend on.
- Jul 28, 2025 Deadline Propagation Across Service Hops Why a timeout configured independently at each hop produces work nobody waits for, how an absolute remaining budget survives the chain, and where cancellation actually stops.
- Jul 28, 2025 Read Models Across Service Boundaries What changes when a screen needs data from three owners, how a replicated projection trades freshness for availability, and how to make staleness a stated contract instead of a bug report.
- Jun 18, 2025 Characterization Tests: Pinning Behaviour Nobody Designed How to write tests that describe what untested code currently does, why the oracle problem makes this different from normal testing, and where golden-master comparisons break down.
- Jun 14, 2025 Pipes and Filters and the Contract Between Stages A filter knows its input and its output and nothing else. Record framing, bounded buffering, end-of-stream propagation, and error policy are what make that independence real or nominal.
- May 24, 2025 The Dual-Write Problem and the Transactional Outbox Why committing to a database and publishing to a broker cannot both be atomic, which failure windows open between them, and how an outbox table turns the problem into a delivery guarantee consumers must absorb.
- Apr 4, 2025 Queueing Bounds as a Deployment Design Test Using Little's law, utilization curves, and the Kingman approximation to decide whether a proposed deployment can meet a latency scenario before anything is built.
- Mar 4, 2025 Coupling and Cohesion as Independent Structural Axes Why dependency strength between modules and relatedness inside a module are separate measurements, and how the classic coupling and cohesion scales describe them.
- Feb 14, 2025 Consumer-Driven Contract Testing and the Cost of Many Consumers How consumer expectations become executable contracts, what verification proves about a provider, and why the pattern needs a broker and a deployment gate to be worth its cost.
- Jan 20, 2025 Mapping Runtime Dependencies from Traffic and Query Logs Why static call graphs miss the dependencies that decide whether a legacy component can be removed, and how to reconstruct the real graph from query logs, flow records, and scheduler output.
- Jan 12, 2025 Data Shape Debt and the Migration That Outlives the Code Stored records encode design mistakes that redeployment cannot undo, and the expand-contract sequence that makes an online change safe leaves debts of its own.
- Dec 18, 2024 Space-Based Architecture and the In-Memory Data Grid Removing the shared database removes the contention and makes memory the capacity limit. Replication windows, eviction, and write-behind persistence decide how much data loss the style concedes.
- Dec 13, 2024 Information Hiding and the Parnas Decomposition Criterion How designing each module around a decision it conceals confines the cost of change, and what an interface must expose for that concealment to survive.
- Dec 7, 2024 Idempotency Keys and Duplicate Suppression at Service Boundaries How to make a retried request safe when the first attempt had an unknown outcome, where the claim record must sit relative to the side effect, and when key-based deduplication is not enough.
- Dec 4, 2024 Drawing Service Boundaries Around Consistency Requirements How invariants determine where a service boundary can fall, what a shared database does to that boundary, and which cross-service operations need a different mechanism entirely.
- Nov 25, 2024 Versioning Strategies and What a Version Number Promises How path, header, and media-type versioning differ in what they can express, why a version is a support commitment rather than a name, and when a new version beats a compatible change.
- Nov 10, 2024 Physical Modularity: Compilation Firewalls and Rebuild Cost How declaration-level dependencies turn a header edit into a full rebuild, what a pimpl or interface boundary costs at runtime, and how package compilers avoid the same trap.
- Nov 6, 2024 Change Coupling Mined from Version History Treating each commit as a set of files, computing co-change rates and lift over a window, and using the result to find coupling that no import graph can see.
- Oct 29, 2024 Change Amplification: How Coupling Sets the Price of an Edit Why a one-line rule change can require edits in seven files, how to tell legitimate breadth from amplification, and which couplings multiply the cost of every future change.
- Sep 25, 2024 Anti-Corruption Layers and the Cost of Model Translation What a translation boundary between a replacement system and a legacy one must handle beyond field renaming, where information is lost in the mapping, and when the layer is not worth its cost.
- Aug 19, 2024 Proving a Legacy Component Is Unused Before Deleting It Why an absence of observed traffic is not evidence of absence, how deliberate denial turns a guess into a measurement, and what must be checked before code and data are removed for good.
- Aug 7, 2024 Where an API Contract Ends and the Implementation Begins Which parts of an HTTP exchange callers may depend on, which are incidental, and why undocumented behaviour still turns into a maintenance obligation.
- Jul 29, 2024 Principal, Interest, and Upkeep in the Technical Debt Model What the debt metaphor actually quantifies: a one-time restoration cost, a recurring surcharge on future changes, and the arithmetic that decides whether repayment ever pays.
- Jun 24, 2024 Repositories and the Persistence Boundary What a repository should expose, why it belongs to the aggregate root rather than the table, and which storage concerns it cannot hide from the model.
- Jun 11, 2024 The Runtime Cost of Indirection at Module Boundaries A cost model for boundary crossings: what inlining loses, what a virtual call and a cache miss actually cost, and when a coarse-grained interface beats a clean one.
- Apr 5, 2024 Backfilling a New Store While the Old One Still Takes Writes How to copy historical rows into a replacement without a consistent cut, how keyset pagination and version guards handle concurrent updates, and what a reconciliation pass can and cannot prove.
- Mar 3, 2024 Divergent Duplicates and the Cost of Two Truths How two copies of one business rule drift apart without any build failing, why the drift is expensive to resolve, and how to detect divergence before deciding which copy is right.
- Feb 6, 2024 Invariants and Illegal States: Making Invalid Combinations Unrepresentable How sum types, smart constructors, and parse-at-the-boundary design remove whole classes of runtime checks, and where the technique stops paying for itself.
- Jan 20, 2024 Pagination Contracts and Why Cursors Drift Less Than Offsets How offset and keyset pagination fail under concurrent writes, what a cursor must encode, and which stability guarantees an API can honestly promise.
- Nov 15, 2023 Feedback Latency as Compounding Interest A slow test suite charges every change a fixed toll and inflates batch size, which makes each failure harder to diagnose. The queueing mechanics behind that second effect.
- Oct 24, 2023 Package Encapsulation and the Leak of Internal Types How languages draw the visibility line around a package, which constructs quietly widen it, and why an exported type in a public signature defeats the boundary it was meant to protect.
- Aug 17, 2023 Instability, Abstractness, and the Main Sequence Metric How afferent and efferent coupling produce an instability score, why stable packages should be abstract, and where the distance-from-the-main-sequence number misleads.
- Jul 31, 2023 Finding Seams in Legacy Code That Was Never Built to Have Them How object, link, and preprocessor seams let behaviour be substituted without editing the code under test, and what each kind of indirection costs at runtime and in maintenance.
- Jul 28, 2023 CQRS and the Consistency Window Between Writes and Read Models Separating the write model from query models buys shape and contention relief, and pays for it with a lag the user can observe. Checkpoints, version tokens, and read-your-writes routing decide whether that lag is tolerable.
- Jul 27, 2023 Anti-Corruption Layers at System Edges How a translation layer keeps an external model and its failure semantics out of the domain, where the layer belongs in the call path, and when it costs more than it saves.
- Jul 14, 2023 Quality-Attribute Scenarios as the Unit of Architectural Evaluation Why adjectives such as scalable or maintainable cannot be evaluated, and how a six-part scenario converts them into statements one can test, disagree about, and rank.
- May 4, 2023 ABI Boundaries as Module Seams in Dynamic Linking What a shared library promises a separately compiled caller, why adding a data member or a virtual function can break that promise, and how symbol visibility turns a design boundary into a loader-enforced one.
- Apr 10, 2023 Compatibility Promises as Borrowed Time Publishing a contract converts a one-time edit into an open-ended obligation. Which changes are actually breaking, and how client tolerance determines what a server may do.
- Apr 1, 2023 Event Sourcing and the Append-Only Log as System of Record Storing the sequence of facts instead of the current state changes what a write has to prove, how a snapshot is defined, and why an event schema cannot be changed once it has been written.
- Mar 16, 2023 Idempotency Keys and the Retry Window for Writes How a client-supplied key turns a retried POST into a single effect, what the server has to store to honour it, and where the guarantee quietly expires.
- Jan 16, 2023 Deprecation Windows and the Gates That Must Close Before Removal How to announce an end date, measure who still depends on an interface, and sequence soft warnings, hard failures, and deletion so that removal is boring.
- Aug 4, 2022 Measuring Debt Without Inventing Numbers Complexity, size, churn, and coupling each measure something different, and none of them measures interest. How to build a debt inventory whose numbers change a decision.
- Jun 23, 2022 Bounded Contexts and the Cost of a Shared Model Why one organisation-wide model accumulates nullable fields, how context boundaries are drawn around consistency, and what a context map records about the relationships between them.
- Feb 28, 2022 Independent Deployability and Cross-Service Contracts What must be true for two services to be released on separate schedules, how wire formats absorb change, and why a passing contract test does not prove compatibility.
- Dec 5, 2021 Utility Trees, Sensitivity Points, and Tradeoff Points How a ranked tree of scenarios drives a structured walkthrough of a design, and how the decisions that move two quality attributes at once are separated from the ones that move only one.