Legacy integration takeover: assuming ownership of code nobody understands
Sooner or later someone has to take responsibility for the script that has been posting your orders for six years. This is the method for doing that safely, in the right order, without a finance outage in week one.
- What a legacy integration takeover actually inherits
- Establish a behavioural baseline before you change a line
- Reconstructing the contract from evidence rather than memory
- Scoping a legacy integration takeover when the requirements are unknown
- Taking custody: parallel running, cutover and the handover you should have had
- Related platform guides
- Key points
What a legacy integration takeover actually inherits
A legacy integration takeover begins the same way almost every time. A nightly job has been moving orders from Magento into Sage 200 since before the current finance manager joined. It was written by a contractor, or by a developer who has since left, or by someone in IT who built it as a favour. There is no documentation, no test environment, and no repository anybody can locate. The only thing everyone agrees on is that it works, mostly, and that nobody wants to touch it.
The pressure to change usually arrives from outside. A tax rate changes, a supplier switches couriers, an API version is deprecated, or the business adds a sales channel that the original author never contemplated. At that point the absence of knowledge stops being a latent risk and becomes an operational one. Somebody has to open the box.
It is worth being precise about what you are inheriting, because it is more than source code. You are inheriting a set of undeclared business rules — the reason credit notes are posted to a particular nominal code, the reason certain order types are silently skipped, the reason the job runs at 02:40 rather than midnight. You are inheriting credentials held in configuration files, scheduled tasks on a server nobody patches, and downstream reports whose correctness depends on the current behaviour. You are also inheriting the accumulated tolerance of the operations team, who have quietly built manual workarounds for every failure mode and may not mention them unless asked directly.
The mistake we see most often is treating this as a rewrite. A rewrite is a tempting response to code you cannot read, but it replaces a system with known, tolerated faults with a system with unknown faults, and it does so on a timetable set by whatever external change forced the issue. The sequence that holds up in production is slower and less dramatic: observe, document, contain, then change.
Establish a behavioural baseline before you change a line
You cannot prove you have not broken something unless you know what it did beforehand. The first deliverable of a takeover is therefore not a fix. It is a record of current behaviour, captured in enough detail that any future change can be compared against it.
In practice this means instrumenting around the existing process rather than inside it. If the job writes to a database, capture a snapshot of the affected tables before and after a run. If it calls an API, put a logging proxy in front of it and record the full request and response bodies, including headers and timings, for a representative period. If it reads files from a landing folder, archive every input for the duration of the observation window rather than letting the job delete them. Two to four weeks of observation is usually enough to see a month-end, a weekend, a bank holiday and at least one failure.
Pay particular attention to what the process does not do. A job that posts orders from Magento into Sage 200 may be excluding staff orders, sample orders, zero-value lines or anything with a particular payment method. Those exclusions are rarely visible in the code as a comment saying why; they appear as an unexplained conditional. The baseline tells you how many records take each branch, which turns an unexplained conditional into a quantified business rule you can ask the business about.
Record the failure behaviour too. When the courier booking call to Royal Mail times out, does the job retry, skip, or abort the whole batch and leave half the orders marked as dispatched? Does anyone receive an alert, or does the warehouse simply notice the next morning that labels are missing? These answers determine how much blast radius your eventual changes have, and they are frequently the single most valuable thing a takeover produces.
- Volume profile — Records processed per run, per day and per month-end, with the shape of the peaks. This tells you whether a rewrite needs to handle 400 orders or 40,000.
- Branch counts — How many records follow each path through the logic, including the paths that silently discard data. Zero-count branches are candidates for deletion; high-count branches are undeclared business rules.
- External call inventory — Every endpoint, credential and third-party dependency the process touches, with authentication method, API version and the date that version is scheduled for withdrawal.
- Failure catalogue — Each observed error, its frequency, what the process did in response, and what a human had to do afterwards to put the data right.
Reconstructing the contract from evidence rather than memory
Once you have a baseline, the work shifts to interpretation. The goal is a written specification of what the integration is contractually obliged to do, assembled from three sources: the observed behaviour, the code itself, and the people who depend on the output. Where these three disagree — and they will — the disagreement is the finding.
Start from the downstream consumers, because they define correctness. Ask the finance team which reports they run, which figures they reconcile, and what they do when the numbers do not match. Ask the warehouse team which fields in Peoplevox they rely on and which ones they have learned to ignore. You are looking for the small number of data elements that must be exactly right, as distinct from the large number that are merely present. In a typical order-to-cash flow the must-be-right list is short: the order reference, the tax treatment, the total value, the customer account and the dispatch confirmation. Everything else can be reconstructed if necessary.
Then read the code against that list. You are not trying to understand every line; you are tracing the path of each critical field from source to destination and noting every transformation applied to it. Rounding, truncation, string concatenation into a reference field, hard-coded nominal codes, date format assumptions, time zone handling — these are where the undocumented business logic lives. Write each one down as a numbered assumption and take it back to the business for confirmation or correction.
Expect a proportion of the assumptions to be wrong. Code that has run unchallenged for years tends to accumulate behaviour that nobody actually wants but nobody has noticed, usually because a manual workaround absorbs the error. Those discoveries need to be logged and priced separately, not folded silently into the takeover. If a six-year-old rounding error has been understating tax by a few pence per order, that is a finance conversation with a potential correction exercise attached, and it should not be buried in a technical change log.
Scoping a legacy integration takeover when the requirements are unknown
Fixed-price work requires a known scope, which creates an obvious problem when the subject of the work is a system nobody understands. The resolution is to separate the two pieces commercially. Discovery and baselining is a discrete, time-boxed piece of work with defined deliverables: the behavioural baseline, the reconstructed specification, the assumption log and a prioritised risk register. The build work that follows is then scoped and fixed against those documents, because by that point the unknowns have been converted into written statements somebody has signed off.
Resist the pressure to compress this. The usual argument is that the external deadline — the API deprecation, the courier change — does not allow time for investigation. In our experience the opposite is true: an uninvestigated change to an undocumented integration tends to produce a week of emergency remediation that costs considerably more than the fortnight of observation would have. If the deadline genuinely cannot accommodate discovery, the correct response is a containment measure, such as pinning an API version or adding a compatibility shim, which buys time without committing to a structural change.
The risk register is the document that earns its keep. Each entry should state the risk, the evidence for it, the operational consequence if it materialises, and the cost of addressing it now versus later. Credentials stored in plain text in a configuration file on an unsupported server is a risk with a cost attached. A dependency on an API version withdrawn in nine months is a risk with a date attached. This is the material that lets a finance manager make a defensible decision about sequencing rather than being presented with an undifferentiated list of technical concerns.
Prioritisation should follow exposure, not elegance. Anything that can produce incorrect financial records ranks above anything that merely produces an outage, because an outage is visible and an incorrect ledger entry is not. Anything with an external deadline ranks above anything that can wait. Code quality, for its own sake, ranks last — unreadable code that produces correct output is a maintenance cost, not a live risk, and it can be addressed when there is a functional reason to open that file anyway.
Taking custody: parallel running, cutover and the handover you should have had
When changes do begin, the safest pattern is to run the new path alongside the old one rather than replacing it. The replacement process writes to a staging table or a shadow environment, and a comparison job reports every field-level difference against the live output. Differences are then individually explained: either the old behaviour was correct and the new code is wrong, or the new behaviour is correct and the old code was wrong. Both outcomes are useful; what matters is that no difference goes unexplained before cutover.
Parallel running needs an agreed duration and an agreed exit test, both written down before it starts. A full month-end cycle is the usual minimum for anything touching accounting, because a great many integration faults only appear in period-close behaviour. The exit test should be expressed in business terms — the aged debtors report reconciles, the stock valuation matches, every dispatched order has a tracking reference — rather than as a statement that the tests pass.
Cutover itself should be reversible for a defined window. Keep the old scheduled job in place but disabled, keep the original credentials valid, and keep the archived inputs so a run can be replayed if a discrepancy emerges a week later. Decommissioning is a separate, deliberate step taken once the new path has survived a full cycle, and it includes revoking the old credentials rather than leaving them active and forgotten.
Finally, produce the handover that was missing in the first place, because the purpose of a takeover is to ensure the next one is unnecessary. That means source code in a repository the client owns, a plain-language description of what the integration does and why, the field mapping and transformation rules, the credential inventory with rotation instructions, the runbook for each known failure mode, and the contact points at each vendor. Hand it over as a deliverable on completion, not as something that exists only in a consultant's head. The measure of a successful legacy integration takeover is not that the code is now elegant. It is that somebody new could pick it up in three years and know within an hour what they are holding.
Related platform guides
- Magento API integration
- Sage 200 API integration
- Peoplevox API integration
- Royal Mail API integration
Key points
- Do not rewrite before you observe: capture a two-to-four week behavioural baseline, including volumes, branch counts and failure responses, so any change can be proved against known prior behaviour.
- Reconstruct the specification from downstream consumers first, then read the code against the short list of fields that must be exactly right; log every undocumented transformation as a numbered assumption for business sign-off.
- Separate discovery from build commercially, parallel-run through at least one full month-end with field-level comparison, and treat the written handover pack as a delivery requirement rather than an afterthought.
Planning an integration?
Send us the two systems and the record types involved. We will come back with an outline scope and the approach we would recommend, within one working day.