Legacy Application Modernization Factory

Architecture diagram: application inventory and dependency discovery feeding architecture mapping, risk and obsolescence scoring, a behaviour-capture regression harness, modernization option modelling and incremental strangler migration with rollback evidence.

Every established business has at least one application it cannot replace and cannot safely change. It runs something important, the people who wrote it have moved on, and the documentation is a folder of screenshots. Modernization stalls not because nobody wants it, but because nobody can prove the replacement behaves the same way.

Status: product concept, in active development. This is something we are building, not something you can buy today. We publish our roadmap because the engineering thinking behind it is the useful part — and because we would rather show you the design than imply a finished product.

Architecture diagram: application inventory and dependency discovery feeding architecture mapping, risk and obsolescence scoring, a behaviour-capture regression harness, modernization option modelling and incremental strangler migration with rollback evidence.

Designed Capabilities

  • Application inventory and dependency discovery — establish what actually exists and what depends on it.
  • Architecture and data-flow mapping — recover the design that was never written down.
  • Risk and obsolescence scoring — prioritise by exposure, not by who complains loudest.
  • Behaviour-capture regression harness — record what the system does today so change can be proven safe.
  • Modernization option modelling — rehost, refactor or replace, costed rather than argued.
  • Incremental strangler migration orchestration — replace in slices, never big-bang.
  • CI/CD and infrastructure templates — the new system arrives with a pipeline.
  • Rollback and validation evidence — every step reversible and demonstrable.

Behaviour Capture Is the Unlock

The reason legacy rewrites fail is that the old system’s real behaviour — including its bugs, which downstream processes now depend on — was never captured. Recording actual behaviour first turns “we think this is equivalent” into a test you can run. Everything else in the platform exists to make that evidence usable.

Tell us if this matches a problem you have — early input shapes what we build first, and we will give you an honest view of where it stands.

Not Every Old System Is Worth Modernizing

This page describes a product concept that is in development. It is not finished, and it is not something you can buy today. What follows is the thinking behind it.

An application that rarely changes, runs on a supported platform, and carries no compliance exposure can reasonably be left alone. Modernization earns its cost when one of three things is true: the platform underneath is out of support, the business needs changes the code cannot absorb, or the knowledge to operate it has left the building. If none of those apply, freezing it and revisiting later is usually the cheaper decision.

There is also a middle option people skip. Wrapping a system with an API, so that new work happens outside it, can defer the deeper question without touching the core. It is not modernization and it does not remove the underlying risk, but it is often the better use of this year’s budget.

Why Do Rewrites Fail Even When Everyone Agrees on the Goal?

The behavior problem is the one people talk about. The scheduling problem is the one that kills projects. A rewrite has to catch a system that is still moving, because the business will not stop asking the old application for changes while the new one is built. Teams then either freeze the old system and absorb the operational pain, or maintain both and pay for both, and that second choice is where schedules quietly stretch.

Incremental replacement exists to avoid that choice. When functionality moves in slices, each slice can stop needing maintenance in the old system once it lands, so the stretch of paying twice narrows as the work proceeds. That only works if each slice can be shown to behave correctly, which is the job recorded behavior is meant to do.

What Behavior Capture Would Show, and What It Would Miss

Recorded behavior can give evidence of equivalence for the paths that actually ran while the recording was on. Common transactions tend to appear early. Month-end, year-end, error handling, and the rare exception one person knows about do not, unless the recording spans long enough to observe them. Any honest assessment of this approach has to include the calendar. A capture window that misses a fiscal close has not tested the part most likely to hurt.

The intended output is evidence: replay the recorded inputs, compare the outputs, and triage every difference as an intended improvement or a regression. Differences will exist. The point is that someone decides about each one deliberately.

What the Tooling Would Not Do

Recording and replay say nothing about whether the current behavior is correct. If the old system has been quietly miscalculating something, an equivalence test will reproduce the error faithfully and call it a pass. Deciding which behaviors deserve preserving is a business conversation, and it tends to be the slowest part of a modernization program.

What Kinds of Systems Is This Aimed At?

The design targets applications an organization owns and can change: in-house Java, .NET and PHP systems, desktop applications, and client-server tools built when the network was the local one. Packaged software from a vendor with a supported upgrade path is a different problem, and usually a conversation with that vendor. So is a system whose source code no longer exists, where the realistic path is replacement.

The Manual Version of This

None of the methods depend on the product existing. Inventory and dependency mapping, risk scoring, and a recorded regression baseline can all be done inside an engagement today, by hand. It is slower, and it takes more effort per application, which is exactly why the tooling is worth building. If you have one system and not a portfolio, the manual route may be the sensible answer anyway.

If the platform underneath is the real constraint, our cloud migration work may be the nearer-term move. The assessment question is the same either way: which workloads deserve to move, which deserve rewriting, and which should stay where they are.

Frequently Asked Questions

Is this a code conversion tool?

No. There is no source-to-source translator in the design, and none is planned. Automated translation produces code in the target language that nobody on the team wrote or reviewed, and it carries the original structure across intact, so a design from 2004 arrives unchanged in a modern runtime and the maintenance problem comes with it. The tooling is designed to sit around the rewrite rather than perform it: capture the old system's inputs and outputs, hold them as a fixture set, and tell you whether the replacement your engineers wrote matches. What language the new code is written in, and what architecture it uses, is a decision the design stays neutral about.

What has to already exist on our side before behavior could be recorded?

An instrumentable seam, first. Recording assumes there is a boundary you can sit on: an HTTP or RPC interface you can proxy, database traffic you can capture statements against, or a queue you can tee. A system whose important logic happens entirely inside one process with no observable hop is a poor fit, because there is nothing to record except the screen. Second, a non-production environment where the recorded inputs can be replayed against a known data state. If the data moves underneath the replay, differences appear that have nothing to do with the code. Third, control of the clock and of anything else nondeterministic in the environment, since timestamps, sequence values and random seeds otherwise produce differences on every run.

How is a rollout designed to proceed, in order?

The tooling cannot be deployed today, so what follows is the intended order rather than a schedule: scope one application, inventory, map, score, instrument and record, baseline replay, then slices. The step teams want to skip is the baseline replay, and it is the one that decides whether any later evidence is worth reading. Before a line of new code exists, the recorded traffic is replayed against the old system itself to confirm it reproduces its own outputs. If it cannot match itself, the difference is coming from something the capture did not control, and every comparison after that inherits the noise. A false positive rate you never measured is indistinguishable from a regression. The baseline run is also what surfaces couplings nobody listed, such as the report that writes back to a table or the job that only works because another one ran first, and what tells you which fields have to be excluded from comparison before the exclusions start looking like convenient ones.

How would it fit the delivery systems we already run?

The design point is that comparison runs where the build runs. The replay and diff are meant to execute as a pipeline stage, so the evidence for a slice is produced by the same build that produces the slice, and a failed comparison fails the build instead of becoming a document written afterward. Fixture sets are versioned next to the code they exercise, so a fixture and the behavior it describes move together through branches. Triaged differences are designed to carry the identifier from whatever tracker you already use rather than living in a second queue, and access follows your existing directory rather than a separate user list. Comparison results are meant to leave as metrics and structured output so they land in the monitoring you already watch.

Where would recorded data live, and who would have access to it?

Recorded production traffic is production data, and the design treats it that way. Capture is intended to run inside the customer's network with the recording store under the customer's control, so the fixtures never have to leave the environment that already governs the underlying records. Masking is designed to happen at the point of capture rather than after storage, because anything written unmasked is a second copy of production data that then needs the same controls as the first. Masking that runs before storage has to be deterministic and format preserving, since a replay compares values: if the same input maps to a different token on each pass, or a masked account number stops being the right length, the comparison breaks on the mask instead of the behavior. Field level rules therefore get set before the first capture, not after. Fixtures are useful for the life of the slice they cover, which makes retention and deletion after cut-over a normal part of the plan.

What would we have to decide, as opposed to what the tooling decides?

Four things, and none of them are technical defaults. Which application goes first, which is rarely the largest one. Where the boundary of the first slice falls, which usually turns out to be narrower than a screen or a module, because a slice that splits a transaction across old and new is a slice that needs distributed rollback. What counts as different: whether list ordering, a rounding difference in the final cent, or a changed message identifier is a regression or noise. Those tolerance rules need writing down before comparisons start, or each difference becomes an argument held twice. And the rollback trigger for a slice once real traffic reaches it: which signal sends traffic back to the old path, who can pull it, and how long both paths stay warm afterward.

Does this cover mainframe systems?

Not in the current design. The approach assumes you can get between the caller and the code, and that a second environment with a controlled data state is practical to stand up. Both assumptions weaken on platforms where licensing, the terminal protocol, or the scheduling system makes a duplicate environment awkward. A mainframe fronted by a service interface can in principle be recorded at that interface, but where a system can only be observed at a terminal session, capture records keystrokes and screens rather than semantic calls, and the comparison then depends on screen layout, which changes for reasons that have nothing to do with behavior. That is a different tool with different failure modes, and it is not what this is.

What would we have to supply in people, not just systems?

Three roles. An engineer who can place the recorder on the boundary and into the network path, which is usually the hardest thing to schedule because it touches production. Someone who knows the application's history well enough to say why a given behavior exists, since the code will not tell you which oddities were deliberate. And a named owner for difference triage, which is the role most often left unfilled. The tooling is designed to surface differences and hold them in one list; the list still needs that owner. An owner works well when they can commit on behalf of the business without convening a meeting per item, because volume peaks right after a slice's first comparison run and falls as the exclusion rules settle. While a difference sits undecided, the slice it belongs to cannot cut over, so the work does not stop, it queues, and the queue is behind the old system's maintenance costs continuing to run.