The application is in the Open Channel Flow simulation (physics simulator), it simulate the propagation of a wave by solving the one-dimensional St-Venant equations. We want to upgrade the application by integrating new data structures that represent more closely mathematical abstraction and algorithm (code was written longtime ago and it’s using some old C-array). Numerical algorithms are tied together make it hard to add or modify. In this kind of applications we need flexibility at algorithm level. In real life project, there are many situations where we may want to try another algorithm on-the-fly, code must be able to adapt to new change quickly. In the meantime we upgrade to C++11 that bring lot of new features that make the code cleaner and easier to understand.
There are a lot of issues with this code making it harder and harder for us to make changes, but I see the three biggest issues being:
- Many of the functions do more (way more) than one thing;
- Very hard to understand (no separation of concerns);
- We have global variables and global state up;
Refactoring pose some problem and one of them its data integrity and behavior. The main difficulties that we face at the beginning, it doesn’t have adequate automated tests. The lack of tests is a problem in itself (there is some validation test). Refactoring without tests is dangerous with all the details we must keep straight, a mistake is easy to make.
The most common form of protection is good unit-test, because that makes it almost impossible for someone to undo your good work without knowing about it right away. Unit tests give you instant feedback at a very local level. They can be run after every change you make and it takes seconds to find any error. This is vital to allowing a programmer to continuously refactor with confidence. I can make a small change to improve the code and know almost instantly if I have broken anything. Also it is part of documenting this knowledge in separate tests.
Here is a legacy code change policy:
- Test-drive new code;
- Add tests to legacy code before modification ;
- Test-drive changes to legacy code;