nativegate
← Blog

Modernizing legacy engineering software: why big rewrites fail

Every engineering organization seems to have one: a Fortran or C++ program older than most of its users, that nobody wants to touch and everybody depends on. The recurring proposal is a rewrite. The recurring outcome is a rewrite that stalls, because halfway through, the team discovers that the legacy code is not obsolete — it is validated, and its validated behavior is documented nowhere except in the code itself. This post is a field guide to strategies that acknowledge that fact from day one.

Why rewrites fail

Engineering code accumulates three kinds of invisible content:

  • Discipline decisions. A units conversion here, a convergence guard there, an occasional factor-of-two embedded in a correlation. None is labeled; all are load-bearing.
  • Decades of bug fixes. Every defect that was found and fixed is embodied behavior a rewrite will re-discover the hard way.
  • Interpretation of specs that no longer exist. The formulation the code implements is often more current than the paper describing it.

A rewrite transfers all of that content by hand, under time pressure, with no oracle to compare against — because the first version of a rewrite has nothing to compare against except the code it replaces, and if anyone actually builds that comparison, they've reinvented the smarter strategy: keep the original, wrap it, and verify.

The strategy that does work: interface-first

Keep the numerics compiled and untouched. Change what's around them, in an order that produces value at every rung:

  1. Import. Bind the highest-value routines into a Python package. Value appears the first time someone calls the model from a script instead of editing an input file.
  2. Serve. When a second consumer appears, expose the same surface over HTTP. Same code, wider audience.
  3. Contain. Put the service in a container so deployment stops being tribal knowledge.
  4. Verify. Around everything, from the first week: a recorded numerical baseline that every change is measured against.

Each rung is useful alone. None requires abandoning the others. And the original program keeps running while all of it happens — there is no day where the new system must be switched over, because nothing was replaced; interfaces accumulated around it.

Numerical regression assurance

The rung most organizations skip, and the one that makes the rest safe, is the baseline. Record the outputs of known configurations before the first change; fail any future change that moves them. nativegate calls this the golden record. It answers "did the answers move?" in seconds, forever, and it is the difference between "we changed the build system" being a prayer and being a checked claim.

A realistic scorecard

What a tool-assisted version of this strategy does not do: it does not make the code readable, does not convert it to another language, and does not make a stateful Fortran model safely multi-tenant. It does make the code reachable — by your scripting languages, your web stack, your CI — without touching the numerics, and it makes every future change provably answer-preserving. For validated engineering software, that is most of the value and almost none of the risk.

Try it on your codebase → Related: modernizing legacy Fortran