Share
Embed
Eastward HO!
Jim Gay
November 19, 2014
Transcript
145 slides
-
EASTWARD HO! A clear path with OO Jim Gay /
@saturnflyer -
IF IF IF IF IF IF IF IF IF IF
IF IF IF -
class Person! attr_reader :address! ! def display_address! ! end! end!
"123 Main St. Arlington" ! "123 Main St. VA 22222" "123 Main St. Arlington, VA 22222” ! "Arlington, VA" -
class Person! attr_reader :address! ! def display_address! ! end! end!
"123 Main St. Arlington" ! "123 Main St. VA 22222" "123 Main St. Arlington, VA 22222” ! "Arlington, VA" -
class Person! def display_address! "".tap do |string|! if !address.street.nil? ||
!address.street.empty?! string << address.street! end! ! string << "\n" unless string.empty?! ! if !address.city.nil? address.city.empty? || address.city.nil?! string << address.city! end! ! if address.province || address.postal_code! string << ", "! end! ! if address.province || address.postal_code! if address.province! string << address.province! end! ! string << " "! ! "123 Main St. Arlington" ! "123 Main St. VA 22222" "123 Main St. Arlington, VA 22222” ! "Arlington, VA" -
class Person! def display_address! ! ! ! ! ! !
! # … all the code …! ! ! ! ! ! ! ! ! ! ! self! end! end! "123 Main St. Arlington" ! "123 Main St. VA 22222" "123 Main St. Arlington, VA 22222” ! "Arlington, VA" RULE 1 -
class Person! def display_address! ! ! ! ! ! !
! # … all the code …! ! ! ! ! ! ! ! ! ! ! self! end! end! "123 Main St. Arlington" ! "123 Main St. VA 22222" "123 Main St. Arlington, VA 22222” ! "Arlington, VA" -
Tell, Don’t Ask ensure a correct division of
responsibility that places the right functionality in the right class without causing excess coupling to other classes. Andy Hunt and Dave Thomas -
Tell, Don’t Ask ensure a correct division of
responsibility that places the right functionality in the right class without causing excess coupling to other classes. Andy Hunt and Dave Thomas -
Command, Don’t Query ! ! ! if !address.street.nil? ||
!address.street.empty?! string << address.street! end -
Command, Don’t Query ! ! ! if !address.street.nil? ||
!address.street.empty?! string << address.street! end -
Command, Don’t Query ! ! ! if !address.street.nil? ||
!address.street.empty?! string << address.street! end -
Command, Don’t Query ! ! ! if !address.street.nil? ||
!address.street.empty?! string << address.street! end -
class Person! def display_address! "".tap do |string|! if !address.street.nil? ||
!address.street.empty?! string << address.street! end! ! string << "\n" unless string.empty?! ! if !address.city.nil? address.city.empty? || address.city.nil?! string << address.city! end! ! if address.province || address.postal_code! string << ", "! end! ! if address.province || address.postal_code! if address.province! string << address.province! end! ! string << " "! ! -
The Pretty Good Idea of Demeter ! ! ! if
!address.street.nil? || !address.street.empty?! string << address.street! end -
The Pretty Good Idea of Demeter ! ! ! if
!address.street.nil? || !address.street.empty?! string << address.street! end -
The Pretty Good Idea of Demeter ! ! ! if
!address.street.nil? || !address.street.empty?! string << address.street! end -
The Pretty Good Idea of Demeter ! ! ! if
!address.street.nil? || !address.street.empty?! string << address.street! end -
The Pretty Good Idea of Demeter ! ! ! if
!address.street.nil? || !address.street.empty?! string << address.street! end -
class Person! def display_address! "".tap do |string|! if !address.street.nil? ||
!address.street.empty?! string << address.street! end! ! string << "\n" unless string.empty?! ! if !address.city.nil? address.city.empty? || address.city.nil?! string << address.city! end! ! if address.province || address.postal_code! string << ", "! end! ! if address.province || address.postal_code! if address.province! string << address.province! end! ! string << " "! ! -
class Person! def display_address! address.display! ! ! self! end! end!
! class Address! def display! "".tap do |string|! if !street.nil? || !street.empty?! string << street! end! ! string << "\n" unless string.empty?! ! if !city.nil? city.empty? || city.nil?! string << city! end! ! if province || postal_code! string << ", "! end! -
class Person! def display_address! address.display! ! ! self! end! end!
! class Address! def display! "".tap do |string|! if !street.nil? || !street.empty?! string << street! end! ! string << "\n" unless string.empty?! ! if !city.nil? city.empty? || city.nil?! string << city! end! ! if province || postal_code! string << ", "! end! RULE 2 -
class Address! def display! ! ! ! ! ! !
! end! end -
class Address! def display! province_and_postal_code = [province, postal_code].compact.join(' ')! province_and_postal_code
= nil if province_and_postal_code.empty?! ! ! ! ! ! end! end "" "VA 22222" "VA 22222” "VA" -
class Address! def display! province_and_postal_code = [province, postal_code].compact.join(' ')! province_and_postal_code
= nil if province_and_postal_code.empty?! ! city_province_postal_code = [city, province_and_postal_code].compact.join(', ')! city_province_postal_code = nil if city_province_postal_code.empty?! ! ! end! end "Arlington" "VA 22222" “Arlington, VA 22222” “Arlington, VA" -
class Address! def display! province_and_postal_code = [province, postal_code].compact.join(' ')! province_and_postal_code
= nil if province_and_postal_code.empty?! ! city_province_postal_code = [city, province_and_postal_code].compact.join(', ')! city_province_postal_code = nil if city_province_postal_code.empty?! ! [street, city_province_postal_code].compact.join("\n")! end! end “123 Main St. Arlington” “123 Main St. VA 22222" “123 Main St. Arlington, VA 22222” “Arlington, VA" -
class Address! def display! province_and_postal_code = [province, postal_code].compact.join(' ')! province_and_postal_code
= nil if province_and_postal_code.empty?! ! city_province_postal_code = [city, province_and_postal_code].compact.join(', ')! city_province_postal_code = nil if city_province_postal_code.empty?! ! [street, city_province_postal_code].compact.join("\n")! end! end -
class Address! def display(line_break="\n")! province_and_postal_code = [province, postal_code].compact.join(' ')! province_and_postal_code
= nil if province_and_postal_code.empty?! ! city_province_postal_code = [city, province_and_postal_code].compact.join(', ')! city_province_postal_code = nil if city_province_postal_code.empty?! ! [street, city_province_postal_code].compact.join(line_break)! end! end -
class Address! def display(line_break="\n")! province_and_postal_code = [province, postal_code].compact.join(' ')! province_and_postal_code
= nil if province_and_postal_code.empty?! ! city_province_postal_code = [city, province_and_postal_code].compact.join(', ')! city_province_postal_code = nil if city_province_postal_code.empty?! ! [street, city_province_postal_code].compact.join(line_break)! end! end! ! class Person! def display_address(line_break)! address.display(line_break)! self! end! end -
class Address! def display(line_break="\n")! province_and_postal_code = [province, postal_code].compact.join(' ')! province_and_postal_code
= nil if province_and_postal_code.empty?! ! city_province_postal_code = [city, province_and_postal_code].compact.join(', ')! city_province_postal_code = nil if city_province_postal_code.empty?! ! [street, city_province_postal_code].compact.join(line_break)! end! end! ! class Person! def display_address(line_break)! address.display(line_break)! self! end! end -
class Template! def display_address(address)! province_and_postal_code = [address.province, address.postal_code].compact.join(' ' province_and_postal_code
= nil if province_and_postal_code.empty?! ! city_province_postal_code = [address.city, province_and_postal_code].compact.join(' city_province_postal_code = nil if city_province_postal_code.empty?! ! STDOUT.puts [address.street, city_province_postal_code].compact.join(“\n")! ! self! end! end -
class Template! def display_address(address)! province_and_postal_code = [address.province, address.postal_code].compact.join(' ' province_and_postal_code
= nil if province_and_postal_code.empty?! ! city_province_postal_code = [address.city, province_and_postal_code].compact.join(' city_province_postal_code = nil if city_province_postal_code.empty?! ! STDOUT.puts [address.street, city_province_postal_code].compact.join(“\n")! ! self! end! end! ! class HtmlTemplate! def display_address(address)! ! ! # data processing… ! ! File.open ‘address.html’ do |file|! file.write [address.street, city_province_postal_code].compact.join("<br />”)! end! ! self! end! -
class Person! def display_address(template=Template.new)! address.display(template)! self! end! end! ! class
Address! def display(template)! template.display_address(self)! self! end! end! -
class Person! def display_address(template=Template.new)! address.display(template)! self! end! end! ! class
Address! def display(template)! template.display_address(self)! self! end! end! ! class Template! def display_address(address)! # data processing…! ! ! STDOUT.puts [address.street, city_province_postal_code].compact.join(“\n")! ! self! end! end -
class Person! def display_address(template=Template.new)! address.display(template)! self! end! end! ! class
Address! def display(template)! template.display_address(self)! self! end! end -
class Person! def display_address(template=Template.new)! address.display(template)! self! end! end! ! !
! ! class Address! def display(template)! template.display_address(self)! self! end! end -
class Person! def display_address(template=Template.new)! address.display(template)! self! end! ! private! attr_reader
:address! end! ! class Address! def display(template)! template.display_address(self)! self! end! ! private! attr_reader :street, :city, :province, :postal_code! end -
class Address! def display(template)! template.display_address(self)! self! end! ! private! attr_reader
:street, :city, :province, :postal_code! end -
class Address! def display(template)! template.display_address(self)! self! end! ! private! attr_reader
:street, :city, :province, :postal_code! end! ! class Template! def display_address(address)! province_and_postal_code = [address.province, address.postal_code].compact.join(' ' province_and_postal_code = nil if province_and_postal_code.empty?! ! city_province_postal_code = [address.city, province_and_postal_code].compact.join(' city_province_postal_code = nil if city_province_postal_code.empty?! ! STDOUT.puts [address.street, city_province_postal_code].compact.join(“\n")! ! self! end! end -
class Address! def display(template)! template.display_address(self)! self! end! ! private! attr_reader
:street, :city, :province, :postal_code! end! ! ! ! ! ! ! class Template! def display_address(address)! # …code…! end! end -
class Address! def display(template)! template.display_address(to_value)! self! end! ! private! attr_reader
:street, :city, :province, :postal_code! ! require ‘ostruct’! def to_value! OpenStruct.new(street: street, city: city, province: province, postal_code: postal_ end! end! ! class Template! def display_address(address)! # …code…! end! end -
class Address! def display(template)! template.display_address(to_value)! self! end! ! private! attr_reader
:street, :city, :province, :postal_code! ! require ‘ostruct’! def to_value! OpenStruct.new(street: street, city: city, province: province, postal_code: postal_ end! end! ! class Template! def display_address(address)! # …code…! end! end -
“123 Main St. Arlington” “123 Main St. VA 22222" “123
Main St. Arlington, VA 22222” “Arlington, VA" -
class Address! def display(template)! template.display_address(to_value)! self! end! ! private! attr_reader
:street, :city, :province, :postal_code! ! require ‘ostruct’! def to_value! OpenStruct.new(street: street, city: city, province: province, postal_code: postal_ end! end -
class Address! def display(template)! template.display_address(to_value)! self! end! ! private! attr_reader
:street, :city, :province, :postal_code! ! require ‘ostruct’! def to_value! if protect_privacy?! OpenStruct.new(street: nil, city: city, province: province, postal_code: nil)! else! OpenStruct.new(street: street, city: city, province: province, postal_code: posta end! end! end -
class Template! def display_address(address)! province_and_postal_code = [address.province, address.postal_code].compact.join(' ' province_and_postal_code
= nil if province_and_postal_code.empty?! ! city_province_postal_code = [address.city, province_and_postal_code].compact.join(' city_province_postal_code = nil if city_province_postal_code.empty?! ! STDOUT.puts [address.street, city_province_postal_code].compact.join(“\n")! ! self! end! end -
class Template! def display_address(address)! province_and_postal_code = [address.province, address.postal_code].compact.join(' ' province_and_postal_code
= nil if province_and_postal_code.empty?! ! city_province_postal_code = [address.city, province_and_postal_code].compact.join(' city_province_postal_code = nil if city_province_postal_code.empty?! ! STDOUT.puts [address.street, city_province_postal_code].compact.join(“\n")! ! self! end! end QUERIES EVERYWHERE -
class Person! def display_address(template=Template.new)! address.display(template)! self! end! end! ! class
Address! def display(template)! template.display_address(self)! self! end! end! ! class Template! def display_address(address)! # data processing…! ! ! STDOUT.puts […].compact.join(“\n”)! ! self! end! end -
EAST ORIENTED James Ladd The structuring of code to an
East orientation decreases coupling and the amount of code needed to be written, whilst increasing code clarity, cohesion and flexibility. -
EAST ORIENTED James Ladd The structuring of code to an
East orientation decreases coupling and the amount of code needed to be written, whilst increasing code clarity, cohesion and flexibility. -
TELL JAMES THANKS @jamesladd The East principle is not
like the “Tell, Don’t Ask” principle because there is no ambiguity, you simply cannot ask, you can only tell. -
TELL JAMES THANKS @jamesladd The East principle is not
like the “Tell, Don’t Ask” principle because there is no ambiguity, you simply cannot ask, you can only tell. -
class Person! ! ! attr_reader :friend! end! ! class Friend!
def make_me_a_sandwich! Table.place "a sandwich!"! end! end! -
class Person! ! ! attr_reader :friend! ! def make_me_a_sandwich! friend.make_me_a_sandwich!
end! end! ! class Friend! def make_me_a_sandwich! Table.place "a sandwich!"! end! end -
class Person! extend Forwardable! delegate :make_me_a_sandwich => :friend! attr_reader :friend!
end! ! class Friend! def make_me_a_sandwich! Table.place "a sandwich!"! end! end! -
describe Direction do! let(:friend){ Friend.new }! let(:person){ person = Person.new!
person.friend = friend! person! }! before do! Table.clear! end! it 'forwards a message to another object' do! assert_equal [], Table.contents! person.make_me_a_sandwich! assert_includes Table.contents, "a sandwich!"! end! end -
describe Direction do! let(:friend){ Friend.new }! let(:person){ person = Person.new!
person.friend = friend! person! }! before do! Table.clear! end! it 'forwards a message to another object' do! assert_equal [], Table.contents! person.friend.make_me_a_sandwich! assert_includes Table.contents, "a sandwich!"! end! ! ! ! -
class Person! extend Forwardable! delegate :make_me_a_sandwich => :friend! attr_reader :friend!
end! ! class Friend! def make_me_a_sandwich! Table.place "a sandwich!"! end! end! -
class Person! extend Forwardable! delegate :make_me_a_sandwich => :friend! ! private!
attr_reader :friend! end! ! class Friend! def make_me_a_sandwich! Table.place "a sandwich!"! end! end! -
class Person! extend Direction! command :make_me_a_sandwich => :friend! ! private!
attr_accessor :friend! end! ! class Friend! def make_me_a_sandwich! Table.place "a sandwich!"! end! end! -
describe Direction do! let(:friend){ Friend.new }! let(:person){ person = Person.new!
person.friend = friend! person! }! before do! Table.clear! end! it 'forwards a message to another object' do! assert_equal [], Table.contents! person.make_me_a_sandwich! assert_includes Table.contents, "a sandwich!"! end! ! it 'returns the original receiver' do! assert_equal person, person.make_me_a_sandwich! end! -
describe Direction do! ! it 'returns the original receiver' do!
assert_equal person, person.make_me_a_sandwich! end! end -
describe Direction do! ! it 'returns the original receiver' do!
assert_equal person, person.make_me_a_sandwich. ! ! get_me_a_drink! end! end -
describe Direction do ! it 'returns the original receiver' do!
assert_equal person, person.make_me_a_sandwich. ! ! get_me_a_drink. ! ! wash_the_car! end! end -
describe Direction do! ! it 'returns the original receiver' do!
assert_equal person, person.make_me_a_sandwich. ! ! get_me_a_drink. ! ! wash_the_car. ! ! jump! end! end -
describe Direction do! ! it 'returns the original receiver' do!
assert_equal person, person.make_me_a_sandwich. ! ! get_me_a_drink. ! ! wash_the_car. ! ! jump. ! ! gimme_five! end! end -
describe Direction do! ! it 'returns the original receiver' do!
assert_equal person, person.make_me_a_sandwich. ! ! get_me_a_drink. ! ! wash_the_car. ! ! jump. ! ! gimme_five. ! ! up_high! end! end -
describe Direction do! ! it 'returns the original receiver' do!
assert_equal person, person.make_me_a_sandwich. ! ! get_me_a_drink. ! ! wash_the_car. ! ! jump. ! ! gimme_five. ! ! up_high. ! ! down_low! end! end -
describe Direction do! ! it 'returns the original receiver' do!
assert_equal person, person.make_me_a_sandwich. ! ! get_me_a_drink. ! ! wash_the_car. ! ! jump. ! ! gimme_five. ! ! up_high. ! ! down_low. ! ! too_slow! end! end -
module Direction! def command(options)! method_defs = []! options.each_pair do |key,
value|! Array(key).map do |command_name|! method_defs.unshift %{! def #{command_name}(*args, &block)! #{value}.__send__(:#{command_name}, *args, &block)! self! end! }! end! end! self.class_eval method_defs.join(' ')! end! end -
module Direction! def command(options)! method_defs = []! options.each_pair do |key,
value|! Array(key).map do |command_name|! method_defs.unshift %{! def #{command_name}(*args, &block)! #{value}.__send__(:#{command_name}, *args, &block)! self! end! }! end! end! self.class_eval method_defs.join(' ')! end! end -
class Person! extend Direction! command [:make_me_a_sandwich, :other] => :friend! !
private! attr_accessor :friend! end! ! class Friend! def make_me_a_sandwich! Table.place "a sandwich!"! end! end!