Your SlideShare is downloading. ×
0
Fluent Refactoring
Sam Livingston-Gray

THERE
WILL BE
CODE!
It may be
this small

puts (1..100).map { |i|
s = ''
fizz = (i...
Math
m/

2
Tuesday, October 22, 13
3
http://2012books.lardbucket.org/books/elementary-algebra/section_06/5d10b670d78abac93a4572dc0c2afb0f.jpg
Tuesday, Octobe...
4
Tuesday, October 22, 13

http://www.wikihow.com/Image:Solve-for-X-Step-12.jpg
5
Tuesday, October 22, 13

http://math.about.com/od/algebra/ss/birthday.htm
6
http://www.smosh.com/smosh-pit/photos/16-wonderfully-stupid-test-answers
Tuesday, October 22, 13
Algebra

7
Tuesday, October 22, 13
Algebra Isn’t Math

8
Tuesday, October 22, 13
Algebra Isn’t all of Math

9
Tuesday, October 22, 13
Algebra ⊂ Math
Algebra

Math
10
Tuesday, October 22, 13
11

http://upload.wikimedia.org/wikipedia/commons/thumb/0/08/NautilusCutawayLogarithmicSpiral.jpg/793px-NautilusCutawayLog...
12
http://upload.wikimedia.org/wikipedia/commons/a/a4/Mandelbrot_sequence_new.gif
Tuesday, October 22, 13
13
http://mathequalslove.blogspot.com/2012/12/hexaflexagon-love.html
Tuesday, October 22, 13
14
http://think-like-a-git.net/sections/graph-theory/seven-bridges-of-konigsberg.html
Tuesday, October 22, 13
Math is a Language

15
Tuesday, October 22, 13
Math is a Language
Algebra is
[one of]
its Grammar[s]

15
Tuesday, October 22, 13
Fluent Refactoring

16
Tuesday, October 22, 13
17
http://www.kickasslabs.com/2012/04/28/rails-conf-2012-images/100_0304/
Tuesday, October 22, 13
Can I get a
definition?

17
http://www.kickasslabs.com/2012/04/28/rails-conf-2012-images/100_0304/
Tuesday, October 22, 13
Re·fac·tor·ing (noun)

18
Tuesday, October 22, 13
Re·fac·tor·ing (noun)
"...a disciplined technique for
restructuring an existing body of code,
altering its internal struct...
TL;DR

19
Tuesday, October 22, 13
TL;DR
"...a disciplined technique for
restructuring an existing body of
code, altering its internal structure
without chan...
Re·fac·tor·ing (noun)
A technique
for restructuring code
without changing behavior

20
Tuesday, October 22, 13
Tell a clearer story
with fewer details

21
Tuesday, October 22, 13
Jargon

22
Tuesday, October 22, 13

http://www.tagxedo.com/app.html
Jargon

22
Tuesday, October 22, 13

http://www.tagxedo.com/app.html
Re·fac·tor·ing (noun)

23
Tuesday, October 22, 13
Re·fac·tor·ing (noun)
A language that
describes ways to
make your code
suck less.
23
Tuesday, October 22, 13
Flu·en·cy (noun)

24
Tuesday, October 22, 13
Flu·en·cy (noun)
What you can say when you’re
not thinking about how to say it

24
Tuesday, October 22, 13
Flu·en·cy (noun)
What you can say when you’re
woken up in the middle of the night
with a flashlight in your face

25
Tuesda...
Stress

26
http://dailyawesimity.files.wordpress.com/2013/01/cat-stress-relief-4.jpg
Tuesday, October 22, 13
Language Hunters

27
Tuesday, October 22, 13
Levels of Proficiency
Level 1
Level 2
Level 3
Level 4

28
Tuesday, October 22, 13

http://www.jamesshore.com/Blog/Proficienc...
Levels of Proficiency
Level 1

Tarzan at
a party

“Beer!”
“Good party.”

Level 2
Level 3
Level 4

29
Tuesday, October 22, 1...
Levels of Proficiency
Level 1

Tarzan at
a party

“Beer!”
“Good party.”

Level 2

Going to
the party

"Where is the party?"...
Levels of Proficiency
Level 1

Tarzan at
a party

“Beer!”
“Good party.”

Level 2

Going to
the party

"Where is the party?"...
Levels of Proficiency
Level 1

Tarzan at
a party

“Beer!”
“Good party.”

Level 2

Going to
the party

"Where is the party?"...
Levels of Proficiency
Level 1

Tarzan at
a party

“Beer!”
“Good party.”

Level 2

Going to
the party

"Where is the party?"...
Levels of Proficiency
Level 1

Tarzan at
a party

“Beer!”
“Good party.”

Level 2

Going to
the party

"Where is the party?"...
Story Time

35
Tuesday, October 22, 13
Production Rails Code

36
Tuesday, October 22, 13
Production Rails Code
Used with:

• Permission

36
Tuesday, October 22, 13
Production Rails Code
Used with:

• Permission
• Obfuscation

36
Tuesday, October 22, 13
Production Rails Code
Used with:

• Permission
• Obfuscation
• Respect

36
Tuesday, October 22, 13
Respect

37
Tuesday, October 22, 13
class InstallationsController < ActionController::Base
# lots more stuff...
def schedule
desired_date = params[:desired_da...
Observations

class InstallationsController < ActionController::Base
# lots more stuff...

def schedule
desired_date = par...
Observations

class InstallationsController < ActionController::Base
# lots more stuff...

def schedule
desired_date = par...
Observations

class InstallationsController < ActionController::Base
# lots more stuff...

def schedule
desired_date = par...
Observations

class InstallationsController < ActionController::Base
# lots more stuff...

def schedule
desired_date = par...
Observations

class InstallationsController < ActionController::Base
# lots more stuff...

def schedule
desired_date = par...
Observations

class InstallationsController < ActionController::Base
# lots more stuff...

def schedule
desired_date = par...
Observations

class InstallationsController < ActionController::Base
# lots more stuff...

def schedule
desired_date = par...
Observations

class InstallationsController < ActionController::Base
# lots more stuff...

def schedule
desired_date = par...
Observations

class InstallationsController < ActionController::Base
# lots more stuff...

def schedule
desired_date = par...
Complexity

40
http://scientopia.org/blogs/whitecoatunderground/2009/06/10/my-head-just-asploded-twice/
Tuesday, October 2...
Ship it!

41
Tuesday, October 22, 13

http://shipitsquirrel.github.io/
~800 lines

42
Tuesday, October 22, 13
~800 lines

42
http://hyperboleandahalf.blogspot.com/2010/06/this-is-why-ill-never-be-adult.html
Tuesday, October 22, 13
~800 lines

42
http://hyperboleandahalf.blogspot.com/2010/06/this-is-why-ill-never-be-adult.html
Tuesday, October 22, 13
~800 lines

43
http://hyperboleandahalf.blogspot.com/2010/06/this-is-why-ill-never-be-adult.html
Tuesday, October 22, 13
Make the Job Smaller

44
Tuesday, October 22, 13
Replace Method with
Method Object
See also:
Katrina Owen,
“Therapeutic Refactoring”

45
Tuesday, October 22, 13
class InstallationsController <
ActionController::Base
def schedule
# LOTS OF CODE
end
end

46
Tuesday, October 22, 13
class InstallationsController <
ActionController::Base
def schedule
# LOTS OF CODE
end
end
class ScheduleInstallation
def ...
class InstallationsController <
ActionController::Base
def schedule
end
end
class ScheduleInstallation
def call
# LOTS OF ...
class InstallationsController <
ActionController::Base
def schedule
ScheduleInstallation.new.call
end
end
class ScheduleIn...
NoMethodError
LOL WUT?

48
Tuesday, October 22, 13
class
def
#
#
#
#
end
end

ScheduleInstallation
call
LOTS OF CODE
... params ...
... render ...
... redirect_to ...

49
Tu...
class ScheduleInstallation
def initialize(controller)
@controller = controller
end
def
#
#
#
#
end
end

call
LOTS OF CODE
...
class ScheduleInstallation
def initialize(controller)
@controller = controller
end
def
#
#
#
#
end
end

call
LOTS OF CODE
...
class ScheduleInstallation
def initialize(controller)
@controller = controller
end
extend Forwardable
def_delegators :@con...
class ScheduleInstallation
def initialize(controller)
@controller = controller
end
def call
# LOTS OF CODE
end
def method_...
Code Archaeology

54
http://anthro.ucsc.edu/undergraduate/sub-fields/anthro-archeaology.html
Tuesday, October 22, 13
if request.xhr?
# ...20 lines...
else
# ...22 lines...
end

55
Tuesday, October 22, 13
if request.xml_http_request?
# ...20 lines...
else
# ...22 lines...
end

56
Tuesday, October 22, 13
if request.xml_http_request?
begin
#...
end
else
# ...22 lines...
end

57
Tuesday, October 22, 13
if request.xml_http_request?
begin
if @installation.pending_credit_check?
render :json => #...
return
end
#...
end
else
# ...
if request.xml_http_request?
begin
if @installation.pending_credit_check?
render :json => #...
return
end
#...
end
else
# ...
if request.xml_http_request?
begin
if @installation.pending_credit_check?
render :json => #...
return
end
#...
Guard Claus...
if request.xhr?
begin
if @installation.pending_credit_check?
render :json => #...
return
end
#...
end
else
if @installatio...
tion.city_id, :view => "calendar") and return

59
Tuesday, October 22, 13
if request.xhr?
begin
if @installation.pending_credit_check?
render :json => #...
return
end
#...
end
else
if @installatio...
if request.xhr?
if request.xhr?
begin
if @installation.pend
if @installation.pending_credit_check? #..
render :json =>
ren...
if request.xhr?
if @installation.pending_credit_check?
render :json => #...
return
end
begin
#...
end
else
if @installatio...
if request.xhr?
if request.xhr?
if @installation.pending_credit_check?
if @installation.pend
render :json => #...
render :...
if request.xhr?
if @installation.pending_credit_check?
render :json => #...
return
end
else
if @installation.pending_credi...
emph·AS·is

63
Tuesday, October 22, 13
if request.xhr?
if @installation.pending_credit_check?
render :json => #...
return
end
else
if @installation.pending_credi...
if request.xhr?
if @installation.pending_credit_check?
render :json => #...
return
end
else
if @installation.pending_credi...
if request.xhr?
if @installation.pending_credit_check?
render :json => #...
return
end
else
if @installation.pending_credi...
Flatten Nested
Conditionals
source:
Michael Feathers
in Dr. Dobbs

65
Tuesday, October 22, 13
if request.xhr?
if @installation.pending_credit_check?
render :json => #...
return
end
else
if @installation.pending_credi...
if ajax
if nope
render :json => #...
return
end
else
if nope
flash[:error] = #...
redirect_to #...
return
end
end

67
Tues...
if ajax
if nope
render :json => #...
return
end
else
if nope
flash[:error] = #...
redirect_to #...
return
end
end

67
Tues...
if ajax
if nope
render :json => #...
return
end
else
if nope
flash[:error] = #...
redirect_to #...
return
end
end

68
Tues...
if ajax
if ajax
if nope
if nope
render :json => #...
render :json => #..
return
return
end
end
else
end
if nope
if not aja...
if ajax
if nope
render :json => #...
return
end
end
if not ajax
if nope
flash[:error] = #...
redirect_to #...
return
end
e...
if ajax
if ajax && nope
if nope
render :json => #...
render :json => #... return
return
end
end
if (not ajax) && nope
end
...
if ajax && nope
render :json => #...
return
end
if (not ajax) && nope
flash[:error] = #...
redirect_to #...
return
end

70...
if ajax && nope
render :json => #...
return
end
if (not ajax) && nope
flash[:error] = #...
redirect_to #...
return
end

70...
if ajax && nope
render :json => #...
return
end
if (not ajax) && nope
flash[:error] = #...
redirect_to #...
return
end

if...
if nope
if ajax
render :json => #...
return
end
if not ajax
flash[:error] = #...
redirect_to #...
return
end
end

71
Tuesd...
if nope
if nope
if ajax
if ajax
render :json => #...
render :json => #..
return
return
end
else
if not ajax
flash[:error] ...
if nope
if ajax
render :json => #...
return
else
flash[:error] = #...
redirect_to #...
return
end
end

72
Tuesday, October...
if nope
if nope
if ajax
if ajax
render :json => #...
render :json => #..
return
else
else
flash[:error] = #..
flash[:error...
if request.xhr?
if @installation.pending_credit_check?
render :json => #...
return
end
else
if @installation.pending_credi...
if request.xhr?
if @installation.pendin
if @installation.pending_credit_check?
if request.xhr?
render :json => #...
render...
if @installation.pending_credit_check?
if request.xhr?
render :json => #...
else
flash[:error] = #...
redirect_to #...
end...
if @installation.pendin
if @installation.pending_credit_check?
cant_schedule_while_c
if request.xhr?
render :json => #... ...
if @installation.pending_credit_check?
cant_schedule_while_credit_check_pending
return
end
if request.xhr?
begin
#...
end
...
“Hard Work” Montage

76
http://spectrumculture.com/2012/09/re-makere-model-the-karate-kid-1984-vs-the-karate-kid-2010.html...
class InstallationsController < ActionController::Base
def schedule
desired_date = params[:desired_date]
if request.xhr?
b...
class InstallationsController < ActionController::Base
def schedule
desired_date = params[:desired_date]
if request.xhr?
b...
class ScheduleInstallation
def call
if @installation.pending_credit_check?
cant_schedule_while_credit_check_pending
return...
class ScheduleInstallation
def call
if @installation.pending_credit_check?
cant_schedule_while_credit_check_pending
return...
class ScheduleInstallation
def call
if @installation.pending_credit_check?
cant_schedule_while_credit_check_pending
return...
Under The Rug

80
Tuesday, October 22, 13
def cannot_schedule_while_#...
if request.xhr?
# ...1 line...
else
# ...2 lines...
end
end

def scheduling_failed
if reque...
def cannot_schedule_while_#...
if request.xhr?
# ...1 line...
else
# ...2 lines...
end
end

def scheduling_failed
if reque...
class ScheduleInstallation
def scheduling_failed
if request.xhr?
render :json => {:errors#...
else
flash[:error] = #...
re...
class ScheduleInstallation
def scheduling_failed
if request.xhr?
render :json => {:errors#...
else
flash[:error] = #...
re...
class ScheduleInstallation
def scheduling_failed
if request.xhr?
render :json => {:errors#...
else
flash[:error] = #...
re...
class ScheduleInstallation
def scheduling_failed
if request.xhr?
render :json => {:errors#...
else
flash[:error] = #...
re...
class ScheduleInstallation
def scheduling_failed
if request.xhr?
render :json => {:errors#...
else
flash[:error] = #...
re...
class ScheduleInstallation
def scheduling_failed
if request.xhr?
render :json => {:errors#...
else
flash[:error] = #...
re...
Single Responsibility
Principle
(SRP for short)

83
Tuesday, October 22, 13
ScheduleInstallation

84
Tuesday, October 22, 13
ScheduleInstallation
ScheduleInstallationAnd
DoOneThingForAJAXRequestsAnd
DoSomethingElseForHTMLRequests

84
Tuesday, Octo...
ScheduleInstallation
ScheduleInstallation And

DoOneThingForAJAXRequests And
DoSomethingElseForHTMLRequests

85
Tuesday, O...
ScheduleInstallation
ScheduleInstallation And
DoOneThingForAJAXRequests And
DoSomethingElseForHTMLRequests

86
Tuesday, Oc...
Recap

87
Tuesday, October 22, 13
InstallationsController

88
Tuesday, October 22, 13
InstallationsController

ScheduleInstallation

88
Tuesday, October 22, 13
InstallationsController
???
ScheduleInstallation

88
Tuesday, October 22, 13
InstallationsController

Responder
???
ScheduleInstallation

89
Tuesday, October 22, 13
InstallationsController
???
Responder
???
ScheduleInstallation

89
Tuesday, October 22, 13
class ScheduleInstallation
def call
private
def
def
def
def
def
end

cannot_schedule_while_credit_check_pendin
handle_exce...
class ScheduleInstallation
class ScheduleInstallat
def call
def call
end
private
class Responder
def cannot_schedule_while...
Responder

91
Tuesday, October 22, 13
if request.xhr?
# do this
else
# do that
end
Tuesday, October 22, 13
Replace Conditional
With Polymorphism

93
Tuesday, October 22, 13
class
def
def
def
def
def
end

Tuesday, October 22, 13

Responder
cannot_schedule_while_credit_check_pending
handle_except...
class
def
def
def
def
def
end

Responder
class AJAXResponder
cannot_schedule_while_credit_check_pending
def
handle_excepti...
class InstallationsController
< ActionController::Base
def schedule
responder = request.xhr?
?
AJAXResponder.new(self) :
H...
class InstallationsController
< ActionController::Base
def schedule
responder = request.xhr?
?
AJAXResponder.new(self) :
H...
class InstallationsController
< ActionController::Base
def schedule
responder = request.xhr?
?
AJAXResponder.new(self) :
H...
class AJAXResponder
def scheduling_failed
if request.xhr?
render :json => #...
else
flash[:error] = #...
redirect_to #...
...
class AJAXResponder
def scheduling_failed
if request.xhr?
render :json => #...
else
flash[:error] = #...
redirect_to #...
...
class InstallationsController
< ActionController::Base
def schedule
responder = request.xhr?
?
AJAXResponder.new(self) :
H...
Where Do We Go
From Here?

98
http://gomakemeasandwich.wordpress.com/2011/10/26/a-yeaf-of-gmmas-where-do-we-go-from-here/
...
99
Tuesday, October 22, 13

http://www.poodr.info/
100
Tuesday, October 22, 13
101
Tuesday, October 22, 13
102
Tuesday, October 22, 13
103
Tuesday, October 22, 13
Commit Early,
Commit Often

104
Tuesday, October 22, 13
Throw Your Work Away

105
Tuesday, October 22, 13
Speed Up Your Tests!

106
Tuesday, October 22, 13
Speed Up Your Tests!
See also:
Katrina Owen,
“Therapeutic Refactoring”
(srsly)

106
Tuesday, October 22, 13
I work at LivingSocial.
We’re hiring.

107
Tuesday, October 22, 13
I work at LivingSocial.
We’re hiring.
(Who isn’t?)

107
Tuesday, October 22, 13
Thanks to:
Jim Shore and Diana Larsen
for “Agile Fluency”
Kirsten Comandich
Sandi Metz, Katrina Owen,
Sonia Connolly
PDX.r...
github.com/geeksam
/fluent-refactoring

109
Tuesday, October 22, 13
github.com/geeksam
/fluent-refactoring
Sam Livingston-Gray
geeksam@gmail.com
Twitter, Github: @geeksam

110
Tuesday, Octob...
Upcoming SlideShare
Loading in...5
×

Fluent Refactoring (Cascadia Ruby Conf 2013)

659

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
659
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Transcript of "Fluent Refactoring (Cascadia Ruby Conf 2013)"

  1. 1. Fluent Refactoring Sam Livingston-Gray THERE WILL BE CODE! It may be this small puts (1..100).map { |i| s = '' fizz = (i % 3).zero? buzz = (i % 5).zero? s << 'Fizz' if fizz s << 'Buzz' if buzz s = i if s.empty? s } 1 Tuesday, October 22, 13
  2. 2. Math m/ 2 Tuesday, October 22, 13
  3. 3. 3 http://2012books.lardbucket.org/books/elementary-algebra/section_06/5d10b670d78abac93a4572dc0c2afb0f.jpg Tuesday, October 22, 13
  4. 4. 4 Tuesday, October 22, 13 http://www.wikihow.com/Image:Solve-for-X-Step-12.jpg
  5. 5. 5 Tuesday, October 22, 13 http://math.about.com/od/algebra/ss/birthday.htm
  6. 6. 6 http://www.smosh.com/smosh-pit/photos/16-wonderfully-stupid-test-answers Tuesday, October 22, 13
  7. 7. Algebra 7 Tuesday, October 22, 13
  8. 8. Algebra Isn’t Math 8 Tuesday, October 22, 13
  9. 9. Algebra Isn’t all of Math 9 Tuesday, October 22, 13
  10. 10. Algebra ⊂ Math Algebra Math 10 Tuesday, October 22, 13
  11. 11. 11 http://upload.wikimedia.org/wikipedia/commons/thumb/0/08/NautilusCutawayLogarithmicSpiral.jpg/793px-NautilusCutawayLogarithmicSpiral.jpg Tuesday, October 22, 13
  12. 12. 12 http://upload.wikimedia.org/wikipedia/commons/a/a4/Mandelbrot_sequence_new.gif Tuesday, October 22, 13
  13. 13. 13 http://mathequalslove.blogspot.com/2012/12/hexaflexagon-love.html Tuesday, October 22, 13
  14. 14. 14 http://think-like-a-git.net/sections/graph-theory/seven-bridges-of-konigsberg.html Tuesday, October 22, 13
  15. 15. Math is a Language 15 Tuesday, October 22, 13
  16. 16. Math is a Language Algebra is [one of] its Grammar[s] 15 Tuesday, October 22, 13
  17. 17. Fluent Refactoring 16 Tuesday, October 22, 13
  18. 18. 17 http://www.kickasslabs.com/2012/04/28/rails-conf-2012-images/100_0304/ Tuesday, October 22, 13
  19. 19. Can I get a definition? 17 http://www.kickasslabs.com/2012/04/28/rails-conf-2012-images/100_0304/ Tuesday, October 22, 13
  20. 20. Re·fac·tor·ing (noun) 18 Tuesday, October 22, 13
  21. 21. Re·fac·tor·ing (noun) "...a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior." -refactoring.com 18 Tuesday, October 22, 13
  22. 22. TL;DR 19 Tuesday, October 22, 13
  23. 23. TL;DR "...a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior." 19 Tuesday, October 22, 13
  24. 24. Re·fac·tor·ing (noun) A technique for restructuring code without changing behavior 20 Tuesday, October 22, 13
  25. 25. Tell a clearer story with fewer details 21 Tuesday, October 22, 13
  26. 26. Jargon 22 Tuesday, October 22, 13 http://www.tagxedo.com/app.html
  27. 27. Jargon 22 Tuesday, October 22, 13 http://www.tagxedo.com/app.html
  28. 28. Re·fac·tor·ing (noun) 23 Tuesday, October 22, 13
  29. 29. Re·fac·tor·ing (noun) A language that describes ways to make your code suck less. 23 Tuesday, October 22, 13
  30. 30. Flu·en·cy (noun) 24 Tuesday, October 22, 13
  31. 31. Flu·en·cy (noun) What you can say when you’re not thinking about how to say it 24 Tuesday, October 22, 13
  32. 32. Flu·en·cy (noun) What you can say when you’re woken up in the middle of the night with a flashlight in your face 25 Tuesday, October 22, 13
  33. 33. Stress 26 http://dailyawesimity.files.wordpress.com/2013/01/cat-stress-relief-4.jpg Tuesday, October 22, 13
  34. 34. Language Hunters 27 Tuesday, October 22, 13
  35. 35. Levels of Proficiency Level 1 Level 2 Level 3 Level 4 28 Tuesday, October 22, 13 http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html
  36. 36. Levels of Proficiency Level 1 Tarzan at a party “Beer!” “Good party.” Level 2 Level 3 Level 4 29 Tuesday, October 22, 13 http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html
  37. 37. Levels of Proficiency 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 Level 4 30 Tuesday, October 22, 13 http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html
  38. 38. Levels of Proficiency 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 31 Tuesday, October 22, 13 http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html
  39. 39. Levels of Proficiency 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?" 32 Tuesday, October 22, 13 http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html
  40. 40. Levels of Proficiency 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?" 33 Tuesday, October 22, 13 http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html
  41. 41. Levels of Proficiency 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?" 34 Tuesday, October 22, 13 http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html
  42. 42. Story Time 35 Tuesday, October 22, 13
  43. 43. Production Rails Code 36 Tuesday, October 22, 13
  44. 44. Production Rails Code Used with: • Permission 36 Tuesday, October 22, 13
  45. 45. Production Rails Code Used with: • Permission • Obfuscation 36 Tuesday, October 22, 13
  46. 46. Production Rails Code Used with: • Permission • Obfuscation • Respect 36 Tuesday, October 22, 13
  47. 47. Respect 37 Tuesday, October 22, 13
  48. 48. 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 Tuesday, October 22, 13 38
  49. 49. Observations 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 Tuesday, October 22, 13 39
  50. 50. Observations 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 ~800 lines in file # lots more stuff... end Tuesday, October 22, 13 39
  51. 51. Observations 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 ~800 lines in file ~50 lines in method # lots more stuff... end Tuesday, October 22, 13 39
  52. 52. Observations 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 ~800 lines in file ~50 lines in method Longest line: 177 chars # lots more stuff... end Tuesday, October 22, 13 39
  53. 53. Observations 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 ~800 lines in file ~50 lines in method Longest line: 177 chars Indentation: 4-16 spaces # lots more stuff... end Tuesday, October 22, 13 39
  54. 54. Observations 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 ~800 lines in file ~50 lines in method Longest line: 177 chars Indentation: 4-16 spaces Nested control structures: # lots more stuff... end Tuesday, October 22, 13 39
  55. 55. Observations 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 ~800 lines in file ~50 lines in method Longest line: 177 chars Indentation: 4-16 spaces Nested control structures: audit_trail_for # lots more stuff... end Tuesday, October 22, 13 39
  56. 56. Observations 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 ~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 # lots more stuff... end Tuesday, October 22, 13 39
  57. 57. Observations 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 ~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 # lots more stuff... end Tuesday, October 22, 13 39
  58. 58. Complexity 40 http://scientopia.org/blogs/whitecoatunderground/2009/06/10/my-head-just-asploded-twice/ Tuesday, October 22, 13
  59. 59. Ship it! 41 Tuesday, October 22, 13 http://shipitsquirrel.github.io/
  60. 60. ~800 lines 42 Tuesday, October 22, 13
  61. 61. ~800 lines 42 http://hyperboleandahalf.blogspot.com/2010/06/this-is-why-ill-never-be-adult.html Tuesday, October 22, 13
  62. 62. ~800 lines 42 http://hyperboleandahalf.blogspot.com/2010/06/this-is-why-ill-never-be-adult.html Tuesday, October 22, 13
  63. 63. ~800 lines 43 http://hyperboleandahalf.blogspot.com/2010/06/this-is-why-ill-never-be-adult.html Tuesday, October 22, 13
  64. 64. Make the Job Smaller 44 Tuesday, October 22, 13
  65. 65. Replace Method with Method Object See also: Katrina Owen, “Therapeutic Refactoring” 45 Tuesday, October 22, 13
  66. 66. class InstallationsController < ActionController::Base def schedule # LOTS OF CODE end end 46 Tuesday, October 22, 13
  67. 67. class InstallationsController < ActionController::Base def schedule # LOTS OF CODE end end class ScheduleInstallation def call end end 47 Tuesday, October 22, 13
  68. 68. class InstallationsController < ActionController::Base def schedule end end class ScheduleInstallation def call # LOTS OF CODE end end 47 Tuesday, October 22, 13
  69. 69. class InstallationsController < ActionController::Base def schedule ScheduleInstallation.new.call end end class ScheduleInstallation def call # LOTS OF CODE end end 47 Tuesday, October 22, 13
  70. 70. NoMethodError LOL WUT? 48 Tuesday, October 22, 13
  71. 71. class def # # # # end end ScheduleInstallation call LOTS OF CODE ... params ... ... render ... ... redirect_to ... 49 Tuesday, October 22, 13
  72. 72. class ScheduleInstallation def initialize(controller) @controller = controller end def # # # # end end call LOTS OF CODE ... params ... ... render ... ... redirect_to ... 50 Tuesday, October 22, 13
  73. 73. class ScheduleInstallation def initialize(controller) @controller = controller end def # # # # end end call LOTS OF CODE ... @controller.params ... ... @controller.render ... ... @controller.redirect_to ... 51 Tuesday, October 22, 13
  74. 74. class ScheduleInstallation def initialize(controller) @controller = controller end extend Forwardable def_delegators :@controller, :params, :render, :redirect_to def # # # # end end call LOTS OF CODE ... params ... ... render ... ... redirect_to ... 52 Tuesday, October 22, 13
  75. 75. 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 53 Tuesday, October 22, 13
  76. 76. Code Archaeology 54 http://anthro.ucsc.edu/undergraduate/sub-fields/anthro-archeaology.html Tuesday, October 22, 13
  77. 77. if request.xhr? # ...20 lines... else # ...22 lines... end 55 Tuesday, October 22, 13
  78. 78. if request.xml_http_request? # ...20 lines... else # ...22 lines... end 56 Tuesday, October 22, 13
  79. 79. if request.xml_http_request? begin #... end else # ...22 lines... end 57 Tuesday, October 22, 13
  80. 80. if request.xml_http_request? begin if @installation.pending_credit_check? render :json => #... return end #... end else # ...22 lines... end 58 Tuesday, October 22, 13
  81. 81. if request.xml_http_request? begin if @installation.pending_credit_check? render :json => #... return end #... end else # ...22 lines... end 58 Tuesday, October 22, 13
  82. 82. if request.xml_http_request? begin if @installation.pending_credit_check? render :json => #... return end #... Guard Clause end -Smalltalk Best Practice Patterns else by Kent Beck # ...22 lines... end 58 Tuesday, October 22, 13
  83. 83. 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 end 59 Tuesday, October 22, 13
  84. 84. tion.city_id, :view => "calendar") and return 59 Tuesday, October 22, 13
  85. 85. 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 60 Tuesday, October 22, 13
  86. 86. if request.xhr? if request.xhr? begin if @installation.pend if @installation.pending_credit_check? #.. render :json => render :json => #... return return end end begin #... #... end end else else if @installation.pending_credit_check? if @installation.pend flash[:error] = #... flash[:error] = #.. redirect_to installations_path(:city_id => redirect_to install return return end end begin begin #... #... end end 60 Tuesday, October 22, 13
  87. 87. if request.xhr? if @installation.pending_credit_check? render :json => #... return end begin #... end else if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path(:city_id => return end begin #... end 61 Tuesday, October 22, 13
  88. 88. if request.xhr? if request.xhr? if @installation.pending_credit_check? if @installation.pend render :json => #... render :json => #.. return return end end begin else #... if @installation.pend end flash[:error] = #.. else redirect_to #... if @installation.pending_credit_check? return flash[:error] = #... end redirect_to installations_path(:city_id => end return end if request.xhr? begin begin #... #... end end 61 Tuesday, October 22, 13
  89. 89. 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 62 Tuesday, October 22, 13
  90. 90. emph·AS·is 63 Tuesday, October 22, 13
  91. 91. 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 64 Tuesday, October 22, 13
  92. 92. 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 64 Tuesday, October 22, 13
  93. 93. 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 64 Tuesday, October 22, 13
  94. 94. Flatten Nested Conditionals source: Michael Feathers in Dr. Dobbs 65 Tuesday, October 22, 13
  95. 95. 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 66 Tuesday, October 22, 13
  96. 96. if ajax if nope render :json => #... return end else if nope flash[:error] = #... redirect_to #... return end end 67 Tuesday, October 22, 13
  97. 97. if ajax if nope render :json => #... return end else if nope flash[:error] = #... redirect_to #... return end end 67 Tuesday, October 22, 13 ajax nope TRUE TRUE ajax nope FALSE TRUE
  98. 98. if ajax if nope render :json => #... return end else if nope flash[:error] = #... redirect_to #... return end end 68 Tuesday, October 22, 13
  99. 99. if ajax if ajax if nope if nope render :json => #... render :json => #.. return return end end else end if nope if not ajax flash[:error] = #... if nope redirect_to #... flash[:error] = #.. return redirect_to #... end return end end end 68 Tuesday, October 22, 13
  100. 100. if ajax if nope render :json => #... return end end if not ajax if nope flash[:error] = #... redirect_to #... return end end 69 Tuesday, October 22, 13
  101. 101. if ajax if ajax && nope if nope render :json => #... render :json => #... return return end end if (not ajax) && nope end flash[:error] = #... if not ajax redirect_to #... if nope return flash[:error] = #...end redirect_to #... return end end 69 Tuesday, October 22, 13
  102. 102. if ajax && nope render :json => #... return end if (not ajax) && nope flash[:error] = #... redirect_to #... return end 70 Tuesday, October 22, 13
  103. 103. if ajax && nope render :json => #... return end if (not ajax) && nope flash[:error] = #... redirect_to #... return end 70 Tuesday, October 22, 13
  104. 104. if ajax && nope render :json => #... return end if (not ajax) && nope flash[:error] = #... redirect_to #... return end if nope if ajax render :json => #.. return end if not ajax flash[:error] = #.. redirect_to #... return end end 70 Tuesday, October 22, 13
  105. 105. if nope if ajax render :json => #... return end if not ajax flash[:error] = #... redirect_to #... return end end 71 Tuesday, October 22, 13
  106. 106. if nope if nope if ajax if ajax render :json => #... render :json => #.. return return end else if not ajax flash[:error] = #.. flash[:error] = #... redirect_to #... redirect_to #... return return end end end end 71 Tuesday, October 22, 13
  107. 107. if nope if ajax render :json => #... return else flash[:error] = #... redirect_to #... return end end 72 Tuesday, October 22, 13
  108. 108. if nope if nope if ajax if ajax render :json => #... render :json => #.. return else else flash[:error] = #.. flash[:error] = #... redirect_to #... redirect_to #... end return return end end end 72 Tuesday, October 22, 13
  109. 109. 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 73 Tuesday, October 22, 13
  110. 110. if request.xhr? if @installation.pendin if @installation.pending_credit_check? if request.xhr? render :json => #... render :json => #.. return else end flash[:error] = #.. else redirect_to #... if @installation.pending_credit_check? end flash[:error] = #... return redirect_to #... end return end end 73 Tuesday, October 22, 13
  111. 111. if @installation.pending_credit_check? if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end return end 74 Tuesday, October 22, 13
  112. 112. if @installation.pendin if @installation.pending_credit_check? cant_schedule_while_c if request.xhr? render :json => #... return end else flash[:error] = #... redirect_to #... end return end 74 Tuesday, October 22, 13
  113. 113. if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end if request.xhr? begin #... end else begin #... end end 75 Tuesday, October 22, 13
  114. 114. “Hard Work” Montage 76 http://spectrumculture.com/2012/09/re-makere-model-the-karate-kid-1984-vs-the-karate-kid-2010.html/ Tuesday, October 22, 13
  115. 115. class InstallationsController < ActionController::Base def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end end 77 Tuesday, October 22, 13
  116. 116. class InstallationsController < ActionController::Base def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end end class ScheduleInstallation def call if @installation.pending_c cant_schedule_while_cred return end 77 Tuesday, October 22, 13 audit_trail_for(current_us if schedule! if @installation.sched scheduling_succeeded end do_post_success_cleanu else scheduling_failed end end rescue => e handle_exception e end end
  117. 117. class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end audit_trail_for(current_user) do if schedule! if @installation.scheduled_date scheduling_succeeded end do_post_success_cleanup else scheduling_failed end end rescue => e handle_exception e end end 78 Tuesday, October 22, 13
  118. 118. class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end audit_trail_for(current_user) do if schedule! if @installation.scheduled_date scheduling_succeeded end do_post_success_cleanup else scheduling_failed end end rescue => e handle_exception e end end request.xhr? 79 Tuesday, October 22, 13
  119. 119. class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end audit_trail_for(current_user) do if schedule! if @installation.scheduled_date scheduling_succeeded end do_post_success_cleanup else scheduling_failed end end rescue => e handle_exception e end end request.xhr? 79 Tuesday, October 22, 13
  120. 120. Under The Rug 80 Tuesday, October 22, 13
  121. 121. def cannot_schedule_while_#... if request.xhr? # ...1 line... else # ...2 lines... end end def scheduling_failed 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 do_post_success_cleanup if request.xhr? # DO NOTHING else # ...1 line... end end def scheduling_succeeded if request.xhr? # ...2 lines... else # ...5 lines... end end 81 Tuesday, October 22, 13
  122. 122. def cannot_schedule_while_#... if request.xhr? # ...1 line... else # ...2 lines... end end def scheduling_failed 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 do_post_success_cleanup if request.xhr? # DO NOTHING else # ...1 line... end end def scheduling_succeeded if request.xhr? # ...2 lines... else # ...5 lines... end end 81 Tuesday, October 22, 13
  123. 123. class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end end end Tuesday, October 22, 13
  124. 124. class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end end end Tuesday, October 22, 13
  125. 125. class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end end end Tuesday, October 22, 13
  126. 126. class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end end end Tuesday, October 22, 13
  127. 127. class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end end end Tuesday, October 22, 13
  128. 128. class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end end end Tuesday, October 22, 13
  129. 129. Single Responsibility Principle (SRP for short) 83 Tuesday, October 22, 13
  130. 130. ScheduleInstallation 84 Tuesday, October 22, 13
  131. 131. ScheduleInstallation ScheduleInstallationAnd DoOneThingForAJAXRequestsAnd DoSomethingElseForHTMLRequests 84 Tuesday, October 22, 13
  132. 132. ScheduleInstallation ScheduleInstallation And DoOneThingForAJAXRequests And DoSomethingElseForHTMLRequests 85 Tuesday, October 22, 13
  133. 133. ScheduleInstallation ScheduleInstallation And DoOneThingForAJAXRequests And DoSomethingElseForHTMLRequests 86 Tuesday, October 22, 13
  134. 134. Recap 87 Tuesday, October 22, 13
  135. 135. InstallationsController 88 Tuesday, October 22, 13
  136. 136. InstallationsController ScheduleInstallation 88 Tuesday, October 22, 13
  137. 137. InstallationsController ??? ScheduleInstallation 88 Tuesday, October 22, 13
  138. 138. InstallationsController Responder ??? ScheduleInstallation 89 Tuesday, October 22, 13
  139. 139. InstallationsController ??? Responder ??? ScheduleInstallation 89 Tuesday, October 22, 13
  140. 140. class ScheduleInstallation def call private def def def def def end cannot_schedule_while_credit_check_pendin handle_exception(e) scheduling_failed scheduling_succeeded do_post_success_cleanup class Responder end 90 Tuesday, October 22, 13
  141. 141. class ScheduleInstallation class ScheduleInstallat def call def call end private class Responder def cannot_schedule_while_credit_check_pendin def cannot_schedule_w def handle_exception(e) def handle_exception( def scheduling_failed def scheduling_failed def scheduling_succeededdef scheduling_succee def do_post_success_cleanup do_post_success_c def end end class Responder end 90 Tuesday, October 22, 13
  142. 142. Responder 91 Tuesday, October 22, 13
  143. 143. if request.xhr? # do this else # do that end Tuesday, October 22, 13
  144. 144. Replace Conditional With Polymorphism 93 Tuesday, October 22, 13
  145. 145. class def def def def def end Tuesday, October 22, 13 Responder cannot_schedule_while_credit_check_pending handle_exception(e) scheduling_failed scheduling_succeeded do_post_success_cleanup
  146. 146. class def def def def def end Responder class AJAXResponder cannot_schedule_while_credit_check_pending def handle_exception(e) cannot_schedule_while_cre scheduling_failed def handle_exception(e) scheduling_succeeded def scheduling_failed do_post_success_cleanup scheduling_succeede def 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 Tuesday, October 22, 13
  147. 147. class InstallationsController < ActionController::Base def schedule responder = request.xhr? ? AJAXResponder.new(self) : HTMLResponder.new(self) ScheduleInstallation.new(responder).call end end Tuesday, October 22, 13
  148. 148. class InstallationsController < ActionController::Base def schedule responder = request.xhr? ? AJAXResponder.new(self) : HTMLResponder.new(self) ScheduleInstallation.new(responder).call end end Tuesday, October 22, 13
  149. 149. class InstallationsController < ActionController::Base def schedule responder = request.xhr? ? AJAXResponder.new(self) : HTMLResponder.new(self) ScheduleInstallation.new(responder).call end end Tuesday, October 22, 13
  150. 150. 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 Tuesday, October 22, 13
  151. 151. 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 Tuesday, October 22, 13 class AJAXResponder def scheduling_failed render :json => #... end end class HTMLResponder def scheduling_failed flash[:error] = #... redirect_to #... end end
  152. 152. class InstallationsController < ActionController::Base def schedule responder = request.xhr? ? AJAXResponder.new(self) : HTMLResponder.new(self) ScheduleInstallation.new(responder).call end end Tuesday, October 22, 13
  153. 153. Where Do We Go From Here? 98 http://gomakemeasandwich.wordpress.com/2011/10/26/a-yeaf-of-gmmas-where-do-we-go-from-here/ Tuesday, October 22, 13
  154. 154. 99 Tuesday, October 22, 13 http://www.poodr.info/
  155. 155. 100 Tuesday, October 22, 13
  156. 156. 101 Tuesday, October 22, 13
  157. 157. 102 Tuesday, October 22, 13
  158. 158. 103 Tuesday, October 22, 13
  159. 159. Commit Early, Commit Often 104 Tuesday, October 22, 13
  160. 160. Throw Your Work Away 105 Tuesday, October 22, 13
  161. 161. Speed Up Your Tests! 106 Tuesday, October 22, 13
  162. 162. Speed Up Your Tests! See also: Katrina Owen, “Therapeutic Refactoring” (srsly) 106 Tuesday, October 22, 13
  163. 163. I work at LivingSocial. We’re hiring. 107 Tuesday, October 22, 13
  164. 164. I work at LivingSocial. We’re hiring. (Who isn’t?) 107 Tuesday, October 22, 13
  165. 165. Thanks to: Jim Shore and Diana Larsen for “Agile Fluency” Kirsten Comandich Sandi Metz, Katrina Owen, Sonia Connolly PDX.rb 108 Tuesday, October 22, 13
  166. 166. github.com/geeksam /fluent-refactoring 109 Tuesday, October 22, 13
  167. 167. github.com/geeksam /fluent-refactoring Sam Livingston-Gray geeksam@gmail.com Twitter, Github: @geeksam 110 Tuesday, October 22, 13
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×