DevOps methodology, tools, and techniques are increasingly being used to deliver customer-facing services that must integrate with core legacy applications. For teams responsible for building a robust end-to-end service across both worlds, this integration is one of the most persistent and underestimated engineering challenges.
The Reality of Legacy in Most Organisations
Unless you are working in a greenfield startup, your organisation almost certainly runs legacy systems that represent significant capital investment and underpin core business processes. Transforming those systems carries substantial risk and cost — and the appetite to do so is rarely strong enough to justify the disruption.
Modern cloud-native applications built with containerised microservices are not a natural fit with legacy systems developed using older, inflexible technologies and hosted in on-premises environments. But bridging that gap is exactly what most development teams are asked to do.
High-scale technology companies such as Google, Amazon, and eBay continuously re-engineer their entire processing pipeline and invest heavily in keeping their systems current. However, most organisations operate at a very different scale and with a fraction of those budgets. The lessons from those engineering giants are worth studying, but they are solving a different problem. Not every organisation needs — or can afford — the same approach.
A common pattern that has emerged is for organisations to adopt DevOps selectively: applying it to customer-facing services where speed and agility deliver the most immediate business value, while leaving back-office and core processing systems largely untouched. The customer-facing DevOps layer can respond quickly to new promotions, competitive pricing changes, or product launches. But it will almost always need to call into those legacy systems to complete a transaction.
Greenfield vs. Brownfield Development
In software development, a greenfield project is one with no existing constraints — you design and build from scratch. A brownfield project, by contrast, requires you to build around or on top of what already exists. The term is borrowed from urban development, where new construction often takes place on land previously used for industry.
Most DevOps transformations take place in a brownfield context. Legacy components impose data definitions, business rules, and integration contracts on any new development. If a system is too risky or expensive to replace, it is typically the system that defines how the business actually holds and processes its most important data. Failing to understand that reality early leads to a painful integration phase later.
Adopting a Hybrid Approach
When one or more DevOps squads are tasked with delivering a service where a significant portion of the functionality is provided by existing legacy components, the first priority is to understand the constraints those legacy components impose.
This is harder than it sounds. Legacy systems are often retained precisely because nobody fully understands them. Knowledge is concentrated in a small, experienced support team. Documentation is typically incomplete, outdated, or both. Do not assume otherwise.
A realistic hybrid approach acknowledges these constraints and builds process around them. The following sections outline the key areas to address.
Produce an End-to-End Architecture
Before writing significant new code, map the integration points between the components your team controls and the legacy components you do not. Treat those integration points as third-party APIs — but with considerably more complexity than a typical external API. These are the systems the organisation was too afraid to touch. They will require deeper investigation and more careful handling.
A practical example illustrates the risk well. Suppose a registration process requires a date field. Your new service applies a straightforward business rule to that field. But what if the legacy system has been silently accepting a default placeholder date for years — because a contact centre team found it easier to enter a fixed value to avoid an obscure validation error? When your new service enforces the rule properly for the first time, you may discover thousands of existing customer records that do not conform to the rule you thought was already being applied. The integration breaks on day one for a large percentage of real users.
This kind of hidden behaviour is common in legacy systems. Exploratory testing on the legacy components — combined with working closely with the support teams who know them — is essential to surface these issues before they reach production.
Document the End-to-End Journey
Agile rightly emphasises collaboration over documentation, but the complexity of legacy integration demands that constraints are captured clearly and shared across all development squads. If a behaviour is a constraint imposed by the legacy system, it is not negotiable — it must be understood and designed around.
Consider a short architectural sprint at the start of the programme to investigate legacy behaviour, document integration contracts, and identify risks. This upfront investment reduces surprises during development and testing. Any constraint discovered and documented early is far cheaper to manage than one found during user acceptance testing or, worse, in live service.
Once the behaviours and constraints of the legacy components are understood, that knowledge should be shared explicitly with all squads contributing to the service — not assumed to be common knowledge.
Account for Data Latency Across the Service
Many legacy systems use batch processing strategies to optimise performance: updates are queued during the day and processed during overnight batch windows. This creates data latency that can be invisible to a newly developed service designed around real-time interactions.
Consider a scenario where a customer completes an application through a mobile application. The new service confirms success immediately to the customer. But the actual provisioning of that service on the legacy back end is dependent on an overnight batch job. If the batch fails or is delayed, the customer experience and the downstream state diverge. This latency must be accounted for explicitly in service design, in the user experience, and in the testing strategy.
Overnight batch cycles also place hard constraints on end-to-end automated testing. Tests that depend on legacy state changes may take hours to complete a single cycle, making them impractical for continuous integration pipelines.
Testing, Automation, and Continuous Testing in a Hybrid Environment
Testing an end-to-end service composed of modern microservices and legacy components is one of the most technically demanding aspects of this type of programme. The two halves of the service have fundamentally different testing characteristics.
The modern DevOps-developed components can typically be tested through automated unit, integration, and contract tests, and continuously validated within a CI/CD pipeline with relatively little friction.
Legacy components introduce constraints at multiple levels:
- Environments: Legacy test environments are typically shared across multiple development and support teams. Availability windows are limited and coordination is required.
- Test data: Data in legacy test environments is often difficult to set up, slow to refresh, and shared — meaning one team’s test can corrupt another team’s data state.
- Batch dependencies: As described above, state changes in legacy systems may only take effect after an overnight run, making rapid test iteration impossible for certain scenarios.
- Fragility: Legacy systems may have undocumented behaviours that cause intermittent test failures, generating false negatives that erode confidence in the test suite.
A risk-based testing strategy is necessary. Consider stubbing or virtualising the legacy component for the purposes of automated testing of the modern layer. This allows your CI/CD pipeline to continue functioning without a live dependency on a fragile shared environment. Dedicated end-to-end integration testing against the actual legacy system can then be scheduled less frequently, in a controlled manner, with acceptance that it will be slower and harder to maintain.
No approach will be perfect. The goal is to identify and agree on an honest, risk-based testing strategy that all stakeholders understand — rather than attempting to apply a continuous testing model uniformly across components that cannot support it.
Key Principles for DevOps and Legacy Integration
- Invest in discovery early. Run an architectural spike or discovery sprint before main development begins to understand legacy behaviour, data contracts, and constraints.
- Treat legacy systems as complex third-party APIs. Define the integration boundary clearly. Do not assume the legacy system will behave as the documentation (if any exists) suggests.
- Work directly with legacy support teams. Their domain knowledge is irreplaceable. Build a working relationship with them from the start of the programme.
- Use exploratory testing on legacy components. Automated tests cannot discover what you do not already know. Manual exploratory sessions on legacy systems surface hidden rules and behaviours.
- Design for latency. If the legacy system uses batch processing, the service design and the user experience must accommodate delays in state propagation.
- Document constraints explicitly. Constraints imposed by legacy systems are not up for discussion. Write them down and share them across all squads.
- Apply a risk-based testing strategy. Continuous end-to-end testing against live legacy environments is rarely achievable. Stub where you can, integrate where you must, and be explicit about what is and is not covered.
Conclusion
Building new DevOps-driven services that integrate with legacy components is a common, difficult, and often underestimated challenge. Each integration is unique — the constraints you will encounter depend on your specific legacy systems, your organisation’s risk tolerance, and the nature of the service being delivered.
The teams that handle this most effectively are those that invest in understanding the legacy estate before they begin building, document what they discover, share that knowledge across squads, and apply a realistic testing strategy that accounts for the fundamental differences between modern and legacy components. Doing the hard work upfront will not eliminate all the difficulties — but it will significantly reduce the number of surprises, and greatly improve the chances of a successful delivery.