Quantcast
Viewing all articles
Browse latest Browse all 25

Code Rules are Lines, not Walls

TL;DR

Coding rules are good. You’ll find good exceptions for each once in awhile (and bad exceptions all the time). That exceptions occur does not invalidate any rules, and sticking to best practices is a good idea.

A white line is like a wall

Image may be NSFW.
Clik here to view.
Consolacao subway station

See that yellow line? It is not there to decorate the station (Photo credit: Wikipedia)

I remember studying the traffic code for my driving licence test. In the chapter on road markings, it said: “A continuous white line cannot be crossed. It is like a wall.”. Hopefully – for all the people that have treaded that white line at some point – you do not crash when you cross it.

As a developer, I tend to be quite adamant about coding rules. Even so – I think coding rules are lines on the ground – not walls. Walls are rules that make it impossible to commit (or even compile) code when they are not respected. Even so, the rules still should be followed 99% of the time – by everyone.

Some samples

Style

We find style to be important, and are mostly following Barzov’s Ruby Style Guide. For instance, we use Ruby 1.9 new hash syntax every time possible (every time the keys are Symbols – which is most of the time).

Now, look at this code:

namespace :assets do
  desc 'recreate sprite images and css'
  task :resprite => :environment do
    Dir.glob('app/assets/images/icons/*.svg').each do |svg_file|
      %x(convert -antialias -background transparent #{svg_file} -resize 15x14 #{File.dirname svg_file}/#{File.basename(svg_file).gsub(/\.svg\z/, ".png")} )
    end
      # …
  end
end

This is a part of a custom Rake task we use to generate our sprites “Bootstrap style”. The third line:

task :resprite => :environment do

defines a new task “rewrite” that depends on the “environment” task. Note that the 1.9 hash syntax is not used here, even if it could be. This is linked to Rake tasks usage of hashes to express dependency between two tasks. This is what is called an internal DSL: code that is still valid Ruby code, but that thanks to specific syntax has a specific, declarative look.

The => operator may be used as the key/value separator, but it really does a good job at being read “resprite depends on environment”, which is exactly what this means in the context of Rake. In this context, preserving the 1.8 syntax makes sense.

Code smells

Using “puts” inside your programs is a bad idea: when the application will be running – on a server or as a library – chances are good that your “puts” will go nowhere. If the information is important, better to put it in a logger (with all the additional benefits). Now have a look at this code:

def handle_error(e, message)
      @errors << message
      warn message
      if @options[:debug]
        puts e.message, e.backtrace
      else
        warn 'To see the complete backtrace run rubocop -d.'
      end
    end
...

This code is an excerpt from Rubocop, a style analyzer created by the Ruby Style Guide’s maintainer. It quite clearly uses a puts in order to (gasp) print a message regarding an error. Is that not exactly the case where you want to use a logger or just raise the exception? Well, yes, except in a specific case: when you are actually in the main command and that it is called from the command line, which is the case here (see the complete code on GitHub). In this situation, using a puts makes total sense.

Unused code

I spent an entire post explaining why unused code is evil, yet Ryan Kohn made a good case for keeping unused code in specific situations in his follow-up post.

Rules are lines

Image may be NSFW.
Clik here to view.
Great Wall of China

That is what I call a wall (Photo credit: matt512)

I could probably go on and find exceptions for almost every rule I know and follow, but my point is quite simple:

  • You’ll find reasonable exception for each rule, however well thought-out it might be

  • The existence of such exceptions does not invalidate the rules at all – they still should be followed 99% of the time.

The purpose of a line on the ground is not to prevent you crossing it (you use physical barriers for that) – the purpose is to warn you. The line tells you you’re going someplace you shouldn’t be going – and that your reason for breaking the rule should be extremely compelling. The examples outlined above each have this kind of “compelling reason”.

Exceptions in code reviews

Those situations happen. In a code review, they’ll probably lead to an exchange between the reviewer and the reviewee – and this is exactly the point. I can have a good reason to violate a rule once in awhile, but when I do cross a line,my reviewer is expected to challenge me: is that exception really needed here?

Now, if you find yourself in this situations systematically, you have another kind of problem. Coding rules are sensible practices – drawn from past frustrations and lessons learned. Systematic exceptions (even well thought out) mean that you are not using the language/library/framework the way it was thought out (like coding in Ruby like you would in Java, which would make you code awkward to most Ruby coders).

Situations like above does happen, and as we use automated tools to review our code (in addition to peer review), it means some of the identified violations will not be solved. This is totally normal – coding is all about adaptation to the use case, and even good rules will found an exception in specific cases. This does not in anyway lessen the benefits of those tools – they are there as signals and reminders of things you should fix.






Viewing all articles
Browse latest Browse all 25

Trending Articles