Refactoring and removing.
Deleted code doesn’t contain bugs, they say. I always felt kind of unsafe with the idea of actually and straightforward removing code while into refactoring smaller or larger parts of the systems – after all, same as it doesn’t contain bugs, deleted code also doesn’t contain business logic anymore which might not be what you want at times. Yet, trying to clean up parts of (the Java / Java EE based) components in our system, I have to some degree changed my mind about that.
Even more, throughout the last bunch of weeks I got used to work right the other way ’round and indeed start out right there – even before touching anything else, clean up and try to remove as much of the code as somehow possible before going any further. In our system, this ain’t difficult. Period.
There’s an inherent tendency to get prototype solutions and “small hacks” in place, some made to stay for years, some to vanish sooner or later, eventually to be replaced by a better, more general solution, to be reworked in this way or the other or to simply be axed because, ultimately, they served a purpose too limited in its scope to really keep maintaining these. And, overally, there’s evidence of those solutions throughout all of our code base, as in most situations, interfaces or interface methods declared and implemented to serve a certain purpose within the scope of some prototype have a tendency to still be kept in the code, eventually be
@Deprecated. Most of these methods, indeed, are by then deprecated because, left in place in case they might be needed then and now, they aren’t likely to be maintained very well because they usually aren’t used anymore. Possibly this is the best case however. A situation way worse is such methods being referenced by just one or two other consumers throughout the code (maybe fragments of yet another prototype which made it to stay in production), requiring modestly complex refactorings each of the time the code is touched (and maybe simply because they represent a slightly different semantics than the rest of the interface or implementation) for virtually nothing.
Until just a few weeks ago, I was likely to leave all this crap in place, eventually (as stated) let it be
@Deprecated or decorated with
//TODO remove this!!! comments throughout the code. I stopped doing so after, all of a sudden, running into a situation of having two “here be dragons” beasts of methods, one being the only method depending upon the other, and both providing enough (implementation) complexity to leave one with the expectation of pain even while just thinking about touching either of these. Beauty, it is not. By now, I once in a while would have messed with both of these just enough to keep them in place until touching the code again. This time, they both ended up being artifacts in the SVN history of the corresponding classes. Along with these, most of my interfaces (and implementations) were subject to drastical pruning, at times removing almost half of the methods exposed which prove either completely unused by any remaining logic in the code base or being superseded by a better / different implementation. Work has become somewhat easier, and overally, I just wonder why I didn’t start out doing so way earlier – given the SVN repository will keep track of all changes anyway, there’s no real need to keep obsoleted fragments of code around longer than strictly required. Deleted code does not only introduce no bugs, it also doesn’t require work to be rebuilt all along the way.
Getting into things again
But maybe even more than cleaning things up, for my working habits I learnt that this path is utterly helpful to again get into code I haven’t touched in months, or even years in some cases. In such situations, with a few unit and integration tests in place and yet a 100% test coverage being more than just a friendly illusion, I then and now experience a load of time to pass until I managed to again and completely understand how a piece of the system was designed to work, how this design actually has been implemented, how all the different gears go together to get something meaningful done. I have no clue why, but the last couple of weeks I had to learn that, at least for me, dealing with this is by magnitudes easier all along the lines of finding (and ultimately removing) unused code. Maybe it’s just the effect of once in a while massively cleaning up (which usually also involves removing classes not longer needed anymore, or removing redundant implementations of things for making the environment a bit more sane in terms of choice of technologies – similar to dumping Java servlets instead of using JAX-RS / Jersey resources because Jersey is heavily used throughout the context and the JAX-RS API is quite a bit more convenient and elegant than the core servlet API. It’s a matter of cleaning, and it ends up at least with the perception of having improved code quality of the whole system, and be it just a bit.
What about it, ultimately? I’m not sure. 🙂 It’s just been an insight which, even though I should have known, came a bit of a surprise in terms of making day-to-day work a bit more effective – just as long, of course, as there is some kind of development and testing tooling around to be capable of doing refactoring, after all. But that’s another, way less shiny story…