Blog

Cohesive behaviors with data clumps

by Jim

A good example of how we use context and locality to understand and manage concepts in our code is using a data clump.

A data clump is a collection of two or more bits of information that are consistently used together. You’ll find that your data loses its meaning when you remove items from the clump.

Date ranges are simple examples of how a data clump puts necessary information into context. An example of this is to find out if a question was asked between today and one month ago. If our Question class implements a query method for this:

class Question
  def asked_within?(start_date, end_date)
    (start_date..end_date).cover?(self.asked_date)
  end
end

Then we can pass in our desired dates to get the answer:

# using ActiveSupport
start_date = 1.month.ago
end_date = Time.now
question.asked_within?(start_date, end_date)

Discovering whether a question is within this time frame always requires both a start and end date. This is an indication that we can only understand the feature and indeed only implement it when we have this data clump. To better encapsulate the behavior of these values, we can create a class to manage initializing objects that represent them.

DateRange = Struct.new(:start_date, :end_date)
last_month = DateRange.new(1.month.ago, Time.now)
question.asked_within?(last_month)

We can then change our Question class to instead take a date range object for the asked_within? method, but the question’s responsibilities have grown a bit here. A question doesn’t have anything to do with comparing dates, so we can move the control of that information into the data clump that represents them.

DateRange = Struct.new(:start_date, :end_date) do
  def contains?(date)
    (start_date..end_date).cover?(date)
  end
end

Now, instead of the question managing its date comparison, the date range can do the work.

last_month.contains?(question.date_asked)

By analyzing the individual parts of this date comparison we have to juggle a bit more in our heads. Considering a range as an complete object rather than a collection of parts is simpler and we tend not to think of every individual day within a month when doing a mental comparison. A date range is a small system of interacting parts that we better understand as a broader context.

This example shows us the value not only of separating responsibilities, but of bringing objects together. We get more value by putting details into context than we would have if they remained separate.

Things to note

Struct.new returns a class instance. Inheriting from the result of a new Struct creates an anonymous class in the ancestors of your created class:

[DateRange, #<Class:0x007f885d0be518>, Struct, ...]

Instead of class DateRange < Struct.new; end use DateRange = Struct.new and avoid an anonymous class in the ancestors:

[DateRange, Struct, ...]

Additionaly, be careful with large ranges. If our code used include? instead of cover?, Ruby would initialize a Time object for every time between the beginning and end. As your range grows, the memory needed to calculate the answer will grow too.

Avoid excessive memory and use cover? instead. It will check that your beginning date is less than or equal to the given date, and that the given date is less than or equal to the end date.

This article is an excerpt from my book Clean Ruby

Clean Up Your Code and get a Free chapter of Clean Ruby

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below. Clean Ruby

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

The difference between instance_eval and instance_exec

by Jim

There’s an important difference between instance_eval and instance_exec. And there’s a great lesson about how to use them well in FactoryGirl

But first, before you go rushing off to build your fantastic DSL, let’s look at what instance_eval is and does.

The simplest of examples can be taken straight from the Ruby docs:

class KlassWithSecret
  def initialize
    @secret = 99
  end
end
k = KlassWithSecret.new
k.instance_eval { @secret } #=> 99

The current value for self inside the provided block will be the object on which you call instance_eval. So in this case the k object is the current context for the block; @secret is a variable stored inside k and instance_eval opens up access to that object and all of it’s internal variables.

The interface that FactoryGirl provides is simple and straightforward. Here’s an example from it’s “Getting Started” documentation:

FactoryGirl.define do
  factory :user do
    first_name "Kristoff"
    last_name  "Bjorgman"
    admin false
  end
end

Here, FactoryGirl uses instance_eval to execute the blocks of code passed to factory.

Let’s take a look at some representative code from how FactoryGirl makes this work:

def factory(name, &block)
  factory = Factory.new(name)
  factory.instance_eval(&block) if block_given?
  # ... more code
end

That’s not actually the code from FactoryGirl, but it represents roughly what happens. When the method factory is called a new Factory is created and then the block is executed in the context of that object. In other words where you see first_name it’s as if you had that factory instance before it and instead had factory.first_name. By using instance_eval, the users of FactoryGirl don’t need to specify the factory object, it’s implicitly applied to it.

Ok, that’s all well and good, but what about instance_exec?

I’m glad you asked.

The instance_eval method can only evaluate a block (or a string) but that’s it. Need to pass arguments into the block? You’ll be frozen in your tracks.

But instance_exec on the other hand, will evaluate a provide block and allow you to pass arguments to it. Let’s take a look…

FactoryGirl allows you to handle callbacks to perform some action, for example, after the object is created.

FactoryGirl.define do
  factory :user do
    first_name "Kristoff"
    last_name "Bjorgman"
    admin false

    after(:create) do |user, evaluator|
      create_list(:post, evaluator.posts_count, user: user)
    end
  end
end

In this sample, the after(:create) is run after the object is created, but the block accepts two arguments: user and evaluator. The user argument is the user that was created. The evaluator is an object which stores all the values created by the factory.

Let’s take a look at how this is implemented:

def run(instance, evaluator)
  case block.arity
  when 1, -1 then syntax_runner.instance_exec(instance, &block)
  when 2 then syntax_runner.instance_exec(instance, evaluator, &block)
  else        syntax_runner.instance_exec(&block)
  end
end

FactoryGirl will create a callback object named by the argument given to the after method. The callback is created with a name, :create in this case, and with a block of code.

The block that we used in our example had two arguments.

The run method decides how to execute the code from the block.

The callback object stores the provided block and Ruby allows us to check the arity of the block, or in other words, it allows us to check the number of arguments.

When looking at a case statement, it’s a good idea to check the else clause first. This gives you an idea of what will happen if there’s no match for whatever code exists in the when parts.

There we see syntax_runner.instance_exec(&block) and this could easily be changed to use instance_eval instead. Ruby will evaluate, or execute, the block in the context of the syntax_runner object.

If the block’s arity is greater than zero, FactoryGirl needs to provide the objects to the block so that our code works the way we expect.

The second part of the case checks if the block arity is equal to 2.

when 2 then syntax_runner.instance_exec(instance, evaluator, &block)

If it is, the syntax_runner receives the instance (or in our case user) and the evaluator.

If, however, the arity is 1 or -1 then the block will only receive the instance object.

So what is that -1 value? Let’s look at the ways we could create a callback:

# Two arguments and arity of 2
after(:create) do |user, evaluator|
  create_list(:post, evaluator.posts_count, user: user)
end
# One argument and arity of 1
after(:create) do |user|
  create_group(:people, user: user)
end
# Zero arguments and arity of 0
after(:create) do
  puts "Yay!"
end
# Any arguments and arity of -1
after(:create) do |*args|
  puts "The user is #{args.first}"
end

Ruby doesn’t know how many args you’ll give it with *args so it throws up it’s hands and tells you that it’s some strange number: -1.

This is the power of understanding how and when to use instance_exec; users of the DSL will expect it to make sense, and it will.

But wait! There’s more!

What if you want to specify the same value for multiple attributes?

FactoryGirl.define do
  factory :user do
    first_name "Kristoff"
    last_name  "Bjorgman"

    password "12345"
    password_confirmation "12345"
  end
end

In the above example, both the password and password_confirmation are set to the same value. This could be bad. What if you change the password for one, but forget to change the other? If they are inherently tied in their implementation, then that could lead to some unexpected behavior when they are not the same.

I would, and probably you would too, prefer to tell FactoryGirl to just use the value I’d already configured.

Fortunately FactoryGirl allows us to use a great trick in Ruby using the to_proc method. Here’s what it looks like in use:

FactoryGirl.define do
  factory :user do
    first_name "Kristoff"
    last_name  "Bjorgman"

    password "12345"
    password_confirmation &:password
  end
end

The important part is the &:password value provided to password_confirmation. Ruby will see the & character and treat the following as a block by calling to_proc on it. To implement this feature, FactoryGirl defines to_proc on attributes and there will use instance_exec to provide the symbol password to the block:

def to_proc
  block = @block

  -> {
    value = case block.arity
            when 1, -1 then instance_exec(self, &block)
            else instance_exec(&block)
            end
    raise SequenceAbuseError if FactoryGirl::Sequence === value
    value
  }
end

What about lambdas and procs?

Some commenters in Reddit raised an important question about how these methods behave when given lambdas and procs.

If you provide a lambda which accepts no arguments as the block, instance_eval will raise an error:

object = Object.new
argless = ->{ puts "foo" }
object.instance_eval(&argless) #=> ArgumentError: wrong number of arguments (1 for 0)

This error occurs because Ruby will yield the current object to the provided block as self. So you can fix it by providing a lambda which accepts an argument:

args = ->(obj){ puts "foo" }
object.instance_eval(&args) #=> "foo"

This changes a bit if you use instance_exec:

object.instance_exec(&argless) #=> "foo"
object.instance_exec(&args) #=> ArgumentError: wrong number of arguments (0 for 1)
object.instance_exec("some argument", &args) #=> "foo"

Because a proc is less restrictive with argument requirements, it will allow either approach to work without error:

p_argless = proc{ puts "foo" }
object.instance_eval(&p_argless) #=> "foo"

p_args = proc{|obj| puts "foo" }
object.instance_eval(&p_args) #=> "foo"

object.instance_exec(&p_args) #=> "foo"
object.instance_exec(&p_argless) #=> "foo"

Now you know, instance_exec and instance_eval are similar in the way they behave, but you’ll reach for instance_exec if you need to pass variables around.

Announcing Ruby Metaprogramming Masterclass

I’m offering a new online class where I’ll be teaching you how to master metaprogramming in Ruby on April 30th (the day after my birthday!)

I’m keeping the spaces limited to 25 so attendees will be able to talk and ask questions but already over a quarter of the seats are gone. So grab a seat now, before they’re all gone.

Clean Up Your Code and get a Free chapter of Clean Ruby

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below. Clean Ruby

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

Locality and Cohesion

by Jim

“The primary feature for easy maintenance is locality: Locality is that characteristic of source code that enables a programmer to understand that source by looking at only a small portion of it.” — Richard Gabriel

This advice is from Patterns of Software by Richard Gabriel.

Keeping cohesive parts of our system together can help us understand it. By managing locality we can keep cohesive parts together.

It’s easy to see coupling in our code. When one object can’t do it’s job without another, we experience frustration in the face of change. We often think about dependencies in our code, but cohesion is the relatedness of the behaviors and plays an import part in how we organize the ideas to support our domain.

def process_payment(amount)
  gateway.authorize_and_charge(amount) do
    deliver_cart
  end
  logger.info "handling payment: #{amount}"
  logger.info "cart delivered: #{id}"
end

The exact purpose of this completely-made-up code isn’t that important. But we can look at parts of this procedure and extract them into a related method:

def process_payment(amount)
  gateway.authorize_and_charge(amount) do
    deliver_cart
  end
  log_purchase(amount)
end

def log_purchase(amount)
  logger.info "handling payment: #{amount}"
  logger.info "cart delivered: #{id}"
end

As Gabriel points out in his book, we can compress a procedure into a simple phrase like log_purchase but this compression carries a cost. In order to understand the behavior of this log_purchase phrase, we need to understand the context around it.

Indeed, we might look at this and realize that there’s a problem with the way we managed the locality of the procedure. Instead of easily understanding a single method, we might look at process_payment and realize there’s a bit more to it than we first expect.

We’re forced to understand the log_purchase and the context which previously surrounded it’s procedure. A second look at this extraction might lead us to reconsider and to go back to inline the method. Let’s keep this code with a tighter locality:

def process_payment(amount)
  gateway.authorize_and_charge(amount) do
    deliver_cart
  end
  logger.info "handling payment: #{amount}"
  logger.info "cart delivered: #{id}"
end

While extracting the log_purchase method was easy, given the original code, it added a bit too much for us to understand and it doesn’t feel quite right. Handling the locality of this code helps us to better understand it and to make better decisions about how to improve the main process_payment method.

Consider this: How much must you pack into your head before you can begin evaluating a part of your code?

While breaking procedures up into small methods can be a useful way to make easy to understand (and easy to test) parts, we may do so to the detriment of understanding.

This is something to consider if you are building a DSL to compress ideas in your code or if you’re trying to create objects to manage your business logic. I’ll be writing more about the value of controlling the locality of behavior in your system, but I’d love to hear how you manage locality. What do you do to ensure that related bits stay together?

Clean Up Your Code and get a Free chapter of Clean Ruby

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below. Clean Ruby

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

The 4 Rules of East-oriented Code: Rule 4

by Jim

Often the rules we create are defined by their exceptions.

It is difficult to create a program which continually passes objects and never returns data. Often the first rule of “Always return self” is met with immediate rejection because it’s easy to see the difficulty you’d encounter if that rule is continually followed for every object.

In my presentation for RubyConf, I showed how we break the rules to allow value objects to handle data for a template. I previously wrote about the approach I used in the presentation to push data into a value object.

class Address
  def display(template)
    if protect_privacy?
      template.display_address(private_version)
    else
      template.display_address(public_version)
    end
    self
  end
end

In the sample above, an Address instance commands a template to display_address with different versions of data: private_version or public_version. This makes a flexible interface that allows Address to create any number of different versions if necessary. Perhaps the requirements will demand a semi_public_version in the future; our design of the template need not change.

This is a great way to break the rules. Value objects allow us to parameterize a collection of data in a single object. The alternative to this approach would be to use setter methods on the template object:

class Address
  def display(template)
    unless protect_privacy?
      template.street = street
      template.apartment = apartment
      template.postal_code = postal_code
    end
    template.city = city
    template.province = province
    template.display_address
    self
  end
end

We can plainly see that although the code follows the rules by commanding the template object, there’s also quite a lot happening in this display method on Address. If the requirements change we might feel encouraged to complicate the unless block or “refactor” it into a case statement. While that might solve our problem, the resulting code could lead to some difficult to read and understand implementation details.

By breaking the rules with a value object we can better encapsulate the ideas in a private address object or public or any other type we desire.

But we’re not just breaking the rules inside the Address methods; the template breaks the rules too. Rule 2 says that objects may query themselves and subsequently means they should not query other objects. But by choosing to break the rules we make a design decision at a specific location to make things better.

No matter what rules you follow, you decide not only to follow them, but decide to break them as well. To make your program easy to understand and to create reasonable expectations, you can lean on creating barriers. Preventing yourself from doing one thing frees you to do another.

Embrace constraints.

How do you add constraints to your programs? What are you better able to do by adding restrictions?

Clean Up Your Code and get a Free chapter of Clean Ruby

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below. Clean Ruby

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

The 4 Rules of East-oriented Code: Rule 3

by Jim

When I set out to create my presentation for RubyConf, I wanted to provide the audience with something they could easily try. By doing that, one could walk away and put themselves in a position to think about their code differently. While, James Ladd, the creator of East-oriented Code made some basic rules, I decide to take them and frame it in the specific context of Ruby:

  1. Always return self
  2. Objects may query themselves
  3. Factories are exempt
  4. Break the rules sparingly

After writing about Rule 1 and Rule 2 I’m very eager to get to Rule 3. It’s an easy way to break the intent of this style without breaking the rules.

Factories are Exempt

They must be. If you returned self from Object.new you’d just get Object back, not an instance of an object. So factories are exempt from returning self.

The best way to get around any of these rules is to just make something into a factory. But here lies the danger. It’s important to first think about what these objects are doing. For what are they responsible?

We could create a class to sweep our messy code under the rug.

user = User.new
signup = UserSignupProcess.new
signup.create_with(user)

The code above, we could say, is East-oriented. The factories create instances, and the signup object is told to create_with and given the user object.

Beyond this (inside create_with), it could easily be an enormous mess. While we can and probably should use different programming techniques for different situations, taking a load of if statements and sweeping it into a class could still be problematic.

Now, the sample code above is completely made up to show how you can take part of your program and say “this part is East-oriented, but over here I used this other technique. I call it If-oriented.”

Examining your domain and creating a program to support it requires that you carefully evaluate what objects should exist, what their responsibilities are, and what you will name them.

East-orientation is all about designating responsibilities.

This leads us to breaking the rules…

We’ll be getting to that later. There’s likely very good reasons to break any particular programming rule, but it probably depends on the context.

I wrote Clean Ruby and the chapter on East-oriented Code before I set up the 4 rules for my presentation, but the same lessons are there. I’ll be adding more to it, particularly as discussion and ideas around DCI evolve, but I’m putting effort toward wrapping up the Ruby DSL Handbook. It will soon be complete and the $12 price will go up to $24, so pick it up now if you’re interested.

Ruby DSL Handbook is about how to create a DSL without headaches from metaprogramming and I just released an update with a chapter about creating a DSL without metaprogramming at all. Much like this discussion today, it’s all about managing responsibilities.

Clean Up Your Code and get a Free chapter of Clean Ruby

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below. Clean Ruby

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

The 4 Rules of East-oriented Code: Rule 2

by Jim

In a previous article I wrote about the first rule of East-oriented Code.

Here again are the rules I set forth in my presentation at RubyConf:

  1. Always return self
  2. Objects may query themselves
  3. Factories are exempt
  4. Break the rules sparingly

The second rule, that “Objects may query themselves”, allows the design of objects to work with their own attributes.

When we design our systems of interacting objects we can use the Tell, Don’t Ask approach to limit the decisions in the code to objects which are responsible for the data used to make them.

The Tell, Don’t Ask article begins by quoting Alec Sharp:

Procedural code gets information then makes decisions. Object-oriented code tells objects to do things.

In order for objects to do things, they may need to ask questions about their own data. Though the first rule of East-oriented Code says that you should return self, internal private methods don’t need to follow this rule. We can and might need to create query methods to allow the object to make decisions.

It’s easy to begin designing an object by specifying what it’s attributes are:

class Person
  attr_reader :name, :nickname, :gender
end

When we do that, we also implicitly allow other objects to use these attributes and make decisions:

if person.nickname =~ /^DJ/
  person.setup_playlist_preferences('house')
else
  person.setup_playlist_preferences('classical')
end

In the sample code above we’re using a method setup_playlist_preferences which accepts a single argument. The decision about what value to set is made outside of the person object. As additional options are added to the system, this if may have elsif clauses added to it or it may turn into a case statement. With public attributes, those changes can appear in multiple places in your system, which can lead to headaches when the structures of your objects change.

Alternatively, we could command the object to do what we want:

person.setup_playlist_preferences

Any decision about what to do to setup preferences can be made inside the setup_playlist_preferences method.

Here’s a summary from the C2 wiki

Very very short summary: It is okay to use accessors to get the state of an object, as long as you don’t use the result to make decisions outside the object. Any decisions based entirely upon the state of one object should be made ‘inside’ the object itself.

One way to prevent decisions about an object from being made outside that object is to limit the public information:

class Person
  private
  attr_reader :name, :nickname, :gender
end

If you like this, check out the new book I’m writing: Ruby DSL Handbook which is currently half-off the final price. It’s designed to be a guide to help you make decisions about how to build your own DSL and compressions of concepts.

Permalink…

1999 - 2015 © Saturn Flyer LLC 2321 S. Buchanan St. Arlington, VA 22206

Call Jim Gay at 571 403 0338