Tag Archives: ruby

Law of Demeter and the delegate method

Written by Richard. Filed under computing, rails. Tagged , , , . 7 Comments.

The Law of Demeter, or Principle of Least Knowledge is a fairly simple design pattern, which, simply put means that an object should only talk to it’s immediate “friends”

The law states that a method M of and object O may only invoke the methods of the following kind:

1. a method on O itself
2. any parameters passed to M
3. any objects instantiated within M
4. any direct components of O

The classic example coined by David Bock used a Paperboy (one object) delivering a paper, then extracting money from a Customer’s (another object) Wallet (and another):

  class Paperboy
    def get_payment(customer)
      self.money += customer.wallet.take_out(10)
    end
  end

In the “real world” the Paperboy would ask the customer for the money who would then take it out for them, rather then the Paperboy reaching into the customer’s back pocket and getting it for themself.

Really we want something as follows:

  class Paperboy
    def get_payment(customer)
      self.money += customer.get_payment(10)
    end
  end

  class Customer
    def get_payment(amount)
      wallet.take_out(10)
    end
  end

This may all seem trivial and a waste of time, but what happens if some Customers want to pay by cheque? Those decisions should have an impact on the Paperboy, otherwise we end up with:

  class Paperboy
    def get_payment(customer)
      if customer.pay_by_cash?
        self.money += customer.wallet.take_out(10)
      elsif customer.pay_by_cheque?
        self.money += customer.cheque_book.write_cheque(10)
      end
    end
  end

Where as it makes more sense for the change to be contained within the Customer:

  class Paperboy
    def get_payment(customer)
      self.money += customer.get_payment(10)
    end
  end

  class Customer
    def get_payment(amount)
      if pay_by_cash?
        wallet.take_out(10)
      elsif pay_by_cheque?
        cheque_book.write_cheque(10)
      end
    end
  end

So what does this have to do with Rails and the delegate method? The delegate method adds a quick and simple way of following the Law of Demeter without having to do very much at all.

  class Order
    belongs_to :customer
  end

  class Customer
    has_many :orders
    has_one :credit_card
    has_one :bank_account

    def payment_method
      if pay_by_card?
        credit_card
      elsif pay_by_account?
        bank_account
      end
    end
  end

  class CreditCard
    belongs_to :customer
  end

  class BankAccount
    belongs_to :customer
  end

This setup means to get an Order’s payment we would have to say:

  @order.customer.payment_method.withdraw(amount)

But if we simply change our objects as such:

  class Order
    belongs_to :customer
    delegate :withdraw_payment, :to => :customer
  end

  class Customer
    has_many :orders
    has_one :credit_card
    has_one :bank_account

    def withdraw_payment(amount)
      if pay_by_card?
        credit_card.withdraw(amount)
      elsif pay_by_account?
        bank_account.withdraw(amount)
      end
    end
  end

Now all we have to say is:

  @order.withdraw_payment(amount)

So at any time, the details of how a payment  is to be decided can be contained with the Customer. This is of course a simplistic example, but hopefully explains how you chould be using this handy feature.

Vlad 2.0 Not Finding Tasks in deploy.rb

Written by Richard. Filed under computing, programming. Tagged , , . 2 Comments.

When I restalled all my gems on Snow Leopard, vlad refused to find any of the tasks I had defined in my deploy.rb. I thought this was a SL issue but turned out a week before it’s release Vlad had been updated to version 2 which used a new plugin system. Looking for vlad rake tasks returned an error:

  >> rake -T vlad
  Could not load vlad: no such file to load -- vlad/git

To solve the problem just required an install of the new vlad-git gem.

  >> sudo gem install vlad-git

Now all my tasks were appearing properly. Vlad 2 always brought around a few changes in it’s deploy.rb and use. Here is my deploy.rb for reference:

  set :application, "yourdomain"
  set :domain, "yourdomain@yourdomain.com"

  set :user, "yourdomain"
  set :repository, "git@github.com:youraccount/yourdomain.git"

  task :staging do
    set :revision, "origin/staging"
    set :deploy_to, "/opt/yourdomain.staging/"
  end   

  task :production do
    set :revision, "origin/master"
    set :deploy_to, "/opt/yourdomain/"
  end

  namespace :vlad do

    desc "Pull from git, run migrations, then (re)start the app server"
    task :migrate_deploy => [:update, :migrate, :start_app]

    desc "Pull from git then (re)start the app server"
    task :deploy => [:update, :start_app]

    desc 'Restart Passenger'
    remote_task :restart do
      puts "Touching: #{deploy_to}current/tmp/restart.txt"
      run "touch #{deploy_to}/current/tmp/restart.txt"
    end

  end

Now invoking Vlad for my staging environment works as such:

  >> rake staging vlad:deploy

The Code Shall Set You Free

Written by Richard. Filed under computing, programming. Tagged , , . No comments.

I was recently asked why I don’t comment my code. It’s a fair enough question. There was a time when commenting your code was the done thing. I was once a great believer in commenting code as much as possible and would bash those that didn’t, but now I vary rarely comment my code at all. In my current project of over 1,500 LOC, there are only a handful of comments. Many people will argue this is irresponsible. Well how is anyone supposed to pick up and understand my code, if it’s not commented?

The code should comment itself.

That just sounds silly. It’s like saying a car should drive itself. But it can be done. A lot of this change of heart about comments has come from my commitment to becoming a better developer and spending countless hours reading about the practice of great development, which is something I’ve written about in the past. I’m a big believer that most of the time if you need to comment a piece of code, then it’s either bad code or too complicated. Of course that’s not true 100% of the time, but for the other 99% it really is. There are cases where things need to be explained and especially warned of, but a lot of the time, commenting is just an easy escape from having to do “proper” coding. It took me years and years to get a basic understanding of proper OO and I’ve still got a long way to go to reaching Journeyman levels of understanding, but I would always create large objects with huge and complex methods, when really what I needed were more concise classes with more responsibility for what they should be able to do. It’s not object orientated when you’re focus is on the method and not the class.

A simple example of commented code:

  # Feed the fish.
  def check_food(food)
     # Check if Fish has eaten more then 5 hours ago.
     if self.last_meal_time < 5.hours.ago
       return "Not hungry"
     # Check if the Fish eats this food.
     elsif !self.edible_foods.contains?(food)
       return "Can't eat that!"
     # Make sure the fish isn't being underfed.
     elsif food.amount <  fish_feeding_amount(self.type)
       return "Not enough food."
     # Make sure the fish isn't being over fed.
     elsif food.amount > fish_feeding_amount(self.type)
       return "Too much food."
     end
     # Eat food.
     self.eat(food)
  end

Most comments can be done away with. If we split out functionality into more concise bits, then just reading the code should explain what’s happening better:

  def feed(food)
    return "Not Hungry" if self.recently_eaten?
    return "Can't eat that!" if self.does_not_eat?(food)
    return "Not Enough food" if self.not_enough_food?(food)
    return "Too much food" if !self.too_much_food?(food)
    self.eat(food)
  end

This isn’t a great example as once again the validation of whether the food can/will be eaten should move into it’s own method or class ever. If we’re follow Uncle Bob’s SOLID principles, the above examples breaks the OCP (Open Closed Principle) where entities should be open to extension and closed to modification. If more validation rules were needed, then that would require the code to be modified.

rake spec fixtures failing

Written by Richard. Filed under programming, rails. Tagged , , . No comments.

For some reason my rspec fixtures were not loading into my development database when doing spec:db:fixtures:load. An extra parameter to db:fixtures:load is all that’s needed.

     >: rake spec:db:fixtures:load
     rake aborted!
     uninitialized constant Fixtures

Fixed by:

     >: rake db:fixtures:load FIXTURES_PATH=spec/fixtures

RSpec + Autotest + Growl + Doom Guy

Written by Richard. Filed under computing, programming. Tagged , , . No comments.

I spent this morning playing around with autotest, but was getting really flaky results with the Growl notifications. I tried about four different autotest configs, but none of them seemed to consistently worked. I remembered that the Growl notifications at Thursday’s Coding Dojo worked pretty well, so after some digging around I found the config on their github. After a tiny tweaking I was even able to get it to work with Przemysław Kowalczyk’s Doom Guy. I’ve packaged it all up and put it on Github. Enjoy.

doomguy-growl-autotest