Why read the old code before a legacy data migration?
A migration can move every row and still be wrong. Why the old system’s code holds what your data means, and what to check before you switch it off.
When a company tells me it’s replacing an old system, the plan for its data is nearly always the same. Export the data, map each old field to a field in the new system, import it, check that the row counts and totals match, and switch the old system off. The new vendor usually offers to run the import, because the data is the part the business can’t afford to lose.
The trouble is that in a system built for your company, the data doesn’t explain itself. Which rows are really deleted, what a field means and which records are duplicates were all decided by the old system’s code, and the code is the one part of the old system everyone plans to throw away.
I’ll cover why a migration can move every row and still be wrong, what happened when one company moved its records, what to do with the old code before you map a single field, and when the standard plan is all you need.
Why can a migration move every row and still be wrong?
A migration can move every row and still be wrong because a database stores values, and the rules for reading those values live in the code that wrote them. When you move the tables without those rules, the values arrive intact and the meaning stays behind.
Those rules tend to hide in a few places, starting with a “deleted” marker the system stopped using at some point, so records that look current were replaced long ago. There’s the field whose meaning changed partway through the system’s life, so one column holds two different things depending on when a record was created. There are records the screens quietly hide but the tables still hold, and there are facts that were never in the database at all, because the team kept them in a spreadsheet.
None of that shows up in a row count, so the counts and totals will match the old database, and the people who use the data will find the problems one record at a time.
What happened when one company moved its records?
A company replacing an earlier custom system moved every row of its records without dropping one, and the data still came out wrong. The first pass worked from a copy of the old database, and once the client started checking records, the emails that came back said the data looked wrong.
Line items the old system no longer treated as current had come across as live, and they sat at the top of the lists. At some point the old system had stopped marking replaced lines as deleted and started relying on version numbers instead, so only the latest version of each line was real, and that rule existed only in the old code.
The problems had to be found before they could be fixed. An Excel file the staff kept turned out to be a better source of truth than the old database, and checking migrated totals against it exposed duplicates, while someone on the client’s side clicked through records and flagged the ones that looked wrong. Reading the old code then explained almost all of it. The engineer who ran the migration said afterward that his biggest lesson was to get the old code and understand the data before mapping anything, and that doing so would have avoided most of those problems.
That company is a client of ours, and the migration was our work. As I told the engineer running it, it had become “less of a migration and more of a reconciliation of data,” meaning a job of checking the old database against every other source until they agree, and I’d plan the next one that way from the start.
What should you do with the old code before you map a field?
Keep the old code, and read it before you map a single field, because right now it’s worth more than the data, which only means what the code says it means.
In practice, that starts with keeping the old system’s code, and keeping the old system readable, until the new one has run long enough to prove itself. Before you map a table, read how the old code creates, changes and removes its records, and write down every place where a status field or a version number decides what’s current. Look at your newest records and check that each column you plan to map is still being filled, because a column the system stopped using will copy across as blanks or leftovers. Ask the staff which spreadsheets they check when they don’t trust the system, and compare against those. When you test, have the people who use the data open records they know well, because a total can match while the lines underneath it are wrong.
When is the standard plan fine?
The standard plan is fine when you’re leaving a standard product. If the old system is a package many companies use, like QuickBooks, with documented fields and an importer the new vendor already supports, trust the importer and spend your time checking records. The old code matters when the system was built or heavily customized for your company, because then the rules for reading your data exist in one place, the old code, and no vendor’s importer knows them.
Signs your migration plan skips the code
You can check these from a chair, before the import starts:
- Nobody can say where the old code is kept.
- Nobody working on the migration has opened the old code.
- The plan is checked with row counts and totals.
- Staff keep a spreadsheet they trust more than the system.
- The old system is switched off the day the import finishes.
If the old system is a standard product and none of these apply, the vendor’s import is probably all you need. If it was built for you and any of them sound familiar, read the code before you move anything.