Table of Contents
A well-written API can be a great asset to the organization that wrote it and to all that use it. Given the importance of good API design, surprisingly little has been written on the subject. In this talk (recorded at Javapolis), Java library designer Joshua Bloch teaches how to design good APIs, with many examples of what good and bad APIs look like.
- Why is API Design Important?
- APIs can be among a company's greates assets.
- Customers invest heavily: buying, writing, learning.
- Cost to stop using an API can be prohibitive
- Successful public APIs capture customers.
- Can also be among company's greatest liabilities
- bad APIs result in unending stream of support calls.
- Public APIs are forever
- One chance to get it right.
- Why is API Design Important to You?
- If you program, you are an API Designer
- Good code is modular - each module has an API
- Usefull modules tend to get reused
- Once module has users, can't change API at will
- You can add new ones,
- But you should not delete or modify existing ones at will.
- Once module has users, can't change API at will
- Thinking in tersm of API improves code quality.
- Characteristics of a Good API
- Easy to learn.
- Easy to use, Hard to misuse
- Easy to read and maintian code that uses it
- Sufficiently powerful to satisfy requirements.
- Easy to extend
- Appropriate to audience.
2 Process of API Design
- Gather requirements - with a Healthy Degree of Skepticism
Often you'll get proposed solutions instead, but better solutions may existing, and your job is to extract true requirements from the use-cases.
And, keep in mind that it can be easier and more rewarding to build somthing more general.
- Make spec short: single page is okey
- Write to Your API Early and Often
- Writing to SPI is Even More Important
- Service Provider Interface (SPI)
- Plugin-in interface enabling multiple implementations
- Example: Java Cryptography Extension (JCE).
- Write multiple plugins before release
- The Rule of threes.
- Maintain Realistic Expectations
3 General Principles
- API should do one thing and do it well
- Functionality should be easy to explain:
- If it's hard to name, that generaty a bad sign.
- Good names drive development.
- Be amenable to spliting and merging modules.
- API should be as mall as possible, but no smaller
- API should satisfy its requirements
- When in doubt, leave it out!
- You can always add, but you can never remove!
- Conceptual weight more important than bulk.
- Look for a good power-to-weight ratio
- Implementation should not impact API
- Minimize Accessibility of Everything
- Make classes and members as private as possible.
- Public classes should have no public fields.
- Maximizes information hiding
- Allow modules to be used, understood, built, tested, and debugged independently.
- Names Matter – API is a Little Language
- Names shoudl be Largely Self-Explanatory
- Be consistent – same word meas same thing
- Be regular – strive for symmetry
- Code should read like prose
- Documentation Matters
- Document Religiosly:
All public APIs should have Documentation:
- Classes: what an instance represents
- Method: contract between method and its client
- Preconditions, postconditions, side-effects.
- Parameter: indicat units, form, ownership
- Document state space very carefully
- Consider Performace Consequences of API Design Decisions
- bad decisions can limit performance.
- API Must Coexist Peacefully with Platform
4 Classes Deisgn
- Minimize Mutability
Classes should be immutable unless there's a good reason to do otherwise. If mutable, keep state-space small, well-defined.
- Subcalss only where it makes sense
Subclassing implies subsitituability,
- Public classses should not subclasses other public classes.
- Design and Document for Inheritance or Else Prohibit it!
5 Method Design
- Don't make the Client Do Anything the Module Could Do
- Don't Violate Principle of Least Astonishment
- Fail Fast – Report Errors as Sonn as Possible After They Occur
- Provide Programmatic Access to All Data Available in String Form
- Overload With Care
if you must provide ambiguous overloadings, ensure same behavior for same arguments.
- Use Appropriate Parameter and Return Types
- Favor interface types over classes for input.
- Use most specifi possible input parameter type
Moves error from runtime to compile time.
- Don't use string if a better type exists
- Do't use floating point for monetary values:
Binary floating point causes inexact result.
- Use double (64 bits) rather than float(32 bits):
Precision loss is real, performance loss negligible.
- Use Consistent parameter Ordering Across Methods
#include <string.h> char *strcpy(char *dest, char *src); void bcopy (void* src, void* dst, int n); // XXX: Bad example!
- Avoid Long Parameter Lists
- Three or fewer parameters is ideal
- Two techniques for shortening parameter lists:
- Break up method
- Create helper class to hold parameters
- Avoid Return Values that Demand Exceptional Processing
6 Exceptions Design
- Throw Exceptions to Indicate Exceptional Conditions
- Don't force client to use exceptions for control flow.
- Don't fail silently
- Favor Unchecked Exceptions
- Include Failure-Capture Information in Exceptions
7 Refactoring API Design
Just some examples….