In this tutorial, we explain how to design and evolve APIs without breaking client code: API Design Patterns and Idioms, Guidelines for writing Specifications, and Process for good API Design.
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Dr. Boris Bokowski, IBM Rational, Ottawa CanadaFull time committer on the Eclipse Platform and e4, Technical lead of the Eclipse Platform UI team, Member of the Eclipse Architecture Council, Committer Representative on the Eclipse Board of Directors.
Dipl.-Ing. Martin Oberhuber, Wind River, Salzburg AustriaSenior Member of Technical Staff at Wind River, Certified ScrumMaster, Chair of the Eclipse Architecture Council, Eclipse PMC Member, Target Management Project Lead, Eclipse Platform Core and e4 Committer.
Dipl.-Phys. Michael Scharf, Wind River, Heidelberg GermanyPrincipal Technologist and Architectural Overseer at Wind River, Member of the Eclipse Architecture Council, Model Enthusiast, Committer and Officially Approved Eclipse Troublemaker.
Requirement:As a Tutorial Presenter, I want to know how many committers vs non-committers are in my talk, such that I can present material that matters to the audience.
API, 1st cut:
public interface Course {public int countCommitters();public int countNonCommitters();
/** * Represents a course at a conference. */public interface Course {
/** * Returns the number of committers who attended the course. * @return the number of committers who attended the course. */public int countCommitters();/** * Returns the number of non-committers who attended the course. * @return the number of non-committers who attended the course. */public int countNonCommitters();
As a Tutorial Presenter, I want to know after the talk how many distinct people heard the talk, and how many left a “+1” card when leaving, such that I get feedback about audience satisfaction.
As a Tutorial Presenter, I want to get live approximate statistics about committers vs non-committers in my talk, such that I can present material that matters to the audience. I may be interested in other attendee roles in the future, such as contributors, private or commercial attendees.
Contest: There will be a prize for the best API for these reqs- Use the patterns you'll learn in this course, and your ingenuity- E-Mail Solutions until today 7pm to [email protected] Will discuss solutions and give out the prize at the Unconference,
Launch Eclipse SDK or any package (JDT preferred) File > Import > General : Existing Projects into Workspace Archive: org.eclipsecon.apitutorial.zip Hand off: File > Export > General : Archive File
Pick up some usable advice for designing good API- Understand why good API is important- Understand the key aspects of good API- Best practices, patterns and idioms for process, code and spec
We'll talk mostly about style – this is not a course on SW Architecture
Know how to safely evolve existing API- Learn what's new in terms of tooling and policy around API
Have fun hearing some API Stories Get some good references to read on or read up on this talk
APIs are interfaces with specified and supported behavior.- Specification: Guideline for implementations, judge what's a bug- Supported: Bugs will be fixed
Key for successful componentization and scaling up- Develop, test and evolve components individually- API: Provide a stable Platform to build on- SPI: Allow multiple implementations, e.g. improve performance
Good APIs capture and bind clients- Clients invest into API (by code, and by learning the API)
Good APIs minimize waste- Encourage code re-use instead of re-writing- Reduce code and complexity- Bad APIs lead to bugs, maintenance and documentation needs
Make your API easy to read, write and evolve Be client centric API is a Cover Story Names Matter! Repeat until happy Keep API Small: If in doubt, leave it out Make simple things simple, make hard things possible Consider non-functional aspects: No Spec - No API. Emulate the Platform
Use int option flags to allow for future extension- Same effort but more flexible than boolean- Common Pattern used in the Platform, e.g.IProject.open(IResource.NONE, IProgressMonitor mon)
Separate concerns: Do one thing at a time- Adapter pattern to mix-and-match functionality- IAddonInterface addon =
Spec too vague, no single consistent Story Completeness (e.g., add but no remove) Names (avoid overly long names for elements that are used a lot) All interfaces, but no constructor Check assumptions about defaults Internationalization: specify if strings are visible to the end-user Lack of considering non-functional requirements
- thread safety- progress reporting- being able to cancel long-running operations- nesting, composeability
There's many things an API User needs to know,which are not expressed in the Java signatures...
Specification Design Goals by RoleA. Tell client what they need to know to use itB. Tell an implementor how to implement it properlyC. Tell tester about key behaviors to testD. Determines blame in event of failure
➔ Document religiously, but only as far as the cover story is concerned (don't let implementation leak)
/** * Removes and returns the object on the top of this stack. * The stack must not be empty. * * @return the object popped off the stack; may * be <code>null</code> */public Object pop();
Is the specification too specific or detailed, making it difficult to evolve or implement?
- Gain flexibility by hiding implementation.- API is a cover story.
Is the spec too vague, making it difficult for clients to know the correct usage?
- Always assume clients are unfamiliar with your code.- Tell a compelling and seamless story.- If incomplete, clients will look up your implementation :(
Is the API designed to be implemented or extended by clients?- Be aware of different kinds of clients.- Keep Client API separate from Service Provider API (SPI).
RFC on specification language: http://www.ietf.org/rfc/rfc2119.txt
Must, must not, required, shall: it is a programmer error for callers not to honor these conditions. If you don’t follow them, you’ll get a runtime exception (or worse)
Should, should not, recommended: Implications of not following these conditions need to be specified, and clients need to understand the trade-offs from not following them
May, can: A condition or behavior that is completely optional
Purpose: Summarized in 1 introductory sentence Contract: Pre-conditions, Post-conditions Data: Argument and result types, ownership, special cases Failure: Any cases worth specifying? Don't overdo! Non-functional aspects: as relevant for Cover Story
- Side effects- Concurrency- Event ordering- Callbacks
Is the story complete, compelling, and seamless? Does your spec help your clients without limiting your freedom?
Know your Clients and Iterate over Requirements with them Make simple things simple, make hard things possible Keep API Small: If in doubt, leave it out. Names Matter! Repeat until happy. API is a Cover Story Specs are important! No Spec - No API. Emulate the Platform
Know where to look for details: http://wiki.eclipse.org/API_Central
public class Test {public void foo(Object o) {}public void foo(String s) {}
}
• Binary compatible• When source references are recompiled they may be bound to the new method• Will cause errors in source references with a null argument, such as test.foo(null)
} x• Not binary compatible• Constant values that can be computed by the compiler are in-lined at compile time. Referring code that is not recompiled will still have the value “5” in-lined in their code
public class Test {protected void foo() throws E {}
}
public class E extends Exception {}
public class Test {protected void foo() {}
}
• Binary compatible• There is no distinction between checked and unchecked exceptions at runtime• Not source compatible because catch blocks in referring methods may become unreachable
• Not binary or source compatible• When a constructor is added, the default constructor is no longer generated by the compiler. References to the default constructor are now invalid• You should always specify at least one constructor for every API class to prevent the default constructor from coming into play (even if it is private)• A constructor generated by the compiler also won’t appear in javadoc
It is very difficult to determine if a change is binary compatible Binary compatibility and source compatibility can be very different You can’t trust the compiler to flag non-binary compatible changes
Evolve once, check twice.
If in doubt, check “The Bible”: Evolving Java-based APIs, Jim des Rivieres et alavailable from http://wiki.eclipse.org/API_Central
Binary compatibility DONT's for API elements Rename a package, class, method, or field Delete a package, class, method, or field Decrease visibility (change public to non-public) Add or delete method parameters Change type of a method parameter Add or delete checked exceptions to a method Change return type of a method Change type of a field Change value of a compile-time constant field Change an instance method to/from a static method Change an instance field to/from a static field Change a class to/from an interface Make a class final (if clients may subclass) Make a class abstract (if clients may subclass)...
File Formats- Workspace Compatibility section in the Eclipse Project's Project Plan- Provide Migration code when changing, e.g. Preferences
Extension Points- Expected Parameters- Can be evolved like Java APIs: Version Numbering- No Tooling available yet
ID's- Even Extensions are API for consumers!- Example: ID's of Property Testers expected to be in the Platform- No Tooling, no good automatic documentation!
Data Protocols, Wire Formats, … Functionality of commandline args, config files, …
Reasons for deprecating API- A new story fixed issues (e.g. concurrency, performance)- Small API – Less to Learn, easy to understand- Planning a major implementation rewrite (think e4)
Reasons for removing API- At first, deprecation is just a recommendation
But nobody will act if there is no axe in the window May remain deprecated forever if just for ease-of-learning
- Schedule API Removal for serious issues- Removal breaks clients and must be clearly announced (Policies)- Announce removal date. Use API Tooling to find parties to discuss.
Eclipse Project Policy for Removal: 2 years lead timehttp://wiki.eclipse.org/API_Central
APIs exist to serve the needs of clients- Where are those clients? What do they need?
Important to work with actual clients when designing API- Designing APIs requires feedback from real clients who will use it- Otherwise risks crummy API that real clients cannot use
Find a primary client- Ideally: adjacent component, different team, same release schedule- E.g., JDT UI is primary client of JDT Core
Work closely with primary client- Listen to their problems with using API- Watch out for lots of utility classes in client code symptomatic of
mismatch between API and what client really needs- Work together to find solutions
Gather Requirements – but with healthy skepticism- Some “Requirements” are really implementation suggestions- API should be the Cover Story but allow different implementations!
Start the spec with 1 page- Iterate, rinse, return - take time to evolve
Code early against the API - Tests, Examples to see how it “feels” in real life- This is not throw-away code but may become regression tests or
examples as part of the spec later on- Even more important for SPI! - If there is just one implementation of a
service that's meant to be changeable, you'll surely mess up.
Component provides API for arbitrary clients- API exists to tame inter-component coupling
Client components are expected to use API “to spec”- Not depend on behavior not covered in API spec- Not depend on internals- Foolish to make exceptions for close friends
Close friends don’t point out flaws Sets bad example for others
Provisional API Guidelines- Mark x-internal:=”true” in the Manifest until solidified- Allows for wider exposure to clients, even across releases- NEW: Allowed to have provisional API in its final namespace
No more forced breaking of clients when refactoring from “internal” package to “public” package namespace
X-internal is the premier markup of provisional API Must have a client
- Each extension point or API must have a client in Open Source- Ensure that example code and test code is there
Has become indispensable for- Adding proper Javadoc Tags- Reporting mis-use according to tags- Detecting Binary Compatibility Breakage- Detecting Leakage of non-API Types into API- Updating Version Numbers correctly
Super easy setup- Window > Preferences > PDE > API Baselines : Register Baseline- Single directory with plugins to compare against- Problem Markers; use Ctrl+1 Quickfix to add problem filters
major.minor.service.qualifier From release to release, the version number changes as follows:
- When you break the API, increment the major number- When you change the API in an (binary) upwards compatible way,
increment the minor number- When you make other changes, increment the service number- The qualifier is changed for each build
Proposal: Less strict versioning for Service Provides (SPI)- Breaking changes in SPI are allowed with minor rev- A variant of the “I know my clients so I can break them” story- Better not make such API public, if I know you, use internals
Guidelines, see http://wiki.eclipse.org/API_Central
.api_description file needed in binary bundles- Conveys information from API tags like @noimplement- No problem reporting without these in the binary baseline
Setup: Just add this to your build.properties:- generateAPIDescription=true
API Central on Eclipse Wikihttp://wiki.eclipse.org/API_Central
- API Process: This Presentation, linked on API Central Eclipse API Process and Policies, all linked from API Central
- API Design: Joshua Bloch, Effective API Design (1 Hr Video)http://www.infoq.com/presentations/effective-api-design
- API Specifications: EclipseCon 2006 API Tutorial, see API Central Sun, Requirements for Writing Java API Specifications Sun, How to Write Doc Comments for the Javadoc Tool
- API Evolution Evolving Java-Based API's, see API Central EclipseCon 2007: Eclipse APIs and Java 5, see API Central
- API Tooling, Documentation and Wiki all linked from API Central
Joshua Bloch, Effective Java Programming Language Guide
Create your API for counting Course attendees and Committer / User Statistics
E-Mail solutions to [email protected] Come to the Winner Selection at the Unconference
- Today 19:15 in this room (Lafayette)- We'll all learn a lot by looking at solutions- … and the winner can take their prize away
If you have any more questions about API...- Find us at the conference, or file a bug with the Architecture Council- http://wiki.eclipse.org/Architecture_Council