167
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

Fluent Refactoring (Cascadia Ruby Conf 2013)

Embed Size (px)

Citation preview

Page 1: Fluent Refactoring (Cascadia Ruby Conf 2013)

Fluent RefactoringSam Livingston-Gray

THERE WILL BE CODE!

It may bethis small

puts (1..100).map { |i| s = '' fizz = (i % 3).zero? buzz = (i % 5).zero? s << 'Fizz' if fizz s << 'Buzz' if buzz s = i if s.empty? s}

1

Tuesday, October 22, 13

Page 2: Fluent Refactoring (Cascadia Ruby Conf 2013)

Math

2

\m/

Tuesday, October 22, 13

Page 4: Fluent Refactoring (Cascadia Ruby Conf 2013)

http://www.wikihow.com/Image:Solve-for-X-Step-12.jpg4

Tuesday, October 22, 13

Page 5: Fluent Refactoring (Cascadia Ruby Conf 2013)

http://math.about.com/od/algebra/ss/birthday.htm5

Tuesday, October 22, 13

Page 7: Fluent Refactoring (Cascadia Ruby Conf 2013)

Algebra

7

Tuesday, October 22, 13

Page 8: Fluent Refactoring (Cascadia Ruby Conf 2013)

Algebra Isn’t Math

8

Tuesday, October 22, 13

Page 9: Fluent Refactoring (Cascadia Ruby Conf 2013)

Algebra Isn’t all of Math

9

Tuesday, October 22, 13

Page 10: Fluent Refactoring (Cascadia Ruby Conf 2013)

Algebra ⊂ Math

Math

Algebra

10

Tuesday, October 22, 13

Page 15: Fluent Refactoring (Cascadia Ruby Conf 2013)

Math is a Language

15

Tuesday, October 22, 13

Page 16: Fluent Refactoring (Cascadia Ruby Conf 2013)

Math is a LanguageAlgebra is[one of]

its Grammar[s]

15

Tuesday, October 22, 13

Page 17: Fluent Refactoring (Cascadia Ruby Conf 2013)

Fluent Refactoring

16

Tuesday, October 22, 13

Page 20: Fluent Refactoring (Cascadia Ruby Conf 2013)

Re·fac·tor·ing (noun)

18

Tuesday, October 22, 13

Page 21: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

Page 22: Fluent Refactoring (Cascadia Ruby Conf 2013)

TL;DR

19

Tuesday, October 22, 13

Page 23: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

Page 24: Fluent Refactoring (Cascadia Ruby Conf 2013)

Re·fac·tor·ing (noun)

A techniquefor restructuring code

without changing behavior

20

Tuesday, October 22, 13

Page 25: Fluent Refactoring (Cascadia Ruby Conf 2013)

Tell a clearer storywith fewer details

21

Tuesday, October 22, 13

Page 26: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

Jargon

22

Tuesday, October 22, 13

Page 27: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

Jargon

22

Tuesday, October 22, 13

Page 28: Fluent Refactoring (Cascadia Ruby Conf 2013)

Re·fac·tor·ing (noun)

23

Tuesday, October 22, 13

Page 29: Fluent Refactoring (Cascadia Ruby Conf 2013)

Re·fac·tor·ing (noun)

A language thatdescribes ways tomake your code

suck less.

23

Tuesday, October 22, 13

Page 30: Fluent Refactoring (Cascadia Ruby Conf 2013)

Flu·en·cy (noun)

24

Tuesday, October 22, 13

Page 31: Fluent Refactoring (Cascadia Ruby Conf 2013)

Flu·en·cy (noun)What you can say when you’renot thinking about how to say it

24

Tuesday, October 22, 13

Page 32: Fluent Refactoring (Cascadia Ruby Conf 2013)

What you can say when you’rewoken up in the middle of the night

with a flashlight in your face

Flu·en·cy (noun)

25

Tuesday, October 22, 13

Page 34: Fluent Refactoring (Cascadia Ruby Conf 2013)

Language Hunters

27

Tuesday, October 22, 13

Page 35: Fluent Refactoring (Cascadia Ruby Conf 2013)

http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html

Level 1

Level 2

Level 3

Level 4

Levels of Proficiency

28

Tuesday, October 22, 13

Page 36: Fluent Refactoring (Cascadia Ruby Conf 2013)

http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html

Level 1 Tarzan ata party

“Beer!”“Good party.”

Level 2

Level 3

Level 4

Levels of Proficiency

29

Tuesday, October 22, 13

Page 37: Fluent Refactoring (Cascadia Ruby Conf 2013)

http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html

Level 1 Tarzan ata party

“Beer!”“Good party.”

Level 2 Going tothe party

"Where is the party?""How do I get to the party?"

Level 3

Level 4

Levels of Proficiency

30

Tuesday, October 22, 13

Page 38: Fluent Refactoring (Cascadia Ruby Conf 2013)

http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html

Level 1 Tarzan ata party

“Beer!”“Good party.”

Level 2 Going tothe party

"Where is the party?""How do I get to the party?"

Level 3 Discussingthe party

"What happened at the party last night?"

Level 4

Levels of Proficiency

31

Tuesday, October 22, 13

Page 39: Fluent Refactoring (Cascadia Ruby Conf 2013)

http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html

Level 1 Tarzan ata party

“Beer!”“Good party.”

Level 2 Going tothe party

"Where is the party?""How do I get to the party?"

Level 3 Discussingthe party

"What happened at the party last night?"

Level 4 Charlie Rose "Should parties be illegal?"

Levels of Proficiency

32

Tuesday, October 22, 13

Page 40: Fluent Refactoring (Cascadia Ruby Conf 2013)

http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html

Level 1 Tarzan ata party

“Beer!”“Good party.”

Level 2 Going tothe party

"Where is the party?""How do I get to the party?"

Level 3 Discussingthe party

"What happened at the party last night?"

Level 4 Charlie Rose "Should parties be illegal?"

Levels of Proficiency

33

Tuesday, October 22, 13

Page 41: Fluent Refactoring (Cascadia Ruby Conf 2013)

http://www.jamesshore.com/Blog/Proficiencies-of-Planning.html

Level 1 Tarzan ata party

“Beer!”“Good party.”

Level 2 Going tothe party

"Where is the party?""How do I get to the party?"

Levels of Proficiency

34

Tuesday, October 22, 13

Page 42: Fluent Refactoring (Cascadia Ruby Conf 2013)

Story Time

35

Tuesday, October 22, 13

Page 43: Fluent Refactoring (Cascadia Ruby Conf 2013)

Production Rails Code

36

Tuesday, October 22, 13

Page 44: Fluent Refactoring (Cascadia Ruby Conf 2013)

Used with:

• Permission

Production Rails Code

36

Tuesday, October 22, 13

Page 45: Fluent Refactoring (Cascadia Ruby Conf 2013)

Used with:

• Permission

• Obfuscation

Production Rails Code

36

Tuesday, October 22, 13

Page 46: Fluent Refactoring (Cascadia Ruby Conf 2013)

Used with:

• Permission

• Obfuscation

• Respect

Production Rails Code

36

Tuesday, October 22, 13

Page 47: Fluent Refactoring (Cascadia Ruby Conf 2013)

Respect

37

Tuesday, October 22, 13

Page 48: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end

# lots more stuff...end

38

Tuesday, October 22, 13

Page 49: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end

# lots more stuff...end

Observations

39

Tuesday, October 22, 13

Page 50: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end

# lots more stuff...end

Observations

~800 lines in file

39

Tuesday, October 22, 13

Page 51: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end

# lots more stuff...end

Observations

~800 lines in file

~50 lines in method

39

Tuesday, October 22, 13

Page 52: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end

# lots more stuff...end

Observations

~800 lines in file

~50 lines in method

Longest line: 177 chars

39

Tuesday, October 22, 13

Page 53: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end

# lots more stuff...end

Observations

~800 lines in file

~50 lines in method

Longest line: 177 chars

Indentation: 4-16 spaces

39

Tuesday, October 22, 13

Page 54: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end

# lots more stuff...end

Observations

~800 lines in file

~50 lines in method

Longest line: 177 chars

Indentation: 4-16 spaces

Nested control structures:

39

Tuesday, October 22, 13

Page 55: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end

# lots more stuff...end

Observations

~800 lines in file

~50 lines in method

Longest line: 177 chars

Indentation: 4-16 spaces

Nested control structures:

audit_trail_for

39

Tuesday, October 22, 13

Page 56: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end

# lots more stuff...end

Observations

~800 lines in file

~50 lines in method

Longest line: 177 chars

Indentation: 4-16 spaces

Nested control structures:

audit_trail_for

begin/rescue/end

39

Tuesday, October 22, 13

Page 57: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end end

# lots more stuff...end

Observations

~800 lines in file

~50 lines in method

Longest line: 177 chars

Indentation: 4-16 spaces

Nested control structures:

audit_trail_for

begin/rescue/end

if/else/end

39

Tuesday, October 22, 13

Page 59: Fluent Refactoring (Cascadia Ruby Conf 2013)

http://shipitsquirrel.github.io/

Ship it!

41

Tuesday, October 22, 13

Page 60: Fluent Refactoring (Cascadia Ruby Conf 2013)

~800 lines

42

Tuesday, October 22, 13

Page 64: Fluent Refactoring (Cascadia Ruby Conf 2013)

Make the Job Smaller

44

Tuesday, October 22, 13

Page 65: Fluent Refactoring (Cascadia Ruby Conf 2013)

Replace Method with Method Object

45

See also:

Katrina Owen,“Therapeutic Refactoring”

Tuesday, October 22, 13

Page 66: Fluent Refactoring (Cascadia Ruby Conf 2013)

class InstallationsController < ActionController::Base def schedule # LOTS OF CODE endend

46

Tuesday, October 22, 13

Page 67: Fluent Refactoring (Cascadia Ruby Conf 2013)

class InstallationsController < ActionController::Base def schedule

endend

class ScheduleInstallation def call

endend

# LOTS OF CODE

47

Tuesday, October 22, 13

Page 68: Fluent Refactoring (Cascadia Ruby Conf 2013)

class InstallationsController < ActionController::Base def schedule

endend

class ScheduleInstallation def call

endend

# LOTS OF CODE

47

Tuesday, October 22, 13

Page 69: Fluent Refactoring (Cascadia Ruby Conf 2013)

class InstallationsController < ActionController::Base def schedule

endend

class ScheduleInstallation def call

endend

ScheduleInstallation.new.call

# LOTS OF CODE

47

Tuesday, October 22, 13

Page 70: Fluent Refactoring (Cascadia Ruby Conf 2013)

48

NoMethodErrorLOL WUT?

Tuesday, October 22, 13

Page 71: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def call # LOTS OF CODE # ... params ... # ... render ... # ... redirect_to ... endend

49

Tuesday, October 22, 13

Page 72: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def initialize(controller) @controller = controller end

def call # LOTS OF CODE # ... params ... # ... render ... # ... redirect_to ... endend

50

Tuesday, October 22, 13

Page 73: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def initialize(controller) @controller = controller end

def call # LOTS OF CODE # ... @controller.params ... # ... @controller.render ... # ... @controller.redirect_to ... endend

51

Tuesday, October 22, 13

Page 74: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def initialize(controller) @controller = controller end

extend Forwardable def_delegators :@controller, :params, :render, :redirect_to

def call # LOTS OF CODE # ... params ... # ... render ... # ... redirect_to ... endend

52

Tuesday, October 22, 13

Page 75: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def initialize(controller) @controller = controller end

def call # LOTS OF CODE end

def method_missing(m, *a, &b) @controller.send(m, *a, &b) endend

53

Tuesday, October 22, 13

Page 77: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? # ...20 lines...else # ...22 lines...end

55

Tuesday, October 22, 13

Page 78: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xml_http_request? # ...20 lines...else # ...22 lines...end

56

Tuesday, October 22, 13

Page 79: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xml_http_request? begin #... endelse # ...22 lines...end

57

Tuesday, October 22, 13

Page 80: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xml_http_request? begin if @installation.pending_credit_check? render :json => #... return end #... endelse # ...22 lines...end

58

Tuesday, October 22, 13

Page 81: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xml_http_request? begin if @installation.pending_credit_check? render :json => #... return end #... endelse # ...22 lines...end

58

Tuesday, October 22, 13

Page 82: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xml_http_request? begin if @installation.pending_credit_check? render :json => #... return end #... endelse # ...22 lines...end

58

Guard Clause-Smalltalk Best Practice Patterns

by Kent Beck

Tuesday, October 22, 13

Page 83: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? begin if @installation.pending_credit_check? render :json => #... return end #... endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin #... endend 59

Tuesday, October 22, 13

Page 84: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? begin if @installation.pending_credit_check? render :json => #... return end #... endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin #... endend 59

Tuesday, October 22, 13

Page 85: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? begin if @installation.pending_credit_check? render :json => #... return end #... endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path(:city_id => return end begin #... end 60

Tuesday, October 22, 13

Page 86: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? begin if @installation.pending_credit_check? render :json => #... return end #... endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path(:city_id => return end begin #... end

if request.xhr? if @installation.pending_credit_check? render :json => #... return end begin #... endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path( return end begin #... end60

Tuesday, October 22, 13

Page 87: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? if @installation.pending_credit_check? render :json => #... return end begin #... endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path(:city_id => return end begin #... end 61

Tuesday, October 22, 13

Page 88: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? if @installation.pending_credit_check? render :json => #... return end begin #... endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to installations_path(:city_id => return end begin #... end

if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend

if request.xhr? begin #... end61

Tuesday, October 22, 13

Page 89: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend

62

Tuesday, October 22, 13

Page 90: Fluent Refactoring (Cascadia Ruby Conf 2013)

emph·AS·is

63

Tuesday, October 22, 13

Page 91: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend

64

Tuesday, October 22, 13

Page 92: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend

64

Tuesday, October 22, 13

Page 93: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend

64

Tuesday, October 22, 13

Page 94: Fluent Refactoring (Cascadia Ruby Conf 2013)

Flatten Nested Conditionals

source:Michael Feathers

in Dr. Dobbs

65

Tuesday, October 22, 13

Page 95: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend

66

Tuesday, October 22, 13

Page 96: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

67

Tuesday, October 22, 13

Page 97: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

67

ajax nope

TRUE TRUE

ajax nope

FALSE TRUE

Tuesday, October 22, 13

Page 98: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

68

Tuesday, October 22, 13

Page 99: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

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

68

Tuesday, October 22, 13

Page 100: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

69

Tuesday, October 22, 13

Page 101: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

if ajax && nope render :json => #... returnendif (not ajax) && nope flash[:error] = #... redirect_to #... returnend

69

Tuesday, October 22, 13

Page 102: Fluent Refactoring (Cascadia Ruby Conf 2013)

if ajax && nope render :json => #... returnendif (not ajax) && nope flash[:error] = #... redirect_to #... returnend

70

Tuesday, October 22, 13

Page 103: Fluent Refactoring (Cascadia Ruby Conf 2013)

if ajax && nope render :json => #... returnendif (not ajax) && nope flash[:error] = #... redirect_to #... returnend

70

Tuesday, October 22, 13

Page 104: Fluent Refactoring (Cascadia Ruby Conf 2013)

if ajax && nope render :json => #... returnendif (not ajax) && nope flash[:error] = #... redirect_to #... returnend

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

70

Tuesday, October 22, 13

Page 105: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

71

Tuesday, October 22, 13

Page 106: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

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

71

Tuesday, October 22, 13

Page 107: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

72

Tuesday, October 22, 13

Page 108: Fluent Refactoring (Cascadia Ruby Conf 2013)

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

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

72

Tuesday, October 22, 13

Page 109: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend

73

Tuesday, October 22, 13

Page 110: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? if @installation.pending_credit_check? render :json => #... return endelse if @installation.pending_credit_check? flash[:error] = #... redirect_to #... return endend

if @installation.pending_credit_check? if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end returnend

73

Tuesday, October 22, 13

Page 111: Fluent Refactoring (Cascadia Ruby Conf 2013)

if @installation.pending_credit_check? if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end returnend

74

Tuesday, October 22, 13

Page 112: Fluent Refactoring (Cascadia Ruby Conf 2013)

if @installation.pending_credit_check? if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end returnend

if @installation.pending_credit_check? cant_schedule_while_credit_check_pending returnend

74

Tuesday, October 22, 13

Page 113: Fluent Refactoring (Cascadia Ruby Conf 2013)

if @installation.pending_credit_check? cant_schedule_while_credit_check_pending returnend

if request.xhr? begin #... endelse begin #... endend

75

Tuesday, October 22, 13

Page 115: Fluent Refactoring (Cascadia Ruby Conf 2013)

class InstallationsController < ActionController::Base def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end endend

77

Tuesday, October 22, 13

Page 116: Fluent Refactoring (Cascadia Ruby Conf 2013)

class InstallationsController < ActionController::Base def schedule desired_date = params[:desired_date] if request.xhr? begin if @installation.pending_credit_check? render :json => {:errors => ["Cannot schedule installation while credit check is pending"]}, :status => 400 return end audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date date = @installation.scheduled_date.in_time_zone(@installation.city.timezone).to_date render :json => {:errors => nil, :html => schedule_response(@installation, date)} end else render :json => {:errors => [%Q{Could not update installation. #{@installation.errors.full_messages.join(' ')}}] } end end rescue ActiveRecord::RecordInvalid => e render :json => {:errors => [e.message] } rescue ArgumentError => e render :json => {:errors => ["Could not schedule installation. Start by making sure the desired date is on a business day."]} end else if @installation.pending_credit_check? flash[:error] = "Cannot schedule installation while credit check is pending" redirect_to installations_path(:city_id => @installation.city_id, :view => "calendar") and return end begin audit_trail_for(current_user) do if @installation.schedule!(desired_date, :installation_type => params[:installation_type], :city => @city) if @installation.scheduled_date if @installation.customer_provided_equipment? flash[:success] = %Q{Installation scheduled} else flash[:success] = %Q{Installation scheduled! Don't forget to order the equipment also.} end end else flash[:error] = %Q{Could not schedule installation, check the phase of the moon} end end rescue => e flash[:error] = e.message end redirect_to(@installation.customer_provided_equipment? ? customer_provided_installations_path : installations_path(:city_id => @installation.city_id, :view => "calendar")) end endend

class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end

audit_trail_for(current_user) if schedule! if @installation.scheduled_date scheduling_succeeded end do_post_success_cleanup else scheduling_failed end end rescue => e handle_exception e endend

77

Tuesday, October 22, 13

Page 117: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end

audit_trail_for(current_user) do if schedule! if @installation.scheduled_date scheduling_succeeded end do_post_success_cleanup else scheduling_failed end end rescue => e handle_exception e endend

78

Tuesday, October 22, 13

Page 118: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end

audit_trail_for(current_user) do if schedule! if @installation.scheduled_date scheduling_succeeded end do_post_success_cleanup else scheduling_failed end end rescue => e handle_exception e endend

request.xhr?

79

Tuesday, October 22, 13

Page 119: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def call if @installation.pending_credit_check? cant_schedule_while_credit_check_pending return end

audit_trail_for(current_user) do if schedule! if @installation.scheduled_date scheduling_succeeded end do_post_success_cleanup else scheduling_failed end end rescue => e handle_exception e endend

request.xhr?

79

Tuesday, October 22, 13

Page 120: Fluent Refactoring (Cascadia Ruby Conf 2013)

Under The Rug

80

Tuesday, October 22, 13

Page 121: Fluent Refactoring (Cascadia Ruby Conf 2013)

def cannot_schedule_while_#... if request.xhr? # ...1 line... else # ...2 lines... endend

def handle_exception(e) if request.xhr? # ...7 lines... else # ...2 lines... endend

def scheduling_succeeded if request.xhr? # ...2 lines... else # ...5 lines... endend

def scheduling_failed if request.xhr? # ...1 line... else # ...2 lines... endend

def do_post_success_cleanup if request.xhr? # DO NOTHING else # ...1 line... endend

81

Tuesday, October 22, 13

Page 122: Fluent Refactoring (Cascadia Ruby Conf 2013)

def cannot_schedule_while_#... if request.xhr? # ...1 line... else # ...2 lines... endend

def handle_exception(e) if request.xhr? # ...7 lines... else # ...2 lines... endend

def scheduling_succeeded if request.xhr? # ...2 lines... else # ...5 lines... endend

def scheduling_failed if request.xhr? # ...1 line... else # ...2 lines... endend

def do_post_success_cleanup if request.xhr? # DO NOTHING else # ...1 line... endend

81

Tuesday, October 22, 13

Page 123: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end endend

Tuesday, October 22, 13

Page 124: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end endend

Tuesday, October 22, 13

Page 125: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end endend

Tuesday, October 22, 13

Page 126: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end endend

Tuesday, October 22, 13

Page 127: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end endend

Tuesday, October 22, 13

Page 128: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def scheduling_failed if request.xhr? render :json => {:errors#... else flash[:error] = #... redirect_to #... end endend

Tuesday, October 22, 13

Page 129: Fluent Refactoring (Cascadia Ruby Conf 2013)

Single Responsibility Principle

83

(SRP for short)

Tuesday, October 22, 13

Page 130: Fluent Refactoring (Cascadia Ruby Conf 2013)

ScheduleInstallation

84

Tuesday, October 22, 13

Page 131: Fluent Refactoring (Cascadia Ruby Conf 2013)

ScheduleInstallationScheduleInstallationAnd

DoOneThingForAJAXRequestsAndDoSomethingElseForHTMLRequests

84

Tuesday, October 22, 13

Page 132: Fluent Refactoring (Cascadia Ruby Conf 2013)

ScheduleInstallationScheduleInstallation And

DoOneThingForAJAXRequests And DoSomethingElseForHTMLRequests

85

Tuesday, October 22, 13

Page 133: Fluent Refactoring (Cascadia Ruby Conf 2013)

ScheduleInstallationScheduleInstallation And

DoOneThingForAJAXRequests And DoSomethingElseForHTMLRequests

86

Tuesday, October 22, 13

Page 134: Fluent Refactoring (Cascadia Ruby Conf 2013)

Recap

87

Tuesday, October 22, 13

Page 135: Fluent Refactoring (Cascadia Ruby Conf 2013)

88

InstallationsController

Tuesday, October 22, 13

Page 136: Fluent Refactoring (Cascadia Ruby Conf 2013)

88

InstallationsController

ScheduleInstallation

Tuesday, October 22, 13

Page 137: Fluent Refactoring (Cascadia Ruby Conf 2013)

88

InstallationsController

ScheduleInstallation

???

Tuesday, October 22, 13

Page 138: Fluent Refactoring (Cascadia Ruby Conf 2013)

89

InstallationsController

Responder

ScheduleInstallation

???

Tuesday, October 22, 13

Page 139: Fluent Refactoring (Cascadia Ruby Conf 2013)

89

InstallationsController

Responder

???

ScheduleInstallation

???

Tuesday, October 22, 13

Page 140: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def call

private

def cannot_schedule_while_credit_check_pendin def handle_exception(e) def scheduling_failed def scheduling_succeeded def do_post_success_cleanupend

class Responderend

90

Tuesday, October 22, 13

Page 141: Fluent Refactoring (Cascadia Ruby Conf 2013)

class ScheduleInstallation def call

private

def cannot_schedule_while_credit_check_pendin def handle_exception(e) def scheduling_failed def scheduling_succeeded def do_post_success_cleanupend

class Responderend

90

class ScheduleInstallation def callend

class Responder def cannot_schedule_while_credit_check_pe def handle_exception(e) def scheduling_failed def scheduling_succeeded def do_post_success_cleanupend

Tuesday, October 22, 13

Page 142: Fluent Refactoring (Cascadia Ruby Conf 2013)

91

Responder

Tuesday, October 22, 13

Page 143: Fluent Refactoring (Cascadia Ruby Conf 2013)

if request.xhr? # do thiselse # do thatend

Tuesday, October 22, 13

Page 144: Fluent Refactoring (Cascadia Ruby Conf 2013)

Replace ConditionalWith Polymorphism

93

Tuesday, October 22, 13

Page 145: Fluent Refactoring (Cascadia Ruby Conf 2013)

class Responder def cannot_schedule_while_credit_check_pending def handle_exception(e) def scheduling_failed def scheduling_succeeded def do_post_success_cleanupend

Tuesday, October 22, 13

Page 146: Fluent Refactoring (Cascadia Ruby Conf 2013)

class Responder def cannot_schedule_while_credit_check_pending def handle_exception(e) def scheduling_failed def scheduling_succeeded def do_post_success_cleanupend

class AJAXResponder def cannot_schedule_while_credit_check_pending def handle_exception(e) def scheduling_failed def scheduling_succeeded def do_post_success_cleanupend

class HTMLResponder def cannot_schedule_while_credit_check_pending def handle_exception(e) def scheduling_failed def scheduling_succeeded def do_post_success_cleanupend

Tuesday, October 22, 13

Page 147: Fluent Refactoring (Cascadia Ruby Conf 2013)

class InstallationsController < ActionController::Base

def schedule responder = request.xhr? ? AJAXResponder.new(self) : HTMLResponder.new(self) ScheduleInstallation.new(responder).call endend

Tuesday, October 22, 13

Page 148: Fluent Refactoring (Cascadia Ruby Conf 2013)

class InstallationsController < ActionController::Base

def schedule responder = request.xhr? ? AJAXResponder.new(self) : HTMLResponder.new(self) ScheduleInstallation.new(responder).call endend

Tuesday, October 22, 13

Page 149: Fluent Refactoring (Cascadia Ruby Conf 2013)

class InstallationsController < ActionController::Base

def schedule responder = request.xhr? ? AJAXResponder.new(self) : HTMLResponder.new(self) ScheduleInstallation.new(responder).call endend

Tuesday, October 22, 13

Page 150: Fluent Refactoring (Cascadia Ruby Conf 2013)

class AJAXResponder def scheduling_failed if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end endend

class HTMLResponder def scheduling_failed if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end endend

Tuesday, October 22, 13

Page 151: Fluent Refactoring (Cascadia Ruby Conf 2013)

class AJAXResponder def scheduling_failed if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end endend

class HTMLResponder def scheduling_failed if request.xhr? render :json => #... else flash[:error] = #... redirect_to #... end endend

class AJAXResponder def scheduling_failed render :json => #... endend

class HTMLResponder def scheduling_failed flash[:error] = #... redirect_to #... endend

Tuesday, October 22, 13

Page 152: Fluent Refactoring (Cascadia Ruby Conf 2013)

class InstallationsController < ActionController::Base

def schedule responder = request.xhr? ? AJAXResponder.new(self) : HTMLResponder.new(self) ScheduleInstallation.new(responder).call endend

Tuesday, October 22, 13

Page 154: Fluent Refactoring (Cascadia Ruby Conf 2013)

http://www.poodr.info/99

Tuesday, October 22, 13

Page 155: Fluent Refactoring (Cascadia Ruby Conf 2013)

100

Tuesday, October 22, 13

Page 156: Fluent Refactoring (Cascadia Ruby Conf 2013)

101

Tuesday, October 22, 13

Page 157: Fluent Refactoring (Cascadia Ruby Conf 2013)

102

Tuesday, October 22, 13

Page 158: Fluent Refactoring (Cascadia Ruby Conf 2013)

103

Tuesday, October 22, 13

Page 159: Fluent Refactoring (Cascadia Ruby Conf 2013)

Commit Early,Commit Often

104

Tuesday, October 22, 13

Page 160: Fluent Refactoring (Cascadia Ruby Conf 2013)

Throw Your Work Away

105

Tuesday, October 22, 13

Page 161: Fluent Refactoring (Cascadia Ruby Conf 2013)

Speed Up Your Tests!

106

Tuesday, October 22, 13

Page 162: Fluent Refactoring (Cascadia Ruby Conf 2013)

Speed Up Your Tests!See also:

Katrina Owen,“Therapeutic Refactoring”

(srsly)

106

Tuesday, October 22, 13

Page 163: Fluent Refactoring (Cascadia Ruby Conf 2013)

107

I work at LivingSocial.We’re hiring.

Tuesday, October 22, 13

Page 164: Fluent Refactoring (Cascadia Ruby Conf 2013)

107

I work at LivingSocial.We’re hiring.

(Who isn’t?)

Tuesday, October 22, 13

Page 165: Fluent Refactoring (Cascadia Ruby Conf 2013)

Jim Shore and Diana Larsenfor “Agile Fluency”

Kirsten Comandich

Sandi Metz, Katrina Owen,Sonia Connolly

PDX.rb

108

Thanks to:

Tuesday, October 22, 13

Page 166: Fluent Refactoring (Cascadia Ruby Conf 2013)

github.com/geeksam/fluent-refactoring

109

Tuesday, October 22, 13

Page 167: Fluent Refactoring (Cascadia Ruby Conf 2013)

github.com/geeksam/fluent-refactoring

Sam [email protected]

Twitter, Github: @geeksam

110

Tuesday, October 22, 13