The art of designing a java API
Abstract
Basic principles
- intuitive
- understandable
- learnable
- discoverable
- consistent
- self-defensive
- concise
- easy to use
- minimal
- orthogonal
- idiomatic
- flexible
- evolvable
- well documented
- right level of abstraction
- correct use of the type system
- limited number of entry-points
- respect the principle of least astonishment
Be ready to change
A good design is not the one that correctly predicts the future, it’s the one makes adapting to the future affordable.
Change is the only constant in the software.
If in doubt, leave it out. A feature that only takes a few hours to be implemented can:
create hundred of hours of support and maintenance in future
bloat your software and confuse your users
become a burden and prevent future improvements
Software doesn't age like wine, it ages like milk.
Best practices and practical hints
- write meaningful Javadocs
- Javadocs are the API specs
- it’s all about boundaries definition and modularity
- use overloading judiciously and sparingly
- consistent argument orders
- consider static factories
- nicer syntax for users (no need of new keyword)
- can return different subclasses
- can check preconditions and edge cases returning different implementations accordingly
- promote fluent API without abusing them
Streams
are a very nice and convenient example of fluent API- fluency works really well for builders
- use the weakest possible type
- e.g. use
Collection
instead ofArrayList
in signature of the API- support lambdas
- avoid checked exceptions
- stay in control (loan pattern)
We are transferring to our users the burden to use our API correctly ⇒ that’s a leaky abstraction.
One way is to use the following:
Then the API consumer won’t need to remember to close the resource:
⇒
the responsibility of avoiding the leak is encapsulated in our API
if clients are forced to use this API, no leak is possible at all
break apart large interfaces into smaller versions
Becomes:
- be defensive with your data
- if necessary return unmodifiable objects to avoid that a client could compromise the consistency of your data
- return empty collections or optionals
- prefer enums to boolean parameters
- use meaningful return types
aka “primitive obsession”
API design is an iterative process
- practice dogfeeding