API Design Matters

31254903db793bf6f84bbd607fe092fd?s=47 Anthony Eden
September 27, 2011

API Design Matters

The effects of API design will likely live with your project for a long time, often beyond your tenure with the project. Yet good API design is very rarely discussed and often leads developers to the conclusion that good APIs are something that "we know when we see them."

This talk will attempt to layout a set of fundamentals for good API design so that we can begin to really understand the difference between well-designed APIs and those that are mediocre. It will also explain about various trade-offs that are made when designing APIs and some of the pros and cons that come with each trade-off. Finally we'll take a look at some good APIs and bad APIs in Ruby.

31254903db793bf6f84bbd607fe092fd?s=128

Anthony Eden

September 27, 2011
Tweet

Transcript

  1. API Design Matters Anthony Eden Monday, September 26, 11

  2. Why? Monday, September 26, 11 How many of you are

    write software for a living? How many of you design APIs for a living? If you write software, you design APIs.
  3. APIs are the product Monday, September 26, 11 Used both

    internally and externally.
  4. APIs outlive implementations Monday, September 26, 11 Clients expect APIs

    to be stable even as implementations change.
  5. APIs lead everything else Monday, September 26, 11 API helps

    guide the implementation, both the implementation of the API as well as the implementation of client code.
  6. Principles Monday, September 26, 11

  7. Easy to learn Monday, September 26, 11 Principle of least

    astonishment. Think about naming. Lead by example.
  8. Produces readable code Monday, September 26, 11 From the client

    perspective, code that uses an API must be readable. A good API will encourage good client code.
  9. Easy to extend Monday, September 26, 11 APIs grow with

    new requirements and should be designed with this in mind. APIs should also be easy to split into smaller APIs.
  10. Hard to misuse Monday, September 26, 11 Makes it easier

    to write correct code. Avoids relying on order or side effects.
  11. Sufficiently powerful Monday, September 26, 11 As small as possible

    but never smaller. Only implements the functionality required to get the job done. Adding is easy, removing is much more difficult because dependencies are broken.
  12. Principles v2* * because everyone loves the letter ‘C’ Monday,

    September 26, 11
  13. Consistent Monday, September 26, 11 Consistent with existing APIs Consistent

    naming throughout “Economy of concepts” - introduce new concepts with frugality
  14. Clear Monday, September 26, 11 Clarity of code. Clarity of

    intent.
  15. Convenient Monday, September 26, 11 Easier to use the API

    than to implement an alternative API. Eschews complexity for usability.
  16. Concise Monday, September 26, 11 Brief but comprehensive.

  17. Complete Monday, September 26, 11 Does the job, no more,

    no less
  18. Examples Monday, September 26, 11

  19. Net::HTTP Monday, September 26, 11 Consistent, clear, convenient, concise, complete?

  20. Net::HTTP.get_print 'example.com', '/' Net::HTTP.get_print URI.parse('http://example.com/') Net::HTTP.get ‘example.com’, ‘/’ Net::HTTP.get URI.parse(‘http://example.com/’)

    Monday, September 26, 11 The difference between get_print is one returns a string and one prints to stdout.
  21. res = Net::HTTP.start ‘example.com’ do |http| http.get ‘/’ end get(path,

    initheader = {}, dest = nil) Monday, September 26, 11 initheader is a Hash of request headers “dest argument is obsolete. It still works but you must not use it.” Oh, and by the way...
  22. “If called with a block, yields each fragment of the

    entity body in turn as a string as it is read from the socket. Note that in this case, the returned response object will not contain a (meaningful) body.” Monday, September 26, 11 Also...
  23. In version 1.1, this method might raise an exception for

    3xx (redirect). In this case you can get a HTTPResponse object by “anException.response“. Monday, September 26, 11 except...
  24. In version 1.2, this method never raises exception. Monday, September

    26, 11
  25. Monday, September 26, 11 * get_print (side effects, unnecessary methods,

    does more than it should) * .start vs. #start (unnecessary methods) * post vs. post2 * D and Proxy (methods using class-naming style) * version_1_1 (side effects, hard to extend) * newobj (unecessary) * exceptions for flow control (raise exceptions for 3xx redirects) * SSL methods (does more than it should) * proxy methods (does more than it should)
  26. Typheous Monday, September 26, 11 Consistent, clear, convenient, concise, complete?

  27. request = Typhoeus::Request.new("http://example.com") hydra = Typhoeus::Hydra.new hydra.queue(request) hydra.run response =

    request.response response.body Monday, September 26, 11 or if you need shortcuts...
  28. response = Typhoeus::Request.get("http://example.com") response.body Monday, September 26, 11

  29. response = Typhoeus::Request.post("http://example.com", { :params => {:person => {:name =>

    “John”}} }) response.body Monday, September 26, 11
  30. Faraday Monday, September 26, 11 Consistent, clear, convenient, concise, complete?

  31. response = Faraday.get("http://example.com") response.body Monday, September 26, 11

  32. conn = Faraday.new(:url => 'http://sushi.com') do |builder| builder.use Faraday::Request::JSON builder.use

    Faraday::Response::Logger end response = conn.get '/nigiri/sake.json', ‘X-Example’ => ‘foo’ response.body Monday, September 26, 11
  33. openuri Monday, September 26, 11 The best API is no

    API open(url) becomes like opening a file
  34. require ‘open-uri’ open("http://example.com/") do |f| f.each_line { |line| p line

    } end Monday, September 26, 11
  35. Monday, September 26, 11 Consistent, clear, convenient, concise, complete.

  36. Techniques Monday, September 26, 11

  37. Ask & Think Monday, September 26, 11 Talk to those

    that need it Know what is required Be the client
  38. Client first Monday, September 26, 11 Clear and concise requirements

    Readme driven design Sample client code Tests
  39. Implementation second Monday, September 26, 11 Favor a clear and

    concise API with a difficult implementation over allowing the implementation to bleed into the API. This is why we love Ruby!
  40. Address your audience Monday, September 26, 11 Define APIs at

    the appropriate level for the type of consumer Domain experts will expect appropriate jargon Non-domain experts will want to avoid being baffled
  41. Choose good defaults Monday, September 26, 11 But make sure

    to document them
  42. Separate API and SPI Monday, September 26, 11 API is

    the public consumer interface SPI is the public provider interface (and is used for extension)
  43. Consistent, clear, convenient, concise, complete? Monday, September 26, 11 Ask

    yourself
  44. The best API is no API Monday, September 26, 11

    Jasmine Blanchette, The Little Manual of API Design
  45. Things to think about Monday, September 26, 11 If you

    are a software developer, then you are an API designer. Design with purpose and intent.
  46. What are other examples of good APIs to learn from?

    Monday, September 26, 11
  47. What can we learn from APIs in functional languages? Monday,

    September 26, 11
  48. How do you refactor APIs to make them better? Monday,

    September 26, 11 Keep in mind the challenges of existing API users.
  49. http://www.flickr.com/photos/heartart/79018288/ http://www.flickr.com/photos/larou/3505324393/ http://www.flickr.com/photos/nuagedenuit/155699074/ http://www.flickr.com/photos/fishbulb1022/4268407490/ http://www.flickr.com/photos/larachris/182959784/ http://www.flickr.com/photos/bartzoni/4201610982/ http://www.flickr.com/photos/stuckincustoms/3932778019/ http://www.flickr.com/photos/stathis1980/4285295041/ Monday, September

    26, 11
  50. How to Design a Good API and Why it Matters

    Joshua Bloch The Little Manual of API Design Jasmin Blanchette Monday, September 26, 11