Recently I’ve had the opportunity to work on a project beginning in a curious state.
An offshore team had failed to deliver and we were brought in by a client to “fix and complete” a rather large code base within a fairly aggressive timeline.
My initial instinct was to treat the code fairly conservatively, to avoid deviating from the existing pattern, get it working, and then re-evaluate, refactor, and clean up the code base. There was a large amount of copy-paste throughout resulting in a lot of duplicated code. A large portion of the system didn’t work at all and a lot of new code would still have to be added.
My instinct was to treat the system as legacy code, avoid large scale changes until the entire system was well-understood, and apply a “red, green, refactor” type of approach on a larger scale across the system. We were currently in the “red” state.
I had the opportunity to work with a new team member, @stephenvisser, who was much more interested in approaching the system in a more aggressive manner – do a refactor first, minimize the code base, flush out some reusable components and then make it work. Initially I was a bit hesitant on this approach given our timeline, as I believed it could cause some up-front re-work of pieces that may have already worked and introduce some risk.
He was quite persistent and we eventually agreed to pursue this direction. We had a lot of code in need of some love. A depressing mess.
We started extracting some components, cleaning up existing code, and patterns started to evolve. Some time passed and we had almost halved the code base, removed duplicate code, and were now progressing much faster with new functionality than could have been possible in the old code base. It was actually becoming fun to fix old code, often times removing 75% of the mass of a function or class.
I had to concede that although a more conservative approach may have eventually yielded a similar result in the end, we certainly could not have been as efficient – and we would have had to work with a messy, bug-riddled, copy-pasted code base for a slightly longer period of time.
Through working on this project, I started to ponder a few things in more depth:
– Forget ego. Teams need to be able to discuss, debate, and move forward together on solutions. Don’t get stuck on your initial opinion just because you’ve done it before. If you’re willing to try an approach that’s new to you, you just might learn something.
– Sometimes learning isn’t just about adding new techniques, technologies, it can also be about re-evaluating what you think you already know and learning more about when it’s appropriate. Sometimes there’s more than just knowing a solution to a problem, we also need to fully understand the pros and cons and when one method might be more advantageous over another in a specific situation.
– Technical debt sucks. I’ve always been a fan of refactoring after, but refactoring out a mess initially, cleaning house before tackling a problem, can provide immense value. If the code base makes you sad, clean it now. If you can constantly be proud of what you’re working on, you’ll be more likely to own it and continue working to make it the best you can.
If you’re working in someone else’s mess, it might be easy to find reasons not to clean it… but as professionals, we need to focus on making everything we touch better than it was initially, no matter who created it. Managers and peers can sometimes underestimate the advantages of clean code, the advantages to maintenance, reducing complexity, and in turn the reduction in the likelihood of bugs.
I for one am enjoying thinking of clean code and our integrity as developers from a slightly more aggressive angle. I always enjoy working with others that bring new perspectives and ideas to the team. Thanks @stephenvisser for making this project more enjoyable!