SlideShare a Scribd company logo
1 of 147
Download to read offline
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

What's hot

WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011John Ford
 
Damn Fine CoffeeScript
Damn Fine CoffeeScriptDamn Fine CoffeeScript
Damn Fine CoffeeScriptniklal
 
Tugas praktikukm pemrograman c++
Tugas praktikukm  pemrograman c++Tugas praktikukm  pemrograman c++
Tugas praktikukm pemrograman c++Dendi Riadi
 
SALARY MANAGEMENT SYSTEM IN C++
SALARY MANAGEMENT SYSTEM IN C++SALARY MANAGEMENT SYSTEM IN C++
SALARY MANAGEMENT SYSTEM IN C++vikram mahendra
 
Zf2 how arrays will save your project
Zf2   how arrays will save your projectZf2   how arrays will save your project
Zf2 how arrays will save your projectMichelangelo van Dam
 
BLOOD DONATION SYSTEM IN C++
BLOOD DONATION SYSTEM IN C++BLOOD DONATION SYSTEM IN C++
BLOOD DONATION SYSTEM IN C++vikram mahendra
 
MoSQL: More than SQL, but Less than ORM @ PyCon APAC 2013
MoSQL: More than SQL, but Less than ORM @ PyCon APAC 2013MoSQL: More than SQL, but Less than ORM @ PyCon APAC 2013
MoSQL: More than SQL, but Less than ORM @ PyCon APAC 2013Mosky Liu
 

What's hot (12)

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

Similar to Fluent Refactoring (Lone Star Ruby Conf 2013)

Blocks by Lachs Cox
Blocks by Lachs CoxBlocks by Lachs Cox
Blocks by Lachs Coxlachie
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme SwiftMovel
 
Real life-coffeescript
Real life-coffeescriptReal life-coffeescript
Real life-coffeescriptDavid Furber
 
SoTWLG Intro to Code Bootcamps 2016 (Roger Nesbitt)
SoTWLG Intro to Code Bootcamps 2016 (Roger Nesbitt)SoTWLG Intro to Code Bootcamps 2016 (Roger Nesbitt)
SoTWLG Intro to Code Bootcamps 2016 (Roger Nesbitt)ruthmcdavitt
 
Intro to Ruby - Twin Cities Code Camp 7
Intro to Ruby - Twin Cities Code Camp 7Intro to Ruby - Twin Cities Code Camp 7
Intro to Ruby - Twin Cities Code Camp 7Brian Hogan
 
Ruby Topic Maps Tutorial (2007-10-10)
Ruby Topic Maps Tutorial (2007-10-10)Ruby Topic Maps Tutorial (2007-10-10)
Ruby Topic Maps Tutorial (2007-10-10)Benjamin Bock
 
Test First Teaching
Test First TeachingTest First Teaching
Test First TeachingSarah Allen
 
Fluent Refactoring (Cascadia Ruby Conf 2013)
Fluent Refactoring (Cascadia Ruby Conf 2013)Fluent Refactoring (Cascadia Ruby Conf 2013)
Fluent Refactoring (Cascadia Ruby Conf 2013)Sam Livingston-Gray
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
Frege - consequently functional programming for the JVM
Frege - consequently functional programming for the JVMFrege - consequently functional programming for the JVM
Frege - consequently functional programming for the JVMDierk König
 
Beware: Sharp Tools
Beware: Sharp ToolsBeware: Sharp Tools
Beware: Sharp Toolschrismdp
 
Ruby Language - A quick tour
Ruby Language - A quick tourRuby Language - A quick tour
Ruby Language - A quick touraztack
 
Test-driven Development (TDD)
Test-driven Development (TDD)Test-driven Development (TDD)
Test-driven Development (TDD)Bran van der Meer
 
Programming python quick intro for schools
Programming python quick intro for schoolsProgramming python quick intro for schools
Programming python quick intro for schoolsDan Bowen
 
Coffee scriptisforclosers nonotes
Coffee scriptisforclosers nonotesCoffee scriptisforclosers nonotes
Coffee scriptisforclosers nonotesBrandon Satrom
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Railsrstankov
 
FITC '14 Toronto - Technology, a means to an end
FITC '14 Toronto - Technology, a means to an endFITC '14 Toronto - Technology, a means to an end
FITC '14 Toronto - Technology, a means to an endThibault Imbert
 
Technology: A Means to an End with Thibault Imbert
Technology: A Means to an End with Thibault ImbertTechnology: A Means to an End with Thibault Imbert
Technology: A Means to an End with Thibault ImbertFITC
 

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

Blocks by Lachs Cox
Blocks by Lachs CoxBlocks by Lachs Cox
Blocks by Lachs Cox
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme Swift
 
Real life-coffeescript
Real life-coffeescriptReal life-coffeescript
Real life-coffeescript
 
SoTWLG Intro to Code Bootcamps 2016 (Roger Nesbitt)
SoTWLG Intro to Code Bootcamps 2016 (Roger Nesbitt)SoTWLG Intro to Code Bootcamps 2016 (Roger Nesbitt)
SoTWLG Intro to Code Bootcamps 2016 (Roger Nesbitt)
 
Intro to Ruby - Twin Cities Code Camp 7
Intro to Ruby - Twin Cities Code Camp 7Intro to Ruby - Twin Cities Code Camp 7
Intro to Ruby - Twin Cities Code Camp 7
 
Ruby Topic Maps Tutorial (2007-10-10)
Ruby Topic Maps Tutorial (2007-10-10)Ruby Topic Maps Tutorial (2007-10-10)
Ruby Topic Maps Tutorial (2007-10-10)
 
Test First Teaching
Test First TeachingTest First Teaching
Test First Teaching
 
Fluent Refactoring (Cascadia Ruby Conf 2013)
Fluent Refactoring (Cascadia Ruby Conf 2013)Fluent Refactoring (Cascadia Ruby Conf 2013)
Fluent Refactoring (Cascadia Ruby Conf 2013)
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
Frege - consequently functional programming for the JVM
Frege - consequently functional programming for the JVMFrege - consequently functional programming for the JVM
Frege - consequently functional programming for the JVM
 
Beware: Sharp Tools
Beware: Sharp ToolsBeware: Sharp Tools
Beware: Sharp Tools
 
Ruby Language - A quick tour
Ruby Language - A quick tourRuby Language - A quick tour
Ruby Language - A quick tour
 
Test-driven Development (TDD)
Test-driven Development (TDD)Test-driven Development (TDD)
Test-driven Development (TDD)
 
Why ruby
Why rubyWhy ruby
Why ruby
 
Programming python quick intro for schools
Programming python quick intro for schoolsProgramming python quick intro for schools
Programming python quick intro for schools
 
Coffee scriptisforclosers nonotes
Coffee scriptisforclosers nonotesCoffee scriptisforclosers nonotes
Coffee scriptisforclosers nonotes
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
FITC '14 Toronto - Technology, a means to an end
FITC '14 Toronto - Technology, a means to an endFITC '14 Toronto - Technology, a means to an end
FITC '14 Toronto - Technology, a means to an end
 
Technology: A Means to an End with Thibault Imbert
Technology: A Means to an End with Thibault ImbertTechnology: A Means to an End with Thibault Imbert
Technology: A Means to an End with Thibault Imbert
 
SOLID Ruby, SOLID Rails
SOLID Ruby, SOLID RailsSOLID Ruby, SOLID Rails
SOLID Ruby, SOLID Rails
 

Recently uploaded

Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 

Recently uploaded (20)

Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 

Fluent Refactoring (Lone Star Ruby Conf 2013)