Refactoring complex domains in Ruby and Rails - Pearsoncmg.com

4 downloads 16 Views 2MB Size Report
Nov 13, 2008 ... file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/ presentation_output/presentation.html (1 of 118) [11/13/2008 ...
Refactoring complex domains in Ruby and Rails

Refactoring complex domains in Ruby and Rails Shane Harvie [email protected]

I lied to you

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (1 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

In the outline for this presentation it said: "This session will be light on the slides, and heavy on the code"

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (2 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

the second part is true

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (3 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

it is "heavy on the code"

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (4 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

but I put the code into slides

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (5 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

so it's also "heavy on the slides"

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (6 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

plus I do this partial sentence per slide thing

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (7 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

which isn't helping my slide count

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (8 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

anyway...

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (9 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

Outline



Delegation, Inheritance, and Module extension



State pattern without delegation



Complex Domains in Rails



Separate Query From Modifier

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (10 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

Inheritance is bad, right?

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (11 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

Not necessarily

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (12 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

When would you use inheritance?

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (13 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

When would you use inheritance?



When the subclasses use a large portion of the superclass's behavior



When the subclasses have common state

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (14 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

Let's start with some base class objects which we are using to construct SQL joins: class LeftOuterJoin < Join def join_type "LEFT OUTER" end end class InnerJoin < Join def join_type "INNER" end end

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (15 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

They can be used like so: InnerJoin.new(:equipment_listings, :on => "equipment_listings.listing_id = listings.id").to_sql

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (16 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

The superclass looks like this: class Join... def initialize(table, options) @table = table @on = options[:on] end def to_sql "#{join_type} JOIN #{@table} ON #{@on}" end end

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (17 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

A good inheritance candidate



Has only a few methods in its subclasses



This indicates a strong "is-a" relationship



InnerJoin *is* basically a Join, with only some minor differences



The interface to join also appropriately represents the interface to its subclasses

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (18 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

But inheritance can be used inappropriately

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (19 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

Inheritance used inappropriately





When you find that many of the superclass methods aren't used by all of the subclasses The superclass becomes a dumping ground for behavior that's shared between some subclasses, but not all



In this case, the superclass does not reflect the interface of the subclasses



The superclass often ends up with an obscure name that doesn't make sense in the domain

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (20 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

So we might use Replace Inheritance with Delegation

file:///C|/Documents%20and%20Settings/ugaviba/Desktop/presentation_output/presentation_output/presentation.html (21 of 118) [11/13/2008 1:36:15 PM]

Refactoring complex domains in Ruby and Rails

Replace Inheritance with Delegation

Here I have a policy class which inherits from Hash. Each hash value is an array of rules, and policy gives the hash an array-like interface by implementing the