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.
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.
- 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
| Pitfall | What it looks like | Stage that catches it |
|---|---|---|
| Hidden readers | A report or script still queries the old tables | Stage 1 analysis and Stage 5 log check |
| A transaction nobody recorded | Data drifts after cut-over because two writes are no longer atomic | Stage 1 exit evidence |
| Silent behaviour change | The new service rounds or validates differently | Stage 3 shadow comparison |
| Big-bang cut-over | Every user moves at once, with no way back | Stage 4 cohorts |
| Sync left running forever | Old and new stores both treated as authoritative | Stage 5 retirement deadline |
| Retiring too early | Old tables removed before rollback was ruled out | Stage 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
