↑ Back to Contents
19

Modernizing Legacy Systems

Turning legacy baggage into a launchpad


ore often than not you won't get lucky and be able to start fresh. Greenfield projects are much rarer than brownfield ones, so there's often some baggage to deal with when you start. Perhaps unsurprisingly, there's growing enthusiasism about breathing fresh life into old, possibly outdated systems without the need for a manual, costly rewrite with help of AI. This chapter discusses the common topics relevant to this kind of work and suggests practical strategies for using AI to help you get on board.

Anatomy of a Modernization Programme

What drives the decision — and what you have to get right

Drivers
End of Life
Business Change
Security & Compliance
Cost of Maintenance
Talent Availability
 
Modernization
Considerations
Feature Parity
Data Migration
Integrations
Security & Access
UX Overhaul
Transition Plan
Modernization is driven by business and technical pressures, but the real work is in the considerations on the right.
Click to enlarge

The diagram above depicts some common drivers for modernization and the aspects typically involved. The list of drivers or aspects is by no means exhaustive, and not all of them are relevant in every project.

Next, we'll dig deeper.

Modernization vs greenfield vs brownfield

In the context of this book, I regard modernization as a full or partial rewrite of an existing system using modern technologies, patterns, and UX.

What actually gets modernized depends on the case. It could be a partial rewrite of some features, replacing a layer (just the UI, integrations, or some third-party technology), or a complete rewrite. The transition strategy varies just as much.

Speaking of modernization — how come I ended up writing a game that looks like it's from the dawn of computing? First of all, it runs on a browser, and secondly, many tout the CLI versions of IDEs as 'improvements'.

The goals might be anything from solving technical end-of-life (risk management), security concerns, new business needs, or changes in ownership or hosting. In many respects, modernization is a special case of a greenfield project, but with restrictions and constraints that come from the legacy system.

What a greenfield project is should be clear, but for completeness: it's something where you can start fresh without much regard for what came before, if anything. A totally new service, system, or app that doesn't replace anything. A brownfield is a regular software project you join after it's been running for a while.

Here are my highlights on how a modernization program typically differs from greenfield and brownfield projects across some key dimensions.

Aspectvs. Greenfieldvs. Brownfield
Starting pointNo old code or documentation to worry aboutEstablished patterns and codebase to learn
Documentation and knowledgeRequirements defined upfrontModernization reverse-engineers specs from code and tribal knowledgeTeams may have incomplete docs but know the systemModernization often gets little to no documentation
Technical debt and scopeNo debt, scope bounded by choiceModernization is often motivated by the debt itself, and scope is dictated by the legacy systemDebt accumulates gradually, scope is incrementalModernization must understand the full system even when only rewriting parts
Feature parity and UXChoose which features to build and design UX from scratchModernization must replicate existing features and decide what legacy UX to keep, phase out, or overhaulEvolves features and UX incrementallyModernization may require a complete rethink while preserving user expectations
Data and integrationsDesign schema from scratch, choose integrations freelyModernization inherits legacy schemas, data migration, and integration points that are difficult to changeWorks with existing schema and integrationsModernization must untangle, migrate, and bridge all of these while maintaining integrity
Rollout and onboardingDeploy in any order, typical onboardingModernization requires careful sequencing plus learning both old and new systems simultaneouslyDeploy incrementally, learn one systemModernization may need parallel deployment and dual-system knowledge

Of course the table oversimplifies a complex topic, but it's worthwhile to understand the starting position and why we need to account for things that aren't relevant in other project types. Now that we have a foundation, let's look at how to get started.

Getting started with modernization

Starting points, motivations, scope and scale of the efforts vary greatly, so it's very hard to give you a 'patent recipe' to tackle this. But here's how I'd go about planning and preparing for a modernization effort. I suggest the following workflow:

Understand the drivers, goals, and phasing

This might seem like a no-brainer, but any vagueness about why we're doing this will lead to problems later. What is the primary driver and desired end state? Also, what is the migration strategy and general time plan? It might be far more complicated than it looks at first glance.

Discuss the scope, limitations and general requirements for the modernized solution

Regardless of how you facilitate the discussion, it's important to get a clear picture of what the modernized solution should look like and what the constraints and limitations are. This is the foundation for all the work that follows, so it's worth investing time to get it right. I've divided this work into the following categories.

Modernization Discovery Areas

Before you write a single line of new code, get clarity on each of these

🎯Drivers & Goals
  • Why are we doing this?
  • What is the desired end state?
  • Migration strategy & phasing
  • Timeline and milestones
📐Scope
  • Full rewrite or partial?
  • Which layers are affected?
  • Non-negotiables vs. nice-to-haves
  • Architectural constraints
🧩Complexity & Features
  • Feature inventory & user flows
  • Scale: screens, actions, rules
  • Complex workflows & forms
  • Feature parity requirements
📋Documentation
  • What docs exist today?
  • How current and accurate?
  • Tribal knowledge holders
  • API specs, data models, wikis
⚙️Code & Technology
  • Full code access?
  • Can you run & test it?
  • Test coverage & quality
  • Target tech stack & hosting
🗄️Data
  • Preserve or start fresh?
  • Schema access & samples
  • Migration scope & quality
  • Data flows & transformations
🔗Integrations
  • How many & how complex?
  • Traffic volume & patterns
  • Specs available? (OpenAPI, WSDL)
  • Replace, bridge, or keep?
🤝Co-operation
  • Stakeholder & user involvement
  • Who drives UX decisions?
  • In-house vs. outsourced?
  • Knowledge transfer plan
A summary of the key areas to investigate before starting modernization work.
Click to enlarge

In detail, you should be asking the following questions.

Complexity and features:

  • Can you produce a list of the features, user flows, integrations, and data flows?
  • Can you assess the scale of the system: how many screens, how many actions on each, complex forms or workflows, complicated business rules?

Documentation and knowledge:

  • What documentation exists for the current system? User manuals, technical documentation, API docs, data models, WIKIs, etc.
  • How up-to-date and accurate is the documentation?
  • Are there knowledgeable individuals who can provide insights into the system?

Architectural constraints:

  • What are the technical requirements the modernized system must meet?
  • Is there a preference for certain technologies, hosting platforms, IDP, and CI/CD pipelines?

Code, technology and hosting:

  • Do you get full access to the code, and to somebody who knows it?
  • Is it possible to run the code and test it?
  • Can we access a test system to explore and test?
  • Does the code have tests? Are they up-to-date and do they cover the critical paths?

Data:

  • Are we supposed to preserve the existing data and data flows, or is it possible to start with a clean slate?
  • Can we see samples of the data and the schema(s) of the databases?
  • What kind of data needs to be migrated?
  • Is the data up to date and good quality, or is the migration selective?

Integrations:

  • Are there integrations that need to be preserved? How many, and how busy and complex are they?
  • Is there an up-to-date specification of the protocols and data formats (OpenAPI, WSDL, etc.)?

Co-operation and involvement:

  • Involve the users and stakeholders in this discussion. What are the non-negotiables vs. what can be improved or phased out?
  • What is the end-user positioning: are they driving the general requirements, e.g. regarding UX? Will they be engaged in the process?
  • Is the customer maintaining the system themselves or is it outsourced? If outsourced, how is the relationship and knowledge transfer going to work?

Collect all materials and interview users, developers and maintainers

Once you've done the initial verification and have a good understanding of the drivers, goals, and scope, it's time to start collecting all the materials and information you can get your hands on. Insist on seeing the old system in action. It's worth a thousand PowerPoint slides. Meet the end users, developers, and maintainers to get their perspective.

If the old code contains a lot of rules and logic, get access to test systems to see the real starting point. There are usually surprises: a "simple" integration protocol turns out to be far more complicated than it looked, a plain VB form is actually a sophisticated calculation engine full of customer business rules, and so on.

You might think that any documentation is better than no documentation. It's not. I've been handed documents on continuous paper printed on a matrix printer as the "source of truth" for a legacy system. Judging by the looks, it was probably printed in the early 90s. The year was 2001. Make sure you assess how up to date all material you receive actually is.

Due diligence: assess the state of the old system

Now that you've gathered and assessed everything you could get, it's time for an honest assessment. Depending on the stated constraints, you have choices to make.

The first and obvious one, regardless of your belief in the superpowers of AI, is the GO/NO-GO decision.

If the entire thing is technically well past its prime, you weren't allowed to see any code, data, or the live system, the original developers retired twenty years ago, and there's no knowledge transfer whatsoever, you need to weigh the risk. At a minimum, have contractual guardrails for the surprises that will come after the project kicks off.

Perhaps that's an extreme case, but not unheard of. A healthy assumption, especially with anything written after the Agile Manifesto, is that there's no documentation whatsoever. That's been the case nine times out of ten in my career.

Certain areas require more due diligence than others. If I had to nominate the most important things to look out for, they'd be:

  • Integrations are often the most expensive and difficult things to migrate. Not only because they're usually the most complex and least documented, but they also involve several parties and systems.
  • Big bang vs. incremental modernization: be careful with both. You need either a very simple case or very good knowledge of what both strategies would really mean.
  • Unused features: chances are many parts of the old system aren't used at all or are single-user maintenance tools. IT might be unaware of that, so you need a proper walkthrough of everything to verify. Otherwise you'll waste time and effort on something not even needed.

At the end of due diligence, you've made a commitment and decision, and perhaps have already developed an idea of how the programme should commence. Let's look at that next.

Develop a solid, actionable plan

Once you've passed the GO gate for your program, you need a solid plan. I'm not going to turn this into a project management book, but I'll share some key things you'd want in your plan when modernizing an existing system.

  • Reserve enough time for careful inventory, research, and requirements analysis. It will pay off. No amount of GPU cycles thrown at reverse-engineering the old codebase will replace this effort.
  • Craft a careful strategy for what you expect to get out of the inevitable AI-powered static code analysis. A feature list? Something else? You'll get line counts, function call paths, perhaps some synthesis of them, but that's not going to be the specification of the new system. It'll just reflect the old.
  • Legacy code (especially VB forms and the like) might, however, give reasonable entry points, especially if you're just modernizing the UI layer with more or less the same actions and data. I've had some success with this kind of straightforward conversion, which does not mean 1:1 module or file mapping but taking the old code as a specification source.

The following diagram illustrates this synthesis model. Information from the old display or page you're modernizing and its code-behind are provided as supplementary context, useful for understanding what exists, but not the blueprint. The new UX design, architecture decisions, and user input on the right are the actual specification. The agent reads both sides but builds to the right.

Design-Driven Modernization

Supplementary — Legacy Artifacts
📸Screenshot
Visual reference of current UI behavior and layout
📜Old Code
Forms, code-behind, business rules — read, not replicated
📋Documentation
User manuals, glossaries, domain terminology and workflows
Primary — Design Inputs
🎨New UX Design
Modern interaction patterns, user journeys, wireframes
🏗️Architecture Design
Target stack, API contracts, component structure
💬User Input
Real needs, pain points, workflows that matter today
Agent-Assisted Synthesis, Planning, Implementation and Testing
Old code as context
New design as specification
Synthesis
Planning
Implementation
Testing

The agent reads legacy code to understand what exists, but builds to the new design — not a 1:1 translation.

Modern UI
Built from the new design, informed by the old — not a port of legacy semantics
Old code informs, new design decides. The legacy artifacts are context, not specification.
Click to enlarge

With this approach, I've already transferred some very complicated existing forms to a modern web-based UI. Think late-90s technology with large code-behinds, dozens of tables, filters, popups, parameter screens, and API calls wired together through complicated data structures. The idea was to extract the main data entities and actions from the old code, plan a component structure interactively using our design guidelines and a reference layout, and then forward that plan to the development and testing agents. What would have been at least a week-long effort not long ago took just hours. All this required careful planning, analysis, and tuning of the agents to understand the task correctly. And yes, a few trials and errors.

Beware of the legacy mirroring risk. Unless something very serious is wrong with the old system (like malfunctioning mainframe hardware), it's rarely worth just converting old code to another language or stack. If you ask an agent to summarize the old code, it'll do it. It won't magically produce a clean specification for a modern system.

Don't just copy the old system

As I've already suggested above, no IT system gets better just by rewriting it in some other language. It will be just as horrible with slightly better UX.

Software engineering, patterns, and architecture have evolved for a reason, and chances are your users' requirements aren't the same as they were 20 years ago. Sure, there have been sidesteps, even very bad ones (hello, CORBA), but things are just better nowadays.

So how do you ensure that your modernization effort is actually a modernization, and not just a rewrite of the old system? If there's a single point to take away, it's this:

Don't take anything old as a blueprint for the new. Things have changed, and usually for the better.

I sincerely believe that modernization of legacy systems, when orchestrated carefully, can be done at a fraction of the cost it would have taken just a couple of years ago, provided you do it with care and due consideration. AI assistance can make a real difference for organizations struggling with legacy systems. Even building your own solution vs. buying a product or SaaS is a viable strategy again.

Legacy code is context, not specification. Understand what the old system does, then design the new one from modern principles — not from the old architecture.