11
January 15, 2013 Talking to strangers causes train wrecks Mike Toppa, ElectNext.com @mtoppa Wednesday, January 16, 13

Talking to strangers causes train wrecks

  • Upload
    mtoppa

  • View
    1.207

  • Download
    1

Embed Size (px)

DESCRIPTION

I give this as a lightning talk at philly.rb on 1/15/2013. It's a discussion of the challenges of applying the Law of Demeter to Rails programming.

Citation preview

Page 1: Talking to strangers causes train wrecks

January 15, 2013

Talking to strangers causes train wrecksMike Toppa, ElectNext.com @mtoppa

Wednesday, January 16, 13

Page 2: Talking to strangers causes train wrecks

Goal: unpack this quote

“Mockist testers do talk more about avoiding 'train wrecks' - method chains of style getThis().getThat().getTheOther(). Avoiding method chains is also known as following the Law of Demeter. While method chains are a smell, the opposite problem of middle men objects bloated with forwarding methods is also a smell. (I've always felt I'd be more comfortable with the Law of Demeter if it were called the Suggestion of Demeter.)”

Martin Fowler, 2004Mocks aren’t Stubs

Wednesday, January 16, 13

Page 3: Talking to strangers causes train wrecks

✤ What is the Law of Demeter?

✤ How does it pertain to traditional OO vs. ActiveRecord?

✤ What are the implications for testing?

✤ What are the alternatives to train wrecks?

Steps to understanding

Wednesday, January 16, 13

Page 4: Talking to strangers causes train wrecks

The Law of Demeter

✤ AKA Principle of Least Knowledge, AKA “Don’t talk to strangers”

✤ Only Talk To Friends

✤ Objects Closely Related To The Class

✤ Reduces Dependencies

✤ Benefits:

✤ Maintainable Code

✤ Reusable Code

✤ Easy To Understand CodeFrom Don’t Be STUPID, grasp SOLID

Wednesday, January 16, 13

Page 5: Talking to strangers causes train wrecks

A helpful analogy....

✤ You can play with yourself.

✤ You can play with your own toys (but you can’t take them apart),

✤ You can play with toys that were given to you.

✤ And you can play with toys you’ve made yourself.

From Peter Van Rooijen, WikiWiki

Wednesday, January 16, 13

Page 6: Talking to strangers causes train wrecks

Traditional OO approach: dependency inversion

<<interface>>

SwitchableDevice+turnOn()+turnOff()

Button+ poll()

Lamp

class Button { private $switchableDevice;

public function __construct(SwitchableDevice $switchableDevice) { $this->switchableDevice = $switchableDevice; }

public function poll() { if (/* some condition */) { $this->switchableDevice->turnOn(); }} From Agile Software Development

Wednesday, January 16, 13

Page 7: Talking to strangers causes train wrecks

Typical Rails approach:Method chaining

✤ ActiveRecord makes it easy, but at the cost of lost abstraction:

✤ Button class: has_one :lamp

✤ Lamp class: belongs_to :button

✤ button.lamp.turn_on

✤ Which makes it easy to end up with a train wreck...

✤ person.timers.first.button.lamp.turn_on

Wednesday, January 16, 13

Page 8: Talking to strangers causes train wrecks

✤ Mocks become impractical

✤ Factories may help, but FactoryGirl can only go two levels deep:

@weed = FactoryGirl.create(:politician, :with_campaign, name: 'M. Teresa Paiva-Weed')

✤ You will probably need to rely on fixtures or seeding with test data

✤ Bottom line: you will have to rely on integration testing, not unit testing

Testing with train wrecks

Wednesday, January 16, 13

Page 9: Talking to strangers causes train wrecks

Reducing the number of dots I

Use a has_many :through relationship

class Physician < ActiveRecord::Base has_many :appointments has_many :patients, :through => :appointmentsend

Wednesday, January 16, 13

Page 10: Talking to strangers causes train wrecks

Reducing the number of dots II

Use delegation

class User delegate :name, :to => :department, :prefix => true, :allow_nil => true # ...end

....

def user_info(user) "Name: #{user.name}. Dept: #{user.department_name}"end

From Demeter: It’s not just a good idea. It’s the law.

Wednesday, January 16, 13

Page 11: Talking to strangers causes train wrecks

Reducing the number of dots III

✤ Use POROs (plain old ruby objects) for business logic. This means

✤ Your Rails models will be skinny

✤ You can use whatever principles and patterns you want

✤ For me, this is where the conundrum lies:

✤ The speed and power of “the Rails way”

vs.

✤ The adaptability (and testability) of traditional OO patterns

Wednesday, January 16, 13