In a previous post I talked about how my team has a daily metrics build that reports on our code quality. One of the things we measure is the Flog score of our methods (Flog is a ruby program that evaluates the complexity of your methods). We have a standing developer task to look at the top five worst methods in our application and reduce their complexity. Every iteration we try to spend some time looking at a few developer tasks, which are things that don't provide any direct business value but do make our code better, automate some manual process, or fix some technical problem not tied to a bug.
Yesterday Chirdeep and I refactored the worst method in our app and while it wasn't easy it produced a number of benefits:
First, about halfway though the refactoring we came upon some twisted logic that seemed as if it could never evaluate to false. After pulling in Ali for some consultation, we realized that indeed it would always be true and therefore was a bug. We fixed it and moved on.
Second, we noticed that the object inherited from another object, but overwrote the constructor with a strange one that took different arguments. This had the effect of making other objects interact weirdly with this class in order to deal with its 'sorta' inheritance. We managed to get rid of the custom constructor and have it rely on it's super class.
Finally, we noticed a nice clear division of labor in the complex method so we were able to extract a method that had a single responsibility. So we ended up with two methods that shared the complexity of the original one.
I would have been happy if all we accomplished was the last item. However, when you take a look at your most complex methods you often find bad stuff hiding amongst the craziness.
It's also important to note what we didn't do:
We did not simply extract out every 5 lines into a method. While that would have improved our Flog score per method, it would been the code equivalent of sweeping dirt under the rug. Methods should, as much as possible, have a single responsibility. If they don't then all you're doing is moving a bunch of complex stuff into many different arbitrary places, instead of just one place. Which is actually worse. So, like all metrics, complexity is something to pay attention to but you don't want to slavishly chase after good numbers.
Subscribe to:
Post Comments (Atom)
About Me
Obtiva (current job)
ThoughtWorks (old job)
Object Mentor (apprentice)
Apprenticeship at Object Mentor Blog
ThoughtWorks (old job)
Object Mentor (apprentice)
Apprenticeship at Object Mentor Blog
Blog Archive
- August 2009 (21)
- July 2009 (22)
- June 2009 (19)
- May 2009 (12)
- April 2009 (12)
- March 2009 (4)
- January 2009 (1)
- December 2008 (1)
- November 2008 (12)
- October 2008 (2)
- September 2008 (10)
- August 2008 (5)
- June 2008 (3)
- May 2008 (3)
- April 2008 (2)
- March 2008 (3)
- February 2008 (2)
- January 2008 (5)
- November 2007 (1)
- October 2007 (1)
- September 2007 (1)
- August 2007 (6)
- July 2007 (3)
- June 2007 (4)
- May 2007 (5)
- April 2007 (4)
- March 2007 (10)
- February 2007 (13)
- January 2007 (7)
Categories-
- Code (61)
- Apprenticeship (57)
- Rails (48)
- commentary (48)
- Ruby (27)
- RSpec (20)
- Metrics (17)
- metric_fu (13)
- Flog (9)
- complexity (9)
- RailsConf2009 (8)
- RubyConf2008 (7)
- test_coverage (7)
- Bugs (6)
- Mocking (6)
- craftsman_swap (6)
- git (6)
- not_code (6)
- Agile2009 (5)
- Amazon (5)
- refactoring (5)
- testing (5)
- ActiveRecord (4)
- Linux (4)
- LoneStarRubyConf2008 (4)
- Saikuro (4)
- churn (4)
- design (4)
- Fixtures (3)
- JRuby (3)
- LoneStarRubyConf2009 (3)
- Math (3)
- RailsConf2007 (3)
- Rake (3)
- Rcov (3)
- Svn (3)
- XP (3)
- legacy_code (3)
- Flay (2)
- GLSEC (2)
- Mingle (2)
- Obtiva (2)
- SQuiD (2)
- TextMate (2)
- Windows (2)
- WindyCityRails (2)
- javascript (2)
- lean (2)
- DUST (1)
- EVDO (1)
- IO (1)
- MacRuby (1)
- OSX (1)
- Routes (1)
- RubyWorks (1)
- Tomcat (1)
- attachment_fu (1)
- cache-fu (1)
- citcon (1)
- craftsmanship (1)
- iPhone (1)
- mac (1)
- memcached (1)
- ord_sessions (1)
- pairing (1)
- restful_authentication (1)


0 comments:
Post a Comment