Vladimir Sarić wrote this on February 22, 2012
Doing code audit before improving software
Recently we received a request to analyze and improve a process in a Rails app which consisted of half a dozen rake tasks. While our standard practice is for a rake task to consist of a single line, usually a class method call that’s properly spec’d, these rake tasks had from 40 to 120 lines of code and almost no test coverage.
Making a correct estimate can be very difficult, sometimes even more than the actual coding, but when you are faced with code that’s full of smells and no tests, it’s practically impossible without a thorough analysis and even writing some meta code.
For starters, before any attempt was made at improving the code and making it more reliable, we were aware that we first needed to refactor. Martin Fowler defined refactoring as “a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior”. But why refactor when the rake tasks were already working? Why not just add or update a method? It’s simple. To begin with, it’s it was impossible to responsibly extend the code as it was. Refactoring allows us to more easily read, understand, update the code and write tests for it. Also, when the code is well written, it’s far easier to accomplish proper benchmarking and profiling.
Tools that we used for the analysis were:
Our workflow was pretty straightforward. We would use the pen and paper to better understand the current code by drawing sketches that visualized the various interactions in the process. After that, we would go line by line and whenever we saw a piece of code that was a candidate for refactoring, we would mark the corresponding lines on GitHub and reference it on WorkFlowy with a short message of what needs to be done. If we already had some meta code in mind, we would write a Gist containing the meta code and attach it to the message.
We decided to first just address the more standard code smells (long method, long parameter list, duplicate code, uncommunicative name…) and later on, when we start with the actual optimization, address the more complex smells that have to do with code structure and system architecture. Majority of the planned refactoring involved moving out pieces of code into a method or a class.
Our goal was to eventually be able to pull out the process into it’s standalone application, which would just send processed data back to the main application. With that in mind we tried to place most of the code into the ‘lib’ directory and make it as independent as possible.
Once we had a WorkFlowy list, which gave us a hight-level overview, we were finally able to create Pivotal Tracker stories and to give a time estimate.
Here are a couple of books that I found very useful when I was learning about refactoring: