Marty Andrews

artful code

Monday, February 8, 2010

Cogent without Steve Hayes

In mid 2006, Steve Hayes and I were both working as independent consultants. I had known Steve since 2001, when the Melbourne XP Enthusiasts Group (MXPEG) had started up and we both became active members. When I became independent, he was kind enough to let me use the company name he had registered, Cogent Consulting, for invoicing. I paid him a nominal fee for processing my payroll.

Within six months, Steve and I decided to run some public training courses together to help market ourselves, and improve the Cogent brand for us both. Easy Access Training (EAT) was born. We ran a few reasonably successful public courses in early 2007.

The market at the time was quite buoyant, and pretty soon Steve and I both found ourselves turning away work because we were already engaged on projects. That triggered conversations between us about taking the opportunity to build Cogent as a business, and we decided to hire some staff and pay ourselves a salary rather than remaining effectively independent.

And so, on July 1 2007, Cogent Consulting was re-born as a structured business. Two and a half years later, we're a profitable consulting company with a dozen staff. Our values and policies are unlike any other local company that I know of, and we're proud of those unique attributes.

Sadly, Steve is now planning to leave the country soon, and therefore Cogent as well.

To say he'll be missed is an understatement. For me, Steve has been a friend, mentor and business partner for years. The shape of my career has undeniably been shaped by his influence, and the opportunity to help build a great company came with our partnership. For the rest of the staff at Cogent, Steve has been a thought leader and guiding influence.

I'm charged with being the steward of the company in Steve's absence. I'm quietly confident of my ability to do the job. Indeed, I've been sharing the role with Steve since the beginning, and we've got a good team around us to help. Cogent Consulting will continue on comfortably without Steve, which is perhaps one of his great achievements. It's culture will undeniably change though. Perhaps sometimes better, more often a little bit worse, but mostly just different. That difference is what I'll miss most of all.

Good luck Steve. I hope your new adventures are prosperous and enjoyable. With any luck, our paths will again cross someday sooner rather than later.

Sunday, December 27, 2009

Roodi 2.1.0 released

Roodi stands for Ruby Object Oriented Design Inferometer. It parses your Ruby code and warns you about design issues you have based on the checks that is has configured.

Changes in 2.1.0:

  • Ruby 1.9 compatible.
  • New framework support to allow start and end file events.
  • Added MissingForeignKeyIndexCheck. Still experimental for now.

http://gemcutter.org/gems/roodi

Sunday, October 25, 2009

Roodi 2.0.1 released

Roodi stands for Ruby Object Oriented Design Inferometer. It parses your Ruby code and warns you about design issues you have based on the checks that is has configured.

Changes in 2.0.1:

  • Fixed a bug where roodi.yml was not being loaded. Patch supplied by Rob Mitchell.

http://roodi.rubyforge.org/

Sunday, August 23, 2009

Roodi 2.0.0 released

Roodi stands for Ruby Object Oriented Design Inferometer. It parses your Ruby code and warns you about design issues you have based on the checks that is has configured.

Changes in 2.0.0:

  • Changed internal structure to use a design much more like a visitor pattern.
  • Got *much* faster as a result of the change.
  • Design change fixed 'feature' where nested blocks would all get listed if the inner one exceeded complexity.
  • Outline for NPath complexity check is now possible. Not working yet though.
  • Removed dependency on facets library.

http://roodi.rubyforge.org/

Saturday, August 15, 2009

GreenScreen - a build monitor BVC

I've just released GreenScreen. It's a build monitor that aggregates feeds from your build server and publishes them as large as it can on a web page. The idea is that you can set up a monitor somewhere in your workspace running GreenScreen so that everyone can see the current status of the build all the time.

Other tools like CCMenu and CCTray exist so that people can see the current status on their local computers, and they are absolutely useful. Having something in your workspace that is visible to *anyone* that happens to walk past has some powerful implications though. Many teams actually use a build light or lava lamps that change colour when builds pass or break. GreenScreen is a software based equivalent that you can use on any spare computer.

A widely visible build status means the team is completely transparent all of the time to anyone who can see it. For teams I've coached in recent times, managers, project stakeholders and regular visitors would often ask what the monitor meant, and quickly learnt to ask what was wrong if builds were red. It gave the team a strong sense of commitment to keep the build passing.

I hope you find it useful. Have a look at the pics below for some examples of what GreenScreen looks like for projects with various numbers of builds:

A single project A few projects Many projects Lots of projects

Friday, May 29, 2009

Enforcing Ruby code quality

Over the last year or so, there's been lots of great tools coming out in the Ruby community that help with static analysis of code. We've now got flay, flog, reek and roodi. metric-fu runs all of these tools (plus more) to generate nice reports.

Generating nice reports is all well and good, but frankly it's not enough. We need to start enforcing code quality, not just reporting on it. The Java community is way ahead on this front, which I find rather embarrassing as a Ruby developer. Fear not though, I'm going to show you exactly how to set it up here.

Getting Started

First of all, you need a continuous integration build. Don't have one? Fail. Go have a good hard look at yourself in the mirror and consider if you really want to be a professional software developer or not.

If you're still here, you need the tools installed. That's pretty easy:

sudo gem install flay
sudo gem install flog
sudo gem install reek
sudo gem install roodi
sudo gem sources -a http://gems.github.com
sudo gem install jscruggs-metric_fu

What you've just installed is a set of tools that check for duplicate code, complex code, code smells and code problems. The last one (metric-fu) will give you a report to look at if you need to browse for more details.

Next, you need to add some tasks to your rakefile. For my rails applications, I have this in lib/tasks/quality.rake, but you can put it anywhere that gets loaded by your build.

    1 require 'flog'
    2 require 'flay'
    3 require 'roodi'
    4 require 'roodi_task'
    5 require 'metric_fu'
    6 
    7 desc "Analyze for code complexity"
    8 task :flog do
    9   flog = Flog.new
   10   flog.flog_files ['app']
   11   threshold = 40
   12 
   13   bad_methods = flog.totals.select do |name, score|
   14     score > threshold
   15   end
   16   bad_methods.sort { |a,b| a[1] <=> b[1] }.each do |name, score|
   17     puts "%8.1f: %s" % [score, name]
   18   end
   19   
   20   raise "#{bad_methods.size} methods have a flog complexity > #{threshold}" unless bad_methods.empty?
   21 end
   22 
   23 desc "Analyze for code duplication"
   24 task :flay do
   25   threshold = 25
   26   flay = Flay.new({:fuzzy => false, :verbose => false, :mass => threshold})
   27   flay.process(*Flay.expand_dirs_to_files(['app']))
   28 
   29   flay.report
   30 
   31   raise "#{flay.masses.size} chunks of code have a duplicate mass > #{threshold}" unless flay.masses.empty?
   32 end
   33 
   34 RoodiTask.new 'roodi', ['app/**/*.rb'], 'roodi.yml'
   35 
   36 task :quality => [:flog, :flay, :roodi, 'metrics:all']

Now, add the quality task to the list of things done in your continuous integration build. That will make sure these things run all the time. Try running rake quality manually. It will almost certainly fail on either flog, flay or roodi. I'll show you how to tweak them one at a time.

Flog

When I ran rake flog for the first time, I got something like this:

~/Data/runway $ rake flog
(in /Users/marty/Data/runway)
    42.3: Token#parse_incubation_days
    60.4: Token#parse_incubation_date
    81.7: ActionParser#parse
    89.7: ActionFormat#format
rake aborted!
4 methods have a flog complexity > 40

This tells me that I have four methods in my code base that have a flog complexity greater than 40. If you look back at line 11 of quality.rake shown above, you'll see that this threshold is configurable. Set that number to something that is just higher than the most complex method in your application (in my case, I set it to 90) and run rake flog again. It should pass.

What you've just done is create a stop loss for complexity in your application. If anyone checks in a method that is more complex than the configured threshold, your build will fail. In other words, methods are not allowed to get any more complex than the most complex method in your application now.

Unless you're working on a green fields application, I'll bet that the threshold you set was higher than you want it be. That method that was the most complex in your application needs some refactoring. You've got somewhere to focus your refactoring efforts now though. Pick that method, refactor it, and ratchet down the threshold to the next most complex method. Now you're incrementally improving the quality in your app in terms of complexity.

Flay

When I ran rake flay for the first time, I got something like this:

~/Data/runway $ rake flay
(in /Users/marty/Data/runway)
Total score (lower is better) = 164

1) Similar code found in :defn (mass = 60)
  app/controllers/signups_controller.rb:5
  app/controllers/user_sessions_controller.rb:6

2) Similar code found in :if (mass = 54)
  app/controllers/forgot_passwords_controller.rb:15
  app/controllers/signups_controller.rb:16

3) Similar code found in :defn (mass = 50)
  app/helpers/actions_helper.rb:43
  app/helpers/actions_helper.rb:49
rake aborted!
3 chunks of code have a duplicate mass > 25

This tells me that I have two pieces of code with a mass greater than 30 that have been duplicated. If you look back at line 25 of quality.rake shown above, you'll see that this threshold is configurable. Set that number to something that is just higher than the largest mass of duplicated code in your application. This can be a little confusing, because the tool reports a number equal to that mass multiplied by the number of times it appears. In my case, the reported mass of 60 is actually 30 (a mass of 30 found in 2 places). So I set the threshold to 30. Run rake flay again. It should pass.

What you've just done is create a stop loss for duplication in your application. If anyone checks in code that duplicates an existing mass of code larger than the configured threshold, your build will fail. In other words, people can't copy and paste code in a fashion any worse than they already have.

Again, that threshold you set is almost certainly higher than you want it be. That largest mass of code that was duplicated needs some refactoring to make your code more DRY. Find that code, refactor it, and ratchet down the threshold to the next largest mass of code. Now you're incrementally improving the quality in your app in terms of duplication.

Roodi

When I ran rake roodi for the first time, I got something like this:

~/Data/runway $ rake roodi
(in /Users/marty/Data/runway)
app/models/action_format.rb:10 - Method name "format" cyclomatic complexity is 12.  It should be 10 or less.
app/models/action_parser.rb:11 - Method name "attributes" cyclomatic complexity is 12.  It should be 10 or less.
app/models/action_parser.rb:30 - Method name "parse" cyclomatic complexity is 14.  It should be 10 or less.
app/models/token.rb:173 - Method name "parse_incubation_date" cyclomatic complexity is 11.  It should be 10 or less.
app/models/token.rb:226 - Method name "parse_incubation_days" cyclomatic complexity is 12.  It should be 10 or less.
app/models/action_parser.rb:50 - Block cyclomatic complexity is 11.  It should be 8 or less.
app/models/token.rb:11 - Block cyclomatic complexity is 10.  It should be 8 or less.
app/models/action.rb:103 - Method "apply_defaults_from_name" has 23 lines.  It should have 20 or less.
app/models/action_parser.rb:30 - Method "parse" has 23 lines.  It should have 20 or less.
rake aborted!
Found 9 errors.

This tells me that I have several pieces of code failing Roodi checks. If you look back at line 34 of quality.rake shown above, you'll see a reference to roodi.yml. This is a config file that allows you to configure Roodi. Create that file in the root directory of your application and paste the following contents into it. It's what I have in my config file.

# AssignmentInConditionalCheck:    { }
# CaseMissingElseCheck:            { }
ClassLineCountCheck:             { line_count: 300 }
ClassNameCheck:                  { pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/ }
# ClassVariableCheck:              { }
# TODO Get block cyclomatic complexity back down to 6 or less
CyclomaticComplexityBlockCheck:  { complexity: 12 }
# TODO Get method cyclomatic complexity back down to 8 or less
CyclomaticComplexityMethodCheck: { complexity: 14 }
EmptyRescueBodyCheck:            { }
ForLoopCheck:                    { }
# TODO Get method line count back down to 20 or less
MethodLineCountCheck:            { line_count: 27 }
MethodNameCheck:                 { pattern: !ruby/regexp /^[_a-z<>=\[|+-\/\*`]+[_a-z0-9_<>=~@\[\]]*[=!\?]?$/ }
ModuleLineCountCheck:            { line_count: 300 }
ModuleNameCheck:                 { pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/ }
ParameterNumberCheck:            { parameter_count: 5 }

This config file describes a list of checks that get run by Roodi, and some parameters that are used to initialise those checks. Have a look at http://roodi.rubyforge.org/ for details on each of those checks. Make a call on which checks are appropriate for your project, and then change the configuration on each item so that your build just passes. What you've just done is create a stop loss for these coding problems in your application. If anyone checks in code that doesn't pass these configured checks, your build will fail.

It's possible that you've had to comment out some checks that you really want on, to get the build to pass. For the ones that are still turned on, you've probably had to increase some of the thresholds. You can find that code, refactor it, and turn checks back on or ratchet down the thresholds over time. Now you're incrementally improving the quality in your app in terms of coding checks.

Summary

The installation of metric-fu will give you some nice reports to browse and find the next worst problems in your application. Run rake metrics:all to get that report generated. Put some time aside regularly to clean up your code and ratchet down the thresholds as described above until you get them to a point you're happy with.

As far as I'm concerned, these tools are not an optional extra for your project. You must have them tools set up. It's unprofessional of you not to do everything you reasonably can to keep the quality of your code high. I hope this helps.

GTD Tweekly review

Kelly Forrister, who goes by the name GTDCoachKelly on twitter recently ran a GTD Tweekly review on twitter. I found it enourmously valuable, and we're in the middle of building support for weekly reviews into Runway, so I wanted to record the transcript of the session somewhere that I could reference it for myself again.

Here's how it went.

#Tweekly #GTD Hello everyone! Ready? We'll do this in 3 parts/11 steps
#Tweekly #GTD PART ONE: GET CLEAR. Collect loose paper and materials. Gather everything that's loose into an Inbox, Tray or folder.
#Tweekly #GTD You have 5 minutes for this step. Go...
#Tweekly #GTD You all have one more minute on step one: Collect loose papers and materials.
#Tweekly #GTD PART ONE-STEP TWO-GET CLEAR: Get In to Zero. Choose the inbox that can good progress on in 5 min--email? paper? VM? Go!
#Tweekly #GTD - a good way to process in is 4D's: Delete it, Do it (under 2 mins), Delegate it, Defer it (onto a list)
#Tweekly #GTD PART ONE-STEP THREE-GET CLEAR: Empty your head. Open a Word doc, or grab and pad and clear your head for 5 minutes. Go.
#Tweekly #GTD - STEP THREE - SOME MINDSWEEP TRIGGERS: Family, health, meetings you've had, meetings you're going to have...
#Tweekly #GTD SOME MORE MINDSWEEP TRIGGERS: Your direct reports, finances, 401k, the dog, your car, health appts you've been putting off...
#Tweekly #GTD PART TWO, STEP FOUR-GET CURRENT: Review your Action lists (or maybe you call them Tasks or To Do's.)5 minutes start now. Go!
#Tweekly #GTD (10:25am) 2 more minutes to review action lists--are they current? anything to mark done? anything trigger you to add?
#Tweekly #GTD (10:28am) PART TWO-STEP 5-Review previous calendar info. Any triggers?
#Tweekly #GTD Many times reviewing your old calendar (go back about 3 wks) catches things you meant to do. 3 more mins left (10:30am)
#Tweekly #GTD PART TWO-STEP 6-REVIEW UPCOMING CALENDAR DATA - anything you should start getting ready for? (10:35am) Go!
#Tweekly #GTD REVIEW UPCOMING CALENDAR TIP: if you find something you need to process, you can add to your mindsweep for now.
#Tweekly #GTD if you don't get anything on reviewing your calendar, try going further out. Recurring Tasks are great for calendar. 10:40am
#Tweekly #GTD PART TWO-STEP 7-REVIEW WAITING FOR - if you've got a list review it. If you don't have one, what are you waiting on? 10:41am
#Tweekly #GTD WAITING FOR TIP: Review your email Sent folder. Usually some waiting for's hiding in there. 10:43am
#Tweekly #GTD - PART TWO-STEP 8-REVIEW PROJECT LISTS. Projects are your outcomes that require more than one action step. 10:47am Go!
#Tweekly #GTD PROJECT TIP: Projects are typically completed within 18 mos. If you can NEVER mark it done, it's likely an Area of Focus.
#Tweekly #GTD PROJECT TIP: Most people we coach have 30-100 current personal & professional projects. Don't be surprised! 10:51am.
#Tweekly #GTD PROJECT TIP: If you are not willing to take any next action on a current project, are you sure it's not Someday/Maybe?
#Tweekly #GTD PART 2-STEP 9 - REVIEW CHECKLISTS - birthday checklists? travel checklists? home mntce? 10:55am Go!
#Tweekly #GTD CHECKLIST TIP: Maybe you want to CREATE a checklist? Anything recurring that would be good? What to always pack for vacation?
#Tweekly #GTD PART 3-GET CREATIVE!-STEP 10-REVIEW SOMEDAY/MAYBE: If you have one, update it. If you don't have one, create it! 11:00am
#Tweekly #GTD SOMEDAY /MAYBE TIP: S/M is not just a "fantasy wish" list. It can be a fantastic place to stage "not yet" projects. 11:02am
#Tweekly #GTD SOMEDAY TIP: You'll trust S/M list(s) more if you know you're actually going to review them again. Otherwise they'll die.
#Tweekly #GTD PART 3-STEP 11-BE CREATIVE & COURAGEOUS! Any new thought-provoking, creative, risk taking ideas to add to your system? 11:07a
#Tweekly #GTD CREATIVE & COURAGEOUS TIP: What's REALLY got your attention in your job, family, environment? This is the last step! 11:09am
#Tweekly #GTD Thanks everyone. Hope you got value! Please post comments here: http://bit.ly/VZbP5 Let me know if you want me to do again.

Thanks for a great review Kelly, I really enjoyed it.