Pillar page
Legacy System Modernization
Incremental monolith-to-microservices refactoring, migration from outdated technologies to modern stacks, cloud migration — without business downtime, with a rollback plan and complete audit trail.
Every company has some legacy system. Some have several. An accounting application from 2008 that somehow still works. A CRM written by consultants nobody remembers anymore. A warehouse running in Access. Each of them will need to be replaced eventually — the question is not whether, but when and how.
Legacy system modernization is one of the hardest types of IT project. It requires balancing three forces: business continuity (the system must keep running the entire time), introducing modern technologies (microservices, cloud, AI), and risk control (every refactor can break something that has worked for years).
Why not just „rewrite from scratch"?
From our experience, 9 out of 10 successful modernizations are incremental refactoring, not rewrites. Rewrites are conceptually tempting („we'll start with a clean slate"), but in practice they have three fundamental problems:
- Invisible business logic. The old system contains years of business rules — special conditions for the largest customers, tax exemptions for specific industries, workarounds for 2015 regulations. Most of it is undocumented. A rewrite has to recreate all of it from people's memories or code analysis.
- Duplicated work. While the new system is being written, the business still demands changes in the old one (regulations, new customers, small bugs). The team either duplicates the work (changes in two places) or freezes the old system (business risk).
- Big bang deployment. After a year of work, the new system is „almost ready". Switching all users in one night generates monumental risk. Any unexpected problem means going back to the old system, losing team morale and eroding business trust.
Incremental refactoring (usually following the Strangler Fig pattern) solves all three: business logic is discovered gradually, one source of truth for each entity, deployment in stages with feature flags.
Six modernization patterns
Each one addresses a specific risk. In most projects we combine several, choosing a pattern per module.
Strangler Fig
Gradually „wrapping" the old system with new components. Old code still runs, but every new feature goes to a new microservice and existing modules are replaced one by one. After 12-24 months the old monolith is switched off.
Anti-corruption layer
An adapter protecting new code from the quirks of the old system (unreadable field names, weird date formats, inconsistent types). All the „ugly" logic is isolated in one place — new code operates on a clean domain model.
Database refactoring
Patterns from Refactoring Databases (Ambler/Sadalage): expand-and-contract for schema migrations, data validation before dropping old columns, running both schemas in parallel during application migration.
Branch by abstraction
Introducing an abstraction layer around the old component, implementing the new component in parallel, gradually switching traffic from 0% to 100% (feature flag). Without a „big bang" deploy.
Shadow mode
The new code runs alongside the old one — both process the same requests, but only the results from the old system reach the user. Results are compared offline. After confirming compatibility (typically 2-4 weeks) we switch traffic to the new code.
Event sourcing for migration
We record the stream of business events from the old system and replay it in the new one. This allows preliminary validation of the new architecture without production risk, and the ability to return to any historical state.
Typical modernization roadmap
For a mid-sized system (a monolith of ~200k lines of code, 5-10 business modules):
- Month 1: Discovery and documentation. Reverse engineering the architecture, mapping dependencies, identifying data flows, documenting business processes with help from business stakeholders.
- Month 2: Target architecture and pilot. Designing the new architecture, technology selection, pilot on the simplest module (proof of concept). First validation of the approach.
- Months 3-4: Carving out the first production module. Strangler Fig pattern, shadow mode for 2-3 weeks, traffic cutover, hypercare. First real business value.
- Months 5-12: Iteratively carving out subsequent modules. Each in a 4-6 week cycle: refactor → tests → shadow → production → hypercare. Continuous improvement of the process, reducing time per module.
- Months 12-18: Data migration and monolith decommissioning. Once all critical modules are carved out, we finalize the historical data migration, switch off the old system, archive. Celebrate.
Legacy system vs. modernized
| Aspect | Legacy system (typical) | After modernization |
|---|---|---|
| Time to ship a new feature | 4-8 weeks (high regression risk) | 3-7 days (automated tests minimize risk) |
| Test coverage | 5-15% (or none) | >80%, in the CI/CD pipeline |
| Developer availability | Low (outdated technology) | High (popular, modern stacks) |
| Security | Old libraries with unpatched CVEs | OWASP scanning, gitleaks, automated updates |
| Scaling | Vertical (more resources for the monolith) | Horizontal (scaling specific microservices) |
| Observability | Logs in files, no metrics | Prometheus + Grafana + Sentry + SIEM |
| Compliance (GDPR, EU AI Act, ISO 27001) | Demanding, expensive to prove | Built into the architecture, audit-ready |
Six typical risks — and how we address them
Risk: No tests in the legacy system
Mitigation: First we build characterization tests (capture tests) — recording the current system behavior based on production logs and traffic captures. Only then do we start refactoring, with tests as a safety net.
Risk: Knowledge concentrated in one person („truck factor 1")
Mitigation: Knowledge transfer starts in the first week of the project. All meetings with the person who knows the system are recorded and transcribed, key processes documented, architectural decisions justified. After the project the whole team understands the system.
Risk: Temporary team slowdown
Mitigation: For the first 2-3 months the team maintains the old system + builds the new one. A natural slowdown in change velocity. We mitigate it by: prioritizing changes that go only to the new system, freezing low-priority changes in the old codebase.
Risk: Data migration
Mitigation: Every data migration has three phases: dry-run (on a production copy), staging (in test environment with real-scale data), production (in a service window or incrementally). Rollback plan ready before start.
Risk: Organizational resistance
Mitigation: Communication with the business from day one: why we modernize, what changes for the user, what's the schedule, how we measure success. The first iteration is chosen to quickly show tangible value (e.g. a new UI or a faster report).
Risk: Cost underestimation
Mitigation: Discovery (1-2 weeks) before project pricing. 2-3 week iterations with concrete deliverables — easier to correct course than in a long „all at once" project. Budget with a 20-30% buffer for the unexpected.
Frequently asked questions
What is a legacy system?
Why modernize if the system works?
Isn't it easier to rewrite everything from scratch?
Does modernization require business downtime?
How long does a typical modernization take?
What technologies do we migrate from most often?
What about existing integrations with other systems?
How do you reduce business risk?
What about the system documentation that doesn't exist?
How does modernization cost compare to maintaining the old system?
Let's start with an audit
A one-week technical audit: mapping the current state, identifying the most urgent modernization areas, a phased plan with concrete business outcomes in the first iteration.