Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rules of Three

Rules of Three

Lightning talk at WindyCityRails 2012, Sept. 7 2012

David Demaree

September 07, 2012
Tweet

More Decks by David Demaree

Other Decks in Programming

Transcript

  1. We make Photoshop™.
    The web’s best fonts.
    I like pie.
    @ddemaree

    View full-size slide

  2. REFACTORING
    PREFACTORING
    VS

    View full-size slide

  3. Don’t
    Repeat
    Yourself
    Too much
    abstraction
    VS

    View full-size slide

  4. THE PROBLEM
    It’s really easy to
    convince yourself that
    today’s code will be more
    complex in the future,
    and design for that.

    View full-size slide

  5. THE PROBLEM
    It’s really easy to
    convince yourself that
    today’s code will be more
    complex in the future,
    and design for that.

    View full-size slide

  6. When is it time
    to refactor?

    View full-size slide

  7. When is it not time
    to refactor?

    View full-size slide

  8. Rules of thumb

    View full-size slide

  9. The Rule of Three
    “Code can be copied once, but that when the
    same code is used three times, it should be
    extracted into a new procedure.”
    http://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)
    1
    2
    3
    A
    A
    A
    A

    View full-size slide

  10. def foo
    # Does some stuff ...
    if @user.status == :active
    @user.status = :inactive
    @user.save!
    end
    end
    OK

    View full-size slide

  11. def foo
    # Does some stuff ...
    if @user.status == :active
    @user.status = :inactive
    @user.save!
    end
    end
    OK
    def bar
    # Does some other stuff ...
    if @user.status == :active
    @user.status = :inactive
    @user.save!
    end
    end
    ❓ STILL OK

    View full-size slide

  12. def foo
    # Does some stuff ...
    if @user.status == :active
    @user.status = :inactive
    @user.save!
    end
    end
    OK
    def bar
    # Does some other stuff ...
    if @user.status == :active
    @user.status = :inactive
    @user.save!
    end
    end
    ❓ STILL OK
    def baz
    # Does yet other stuff ...
    if @user.status == :active
    @user.status = :inactive
    @user.save!
    end
    end
    ⚠ JANKY

    View full-size slide

  13. def deactivate_user(user)
    if user.status == :active
    user.status = :inactive
    user.save!
    end
    end
    def foo
    # Does some stuff ...
    deactivate_user(@user)
    end
    def bar
    # Does some other stuff ...
    deactivate_user(@user)
    end
    def baz
    # Does yet other stuff ...
    deactivate_user(@user)
    end

    View full-size slide

  14. def deactivate_user(user)
    if user.status == :active
    user.status = :inactive
    user.save!
    end
    end
    def foo
    # Does some stuff ...
    deactivate_user(@user)
    end
    def bar
    # Does some other stuff ...
    deactivate_user(@user)
    end
    def baz
    # Does yet other stuff ...
    deactivate_user(@user)
    end
    This is better code
    BUT
    Resist the temptation to
    do this until you really
    have repeated yourself
    three times

    View full-size slide

  15. Three of a Kind
    Three or more related methods/symbols
    can be meaningfully grouped together

    View full-size slide

  16. class User < ActiveRecord::Base
    def adobe_profile
    AdobeId::Profile.new(self.adobe_profile_id)
    end
    def connected_to_adobe_profile?
    !self.adobe_profile_id.nil?
    end
    end

    View full-size slide

  17. class User < ActiveRecord::Base
    def adobe_profile
    AdobeId::Profile.new(self.adobe_profile_id)
    end
    def connected_to_adobe_profile?
    !self.adobe_profile_id.nil?
    end
    end

    def connect_to_adobe_profile(profile_obj)
    self.adobe_profile_id = profile_obj.id
    self.email_unique = false
    save
    end

    View full-size slide

  18. class User < ActiveRecord::Base
    def adobe_profile
    AdobeId::Profile.new(self.adobe_profile_id)
    end
    def connected_to_adobe_profile?
    !self.adobe_profile_id.nil?
    end
    end

    def connect_to_adobe_profile(profile_obj)
    self.adobe_profile_id = profile_obj.id
    self.email_unique = false
    save
    end

    def disconnect_adobe_profile
    self.adobe_profile_id = nil
    self.email_unique = true
    save
    end

    View full-size slide

  19. module UserAdobeProfile
    def adobe_profile
    AdobeId::Profile.new(self.adobe_profile_id)
    end
    def connected_to_adobe_profile?
    !self.adobe_profile_id.nil?
    end
    # Anything else pertaining to users'
    # Adobe profiles …
    end
    class User < ActiveRecord::Base
    include UserAdobeProfile
    end

    View full-size slide

  20. No Assumptions
    You don’t know what you know
    until you know it.

    View full-size slide

  21. I believe writing a truly reusable class is an order of
    magnitude harder than writing a single use class.
    Sometimes the right thing to do is resist the urge to
    write "general purpose" solutions.


    http://www.codinghorror.com/blog/2004/09/the-delusion-of-reuse.html
    JEFF ATWOOD:

    View full-size slide

  22. PREFACTORING

    It’s awesome.

    View full-size slide

  23. [email protected]
     @ddemaree
     log.demaree.me

    View full-size slide

  24. It will not surprise you to learn that
    WE ARE HIRING
    http://bit.ly/typekitrailsjob
    or just come talk to me

    View full-size slide