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

Building Gems that Don't Suck

avdi
May 23, 2012

Building Gems that Don't Suck

A Lunch & Learn talk I gave at Hashrocket going over some tips for architecting and packaging quality Ruby libraries

avdi

May 23, 2012
Tweet

More Decks by avdi

Other Decks in Programming

Transcript

  1. Hashrocket Lunch & Learn #2
    Avdi Grimm
    2012-04-19

    View Slide

  2. Building Libraries that Don’t Suck
    Distribution
    Coding
    API Design
    Error API Design

    View Slide

  3. Distribution

    View Slide

  4. Limit dependencies
    Yes, ActiveSupport is the bee’s knees
    . . . but it may break someone’s codebase

    View Slide

  5. Semantic Versioning
    Patch versions: fix defects.
    Minor versions: add features; never change existing
    (correct) behavior.
    Major version: break backwards compatibility
    Make the tiddly-waka (~>) count for something!

    View Slide

  6. Don’t name it after a pattern
    That’s just confusing.

    View Slide

  7. Coding

    View Slide

  8. No monkey patching!
    (Unless that’s the purpose of the library)

    View Slide

  9. No classes named “Base”
    Don’t make grepping any harder than it needs to be.
    Identify the concept, and name it.
    (ActiveRecord::Record, anyone?)
    Exceptions:
    Libraries involving baseball
    Libraries about base jumping
    Libraries concerned with Swedish 90s pop group Ace
    of Base

    View Slide

  10. Don’t eat client exceptions
    module SWS
    def with_sandwich
    # ...
    yield sandwich
    rescue => e # OM NOM NOM EXCEPTIONS!
    nil
    end
    end

    View Slide

  11. Don’t eat client exceptions
    # Meanwhile, in client code
    SWS.with_sandwich do
    # ...
    some_method_that_raises_a_runtime_error
    # ...
    end

    View Slide

  12. API design

    View Slide

  13. Block-style configuration
    SWS.configure do |config|
    conf.selleck_shirtless = true
    conf.sandwich_type = :baloney
    conf.waterfall_height *= 2
    end

    View Slide

  14. Block-style configuration
    Code-as-config for ultimate flexibility
    Discoverable: default values can be queried.
    A convenient point to add validations
    Can be called more than once

    View Slide

  15. Top-level Facade
    # Instead of:
    SWS::Sandwich.new(...)
    # Try:
    SWS.new_sandwich(...)

    View Slide

  16. Top-level Facade
    Top-level API acts as a reference
    Doesn’t tie client code to the structure of your
    library
    Gives you more leeway to move things around
    internally
    Or proliferate classes

    View Slide

  17. Error API

    View Slide

  18. Exception Classes
    Logic Error: Library has a defect.
    Client Error: Client mis-used the library.
    Transient Failure: Some external dependency isn’t
    working right now.

    View Slide

  19. Exception Tagging with Modules
    module SWS::Error; end
    # ...
    def upload_selleck_to_waterfall
    # ...
    rescue HTTPError => e
    e.extend(SWS::Error)
    raise
    end

    View Slide

  20. Exception Tagging with Modules
    # Client code interested in HTTP errors
    def foo
    upload_selleck_to_waterfall
    rescue HTTPError => e
    log_http_error(e)
    end

    View Slide

  21. Exception Tagging with Modules
    # Client code concerned with SWS errors
    def foo
    upload_selleck_to_waterfall
    rescue SWS::Error
    # ignore SWS errors
    end

    View Slide

  22. No-raise API
    request.on_complete do |response|
    if response.success?
    # hell yeah
    elsif response.timed_out?
    # aw hell no
    log( "got a time out" )
    elsif response.code == 0
    # Could not get an http response
    log(response.curl_error_message)
    else
    # Received a non-successful http response.
    log( "request failed: " + response.code.to_s)
    end
    end

    View Slide

  23. Tiered Architecture
    For wrapping services / libraries
    Layer 1: Thinnest possible wrapper
    Typically procedural
    Stateless
    Minimal “magic”
    Layer 2: Object model
    Stateful

    View Slide

  24. Tiered Architecture Evolution
    Layer 1: Thinnest possible wrapper
    Layer 2: Glue
    Layer 3: Object model

    View Slide

  25. Your Turn

    View Slide