Style Matters
Does style matter to you?
Here is the Martin 15-seconds test about whether style does matter to you or not.
Let’s take a look at this code:
class Blog_engine def initialize @posts = [] end def addPost post @posts <<post unless !post||@posts.include?(post) end def AllPostsTitles return @posts.collect{|post|post.title} end def allPosts_hash hall = [] @posts.each {|p| hall << {:title =>p.title,:contents=>p.contents,comments:p.comments.map{|c|c.text}} } hall end def postByCategories by_cat={} @posts.each{|post| if by_cat[post.category] then by_cat[post.category]<<by_cat[post.category]=[] and by_cat[post.category]<<post end } return @posts end end
Does this code make your eyes bleed? Why? It is perfectly correct Ruby code, and it does what it says. Still, I prefer to have it written like this:
class BlogEngine def initialize @posts = [] end . def add_post(post) @posts << post unless post || @posts.include?(post) end . def all_posts_titles return @posts.map { |post| post.title } end . def all_posts_hash all_hash = [] @posts.each do |post| all_hash << { title: post.title, contents: post.contents, comments: post.comments.map do |comment| comment.text end } end return all_hash end . def post_by_categories post_by_categories = {} @posts.each do |post| (post_by_categories[post.category] ||= []) << post end return @posts end end
If the difference between the two excerpts is important to you, then style probably matters to you too.
Style differences
Let’s dissect the differences a bit:
Naming
Ruby has opted for a mix of most used naming schemes: CamelCase for the classes and modules, snake_case for the methods, variable, and file names. While the convention is arbitrary (I use
CamelCase (Photo credit: Wikipedia)
CamelCase in Java and snake_case in Ruby without problems), having one standard helps a lot. The problem with the code above is not that it uses CamelCase - it’s the fact that it is mixing naming schemes for the same kind of elements. In other words, it is bad, without even starting the (heated) debate about which format is “best”.
Sticking to one standard inside a project is very important for readability - good style allows the reader to understand the nature of various tokens immediately, just by how they are written.
Spacing (lines)
Not spacing between methods really hurts readability, as it impedes the reader’s ability to “make blocks” in his/her mind, forcing him or her to go back to the “line per line” deciphering - One cannot “jump” to a method if one first need to find it.
Spacing (characters)
Code lines are not random groups of characters. As such, spaces - again - help to decipher the parts. Lose the lines - and the code becomes gibberish.
While spaces are actual “void” characters for the machine, they are not void for other people reading your code. For the human readers, they are a necessaty part of it. Once more - code for the human - not the machine.
If-else
While it makes no real difference to the machine, using double negation in alternatives has the same effect as in text - it makes the point difficult to grasp.
Blocks
Ruby blocks can use either do... end or {} (their only difference lies in their precedence order). Both are fine, but mixing them makes reading difficult. The Ruby guide push toward do... end for multi lines blocks and {} for single, which is as good as any other rules - meaning it is clear and unambiguous.
Aliases
Ruby has lots of aliases - methods that exist under several names: map & collect, reduce and inject or Array length and size. Ruby provides this range make everyone - notably smalltalkers - comfortable, and each choice has its merits. Just try not mix them.
Hashes
Hashes have a simplified syntax since Ruby 1.9, as long as you use Symbols as keys (which is a good idea in a large number of cases). Nothing was really wrong with the old one, but mix these and you’ll see colons in your nightmares.
Other reasons
I hope to have made my point about the importance of style for readability. If not - or for variations - do not hesitate to look at other sources.
In any case, there are actually other good reasons to adopt a common style in a team.
Promote collective ownership
Nothing impedes collective ownership more than being able to immediately identify the author of any snippet of code - “this is Mark’s code”. Using the same conventions is a small but important step towards the “this code is our code” objective.
VCS and Diffs
Changes in style introduce false positive in the VCS change set, whether in the form of conflicts or just unnecessary differences. A large set of “style only” changes can certainly be ignored when reviewing... until I hide a real change in the middle. Good luck finding it.
How to manage style
-
Pick one. The most important thing is to standardize around something, whatever it can be (well, try to not be too creative). The Ruby community seems to have standardized around Bozhidar Batsov’s “Ruby Style Guide”, or its slightly diverging GitHub variant.
-
Stick to a standard. Most conventions are good because just because they are conventions, and that is fine.
-
Use tools to check style. Discipline is difficult, so don’t depend on it - have your SublimeText (or whatever you are using to edit Ruby code) do it for you.
Finally
Style is what separates the good from the great.
-- Bozhidar BatsovWill style save your code? No, but it can help saving it.
-- Martin