This is a continuation of the earlier post on design techniques when refactoring legacy systems. This post talks about backward compatibility and
Keep backward compatibility in mind
If there is one thing that is tricky about refactoring legacy assets it is backward compatibility. Although this isn't often talked about this is a very critical aspect. Creating abstractions, loosening tight couplings, and creating wrappers are all good practices but unless your change guarantees no harm you might be stepping over landmines. A lot of pain can be avoided if you take this into account. Backward compatibility is a simple goal but isn't always easy to achieve. Here are some things to think about:
• You will need to make sure that you don't leave legacy data sources in any invalid state after the refactoring changes
• In most cases you cannot save new data values into legacy database tables. Legacy data values could have hidden, implicit, or multiple meanings that are hard to fix in a single iteration or even few iterations. The best thing is to keep chipping away slowly and opportunistically.
• The changes you make to legacy components cannot break inbound or outbound data feeds, batch jobs, or terminal emulations. I have sat through some tense meetings when things break and there is financial or reputation risk involved. Add tight time windows to correct and reprocess batch jobs this is something you want to be absolutely sure about.
• Ideally you want no consumer to directly call a legacy module. You should consider yourself lucky if you happen to be in such an environment.
Minimize point to point interactions with external systems
If legacy modules are sending data to external systems - this could be via remote terminal emulations, messaging, batch jobs, or FTP - you can introduce an abstraction layer that will break this link. The abstraction layer might need to wrap these legacy assets before you can use them but this has several benefits.
Although these practices seem straightforward you should never refactor in isolation. You most likely won't have a set of automated regression tests for your legacy application. Before making changes to your legacy code you need to be sure that new defects are not being introduced. The straightforward way to do this is using test driven development. You should:
- Create a unit test
- Run and watch it fail
- Make the change to the legacy asset
- Re-run the test to watch it pass (if not make the change, run the test, you get the idea!)
Repeat these steps for all the identified refactorings. At this point ensure that your reusable asset is integrated from the legacy app, the source code control repository is up to date, and the relevant automated tests are included in your regression test suite. You might be tempted to declare victory but resist the thought. Now you need to map out how you want to package, deploy, expose, and support this asset. For example, in the java platform the asset could be packages as a JAR. If this is a service, it could be SOAP over HTTP web service or available over JMS for queue based integrations. The key thing is that you identify the mechanics and decide what your strategy is for consuming the reusable asset.













Leave a comment