Why Style Matters

Share this article

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.

Martin EnglundMartin Englund
View Author

Martin Englund is the Senior Operations Architect at Turn Inc, where he works on fully automating the company's infrastructure, to meet the demands of handling over 1,000,000 QPS. He is a firm believer that if you aren't automating it, you are doing it wrong. Martin has over twenty years of experience in security and automation, and has contributed to DevOps tools, like Puppet and Vagrant. Prior to this role, he worked at VMwave/Pivotal where he developed BOSH - the orchestration tool chain that deploys, runs and manages the open source Cloud Foundry PaaS as the commercial service cloudfoundry.com. Before that he worked a long time and held many positions at Sun Microsystems, including Principal Security Engineer running Sun's external web presence, in Java Security Engineering and the Sun IT Security Office, where he was responsible for creating the standards and tools used by Sun IT to secure its servers. He has also authored numerous technical papers on security, including co-authoring the Solaris Security Essentials book.

Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week