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

Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAndikSusilo4
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
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
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
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
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 

Recently uploaded (20)

Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & Application
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
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
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
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
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 

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