advanced 3 min answer Multiple choice

A 2004-era order management system runs on an Oracle database where roughly 40 PL/SQL triggers and packages hold business rules that exist nowhere else. A facade is in place and three read-only capabilities already route to the new service. The team must now move its first write. Which rule should decide which write goes first?

strangler figoracletriggerscutoverreconciliation
Pick one
Show the full answer Hide the answer

The deciding property

A read can be moved wrongly and the worst outcome is a wrong answer you can compare against the legacy answer whenever you like. A write cannot be checked afterwards, because in a system of this age the legacy write is not storage: it is the trigger that decrements stock, the package that writes the audit row, the row trigger that enqueues the warehouse message, and the nightly job keying off a column the trigger set.

Move a write without that list and either the side effects silently stop, so stock drifts and the warehouse never hears about the order, or you keep the legacy path warm as a safety net and they happen twice. Both surface weeks later as a number that does not add up.

So the selection rule is knowability. Choose the write whose consequences you can list, reproduce in the new service, and then disable on the legacy side, in that order. Volume, payload size and business enthusiasm are tiebreakers among the candidates that pass.

How to build the list

Two sources, and the gap between them is the finding. ALL_TRIGGERS, ALL_DEPENDENCIES and ALL_SOURCE in the Oracle data dictionary give the declared graph and miss dynamic SQL assembled inside packages. A week of DML auditing shows what actually fires and misses the month-end path that did not run that week.

Use both, and treat anything in one list and not the other as this capability's risk register. If the register cannot be closed, pick a different capability.

The sequence, each step reversible

  1. Shadow. The new service computes the write and persists nothing; diff against the legacy row. Reverting is deleting a flag.
  2. Dual-persist with legacy authoritative. New service writes its own store; legacy still owns the truth and fires the triggers.
  3. Flip authority. New service is the writer; legacy reads a replicated copy and reconciles.
  4. Disable the legacy triggers for this capability.
  5. Delete the legacy path.

Step 4 is the point of no return. Up to there, a revert is a routing change. After it, a revert means re-enabling the triggers and replaying every row written while they were off through logic you have just proved you do not fully understand.

Divergence shows up in small numbers, so reconcile daily on the business event and alert on the first unmatched pair rather than on a rate. A capability cut over in week 14 yields a handful of mismatches a day, which no percentage threshold notices.

Why the other options fail

  • Lowest volume. Sound reasoning about blast radius, and the right tiebreaker once the trigger question is settled. Alone it optimises the wrong variable: a quarterly write with twelve triggers has the lowest volume in the system and is the worst possible first move. Low volume limits damage per hour and does nothing for detectability.
  • Smallest payload. This confuses the interface with the behaviour. The payload ports in an afternoon; the 40 triggers are not in it and are invisible from the API contract, which is why teams reach for this criterion.
  • What the business most wants. The funding pressure is real and this is how programmes acquire an irreversible first step. The capability most wanted rewritten usually holds the most accumulated rules, which makes its side effects the least enumerable of all.

When not to do it this way

If no capability has an enumerable trigger set, incremental write migration is not available yet. The first deliverable is then making the legacy side legible: move trigger logic into callable procedures the new service can invoke, or into application code, before any write moves.

If this changes Choose Because
The legacy logic lives in application code Lowest-volume write first Side effects are already visible in a call graph you can read
A tested trigger inventory already exists Highest business value first The gating risk is retired and ordering becomes a product decision