fluent refactoring (cascadia ruby conf 2013)
TRANSCRIPT
Fluent RefactoringSam Livingston-Gray
THERE WILL BE CODE!
It may bethis small
puts (1..100).map { |i| s = '' fizz = (i % 3).zero? buzz = (i % 5).zero? s << 'Fizz' if fizz s << 'Buzz' if buzz s = i if s.empty? s}
1
Tuesday, October 22, 13
Math
2
\m/
Tuesday, October 22, 13
http://2012books.lardbucket.org/books/elementary-algebra/section_06/5d10b670d78abac93a4572dc0c2afb0f.jpg3
Tuesday, October 22, 13
http://www.wikihow.com/Image:Solve-for-X-Step-12.jpg4
Tuesday, October 22, 13
http://math.about.com/od/algebra/ss/birthday.htm5
Tuesday, October 22, 13
http://www.smosh.com/smosh-pit/photos/16-wonderfully-stupid-test-answers6
Tuesday, October 22, 13
Algebra
7
Tuesday, October 22, 13
Algebra Isn’t Math
8
Tuesday, October 22, 13
Algebra Isn’t all of Math
9
Tuesday, October 22, 13
Algebra ⊂ Math
Math
Algebra
10
Tuesday, October 22, 13
http://upload.wikimedia.org/wikipedia/commons/thumb/0/08/NautilusCutawayLogarithmicSpiral.jpg/793px-NautilusCutawayLogarithmicSpiral.jpg11
Tuesday, October 22, 13
http://upload.wikimedia.org/wikipedia/commons/a/a4/Mandelbrot_sequence_new.gif12
Tuesday, October 22, 13
http://mathequalslove.blogspot.com/2012/12/hexaflexagon-love.html13
Tuesday, October 22, 13
http://think-like-a-git.net/sections/graph-theory/seven-bridges-of-konigsberg.html14
Tuesday, October 22, 13
Math is a Language
15
Tuesday, October 22, 13
Math is a LanguageAlgebra is[one of]
its Grammar[s]
15
Tuesday, October 22, 13
Fluent Refactoring
16
Tuesday, October 22, 13
http://www.kickasslabs.com/2012/04/28/rails-conf-2012-images/100_0304/17
Tuesday, October 22, 13
http://www.kickasslabs.com/2012/04/28/rails-conf-2012-images/100_0304/
Can I get a definition?
17
Tuesday, October 22, 13
Re·fac·tor·ing (noun)
18
Tuesday, October 22, 13
Re·fac·tor·ing (noun)"...a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior."
-refactoring.com
18
Tuesday, October 22, 13
TL;DR
19
Tuesday, October 22, 13
TL;DR"...a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior."
19
Tuesday, October 22, 13
Re·fac·tor·ing (noun)
A techniquefor restructuring code
without changing behavior
20
Tuesday, October 22, 13
Tell a clearer storywith fewer details
21
Tuesday, October 22, 13
http://www.tagxedo.com/app.html
Jargon
22
Tuesday, October 22, 13
http://www.tagxedo.com/app.html
Jargon
22
Tuesday, October 22, 13
Re·fac·tor·ing (noun)
23
Tuesday, October 22, 13
Re·fac·tor·ing (noun)
A language thatdescribes ways tomake your code
suck less.
23
Tuesday, October 22, 13
Flu·en·cy (noun)
24
Tuesday, October 22, 13
Flu·en·cy (noun)What you can say when you’renot thinking about how to say it
24
Tuesday, October 22, 13
What you can say when you’rewoken up in the middle of the night
with a flashlight in your face
Flu·en·cy (noun)
25
Tuesday, October 22, 13
http://dailyawesimity.files.wordpress.com/2013/01/cat-stress-relief-4.jpg
Stress
26
Tuesday, October 22, 13
Language Hunters
27
Tuesday, October 22, 13
http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html
Level 1
Level 2
Level 3
Level 4
Levels of Proficiency
28
Tuesday, October 22, 13
http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html
Level 1 Tarzan ata party
“Beer!”“Good party.”
Level 2
Level 3
Level 4
Levels of Proficiency
29
Tuesday, October 22, 13
http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html
Level 1 Tarzan ata party
“Beer!”“Good party.”
Level 2 Going tothe party
"Where is the party?""How do I get to the party?"
Level 3
Level 4
Levels of Proficiency
30
Tuesday, October 22, 13
http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html
Level 1 Tarzan ata party
“Beer!”“Good party.”
Level 2 Going tothe party
"Where is the party?""How do I get to the party?"
Level 3 Discussingthe party
"What happened at the party last night?"
Level 4
Levels of Proficiency
31
Tuesday, October 22, 13
http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html
Level 1 Tarzan ata party
“Beer!”“Good party.”
Level 2 Going tothe party
"Where is the party?""How do I get to the party?"
Level 3 Discussingthe party
"What happened at the party last night?"
Level 4 Charlie Rose "Should parties be illegal?"
Levels of Proficiency
32
Tuesday, October 22, 13
http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html
Level 1 Tarzan ata party
“Beer!”“Good party.”
Level 2 Going tothe party
"Where is the party?""How do I get to the party?"
Level 3 Discussingthe party
"What happened at the party last night?"
Level 4 Charlie Rose "Should parties be illegal?"
Levels of Proficiency
33
Tuesday, October 22, 13
http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html
Level 1 Tarzan ata party
“Beer!”“Good party.”
Level 2 Going tothe party
"Where is the party?""How do I get to the party?"
Levels of Proficiency
34
Tuesday, October 22, 13
Story Time
35
Tuesday, October 22, 13
Production Rails Code
36
Tuesday, October 22, 13
Used with:
• Permission
Production Rails Code
36
Tuesday, October 22, 13
Used with:
• Permission
• Obfuscation
Production Rails Code
36
Tuesday, October 22, 13
Used with:
• Permission
• Obfuscation
• Respect
Production Rails Code
36
Tuesday, October 22, 13
Respect
37
Tuesday, October 22, 13
class InstallationsController < ActionController::Base # lots more stuff...
def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end
# lots more stuff...end
38
Tuesday, October 22, 13
class InstallationsController < ActionController::Base # lots more stuff...
def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end
# lots more stuff...end
Observations
39
Tuesday, October 22, 13
class InstallationsController < ActionController::Base # lots more stuff...
def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end
# lots more stuff...end
Observations
~800 lines in file
39
Tuesday, October 22, 13
class InstallationsController < ActionController::Base # lots more stuff...
def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end
# lots more stuff...end
Observations
~800 lines in file
~50 lines in method
39
Tuesday, October 22, 13
class InstallationsController < ActionController::Base # lots more stuff...
def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end
# lots more stuff...end
Observations
~800 lines in file
~50 lines in method
Longest line: 177 chars
39
Tuesday, October 22, 13
class InstallationsController < ActionController::Base # lots more stuff...
def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end
# lots more stuff...end
Observations
~800 lines in file
~50 lines in method
Longest line: 177 chars
Indentation: 4-16 spaces
39
Tuesday, October 22, 13
class InstallationsController < ActionController::Base # lots more stuff...
def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end
# lots more stuff...end
Observations
~800 lines in file
~50 lines in method
Longest line: 177 chars
Indentation: 4-16 spaces
Nested control structures:
39
Tuesday, October 22, 13
class InstallationsController < ActionController::Base # lots more stuff...
def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end
# lots more stuff...end
Observations
~800 lines in file
~50 lines in method
Longest line: 177 chars
Indentation: 4-16 spaces
Nested control structures:
audit_trail_for
39
Tuesday, October 22, 13
class InstallationsController < ActionController::Base # lots more stuff...
def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end
# lots more stuff...end
Observations
~800 lines in file
~50 lines in method
Longest line: 177 chars
Indentation: 4-16 spaces
Nested control structures:
audit_trail_for
begin/rescue/end
39
Tuesday, October 22, 13
class InstallationsController < ActionController::Base # lots more stuff...
def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end
# lots more stuff...end
Observations
~800 lines in file
~50 lines in method
Longest line: 177 chars
Indentation: 4-16 spaces
Nested control structures:
audit_trail_for
begin/rescue/end
if/else/end
39
Tuesday, October 22, 13
http://scientopia.org/blogs/whitecoatunderground/2009/06/10/my-head-just-asploded-twice/
Complexity
40
Tuesday, October 22, 13
http://shipitsquirrel.github.io/
Ship it!
41
Tuesday, October 22, 13
~800 lines
42
Tuesday, October 22, 13
http://hyperboleandahalf.blogspot.com/2010/06/this-is-why-ill-never-be-adult.html
~800 lines
42
Tuesday, October 22, 13
http://hyperboleandahalf.blogspot.com/2010/06/this-is-why-ill-never-be-adult.html
~800 lines
42
Tuesday, October 22, 13
http://hyperboleandahalf.blogspot.com/2010/06/this-is-why-ill-never-be-adult.html
~800 lines
43
Tuesday, October 22, 13
Make the Job Smaller
44
Tuesday, October 22, 13
Replace Method with Method Object
45
See also:
Katrina Owen,“Therapeutic Refactoring”
Tuesday, October 22, 13
class InstallationsController < ActionController::Base def schedule # LOTS OF CODE endend
46
Tuesday, October 22, 13
class InstallationsController < ActionController::Base def schedule
endend
class ScheduleInstallation def call
endend
# LOTS OF CODE
47
Tuesday, October 22, 13
class InstallationsController < ActionController::Base def schedule
endend
class ScheduleInstallation def call
endend
# LOTS OF CODE
47
Tuesday, October 22, 13
class InstallationsController < ActionController::Base def schedule
endend
class ScheduleInstallation def call
endend
ScheduleInstallation.new.call
# LOTS OF CODE
47
Tuesday, October 22, 13
48
NoMethodErrorLOL WUT?
Tuesday, October 22, 13
class ScheduleInstallation def call # LOTS OF CODE # ... params ... # ... render ... # ... redirect_to ... endend
49
Tuesday, October 22, 13
class ScheduleInstallation def initialize(controller) @controller = controller end
def call # LOTS OF CODE # ... params ... # ... render ... # ... redirect_to ... endend
50
Tuesday, October 22, 13
class ScheduleInstallation def initialize(controller) @controller = controller end
def call # LOTS OF CODE # ... @controller.params ... # ... @controller.render ... # ... @controller.redirect_to ... endend
51
Tuesday, October 22, 13
class ScheduleInstallation def initialize(controller) @controller = controller end
extend Forwardable def_delegators :@controller, :params, :render, :redirect_to
def call # LOTS OF CODE # ... params ... # ... render ... # ... redirect_to ... endend
52
Tuesday, October 22, 13
class ScheduleInstallation def initialize(controller) @controller = controller end
def call # LOTS OF CODE end
def method_missing(m, *a, &b) @controller.send(m, *a, &b) endend
53
Tuesday, October 22, 13
http://anthro.ucsc.edu/undergraduate/sub-fields/anthro-archeaology.html
Code Archaeology
54
Tuesday, October 22, 13
if request.xhr? # ...20 lines...else # ...22 lines...end
55
Tuesday, October 22, 13
if request.xml_http_request? # ...20 lines...else # ...22 lines...end
56
Tuesday, October 22, 13
if request.xml_http_request? begin #... endelse # ...22 lines...end
57
Tuesday, October 22, 13
if request.xml_http_request? begin if @installation.pending_credit_check? render :json => #... return end #... endelse # ...22 lines...end
58
Tuesday, October 22, 13
if request.xml_http_request? begin if @installation.pending_credit_check? render :json => #... return end #... endelse # ...22 lines...end
58
Tuesday, October 22, 13
if request.xml_http_request? begin if @installation.pending_credit_check? render :json => #... return end #... endelse # ...22 lines...end
58
Guard Clause-Smalltalk Best Practice Patterns
by Kent Beck
Tuesday, October 22, 13
if request.xhr? begin if @installation.pending_credit_check? render :json => #... return end #... endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin #... endend 59
Tuesday, October 22, 13
if request.xhr? begin if @installation.pending_credit_check? render :json => #... return end #... endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin #... endend 59
Tuesday, October 22, 13
if request.xhr? begin if @installation.pending_credit_check? render :json => #... return end #... endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path(:city_id => return end begin #... end 60
Tuesday, October 22, 13
if request.xhr? begin if @installation.pending_credit_check? render :json => #... return end #... endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path(:city_id => return end begin #... end
if request.xhr? if @installation.pending_credit_check? render :json => #... return end begin #... endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path( return end begin #... end60
Tuesday, October 22, 13
if request.xhr? if @installation.pending_credit_check? render :json => #... return end begin #... endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path(:city_id => return end begin #... end 61
Tuesday, October 22, 13
if request.xhr? if @installation.pending_credit_check? render :json => #... return end begin #... endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path(:city_id => return end begin #... end
if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend
if request.xhr? begin #... end61
Tuesday, October 22, 13
if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend
62
Tuesday, October 22, 13
emph·AS·is
63
Tuesday, October 22, 13
if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend
64
Tuesday, October 22, 13
if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend
64
Tuesday, October 22, 13
if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend
64
Tuesday, October 22, 13
Flatten Nested Conditionals
source:Michael Feathers
in Dr. Dobbs
65
Tuesday, October 22, 13
if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend
66
Tuesday, October 22, 13
if ajax if nope render :json => #... return endelse if nope flash[:error] = #... redirect_to #... return endend
67
Tuesday, October 22, 13
if ajax if nope render :json => #... return endelse if nope flash[:error] = #... redirect_to #... return endend
67
ajax nope
TRUE TRUE
ajax nope
FALSE TRUE
Tuesday, October 22, 13
if ajax if nope render :json => #... return endelse if nope flash[:error] = #... redirect_to #... return endend
68
Tuesday, October 22, 13
if ajax if nope render :json => #... return endelse if nope flash[:error] = #... redirect_to #... return endend
if ajax if nope render :json => #... return endendif not ajax if nope flash[:error] = #... redirect_to #... return endend
68
Tuesday, October 22, 13
if ajax if nope render :json => #... return endendif not ajax if nope flash[:error] = #... redirect_to #... return endend
69
Tuesday, October 22, 13
if ajax if nope render :json => #... return endendif not ajax if nope flash[:error] = #... redirect_to #... return endend
if ajax && nope render :json => #... returnendif (not ajax) && nope flash[:error] = #... redirect_to #... returnend
69
Tuesday, October 22, 13
if ajax && nope render :json => #... returnendif (not ajax) && nope flash[:error] = #... redirect_to #... returnend
70
Tuesday, October 22, 13
if ajax && nope render :json => #... returnendif (not ajax) && nope flash[:error] = #... redirect_to #... returnend
70
Tuesday, October 22, 13
if ajax && nope render :json => #... returnendif (not ajax) && nope flash[:error] = #... redirect_to #... returnend
if nope if ajax render :json => #... return end if not ajax flash[:error] = #... redirect_to #... return endend
70
Tuesday, October 22, 13
if nope if ajax render :json => #... return end if not ajax flash[:error] = #... redirect_to #... return endend
71
Tuesday, October 22, 13
if nope if ajax render :json => #... return end if not ajax flash[:error] = #... redirect_to #... return endend
if nope if ajax render :json => #... return else flash[:error] = #... redirect_to #... return endend
71
Tuesday, October 22, 13
if nope if ajax render :json => #... return else flash[:error] = #... redirect_to #... return endend
72
Tuesday, October 22, 13
if nope if ajax render :json => #... return else flash[:error] = #... redirect_to #... return endend
if nope if ajax render :json => #... else flash[:error] = #... redirect_to #... end returnend
72
Tuesday, October 22, 13
if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend
73
Tuesday, October 22, 13
if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend
if @installation.pending_credit_check? if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end returnend
73
Tuesday, October 22, 13
if @installation.pending_credit_check? if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end returnend
74
Tuesday, October 22, 13
if @installation.pending_credit_check? if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end returnend
if @installation.pending_credit_check? cant_schedule_while_credit_check_pending returnend
74
Tuesday, October 22, 13
if @installation.pending_credit_check? cant_schedule_while_credit_check_pending returnend
if request.xhr? begin #... endelse begin #... endend
75
Tuesday, October 22, 13
http://spectrumculture.com/2012/09/re-makere-model-the-karate-kid-1984-vs-the-karate-kid-2010.html/
“Hard Work” Montage
76
Tuesday, October 22, 13
class InstallationsController < ActionController::Base def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end endend
77
Tuesday, October 22, 13
class InstallationsController < ActionController::Base def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end endend
class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
audit_trail_for(current_user) if schedule! if @installation.scheduled_date scheduling_succeeded end do_post_success_cleanup else scheduling_failed end end rescue => e handle_exception e endend
77
Tuesday, October 22, 13
class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
audit_trail_for(current_user) do if schedule! if @installation.scheduled_date scheduling_succeeded end do_post_success_cleanup else scheduling_failed end end rescue => e handle_exception e endend
78
Tuesday, October 22, 13
class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
audit_trail_for(current_user) do if schedule! if @installation.scheduled_date scheduling_succeeded end do_post_success_cleanup else scheduling_failed end end rescue => e handle_exception e endend
request.xhr?
79
Tuesday, October 22, 13
class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
audit_trail_for(current_user) do if schedule! if @installation.scheduled_date scheduling_succeeded end do_post_success_cleanup else scheduling_failed end end rescue => e handle_exception e endend
request.xhr?
79
Tuesday, October 22, 13
Under The Rug
80
Tuesday, October 22, 13
def cannot_schedule_while_#... if request.xhr? # ...1 line... else # ...2 lines... endend
def handle_exception(e) if request.xhr? # ...7 lines... else # ...2 lines... endend
def scheduling_succeeded if request.xhr? # ...2 lines... else # ...5 lines... endend
def scheduling_failed if request.xhr? # ...1 line... else # ...2 lines... endend
def do_post_success_cleanup if request.xhr? # DO NOTHING else # ...1 line... endend
81
Tuesday, October 22, 13
def cannot_schedule_while_#... if request.xhr? # ...1 line... else # ...2 lines... endend
def handle_exception(e) if request.xhr? # ...7 lines... else # ...2 lines... endend
def scheduling_succeeded if request.xhr? # ...2 lines... else # ...5 lines... endend
def scheduling_failed if request.xhr? # ...1 line... else # ...2 lines... endend
def do_post_success_cleanup if request.xhr? # DO NOTHING else # ...1 line... endend
81
Tuesday, October 22, 13
class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end endend
Tuesday, October 22, 13
class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end endend
Tuesday, October 22, 13
class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end endend
Tuesday, October 22, 13
class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end endend
Tuesday, October 22, 13
class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end endend
Tuesday, October 22, 13
class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end endend
Tuesday, October 22, 13
Single Responsibility Principle
83
(SRP for short)
Tuesday, October 22, 13
ScheduleInstallation
84
Tuesday, October 22, 13
ScheduleInstallationScheduleInstallationAnd
DoOneThingForAJAXRequestsAndDoSomethingElseForHTMLRequests
84
Tuesday, October 22, 13
ScheduleInstallationScheduleInstallation And
DoOneThingForAJAXRequests And DoSomethingElseForHTMLRequests
85
Tuesday, October 22, 13
ScheduleInstallationScheduleInstallation And
DoOneThingForAJAXRequests And DoSomethingElseForHTMLRequests
86
Tuesday, October 22, 13
Recap
87
Tuesday, October 22, 13
88
InstallationsController
Tuesday, October 22, 13
88
InstallationsController
ScheduleInstallation
Tuesday, October 22, 13
88
InstallationsController
ScheduleInstallation
???
Tuesday, October 22, 13
89
InstallationsController
Responder
ScheduleInstallation
???
Tuesday, October 22, 13
89
InstallationsController
Responder
???
ScheduleInstallation
???
Tuesday, October 22, 13
class ScheduleInstallation def call
private
def cannot_schedule_while_credit_check_pendin def handle_exception(e) def scheduling_failed def scheduling_succeeded def do_post_success_cleanupend
class Responderend
90
Tuesday, October 22, 13
class ScheduleInstallation def call
private
def cannot_schedule_while_credit_check_pendin def handle_exception(e) def scheduling_failed def scheduling_succeeded def do_post_success_cleanupend
class Responderend
90
class ScheduleInstallation def callend
class Responder def cannot_schedule_while_credit_check_pe def handle_exception(e) def scheduling_failed def scheduling_succeeded def do_post_success_cleanupend
Tuesday, October 22, 13
91
Responder
Tuesday, October 22, 13
if request.xhr? # do thiselse # do thatend
Tuesday, October 22, 13
Replace ConditionalWith Polymorphism
93
Tuesday, October 22, 13
class Responder def cannot_schedule_while_credit_check_pending def handle_exception(e) def scheduling_failed def scheduling_succeeded def do_post_success_cleanupend
Tuesday, October 22, 13
class Responder def cannot_schedule_while_credit_check_pending def handle_exception(e) def scheduling_failed def scheduling_succeeded def do_post_success_cleanupend
class AJAXResponder def cannot_schedule_while_credit_check_pending def handle_exception(e) def scheduling_failed def scheduling_succeeded def do_post_success_cleanupend
class HTMLResponder def cannot_schedule_while_credit_check_pending def handle_exception(e) def scheduling_failed def scheduling_succeeded def do_post_success_cleanupend
Tuesday, October 22, 13
class InstallationsController < ActionController::Base
def schedule responder = request.xhr? ? AJAXResponder.new(self) : HTMLResponder.new(self) ScheduleInstallation.new(responder).call endend
Tuesday, October 22, 13
class InstallationsController < ActionController::Base
def schedule responder = request.xhr? ? AJAXResponder.new(self) : HTMLResponder.new(self) ScheduleInstallation.new(responder).call endend
Tuesday, October 22, 13
class InstallationsController < ActionController::Base
def schedule responder = request.xhr? ? AJAXResponder.new(self) : HTMLResponder.new(self) ScheduleInstallation.new(responder).call endend
Tuesday, October 22, 13
class AJAXResponder def scheduling_failed if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end endend
class HTMLResponder def scheduling_failed if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end endend
Tuesday, October 22, 13
class AJAXResponder def scheduling_failed if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end endend
class HTMLResponder def scheduling_failed if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end endend
class AJAXResponder def scheduling_failed render :json => #... endend
class HTMLResponder def scheduling_failed flash[:error] = #... redirect_to #... endend
Tuesday, October 22, 13
class InstallationsController < ActionController::Base
def schedule responder = request.xhr? ? AJAXResponder.new(self) : HTMLResponder.new(self) ScheduleInstallation.new(responder).call endend
Tuesday, October 22, 13
http://gomakemeasandwich.wordpress.com/2011/10/26/a-yeaf-of-gmmas-where-do-we-go-from-here/
Where Do We Go From Here?
98
Tuesday, October 22, 13
100
Tuesday, October 22, 13
101
Tuesday, October 22, 13
102
Tuesday, October 22, 13
103
Tuesday, October 22, 13
Commit Early,Commit Often
104
Tuesday, October 22, 13
Throw Your Work Away
105
Tuesday, October 22, 13
Speed Up Your Tests!
106
Tuesday, October 22, 13
Speed Up Your Tests!See also:
Katrina Owen,“Therapeutic Refactoring”
(srsly)
106
Tuesday, October 22, 13
107
I work at LivingSocial.We’re hiring.
Tuesday, October 22, 13
107
I work at LivingSocial.We’re hiring.
(Who isn’t?)
Tuesday, October 22, 13
Jim Shore and Diana Larsenfor “Agile Fluency”
Kirsten Comandich
Sandi Metz, Katrina Owen,Sonia Connolly
PDX.rb
108
Thanks to:
Tuesday, October 22, 13
github.com/geeksam/fluent-refactoring
109
Tuesday, October 22, 13
github.com/geeksam/fluent-refactoring
Twitter, Github: @geeksam
110
Tuesday, October 22, 13