Skip to content
willowark

Modernize the legacy system without betting the business on a rewrite

Legacy software modernization is how you deal with the aging system your business depends on — the VB6 application, the aging Access database, the codebase whose original developer is gone — without the classic disaster of a multi-year rewrite that ships late, broken, or never. It removes the standing risk of the system nobody dares touch running the thing you cannot afford to stop.

Willowark modernizes incrementally, on the strangler-fig pattern: put a stable interface in front of the old system, then move functionality out piece by piece, with old and new running side by side until the last piece is retired. At every point you have a working system — the property big-bang rewrites give up first.

Illustrative: an engineer's desk with code and a system diagram on two monitorsSoftware Engineering

How the work gets done

The same way every time: scope, build, hand over.

The work starts with archaeology: reading the old code and the database to recover what the system actually does, including the undocumented behaviors your operation quietly depends on. We pin that behavior with characterization tests before changing anything, so 'the new system matches the old one' is verifiable rather than hopeful. Data migration gets the same discipline: mapped, scripted, and rehearsed against copies before any cutover, with reconciliation checks proving the counts match.

Each migrated piece cuts over on its own schedule, often with a parallel-run period where both systems process the same inputs and we compare outputs. Success is measured in risk retired and capability unblocked: the unsupported runtime decommissioned, the integrations the old system could never support, a migration your customers never noticed.

Scoping a modernization is an exercise in sequencing. The assessment produces an inventory of the old system's functions, ranked by how much risk each one carries and how much it blocks — the unsupported runtime, the report finance cannot get, the integration the old platform cannot support. We migrate in that order rather than in the order the code happens to be arranged. The trade-off we weigh most is fidelity versus improvement: reproducing an old behavior exactly is safest, but some behaviors were always bugs that users learned to live with. We reproduce first, then fix deliberately, so a change in output is a decision and not an accident.

Modernizations fail when the old system refuses to die: the functions nobody migrated, the report still run from the retired database, the parallel period that became permanent because switching off felt risky. We design against that by defining decommissioning as a milestone with its own checklist — data archived, access revoked, licenses retired — and by making the new system the only place certain records can be changed. Handover includes the modernized code, the migration scripts and their reconciliation results as an audit trail, and documentation for the engineer who joins after we leave. The job is finished when the old system is off, not when the new one is on.

  1. Scope it in writing

    What we agree before work starts

    • System assessment documenting recovered behavior, dependencies, and risk
    • Characterization test suite pinning current behavior before changes
  2. Build with checkpoints

    Working results, not slide decks

    • Incremental migration plan with per-piece cutover milestones
    • Rehearsed, scripted data migration with reconciliation reports
  3. Hand over something you own

    Documentation, source, and training

    • Modernized system with documentation your next engineer can start from
    • Decommissioning checklist and archived data from the retired system

Sound familiar?

Where legacy software modernization earns its keep.

A job-costing system in Access that the whole shop floor depends on and one retiree understands

A VB6 application that cannot run on the new machines IT needs to deploy

A core product on a framework version that stopped receiving security patches years ago

A custom ERP add-on written against a database version the vendor is about to drop support for

Common questions

Asked before every legacy software modernization project.

Rewrite or refactor — how do you decide?

By component, not wholesale. Some pieces are worth wrapping and keeping; some need rewriting because the platform is dead; some can now be replaced by an off-the-shelf product that finally fits. The assessment maps this piece by piece, avoiding both a needless full rewrite and an endless patch job.

Can the business keep running during the migration?

That is the design constraint everything else serves. Incremental cutover means the old system keeps working while each piece moves, parallel runs prove the replacement before it takes over, and every cutover has a rehearsed rollback. The migrations that hurt are the ones staked on a single weekend; we do not build those.

The original developer is gone and there's no documentation. Is that a problem?

It is the normal starting condition. The code and the database are the documentation — they say what the system does, if not why — and characterization tests plus time with the system's daily users recover the rest. Undocumented systems take more archaeology up front, but they are modernized successfully all the time.

How long does a modernization take?

It depends on how much the old system does and how much of that still matters, which is exactly what the assessment measures. Small systems typically move in a few months; large ones are usually a series of phases over a year or more, each retiring specific risk. We do not quote a total before the assessment because nobody can honestly do so, but every phase has its own scope, and you see working software at the end of each.

Will our staff have to relearn everything?

Not all at once, and not more than necessary. Because functionality moves piece by piece, users learn one new screen at a time while the rest stays familiar, and we design the new screens around the work people already do rather than around how the old software happened to arrange it. Where the old interface encoded a genuinely good workflow, we keep it. Training is part of each cutover, and the people who use the system daily review each piece before it goes live.

Where this sits

Legacy Software Modernization, inside a software engineering system.

The whole system this service belongs to. Hover or focus a component to see what it is and what it talks to.

A production web applicationRESTRESTSQLeventswebhookUsersWeb appAPIDatabaseWorkersjobs, queuesIntegrationsexisting tools

Hover or focus a component to see what it is and what it talks to. Arrow keys move between them.

Users reach a web app that talks to an API over a database, with background workers for the slow work and integrations to the systems already in use.

Components:

  1. Users: Staff, customers, or both.
  2. Web app: The interface: fast, accessible, works on a phone.
  3. API: Typed, versioned, authenticated.
  4. Database: Postgres, usually. Backed up, migrated, monitored.
  5. Workers (jobs, queues): Reports, syncs, emails — anything that should not block a click.
  6. Integrations (existing tools): Accounting, CRM, email, payments.

Connections:

  • Users to Web app over REST
  • Web app to API over REST
  • API to Database over SQL
  • API to Workers over events
  • Workers to Integrations over webhook, both directions
A typical architecture, drawn to explain the pattern — not a specific client's system.

Strategy. Software. Systems.

Have a system that should exist?

Tell us what your operation is doing manually, what isn't connected, or what you're trying to build. We'll tell you plainly whether and how we can help.