Sonntag, 28. September 2014

Express boolean parameters the Ruby way!

At first: prevent using boolean parameters in method definitions!
In Ruby land boolean parameters are outlawed. And there is a reason for. They:
  1. are not readable
  2. duplicates code or responsibility inside and outside the method
1.) Boolean parameters are no readable, because they do not express which meaning is behind true or false.
2.) And they duplicate the condition, which led to the boolean parameter inside and outside the method. The reason for having a boolean parameter often is the wish to generalize the message (method). But the wish is insidious, because it moves the arisen condition out of the method and repeats checking the boolean parameter inside the method. This fact couples the message (method) to its callers (code coupling).
A solution often is making the method private and revealing 2 public message points instead, calling the private method.
Since there are APIs expecting boolean parameters for various reasons, there is also a nice way to deal with it. For example the Ruby on Rails helper method ActionView::Helpers::FormTagHelper#check_box_tag with the method signature:
check_box_tag(name, value = "1", checked = false, 
  options = {})
expects a boolean parameter as the third.
The original code generates a HTML check box tag being unchecked:
check_box_tag("Permitted", "1", true, id: "permitted")
which is unreadable in terms of the boolean parameter. What does "true" mean? You only know, if you know the API method signature...
But it can be refactored to:
check_box_tag("Permitted", "1", :checked, id: "permitted")
which solves the readability issue, because it reveals that the HTML check box tag will be checked, since all objects except FalseClass and NilClass are true and therefore a Symbol is too.
Improving the readability by assigning expressive symbols/ strings is a solution for all APIs expecting a FalseClass boolean parameter by default, which is common practice.
Further articles of interest:

Supported by Ruby 2.1.1 and Ruby on Rails 3.2.17

Sonntag, 21. September 2014

5 Ruby shots!

1. Extract regular expression matches quickly!

String#match is the typical message receiver for examining String patterns. With the help of regular expressions the Stings patterns can be matched/ found like:
email = "chris@ruby.de"
email.match(/@((?:[-a-z0-9]+\.)+[a-z]{2,})/)[1]
can be refactored to:
email[/@((?:[-a-z0-9]+\.)+[a-z]{2,})/, 1]
which looks much cleaner. With Strings being a sequence (array) of characters in mind, the logic is even more compelling.
The API String#[] documentation reveals even more examples.

2. Use the method block shortcut!

Methods and especially enumerations and their blocks can look way too extensive in simple use cases, for example:
[1, 2, 3 ].map { |number| number.to_s } #=> ["1", "2", "3"]
[1, 2, 3 ].select { |number| number.odd? } #=> [1, 3]
Inside the block there is only one message sent to the iterated Fixnum object, without any parameters. The logic is super simple and that is why Ruby offers a shortcut for such. Please compare the examples with:
[1, 2, 3 ].map(&:to_s) # => ["1", "2", "3"]
[1, 2, 3 ].select(&:odd?) # => [1, 3]
Use the shortcut for all iterators, with the receiver (iterated object) only receiving one message (method call) inside the block and the message (method call) expecting any parameters.
It is implemented by passing the message (method call) as a symbol and an unary ampersand (&).
Please note that the shortcut is not an enumerator thing only. It can be used for every method expecting a block.

3. Explode enumerables!

There are methods having a variable length of parameters. Array#values_at is such a candidate. For example getting objects at specific indexes:
[1, 2, 3, 4, 5].values_at(0, 4) # => [1, 5]
works fine as long as the indexes are known. But if the number of indexes or the indexes themselves are calculated, there is no other option than dealing with an array and exploding it to a parameter list:
# indexes = [0, 4]
[1, 2, 3, 4, 5].values_at(*indexes) # => [1, 5]
In the case the sequence of numbers also is calculated, it can be achieved by exploding a range like:
first = 1
last = 5
numbers = *(first..last) # => [1, 2, 3, 4, 5]
indexes = [0, 4]
numbers.values_at(*indexes) # => [1, 5]
... so powerful.

4. Rescue without verbosity!

The verbose way of exception handling looks like:
def slice_it
  begin
    "Ruby".slice
  rescue ArgumentError => e
    $stderr.puts "Read the API documention of String#slice.
      Message: '#{e}'"
  end
end
but it can be less verbose without the explicit begin/ end block style, because method definitions are implicitly also exception blocks:
def slice_it
  "Ruby".slice
rescue ArgumentError => e
  $stderr.puts "Read the API documention of String#slice.
    Message: '#{e}'"
end

5. Identify the Hash values with non Strings/ Symbols!

Associative arrays (aka Hash) are key/ value stores in their basic meaning. The keys usually are symbols or strings. For example:
{ language: 'Ruby', 'version' => 2.1 }
Sometimes it is a better idea to have meaningful keys. Imagine a cache store for all people grouped by their birthday:
people = Person.all.group_by(&:birthday)
# => { Sat, 21 Sep 1996 => [#<Person 1>, #<Person 2>], 
Fri, 19 Apr 1996 => [#<Person 3>] }
which can be accessed easily:
people[18.years.ago]
# => [#<Person 1>, #<Person 2>]
In this case the keys are Date objects, but Hash keys can be any kind of objects.

Supported by Ruby 2.1.1

Sonntag, 14. September 2014

Load your ActiveRecord objects eagerly!

Eager loading associated ActiveRecord::Base model objects by ActiveRecord::QueryMethods#includes is a common practice for Ruby on Rails developer. Especially when the resulting query is generated dynamically on run time depending on unknown factors.
The nice thing about it: it decides whether it generates one huge SQL join query or multiple small queries for performance reasons. The decision is based on the selection part of the SQL query. If the selection refers to one of the joined tables, the SQL query has to be the huge SQL chunk with all its joins and attributes aliasings, which is a parsing nightmare.
That is why the default approach for includes is preload, with its small and fast querying (read Preload your ActiveRecord objects!). Besides each of the small queries are likely a candidate for query caching and therefore a performance improvement.
For example the original code:
class Category < ActiveRecord::Base
  has_many :foods
end

class Food < ActiveRecord::Base
  belongs_to :category
end
and eager loading (aka preloading) the categories and their associated foods by searching the food name:
@categories = Category.includes(:foods).
  where("foods.name LIKE :term", { term: '%milk%' })
also generates the SQL:
SELECT "categories"."id" AS t0_r0, 
"categories"."name" AS t0_r1, 
"categories"."created_at" AS t0_r2, 
"categories"."updated_at" AS t0_r3, 
"foods"."id" AS t1_r0, 
"foods"."name" AS t1_r1, 
"foods"."created_at" AS t1_r2, 
"foods"."updated_at" AS t1_r3, 
"foods"."category_id" AS t1_r4, 
"foods"."description" AS t1_r5 
FROM "categories" 
LEFT OUTER JOIN "foods" 
  ON "foods"."category_id" = "categories"."id" 
WHERE (foods.name LIKE '%milk%')
Please note that ActiveRecord::QueryMethods#includes generates 1 SQL query joining both tables by a LEFT JOIN and the projection part contains already a lot of aliased attributes.
An easy step to improve the codes intention is to replace includes by eager_load like:
@categories = Category.eager_load(:foods).
  where("foods.name LIKE :term", { term: '%milk%' })
The generated SQL is exactly the same:
SELECT "categories"."id" AS t0_r0, 
"categories"."name" AS t0_r1, 
"categories"."created_at" AS t0_r2, 
"categories"."updated_at" AS t0_r3, 
"foods"."id" AS t1_r0, 
"foods"."name" AS t1_r1, 
"foods"."created_at" AS t1_r2, 
"foods"."updated_at" AS t1_r3, 
"foods"."category_id" AS t1_r4, 
"foods"."description" AS t1_r5 
FROM "categories" 
LEFT OUTER JOIN "foods" 
  ON "foods"."category_id" = "categories"."id" 
WHERE (foods.name LIKE '%milk%')
But if you want to reveal which eager loading approach will happen, you should stick to eager_load, because that makes clear, you kow:
  1. a huge join query will be generated
  2. the query will not be cached
  3. there is a reference of the query selection/ aggregation/ order part to at least 1 join table
Otherwise you point out that you do not know anything about how the ActiveRecord objects are loaded eagerly.
Further articles of interest:

Supported by Ruby 2.1.1 and Ruby on Rails 3.2.17

Sonntag, 7. September 2014

Preload your ActiveRecord objects!

Eager loading associated ActiveRecord::Base model objects is always a good choice. A lot Ruby on Rails developer take advantage of the ActiveRecord::QueryMethods#includes and do not care anymore. A better approach is to care.
For example the original associations:
class Category < ActiveRecord::Base
  has_many :foods
end

class Food < ActiveRecord::Base
  belongs_to :category
end
and eager loading (aka preloading) the categories and their associated foods:
@categories = Category.includes(:foods).all
generates a SQL like:
SELECT "categories".* FROM "categories"
SELECT "foods".* FROM "foods" WHERE "foods"."category_id" IN (1, 2, 3)
Please note that ActiveRecord::QueryMethods#includes generates 2 SQL queries. The database tables categories and foods are not joined together.
And that is exactly the same what ActiveRecord::QueryMethods#preload does. That is why:
@categories = Category.preload(:foods).all
also generates the SQL:
SELECT "categories".* FROM "categories"
SELECT "foods".* FROM "foods" WHERE "foods"."category_id" IN (1, 2, 3)
But beware, the selection conditions are not allowed to refer to the preloaded association table attributes.
So something like:
@categories = Category.preload(:foods).where("foods.name LIKE '%corn%'").all
will raise an SQL exception:
SQLException: no such column: foods.name: SELECT "categories".* FROM "categories"  WHERE (foods.name LIKE '%corn%')
But as long as the query is simple and is intended to keep on being simple, it totally makes sense to prefer ActiveRecord::QueryMethods#preload to ActiveRecord::QueryMethods#includes.
Furthermore it is more intentional about what the code is doing. And that is always a win.
Further articles of interest:

Supported by Ruby 2.1.1 and Ruby on Rails 3.2.17