Why Style Matters

Martin Englund
Share

Freedom of expression is a good thing, and we all have our own style of coding. One of the great aspects of Ruby is it gives you a lot of liberty with the syntax. Some people always leave out parentheses, unless they’re required, while others always include them, even when they are superfluous.

Punk

Picture by Man Alive!

When you work together with others on a project, the team should agree upon a coding standard and strictly adhere to it. Exactly what is in the standard is less important, but everyone agreeing to it and following it is crucial.

Opening up files in a project to find a different style in each file subtracts a lot from the readability, which is a key thing when collaborating with others. You are likely going to spend more time reading other peoples’ code than your own, so cringing every time you open up a file is not going to be fun in the long run…

Be Uniform

Uniform

Picture by Michael Nutt

Consistency is key. I’ve seen code written by a single author who managed to be inconsistent with himself! Different levels of indentation, different spacing, different variable naming, e.g.

def foo(var_a,var_b, var_c, varD ) 
    fooBar = "a(#{a}) "+ 'b(' +b+') cd(' +bar( var_c,varD)+")"
  return fooBar
end

(code changed to protect the guilty)

Compare this to the below:

def foo(a, b, c, d)
  "a(#{a}) b(#{b}) cd(#{bar(c, d)})"
end

Quite a difference, right?

Ruby Style Guide

In Ruby, there is more than one way to do the same thing. For instance,

  • Change the load path by using either $: or $LOAD_PATH
  • Create a proc using proc or Proc.new
  • Use a module with module_function :foo or a class with def self.foo for an object which only has class methods.

Then, there are some things which are a matter of taste. For example, how you indent, ending lines with a semicolon, if you use parenthesis for a method without arguments, spacing after a comma, etc. What you choose is up to you, but there are good reasons for picking one over the other.

There are a number of Ruby style guides available, and which one you select is up to you and your team:

This is far from a complete list. In the end, an important consideration is if you can automate style compliance validation, as manual inspection is slow and faulty.

Automatic Style Checking

To enforce the chosen style, you should deploy an automatic style checker. For some languages, like go, this is really easy, as the language itself comes with with it (see the go fmt command).

In Ruby, you have to rely on external tools.

Rubocop

I prefer to use rubocop as it is fast, highly configurable, and comes with sensible defaults.

Continuous Integration

To prevent badly formatted code from making it into the repo, you could use a pre-commit hook (if you are using git). You should also include an automated check in your continuous integration server. With Rubocop, it is really easy, as there is a rake task that does it for you:

require 'rspec/core/rake_task'
require 'rubocop/rake_task'

task default: [:rubocop, :spec]

RSpec::Core::RakeTask.new
Rubocop::RakeTask.new

This will now run style checking before it runs the (rspec) tests.

Similarly, if you are running guard, adding Rubocop to the Guardfile is simple using a gem like guard-rubocop. The point is, working automated style checking into your routine is simple, and the payoff is well worth it.

Sample Output

Running the horrific piece of code I showed you at the beginning through rubocop yields the following list of violations:

$ rubocop foo.rb
Inspecting 1 file
C

Offences:

foo.rb:1:14: C: Space missing after comma.
def foo(var_a,var_b, var_c, varD )
             ^
foo.rb:1:33: C: Space inside parentheses detected.
def foo(var_a,var_b, var_c, varD )
                                ^
foo.rb:1:35: C: Trailing whitespace detected.
def foo(var_a,var_b, var_c, varD )
                                  ^
foo.rb:2:1: C: Use 2 (not 3) spaces for indentation.
   fooBar = "a(#{a}) "+ 'b(' +b+') cd(' +bar( var_c,varD)+")"
^^^
foo.rb:2:4: C: Use snake_case for variables.
   fooBar = "a(#{a}) "+ 'b(' +b+') cd(' +bar( var_c,varD)+")"
   ^^^^^^
foo.rb:2:23: C: Surrounding space missing for operator '+'.
   fooBar = "a(#{a}) "+ 'b(' +b+') cd(' +bar( var_c,varD)+")"
                      ^
foo.rb:2:30: C: Surrounding space missing for operator '+'.
   fooBar = "a(#{a}) "+ 'b(' +b+') cd(' +bar( var_c,varD)+")"
                             ^
foo.rb:2:32: C: Surrounding space missing for operator '+'.
   fooBar = "a(#{a}) "+ 'b(' +b+') cd(' +bar( var_c,varD)+")"
                               ^
foo.rb:2:41: C: Surrounding space missing for operator '+'.
   fooBar = "a(#{a}) "+ 'b(' +b+') cd(' +bar( var_c,varD)+")"
                                        ^
foo.rb:2:46: C: Space inside parentheses detected.
   fooBar = "a(#{a}) "+ 'b(' +b+') cd(' +bar( var_c,varD)+")"
                                             ^
foo.rb:2:52: C: Space missing after comma.
   fooBar = "a(#{a}) "+ 'b(' +b+') cd(' +bar( var_c,varD)+")"
                                                   ^
foo.rb:2:58: C: Surrounding space missing for operator '+'.
   fooBar = "a(#{a}) "+ 'b(' +b+') cd(' +bar( var_c,varD)+")"
                                                         ^
foo.rb:2:59: C: Prefer single-quoted strings when you don't need string interpolation or special symbols.
   fooBar = "a(#{a}) "+ 'b(' +b+') cd(' +bar( var_c,varD)+")"
                                                          ^^^
foo.rb:3:1: C: Inconsistent indentation detected.
  return fooBar
^^
foo.rb:3:3: C: Redundant `return` detected.
  return fooBar
  ^^^^^^
foo.rb:5:1: C: 1 trailing blank lines detected.

1 file inspected, 16 offences detected

Wrapping Up

Whenever you start a new project, be sure to include automatic style checking at the very beginning, or it will take a major effort to get all files into compliance.

If you inherit an existing project with divergent styles, you can exclude the checks which generate the most failures so you slowly can bring them in order.

However you do it, enforce your style. You’ll be very glad you did.

CSS Master, 3rd Edition