Joshua Bloch
Principal Software Engineer
Easy to learn
Easy to use, even without documentation
Hard to misuse
Easy to read and maintain code that uses it
Sufficiently powerful to satisfy requirements
Easy to extend
Appropriate to audience
Your job is to extract true requirements Should take the form of use-cases
USE-cases
Can be easier and more rewarding to build something more general
Start with Short Spec 1 page is Ideal
At this stage, agility trumps over completeness
Bounce spec off as many people as possible
_ Listen to their input and take it seriously
If you keep the spec short, it’s easy to modify
Flesh it out as you gain confidence
_ This necessarily involves coding
Write to Your API Early and Often
Start before you've implemented the API
_ Saves you doing implementation you'll throw away
Continue writing to API as you flesh it out
_ Prevents nasty surprises
_ Code lives on as examples, unit tests
Writing to SPI is Even More Important
Service Provider Interface (SPI)
Plug-in interface enabling multiple implementations
Write multiple plug-ins before release
_ If you write one, it probably won't support another
_ If you write two, it will support more with difficulty
_ If you write three, it will work fine
Maintain Realistic Expectations
Most API designs are over-constrained
_ You won't be able to please everyone
_ Aim to displease everyone equally
Expect to make mistakes
_ A few years of real-world use will flush them out
_ Expect to evolve API
API Should Do One Thing and Do it Well
• Functionality should be easy to explain
_ If it's hard to name, that's generally a bad sign
_ Good names drive development
_ Be amenable to splitting and merging modules
API Should Be As Small As Possible But
No Smaller
When in doubt leave it out
_ Functionality, classes, methods, parameters, etc.
_ You can always add, but you can never remove
Look for a good power-to-weight ratio
This maximizes information hiding
• Allows modules to be used, understood, built,
tested, and debugged independently
Documentation Matters
Document every class, interface, method,
constructor, parameter, and exception
Class: what an instance represents
_ Method: contract between method and its client
_ Preconditions, postconditions, side-effects
_ Parameter: indicate units, form, ownership
Document state space very carefully
• Take advantage of API-friendly features
_ Generics, varargs, enums, default arguments
• Know and avoid API traps and pitfalls
_ Finalizers, public static final arrays
Subclass Only Where It Makes Sense
• Subclassing implies substitutability (Liskov)
_ Subclass only when is-a relationship exists
_ Otherwise, use composition
Provide Programmatic Access to All
Data Available in String Form
Use most specific possible input parameter type
_ Moves error from runtime to compile time
• Don't use string if a better type exists
_ Strings are cumbersome, error-prone, and slow
• Don't use floating point for monetary values
_ Binary floating point causes inexact results!
• Use double (64 bits) rather than float (32 bits)
_ Precision loss is real, performance loss negligible
Avoid Long Parameter Lists
Three or fewer parameters is ideal
_ More and users will have to refer to docs
Long lists of identically typed params harmful
_ Programmers transpose parameters by mistake
_ Programs still compile, run, but misbehave!
Two techniques for shortening parameter lists
_ Break up method
_ Create helper class to hold parameters
Avoid Return Values that Demand
Exceptional Processing
return zero-length array or empty collection, not null
No comments:
Post a Comment