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

Ruby Patterns from GitHub's Codebase

Ruby Patterns from GitHub's Codebase

We've had some pretty terrible ideas at GitHub. But they're not all bad, honest! Let's talk about some of the good Ruby-themed patterns we use.

Zach Holman

February 29, 2012
Tweet

More Decks by Zach Holman

Other Decks in Programming

Transcript

  1. your company is going to have TONS OF SUCCESS which

    means you’ll have to hire TONS OF PEOPLE
  2. Most of our Ruby projects have a file called in

    the directory. bootstrap script/ Easily jump into a project and start contributing.
  3. { static page compilation language compilation db seeding dependency checks

    bundler db creation db migration is mysql installed? (here’s how to install it) is redis running? (here’s how to run it)
  4. { static page compilation language compilation db seeding dependency checks

    bundler db creation db migration bundle install \ --binstubs \ --local \ --path=vendor/gems \ --without=production
  5. { static page compilation language compilation db seeding dependency checks

    bundler db creation db migration rake db:create
  6. { static page compilation language compilation db seeding dependency checks

    bundler db creation db migration rake db:migrate
  7. { static page compilation language compilation db seeding dependency checks

    bundler db creation db migration script/replicate-repo (see rtomayko/replicate)
  8. { static page compilation language compilation db seeding dependency checks

    bundler db creation db migration python, c, erlang...
  9. should be fast, straightforward, and require no knowledge of the

    underlying language or app setup script/bootstrap
  10. You can also run during any process that loads the

    environment, like script/bootstrap script/server
  11. Our CI server only needs to ever run . script/cibuild

    We add to most projects. Lets us keep test config in the repository. script/cibuild
  12. - GitHub is a Rails 2.3(ish) app PROBLEM: - Upgrading

    to Rails 3.x sucks - Biggest concern is escaping-by-default - We wanted incremental rollout
  13. Sinatra is (naturally) great for an API. get “/” do

    “an web app” end translates easily to GET / HTTP/1.1
  14. GITHUB API V3 ~30 Sinatra apps located in app/api in

    our Rails app mounted at api.github.com/ (version in headers) routed in rack with path regex
  15. USE HELPERS, SIMPLIFY ROUTES # List a user's followers. get

    "/users/:user/followers" do control_access :public_read deliver find_user.followers.paginate(pagination) end
  16. USE HELPERS, SIMPLIFY ROUTES # List a user's followers. get

    "/users/:user/followers" do control_access :public_read deliver find_user.followers.paginate(pagination) end control_access verifies user has permission for the request pulls user data from currently-authenticated user
  17. USE HELPERS, SIMPLIFY ROUTES # List a user's followers. get

    "/users/:user/followers" do control_access :public_read deliver find_user.followers.paginate(pagination) end find_user auto-populated based on params[:user] manages error handling for nonexistent users
  18. USE HELPERS, SIMPLIFY ROUTES # List a user's followers. get

    "/users/:user/followers" do control_access :public_read deliver find_user.followers.paginate(pagination) end pagination auto-populated based on per_page & page params
  19. USE HELPERS, SIMPLIFY ROUTES # List a user's followers. get

    "/users/:user/followers" do control_access :public_read deliver find_user.followers.paginate(pagination) end deliver handles nil objects (404) appends OAuth scope & rate limiting headers encodes as JSON and sets Content-Type handles JSONP callbacks
  20. USE HELPERS, SIMPLIFY ROUTES # List a user's followers. get

    "/users/:user/followers" do control_access :public_read deliver find_user.followers.paginate(pagination) end
  21. USE HELPERS, SIMPLIFY ROUTES Extract all these little methods out

    Your API becomes extremely Your API becomes extremely readable testable
  22. Single responsibility principle and all that jazz. But it’s harder

    to do! LET ME JUST THROW THIS IN THE MODEL!!!!!!111
  23. As you grow, it’s harder to mentally grasp your entire

    app. Splitting into well- documented chunks can really help.
  24. ...particularly in Ruby, because following this sucks: def mailing_address full_name

    + “\n” street_address_1 + “\n” + street_address_2 + “\n” + “#{city}, #{state} #{zip}” end def street_address_1 house_with_street.formatted end def house_with_street StreetAddress.new(data) end
  25. # Cures cancer. Beware of race conditions or else you’ll

    turn into a # newt or something. # # options - A Hash consisting of: # age - The Integer age of the patient. # money - The Float amount of money in the patient’s account # valuable - A Boolean value of whether the patient is valuable # to society or not. # rollback - A Boolean of whether we should troll the patient and give # cancer again once they’re cured. # # This returns a Patient record. Raises UncurableError if the patient can’t # be cured. def cure_cancer (options, rollback) # boring implementation details, you can figure it out yourself end
  26. # Cures cancer. Beware of race conditions or else you’ll

    turn into a # newt or something. # # options - A Hash consisting of: # age - The Integer age of the patient. # money - The Float amount of money in the patient’s account # valuable - A Boolean value of whether the patient is valuable # to society or not. # rollback - A Boolean of whether we should troll the patient and give # cancer again once they’re cured. # # This returns a Patient record. Raises UncurableError if the patient can’t # be cured. def cure_cancer (options, rollback) # boring implementation details, you can figure it out yourself end
  27. # Cures cancer. Beware of race conditions or else you’ll

    turn into a # newt or something. # # options - A Hash consisting of: # age - The Integer age of the patient. # money - The Float amount of money in the patient’s account # valuable - A Boolean value of whether the patient is valuable # to society or not. # rollback - A Boolean of whether we should troll the patient and give # cancer again once they’re cured. # # This returns a Patient record. Raises UncurableError if the patient can’t # be cured. def cure_cancer (options, rollback) # boring implementation details, you can figure it out yourself end
  28. # Cures cancer. Beware of race conditions or else you’ll

    turn into a # newt or something. # # options - A Hash consisting of: # age - The Integer age of the patient. # money - The Float amount of money in the patient’s account # valuable - A Boolean value of whether the patient is valuable # to society or not. # rollback - A Boolean of whether we should troll the patient and give # cancer again once they’re cured. # # This returns a Patient record. Raises UncurableError if the patient can’t # be cured. def cure_cancer (options, rollback) # boring implementation details, you can figure it out yourself end
  29. # Cures cancer. Beware of race conditions or else you’ll

    turn into a # newt or something. # # options - A Hash consisting of: # age - The Integer age of the patient. # money - The Float amount of money in the patient’s account. # valuable - A Boolean value of whether the patient is valuable # to society or not. # rollback - A Boolean of whether we should troll the patient and give # cancer again once they’re cured. # # This returns a Patient record. Raises UncurableError if the patient can’t # be cured. def cure_cancer (options, rollback) # boring implementation details, you can figure it out yourself end
  30. # Cures cancer. Beware of race conditions or else you’ll

    turn into a # newt or something. # # options - A Hash consisting of: # age - The Integer age of the patient. # money - The Float amount of money in the patient’s account. # valuable - A Boolean value of whether the patient is valuable # to society or not. # rollback - A Boolean of whether we should troll the patient and give # cancer again once they’re cured. # # This returns a Patient record. Raises UncurableError if the patient can’t # be cured. def cure_cancer (options, rollback) # boring implementation details, you can figure it out yourself end
  31. # Cures cancer. Beware of race conditions or else you’ll

    turn into a # newt or something. # # options - A Hash consisting of: # age - The Integer age of the patient. # money - The Float amount of money in the patient’s account # valuable - A Boolean value of whether the patient is valuable # to society or not. # rollback - A Boolean of whether we should troll the patient and give # cancer again once they’re cured. # # This returns a Patient record. Raises UncurableError if the patient can’t # be cured. def cure_cancer (options, rollback) # boring implementation details, you can figure it out yourself end
  32. DON’T WORRY, IT’S NOT VERBOSE: Most of your TomDoc will

    only be two lines: # EXPLANATION # # RETURNS Complicated methods (like the previous example) will require more detailed TomDoc.