This application was written without any knowledge of design principles (SOLID) by the previous developer. The most critical issue of the app is that it has god class with lots and lots of switch statements. This ill-advised structure makes it hard to maintain the app. Of course, there is no unit testing at all.
First on switch statements, I found there are two main potential classes that varies over the application. So I will try to first construct those two classes and move the corresponding code to the classes from the god class. Is this a right way? What is a good process to attack this issue?
BYW, I have the book "Working Effectively with Legacy Code". So you can suggest which part of the book I have to read for this too :-)
preguntado el 10 de marzo de 12 a las 14:03
What is a good process to attack this issue?
"don't fix it if it ain't broke".
The good process is to leave the issue alone until you HAVE to deal with it or unless you were ordered to refactor the code. It doesn't sound like this is the case in your scenario.
The rationale behind this kind of reasoning is quite simple: a sudden fit of perfectionism ("let's make it better, cleaner and shinier") might cost you next 6 months of your life with no reward of any kind (satisfaction doesn't count, because things like this quickly stop being satisfying enough). In the process you'll introduce multiple new bugs and probably break the whole system at least once, so there will be periods of time when you have large code base that doesn't work. The whole thing will increase the workload and might stress you badly which can result in bad health problems. Unless you were given the task of refactoring the code and a decent reward is guaranteed, supress the urge to improve the codebase "for the greater good" - thinking this way can badly backfire.
Put the whole thing under version control that allows quick branching/merging (git). Because you haven't mentioned version control, then by murphy's law I'll have to assume you aren't using it.
Concentrate on immediate bugs you have to fix. In areas you work with, improve code to make it fit your favorite style, but keep changes minimal, and do not touch anything that is not related to immediate problem. When you have bastante of free time if you feel like it, start implementing tests where it is necessary (contrary to popular belief, unit testing is not a silver bullet). Once you have some way to test that application still works, create separate development branch, and start modifying the code very slowly and only when you have time for that. Avoid merging changes back into master branch (that contains unmodified legacy code) as long as possible - until you're sure that everything works properly.
Keep in mind that your goal is not to make perfect code. Your goal is to provide fast and efficient solution for current problem using minimum amount of resources (time/effort), while getting maximum reward for your work. In my experience, deviating from this principle is extremely unhealthy.
Maintaining and improving existing los ancianos code base is roughly equivalent to rebuilding bottom floor of 3 foot tall card house. I.e. it is challenging, tedious, risky, but does not provide necessary level of emotional satisfaction. So unless there's a big reward of some sort, it makes sense to avoid doing this as long as possible. Code doesn't rot, so if existing works properly, there is no reason to modify it just because you don't like the look of current source code.
However, it would be a good idea to read the code and attempt to understand thinking of previous author and get better understanding of program structure. This might pay off in the long run.
Switches are an obvious refactor target. But there could be others. You give uslittle to go on.
I often spend a great deal of time massaging the code, rewriting it such that I can change the type used by commenting/uncommenting a few lines.
For a swich on an enum, it can be useful to define a struct that contains one member: the enum value, and has an implicit conversion to the enum value. Using typedefs or macro, you can make sure that your new type is passed around in stead of the enum. If that has undesired side effecs, revert, fix the implementation, and try to use yournew type.
Next, move the switch code to a member function of the new type, one switch at a time.
If unit tests are required in the process is up to you.