SlideShare a Scribd company logo
Fluent Refactoring
Sam Livingston-Gray
THERE
WILL BE
CODE!
It may be
this 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 s
end
1
Let’s Talk About Math!
2
http://2012books.lardbucket.org/books/elementary-algebra/section_06/5d10b670d78abac93a4572dc0c2afb0f.jpg
3
http://www.wikihow.com/Image:Solve-for-X-Step-12.jpg
4
http://math.about.com/od/algebra/ss/birthday.htm
5
http://www.smosh.com/smosh-pit/photos/16-wonderfully-stupid-test-answers
6
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.jpg
11
http://upload.wikimedia.org/wikipedia/commons/a/a4/Mandelbrot_sequence_new.gif
12
http://mathequalslove.blogspot.com/2012/12/hexaflexagon-love.html
13
http://think-like-a-git.net/sections/graph-theory/seven-bridges-of-konigsberg.html
14
Math is a Language
Algebra 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’re
not thinking about how to say it
19
What you can say when you’re
woken 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 at
a party
“Beer!”
“Good party.”
Level 2
Going to
the party
"Where is the party?"
"How do I get to the party?"
Level 3
Discussing
the 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 take
a 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 take
a 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 take
a 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 for
restructuring code
without changing behavior
33
Re·fac·tor (verb)
To restructure code
without changing behavior
34
Tell a clearer story
with fewer details
35
Re·fac·tor·ing (noun)
A language that describes
ways to make your code
suck less.
36
THESISES
37
THESISES
THESES
38
THESISES
THESES
THESII
39
THESISES
THESES
THESII
MY POINT(S)
40
You're probably already fluent
in refactoring.
Level 1:
RenameVariable; 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
end
end
56
class InstallationsController <
ActionController::Base
def schedule
end
end
class ScheduleInstallation
def call
end
end
# LOTS OF CODE
57
class InstallationsController <
ActionController::Base
def schedule
end
end
class ScheduleInstallation
def call
end
end
# LOTS OF CODE
58
class InstallationsController <
ActionController::Base
def schedule
end
end
class ScheduleInstallation
def call
end
end
ScheduleInstallation.new.call
# LOTS OF CODE
59
class ScheduleInstallation
def call
# LOTS OF CODE
end
end
60
class ScheduleInstallation
def initialize(controller)
@controller = controller
end
def call
# LOTS OF CODE
end
end
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)
end
end
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
#...
end
else
# ...22 lines...
end
66
if request.xhr?
begin
if @installation.pending_credit_check?
render :json => #...
return
end
#...
end
else
if @installation.pending_credit_check?
flash[:error] = #...
redirect_to installations_path(:city_id =>
end
begin
#...
end
67
ion.pending_credit_check?
n => #...
n.pending_credit_check?
= #...
nstallations_path(:city_id => @installation.city
68
check?
eck?
city_id => @installation.city_id, :view => "cale
69
lation.city_id, :view => "calendar") and return
70
if request.xhr?
begin
if @installation.pending_credit_check?
render :json => #...
return
end
#...
end
else
if @installation.pending_credit_check?
flash[:error] = #...
redirect_to installations_path(:city_id =>
return
end
begin
#...
end
if request.xhr?
if @installation.pend
render :json => #..
return
end
else
if @installation.pend
flash[:error] = #..
redirect_to(...) an
return
end
end
if request.xhr?
#...
else
#...71
if request.xhr?
#...
else
#...
end
if request.xhr?
#...
else
#...
end
ZOMG
duplication!!!1!!
72
if request.xhr?
if @installation.pending_credit_check?
#...
end
else
if @installation.pending_credit_check?
#...
end
end
if request.xhr?
#...
else
#...
end
73
Emphasis
74
if request.xhr?
if @installation.pending_credit_check?
#...
end
else
if @installation.pending_credit_check?
#...
end
end
75
Flatten Nested
Conditionals
source: Michael Feathers,
writing for Dr. Dobbs
76
if request.xhr?
if @installation.pending_credit_check?
render :json => #...
return
end
else
if @installation.pending_credit_check?
flash[:error] = #...
redirect_to #...
return
end
end
77
if ajax
if pending_credit_check
render :json => #...
return
end
else
if pending_credit_check
flash[:error] = #...
redirect_to #...
return
end
end
78
if ajax
if pending_credit_check
render :json => #...
return
end
else
if pending_credit_check
flash[:error] = #...
redirect_to #...
return
end
end
if ajax
if pending_credit_che
render :json => #..
return
end
end
if not ajax
if pending_credit_che
flash[:error] = #..
redirect_to #...
return
end
end
79
if ajax
if pending_credit_check
render :json => #...
return
end
end
if not ajax
if pending_credit_check
flash[:error] = #...
redirect_to #...
return
end
end
if ajax && pending_cred
render :json => #...
return
end
if (not ajax) && pendin
flash[:error] = #...
redirect_to #...
return
end
80
if ajax && pending_credit_check
render :json => #...
return
end
if (not ajax) && pending_credit_check
flash[:error] = #...
redirect_to #...
return
end
if pending_credit_check
if ajax
render :json => #..
return
end
if not ajax
flash[:error] = #..
redirect_to #...
return
end
end
81
if pending_credit_check
if ajax
render :json => #...
return
end
if not ajax
flash[:error] = #...
redirect_to #...
return
end
end
if pending_credit_check
if ajax
render :json => #..
return
else
flash[:error] = #..
redirect_to #...
return
end
end
82
if pending_credit_check
if ajax
render :json => #...
return
else
flash[:error] = #...
redirect_to #...
return
end
end
if pending_credit_check
if ajax
render :json => #..
else
flash[:error] = #..
redirect_to #...
end
return
end
83
if ajax
if pending_credit_check
render :json => #...
return
end
else
if pending_credit_check
flash[:error] = #...
redirect_to #...
return
end
end
if pending_credit_check
if ajax
render :json => #..
else
flash[:error] = #..
redirect_to #...
end
return
end
84
if pending_credit_check
if ajax
render :json => #...
else
flash[:error] = #...
redirect_to #...
end
return
end
if pending_credit_check
cant_schedule_while_c
return
end
85
Exception Handling
86
raise “wtf” if coin.toss.heads?begin
raise “wtf” if coin.t
end
87
begin
raise “wtf” if coin.toss.heads?
end
begin
raise “wtf” if coin.t
rescue => e
raise e
end
88
begin
raise “wtf” if coin.toss.heads?
rescue => e
raise e
end
89
begin
begin
raise “wtf” if coin.toss.heads?
rescue
#...
end
rescue => e
raise e
end
90
begin
begin
raise “wtf” if coin.toss.heads?
rescue
if request.xhr?
raise “tfw” if tuesday?
else
raise “yak” if Moon.gibbous?
end
end
rescue => e
raise e
end
begin
begin
raise “wtf” if coin
rescue
if request.xhr?
raise “tfw” if tu
else
raise “yak” if Mo
end
end
rescue => e
if request.xhr?
raise e
else
raise e
end
end91
begin
begin
raise “wtf” if coin.toss.heads?
rescue
if request.xhr?
raise “tfw” if tuesday?
else
raise “yak” if Moon.gibbous?
end
end
rescue => e
if request.xhr?
raise e
else
raise e
end
end
begin
begin
raise “wtf” if coin
rescue
if request.xhr?
# DO NOTHING
else
raise “yak” if Mo
end
end
rescue => e
if request.xhr?
raise “tfw” if tues
else
raise e
end
end92
begin
begin
raise “wtf” if coin.toss.heads?
rescue
if request.xhr?
# DO NOTHING
else
raise “yak” if Moon.gibbous?
end
end
rescue => e
if request.xhr?
raise “tfw” if tuesday?
else
raise e
end
end
begin
begin
raise “wtf” if coin
rescue
if request.xhr?
# DO NOTHING
else
# DO NOTHING
end
end
rescue => e
if request.xhr?
raise “tfw” if tues
else
raise “yak” if Moon
end
end93
begin
begin
raise “wtf” if coin.toss.heads?
rescue
if request.xhr?
# DO NOTHING
else
# DO NOTHING
end
end
rescue => e
if request.xhr?
raise “tfw” if tuesday?
else
raise “yak” if Moon.gibbous?
end
end
begin
begin
raise “wtf” if coin
rescue
# DO NOTHING
end
rescue => e
if request.xhr?
raise “tfw” if tues
else
raise “yak” if Moon
end
end
94
begin
begin
raise “wtf” if coin.toss.heads?
rescue
# DO NOTHING
end
rescue => e
if request.xhr?
raise “tfw” if tuesday?
else
raise “yak” if Moon.gibbous?
end
end
begin
begin
raise “wtf” if coin
end
rescue => e
if request.xhr?
raise “tfw” if tues
else
raise “yak” if Moon
end
end
95
begin
begin
raise “wtf” if coin.toss.heads?
end
rescue => e
if request.xhr?
raise “tfw” if tuesday?
else
raise “yak” if Moon.gibbous?
end
end
begin
raise “wtf” if coin.t
rescue => e
if request.xhr?
raise “tfw” if tues
else
raise “yak” if Moon
end
end
96
begin
raise “wtf” if coin.toss.heads?
rescue => e
if request.xhr?
raise “tfw” if tuesday?
else
raise “yak” if Moon.gibbous?
end
end
begin
raise “wtf” if coin.t
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
end
end
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
end
end
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
end
end
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
end
end
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
end
end
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
end
end
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
end
end
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
end
end
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
end
end
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
end
end
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
end
end
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
end
end
112
Single Responsibility
Principle
113
ScheduleInstallation
ScheduleInstallationAnd
DoOneThingForAJAXRequestsAnd
DoSomethingElseForHTMLRequests
114
ScheduleInstallation
ScheduleInstallation And
DoOneThingForAJAXRequests And
DoSomethingElseForHTMLRequests
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).jpg
117
http://en.wikipedia.org/wiki/File:Paris_Tuileries_Garden_Facepalm_statue.jpg
118
Single Responsibility
Principle
Every class should have a single
responsibility, and that responsibility
should be entirely encapsulated
by the class.
119
ScheduleInstallation
ScheduleInstallation And
DoOneThingForAJAXRequests And
DoSomethingElseForHTMLRequests
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_cleanup
end
class Responder
end
class ScheduleInstallat
def call
end
class Responder
def cannot_schedule_w
def handle_exception(
def scheduling_failed
def scheduling_succee
def do_post_success_c
end
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 foo
else
# do bar
end
Replace Conditional
With 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_cleanup
end
class AJAXResponder
def
cannot_schedule_while_cre
def handle_exception(e)
def scheduling_failed
def scheduling_succeede
def do_post_success_cle
end
class HTMLResponder
def
cannot_schedule_while_cre
def handle_exception(e)
def scheduling_failed
def scheduling_succeede
def do_post_success_cle
end
class AJAXResponder
def scheduling_failed
if request.xhr?
render :json => #...
else
flash[:error] = #...
redirect_to #...
end
end
end
class HTMLResponder
def scheduling_failed
if request.xhr?
render :json => #...
else
flash[:error] = #...
redirect_to #...
end
end
end
class AJAXResponder
def scheduling_failed
render :json => #...
end
end
class HTMLResponder
def scheduling_failed
flash[:error] = #...
redirect_to #...
end
end
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
end
end
LESSONS LEARNED
134
Refactoring is Math
135
Fast Characterization
Tests Rock
136
Embrace Duplication
if request.xhr?
137
0
2
4
6
8
10
Embrace Evil Hacks
138
Perspective Matters
Superficial design flaws
can conceal
fundamental 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
http://www.poodr.info/
144
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 Refactoring
github.com/geeksam
/fluent-refactoring
Sam Livingston-Gray
geeksam@gmail.com
Twitter, Github: @geeksam
147

More Related Content

PDF
RubyEnRails2007 - Dr Nic Williams - Keynote
PDF
RubyEnRails2007 - Dr Nic Williams - DIY Syntax
PDF
PDF
Slaying the Dragon: Implementing a Programming Language in Ruby
PDF
Speeding up Red Team engagements with carnivorall
PDF
Computer practicals(part) Class 12
TXT
R57.Php
TXT
RubyEnRails2007 - Dr Nic Williams - Keynote
RubyEnRails2007 - Dr Nic Williams - DIY Syntax
Slaying the Dragon: Implementing a Programming Language in Ruby
Speeding up Red Team engagements with carnivorall
Computer practicals(part) Class 12
R57.Php

What's hot (11)

PDF
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
PDF
Perl 6 by example
PDF
Damn Fine CoffeeScript
DOCX
Tugas praktikukm pemrograman c++
DOC
SALARY MANAGEMENT SYSTEM IN C++
PDF
Zf2 how arrays will save your project
DOC
Ip project
DOC
BLOOD DONATION SYSTEM IN C++
PPTX
Expressions and Variables
PDF
MoSQL: More than SQL, but Less than ORM @ PyCon APAC 2013
PDF
Computer Investgatort Project (HOTEL MANAGEMENT SYSTEM)
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
Perl 6 by example
Damn Fine CoffeeScript
Tugas praktikukm pemrograman c++
SALARY MANAGEMENT SYSTEM IN C++
Zf2 how arrays will save your project
Ip project
BLOOD DONATION SYSTEM IN C++
Expressions and Variables
MoSQL: More than SQL, but Less than ORM @ PyCon APAC 2013
Computer Investgatort Project (HOTEL MANAGEMENT SYSTEM)
Ad

Similar to Fluent Refactoring (Lone Star Ruby Conf 2013) (20)

PDF
Fluent Refactoring (Cascadia Ruby Conf 2013)
PDF
So You Want to Start Refactoring?
PDF
Refactoring
PDF
Refactoring 2TheMax (con ReSharper)
KEY
Refactoring at Large
PDF
Pragmatic Patterns of Ruby on Rails - Ruby Kaigi2009
PDF
Refactoring 2 The Max
PDF
Simplifying Code: Monster to Elegant in 5 Steps
PDF
Ruby on Rails Presentation
PPTX
Code for Startup MVP (Ruby on Rails) Session 2
ODP
Refactoring Techniques
PPTX
Clean code
PDF
Crafting a Ruby-on-Rails Course for Developers
PDF
Ruby on Rails For Java Programmers
PPTX
Ruby on Rails: Coding Guideline
PDF
The Well-Grounded Nuby
PDF
The Power Of Refactoring (PHPCon Italia)
PDF
Slides chapter3part1 ruby-forjavaprogrammers
PPT
Refactoring Tips by Martin Fowler
PDF
Writing Loveable Code
Fluent Refactoring (Cascadia Ruby Conf 2013)
So You Want to Start Refactoring?
Refactoring
Refactoring 2TheMax (con ReSharper)
Refactoring at Large
Pragmatic Patterns of Ruby on Rails - Ruby Kaigi2009
Refactoring 2 The Max
Simplifying Code: Monster to Elegant in 5 Steps
Ruby on Rails Presentation
Code for Startup MVP (Ruby on Rails) Session 2
Refactoring Techniques
Clean code
Crafting a Ruby-on-Rails Course for Developers
Ruby on Rails For Java Programmers
Ruby on Rails: Coding Guideline
The Well-Grounded Nuby
The Power Of Refactoring (PHPCon Italia)
Slides chapter3part1 ruby-forjavaprogrammers
Refactoring Tips by Martin Fowler
Writing Loveable Code
Ad

Recently uploaded (20)

PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
Cloud computing and distributed systems.
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Electronic commerce courselecture one. Pdf
PDF
cuic standard and advanced reporting.pdf
PPTX
Big Data Technologies - Introduction.pptx
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PDF
Machine learning based COVID-19 study performance prediction
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PPTX
MYSQL Presentation for SQL database connectivity
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Mobile App Security Testing_ A Comprehensive Guide.pdf
Cloud computing and distributed systems.
MIND Revenue Release Quarter 2 2025 Press Release
Spectral efficient network and resource selection model in 5G networks
Dropbox Q2 2025 Financial Results & Investor Presentation
Review of recent advances in non-invasive hemoglobin estimation
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Chapter 3 Spatial Domain Image Processing.pdf
Electronic commerce courselecture one. Pdf
cuic standard and advanced reporting.pdf
Big Data Technologies - Introduction.pptx
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Assigned Numbers - 2025 - Bluetooth® Document
Machine learning based COVID-19 study performance prediction
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
MYSQL Presentation for SQL database connectivity
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Encapsulation_ Review paper, used for researhc scholars
Build a system with the filesystem maintained by OSTree @ COSCUP 2025

Fluent Refactoring (Lone Star Ruby Conf 2013)