A team inherits a payroll system the people who built it left long ago — three eras of architectural taste visible in its layers, a pay run nobody currently employed fully understands, decisions taken under constraints nobody can name anymore. The first instinct is to throw it away and begin again. They don’t. Six months on, they are neither building a replacement nor suffering the original; they are moving the system one correct step at a time. The methodology that lets them is the methodology of the spiral chapters, applied backwards from what already exists.
What this chapter does
Greenfield methodologies look elegant. They start from a clean slate, and a clean slate is forgiving: every decision is an addition, every contradiction is a question that has not yet been asked. The real test of a methodology is whether it survives a system somebody else built — whose original constraints were different, whose assumptions disagree, whose half-finished migrations left both halves in place, whose operational debt has compounded for years. A reviewer of an early version of the methodology framed it that way and challenged the book to demonstrate that the methodology does not “collapse into another abstraction layer” under those conditions. This chapter is that demonstration.
The chapter does three things. It applies the methodology in reverse — start from the system that runs, identify what its use cases actually are, watch workflows surface as they cohere, watch subsystems surface above the workflows, the same vocabulary the spiral built going the other direction. It treats every change to that system as a step in a continuous transformation rather than a migration to a destination, because the systems that survive long enough to be inherited are the systems that never stopped being transformed. And it confronts the brownfield-specific failure modes by name: the legacy persistence model that swallowed the domain, the model that was never really a model, the services that were never really independent, the boundaries that were drawn before anyone knew what a boundary was for. None of those gets a rewrite. Each gets a next correct step.
The continuous-transformation framework was presented in the previous module: the Phase-4 questions, the six-axis vector, the cost-and-risk indicators, the five general failure modes. This chapter does not duplicate it. It applies it to a system the reader did not design, and it makes the methodology earn its keep under the four brownfield constraints the reviewer named: legacy constraints, partial migrations, conflicting domain assumptions, and accumulated operational debt.
The system, in its own words
The inherited system in this chapter is a payroll and HR platform — chosen deliberately to be a domain the spiral never touched. The spiral magnified one example, ticketing, across four altitudes, and that single domain was the honest way to show telescoping. Brownfield is the one place where a contrasting domain earns more than it costs: a methodology that only ever transformed the system it had just designed would be proving very little. Applying it in reverse to payroll is the test that it travels.
A small vocabulary, fixed here so the rest of the chapter can use it:
- Pay run — the scheduled batch that pays a population of employees for a period: gather time, compute gross, apply deductions, withhold tax, arrive at net, disburse, generate payslips, post to the ledger. The system’s heartbeat, and unlike ticketing’s customer-facing flow it is driven by a clock, not a request.
- Off-cycle correction — a retroactive recompute of a prior period (a missed raise, a wrong deduction), issuing an adjustment that tops up or claws back. The compensation-shaped workflow.
- Remittance — paying withheld taxes and contributions onward to the authorities, on their schedule, with the filings they require.
- Employee master — the record the legacy system treats as the centre of the domain: identity, pay rate, tax codes, bank details, benefit elections, accruals, all in one place.
- Payslip — the per-employee, per-period statement of gross, deductions, tax, and net; a legal record, not just a screen.
- Subsystems the reverse-application will surface: Payroll (calculation and disbursement), Tax & Compliance (withholding, remittance, filings), HR / Employee (lifecycle: hire, change, leave, terminate), and Time & Attendance (hours, PTO accrual).
The methodology, applied in reverse
The spiral worked forward. It started from a single use case, let workflows emerge as use cases multiplied, let subsystems emerge as workflows clustered, and let the system stand above them. A brownfield reader has the opposite problem. The system is already there; it runs; people are paid by it. The use cases are not specified, they are enacted, and the only complete description of them is the running code and the running data. The methodology applies in reverse without changing shape.
Start with what the system actually does, not with what its documentation claims it does. A use case is a trigger producing an outcome, and an inherited system has a discoverable set of these: the endpoints that fire, the scheduled jobs that run, the queue handlers that activate. Each is a use case in the methodology’s sense, whether or not the original team wrote it that way. Name them in domain terms — run pay, compute gross, file remittance, onboard employee — even if the code names them after their HTTP routes or their cron entries. The naming is the first audit step; a use case nobody can name is a use case nobody can reason about, and the system already contains several of those.
Workflows surface from how the use cases compose. The two or three use cases that always run for one outcome — gather time, compute pay, disburse — are one workflow with several steps, even if the original code spreads them across four services and a batch queue. Read the composition from the call graph and the data flow, not from the org chart, and group by change driver: the use cases that would all change together if the underlying business policy changed. This is the same recognition test the spiral applied at every transition, here applied to code that does not announce its own structure.
A real call graph rarely reads as a clean tree; it is a mesh — several endpoints calling the same methods, several layers deep. That mesh is not a counterexample to the exercise, it is the use-case hierarchy read by the wrong key. The endpoints are the use-case roots; a shared method many of them call is a shared step, and which kind it is decides everything. A shared read or pure computation (load the seat, price the order) is legitimate reuse: a shared Leaf or value object couples nothing, however many endpoints call it. The tangle is the shared write. Process-first allows exactly one legitimate shared write per resource, the guarded transition on its state; every other shared mutation is accidental coupling that goes home to the use case whose driver owns it. So the mesh thins as you classify: reads stay shared, writes resolve to one owned transition each, and the layers that remain are the altitudes. The cut is never read off the topology — the call graph only shows the candidates; what makes it is the change driver, and the commit history confirms it: the endpoints that change together are the ones that cohere. A mesh of shared mutable methods is the entity-first symptom, not a structure the method fails to find; recovering the hierarchy from it is the whole exercise.
Subsystems surface above the workflows by the same rule, one altitude up. The workflows that compute and disburse pay cohere around the payroll domain; the workflows that withhold, remit, and file cohere around tax and compliance; the workflows that hire, change, and terminate cohere around employee lifecycle. The boundaries the existing code drew may or may not match. Where they match, the subsystem boundary is already drawn, and the work above can move along it. Where they differ — a single service holding workflows from two subsystems, or a workflow spread across services that belong to two different change drivers — that is a deferred problem, named and recorded, not solved this minute.
What this exercise produces is not a redesign. It is a map of the system in the methodology’s own vocabulary, against which the rest of the chapter’s work can be done. The current axis vector V₀ is visible from the map: the deployment topology the system actually has, the substrate it uses to communicate, the read/write and storage shapes its data classes carry, the persistence layout, the recovery classes the code expresses. V₀ is the starting point; V₁ is what some next step might be; the gap between them is where the work is. Until V₀ is named honestly, no V₁ can be derived honestly.
The audit phase
The reason most legacy work goes wrong is not that the system is bad. It is that the team did not bound the work. A discovery surfaces — a pay run that overran its window, a failed deploy, a regulatory finding — and the response is audit everything. Everything-audits produce target-state migration plans, target-state plans produce rewrites, and rewrites produce systems that, on the day they ship, are themselves brownfield. The methodology refuses this loop by bounding the audit to the trigger that surfaced it.
The audit’s lens is the Phase-4 minimal set, the same nine questions the previous module named. The lens is applied narrowly: the trigger names which questions are live for this audit, not all of them. A pay run that overruns its window makes the time budget (question one) and load (question five) live; it does not make external constraints (question six) live unless a mandate or regime is actually in play. A new tax-jurisdiction obligation makes external constraints (question six) and the affected data classes’ consistency contract (question four) and loss budget (question three) live; it does not make release structure (question seven) live. The bound is the trigger’s shape, and the discipline is asking the smallest set of questions whose answers could affect what to do next.
Audits in the methodology’s frame produce one of two outputs. Either the current vector still satisfies the live Phase-4 inputs (in which case nothing structural needs to change, and the audit’s output is “no architectural change; address the trigger inside the existing vector”); or one or more axes in V₀ no longer satisfies a Phase-4 input that has changed, and the output is a candidate axis delta, V₁, that does. Both outputs are useful, and the discipline of allowing the first output is what protects the system from churn. Most triggers do not need an architecture change; they need a fix inside the architecture that exists. The methodology surfaces the cases where architecture change is the correct answer by ruling out the cases where it is not.
The anti-pattern this discipline refuses is the rewrite reflex. A rewrite is, in the methodology’s terms, V₁ derived from a clean slate and applied as a one-step transformation: every axis changes at once, the intermediate state is not feasible (because the system stops running), the dependency cost is total (every later step depends on the rewrite finishing), and the failure-mode amplification is the entire system. The cost-and-risk indicators developed in the previous module rule it out in almost every realistic case, and the methodology says so plainly: a rewrite is rarely the next correct step. It is the desire for a next step, masquerading as one.
From audit to delta
The output of the audit is a candidate axis delta. Each delta moves one or more of the six axes from its V₀ value to a V₁ value that satisfies a now-failed Phase-4 input. Some deltas are simple — one axis, one move, one trigger satisfied. Others are staged, because the change the Phase-4 answer demands cannot happen in one step without violating coherence; the system must move through an intermediate vector that is itself feasible.
A small catalog of common deltas, each anchored in a trigger and a minimum move, captures the shapes the methodology surfaces over and over:
| From V₀ | To V₁ | Trigger | Minimum move |
|---|---|---|---|
| Modulith | Modulith with one service extracted | A workflow with its own scaling shape or its own SLO | Extract the workflow whose change-driver is most independent; leave the rest |
| Microservices that deploy together | Modulith | Services share entities and deploy together anyway | Merge back; rare admission, often correct |
| Direct everywhere | Mixed (direct within, event-based across) | A cross-subsystem path tolerates lag and is paying latency for autonomy | Move that path to events; leave the rest direct |
| Unified read/write | Separated read model on one path | One read path dominates load and tolerates staleness | Project the read; leave writes alone |
| Single shared store | Per-component for one component | A component has divergent persistence forces (scale, regulation, audit) | Carve out that component’s store; keep the rest shared |
| Current-state | Current-state + audit log as data | A regulatory or dispute-reconstruction requirement on a data class | Add the log; do not slide into event-sourcing the whole store |
| Current-state | Event-sourced for one data class | A genuine replay or projection-from-history requirement | Event-source that class; keep the rest current-state |
| Direct-composed saga | Event-based saga | Step coordination fragile under partial failure | Move compensation to events; keep the saga shape |
| Direct calls across subsystems | Typed versioned facts on a bus | A boundary is paying coupling cost without consistency benefit | Replace the calls with published facts; subsystems read at their own pace |
These are not patterns to choose from. They are recurring deltas the methodology produces when a particular Phase-4 input fails against a particular V₀. The walkthrough later in this chapter shows one of them being derived rather than picked. Each delta lands at a vector V₁ that is itself coherent — no infeasible combinations during transition — and each delta is judged on four properties that govern whether it is the correct next step.
The first property is coherence, and coherence is multi-dimensional. A delta is technically coherent if the V₁ vector it produces has no infeasible axis combinations: events without the substrate to carry them, distributed persistence without the operational capability to run it, recovery classes that contradict the consistency contract. A delta is also business coherent: it lands at a vector the team has the capacity to operate, in a market window that admits the transition, with the organizational reality to support it. There is no version of brownfield work where coherence is purely technical. A vector that fits the system but breaks the team is not coherent at this altitude.
The second property is justification: each axis change in the delta satisfies a specific Phase-4 input that has changed. Axis changes that satisfy no input are speculation, and speculation is the source of most accidental complexity in inherited systems. The discipline is to refuse deltas whose justification cannot be stated in one sentence, naming the failed input and the axis change that addresses it.
The third property is reversibility, preferred but not always available. A delta that can be undone cheaply if the Phase-4 answers shift again is a delta the team can take with confidence. A delta that cannot be undone — a schema split, a data migration, an irreversible commitment to a substrate class — does not fail the methodology, but it earns a mitigation plan: the explicit acknowledgment that this step is one-way, the surfacing of the conditions under which the team would regret it, and the preparation for those conditions before the step is taken. Irreversibility is not forbidden; it is named, so that the cost is paid deliberately rather than discovered.
The fourth property is composability: each delta is independent enough from later deltas that the team can defer the later ones. A delta that locks the team into a sequence of seven further steps is not really one delta; it is the first move in a plan, and plans of that length are migration projects in disguise. The methodology prefers shorter independent steps because the Phase-4 answers may shift before the long plan finishes, and a shorter step adapts where a longer plan must be restarted.
Some deltas are genuinely staged, even under this discipline. Moving from a shared database used by several services toward per-service stores is rarely one step; the dependency between the services on the shared schema is the very thing the move is trying to dissolve, and dissolving it requires an intermediate state in which the schema is partitioned logically before any service owns its own physical store. The methodology recognizes the staging by producing two or three deltas with a named dependency between them, each landing at a coherent vector, each justifiable on its own. It does not produce a seven-step migration plan with the seventh step as the goal. The staging is what coherence requires when the change is too large to land in one feasible move; the discipline of producing the staged sequence rather than the seven-step plan is what keeps the team from spending two years on a migration whose justification expired in month four.
The six indicators, applied in brownfield
The previous module named six cost-and-risk indicators for weighing a candidate next-correct-step. In brownfield, those indicators become the chapter’s working tool. Each shows up differently in an inherited system than in a clean design, and the differences are worth naming.
Reversibility in greenfield is a property of the chosen design. In brownfield, it is a property of the step relative to the existing system. A delta that adds something (a new read model, a new audit log) is usually reversible by removing the addition. A delta that splits something (a schema, a service, a workflow) is usually irreversible at any practical cost; the data has fanned out, the consumers have multiplied, the team has reorganized around the split. The brownfield instinct is to under-rate reversibility because everything in legacy already feels permanent. The methodology argues for the opposite: when the legacy is dense, the reversible additions are where the team has the most room to learn cheaply, and the irreversible splits are where every false move compounds.
Intermediate-state feasibility is where most brownfield migrations fail in practice. A delta produces an intermediate vector while the change is in progress, and that intermediate vector must run a real system carrying real traffic. A schema split that requires reads from both old and new stores during the transition, and that produces inconsistent answers between the two, is intermediate-state infeasible — the system does not work during the migration, and the team is forced to stop and roll back or push through against the system’s own logic. The discipline is to design the intermediate state explicitly, with the same care as the destination state, before committing to a delta whose intermediate is not visible from V₀.
Coupling cost is what the legacy version of a step actually charges. A change that looks small at the source ripples through the call graph until it reaches the parts of the system the original architects would have warned against changing. In brownfield, this indicator is read by probing — making the smallest possible change, observing what breaks, and using the breakage as data on what depends on what. Probes are cheap and informative; rewrites are expensive and uninformative. A team that probes before deciding the size of a step usually finds the step is either smaller than feared or much larger, and either answer is better than the unmeasured estimate.
Transition duration is the time the system spends in the intermediate vector. Long transitions exhaust the team and expose the intermediate vector to environmental changes the original plan did not anticipate — a new compliance regime, a vendor sunset, a reorganization. Short transitions are not always available, but when they are, they beat long ones at every margin. The methodology prefers a sequence of short transitions over a single long one whenever the staging is coherent, because each short transition is a place the team can stop, reassess, and decide whether the next step is still the right one given what has changed.
Dependency cost captures how many other steps a candidate step depends on or enables. In brownfield, dependency runs both backwards (this step requires a scaffolding investment first) and forwards (this step is a precursor to several others). A step with high backwards dependency is a step that cannot begin until something else is in place; the methodology asks whether the scaffolding investment itself is justified before the dependent step is even queued. A step with high forwards dependency — a step that, once taken, opens several other moves — is often worth taking earlier than its own immediate justification would suggest, because it unlocks the team rather than just satisfying one input.
Failure-mode amplification is what irreversible steps carry. The previous module argued that irreversible steps deserve mitigation plans rather than prohibition; in brownfield, the mitigation plan is concrete. It is the rollback procedure, even when rollback is incomplete. It is the dual-running window, where old and new coexist long enough for the team to verify the new is sound. It is the explicit list of failure conditions under which the team would freeze the transition rather than continue. Naming these before the step is taken is what separates a calculated risk from a hope.
A convergence worth noting. The same catalog that corroborated the deployment axis in Architecture Synthesis — Denys Poltorak’s Architectural Metapatterns (CC BY 4.0) — also catalogs the transitions between architectural styles, each recording what must hold before it, what it gains, and what it costs. Read in this chapter’s vocabulary, those prerequisites map onto intermediate-state feasibility and dependency cost, and the listed downsides onto failure-mode amplification: independent confirmation that the indicators are asking about the right dimensions. It corroborates; it is not the spine. The next correct step is still derived from the Phase-4 delta and the V₀ probe, not selected from a catalog.
Methodology informs, business decides
A brownfield team operates under constraints the methodology does not own. Capacity is finite; market windows close; the organization has its own clock. The methodology’s discipline is to be clear about what it provides and what it does not, so the conversation with the business is honest.
What the methodology provides:
- Vector analysis — V₀ named honestly, the live Phase-4 inputs identified, the axes where V₀ fails them surfaced.
- Delta options — one or more candidate next-correct-steps, each anchored in a specific failed input and a specific axis change.
- Coherence check — for each delta, whether the resulting V₁ is feasible, and whether the intermediate state during the transition is feasible.
- Reversibility assessment — whether the delta can be undone cheaply, and if not, what its mitigation plan would look like.
- Cost-and-risk indicators — the six dimensions, applied to each candidate so the trade-offs are visible.
What the business decides:
- Whether to act now — the methodology says a delta is correct; whether this is the moment is a business judgment.
- How aggressive to be — short and many, or longer and fewer; the methodology produces both; the business picks.
- Resource allocation — which team, which window, against what other work.
- Risk acceptance — whether the failure-mode amplification of an irreversible step is acceptable given the upside; the methodology surfaces it, the business owns the answer.
- Final commitment — the decision to begin, and the decision to stop.
The line is sharp on purpose. A methodology that pretends to make business decisions sacrifices its credibility on the technical ones; a methodology that hides from business decisions becomes the abstraction layer the reviewer warned against. The methodology stays on its side of the line and asks the business to stay on its own. Where the two meet — coherence is multi-dimensional — the methodology surfaces the technical shape of the trade-off in terms the business can act on, rather than absorbing the business question into itself.
The conversation looks the same shape every time the methodology has produced a candidate delta. The team brings what the methodology produced: V₀ named, the failed Phase-4 inputs identified, one or two candidate deltas with their V₁ and intermediate-state designs, the six indicators per delta. The business asks the questions the methodology cannot answer: how much engineering capacity the delta consumes; whether the transition window falls inside or outside a sensitive period (year-end close and tax-filing season are payroll’s immovable walls); what the team will not do during the transition that they would otherwise be doing; what the employee-visible risk is and what protections are available. Some questions cross back over the line, and the methodology answers them: whether a postponement to a calmer quarter changes the indicator profile (it changes transition-duration risk, sometimes intermediate-state feasibility); whether a smaller staged delta would lower the failure-mode amplification (often yes, at the cost of a longer total program). Some questions stay on the business side, and the methodology refuses to answer them: whether the cost is worth paying, whether the timing is right, whether the team has the capacity now. The discipline of refusing those questions is what keeps the methodology useful on the questions it can answer.
Brownfield-specific failure modes
Greenfield can fail in five ways, named in the previous module: Phase-4 contradictions, vector infeasibility, trapped state, knowledge gap, unexplored territory. Brownfield inherits those and adds four of its own — patterns in inherited systems so common that any methodology worth its keep has to name them and produce a next correct step for each. The four are not exhaustive, but they account for most of the work an inheriting team will do in its first year.
Legacy persistence that swallowed the domain
The pattern: the system’s domain types live inside the persistence framework’s classes. Entities are framework objects with lifecycles the framework manages; the operations on them are methods on those classes; the database schema and the in-memory domain model are the same shape. The cost is that every domain change is also a persistence change, every persistence concern leaks into every workflow, and the change-driver cohesion the methodology cares about is invisible because the persistence framework is dictating the boundaries.
The methodology’s diagnosis is the audit. The Phase-4 input that fails is rarely the one the team thinks: it is usually consistency contract (question four), because the persistence framework’s defaults do not match what the domain actually requires per data class. Sometimes it is the loss budget (question three) on data classes the framework treats as ephemeral. The next correct step is rarely “switch frameworks.” It is to surface the per-data-class consistency contracts the domain actually needs, introduce per-process types for the workflows whose consistency contract differs from the framework’s default, and let the persistence concerns retreat to the boundary where they belong. The transformation is staged: types first, workflows next, persistence boundary last. None of the steps requires touching the framework; the framework simply stops being the source of truth for shape.
In the payroll platform this shape is concrete. An Employee master record owned by the persistence framework holds everything about a person (pay rate, tax codes, accruals, bank details, benefit elections) and the pay-run workflow walks it through a period by calling framework-managed mutators, every change triggering cascading persistence side effects the workflow does not see. The typed steps and typed failures the methodology asks for (GrossPay, Deductions, NetPay as per-process types; TaxCodeMissing, BankDetailsInvalid as named failures) do not exist; the workflow interrogates the record by reading fields. The next correct step is not to rewrite the entity. It is to introduce the per-process types at the workflow boundary — the workflow builds them from the record on entry and produces them as typed outputs the next step accepts — and to let the employee master become a place state lives, not the shape the workflow runs on.
The model that was never a model
The pattern: classes named for domain concepts hold data and almost no behavior; the behavior lives in service classes that operate on the data structures from outside. The domain has the names of its concepts and none of their operations; the system’s logic is dispersed across services that none of the domain names belong to.
The methodology’s diagnosis here is structural. The workflows the system runs are not derivable from the so-called domain types, because the types do not carry the workflow’s invariants. Phase-4 input failures often look like ambient ones (slow screens, inconsistent reports), but the underlying cause is that no use case has a clean type to operate on, so every workflow is fighting its inputs into shape before it begins. The next correct step is to find the highest-traffic workflow whose typed inputs and typed outputs would be the most clarifying, and produce them as per-process types — not as a refactor of the existing classes, which would propagate the dispersion, but as new types that the workflow constructs from existing data at its boundary and consumes internally. The original anemic classes can stay; they will gradually shrink as workflows stop depending on them. The methodology does not require the team to delete what is there; it requires the team to start producing what was missing.
The payroll variant is recognizable, and it is sharpest on the Payslip rather than the employee record. A Payslip data class holds identifiers, amounts, and status; a PayrollService in another package holds computeGross, applyDeductions, withholdTax, disburse, each reading and writing the payslip through the persistence layer. The rule that tax is withheld on gross only after pre-tax deductions are applied lives inside PayrollService.withholdTax, as a runtime check that throws on violation. The rule is invisible at the type level; the payslip’s fields can hold any combination of amounts regardless of what was computed before. The methodology’s next correct step is to introduce typed states for the run (ValidatedRun, GrossComputed, DeductionsApplied, TaxWithheld) and let the typed transitions enforce what the runtime check was approximating. The data class stays as the persistence shape; the workflow stops depending on its mutability.
Microservices that deploy together
The pattern: the team adopted services years ago for reasons that made sense at the time — team independence, scaling stories, the architectural fashion of the era — and finds that the services share a database, share entity definitions, deploy in lockstep, fail together, and require coordinated releases to ship any cross-service feature. The architecture is microservices by deployment; it is a monolith by behavior. The team pays both costs: the operational complexity of many services and the coupling cost of one shared model.
The methodology’s diagnosis is direct. The Phase-4 inputs that justify multiple deployables — team independence on independent release cadences, scaling shapes that differ enough to require independent scaling, blast-radius containment between failure domains — are not satisfied by the current system. Several inputs that suggest consolidation are satisfied: bounded operational capacity, a small team, a release cadence that wants to be uniform anyway. The next correct step is rare in the literature and frequent in practice: merge back to a modulith. The services become modules in one deployable, the shared database survives the transition unchanged, the team’s deployment surface shrinks, and the coupling that was already there becomes visible rather than hidden. This is the worked walkthrough below; it deserves a section of its own because it is the most contested move the methodology produces.
Boundaries that predate their reasons
The pattern: the system’s largest structural boundaries were drawn before anyone knew what they were for — early in the project, by someone whose intuition was the only available guide, or copied from a reference architecture the team was reading at the time. The boundaries now constrain everything, but no Phase-4 input justifies them. The team works across the boundaries continuously, paying the coordination cost, because the work the system actually does runs perpendicular to the lines the architecture drew.
The methodology’s diagnosis is the reverse-application exercise from the first section of this chapter. Apply the change-driver test to the workflows the system actually runs, and see where the real subsystem boundaries fall. Compare against where the system currently draws them. The misalignment is the cost. The next correct step is rarely to re-draw all the boundaries; it is to move one workflow at a time across the existing boundary toward the side its change driver actually belongs to, until enough workflows have moved that the architectural boundary itself can shift to follow them. The methodology produces a sequence of small workflow-level moves, each justified by its own change-driver alignment, that together — over years, not weeks — bring the architectural boundaries into agreement with the work. The team rarely moves the boundary; the boundary drifts under the accumulated weight of correctly-placed workflows.
Named in the two axes, the old boundaries fail both at once: each tier is impure, holding workflows from several change drivers so that every domain’s churn passes through it (accidental coupling), and each change driver is incomplete, its workflows scattered across all three tiers so that one change is shotgun surgery. The reverse-application exercise is a purity-and-completeness audit, and the one-workflow-at-a-time fix restores both.
A payroll example sharpens what this looks like. A platform whose original boundaries were Web, Application, and Data (the technical tiers) has its pay-run workflow crossing all three and its tax-filing workflow crossing all three too, every change to either rippling through the same three places. Apply the change-driver test: what workflows change together when tax law changes? Withholding, remittance, year-end filing, the deduction rules the law governs — all in the tax-and-compliance domain regardless of which tier currently holds their code. What workflows change together when pay policy changes? Gross calculation, overtime rules, accrual, the pay-run schedule — all in payroll. The real subsystem boundaries run perpendicular to the technical tiers. The next correct step is to take one workflow, say off-cycle correction, and re-home its pieces along the payroll-domain boundary inside the existing code, leaving the tiers in place. Repeat for the next workflow. Over enough cycles, the payroll subsystem becomes visible as a coherent place in the code, and the technical tiers stop being the axis the code is decomposed along. They do not vanish — a tier is still its own language, its own technology, its own security posture, its own people, and cutting it into subdomains changes none of that — but they no longer drive the structure; the change-driver boundaries do, and each tier becomes an implementation fact inside a subsystem rather than a seam the whole system is cut on.
A worked walkthrough: distributed-monolith remediation
A payroll platform inherited from an earlier era. Three services exist on paper — payroll, benefits, and time-tracking — each owned by its own team. In practice all three share the employee database, all three share a set of entity classes that started as DTOs and grew into the system’s data model, and a release of any one of them is coordinated with the other two because schema migrations affect all three. The platform pages frequently during deploys, because a deploy is effectively a system-wide change, and a botched deploy during a pay-run window threatens people’s wages. The teams have been arguing for two years about whether the answer is more services or fewer, neither side wins, and the operational cost compounds.
The audit, bounded by the trigger that surfaced the problem (deploy-time failures and the operational paging), starts with the Phase-4 minimal set restricted to the live inputs. Release structure (question seven) is failing — the teams cannot deploy independently and a single deploy fails frequently. The failure budget (question two) is failing on the deploy-related incidents, and for payroll an availability miss in the wrong window is a missed payday. The cost and capacity envelope (question eight) is failing — the operational overhead of three services running and being administered is being paid for none of the benefits multiple services were supposed to deliver. Load (question five) is neutral; nothing in it actually requires three deployables. The other inputs are stable.
The current vector V₀, read from the reverse-application exercise: three deployables / direct calls between services with a shared schema / unified read/write / current-state / single shared store with one schema across services / BER throughout. The map matches the literature’s pattern of services-by-deployment, monolith-by-behavior: the three services partition deployment without partitioning anything else.
The candidate delta the methodology produces is the merge-back. V₁: single deployable, modulith / direct calls within the modulith / unified / current-state / single shared store / BER. Four axes are unchanged; deployment topology moves from many to one. The justification is direct: the Phase-4 inputs that failed (deploy independence, availability under deploy, operational cost) are all satisfied by removing the deployment separation that the rest of the architecture never honored anyway. The delta carries no axis changes that fail other inputs, because the system was already operating as a modulith under the surface of its deployment.
The six indicators applied to this delta:
- Reversibility. Re-splitting the modulith into services later is possible if the Phase-4 answers shift to justify it; the modulith preserves the subdomain boundaries internally as modules, which keeps the option open. The merge itself is also reversible in the short term by redeploying the previous topology, before consumers and operators have re-tuned around the modulith.
- Intermediate-state feasibility. The intermediate is the most awkward part of this delta and deserves explicit design. Running services and modulith in parallel during cutover is rarely feasible; the cleaner intermediate is a planned window between pay runs combined with a rollback path. The team that cannot accept the window will need to stage the merge differently (module by module behind a front routing layer, a longer sequence of smaller deltas), and the methodology produces that sequence on request, with its own indicator profile.
- Coupling cost. Low. The services already shared everything that matters; the merge surfaces couplings that were already in place. The cost of not merging is what the indicator captures: every cross-service change continues paying coordination cost that the merge eliminates.
- Transition duration. Short if the planned-window version is acceptable; weeks if the staged version is required. Either is short compared to the alternative of pursuing real microservices, which is a multi-year transformation with its own indicator profile.
- Dependency cost. Low backwards (no prior step is required to enable the merge), high forwards (several other deltas become possible after the merge — re-drawing module boundaries by change driver, introducing a read replica for the reporting path, eventually extracting one module as a service if a future Phase-4 input demands it). The forwards leverage is a strong argument for taking the merge step earlier rather than later.
- Failure-mode amplification. Moderate. A failed merge requires rollback to the three-service topology with whatever drift occurred during the window. The mitigation plan is straightforward: stage the merge against a feature freeze and outside any pay-run or filing window, validate at each module boundary, hold the previous deployment artifacts ready for rapid rollback, and define explicit failure conditions under which the team aborts.
The methodology delivers the analysis. The business decides whether the cost of the merge, the risk of the mitigation plan, and the loss of the original microservices investment are acceptable trades for the operational dividend. The conversation is sharp on each side: the team can explain why the merge is the next correct step in terms the business reads (current state fails three Phase-4 inputs, the alternative is a multi-year program, the merge unlocks several smaller steps after it), and the business can accept or defer on terms the methodology does not pretend to own.
This walkthrough is one delta on one platform under one set of Phase-4 inputs. The other three failure modes named above are addressed by different deltas under different inputs, but the procedure is the same: reverse-apply the methodology, name V₀ honestly, identify the failed Phase-4 inputs, derive a candidate delta, apply the indicators, separate the methodology’s output from the business decision. The procedure does not change with the failure mode, and — the point of re-domaining this chapter — it did not change with the domain either. That is what the spiral’s claim to telescope across altitudes meant, when the methodology was being built; it means the same thing when applied in reverse, to a system the book never designed.
The five failure modes in brownfield form
The five general failure modes the previous module named — Phase-4 contradictions, vector infeasibility, trapped state, knowledge gap, unexplored territory — recur in brownfield work, with shapes specific to inherited systems.
Phase-4 contradictions in brownfield often come from the gap between what the system was built for and what it now carries. A consistency contract that was correct for the original use case fails the new use cases the system grew. A cost envelope that was tolerable at the original scale is no longer. Multi-X requirements have appeared since the original design — a second country’s tax regime, a second currency — and have nothing in the design to attach to. The methodology surfaces the contradiction as two Phase-4 inputs that no single vector satisfies, and the team’s job is to decide which input wins, knowing the cost of either answer.
Vector infeasibility in brownfield is the more common failure mode. The team can produce no V₁ satisfying all live Phase-4 inputs given V₀, because the current system blocks the required axis change. A reporting path needs separated read and write models, but the projection would have to come from inside the legacy persistence framework that owns the employee master, and cannot be addressed cleanly. The methodology names the infeasibility and asks: what would have to change about V₀ to make a feasible V₁ available? That smaller question opens a scaffolding step — a delta whose only job is to make later deltas feasible.
Trapped state is the most useful failure mode the methodology surfaces, because it diagnoses the situation where the obvious next steps all fail their indicators. The system is locked: every candidate delta fails coherence, or fails reversibility past the team’s appetite, or fails intermediate-state feasibility. The methodology’s answer is not to lower its standards but to invest in scaffolding before any architectural step. Test substrate that lets the team verify intermediate states. Observability that makes failure modes visible in time to react. Deployment automation that brings transition duration down to where the team can stomach it. The scaffolding is not the goal; it is what makes the goal reachable, and recognizing that an inherited system needs scaffolding before structural change is half of what experienced brownfield teams already know.
Knowledge gap in brownfield is usually a Phase-4 elicitation problem masquerading as an architecture problem. The team does not know what the system’s real consistency contracts are, because the original requirements are lost and the current behavior is ambiguous. The methodology asks the team to elicit before deriving, even when the elicitation feels slow; deltas derived against unknown inputs are deltas applied to a fantasy of the system. The cost of the elicitation is paid back several times over by the deltas it prevents.
Unexplored territory in brownfield is the honest output that the system in front of the team is outside the methodology’s bounded scope — enterprise backend, the methodology’s commitment, ends somewhere, and a real-time control system, a numerical analysis pipeline, an embedded firmware codebase does not get the same procedure run against it. The methodology says so, hands the reader their own judgment back, and stops pretending. That refusal is what keeps it from becoming the abstraction layer the reviewer warned against.
Hybrid V₁ is what real systems look like
The walkthrough produced a clean V₁ in which only one axis changed. Most brownfield deltas are less clean. A team that has been operating an inherited system for any length of time finds itself at vectors that are hybrid across nearly every axis — modulith plus one extracted service, mixed substrate, unified storage with one event-sourced data class, persistence partitioned for one component and shared for the rest, recovery classes mixed by subsystem. The hybrid is not a defect of the methodology. It is the accumulated record of correct next-correct-steps, each justified, each applied, none of them aspiring to uniformity for its own sake.
The previous module argued that hybrid is normal at any real scale. Brownfield sharpens the point. Greenfield can choose uniformity at the moment of design if the Phase-4 answers point that way; brownfield almost never can, because the system arrives carrying a vector that was correct for inputs that no longer hold and that the team cannot afford to undo wholesale. A brownfield team that insists on uniform vectors is a team that is rewriting; a brownfield team that accepts hybrid as the working state of a living system is a team that is transforming. The vector V₁ a brownfield team reaches is the vector that satisfies the live Phase-4 inputs and survives the path it took to get there, which is rarely the vector a clean-slate derivation would have chosen, and is rarely worse off for the difference.
What a long-lived hybrid actually looks like, written out, is closer to the enterprise vector the synthesis walkthrough reached than to either of its smaller profiles. A team five years into operating an inherited payroll platform might be sitting at a modulith with one or two services extracted along genuine SLO or scaling lines — a high-volume time-import path, say. The substrate is mixed: direct calls inside the modulith, event-based to the extracted services, streaming for the one data class whose volume earns it. Read and write are unified everywhere except one separated reporting path carved out under a specific load profile. Storage is current-state everywhere except the tax-decision class the regulator made event-sourced, and the store is single and shared except for the components whose persistence forces diverged enough to earn their own. Recovery is mixed by subsystem because each subsystem’s domain shape demands a different class: BER for the money in payroll, design-out for the append-only tax-decision log, FER for the accruals that tolerate lag. Every “except” in that description is a delta the team took for a reason. Read together, they are not a half-finished migration; they are the architecture this team operates against the current Phase-4 inputs.
The discipline is to read V_now without apology. Each exception in the hybrid is justifiable by the delta that produced it; if it is not, the audit will surface it as a candidate for the next correct step. The exceptions a team cannot justify are technical debt in the methodology’s own terms: an axis value that no Phase-4 input requires and that some Phase-4 input is paying for. Naming those exceptions is useful work; rewriting around them rarely is. The hybrid is the system speaking honestly about what it has been asked to do, and the methodology’s job is to read what it says.
Closing — moving without rewriting
The chapter began with the reviewer’s challenge: a methodology that looks elegant on a clean slate is not the same thing as one that survives an inherited system — and the answer was not to defend the methodology with argument but to apply it in reverse, on a domain the spiral never touched, and watch what it does. Reverse application produced a map of V₀; the trigger-bounded Phase-4 audit produced the live inputs and the axes that fail them; candidate deltas produced V₁s reachable through feasible intermediate states; the indicators weighted them; the methodology informed and the business decided. That it ran the same way on payroll as on ticketing is the demonstration the reviewer asked for.
What the chapter does not produce is a target-state migration plan. The team that finished it has no vector it is migrating toward — it has a procedure for deriving the next correct step from where the system stands now, and the discipline to take that one step and then re-derive. The plan, if a plan is needed at all, is the sequence of small derivations the team performs over months and years; it is not written down in advance, because writing it down in advance is what produces the multi-year programs that fail their own justifications by the time they ship.
The book closes from here. What remains is honest scope — what the methodology does not cover, what it predicts, and what it invites the reader to test against their own systems. The closing names what the methodology bets on, what would force a rethink, and where the open work is.