All along my life, i had complete control over my code. I could change method/class names, signatures at will and all users would be in the same code base. I could do endless refactoring. Now I have to maintain and keep enhancing an API. Sounds easy ? Its actually big trouble, every method you publish would end up being called by thousands of people and you lose your ability to refactor in a jiffy.
Public API's are forever and there is only one chance to get them right - Joshua Bloch
I learnt good API design is an art in itself and i also picked up some basic rules that should be followed. They are
1.Intuitive APIs
When designing an API, always consider specific examples of what code clients should write to use it. Model api's after commonly used usage patterns/api's. This will help us avoid cumbersome or unintuitive APIs.
2.Internal Code
All internal code that should not be called by public should go in a separate package marked internal. Like all public classes in com.company.product.* and internal classes in com.company.product.internal.*.
3.Expose only what's needed
Use the most stringent access specifiers possible (private/package provate/protected/public). The idea is to prevent unintended usage of the api's. Some common tips
1) All classes/functions that should be called by other classes in the same package should be declared as package private. Note there is no such thing as package private interfaces since all methods in a package private interface have to be declared public.
2) If a method needs to be called by classes in a different package then the tendency is to make it public even though it is not a true public api. In such cases, a good way to proceed is to make the class as abstract, then subclass this class in the private packages and use static factory methods to return an instance of the internal class. This way the methods would be exposed in private packages only.
3) Declaring a method as protected is as good as declaring it as public since any one can subclass and be able to call the method. It should be used only when it is sure that clients should be able to override them or subclasses are in different packages.
4) Make classes/methods final such that they cannot be overridden. Turning it around, assuming clients will extend any of the public classes which are not final it is unpredicatable to let clients overide selected methods without understanding the big picture.
5) No member variables should be public except constants (public static final)
4.Javadoc
All public methods/constants in a public class must be documented. The ease of use of your api depends on how good the javadoc is. A good clean javadoc means there is no implementation detail specified. All operations on data that are visibile to clients is well documented as are error conditions. Specify clearly what each method will and more importantly will not do.
5.Static Factory creation
Prefer using Static factory methods to create objects than using new. This allows us to create any object that implements the specified contract than exposing a truckload of classes to the public. Use of a constructor forces the implementation to return an instance of the class itself rather than a subclass (or one of a set of subclasses). This would force the class to have knowledge of all variant behaviours.
6.Contexts
Dont store contexts in objects. Prefer to pass them as method parameters. If we store contexts in objects and pool those objects, then we have to ensure that the context is valid throughout object lifecycle. This is a big pain.
7.Thread safe classes
Immutable classes and fly weights are easily thread safe. Prefer to use them judiciously.
8.Helpers & Utils
Any util class that needs to be associated to a state should be made a helper that has to be instantiated with the state. Utils should be final and non instantiable and all methods should be static.
9.Class Names and Method names
Make names consistent throughout the api, length() method returns length of both String/StringBuffer. If you get the naming correct most people would be able to use it intuitively without poring over the docs. This makes the api's very simple to use.
10. Exceptions
Never throw a single type of exception with different messages. Use lots of different exception classes with the rule being roughly for each kind of error throw an exception. Be sure to put them in proper hierarchy like java.io.IOException so that clients have the flexibility to declare a single block for a general category of exceptions.
Always ensure that the exception message is picked up from a resource bundle or some other file so that messages can be easily translated. Hey, you never know who is going to use your api's !
When in doubt leave it out. We can always go in and add something later after more delibration.
Wednesday, April 19, 2006
10 Tips for good API Design
Posted by Kaushik at 7:53 AM
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment