Thursday, August 16, 2007

Blogs I Read

These are the blogs that I read, in no particular order.

Don't see yours on there, but think it should be? let me know: ruby at [my domain] . com

RubyGems: Dust

I've often shown examples similar to the following snippet.

functional_tests do
test "given no name, when validated, then error is in the objects error collection" do
instance = Klass.new
instance.valid?
assert_equal "can't be empty", instance.errors.on(:name)
end
end

Forgetting the body of the test, the interesting thing about the snippet is that it's a grouping of tests that contains a single test. I prefer this syntax to defining a class that inherits from Test::Unit::TestCase and then defining tests by creating methods that start with "test_". All of the projects that I'm a part of use this syntax and I've yet to hear anyone say that they prefer the classic Test::Unit syntax.

Adding this to your project just got a bit easier. I extracted the core methods and created a new gem: Dust.

Dust gives you unit_tests, functional_tests, and test methods that can be used for defining tests. Dust also includes additional methods that can help enforce design decisions. For example, if you subscribe to the theory that setup and helper methods should be removed if possible, the Test::Unit::TestCase.disallow_setup! and Test::Unit::TestCase.disallow_helpers! should interest you.

Thursday, August 09, 2007

Eagerly Initialized Attribute

Initialize an attribute at construction time instead of on the first access.

class Employee
def emails
@emails ||= []
end
end

==>

class Employee
def initialize
@emails = []
end
end


Motivation
The motivation for converting attributes to be eagerly initialized is for code readability purposes. Lazily initialized attributes change their value upon access. Lazily initialized attributes can be problematic to debug because their values change upon access. Eagerly Initialized Attributes initialize their attributes in the constructor of the class. This leads to encapsulating all initialization logic in the constructor and consistent results when querying the value of the instance variable.

Discussion
I prefer Lazily Initialized Attributes, but Martin prefers Eagerly Initialized Attributes. I opened up the discussion to the reviewers of Refactoring, Ruby Edition and my current ThoughtWorks team, but in the end it was split 50/50 on preference. Based on that fact, I told Martin I didn't think it was a good candidate for Refactoring, Ruby Edition. Not surprisingly, he had a better solution: Provide examples of both refactoring to Eagerly Initialized Attribute and refactoring to Lazily Initialized Attribute.

Martin and I agree that this isn't something worth being religious about. Additionally, we both think it's valuable for a team to standardize on Lazily or Eagerly Initialized Attributes.

Mechanics
  • Move the initialization logic to the constructor.
  • Test
Example
The code below is an Employee class with both the email and voice_mail attributes lazily initialized.

class Employee
def emails
@emails ||= []
end

def voice_mails
@voice_mails ||= []
end
end

Moving to an Eagerly Initialized Attribute generally means moving the initialization logic from the getter methods into the constructor.

class Employee
attr_reader :emails, :voice_mails

def initialize
@emails = []
@voice_mails = []
end
end

Monday, August 06, 2007

Ruby: Lazily Initialized Attributes

Update: This is probably going to be included in Refactoring, Ruby Edition so I took another pass through it following all of your comments. Thanks for the feedback.

Initialize an attribute on access instead of at construction time.

class Employee
def initialize
@emails = []
end
end

==>

class Employee
def emails
@emails ||= []
end
end

Motivation
The motivation for converting attributes to be lazily initialized is for code readability purposes. While the above example is trivial, when the Employee class has multiple attributes that need to be initialized the constructor will need to contain all the initialization logic. Classes that initialize instance variables in the constructor need to worry about both attributes and instance variables.The procedural behavior of initializing each attribute in a constructor is unnecessary and less maintainable than a class that deals exclusivey with attributes. Lazily Initialized Attributes can encapsulate all their initialization logic within the methods themselves.

Mechanics
  • Move the initialization logic to the attribute getter.
  • Test
Example using ||=
The code below is an Employee class with the email attribute initialized in the constructor.

class Employee
attr_reader :emails, :voice_mails

def initialize
@emails = []
@voice_mails = []
end
end

Moving to a Lazily Initialized Attribute generally means moving the initialization logic to the getter method and initializing on the first access.

class Employee
def emails
@emails ||= []
end

def voice_mails
@voice_mails ||= []
end
end

Example using instance_variable_defined?
Using ||= for Lazily Initialized Attributes is a common idiom; however, this idiom falls down when nil or false are valid values for the attribute.

class Employee...
def initialize
@assistant = Employee.find_by_boss_id(self.id)
end

In the above example it's not practical to use an ||= operator for a Lazily Initialized Attribute because the find_by_boss_id might return nil. In the case where nil is returned, each time the assistant attribute is accessed another database trip will occur. A superior solution is to use code similar to the example below that utilizes the instance_variable_defined? method that was introduced in ruby 1.8.6.

class Employee...
def assistant
@assistant = Employee.find_by_boss_id(self.id) unless instance_variable_defined? :@assistant
@assistant
end

Sunday, August 05, 2007

Ruby: operator precedence of && and = (which also applies to || or)

Recently a bug popped up on my project surrounding code similar to the following sample.

total = shopping_cart.empty? and shopping_cart.total

The problem with the above code is that it evaluates as if it were the snippet below.

(total = shopping_cart.empty?) and shopping_cart.total

It should be obvious that setting the total to true or false is not the intended behavior.

The problem with the original snippet is the usage of the 'and' operator. The Ruby operator precedence table shows that '=' has as higher precedence than the 'and' operator.

The solution is to use the '&&' operator instead of the 'and' operator. The precedence table shows that the '&&' operator has a higher precedence than the '=' operator. Therefore, the following two lines of code are basically the same.

total = shopping_cart.empty? && shopping_cart.total
total = (shopping_cart.empty? && shopping_cart.total)

As the title says, the same rules apply to the precedence of '||' and 'or'.