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

Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontologyjohnbeverley2021
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
Working together SRE & Platform Engineering
Working together SRE & Platform EngineeringWorking together SRE & Platform Engineering
Working together SRE & Platform EngineeringMarcus Vechiato
 
Navigating Identity and Access Management in the Modern Enterprise
Navigating Identity and Access Management in the Modern EnterpriseNavigating Identity and Access Management in the Modern Enterprise
Navigating Identity and Access Management in the Modern EnterpriseWSO2
 
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on ThanabotsContinuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on ThanabotsLeah Henrickson
 
Portal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russePortal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russe中 央社
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Zilliz
 
Event-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream ProcessingEvent-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream ProcessingScyllaDB
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityWSO2
 
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...WSO2
 
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)Samir Dash
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2
 
The Zero-ETL Approach: Enhancing Data Agility and Insight
The Zero-ETL Approach: Enhancing Data Agility and InsightThe Zero-ETL Approach: Enhancing Data Agility and Insight
The Zero-ETL Approach: Enhancing Data Agility and InsightSafe Software
 
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...FIDO Alliance
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxFIDO Alliance
 
WebRTC and SIP not just audio and video @ OpenSIPS 2024
WebRTC and SIP not just audio and video @ OpenSIPS 2024WebRTC and SIP not just audio and video @ OpenSIPS 2024
WebRTC and SIP not just audio and video @ OpenSIPS 2024Lorenzo Miniero
 
Design and Development of a Provenance Capture Platform for Data Science
Design and Development of a Provenance Capture Platform for Data ScienceDesign and Development of a Provenance Capture Platform for Data Science
Design and Development of a Provenance Capture Platform for Data SciencePaolo Missier
 
JohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard37
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistandanishmna97
 
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...TrustArc
 

Recently uploaded (20)

Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Working together SRE & Platform Engineering
Working together SRE & Platform EngineeringWorking together SRE & Platform Engineering
Working together SRE & Platform Engineering
 
Navigating Identity and Access Management in the Modern Enterprise
Navigating Identity and Access Management in the Modern EnterpriseNavigating Identity and Access Management in the Modern Enterprise
Navigating Identity and Access Management in the Modern Enterprise
 
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on ThanabotsContinuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
 
Portal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russePortal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russe
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
Event-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream ProcessingEvent-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream Processing
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
 
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
The Zero-ETL Approach: Enhancing Data Agility and Insight
The Zero-ETL Approach: Enhancing Data Agility and InsightThe Zero-ETL Approach: Enhancing Data Agility and Insight
The Zero-ETL Approach: Enhancing Data Agility and Insight
 
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
 
WebRTC and SIP not just audio and video @ OpenSIPS 2024
WebRTC and SIP not just audio and video @ OpenSIPS 2024WebRTC and SIP not just audio and video @ OpenSIPS 2024
WebRTC and SIP not just audio and video @ OpenSIPS 2024
 
Design and Development of a Provenance Capture Platform for Data Science
Design and Development of a Provenance Capture Platform for Data ScienceDesign and Development of a Provenance Capture Platform for Data Science
Design and Development of a Provenance Capture Platform for Data Science
 
JohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptx
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
 

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