Date post: | 11-May-2015 |
Category: |
Technology |
Upload: | sam-livingston-gray |
View: | 1,175 times |
Download: | 3 times |
Fluent RefactoringSam Livingston-Gray
THERE WILL BE CODE!
It may bethis small
(1..100).each do |i| s = '' fizz = (i % 3).zero? buzz = (i % 5).zero? s << 'Fizz' if fizz s << 'Buzz' if buzz s << '!' if fizz || buzz s = i if s =~ /^$/ puts send
1
Let’s Talk About Math!
2
http://2012books.lardbucket.org/books/elementary-algebra/section_06/5d10b670d78abac93a4572dc0c2afb0f.jpg3
http://www.wikihow.com/Image:Solve-for-X-Step-12.jpg4
http://math.about.com/od/algebra/ss/birthday.htm5
http://www.smosh.com/smosh-pit/photos/16-wonderfully-stupid-test-answers6
Algebra
7
Algebra Isn’t Math
8
Algebra Isn’t all of Math
9
Algebra ⊂ Math
Math
Algebra
10
http://upload.wikimedia.org/wikipedia/commons/thumb/0/08/NautilusCutawayLogarithmicSpiral.jpg/793px-NautilusCutawayLogarithmicSpiral.jpg11
http://upload.wikimedia.org/wikipedia/commons/a/a4/Mandelbrot_sequence_new.gif12
http://mathequalslove.blogspot.com/2012/12/hexaflexagon-love.html13
http://think-like-a-git.net/sections/graph-theory/seven-bridges-of-konigsberg.html14
Math is a LanguageAlgebra is its Grammar
15
Dick and Jane
16
Fluent Refactoring
17
http://www.kickasslabs.com/2012/04/28/rails-conf-2012-images/100_0304/
Can I get a definition?
18
Flu·en·cy (noun)What you can say when you’renot thinking about how to say it
19
What you can say when you’rewoken up in the middle of the night
with a flashlight in your face
Flu·en·cy (noun)
20
http://dailyawesimity.files.wordpress.com/2013/01/cat-stress-relief-4.jpg
Stress
21
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
22
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
23
http://refactoring.com/
"...a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior."
24
"Yeah, we're going to have to takea couple of weeks out of the schedule for refactoring, and that's probably going
to break some stuff."
Doin It Rong
25
"Yeah, we're going to have to takea couple of weeks out of the schedule for refactoring, and that's probably going
to break some stuff."
Doin It Rong
26
"Yeah, we're going to have to takea couple of weeks out of the schedule for refactoring, and that's probably going
to break some stuff."
Doin It Rong
27
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
28
http://refactoring.com/
"...a disciplined technique for restructuring an existing body of code, altering its internal structure
without changing its external behavior."
29
Tests are implied.-Katrina Owen,
“Therapeutic Refactoring”
30
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
31
Re·fac·tor·ing (noun)"...a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior."
32
Re·fac·tor·ing (noun)
A technique forrestructuring code
without changing behavior
33
Re·fac·tor (verb)
To restructure codewithout changing behavior
34
Tell a clearer storywith fewer details
35
Re·fac·tor·ing (noun)
A language that describes ways to make your code
suck less.
36
THESISES
37
THESISESTHESES
38
THESISESTHESESTHESII
39
THESISESTHESESTHESII
MY POINT(S)
40
You're probably already fluent in refactoring.
Level 1:Rename Variable; Rename Method.
41
You can become more fluent in refactoring.
It just takes practice.
42
Putting in the practice to become more fluent in refactoring is worth it.
Because you’ll be able to say more things when you’re under stress.
43
Refactoring Session
44
Used with:
• Permission
• Obfuscation
• Respect
Production Rails Code
45
Schedule Cable Installs
46
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
47
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
48
http://scientopia.org/blogs/whitecoatunderground/2009/06/10/my-head-just-asploded-twice/
Complexity
49
http://shipitsquirrel.github.io/
Ship it!
50
http://shipitsquirrel.github.io/
Ship Shit!
51
http://hyperboleandahalf.blogspot.com/2010/06/this-is-why-ill-never-be-adult.html
~800 lines
52
http://hyperboleandahalf.blogspot.com/2010/06/this-is-why-ill-never-be-adult.html
~800 lines
53
Make the Job Smaller
54
Replace Method with Method Object
55
class InstallationsController < ActionController::Base def schedule # LOTS OF CODE endend
56
class InstallationsController < ActionController::Base def schedule
endend
class ScheduleInstallation def call
endend
# LOTS OF CODE
57
class InstallationsController < ActionController::Base def schedule
endend
class ScheduleInstallation def call
endend
# LOTS OF CODE
58
class InstallationsController < ActionController::Base def schedule
endend
class ScheduleInstallation def call
endend
ScheduleInstallation.new.call
# LOTS OF CODE
59
class ScheduleInstallation def call # LOTS OF CODE endend
60
class ScheduleInstallation def initialize(controller) @controller = controller end
def call # LOTS OF CODE endend
61
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
62
Code Archaeology
63
if request.xhr? # ...20 lines...else # ...22 lines...end
64
if request.xml_http_request? # ...20 lines...else # ...22 lines...end
65
if request.xml_http_request? begin if @installation.pending_credit_check? render :json => #... return end #... endelse # ...22 lines...end
66
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 #...end
67
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 #...end
68
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 #...end
69
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 #...end
70
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 endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to(...) and return return endend
if request.xhr? #...else #...71
if request.xhr? #...else #...end
if request.xhr? #...else #...end
ZOMGduplication!!!1!!
72
if request.xhr? if @installation.pending_credit_check? #... endelse if @installation.pending_credit_check? #... endend
if request.xhr? #...else #...end
73
Emphasis
74
if request.xhr? if @installation.pending_credit_check? #... endelse if @installation.pending_credit_check? #... endend
75
Flatten Nested Conditionals
source: Michael Feathers,writing for Dr. Dobbs
76
if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend
77
if ajax if pending_credit_check render :json => #... return endelse if pending_credit_check flash[:error] = #... redirect_to #... return endend
78
if ajax if pending_credit_check render :json => #... return endelse if pending_credit_check flash[:error] = #... redirect_to #... return endend
if ajax if pending_credit_check render :json => #... return endendif not ajax if pending_credit_check flash[:error] = #... redirect_to #... return endend
79
if ajax if pending_credit_check render :json => #... return endendif not ajax if pending_credit_check flash[:error] = #... redirect_to #... return endend
if ajax && pending_credit_check render :json => #... returnendif (not ajax) && pending_credit_check flash[:error] = #... redirect_to #... returnend
80
if ajax && pending_credit_check render :json => #... returnendif (not ajax) && pending_credit_check flash[:error] = #... redirect_to #... returnend
if pending_credit_check if ajax render :json => #... return end if not ajax flash[:error] = #... redirect_to #... return endend
81
if pending_credit_check if ajax render :json => #... return end if not ajax flash[:error] = #... redirect_to #... return endend
if pending_credit_check if ajax render :json => #... return else flash[:error] = #... redirect_to #... return endend
82
if pending_credit_check if ajax render :json => #... return else flash[:error] = #... redirect_to #... return endend
if pending_credit_check if ajax render :json => #... else flash[:error] = #... redirect_to #... end returnend
83
if ajax if pending_credit_check render :json => #... return endelse if pending_credit_check flash[:error] = #... redirect_to #... return endend
if pending_credit_check if ajax render :json => #... else flash[:error] = #... redirect_to #... end returnend
84
if pending_credit_check if ajax render :json => #... else flash[:error] = #... redirect_to #... end returnend
if pending_credit_check cant_schedule_while_credit_check_pending returnend
85
Exception Handling
86
raise “wtf” if coin.toss.heads?begin raise “wtf” if coin.toss.heads?end
87
begin raise “wtf” if coin.toss.heads?end
begin raise “wtf” if coin.toss.heads?rescue => e raise eend
88
begin raise “wtf” if coin.toss.heads?rescue => e raise eend
89
begin begin raise “wtf” if coin.toss.heads? rescue #... endrescue => e raise eend
90
begin begin raise “wtf” if coin.toss.heads? rescue if request.xhr? raise “tfw” if tuesday? else raise “yak” if Moon.gibbous? end endrescue => e raise eend
begin begin raise “wtf” if coin.toss.heads? rescue if request.xhr? raise “tfw” if tuesday? else raise “yak” if Moon.gibbous? end endrescue => e if request.xhr? raise e else raise e endend91
begin begin raise “wtf” if coin.toss.heads? rescue if request.xhr? raise “tfw” if tuesday? else raise “yak” if Moon.gibbous? end endrescue => e if request.xhr? raise e else raise e endend
begin begin raise “wtf” if coin.toss.heads? rescue if request.xhr? # DO NOTHING else raise “yak” if Moon.gibbous? end endrescue => e if request.xhr? raise “tfw” if tuesday? else raise e endend92
begin begin raise “wtf” if coin.toss.heads? rescue if request.xhr? # DO NOTHING else raise “yak” if Moon.gibbous? end endrescue => e if request.xhr? raise “tfw” if tuesday? else raise e endend
begin begin raise “wtf” if coin.toss.heads? rescue if request.xhr? # DO NOTHING else # DO NOTHING end endrescue => e if request.xhr? raise “tfw” if tuesday? else raise “yak” if Moon.gibbous? endend93
begin begin raise “wtf” if coin.toss.heads? rescue if request.xhr? # DO NOTHING else # DO NOTHING end endrescue => e if request.xhr? raise “tfw” if tuesday? else raise “yak” if Moon.gibbous? endend
begin begin raise “wtf” if coin.toss.heads? rescue # DO NOTHING endrescue => e if request.xhr? raise “tfw” if tuesday? else raise “yak” if Moon.gibbous? endend
94
begin begin raise “wtf” if coin.toss.heads? rescue # DO NOTHING endrescue => e if request.xhr? raise “tfw” if tuesday? else raise “yak” if Moon.gibbous? endend
begin begin raise “wtf” if coin.toss.heads? endrescue => e if request.xhr? raise “tfw” if tuesday? else raise “yak” if Moon.gibbous? endend
95
begin begin raise “wtf” if coin.toss.heads? endrescue => e if request.xhr? raise “tfw” if tuesday? else raise “yak” if Moon.gibbous? endend
begin raise “wtf” if coin.toss.heads?rescue => e if request.xhr? raise “tfw” if tuesday? else raise “yak” if Moon.gibbous? endend
96
begin raise “wtf” if coin.toss.heads?rescue => e if request.xhr? raise “tfw” if tuesday? else raise “yak” if Moon.gibbous? endend
begin raise “wtf” if coin.toss.heads?rescue => e handle_exception(e)end
97
Training Montage
98
class ScheduleInstallation def call desired_date = params[:desired_date] if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
begin if request.xhr? 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 else 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 redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end rescue Exception => e handle_exception e end endend
99
class ScheduleInstallation def call desired_date = params[:desired_date] if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
begin audit_trail_for(current_user) do if request.xhr? 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 else 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 redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end rescue Exception => e handle_exception e end endend
100
class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
begin audit_trail_for(current_user) do if request.xhr? if @installation.schedule!(params[: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 else if @installation.schedule!(params[: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 redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end rescue Exception => e handle_exception e end endend
101
class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
begin audit_trail_for(current_user) do success = schedule! if request.xhr? if success 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 else if success 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 redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end rescue Exception => e handle_exception e end endend
102
class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
begin audit_trail_for(current_user) do success = schedule! if success if request.xhr? 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 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 redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end else if request.xhr? render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end end rescue Exception => e handle_exception e end endend
103
class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
begin audit_trail_for(current_user) do success = schedule! if success if request.xhr? 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 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 redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end else scheduling_failed end end rescue Exception => e handle_exception e end endend
104
class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
begin audit_trail_for(current_user) do success = schedule! if success if @installation.scheduled_date if request.xhr? date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} else 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 end if request.xhr? # do nothing else redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end else scheduling_failed end end rescue Exception => e handle_exception e end endend
105
class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
begin audit_trail_for(current_user) do success = schedule! if success if @installation.scheduled_date scheduling_succeeded end if request.xhr? # do nothing else redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end else scheduling_failed end end rescue Exception => e handle_exception e end endend
106
class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
begin audit_trail_for(current_user) do success = schedule! if success if @installation.scheduled_date scheduling_succeeded end do_post_success_cleanup else scheduling_failed end end rescue Exception => e handle_exception e end endend
107
class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
begin 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 Exception => e handle_exception e end endend
108
class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end
begin 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 Exception => e handle_exception e end endend
request.xhr?
109
Under The Rug
110
class ScheduleInstallation def cannot_schedule_while_#... if request.xhr? # ...1 line... else # ...2 lines... end end
def handle_exception(e) if request.xhr? # ...7 lines... else # ...2 lines... end end
def scheduling_failed if request.xhr? # ...1 line... else # ...2 lines... end end
def scheduling_succeeded if request.xhr? # ...2 lines... else # ...5 lines... end end
def do_post_success_cleanup if request.xhr? # DO NOTHING else # ...1 line... end end
end
111
class ScheduleInstallation private
def scheduling_failed if request.xhr? render :json => {:errors => [#... else flash[:error] = #... redirect_to #... end endend
112
Single Responsibility Principle
113
ScheduleInstallationScheduleInstallationAnd
DoOneThingForAJAXRequestsAndDoSomethingElseForHTMLRequests
114
ScheduleInstallationScheduleInstallation And
DoOneThingForAJAXRequests AndDoSomethingElseForHTMLRequests
115
“Methods, like classes, should have a single
responsibility.”-Sandi Metz
116
http://en.wikipedia.org/wiki/File:Bill_%26_Ted%27s_Excellent_Adventure_(Original_Motion_Picture_Soundtrack).jpg117
http://en.wikipedia.org/wiki/File:Paris_Tuileries_Garden_Facepalm_statue.jpg118
Single Responsibility Principle
Every class should have a single responsibility, and that responsibility
should be entirely encapsulatedby the class.
119
ScheduleInstallationScheduleInstallation And
DoOneThingForAJAXRequests AndDoSomethingElseForHTMLRequests
120
Responder
121
122
InstallationsController
123
InstallationsController
ScheduleInstallation???
124
InstallationsController
Responder
???
ScheduleInstallation???
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
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
125
126
Dualism
class Responder def cannot_schedule_while_credit_check_pending # ...6 lines... end
def cannot_schedule_while_credit_check_pending if request.xhr? # ...1 line... else # ...2 lines... end end
def handle_exception(e) if request.xhr? # ...7 lines... else # ...2 lines... end end
def scheduling_failed if request.xhr? # ...1 line... else # ...2 lines... end end
def scheduling_succeeded if request.xhr? # ...2 lines... else # ...5 lines... end end
def do_post_success_cleanup if request.xhr? # NOP else # ...2 lines... end end end
if request.xhr? # do fooelse # do barend
Replace ConditionalWith Polymorphism
129
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
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
132
InstallationsController
Responder
???
ScheduleInstallation???
class InstallationsController < ActionController::Base
def schedule responder = if request.xhr? AJAXResponder.new(self) else HTMLResponder.new(self) end ScheduleInstallation.new(responder).call endend
LESSONS LEARNED
134
Refactoring is Math
135
Fast CharacterizationTests Rock
136
Embrace Duplicationif request.xhr?
137
0
2
4
6
8
10
Embrace Evil Hacks
138
Perspective MattersSuperficial design flaws
can concealfundamental design flaws
139
http://gomakemeasandwich.wordpress.com/2011/10/26/a-yeaf-of-gmmas-where-do-we-go-from-here/
Where Do We Go From Here?
140
141
142
143
Practice!• Play with automated refactorings in an IDE
• Do them manually in the editor (wax on, wax off)
145
Practice!• Commit early, commit often:
‘git reset --hard’ is your friend!
• Use throwaway branches
• Write fast characterization tests
146
Fluent Refactoringgithub.com/geeksam/fluent-refactoring
Twitter, Github: @geeksam
147