Solution Architecture5 November 20268 min read

Architecture Must Earn Its Complexity — Part 7 of 9

Extract the module with its data

Part 7 of Architecture Must Earn Its Complexity. Moving a module's code into a service while leaving its tables behind produces a distributed monolith. A staged, strangler-style extraction with exit evidence and a rollback point at every stage, worked through for a verification module that needed its own security boundary.

#Solution Architecture#Microservices#Cloud Migration#Architecture Decisions#Risk Management
A compact building of clearly walled modules, with one module moved out on a rail into its own unit and new cables spanning the gap.

The decision to extract the Verification module at the fictional Magaliesberg Provincial Supplier Desk was easy to justify. The province had contracted an external verification source for company and compliance checks. The contract required a dedicated network path, credentials that no other part of the platform could hold, a separate audit log and a separate group of administrators. Annelie Botha, the department's security and compliance officer, put it plainly: "The rest of the application should not be able to reach that source, even by mistake." That is a security boundary, one of the extraction triggers recorded in Part 1, and the evidence gate passed in one meeting.

The harder question was how. The first plan on the table was the one most teams reach for: copy the Verification code into a new service, point it at the existing database and switch the traffic over on a Sunday. Thabo Molefe rejected it. "If the new service still reads the old tables," he said, "we have not moved the boundary. We have stretched it across a network."

The Magaliesberg Provincial Supplier Desk is a fictional provincial supplier-support platform. Its people, systems, contracts and figures are illustrative. This part describes a staged extraction that moves the module and its data together, with a way back at every stage.

Code without data is a distributed monolith

A service that shares tables with the application it left has the costs of both designs and the benefits of neither. Every call between them now crosses a network, as Part 3 described, and yet neither side can change its schema without breaking the other. Incidents become harder to diagnose, because a slow query in one process can stall the other. The security boundary Annelie needed would not exist, because the main application's database role could still read verification results directly.

Our article on when a module should become a microservice gives the order of extraction: boundary in code, then data, then how others get the data, then parallel running, then the route. This part adds what that order needs in practice: exit evidence for each stage, and a named rollback point, so that the team always knows whether it can still go back and what it would cost.

Six stages, each with a way back

The approach follows the strangler fig idea. Martin Fowler's description (22 August 2024) emphasises replacing a system gradually, through seams that let old and new coexist, rather than all at once. Microsoft's Strangler Fig pattern guidance (checked on 5 November 2026) applies the same idea to a database: copy the domain tables to a new store, keep them in sync with change data capture, validate, cut over, and only then remove the old objects.

Six stages, each with a way backSTAGESTAGE 0Decide andrecordWAY BACKNothingchangedSTAGE 1Finish theboundaryWAY BACKCoderevertSTAGE 2Seam behindthe contractWAY BACKSwitch toin-processSTAGE 3Copy data,run shadowWAY BACKSwitch offthe shadowSTAGE 4Cut overby cohortWAY BACKMove cohortbackSTAGE 5Retire theold pathWAY BACKRestore andreplay data
Every stage has exit evidence and a named rollback point. Until the last stage, going back is a switch or a revert, because the old schema stays current through reverse sync. Only retirement makes rollback expensive, which is why the old tables are removed last and only after a waiting period with no reads.

Stage 0: Decide and record. The decision record names the trigger, the evidence, the expected improvement, the service and data owners, the operating budget from Part 6 and the review date, together with the architecture delta: what changes and what stays the same. Exit evidence: an approved record. Rollback: nothing has changed.

Stage 1: Finish the boundary in place. Before any new infrastructure, the module must already be a real module. At the Supplier Desk this meant two things. All callers already used Verification's contract, after the work in Part 2. The one cross-module transaction recorded in Part 4, suspending a supplier and cancelling its verification requests together, had to be redesigned. Registration now suspends the supplier and publishes SupplierSuspended. Verification keeps a small, event-fed copy of each supplier's status and checks it before publishing any outcome. If an outcome slips out in the seconds before the suspension event arrives, Verification publishes VerificationRevoked for it. This is eventual consistency with a guard, not a transaction, and the decision record says so. Exit evidence: no cross-schema queries, no cross-module transactions, contract tests passing. Rollback: ordinary code revert.

Stage 2: Put a seam behind the contract. The Verification contract got a second implementation: a client that calls the new service over the network. A configuration switch decides which implementation each caller uses. This technique is often called branch by abstraction. Exit evidence: both implementations pass the same contract tests. Rollback: switch back to in-process.

The seam exposed an awkward fact. Until Stage 5, the in-process path is still live, and it is the in-process path that calls the external verification source, which Annelie wanted no part of the main application to reach. The team did not pretend otherwise. The in-process path kept a temporary, narrowly scoped credential, recorded as a time-boxed exception in the exemption register with Annelie as its owner and the planned Stage 5 date as its expiry. Part 8 describes how that register is enforced.

Stage 3: Copy the data and run in the shadow. The new service got its own database in its own network zone. An initial copy loaded historical verification records, and change data capture kept the new store in step with the old schema, which remained the system of record. The new service received a copy of every verification request and computed its own result, which was compared with the in-process result and then discarded. Shadow traffic doubles the calls to the external source, so the volume was agreed with the provider in advance; above that volume, the shadow used recorded responses instead of live calls. Exit evidence: two weeks of comparisons with no unexplained differences, and the sync lag inside an agreed bound. Rollback: switch off the shadow; nothing user-facing depended on it.

Stage 4: Cut over by cohort. Live traffic moved to the new service one district at a time, starting with the smallest. For a cut-over district, the new service became the system of record, and changes flowed back to the old schema so that reporting and rollback still worked. Each record was owned by exactly one side, decided by the supplier's district, and each sync skipped changes that had originated from the other sync, so no update could loop between the stores. Exit evidence: each district's error rate, latency and verification turnaround within the agreed range for a week. Rollback: switch the district back; the reverse sync means the old schema is still current.

Stage 5: Retire the old path. Only after every district had run on the new service for a month did the team remove the reverse sync, the in-process implementation and finally the old tables. Exit evidence: no reads of the old schema for the full period, confirmed from database logs. Rollback: possible only by restoring the old objects and replaying changes, which Microsoft's guidance rightly describes as significantly more effort and risk. That is why it comes last.

What moves with the data

The data is not only the tables. Moving a module's data means moving everything that depends on how it is stored.

What moves with the dataShared database:verification schemaVerification service:own database and zoneHistorical recordsReporting exportAudit history, checkedBackups, restore testCredentials and access
Moving a module's data means moving everything that depends on how it is stored. The verification history moves with checked counts, the reporting view keeps its shape from a new source, backups and restores are tested before cut-over, and the external verification credentials exist only inside the new service's zone.
  • Reporting. Kagiso's report read Verification's reporting view in the shared database. After extraction, the service publishes a nightly export with the same shape into the reporting area. The view's contract survived; its source changed.
  • Audit history. All verification history since launch had to move with the module, because the new audit log was meant to be complete. The team verified record counts and checksums by year before Stage 5.
  • Backups and retention. The new database has its own backup schedule and retention rules, agreed with Annelie, and a restore test before Stage 4.
  • Access. The external verification credentials exist only in the new service's secret store. The main application's database role has no route to the new database at all.

Pitfalls the stages are designed to catch

PitfallWhat it looks likeStage that catches it
Hidden readersA report or script still queries the old tablesStage 1 analysis and Stage 5 log check
A transaction nobody recordedData drifts after cut-over because two writes are no longer atomicStage 1 exit evidence
Silent behaviour changeThe new service rounds or validates differentlyStage 3 shadow comparison
Big-bang cut-overEvery user moves at once, with no way backStage 4 cohorts
Sync left running foreverOld and new stores both treated as authoritativeStage 5 retirement deadline
Retiring too earlyOld tables removed before rollback was ruled outStage 5 waiting period

The Stage 3 comparison caught one real difference. The in-process code trimmed trailing spaces from company registration numbers before calling the external source; the new service did not, and about one request in two hundred failed as a result. In a big-bang migration, that would have been a production incident. In the shadow, it was a one-line fix, and the comparison results went into the decision record, where upgrade evidence belongs.

How long it took

The extraction took about sixteen weeks from approval to retirement: roughly five weeks for Stages 0 to 2, then two weeks of shadow running, five weeks of district cut-overs, and a month before the old tables were removed. Most of the calendar time was waiting on purpose. The engineering effort was concentrated in Stage 1 and Stage 3. The figures are illustrative, but the distribution is typical: the work is front-loaded, and the calendar time is mostly evidence gathering.

Our article on as-is, bridge states and to-be makes the general point that the bridge states are architecture too. Each stage here is a bridge state with its own owner, evidence and exit.

A stage-gate checklist

  • Stage 0: decision record approved, with trigger, evidence, owners, budget and review date.
  • Stage 1: no cross-schema queries, no cross-module transactions, contract tests green.
  • Stage 2: in-process and remote implementations pass the same contract tests.
  • Stage 3: shadow comparisons clean for an agreed period; sync lag within bound.
  • Stage 4: cohorts cut over one at a time, each meeting its exit measures.
  • Stage 5: no reads of old objects for the full waiting period; then retire.
  • Reporting, audit history, backups and access have all moved with the data.

Key points

  • A service that shares tables with the application it left is a distributed monolith.
  • Extract in stages, each with exit evidence and a named rollback point.
  • Finish the boundary in place first, including redesigning any cross-module transaction.
  • Use a seam behind the contract, a shadow run with comparison, and cut-over by cohort.
  • Reporting, audit history, backups and access move with the data, and old tables are removed last.

Previous: Part 6, The distributed-systems tax nobody put in the business case. Next: Part 8, Architecture fitness functions for the modular monolith. All parts are on the series page.

How CloudNala can help

CloudNala plans and supports module extractions that move code and data together. We assess whether the boundary is ready in place, design the seam, the data copy and the shadow comparison, set exit evidence and rollback points for each stage, and make sure reporting, audit history, backups and access move with the module, so that the extraction delivers the boundary you approved and nothing you did not.


Work with CloudNala

CloudNala helps organisations move from technology ambition to practical execution across cloud, AI, data, platform engineering and digital services.

Whether you are exploring AI, modernising your cloud environment, building a public-sector digital service, or turning an idea into a working MVP, we can help you shape the roadmap and deliver the next step.

Book an Architecture Complexity Review or write to us at consult@cloudnala.co.za