
Many organizations depend on software that is hard to change: a COBOL or C++ system that runs payroll or billing, an aging .NET Framework application nobody wants to touch, or a PHP application that grew one feature at a time for fifteen years. The tempting answer is to rewrite it from scratch. That is also the riskiest answer. This article explains why, and how to modernize incrementally instead.
Signs it is time to modernize
- Small changes take weeks because nobody is sure what else will break
- The platform, language version, or database is out of vendor support
- Only one or two people understand the system, and they are close to retirement
- Security patches cannot be applied without major work
- Integrations and reports depend on manual exports and re-keying
- The system cannot meet current accessibility, security, or audit requirements
Why big-bang rewrites fail
A full rewrite has to reproduce years of business rules, many of them undocumented, before it delivers any value. The old system keeps changing while the new one is being built, so the target moves. Users see nothing for a long time, budgets run out, and the cutover becomes a single high-risk weekend. Many rewrites are abandoned partway, leaving two systems to support instead of one.
The incremental alternative
The approach often called the strangler pattern replaces a system one piece at a time. New components take over specific workflows behind the existing interface, traffic shifts to them gradually, and the old code is retired once nothing calls it. The system stays in production throughout, and each step is small enough to test and reverse.
1. Assess and map
Document what the system actually does: modules, data, integrations, scheduled jobs, and reports. Capture the knowledge in people’s heads while they are still available. Identify the areas with the most change, risk, or cost, because those are usually the best place to start.
2. Make change safe
Before changing behavior, put automated tests around what the system does today, including its odd edge cases. These characterization tests are what let you change code with confidence.
3. Create seams
Introduce a boundary, such as an API layer or a routing point, where a request can go to either the old code or the new code. This is what allows gradual replacement.
4. Replace in slices
Move one workflow at a time to the new platform, often C#/.NET in our work, starting with the slice that delivers the most value for the least risk. Release it, measure it, and move on.
5. Migrate data deliberately
Script conversions so they are repeatable, run them many times before cutover, and reconcile record counts and totals against the source. Plan for a period when both systems read or write the same data.
6. Retire the old code
When nothing calls a legacy module anymore, remove it. Retiring code is how modernization actually reduces cost and risk.
Planning and budgeting in phases
Incremental modernization fits public-sector and enterprise budgeting well. Each phase has a defined scope, a working result, and a decision point. If funding stops after phase two, you still have a better system than you started with, rather than half of an unfinished rewrite. For agencies, phased work can also be procured in smaller, lower-risk task orders.
When not to modernize
Sometimes the right answer is to replace a custom system with commercial software, or to leave a stable system alone and wrap it with a modern API. A good assessment should say so. Modernization is a means to lower risk and cost, not an end in itself.
How we help
SiteHatchery’s principals have spent two decades building and modernizing enterprise software, including public-sector financial ERP written in COBOL, C++, and C#, and a high-volume commerce platform modernized while it stayed in production. See Application Modernization, or talk to us about your system.