Avoid common pitfalls when replacing legacy systems

As agencies continue to implement customer experience mandates, there is a growing need to modernize legacy systems to better meet the changing needs of their users.

This is a critical foundation enabling progress towards building responsive, human-centric government services. However, many contracts for replacing large legacy systems are still based on long-term blueprints, fixed timelines, and other outdated assumptions that discourage modern software delivery practices.

With that in mind, we’ve outlined three…

read more

As institutions continue to implement Customer Experience Executive Orderthere is an increasing need to modernize legacy systems to better meet the changing needs of users.

This is a critical foundation enabling progress towards building responsive, human-centric government services. However, many contracts for replacing large legacy systems are still based on long-term blueprints, fixed timelines, and other outdated assumptions that discourage modern software delivery practices.

With that in mind, we’ve outlined three common pitfalls practitioners experience when working with institutions to replace legacy systems. We then offer specific, actionable suggestions that can mitigate each situation. By implementing these recommendations, teams can prioritize delivery success throughout the planning process, even before development work begins.

Pitfall 1: Underestimating Legacy Systems

Legacy government systems are large, built over years and decades, use outdated user interfaces, use technology that is no longer supported, and require cumbersome workarounds for core functionality. There are cases. If it doesn’t look impressive, it’s tempting to underestimate the actual results.

However, existing legacy systems typically have extensive specific functionality that must be present in new systems, even after omitting obsolete functionality. This may be dictated by a project contract, the system the software needs to run on, or a critical task the user needs to be able to do. New systems can often be better implemented, but certain features must be maintained.

Build new functionality while maintaining key legacy functionality

Teams sometimes think that replacing critical parts of legacy systems without adding new functionality is a failure. They believe that creating a usable version with clean, extensible, tested, and easily deployable code and architecture is difficult to deliver and allows for future updates and maintenance. It misses the fact that it has value in itself. The urge to focus on new functionality is well-intentioned and often leads to good high-level ideas, but those ideas are most successful when repeated within a functional system. I guess.

As a result, government agencies should not ignore legacy systems in their requirements gathering. Users are subject matter experts in current systems, but the reality is that learning the ins and outs of large legacy systems can require a variety of sources of information, depending on what is available. It often happens. These include:

  • User interview
  • system documentation
  • User training materials
  • Using exploratory apps
  • application code

Understanding the details of legacy systems helps teams complete the functionality they need and minimizes the risk of last-minute surprises.

Agencies should prioritize key features first and iterate additional changes from there to ensure that all required features are complete and delivered. This will give you a clearer understanding of your business rules and system constraints, allowing your team to implement the next “nice-to-have” feature.

Pitfall 2: Relying on large, infrequent deployments and releases

Government projects can rely on large and infrequent deployments and releases despite increased risks to system stability, user experience, and flexible services.

Code is considered “deployed” as soon as it is moved to production. Deploying small, frequent splits to production is beneficial because changes are smaller, less complex, have fewer dependencies, and have fewer interfering systems, limiting risk. As a result, changes often require less downtime and fewer rollbacks.

Similarly, code is “released” when it is made available to end users. Releasing code to users frequently is beneficial because it isolates high-risk features, enables rapid feedback loops, and corrects project direction if necessary. Code deployed to production can be released immediately, selectively released to only a subset of users, or hidden by feature flags for future releases.

Even legacy systems with established active user bases that rely on full workflows can be functionally replaced in smaller segments. The feasibility and implementation of these ideas vary widely based on the specifics of the project, but government agencies often overlook opportunities to intentionally structure projects to enable early and frequent releases.

Increase frequency to minimize risk and increase flexibility

Martin Fowler I wrote an article in 2004 A safer way to replace critical legacy systems is to build new apps around them, allowing them to grow over time until they are no longer needed. While the details of this approach vary and require careful planning and prioritization, many examples It shows success in enabling early and frequent releases.

In addition to finding ways to run old and new apps side-by-side during development, you should focus on building features by releasing early and often. vertical slice It contains functionality for all layers of the app. Instead of building dozens of UI components with mocked-out backend functionality, build a complete feature that includes frontend, backend, auth, logging, deployment, etc. and can be shipped together. to

This approach also helps agencies gain an early understanding of all layers of the system, enabling better team decision-making on other parts of the app. Many projects have specific backend system complexities and limitations (integration with dependencies, databases that must be used, schemas that cannot be changed, etc.) and these realities limit what teams can do. is often If those realities are not discovered until later in the project, significant rework may be required.

Pitfall 3: Delaying or ignoring basic software delivery practices to meet deadlines

All teams experience unforeseen problems or something that takes longer than planned. They want to deliver, so find an easy workaround. However, doing so may cause you to skip important steps in the process.

Disruptions to basic software delivery practices such as testing, addressing technical debt, and dealing with error scenarios can be infrequent and have no impact on a project. However, doing this too often or continuing without resolving the issue can have a significant impact on the stability and development speed of your app in the future.

Test your code throughout the process

If your team is in a rush, the urge to add tests later can be strong. But trying to backfill tests is harder and less effective than writing them halfway through. Context is important for understanding edge cases that need testing, so it’s easier and more effective to do this during development when the information is fresh.

Additionally, code architecture is a big part of testability. If your code isn’t built to be easily tested, it may need refactoring before your team can write tests. However, refactoring an untested codebase increases the risk of unintentionally breaking functionality. Also, refactoring an established codebase takes longer than a small section of code. And once patterns are established, they tend to continue. By establishing testable patterns instead of doubling down on hard-to-test patterns, the whole process becomes easier and less time consuming.

Developers may be hesitant to refactor code they don’t understand (even if it’s necessary). These effects are exacerbated in large projects and high turnover projects, as many people may have written the code, including those who are no longer able to provide context. The pressure to deliver doesn’t diminish over time, but the team’s ability to deliver diminishes as code becomes harder to maintain and develop.

Dealing with technical debt

In addition to writing good tests, it’s important to be disciplined about: Continuously work on technology debtSome teams intentionally set aside a percentage of sprint points for technical debt tickets. Others include their efforts in prioritizing all work as a whole. The key is to find a workable approach and hold the team accountable.

Technical debt is a normal part of the development process, but agencies may not understand it or think it reflects poor quality. Openly discussing the process and benefits of dealing with technical debt can help mitigate these misconceptions.

A resilient system accounts for edges and error cases and handles them gracefully. A project that tries to move quickly by considering only happy path scenarios can quickly destabilize and give the illusion of progress. Any form that accepts user input should be validated and provide useful feedback if the information provided does not meet the criteria.and the team Don’t assume your data is cleanBugs in legacy apps and different validation rules can result in unpredictable data. New code must be intentionally treated to avoid inevitable problems.

Legacy Systems and Customer Experience

Identifying the pitfalls and recommendations above will help your team address common challenges when trying to replace legacy systems. This list is by no means exhaustive, but avoiding these common pitfalls can lead to more efficient systems that benefit both the teams that maintain them and the public that depends on them. Maximize your chances of a successful migration.

Saul Rodriguez Director of Engineering at Ad Hoc, a digital services company focused on federal government. Avoid common pitfalls when replacing legacy systems

Back to top button