This talk shows how to use Object-Oriented Design to create the best kinds of messes, those that let you get software out the door today without regretting your actions tomorrow.
This is the 45 minute version, given at GoGaRuCo, Sept. 15 2012.
@sandimetz Sept 2012 Example #1 class
Game
def
shock_cost
Shock.new.cost
end end class
Shock
def
cost
#
lines
of
messy
math
#
...
#
which
eventually
return
cost
end
@sandimetz Sept 2012 Example #1 class
Game
def
shock_cost
Shock.new.cost
end end class
Shock
def
cost
#
lines
of
messy
math
#
...
#
which
eventually
return
cost
end
@sandimetz Sept 2012 Example #1 class
Game
def
shock_cost
Shock.new.cost
end end class
Shock
def
cost
#
lines
of
messy
math
#
...
#
which
eventually
return
cost
end
@sandimetz Sept 2012 Example #1 class
Game
def
shock_cost
Shock.new.cost
end end class
Shock
def
cost
#
lines
of
messy
math
#
...
#
which
eventually
return
cost
end
@sandimetz Sept 2012 Example #1 class
Game
def
shock_cost
Shock.new.cost
end end class
Shock
def
cost
#
lines
of
messy
math
#
...
#
which
eventually
return
cost
end
@sandimetz Sept 2012 Example #1 class
Game
def
shock_cost
Shock.new.cost
end end class
Shock
def
cost
#
lines
of
messy
math
#
...
#
which
eventually
return
cost
end
@sandimetz Sept 2012 Example #1 class
Game
def
shock_cost
Shock.new.cost
end end class
Shock
def
cost
#
lines
of
messy
math
#
...
#
which
eventually
return
cost
end
@sandimetz Sept 2012 class
Game
def
shock_cost
Shock.new.cost
end end class
Shock
def
cost
#
lines
of
messy
math
#
...
#
which
eventually
return
cost
end
@sandimetz Sept 2012 class
Game
def
shock_cost
Shock.new.cost
end end class
Shock
def
cost
#
lines
of
messy
math
#
...
#
which
eventually
return
cost
end
end It’s not about the code Example #1 38 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Plot Stable Unstable Within My Purpose Outside of My Purpose Public API Private Behavior Dependencies 43 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Plot Stable Unstable Within My Purpose Outside of My Purpose Public API Private Behavior Dependencies Expose 43 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Plot Stable Unstable Within My Purpose Outside of My Purpose Public API Private Behavior Dependencies Expose Hide 43 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Plot Stable Unstable Within My Purpose Outside of My Purpose Public API Private Behavior Dependencies Expose Hide Minimize 43 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Plot Stable Unstable Within My Purpose Outside of My Purpose Public API Private Behavior Dependencies Expose Hide Minimize Move 43 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Plot Stable Unstable Within My Purpose Outside of My Purpose Expose Hide Minimize Move 1 2 48 Friday, September 14, 2012
@sandimetz Sept 2012 class
Game
def
shock_cost
Shock.new.cost
end end class
Shock
def
cost
#
lines
of
messy
math
#
...
#
which
eventually
return
cost
end
@sandimetz Sept 2012 class
Game
def
shock_cost
Shock.new.cost
end end class
Shock
def
cost
#
lines
of
messy
math
#
...
#
which
eventually
return
cost
end
@sandimetz Sept 2012 class
Game
def
shock_cost
Shock.new.cost
end end class
Shock
def
cost
#
lines
of
messy
math
#
...
#
which
eventually
return
cost
end
end I would inject this dependency Example #1 56 Friday, September 14, 2012
@sandimetz Sept 2012 class
Game
def
shock_cost
Shock.new.cost
end end class
Shock
def
cost
#
lines
of
messy
math
#
...
#
which
eventually
return
cost
end
end I would inject this dependency I would neaten this mess Example #1 56 Friday, September 14, 2012
@sandimetz Sept 2012 class
Game
def
shock_cost
Shock.new.cost
end end class
Shock
def
cost
#
lines
of
messy
math
#
...
#
which
eventually
return
cost
end
end I would inject this dependency I would neaten this mess You might not Example #1 56 Friday, September 14, 2012
@sandimetz Sept 2012 Example #2 class
Shock
attr_reader
:type
def
initialize(type)
#
...
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end
61 Friday, September 14, 2012
@sandimetz Sept 2012 Example #2 class
Shock
attr_reader
:type
def
initialize(type)
#
...
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end
61 Friday, September 14, 2012
@sandimetz Sept 2012 Example #2 class
Shock
attr_reader
:type
def
initialize(type)
#
...
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end
61 Friday, September 14, 2012
@sandimetz Sept 2012 Example #2 class
Shock
attr_reader
:type
def
initialize(type)
#
...
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end
61 Friday, September 14, 2012
@sandimetz Sept 2012 Example #2 class
Shock
attr_reader
:type
def
initialize(type)
#
...
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end
61 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Shock knows 1. cost method 2. four shock cost calculations 3. four shock types 4. which type gets what calculation 64 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Shock knows 1. cost method 2. four shock cost calculations 3. four shock types 4. which type gets what calculation 64 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Shock knows 1. cost method 2. four shock cost calculations 3. four shock types 4. which type gets what calculation 64 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Shock knows 1. cost method 2. four shock cost calculations 3. four shock types 4. which type gets what calculation 65 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Shock knows 1. cost method 2. four shock cost calculations 3. four shock types 4. which type gets what calculation Meta Knowledge 67 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Shock knows 1. cost method 2. four shock cost calculations 3. four shock types 4. which type gets what calculation 72 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Shock knows 1. cost method 2. four shock cost calculations 3. four shock types 4. which type gets what calculation 72 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Shock knows 1. cost method 2. four shock cost calculations 3. four shock types 4. which type gets what calculation 72 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Shock knows 1. cost method 2. four shock cost calculations (move) 3. four shock types 4. which type gets what calculation 74 Friday, September 14, 2012
@sandimetz Sept 2012 Knowledge Shock knows 1. cost method 2. four shock cost calculations (move) 3. four shock types 4. which type gets what calculation 74 Friday, September 14, 2012
@sandimetz Sept 2012 #3 Composition
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end 83 Friday, September 14, 2012
@sandimetz Sept 2012 #3 Composition
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end 83 Friday, September 14, 2012
@sandimetz Sept 2012 #3 Composition
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end 83 Friday, September 14, 2012
@sandimetz Sept 2012 #3 Composition
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end What’s the message? 83 Friday, September 14, 2012
@sandimetz Sept 2012 #3 Composition
def
cost
case
type
when
:front
someObligingObj.compute
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end 84 Friday, September 14, 2012
@sandimetz Sept 2012 #3 Composition
def
cost
case
type
when
:front
someObligingObj.compute
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end ??? 84 Friday, September 14, 2012
@sandimetz Sept 2012
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end #3 Composition class
FrontShockCost
def
compute
#
the
original
mess
end end 85 Friday, September 14, 2012
@sandimetz Sept 2012
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end #3 Composition class
FrontShockCost
def
compute
#
the
original
mess
end end 85 Friday, September 14, 2012
@sandimetz Sept 2012
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end #3 Composition class
FrontShockCost
def
compute
#
the
original
mess
end end Hide the Mess 85 Friday, September 14, 2012
@sandimetz Sept 2012
def
cost
case
type
when
:front
FrontShockCost.new.compute
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end #3 Composition class
FrontShockCost
def
compute
#
the
original
mess
end end 86 Friday, September 14, 2012
@sandimetz Sept 2012
def
cost
case
type
when
:front
FrontShockCost.new.compute
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end #3 Composition class
FrontShockCost
def
compute
#
the
original
mess
end end Send the Message 86 Friday, September 14, 2012
@sandimetz Sept 2012
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end #3 Composition 87 Friday, September 14, 2012
@sandimetz Sept 2012
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end #3 Composition 87 Friday, September 14, 2012
@sandimetz Sept 2012
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end #3 Composition 87 Friday, September 14, 2012
@sandimetz Sept 2012
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end #3 Composition Hide all of the Messes 87 Friday, September 14, 2012
@sandimetz Sept 2012 #3 Composition class
FrontShockCost
def
compute
#
the
original
mess
end end class
RearShockCost
def
compute
#
slightly
changed
mess
end end #
etc 88 Friday, September 14, 2012
@sandimetz Sept 2012 #3 Composition class
FrontShockCost
def
compute
#
the
original
mess
end end class
RearShockCost
def
compute
#
slightly
changed
mess
end end #
etc 88 Friday, September 14, 2012
@sandimetz Sept 2012 #3 Composition class
FrontShockCost
def
compute
#
the
original
mess
end end class
RearShockCost
def
compute
#
slightly
changed
mess
end end #
etc 88 Friday, September 14, 2012
@sandimetz Sept 2012 #3 Composition class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end 89 Friday, September 14, 2012
@sandimetz Sept 2012 #3 Composition class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end Send the Message 89 Friday, September 14, 2012
@sandimetz Sept 2012 #3 Composition class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end 90 Friday, September 14, 2012
@sandimetz Sept 2012 #3 Composition class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end 90 Friday, September 14, 2012
@sandimetz Sept 2012 #3 Composition class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end Really? 90 Friday, September 14, 2012
@sandimetz Sept 2012 Meta Knowledge Shock knows 1. cost method 2. four shock cost calculations 3. four shock types 4. which type gets what calculation 91 Friday, September 14, 2012
@sandimetz Sept 2012 Meta Knowledge Shock knows 1. cost method 2. four shock cost calculations 3. four shock types 4. which type gets what calculation 91 Friday, September 14, 2012
@sandimetz Sept 2012 Meta Knowledge Shock knows 1. cost method 2. four ShockCostxx classes 3. four shock types 4. which type gets what calculation 92 Friday, September 14, 2012
@sandimetz Sept 2012 Meta Knowledge Shock knows 1. cost method 2. four ShockCostxx classes 3. four shock types 4. which type gets what calculation 93 Friday, September 14, 2012
@sandimetz Sept 2012 Meta Knowledge Shock knows 1. cost method 2. four ShockCostxx classes 3. four shock types 4. which type gets what class 94 Friday, September 14, 2012
@sandimetz Sept 2012 class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end #3 Composition 97 Friday, September 14, 2012
@sandimetz Sept 2012 class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end #3 Composition 97 Friday, September 14, 2012
@sandimetz Sept 2012 class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end when
:front
FrontShockCost.new.compute #3 Composition 98 Friday, September 14, 2012
@sandimetz Sept 2012 class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end when
:foo
FooShockCost.new.compute #3 Composition 98 Friday, September 14, 2012
@sandimetz Sept 2012 class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end when
:foo
FooShockCost.new.compute #3 Composition 98 Friday, September 14, 2012
@sandimetz Sept 2012 class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end when
:foo
FooShockCost.new.compute #3 Composition Convention over con guration 98 Friday, September 14, 2012
@sandimetz Sept 2012 class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end when
:foo
FooShockCost.new.compute class_name
=
type.to_s.titleize
+
"ShockCost" #3 Composition Convention over con guration 98 Friday, September 14, 2012
@sandimetz Sept 2012 class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end class_name
=
type.to_s.titleize
+
"ShockCost" eval(class_name).new.compute #3 Composition Convention over con guration when
:foo
FooShockCost.new.compute 99 Friday, September 14, 2012
@sandimetz Sept 2012 class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end class_name
=
type.to_s.titleize
+
"ShockCost" eval(class_name).new.compute Object.const_get(class_name).new.compute #3 Composition Convention over con guration when
:foo
FooShockCost.new.compute 100 Friday, September 14, 2012
@sandimetz Sept 2012 class
Shock
def
cost(type)
case
type
when
:front
FrontShockCost.new.compute
when
:rear
RearShockCost.new.compute
when
:lefty
LeftyShockCost.new.compute
else
ShockCost.new.compute
end
end
#
... end class_name
=
type.to_s.titleize
+
"ShockCost" eval(class_name).new.compute Object.const_get(class_name).new.compute class_name.constantize.new.compute #3 Composition Convention over con guration when
:foo
FooShockCost.new.compute 101 Friday, September 14, 2012
@sandimetz Sept 2012 Example #3 class
Shock
def
cost(type)
class_name
=
(type.to_s.titleize
+
"ShockCost")
class_name.constantize.new.compute
end end 102 Friday, September 14, 2012
@sandimetz Sept 2012 Example #3 class
Shock
def
cost(type)
class_name
=
(type.to_s.titleize
+
"ShockCost")
class_name.constantize.new.compute
end end 102 Friday, September 14, 2012
@sandimetz Sept 2012 Example #3 class
Shock
def
cost(type)
class_name
=
(type.to_s.titleize
+
"ShockCost")
class_name.constantize.new.compute
end end Factory 102 Friday, September 14, 2012
@sandimetz Sept 2012 Meta Knowledge Shock knows 1. cost method 2. four ShockCostxx classes 3. four shock types 4. which type gets what class 104 Friday, September 14, 2012
@sandimetz Sept 2012 Meta Knowledge Shock knows 1. cost method 2. four ShockCostxx classes 3. four shock types 4. which type gets what class 104 Friday, September 14, 2012
@sandimetz Sept 2012 Meta Knowledge Shock knows 1. cost method 2. four ShockCostxx classes 3. four shock types 4. which type gets what class 104 Friday, September 14, 2012
@sandimetz Sept 2012 Meta Knowledge Shock knows 1. cost method 2. four ShockCostxx classes 3. four shock types 4. which type gets what class 104 Friday, September 14, 2012
@sandimetz Sept 2012 Before #3 Composition
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
#
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end 106 Friday, September 14, 2012
@sandimetz Sept 2012 Before #3 Composition
def
cost
case
type
when
:front
#
the
original
mess
when
:rear
#
a
slightly
#
different
mess
when
:lefty
#
another
variant
else
#
and
so
on.
end
end Many changes affect this code 106 Friday, September 14, 2012
@sandimetz Sept 2012 After Example #3 class
Shock
def
cost(type)
class_name
=
(type.to_s.titleize
+
"ShockCost")
class_name.constantize.new.compute
end end 107 Friday, September 14, 2012
@sandimetz Sept 2012 After Example #3 class
Shock
def
cost(type)
to_class(type).new.compute
end
def
to_class(type)
(type.to_s.titleize
+
"ShockCost").constantize
end end 108 Friday, September 14, 2012
@sandimetz Sept 2012 After Example #3 class
Shock
def
cost(type)
to_class(type).new.compute
end
def
to_class(type)
(type.to_s.titleize
+
"ShockCost").constantize
end end Few changes affect this code 109 Friday, September 14, 2012
@sandimetz Sept 2012 After Example #3 class
FrontShockCost
def
compute
#
the
original
mess
end end class
Shock
def
cost(type)
to_class(type).new.compute
end
def
to_class(type)
(type.to_s.titleize
+
"ShockCost").constantize
end end Few changes affect this code 109 Friday, September 14, 2012
@sandimetz Sept 2012 After Example #3 class
FrontShockCost
def
compute
#
the
original
mess
end end class
Shock
def
cost(type)
to_class(type).new.compute
end
def
to_class(type)
(type.to_s.titleize
+
"ShockCost").constantize
end end class
RearShockCost
def
compute
#
slightly
changed
mess
end end Few changes affect this code 109 Friday, September 14, 2012
@sandimetz Sept 2012 After Example #3 class
FrontShockCost
def
compute
#
the
original
mess
end end class
Shock
def
cost(type)
to_class(type).new.compute
end
def
to_class(type)
(type.to_s.titleize
+
"ShockCost").constantize
end end class
RearShockCost
def
compute
#
slightly
changed
mess
end end Etc... Few changes affect this code 109 Friday, September 14, 2012
@sandimetz Sept 2012 After Example #3 class
FrontShockCost
def
compute
#
the
original
mess
end end class
Shock
def
cost(type)
to_class(type).new.compute
end
def
to_class(type)
(type.to_s.titleize
+
"ShockCost").constantize
end end class
RearShockCost
def
compute
#
slightly
changed
mess
end end Etc... Few changes affect this code Need a new one? Follow the convention! 109 Friday, September 14, 2012