About to embark on the initial phases of a project to rewrite a legacy application from the ground up (existing business rules will change somewhat, and be extended to incorporate a large number of new requirements that the existing infrastructure cannot handle). I am looking for items that are important to remember when working to reengineer an existing application.
Write a suite of unit tests for the existing functionality first. When you do your rewrite, you can use this unit test suite to verify that your existing business rules still work in the new application.
Come up with an incremental transition plan. That is, make it so the project is always in a runnable state, transitioning from old code to new code without getting in the position of requiring effectively all of the new code to be written first before anything works.
There might be some things still done "the old way," while other features are done "the new way," and the user interface might be less than desirable for a while. But this approach will significantly reduce your risk, because you can always ship something. (Actually, if you have a gradual UI transition too, this might work nicely with Joel's notion of the Iceberg Effect: management/customers will see progress and have a notion of what remains to be done.)
This depends somewhat on the circumstances of your code base, but look carefully before deciding if this base is the exception to the rule or not, because it probably isn't.
- Understand what the existing code base is doing. In any old legacy application there may be a good number of special cases that users are expecting, be wary of these and only intentionally and rationally change existing behaviour.
- Coupled with 1. you must also test that the new functionality is doing what is intended (based off the understanding of what it is currently doing, or will be changing).
- If it is a large application or code-base, plan for the change to be incrementally introduced, this should mitigate the danger of one large release and show progress.
- Be especially careful if operating in an environment that is heterogeneous in versions of the software: beware file formats, network protocols, shared memory formats. Test and ensure compatibility between versions.
- If changing a data storage system, be prepared to mirror writes for a while into the new system to test load and gradually transition reads onto the new system while retaining writes into the old system. Once the new system is solid, add the new functionality.
Trying to come up with things not already said:
- Secure management involvement. Remember that the success of a high-risk project often depends on management buy-in. Make sure you have legit and active stakeholders who want this badly. If not, you may find serious roadblocks if you meet resistance to change, and when changing systems, you will meet resistance to change. In one project where we were moving people to a new system, all they could talk about was how much better the old system was. Management gave people a chance to get on board, and if there were serious dissenters, they were released. The sad truth is that there were parts of the old system that were indeed better (a long story that's too depressing for me to retell here) but because management was serious, the implementation team got the backing it needed.
- Secure a champion on the user side for the project. If the previous application's product manager is on board and actively involved, that's a plus. If not, an expert user that's respected in the community will be important. Demarco and Lister said something once to the effect of, "Every time a new system comes online, someone gains power and someone loses power." If a good leader on the user side is onboard with things, they'll potentially smooth the way for user acceptance.
- Treat the new system like a new project and have a really good analyst involved. That analyst might be a senior developer, but whatever, you don't want to make the mistake of saying, "Oh, this'll be easy, just do what the old system does, but better." The problem is that if the old system is anything like most of those in corporate America, then identifying exactly "what the old system does" might not be as easy as it sounds...there's probably outdated, if any, documentation, and lots of crufty old ways of doing things in the system that might not even be relevant anymore. Lots of times systems do things just because that's the way it was done in the old manual process, and you can save a lot of work and wipe out a lot of convoluted logic by removing unneeded complications. Sometimes the best code is the line you don't write.
- Look at the reporting component first. Reporting is often forgotten or left do finish as an afterthought, but this is losing out on a great tool for information. The old system's reports can tell you what the users needed most, and can be a good starting point for verifying what the new system's output should be. Be careful though to vet every report...probably some are not even used anymore.
- Step 1: Read http://www.joelonsoftware.com/articles/fog0000000069.html
- Step 2: Make other engineers in your office read Step 1
- Step 3: Don't make a strategic mistake
I really wanted to leave it at those three steps, but just in case someone took it as me being lazy, rewriting from scratch is almost doomed to fail. Incrementally adapting and refactoring code is the best way.
Lots of good answers so far. (I assume the existing system is either a hopeless jumble or coded on the wrong platform)
Here are my thoughts:
Build your test system!: Chances are the current project doesn't have one, and this is a great time to start out doing things right. This includes making the code easily testable as well.
Define success upfront: When will you know the project is done? Without this you could end up reproducing much of the original system, but get mired in 'just one more thing' additions to the functionality.
Say NO to synchronization jobs!: I spent 2 years of my development life cleaning up the mess these made in one company trying to run side-by-side systems. Poor planning and lack of business buy-in created these jobs and in the end significantly slowed the final development time.
One big thing to remember when rebuilding from scratch is domain knowledge. Companies often engage in 'complete rewrites' - using the most recent technologies and development projects to ensure the highest order of buzzword compliance - leading to dissappointing results because the people who knew most about the topic were not consulted with extensively.
There's nothing wrong with complete re-writes. Or mostly complete rewrites. There's a time and a place for them. Platforms change, technologies change... sometimes they just have to be done. But, they are best done under the guidance of the people who are the most expert at the topic - those involved in the previous implementation - for the best chances of a positive outcome.
There are a lot of good answers here that are really good points. There is one thing that I think is also important. Look at how technology has progressed from the point where the original code was written and what is out there now:
By all means, you must assess the existing code; unit test, plan, research, development, more testing. But you also have to take into consideration new technologies that may extend the lifetime of version 2.