Design Patterns
Philip Ritchey
slides generously gifted by Jeff Huang
Example 1
• Suppose you want to implement a
output_report functionality for different
formats, e.g, html, pdf, xml.
class Report
def output_report
case @format
when :html
HtmlFormatter.new(self).output
when :pdf
PdfFormatter.new(self).output
• Can’t extend (add new report types) without
changing Report base class
Template method stays the same;
helpers overridden in subclass
Report Generation Using Template
class Report
attr_accessor :title, :text
def output_report
output_title
output_header
output_body
end
end
class HtmlReport < Report
def output_title ... end
def output_header ... end
end
class PdfReport < Report
def output_title ... end
def output_header ... end
end
HtmlReport
output_title()
output_header()
output_body()
PdfReport
output_title()
output_header()
output_body()
Report
output_report()
output_title()
output_header()
output_body()
Delegation
(vs. inheritance)
Report Generation Using Strategy
class Report
attr_accessor :title, :text, :formatter
def output_report
formatter.output_report
end
end
Report
@formatter
output_report()
Formatter
output_report()
HtmlFormatter
output_report()
PdfFormatter
output_report()
“Prefer composition over inheritance”
Example 2
• What’s wrong with this in a view:
- @vips = User.where('group="VIP"')
• A little better:
- @vips = User.find_vips
• Happiness:
# in controller
@vips = User.find_vips
Independent of how VIPs are represented
in model!
ActionView
User
User.where(…)
ActionView
@vips
Controller
User model
@vips
Injecting Dependencies with the
Adapter Pattern
• Problem: client wants to use a “service”...
– service generally supports desired operations
– but the APIs don’t match what client expects
– and/or client must interoperate transparently with
multiple slightly-different services
• Rails example: database “adapters” for MySQL,
Oracle, PostgreSQL, ...
ActiveRecord::Base
connection()
AbstractAdapter
connection()
MySQLAdapter
connection()
mysql_connection()
MySQL
Delegation Overriding
Design Patterns Promote Reuse
“A pattern describes a problem that
occurs often, along with a tried solution to
the problem” - Christopher Alexander, 1977
• Christopher Alexander’s 253 (civil)
architectural patterns range from the
creation of cities (2. distribution of
towns) to particular building problems
(232. roof cap design)
• A pattern language is an organized
way of tackling an architectural problem
using patterns
• Separate the things that change
from those that stay the same
Kinds of Patterns in Software
• Architectural (“macroscale”) patterns
– Model-view-controller
– Pipe & Filter (e.g. compiler, Unix pipeline)
– Event-based (e.g. interactive game)
– Layering (e.g. SaaS technology stack)
• Computation patterns
– Fast Fourier transform
– Structured & unstructured grids
– Dense linear algebra
– Sparse linear algebra
• GoF (Gang of Four) Patterns: structural,
creational, behavioral
The Gang of Four (GoF)
• 23 design patterns
• Description of communicating
objects & classes
– Captures common (and
successful) solution to a category
of related problem instances
– Can be customized to solve a
specific (new) problem in that
category
• Pattern ≠
– Individual classes or libraries (list, hash, ...)
– Full design - more like a blueprint for a design
The GoF Pattern Zoo
1. Factory
2. Abstract Factory
3. Builder
4. Prototype
5. Singleton/Null
Obj
6. Adapter
7. Composite
8. Proxy
9. Bridge
10. Flyweight
11. Façade
12. Decorator
13. Observer
14. Mediator
15. Chain of responsibility
16. Command
17. Interpreter
18. Iterator
19. Memento (memoization)
20. State
21. Strategy
22. Template
23. Visitor
Creational
Structural
Behavioral
Just Enough UML
• Unified Modeling Language (UML):
notation for describing various artifacts in
OOP systems
• One type of UML diagram is a class diagram,
showing class relationships and principal
methods:
– Car is a subclass of Vehicle
– Engine is a component of Car
– Engine includes start(),
stop() methods
Relationships
Relationships
Aggregation
Composition
Inheritance
Too Much UML
Observer
• Problem: entity O (“observer”) wants to know when
certain things happen to entity S (“subject”)
• Design issues
– acting on events is O’s concern—don’t want to pollute S
– any type of object could be an observer or subject—
inheritance is awkward
• Example use cases
– full-text indexer wants to
know about new post (e.g.
eBay, Craigslist)
– auditor wants to know
whenever “sensitive” actions
are performed by an admin
Visitor
• When traversing data structure (DS), provide a
callback method to execute for each DS member
– Visit each element without knowing how the data
structure is organized
SOLID OOP principles
(Robert C. Martin, co-author of Agile Manifesto)
Motivation: minimize cost of change
• Single Responsibility principle
• Open/Closed principle
• Liskov substitution principle
• Injection of dependencies
– Traditionally, Interface Segregation principle
• Demeter principle
Single Responsibility Principle
(SRP)
• A class should have one and only one
reason to change
– Each responsibility is a possible axis of change
– Changes to one axis shouldn’t affect others
• What is class’s responsibility, in ≤25 words?
– Part of the craft of OO design is defining
responsibilities and then sticking to them
• Models with many sets of behaviors
– E.g. a user is a moviegoer, an authentication
principal, a social network member, etc.
– really big class files are a tipoff of SRP violation
Lack of Cohesion of Methods
• Revised Henderson-Sellers LCOM
LCOM = 1 – ((MVi)) / (MV) (between 0 and 1)
– M = # instance methods
– V = # instance variables
– MVi = # instance methods that access the i’th instance
variable (excluding “trivial” getters/setters)
• LCOM-4 counts # of connected components in
graph where related methods are connected by an
edge
• High LCOM suggests possible SRP violation
19
Open/Closed Principle
• Classes should be open for extension, but
closed for source modification
class Report
def output_report
case @format
when :html
HtmlFormatter.new(self).output
when :pdf
PdfFormatter.new(self).output
• Can’t extend (add new report types) without
changing Report base class
–Not as bad as in statically typed language...but still ugly
Template Method Pattern &
Strategy Pattern
• Template method: set of steps is the same, but
implementation of steps different
– Inheritance: subclasses override abstract “step” methods
• Strategy: task is the same, but many ways to do it
– composition: component classes implement whole task
Template method stays the same;
helpers overridden in subclass
Report Generation Using Template
class Report
attr_accessor :title, :text
def output_report
output_title
output_header
output_body
end
end
class HtmlReport < Report
def output_title ... end
def output_header ... end
end
class PdfReport < Report
def output_title ... end
def output_header ... end
end
HtmlReport
output_title()
output_header()
output_body()
PdfReport
output_title()
output_header()
output_body()
Report
output_report()
output_title()
output_header()
output_body()
Delegation
(vs. inheritance)
Report Generation Using Strategy
class Report
attr_accessor :title, :text, :formatter
def output_report
formatter.output_report
end
end
Report
@formatter
output_report()
Formatter
output_report()
HtmlFormatter
output_report()
PdfFormatter
output_report()
“Prefer composition over inheritance”
Decorator Pattern: DRYing Out
Extension Points
Example in Rails: ActiveRecord scopes
Movie.for_kids.with_good_reviews(3)
Movie.with_many_fans.recently_reviewed
Another example of composition over inheritance!
Liskov Substitution: Subtypes Can
Substitute for Base Types
• Current formulation attributed to (Turing
Award winner) Barbara Liskov
• Let’s see an example
• Type/subtype != class/subclass
With duck typing, substitutability depends
on how collaborators interact with object
“A method that works on an instance of
type T, should also work on any
subtype of T”
http://pastebin.com/nf2D9RYj
Contracts
• Composition vs. (misuse of) inheritance
• If can’t express consistent assumptions
about “contract” between class &
collaborators, likely LSP violation
– Symptom: change to subclass requires change
to superclass (shotgun surgery)
Square
@rect
area(), perimeter()
Rectangle
width, height
area(), perimeter()
Rectangle
area, perimeter
width, height
Square
make_twice_as_wide
_as_high
Dependency Inversion
& Dependency Injection
• Problem: a depends on b, but b
interface & implementation can
change, even if functionality stable
• Solution: “inject” an abstract
interface that a & b depend on
– If not exact match, Adapter/Façade
– “inversion”: now b (and a) depend on
interface, vs. a depending on b
• Ruby equivalent: Extract a Module
to isolate the interface
SessionStore
Database
read_from_db()
store_in_db()
SessionMgr
get_session()
store_session()
«interface»
SessionStore
Database
DIP in Rails: Example
• What’s wrong with this in a view:
- @vips = User.where('group="VIP"')
• A little better:
- @vips = User.find_vips
• Happiness:
# in controller
@vips = User.find_vips
Independent of how VIPs are represented
in model!
ActionView
User
User.where(…)
ActionView
@vips
Controller
User model
@vips
Injecting Dependencies with the
Adapter Pattern
• Problem: client wants to use a “service”...
– service generally supports desired operations
– but the APIs don’t match what client expects
– and/or client must interoperate transparently with
multiple slightly-different services
• Rails example: database “adapters” for MySQL,
Oracle, PostgreSQL, ...
ActiveRecord::Base
connection()
AbstractAdapter
connection()
MySQLAdapter
connection()
mysql_connection()
MySQL
Delegation Overriding
Example:
Supporting External Services
• Suppose RottenPotatoes adds email
marketing – send discount emails to
moviegoers
• Use external service MailerMonkey
• Suppose very popular, you want to extend to
send emails to Amiko friends
• Suppose Amiko exposes a different API
– Adaptor:
http://pastebin.com/ZdhcYb7w
http://pastebin.com/8PHBpm5k
http://pastebin.com/Eimsw8ZF
Related: Null Object
• Problem: want invariants to simplify design,
but app requirements seem to break this
• Null object: stand-in on which “important”
methods can be called
@customer = Customer.null_customer
@customer.logged_in? # => false
@customer.last_name # => "ANONYMOUS"
@customer.is_vip? # => false
EmailList
opt_in()
opt_out()
update_email()
MailchimpList
subscribe()
unsubscribe()
update_member()
FakeEmailList
opt_in()
opt_out()
update_email()
Example:
Supporting External Services
• We want to disable email sending from time
to time http://pastebin.com/js6C67mJ
http://pastebin.com/avRQAgZc
Demeter Principle
• Only talk to your friends...not strangers
• You can call methods on:
– yourself
– your own instance variables, if applicable
• But not on the results returned by them
• Solutions:
– Replace method with delegate
– Be aware of important events without knowing
implementation details (Observer)
– Separate traversal from computation (Visitor)
http://pastebin.com/NRSkHstN
Getting Started with
Design Patterns
• GoF distinguishes design patterns from
frameworks
– Patterns are more abstract, narrower in focus,
not targeted to problem domain
• Nevertheless, frameworks great way for
novice to get started with design patterns
– Gain experience on creating code based on
design patterns by examining patterns in
frameworks instantiated as code
34
A Few Patterns Seen in Rails
• Adapter (database connection)
• Abstract Factory (database connection)
• Observer (caching—Chapter 12)
• Proxy (AR association collections)
• Singleton (Inflector)
• Decorator (AR scopes, alias_method_chain)
• Command (migrations)
• Iterator (everywhere)
• Duck typing simplifies expressing and “plumbing”
most of these by “weakening” the relative coupling
of inheritance
SOLID Caveat
• Designed for statically typed languages, so
some principles have more impact there
– “avoid changes that modify type signature”
(often implies contract change)—but Ruby
doesn’t really use types
– “avoid changes that require gratuitous
recompiling”—but Ruby isn’t compiled
• Use judgment: goal is deliver working &
maintainable code quickly
Summary
• Design patterns represent successful solutions to
classes of problems
– Reuse of design rather than code/classes
– A few patterns “reified” in Rails since useful to SaaS
• Can apply at many levels: architecture, design
(GoF patterns), computation
• Separate what changes from what stays the same
– program to interface, not implementation
– prefer composition over inheritance
– delegate!
– all 3 are made easier by duck typing
• Much more to read & know—this is just an intro
Refactoring & Design Patterns
Methods within a class Relationships among classes
Code smells Design smells
Many catalogs of code smells &
refactorings
Many catalogs of design smells &
design patterns
Some refactorings are superfluous
in Ruby
Some design patterns are
superfluous in Ruby
Metrics: ABC & Cyclomatic
Complexity
Metrics: Lack of Cohesion of
Methods (LCOM)
Refactor by extracting methods and
moving around code within a class
Refactor by extracting classes and
moving code between classes
SOFA: methods are Short, do One
thing, have Few arguments, single
level of Abstraction
SOLID: Single responsibility per
class, Open/closed principle, Liskov
substitutability, Injection of
dependencies, Demeter principle

Patterns of Design, as Presented by Ritchey

  • 1.
    Design Patterns Philip Ritchey slidesgenerously gifted by Jeff Huang
  • 2.
    Example 1 • Supposeyou want to implement a output_report functionality for different formats, e.g, html, pdf, xml. class Report def output_report case @format when :html HtmlFormatter.new(self).output when :pdf PdfFormatter.new(self).output • Can’t extend (add new report types) without changing Report base class
  • 3.
    Template method staysthe same; helpers overridden in subclass Report Generation Using Template class Report attr_accessor :title, :text def output_report output_title output_header output_body end end class HtmlReport < Report def output_title ... end def output_header ... end end class PdfReport < Report def output_title ... end def output_header ... end end HtmlReport output_title() output_header() output_body() PdfReport output_title() output_header() output_body() Report output_report() output_title() output_header() output_body()
  • 4.
    Delegation (vs. inheritance) Report GenerationUsing Strategy class Report attr_accessor :title, :text, :formatter def output_report formatter.output_report end end Report @formatter output_report() Formatter output_report() HtmlFormatter output_report() PdfFormatter output_report() “Prefer composition over inheritance”
  • 5.
    Example 2 • What’swrong with this in a view: - @vips = User.where('group="VIP"') • A little better: - @vips = User.find_vips • Happiness: # in controller @vips = User.find_vips Independent of how VIPs are represented in model! ActionView User User.where(…) ActionView @vips Controller User model @vips
  • 6.
    Injecting Dependencies withthe Adapter Pattern • Problem: client wants to use a “service”... – service generally supports desired operations – but the APIs don’t match what client expects – and/or client must interoperate transparently with multiple slightly-different services • Rails example: database “adapters” for MySQL, Oracle, PostgreSQL, ... ActiveRecord::Base connection() AbstractAdapter connection() MySQLAdapter connection() mysql_connection() MySQL Delegation Overriding
  • 7.
    Design Patterns PromoteReuse “A pattern describes a problem that occurs often, along with a tried solution to the problem” - Christopher Alexander, 1977 • Christopher Alexander’s 253 (civil) architectural patterns range from the creation of cities (2. distribution of towns) to particular building problems (232. roof cap design) • A pattern language is an organized way of tackling an architectural problem using patterns • Separate the things that change from those that stay the same
  • 8.
    Kinds of Patternsin Software • Architectural (“macroscale”) patterns – Model-view-controller – Pipe & Filter (e.g. compiler, Unix pipeline) – Event-based (e.g. interactive game) – Layering (e.g. SaaS technology stack) • Computation patterns – Fast Fourier transform – Structured & unstructured grids – Dense linear algebra – Sparse linear algebra • GoF (Gang of Four) Patterns: structural, creational, behavioral
  • 9.
    The Gang ofFour (GoF) • 23 design patterns • Description of communicating objects & classes – Captures common (and successful) solution to a category of related problem instances – Can be customized to solve a specific (new) problem in that category • Pattern ≠ – Individual classes or libraries (list, hash, ...) – Full design - more like a blueprint for a design
  • 10.
    The GoF PatternZoo 1. Factory 2. Abstract Factory 3. Builder 4. Prototype 5. Singleton/Null Obj 6. Adapter 7. Composite 8. Proxy 9. Bridge 10. Flyweight 11. Façade 12. Decorator 13. Observer 14. Mediator 15. Chain of responsibility 16. Command 17. Interpreter 18. Iterator 19. Memento (memoization) 20. State 21. Strategy 22. Template 23. Visitor Creational Structural Behavioral
  • 11.
    Just Enough UML •Unified Modeling Language (UML): notation for describing various artifacts in OOP systems • One type of UML diagram is a class diagram, showing class relationships and principal methods: – Car is a subclass of Vehicle – Engine is a component of Car – Engine includes start(), stop() methods
  • 12.
  • 13.
  • 14.
  • 15.
    Observer • Problem: entityO (“observer”) wants to know when certain things happen to entity S (“subject”) • Design issues – acting on events is O’s concern—don’t want to pollute S – any type of object could be an observer or subject— inheritance is awkward • Example use cases – full-text indexer wants to know about new post (e.g. eBay, Craigslist) – auditor wants to know whenever “sensitive” actions are performed by an admin
  • 16.
    Visitor • When traversingdata structure (DS), provide a callback method to execute for each DS member – Visit each element without knowing how the data structure is organized
  • 17.
    SOLID OOP principles (RobertC. Martin, co-author of Agile Manifesto) Motivation: minimize cost of change • Single Responsibility principle • Open/Closed principle • Liskov substitution principle • Injection of dependencies – Traditionally, Interface Segregation principle • Demeter principle
  • 18.
    Single Responsibility Principle (SRP) •A class should have one and only one reason to change – Each responsibility is a possible axis of change – Changes to one axis shouldn’t affect others • What is class’s responsibility, in ≤25 words? – Part of the craft of OO design is defining responsibilities and then sticking to them • Models with many sets of behaviors – E.g. a user is a moviegoer, an authentication principal, a social network member, etc. – really big class files are a tipoff of SRP violation
  • 19.
    Lack of Cohesionof Methods • Revised Henderson-Sellers LCOM LCOM = 1 – ((MVi)) / (MV) (between 0 and 1) – M = # instance methods – V = # instance variables – MVi = # instance methods that access the i’th instance variable (excluding “trivial” getters/setters) • LCOM-4 counts # of connected components in graph where related methods are connected by an edge • High LCOM suggests possible SRP violation 19
  • 20.
    Open/Closed Principle • Classesshould be open for extension, but closed for source modification class Report def output_report case @format when :html HtmlFormatter.new(self).output when :pdf PdfFormatter.new(self).output • Can’t extend (add new report types) without changing Report base class –Not as bad as in statically typed language...but still ugly
  • 21.
    Template Method Pattern& Strategy Pattern • Template method: set of steps is the same, but implementation of steps different – Inheritance: subclasses override abstract “step” methods • Strategy: task is the same, but many ways to do it – composition: component classes implement whole task
  • 22.
    Template method staysthe same; helpers overridden in subclass Report Generation Using Template class Report attr_accessor :title, :text def output_report output_title output_header output_body end end class HtmlReport < Report def output_title ... end def output_header ... end end class PdfReport < Report def output_title ... end def output_header ... end end HtmlReport output_title() output_header() output_body() PdfReport output_title() output_header() output_body() Report output_report() output_title() output_header() output_body()
  • 23.
    Delegation (vs. inheritance) Report GenerationUsing Strategy class Report attr_accessor :title, :text, :formatter def output_report formatter.output_report end end Report @formatter output_report() Formatter output_report() HtmlFormatter output_report() PdfFormatter output_report() “Prefer composition over inheritance”
  • 24.
    Decorator Pattern: DRYingOut Extension Points Example in Rails: ActiveRecord scopes Movie.for_kids.with_good_reviews(3) Movie.with_many_fans.recently_reviewed Another example of composition over inheritance!
  • 25.
    Liskov Substitution: SubtypesCan Substitute for Base Types • Current formulation attributed to (Turing Award winner) Barbara Liskov • Let’s see an example • Type/subtype != class/subclass With duck typing, substitutability depends on how collaborators interact with object “A method that works on an instance of type T, should also work on any subtype of T” http://pastebin.com/nf2D9RYj
  • 26.
    Contracts • Composition vs.(misuse of) inheritance • If can’t express consistent assumptions about “contract” between class & collaborators, likely LSP violation – Symptom: change to subclass requires change to superclass (shotgun surgery) Square @rect area(), perimeter() Rectangle width, height area(), perimeter() Rectangle area, perimeter width, height Square make_twice_as_wide _as_high
  • 27.
    Dependency Inversion & DependencyInjection • Problem: a depends on b, but b interface & implementation can change, even if functionality stable • Solution: “inject” an abstract interface that a & b depend on – If not exact match, Adapter/Façade – “inversion”: now b (and a) depend on interface, vs. a depending on b • Ruby equivalent: Extract a Module to isolate the interface SessionStore Database read_from_db() store_in_db() SessionMgr get_session() store_session() «interface» SessionStore Database
  • 28.
    DIP in Rails:Example • What’s wrong with this in a view: - @vips = User.where('group="VIP"') • A little better: - @vips = User.find_vips • Happiness: # in controller @vips = User.find_vips Independent of how VIPs are represented in model! ActionView User User.where(…) ActionView @vips Controller User model @vips
  • 29.
    Injecting Dependencies withthe Adapter Pattern • Problem: client wants to use a “service”... – service generally supports desired operations – but the APIs don’t match what client expects – and/or client must interoperate transparently with multiple slightly-different services • Rails example: database “adapters” for MySQL, Oracle, PostgreSQL, ... ActiveRecord::Base connection() AbstractAdapter connection() MySQLAdapter connection() mysql_connection() MySQL Delegation Overriding
  • 30.
    Example: Supporting External Services •Suppose RottenPotatoes adds email marketing – send discount emails to moviegoers • Use external service MailerMonkey • Suppose very popular, you want to extend to send emails to Amiko friends • Suppose Amiko exposes a different API – Adaptor: http://pastebin.com/ZdhcYb7w http://pastebin.com/8PHBpm5k http://pastebin.com/Eimsw8ZF
  • 31.
    Related: Null Object •Problem: want invariants to simplify design, but app requirements seem to break this • Null object: stand-in on which “important” methods can be called @customer = Customer.null_customer @customer.logged_in? # => false @customer.last_name # => "ANONYMOUS" @customer.is_vip? # => false EmailList opt_in() opt_out() update_email() MailchimpList subscribe() unsubscribe() update_member() FakeEmailList opt_in() opt_out() update_email()
  • 32.
    Example: Supporting External Services •We want to disable email sending from time to time http://pastebin.com/js6C67mJ http://pastebin.com/avRQAgZc
  • 33.
    Demeter Principle • Onlytalk to your friends...not strangers • You can call methods on: – yourself – your own instance variables, if applicable • But not on the results returned by them • Solutions: – Replace method with delegate – Be aware of important events without knowing implementation details (Observer) – Separate traversal from computation (Visitor) http://pastebin.com/NRSkHstN
  • 34.
    Getting Started with DesignPatterns • GoF distinguishes design patterns from frameworks – Patterns are more abstract, narrower in focus, not targeted to problem domain • Nevertheless, frameworks great way for novice to get started with design patterns – Gain experience on creating code based on design patterns by examining patterns in frameworks instantiated as code 34
  • 35.
    A Few PatternsSeen in Rails • Adapter (database connection) • Abstract Factory (database connection) • Observer (caching—Chapter 12) • Proxy (AR association collections) • Singleton (Inflector) • Decorator (AR scopes, alias_method_chain) • Command (migrations) • Iterator (everywhere) • Duck typing simplifies expressing and “plumbing” most of these by “weakening” the relative coupling of inheritance
  • 36.
    SOLID Caveat • Designedfor statically typed languages, so some principles have more impact there – “avoid changes that modify type signature” (often implies contract change)—but Ruby doesn’t really use types – “avoid changes that require gratuitous recompiling”—but Ruby isn’t compiled • Use judgment: goal is deliver working & maintainable code quickly
  • 37.
    Summary • Design patternsrepresent successful solutions to classes of problems – Reuse of design rather than code/classes – A few patterns “reified” in Rails since useful to SaaS • Can apply at many levels: architecture, design (GoF patterns), computation • Separate what changes from what stays the same – program to interface, not implementation – prefer composition over inheritance – delegate! – all 3 are made easier by duck typing • Much more to read & know—this is just an intro
  • 38.
    Refactoring & DesignPatterns Methods within a class Relationships among classes Code smells Design smells Many catalogs of code smells & refactorings Many catalogs of design smells & design patterns Some refactorings are superfluous in Ruby Some design patterns are superfluous in Ruby Metrics: ABC & Cyclomatic Complexity Metrics: Lack of Cohesion of Methods (LCOM) Refactor by extracting methods and moving around code within a class Refactor by extracting classes and moving code between classes SOFA: methods are Short, do One thing, have Few arguments, single level of Abstraction SOLID: Single responsibility per class, Open/closed principle, Liskov substitutability, Injection of dependencies, Demeter principle

Editor's Notes

  • #3 Optional
  • #10 Patterns in italics covered in ESAAS book
  • #11 Use UML to aid your documentation, not as a formal specification.
  • #14 Does not fit in with agile methods. Use UML when it helps you document and communicate, not as a formal specification. Lots of UML can be appropriate in safety-critical systems – systems where you must formally prove something about the behavior.
  • #22 Optional
  • #26 COPY PASTE
  • #27 In static language, interfaces can shield you from having to recompile; in Ruby there's no compilation. In static language, implementing an interface involves statically-checkable promises; in Ruby you can implement an interface by mixing in new methods to a class, or by subclassing.