InfoQ

Article

Joshua Bloch: Bumper-Sticker API Design

Posted by Joshua Bloch on Sep 22, 2008 07:15 AM

Community
Java,
.NET,
Architecture,
Ruby
Topics
Programming

My conference session How to Design a Good API and Why it Matters has always drawn large crowds; on InfoQ was the third most viewed content last year. When I presented this session as an invited talk at OOPSLA 2006, I was given the opportunity to write an abstract for the proceedings. In place of an ordinary abstract I decided to try something a bit unusual: I distilled the essence of the talk down to a modest collection of pithy maxims, in the spirit of Jon Bentley's classic Bumper-Sticker Computer Science, Item 6 in his excellent book, More Programming Pearls: Confessions of a Coder (Addison-Wesley, 1988).

It is my hope that these maxims provide a concise summary of the key points of API design, in easily digestible form:

All programmers are API designers. Good programs are modular, and intermodular boundaries define APIs. Good modules get reused.

APIs can be among your greatest assets or liabilities. Good APIs create long-term customers; bad ones create long-term support nightmares.

Public APIs, like diamonds, are forever. You have one chance to get it right so give it your best.

APIs should be easy to use and hard to misuse. It should be easy to do simple things; possible to do complex things; and impossible, or at least difficult, to do wrong things.

APIs should be self-documenting: It should rarely require documentation to read code written to a good API. In fact, it should rarely require documentation to write it.

When designing an API, first gather requirements—with a healthy degree of skepticism. People often provide solutions; it's your job to ferret out the underlying problems and find the best solutions.

Structure requirements as use-cases: they are the yardstick against which you'll measure your API.

Early drafts of APIs should be short, typically one page with class and method signatures and one-line descriptions. This makes it easy to restructure the API when you don't get it right the first time.

Code the use-cases against your API before you implement it, even before you specify it properly. This will save you from implementing, or even specifying, a fundamentally broken API.

Maintain the code for uses-cases as the API evolves. Not only will this protect you from rude surprises, but the resulting code will become the examples for the API, the basis for tutorials and tests.

Example code should be exemplary. If an API is used widely, its examples will be the archetypes for thousands of programs. Any mistakes will come back to haunt you a thousand fold.

You can't please everyone so aim to displease everyone equally. Most APIs are overconstrained.

Expect API-design mistakes due to failures of imagination. You can't reasonably hope to imagine everything that everyone will do with an API, or how it will interact with every other part of a system.

API design is not a solitary activity. Show your design to as many people as you can, and take their feedback seriously. Possibilities that elude your imagination may be clear to others.

Avoid fixed limits on input sizes. They limit usefulness and hasten obsolescence.

Names matter. Strive for intelligibility, consistency, and symmetry. Every API is a little language, and people must learn to read and write it. If you get an API right, code will read like prose.

If it's hard to find good names, go back to the drawing board. Don't be afraid to split or merge an API, or embed it in a more general setting. If names start falling into place, you're on the right track.

When in doubt, leave it out. If there is a fundamental theorem of API design, this is it. It applies equally to functionality, classes, methods, and parameters. Every facet of an API should be as small as possible, but no smaller. You can always add things later, but you can't take them away. Minimizing conceptual weight is more important than class- or method-count.

Keep APIs free of implementations details. They confuse users and inhibit the flexibility to evolve. It isn't always obvious what's an implementation detail: Be wary of overspecification.

Minimize mutability. Immutable objects are simple, thread-safe, and freely sharable.

Documentation matters. No matter how good an API, it won't get used without good documentation. Document every exported API element: every class, method, field, and parameter.

Consider the performance consequences of API design decisions, but don't warp an API to achieve performance gains. Luckily, good APIs typically lend themselves to fast implementations.

When in Rome, do as the Romans do. APIs must coexist peacefully with the platform, so do what is customary. It is almost always wrong to “transliterate” an API from one platform to another.

Minimize accessibility; when in doubt, make it private. This simplifies APIs and reduces coupling.

Subclass only if you can say with a straight face that every instance of the subclass is an instance of the superclass. Exposed classes should never subclass just to reuse implementation code.

Design and document for inheritance or else prohibit it. This documentation takes the form of selfuse patterns: how methods in a class use one another. Without it, safe subclassing is impossible.

Don't make the client do anything the library could do. Violating this rule leads to boilerplate code in the client, which is annoying and error-prone.

Obey the principle of least astonishment. Every method should do the least surprising thing it could, given its name. If a method doesn't do what users think it will, bugs will result.

Fail fast. The sooner you report a bug, the less damage it will do. Compile-time is best. If you must fail at run-time, do it as soon as possible.

Provide programmatic access to all data available in string form. Otherwise, programmers will be forced to parse strings, which is painful. Worse, the string forms will turn into de facto APIs.

Overload with care. If the behaviors of two methods differ, it's better to give them different names.

Use the right data type for the job. For example, don't use string if there is a more appropriate type.

Use consistent parameter ordering across methods. Otherwise, programmers will get it backwards.

Avoid long parameter lists, especially those with multiple consecutive parameters of the same type.

Avoid return values that demand exceptional processing. Clients will forget to write the specialcase code, leading to bugs. For example, return zero-length arrays or collections rather than nulls.

Throw exceptions only to indicate exceptional conditions. Otherwise, clients will be forced to use exceptions for normal flow control, leading to programs that are hard to read, buggy, or slow.

Throw unchecked exceptions unless clients can realistically recover from the failure.

API design is an art, not a science. Strive for beauty, and trust your gut. Do not adhere slavishly to the above heuristics, but violate them only infrequently and with good reason.

Watch Presentation: How to Design a Good API & Why it Matters

Joshua Bloch is Chief Java Architect at Google, author of Effective Java, Second Edition (Addison-Wesley, 2008), and coauthor of Java Puzzlers: Traps, Pitfalls, and Corner Cases (Addison-Wesley, 2005) and Java Concurrency in Practice. He was a Distinguished Engineer at Sun Microsystems, where he led the design and implementation of numerous Java platform features including JDK 5.0 language enhancements and the Java Collections Framework. He holds a Ph.D. from Carnegie-Mellon and a B.S from Columbia.

9 comments

Reply

Documentation... by Seb Rose Posted Sep 22, 2008 8:59 AM
Re: Documentation... by Kurt Christensen Posted Sep 22, 2008 10:39 AM
Re: Documentation... by Albert Hwang Posted Sep 22, 2008 4:16 PM
Converting use-case tests into examples in tutorials: code citing by Peter Arrenbrecht Posted Sep 23, 2008 1:06 AM
I've read this before. by Jasper Novotny Posted Sep 23, 2008 5:17 AM
Re: I've read this before. by Abel Avram Posted Sep 24, 2008 3:05 AM
Re: I've read this before. by Rich Unger Posted Sep 26, 2008 1:44 PM
Re: I've read this before. by Ilja Preuß Posted Oct 17, 2008 11:06 AM
Diamonds vs. stars by Jaroslav Tulach Posted Sep 25, 2008 4:11 PM
  1. Back to top

    Documentation...

    Sep 22, 2008 8:59 AM by Seb Rose

    "APIs should be self-documenting: It should rarely require documentation to read code written to a good API. In fact, it should rarely require documentation to write it."

    <p>"Documentation matters. No matter how good an API, it won't get used without good documentation. Document every exported API element: every class, method, field, and parameter."

    <p>A contradiction, I think.</p></p>

  2. Back to top

    Re: Documentation...

    Sep 22, 2008 10:39 AM by Kurt Christensen

    There are always contradictory principles in engineering. That's why design is a non-trivial activity.

  3. Back to top

    Re: Documentation...

    Sep 22, 2008 4:16 PM by Albert Hwang

    The first refers to documentation of the code that uses the API. The second refers to the documentation of the API itself. If the API is properly named, then the code that uses it does not require documentation.

    For example, if your API had a method that parsed a string and removed all white spaces, 'trim' would be much better than 'parse'.


    // does not require documentation
    a.trim();

    // does require documentation
    // parse string and remove all white spaces
    a.parse();

  4. Maintain the code for uses-cases as the API evolves. Not only will this protect you from rude surprises, but the resulting code will become the examples for the API, the basis for tutorials and tests.


    I wrote a tool to cite snippets of Java source code into documentation for exactly this purpose. Supports omitting irrelevant detail and highlighting especially relevant parts.


    You can see it in action in a largish project in that project's Quick Start example and all of the tutorial, as in this example.

  5. Back to top

    I've read this before.

    Sep 23, 2008 5:17 AM by Jasper Novotny

    These things are a lot in Jaroslav Tulach's new book. Only real difference is that 'diamonds' above are 'stars' there.

  6. Back to top

    Re: I've read this before.

    Sep 24, 2008 3:05 AM by Abel Avram

    These things are a lot in Jaroslav Tulach's new book. Only real difference is that 'diamonds' above are 'stars' there.


    Joshua Bloch's article is just a late follow-up of his presentation done in 2006 (www.infoq.com/presentations/effective-api-design). I hope you don't suspect Bloch plagiarizing Tulach.

  7. Back to top

    Diamonds vs. stars

    Sep 25, 2008 4:11 PM by Jaroslav Tulach

    There is a significant difference between diamonds and stars. While diamonds are said to be forever, nobody considers stars eternal. As such the allegories are not the same. They are in fact quite different. Read more...

  8. Back to top

    Re: I've read this before.

    Sep 26, 2008 1:44 PM by Rich Unger

    Whoa, I highly doubt anyone would ever suspect such a thing. Not least because Jaroslav's book is almost entirely devoted to disproving the last one: "API design is an art, not a science." He argues (convincingly, I think) that there are sound engineering principles which can be applied to design an API.

  9. Back to top

    Re: I've read this before.

    Oct 17, 2008 11:06 AM by Ilja Preuß

    Jaroslav's book is almost entirely devoted to disproving the last one: "API design is an art, not a science." He argues (convincingly, I think) that there are sound engineering principles which can be applied to design an API.


    So, are you saying that engineering is science, not art? ;)

Educational Content

JRuby: The Pain of Bringing an Off-Platform Dynamic Language to the JVM

Charles Nutter discusses bringing JRuby to the JVM, why Ruby is hard to implement, JIT compilation, precompilation, core Ruby implementation, Java library access, library challenges and future plans.

Performance Anti-Patterns in Database-Driven Applications

Alois Reitbauer specifies several architectural anti-patterns that one should stay away from and which can downgrade an application’s performance.

Making TDD Stick: Problems and Solutions for Adopters

Teams in large organizations still struggle to adopt TDD. In this article Mark Levison shares problems he uncovered when he surveyed teams, and his own strategy to introduce TDD into an organization.

Testing is Overrated

In this talk from RubyFringe, Luke Francl asks: is developer-driven testing really the best way to find software defects? Or is the emphasis on testing and test coverage barking up the wrong tree?

VM Optimizations for Language Designers

John Pampuch discusses the HotSpot compiler, the history of Java performance, HotSpot development philosophies and challenges, optimization, JVM library improvements, and tips for better performance.

Keith Braithwaite, an Agile Skeptic

In this interview, Keith Braithwaite, an Agile developer, consultant and trainer, says that we should show a good deal of skepticism towards today’s Agile practice.

Workflow Orchestration Using Spring AOP and AspectJ

This article demonstrates how to build and orchestrate highly configurable and extensible yet light-weight embedded process flow using AOP techniques with Spring AOP and Aspect J.

Embrace Uncertainty

Jeff Patton explains why one needs to embrace uncertainty in order to succeed with his/her Agile project and how to avoid some of the common mistakes leading to project failure.