SlideShare a Scribd company logo
1 of 135
Download to read offline
REFACTORING IN
                          PRACTICE



Saturday, September 4, 2010
WHO IS TEH ME?
      Alex Sharp
      Lead Developer at OptimisDev



      { :tweets_as => '@ajsharp'
        :blogs_at => 'alexjsharp.com'
        :ships_at => 'github.com/ajsharp' }


Saturday, September 4, 2010
_WHY THIS TALK?




Saturday, September 4, 2010
RAILS IS GROWING UP




Saturday, September 4, 2010
RAILS IS GROWING UP
           MATURING




Saturday, September 4, 2010
IT’S NOT ALL GREEN FIELDS
              AND “SOFT LAUNCHES”




Saturday, September 4, 2010
APPS MATURE TOO


Saturday, September 4, 2010
so what is this talk about?




Saturday, September 4, 2010
large apps are a completely different
                        beast than small apps




Saturday, September 4, 2010
domain complexity




Saturday, September 4, 2010
tight code coupling across domain
                                 concepts




Saturday, September 4, 2010
these apps become harder to maintain
                      as size increases




Saturday, September 4, 2010
tight domain coupling exposes itself as a
                symptom of application size




Saturday, September 4, 2010
this talk is about working with large apps




Saturday, September 4, 2010
it’s about staying on the
                                  straight and narrow




Saturday, September 4, 2010
it’s about fixing bad code.




Saturday, September 4, 2010
it’s about responsibly fixing bad code.




Saturday, September 4, 2010
it’s about responsibly fixing bad and
                             improving code.




Saturday, September 4, 2010
RULES

                                  OF

                              REFACTORING

Saturday, September 4, 2010
RULE #1
                              TESTS ARE CRUCIAL



Saturday, September 4, 2010
we’re out of our element without tests




Saturday, September 4, 2010
red, green, refactor doesn’t work
                                without the red




Saturday, September 4, 2010
Saturday, September 4, 2010
RULE #2
                              AVOID RABBIT HOLES



Saturday, September 4, 2010
RULE #3:
                              TAKE SMALL WINS



Saturday, September 4, 2010
I.E. AVOID THE EPIC REFACTOR
                              (IF POSSIBLE)




Saturday, September 4, 2010
what do we mean when
                              we use the term “refactor”




Saturday, September 4, 2010
TRADITIONAL DEFINITION

                          To refactor code is to change it’s implementation
                                    while maintaining it’s behavior.

                                - via Martin Fowler, Kent Beck et. al




Saturday, September 4, 2010
in web apps this means that the behavior
                           for the end user remains unchanged




Saturday, September 4, 2010
let’s look at some code




Saturday, September 4, 2010
DEPRECATE ACTION




Saturday, September 4, 2010
MAJOR VIOLATIONS

    • Zero            tests

    • Performance                  bottlenecks

         • main               impetus for touching this code

    • Phantom                   calling code

         • this        is why we need to deprecate



Saturday, September 4, 2010
Saturday, September 4, 2010
FIRST STEP:
                              READ CODE



Saturday, September 4, 2010
Before: /patients


 def index
   @patients = Patient.search(params[:search], params[:page])

   respond_to do |format|
     format.html { render :layout => 'application' }
     format.json { render :json => @patients.to_json }
   end
 end




Saturday, September 4, 2010
Before: /patients


 def index
   @patients = Patient.search(params[:search], params[:page])

   respond_to do |format|
     format.html { render :layout => 'application' }
     format.json { render :json => @patients.to_json }
   end
 end


                  This method is crazy. Crazy slow, that is.


Saturday, September 4, 2010
def self.search(search, page)
    includes = {}
    unless search.nil?
      if search.index('@')
        conditions = ['(contacts.email like ?) and contacts.ispatient = ?', "%#{search}%", true]
        includes = [:contact]
      elsif search.match(/^[0-9]+//)
        d = Date.parse( search, true )
        if d.year > Date.today.year
           d = Date.civil( d.year - 100, d.month, d.day )
        end
        conditions = ['(patients.birth_date = ? )', d]
      elsif search.match(/^[0-9]+/)
        conditions = ['(patients.ssn like ? or phones.number like ?) and contacts.ispatient
= ?', "%#{search}%", "%#{search}%", true]
        includes = {:contact => [:phones]}
      else
        conditions = ['(patients.last_name like ? or patients.first_name like ?)', "%#{search}
%", "%#{search}%"]
      end
    end

     paginate :per_page => 15, :page => page,
            :include => includes,
            :conditions => conditions,
            :order => 'patients.last_name, patients.first_name'
   end


Saturday, September 4, 2010
def self.search(search, page)
    includes = {}
                                           very hard to test
    unless search.nil?
      if search.index('@')
        conditions = ['(contacts.email like ?) and contacts.ispatient = ?', "%#{search}%", true]
        includes = [:contact]
      elsif search.match(/^[0-9]+//)
        d = Date.parse( search, true )
        if d.year > Date.today.year
           d = Date.civil( d.year - 100, d.month, d.day )
        end
        conditions = ['(patients.birth_date = ? )', d]
      elsif search.match(/^[0-9]+/)
        conditions = ['(patients.ssn like ? or phones.number like ?) and contacts.ispatient
= ?', "%#{search}%", "%#{search}%", true]
        includes = {:contact => [:phones]}
      else
        conditions = ['(patients.last_name like ? or patients.first_name like ?)', "%#{search}
%", "%#{search}%"]
      end
    end

     paginate :per_page => 15, :page => page,
            :include => includes,
            :conditions => conditions,
            :order => 'patients.last_name, patients.first_name'
   end


Saturday, September 4, 2010
def self.search(search, page)
    includes = {}
    unless search.nil?            could not figure out the bottleneck
      if search.index('@')
        conditions = ['(contacts.email like ?) and contacts.ispatient = ?', "%#{search}%", true]
        includes = [:contact]
      elsif search.match(/^[0-9]+//)
        d = Date.parse( search, true )
        if d.year > Date.today.year
           d = Date.civil( d.year - 100, d.month, d.day )
        end
        conditions = ['(patients.birth_date = ? )', d]
      elsif search.match(/^[0-9]+/)
        conditions = ['(patients.ssn like ? or phones.number like ?) and contacts.ispatient
= ?', "%#{search}%", "%#{search}%", true]
        includes = {:contact => [:phones]}
      else
        conditions = ['(patients.last_name like ? or patients.first_name like ?)', "%#{search}
%", "%#{search}%"]
      end
    end

     paginate :per_page => 15, :page => page,
            :include => includes,
            :conditions => conditions,
            :order => 'patients.last_name, patients.first_name'
   end


Saturday, September 4, 2010
def self.search(search, page)
    includes = {}
    unless search.nil?
      if search.index('@')
        conditions = ['(contacts.email like ?) and contacts.ispatient = ?', "%#{search}%", true]
        includes = [:contact]
      elsif search.match(/^[0-9]+//)
        d = Date.parse( search, true )
        if d.year > Date.today.year
           d = Date.civil( d.year - 100, d.month, d.day )
        end
        conditions = ['(patients.birth_date = ? )', d]
      elsif search.match(/^[0-9]+/)
        conditions = ['(patients.ssn like ? or phones.number like ?) and contacts.ispatient
= ?', "%#{search}%", "%#{search}%", true]
        includes = {:contact => [:phones]}
      else
        conditions = ['(patients.last_name like ? or patients.first_name like ?)', "%#{search}
%", "%#{search}%"]
      end
    end
                                                good candidate for extraction
     paginate :per_page => 15, :page => page,
            :include => includes,
            :conditions => conditions,
            :order => 'patients.last_name, patients.first_name'
   end


Saturday, September 4, 2010
a slight improvement
  def self.search(search, page)

    includes = {}
    unless search.nil?
      # i.e. are we searching by email
      if search.index('@')
        conditions = ['(contacts.email like ?) and contacts.ispatient = ?', "%#{search}%", true]
        includes = [:contact]
      elsif search.match(/^[0-9]+//)
        d = Date.parse( search, true )
        if d.year > Date.today.year
           d = Date.civil( d.year - 100, d.month, d.day )
        end
        conditions = ['(patients.birth_date = ? )', d]
      elsif search.match(/^[0-9]+/)
        conditions = ['(patients.ssn like ? or phones.number like ?) and contacts.ispatient = ?', "%#{search}%", "%#{search}
%", true]
        includes = {:contact => [:phones]}
      else
        conditions = ['(patients.last_name like ? or patients.first_name like ?)', "%#{search}%", "%#{search}%"]
      end
    end

    all_paginated(includes, conditions, page)
  end

  def self.all_paginated(includes, conditions, page)
    includes = { :contact => [:primary_phone] } if includes.empty?
    paginate(:per_page   => 15,
             :page       => page,
             :include    => includes,
             :conditions => conditions,
             :order      => 'patients.last_name, patients.first_name')
  end




Saturday, September 4, 2010
so why not just fix the whole thing?




Saturday, September 4, 2010
crazy phantom javascript code




Saturday, September 4, 2010
We want to alter
                       some behavior here     Calling Code

                                                 index.erb
                 PatientsControllerV2#index
                  PatientsController#index                        Known calls
                                                  show.erb



                                              phantom ajax call   Unknown calls




Saturday, September 4, 2010
We want to alter
                       some behavior here     Calling Code

                                                 index.erb
                 PatientsControllerV2#index                       Known calls
                                                  show.erb

                   PatientsController#index   phantom ajax call   Unknown calls




Saturday, September 4, 2010
After: /patients
   class PatientsController < ApplicationController
     before_filter :deprecate_action, :only => [:index]

       def index
         @patients = Patient.search(params[:search], params[:page])

         respond_to do |format|
           # ...
         end
       end

     private
       def deprecate_action
         notify_hoptoad(:error_message => "DEPRECATION WARNING!: /
   patients/index invoked")
       end
   end



Saturday, September 4, 2010
After: /patients

   def deprecate_action
     notify_hoptoad(:error_message => "DEPRECATION WARNING!: /patients/
   index invoked")
   end

                              use hoptoad in production to notify us
                                   of hits to deprecated code




Saturday, September 4, 2010
After: /patients

   def deprecate_action
     notify_hoptoad(:error_message => "DEPRECATION WARNING!: /patients/
   index invoked")
   end

                              use hoptoad in production to notify us
                                   of hits to deprecated code
         CAREFUL! This can crush your app w/ lots of requests.
                  Consider pushing into a BG job.




Saturday, September 4, 2010
After: /v2/patients



  class V2::PatientsController < ApplicationController
    def index
      @patients = Patient.all_paginated([], [], params[:page])
    end
  end




Saturday, September 4, 2010
WINS

    • Massive                 performance improvement

    • Separation                of responsibilities




Saturday, September 4, 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010
Refactoring in Practice - Ruby Hoedown 2010

More Related Content

Recently uploaded

Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfhans926745
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 

Recently uploaded (20)

Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 

Featured

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by HubspotMarius Sescu
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTExpeed Software
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsPixeldarts
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthThinkNow
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 

Featured (20)

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPT
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 

Refactoring in Practice - Ruby Hoedown 2010

  • 1. REFACTORING IN PRACTICE Saturday, September 4, 2010
  • 2. WHO IS TEH ME? Alex Sharp Lead Developer at OptimisDev { :tweets_as => '@ajsharp' :blogs_at => 'alexjsharp.com' :ships_at => 'github.com/ajsharp' } Saturday, September 4, 2010
  • 3. _WHY THIS TALK? Saturday, September 4, 2010
  • 4. RAILS IS GROWING UP Saturday, September 4, 2010
  • 5. RAILS IS GROWING UP MATURING Saturday, September 4, 2010
  • 6. IT’S NOT ALL GREEN FIELDS AND “SOFT LAUNCHES” Saturday, September 4, 2010
  • 7. APPS MATURE TOO Saturday, September 4, 2010
  • 8. so what is this talk about? Saturday, September 4, 2010
  • 9. large apps are a completely different beast than small apps Saturday, September 4, 2010
  • 11. tight code coupling across domain concepts Saturday, September 4, 2010
  • 12. these apps become harder to maintain as size increases Saturday, September 4, 2010
  • 13. tight domain coupling exposes itself as a symptom of application size Saturday, September 4, 2010
  • 14. this talk is about working with large apps Saturday, September 4, 2010
  • 15. it’s about staying on the straight and narrow Saturday, September 4, 2010
  • 16. it’s about fixing bad code. Saturday, September 4, 2010
  • 17. it’s about responsibly fixing bad code. Saturday, September 4, 2010
  • 18. it’s about responsibly fixing bad and improving code. Saturday, September 4, 2010
  • 19. RULES OF REFACTORING Saturday, September 4, 2010
  • 20. RULE #1 TESTS ARE CRUCIAL Saturday, September 4, 2010
  • 21. we’re out of our element without tests Saturday, September 4, 2010
  • 22. red, green, refactor doesn’t work without the red Saturday, September 4, 2010
  • 24. RULE #2 AVOID RABBIT HOLES Saturday, September 4, 2010
  • 25. RULE #3: TAKE SMALL WINS Saturday, September 4, 2010
  • 26. I.E. AVOID THE EPIC REFACTOR (IF POSSIBLE) Saturday, September 4, 2010
  • 27. what do we mean when we use the term “refactor” Saturday, September 4, 2010
  • 28. TRADITIONAL DEFINITION To refactor code is to change it’s implementation while maintaining it’s behavior. - via Martin Fowler, Kent Beck et. al Saturday, September 4, 2010
  • 29. in web apps this means that the behavior for the end user remains unchanged Saturday, September 4, 2010
  • 30. let’s look at some code Saturday, September 4, 2010
  • 32. MAJOR VIOLATIONS • Zero tests • Performance bottlenecks • main impetus for touching this code • Phantom calling code • this is why we need to deprecate Saturday, September 4, 2010
  • 34. FIRST STEP: READ CODE Saturday, September 4, 2010
  • 35. Before: /patients def index @patients = Patient.search(params[:search], params[:page]) respond_to do |format| format.html { render :layout => 'application' } format.json { render :json => @patients.to_json } end end Saturday, September 4, 2010
  • 36. Before: /patients def index @patients = Patient.search(params[:search], params[:page]) respond_to do |format| format.html { render :layout => 'application' } format.json { render :json => @patients.to_json } end end This method is crazy. Crazy slow, that is. Saturday, September 4, 2010
  • 37. def self.search(search, page) includes = {} unless search.nil? if search.index('@') conditions = ['(contacts.email like ?) and contacts.ispatient = ?', "%#{search}%", true] includes = [:contact] elsif search.match(/^[0-9]+//) d = Date.parse( search, true ) if d.year > Date.today.year d = Date.civil( d.year - 100, d.month, d.day ) end conditions = ['(patients.birth_date = ? )', d] elsif search.match(/^[0-9]+/) conditions = ['(patients.ssn like ? or phones.number like ?) and contacts.ispatient = ?', "%#{search}%", "%#{search}%", true] includes = {:contact => [:phones]} else conditions = ['(patients.last_name like ? or patients.first_name like ?)', "%#{search} %", "%#{search}%"] end end paginate :per_page => 15, :page => page, :include => includes, :conditions => conditions, :order => 'patients.last_name, patients.first_name' end Saturday, September 4, 2010
  • 38. def self.search(search, page) includes = {} very hard to test unless search.nil? if search.index('@') conditions = ['(contacts.email like ?) and contacts.ispatient = ?', "%#{search}%", true] includes = [:contact] elsif search.match(/^[0-9]+//) d = Date.parse( search, true ) if d.year > Date.today.year d = Date.civil( d.year - 100, d.month, d.day ) end conditions = ['(patients.birth_date = ? )', d] elsif search.match(/^[0-9]+/) conditions = ['(patients.ssn like ? or phones.number like ?) and contacts.ispatient = ?', "%#{search}%", "%#{search}%", true] includes = {:contact => [:phones]} else conditions = ['(patients.last_name like ? or patients.first_name like ?)', "%#{search} %", "%#{search}%"] end end paginate :per_page => 15, :page => page, :include => includes, :conditions => conditions, :order => 'patients.last_name, patients.first_name' end Saturday, September 4, 2010
  • 39. def self.search(search, page) includes = {} unless search.nil? could not figure out the bottleneck if search.index('@') conditions = ['(contacts.email like ?) and contacts.ispatient = ?', "%#{search}%", true] includes = [:contact] elsif search.match(/^[0-9]+//) d = Date.parse( search, true ) if d.year > Date.today.year d = Date.civil( d.year - 100, d.month, d.day ) end conditions = ['(patients.birth_date = ? )', d] elsif search.match(/^[0-9]+/) conditions = ['(patients.ssn like ? or phones.number like ?) and contacts.ispatient = ?', "%#{search}%", "%#{search}%", true] includes = {:contact => [:phones]} else conditions = ['(patients.last_name like ? or patients.first_name like ?)', "%#{search} %", "%#{search}%"] end end paginate :per_page => 15, :page => page, :include => includes, :conditions => conditions, :order => 'patients.last_name, patients.first_name' end Saturday, September 4, 2010
  • 40. def self.search(search, page) includes = {} unless search.nil? if search.index('@') conditions = ['(contacts.email like ?) and contacts.ispatient = ?', "%#{search}%", true] includes = [:contact] elsif search.match(/^[0-9]+//) d = Date.parse( search, true ) if d.year > Date.today.year d = Date.civil( d.year - 100, d.month, d.day ) end conditions = ['(patients.birth_date = ? )', d] elsif search.match(/^[0-9]+/) conditions = ['(patients.ssn like ? or phones.number like ?) and contacts.ispatient = ?', "%#{search}%", "%#{search}%", true] includes = {:contact => [:phones]} else conditions = ['(patients.last_name like ? or patients.first_name like ?)', "%#{search} %", "%#{search}%"] end end good candidate for extraction paginate :per_page => 15, :page => page, :include => includes, :conditions => conditions, :order => 'patients.last_name, patients.first_name' end Saturday, September 4, 2010
  • 41. a slight improvement def self.search(search, page) includes = {} unless search.nil? # i.e. are we searching by email if search.index('@') conditions = ['(contacts.email like ?) and contacts.ispatient = ?', "%#{search}%", true] includes = [:contact] elsif search.match(/^[0-9]+//) d = Date.parse( search, true ) if d.year > Date.today.year d = Date.civil( d.year - 100, d.month, d.day ) end conditions = ['(patients.birth_date = ? )', d] elsif search.match(/^[0-9]+/) conditions = ['(patients.ssn like ? or phones.number like ?) and contacts.ispatient = ?', "%#{search}%", "%#{search} %", true] includes = {:contact => [:phones]} else conditions = ['(patients.last_name like ? or patients.first_name like ?)', "%#{search}%", "%#{search}%"] end end all_paginated(includes, conditions, page) end def self.all_paginated(includes, conditions, page) includes = { :contact => [:primary_phone] } if includes.empty? paginate(:per_page => 15, :page => page, :include => includes, :conditions => conditions, :order => 'patients.last_name, patients.first_name') end Saturday, September 4, 2010
  • 42. so why not just fix the whole thing? Saturday, September 4, 2010
  • 43. crazy phantom javascript code Saturday, September 4, 2010
  • 44. We want to alter some behavior here Calling Code index.erb PatientsControllerV2#index PatientsController#index Known calls show.erb phantom ajax call Unknown calls Saturday, September 4, 2010
  • 45. We want to alter some behavior here Calling Code index.erb PatientsControllerV2#index Known calls show.erb PatientsController#index phantom ajax call Unknown calls Saturday, September 4, 2010
  • 46. After: /patients class PatientsController < ApplicationController before_filter :deprecate_action, :only => [:index] def index @patients = Patient.search(params[:search], params[:page]) respond_to do |format| # ... end end private def deprecate_action notify_hoptoad(:error_message => "DEPRECATION WARNING!: / patients/index invoked") end end Saturday, September 4, 2010
  • 47. After: /patients def deprecate_action notify_hoptoad(:error_message => "DEPRECATION WARNING!: /patients/ index invoked") end use hoptoad in production to notify us of hits to deprecated code Saturday, September 4, 2010
  • 48. After: /patients def deprecate_action notify_hoptoad(:error_message => "DEPRECATION WARNING!: /patients/ index invoked") end use hoptoad in production to notify us of hits to deprecated code CAREFUL! This can crush your app w/ lots of requests. Consider pushing into a BG job. Saturday, September 4, 2010
  • 49. After: /v2/patients class V2::PatientsController < ApplicationController def index @patients = Patient.all_paginated([], [], params[:page]) end end Saturday, September 4, 2010
  • 50. WINS • Massive performance improvement • Separation of responsibilities Saturday, September 4, 2010