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. Limit dependencies Yes, ActiveSupport is the bee’s knees . .

    . but it may break someone’s codebase
  2. 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!
  3. 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
  4. Don’t eat client exceptions module SWS def with_sandwich # ...

    yield sandwich rescue => e # OM NOM NOM EXCEPTIONS! nil end end
  5. Don’t eat client exceptions # Meanwhile, in client code SWS.with_sandwich

    do # ... some_method_that_raises_a_runtime_error # ... end
  6. 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
  7. 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
  8. 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.
  9. Exception Tagging with Modules module SWS::Error; end # ... def

    upload_selleck_to_waterfall # ... rescue HTTPError => e e.extend(SWS::Error) raise end
  10. Exception Tagging with Modules # Client code interested in HTTP

    errors def foo upload_selleck_to_waterfall rescue HTTPError => e log_http_error(e) end
  11. Exception Tagging with Modules # Client code concerned with SWS

    errors def foo upload_selleck_to_waterfall rescue SWS::Error # ignore SWS errors end
  12. 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
  13. Tiered Architecture For wrapping services / libraries Layer 1: Thinnest

    possible wrapper Typically procedural Stateless Minimal “magic” Layer 2: Object model Stateful