Refactoring Ruby Code
-
Upload
caike-souza -
Category
Technology
-
view
2.021 -
download
1
description
Transcript of Refactoring Ruby Code
@caikehttp://caikesouza.com
Refatorando CódigoRuby
Métodos Ágeis
Testes
(Anti-)Patterns
Software Craftsmanship
"Any fool can write code that a computer can understand.
Good programmers write code that humans can understand"
(Martin Fowler)
Refatorar é ...
Limpar a casa sem mudar a fachada
Algumas razões
Design
Responder a mudanças
EntregasConstantes
Jan Feb Mar Apr May Jun Jul
Cost of Maintenance
Waterfall
Extreme Programming Explained: Embrace ChangeAddison Wesley, 2000
Jan Feb Mar Apr May Jun Jul
Cost of Maintenance Extreme Programming Explained: Embrace ChangeAddison Wesley, 2000
XP
Quando ?
novas features
bugs
Débito Técnico
Code Reviews
“The great thing about programming is pretty much everyone's code is shit.
Writing software is hard, so it's no problem finding dogs in someone's stuff”
(Zed Shaw)
exemplos.rb
managers = []
employees.each do |e| managers << e if e.is_manager?end
managers = []
employees.each do |e| managers << e if e.is_manager?end
Replace Loop withClosure Method
managers = []
employees.each do |e| managers << e if e.is_manager?end
managers = employees. select { |e| e.is_manager? }
class Movie def initialize(stars) @stars = stars end def recommended? ((@stars > 5) ? 8 : 1) >= 8 endend
class Movie def initialize(stars) @stars = stars end def recommended? ((@stars > 5) ? 8 : 1) >= 8 endend
Introduce ExplainingVariable
class Movie def initialize(stars) @stars = stars end def recommended? ((@stars > 5) ? 8 : 1) >= 8 endend
class Movie def initialize(stars) @stars = stars end def recommended? rating = (@stars > 5) ? 8 : 1 rating >= 8 endend
class Movie def initialize(stars) @stars = stars end def recommended? rating = (@stars > 5) ? 8 : 1 rating >= 8 endend
Replace TempWith Query
class Movie def initialize(stars) @stars = stars end def recommended? rating = (@stars > 5) ? 8 : 1 rating >= 8 endend
class Movie def initialize(stars) @stars = stars end def recommended? rating >= 8 end
def rating (@stars > 5) ? 8 : 1 end end
OMG OMG OMG OMG OMG
class Movie
def recommended? rating >= 8 end
def rating (@stars > 5) ? 8 : 1 end end
class Movie
def recommended? rating >= 8 end
def rating more_than_five_stars? ? 8 : 1 end
def more_than_five_stars? @stars > 5 end end
Inline Method
class Movie def initialize...end def recommended? rating >= 8 end
def rating more_than_five_stars? ? 8 : 1 end
def more_than_five_stars? @stars > 5 end end
class Movie def initialize...end def recommended? rating >= 8 end
def rating @stars > 5 ? 8 : 1 end
end
mock = mock('user')expectation = mock.expects(:find)expectation.with("1")expectation.returns([])
mock = mock('user')expectation = mock.expects(:find)expectation.with("1")expectation.returns([])
Replace TempWith Chain
mock = mock('user')expectation = mock.expects(:find)expectation.with("1")expectation.returns([])
mock = mock('user')mock.expects(:find).with("1"). returns([])
Commandvs.
Query
def expects ... selfend
def with ... selfend
def returns ... selfend
def charge(amount, card_number) begin conn = CC_Charger_Server.connect(...) conn.send(amount, card_number) rescue IOError => e Logger.log "Error: #{e}" return nil ensure conn.close endend
def charge(amount, card_number) begin conn = CC_Charger_Server.connect(...) conn.send(amount, card_number) rescue IOError => e Logger.log "Error: #{e}" return nil ensure conn.close endend
Extract SurroundingMethod
def charge(amount, ccnumber) begin conn = CC_Charger_Server.connect(...) conn.send(amount, card_number) rescue IOError => e Logger.log "Error: #{e}" return nil ensure conn.close endend
def charge(amount, card_number) connect do |conn| conn.send(amount, card_number) endend
def connect begin conn = CC_Charger_Server.connect(...) yield conn rescue IOError => e Logger.log "Error: #{e}" return nil ensure conn.close endend
def body_fat_percentage(name, age, height, weight, metric_system) ...end
body_fat_percentage("fred", 30, 1.82, 90, 1)body_fat_percentage("joe", 32, 6, 220, 2)
body_fat_percentage("fred", 30, 1.82, 90, 1)body_fat_percentage("joe", 32, 6, 220, 2)
Introduce Named Parameter
body_fat_percentage("fred", 30, 1.82, 90, 1)body_fat_percentage("joe", 32, 6, 220, 2)
body_fat_percentage("fred", :age => 30, :height => 1.82, :weight => 90, MetricSystem::METERS_KG)
body_fat_percentage("joe", :age => 32, :height => 6, :weight => 220, MetricSystem::FEET_LB)
def body_fat_percentage(name, age, height, weight, metric_system) ...end
def body_fat_percentage(name, params={}) # params[:age] # params[:height] # params[:weight] # params[:metric_system]end
user.posts.paginate(:page => params[:page], :per_page => params[:per_page] || 15)
user.posts.paginate(:page => params[:page], :per_page => params[:per_page] || 15)
Replace Magic Number with Symbolic Constant
user.posts.paginate(:page => params[:page], :per_page => params[:per_page] || 15)
CONTACTS_PER_PAGE = 15
user.posts.paginate(:page => params[:page], :per_page => params[:per_page] || CONTACTS_PER_PAGE)
class MountainBike def price ... endend
MountainBike.new(:type => :rigid, ...)MountainBike.new(:type => :front_suspension, ...)MountainBike.new(:type => :full_suspension, ...)
def price if @type_code == :rigid (1 + @comission) * @base_price end if @type_code == :font_suspension (1 + @comission) * @base_price + @front_suspension_price end if @type_code == :full_suspension (1 + @comission) * @base_price+ @front_suspension_price + @rear_suspension_price
end
end
def price if @type_code == :rigid (1 + @comission) * @base_price end
if @type_code == :font_suspension (1 + @comission) * @base_price + @front_suspension_priceend if @type_code == :full_suspension (1 + @comission) * @base_price+
@front_suspension_price + @rear_suspension_price
end if @type_code == :ultra_suspension ... end end
CLOSED for modificationOPEN for extension
Replace ConditionalWith Polymorphism
class MountainBike def price ... endend
module MountainBike def price ... endend
class RigidMountainBike include MountainBikeend
class FrontSuspensionMountainBike include MountainBikeend
class FullSuspensionMountainBike include MountainBikeend
RigidMountainBike.new(:type => :rigid, ...)
FrontSuspensionMountainBike.new(:type => :front_suspension, ...)
FullSuspensionMountainBike.new(:type => :full_suspension, ...)
class RigidMountainBike include MountainBike
def price (1 + @comission) * @base_price endend
class FrontSuspensionMountainBike include MountainBike def price (1 + @comission) * @base_price + @front_suspension_price end end
class FullSuspensionMountainBike include MountainBike def price (1 + @comission) * @base_price + @front_suspension_price + @rear_suspension_price endend
def price if @type_code == :rigid raise "should not be called" end if @type_code == :font_suspension (1 + @comission) * @base_price + @front_suspension_price end if @type_code == :full_suspension (1 + @comission) * @base_price+ @front_suspension_price + @rear_suspension_price
end end
def price if @type_code == :rigid raise "should not be called" end if @type_code == :font_suspension raise "should not be called" end if @type_code == :full_suspension raise "should not be called" end end
def price if @type_code == :rigid raise "should not be called" end if @type_code == :font_suspension raise "should not be called" end if @type_code == :full_suspension raise "should not be called" end end
class RigidMountainBike include MountainBikeend
class FrontSuspensionMountainBike include MountainBikeend
class FullSuspensionMountainBike include MountainBikeend
Coding Dojo
http://orlandodojo.org/http://dojorio.org/
Obrigado!http://www.flickr.com/photos/eurleif/255241547/http://www.flickr.com/photos/dhammza/91435718/http://www.flickr.com/photos/krash0387http://www.flickr.com/photos/benfrantzdale/208672143/http://www.flickr.com/photos/improveit/1574023621/http://www.flickr.com/photos/aaroncoyle/972403508http://www.flickr.com/photos/talios/3726484920http://www.flickr.com/photos/moow/3412079622http://www.flickr.com/photos/highwayoflife/2699887178/
@caikehttp://caikesouza.comhttp://smallactsmanifesto.org