Developing Useful APIs
Dmitry Buzdin
October 2013, Riga
Dmitry Buzdin
buzdin@gmail.com
@buzdin
www.buzdin.lv
What is API?
API is the code you	

use every day
How many Jars do you 	

have in your classpath?
from 20 to100 jars?
Each
library has
its own API
!
and personality
Moreover, you create
new reusable APIs
inside your project
may be even in a separate module
APIs are written by
developers for
developers
Everything is Open
Source today!
Frameworks are
turning into micro-
frameworks
I have to
learn 100
APIs?
!
Is it possible
at all?
Option I:
lock yourself in a
dungeon
The best code in the world is 	

the one I wrote yesterday!
Option II:
learn to ride APIs
Are all APIs different?
Let’s try to
understand...
What is a Good API
• Easy to read	

• Easy to use	

• Hard to misuse	

• Easy to extend
How to Achieve That?
• Lets take a look at some:	

• module/package level approaches	

• class level patterns	

• method/code level idioms
Imagine building API for
the next 10 years and
1000s of people
Module Level
Dependency Management
• Put less transitive dependencies	

• Do you really need that commons-lang?	

• Do you remember about Guava
incompatibilities
Extreme example: OrientDB - zero dependencies!
Packaging
com.acme.lib
PublicAPI.java
impl
PublicInterface.java
spi CustomListener.java
Internal.java
Util.java
PublicBean.java
Stuff you
want to be
reused
Extension
API
Licensing
http://choosealicense.com/
Class Level
Lets build an API for a reusable gadget
Gadget gadget = new Gadget(name, id, options);!
// Gadget is connected at this point
public Gadget(name, id, options) {!
this.name = name;!
this.id = id;!
this.options = options;!
connect(); // could throw an exception!
}
Gadgets should always be connected
Can not create an instance
for testing
Create Gadget by static method or factory class
public Gadget(name, id, options) {!
this.name = name;!
this.id = id;!
this.options = options; !
}!
!
public static Gadget newGadget(name, id, options) {!
Gadget gadget = new Gadget(name, id, options);!
gadget.connect();!
return gadget;!
}!
!
public class GadgetFactory {!
public Gadget newGadget(name, id, options) {!
Gadget gadget = new Gadget(name, id, options);!
gadget.connect();!
return gadget;!
} !
}
public static Gadget newGadget(name, id, options) {!
Gadget gadget = new DefaultGadget(name, id, options);!
gadget.connect();!
return gadget;!
}!
!
public interface Gadget {!
void connect();!
}!
!
public class DefaultGadget implements Gadget {!
public void connect() {!
}!
}
Hide your gadget behind interface
Because you could change the implementation	

Details are well hidden
public static Gadget newGadget(name, id, options) {!
Gadget gadget = new DefaultGadget(name, id, options);!
gadget.connect();!
return gadget;!
}!
!
public interface Gadget {!
void connect();!
}!
!
public final class DefaultGadget implements Gadget {!
DefaultGadget() {!
}!
public void connect() {!
}!
}
Make it final with package-level constructor
Disallow
unsanctioned
modification of
your code
Open Closed Principle
"software entities (classes, modules, functions, etc.) !
should be open for extension, but closed for modification"
public final class DefaultGadget implements Gadget {!
public void setStrategy(BehaviorStrategy s) {!
// changes the behavior of this Gadget;!
}!
}
Allowing
sanctioned
modifications
Gadget gadget = Gadgets.newGadget(name, id, options);!
// Gadget is connected at this point!
!
!
// Similar APIs!
Files.createFile(...); // JDK 7!
Lists.newArrayList(...); // Guava
Resulting code
Method Overloading
Gadget gadget = Gadgets.newGadget(name, id, options);!
Gadget gadget = Gadgets.newGadget(id, options);!
Gadget gadget = Gadgets.newGadget(name, options);!
Gadget gadget = Gadgets.newGadget(id, enabled);!
Gadget gadget = Gadgets.newGadget(id, name, enabled);!
What if different parameter
combinations should be supported?
public class GadgetBuilder() {!
!
// ...!
Long id;!
String name;!
!
GadgetBuilder withId(Long id) {!
this.id = id;!
return this;!
}!
!
GadgetBuilder withName(String name) {!
this.name = name;!
return this;!
}!
!
Gadget build() {!
Gadget gadget = new GadgetImpl();!
gadget.setId(id);!
gadget.setName(name);!
gadget.setOptions(options);!
gadget.setEnabled(enabled)!
}!
}
Covering all
possibilities
// Quartz Trigger Builder Example!
trigger = newTrigger()!
.withIdentity("trigger3", "group1")!
.withSchedule(cronSchedule("0 0/2 8-17 * * ?"))!
.forJob("myJob", "group1")!
.build();
// Constructing stuff using builder!
Gadget gadget = new GadgetBuilder()!
.withId(1)!
.withName(“ok”)!
.withOptions(options)!
.build();
Much better now!
Lets build a
Gadget Service
Gadget Service
public final class GadgetService {!
!
private static final GadgetService instance = new GadgetService();!
!
public static void getInstance() {!
return instance;!
}!
!
public void saveGadget(Gadget gadget) {!
...!
}!
}
Static fields may produce memory leaks	

Difficult to test code using that
Gadget Service
public class GadgetServiceImpl implements GadgetService {!
!
// To be called by factory method/class!
public GadgetServiceImpl() {}!
!
public void saveGadget(Gadget gadget) {!
...!
}!
!
}!
!
!
public class MyClass {!
@Inject!
GadgetService service;!
}
Everyone is using
Dependency
Injection now
You do not know which 	

Dependency Injection
framework 	

developers will use!
Spring, Guice, CDI, Dagger, PicoContainer etc.
Abstract DI
public interface BeanRegistry {!
!
  void register(Class<?> type);!
!
  <T> T getBean(Class<T> type);!
!
  <T> Collection<T> getBeans(Class<T> type);!
!
}
https://github.com/DozerMapper/dozer/blob/master/core/src/main/java/org/dozer/inject/
DozerBeanContainer.java
Provide DI Bindings
• Write bindings for other frameworks	

• Your beans are accessible	

• Ready for the next big thing
public class SpringBeanRegistry implements BeanRegistry {!
public SpringBeanRegistry(ApplicationContext context) {!
//..!
}!
}
Make your api Extensible
interface Plugin {!
void init(Context context);!
}
How to allow
people to
contribute
extensions?
Service Provider Interface
http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html
ServiceLoader<Plugin> pluginLoader = ServiceLoader.load(Plugin.class);!
for (Plugin plugin : pluginLoader) {!
plugin.init(context);!
}
META-INF/services/lv.jug.api.Plugin
lv.jug.api.plugin1.Plugin
lv.jug.api.plugin2.Plugin!
lv.jug.api.plugin3.Plugin
class MyExtensionPlugin implements Plugin {!
@Override!
void init(Context context) {!
System.out.println(“Hello”);!
}!
}
SPI Benefits
• No static initialization	

• Automatic lookup in all Jars	

• Everything is initialized in one place
Annotation Scanning
• Mark extensions with custom annotations	

• Use bytecode scanning library
@Extension
final TypeReporter reporter = new TypeReporter() {!
!
@Override!
public Class<? extends Annotation>[] annotations() {!
return new Class[]{Extension.class};!
}!
!
@Override!
public void reportTypeAnnotation(Class<? extends Annotation> annotation, String className) {!
// do something!
}!
!
};!
final AnnotationDetector cf = new AnnotationDetector(reporter);!
cf.detect();
@Extension!
class MyExtensionPlugin implements Plugin {!
@Override!
void init(Context context) {!
System.out.println(“Hello”);!
}!
}
Finds all
annotated
classess
https://github.com/rmuller/infomas-asl
Annotation Benefits
• Instantiating and using via reflection	

• Easy API to explain	

• Quite fast
Method Level
List<String> myList = new ArrayList<>();!
updateList(myList);!
return myList;
void updateList(List<String> items) {!
for (Iterator<String> iterator=items.iterator();
iterator.hasNext();) {!
String item = iterator.next() {!
if (item.startsWith(“//”)) {!
iterator.remove();!
}!
}!
}
Modifying mutable parameters
List<Item> myList = new ArrayList<>();!
List<Item> updatedList = updateItems(myList);!
return updatedList;
List<String> updateList(final List<String> items) {!
List<String> result = new ArrayList<>();!
for (String item : items) {!
if (!item.startsWith(“//”)) {!
result.add(item);!
}!
}!
return result;!
}
Considering all
method
arguments as
immutable
try {!
downloadPhoto(id, path);!
} catch(ConnectionNotAvailable | PhotoNotFound e) {!
System.out.println(“WAT!?”);!
}
void downloadPhoto(String id, Path path) !
throws ConnectionNotAvailable, PhotoNotFound {!
...!
}
Have to handle all exceptions
downloadPhoto(id, path);
void downloadPhoto(String id, Path path) {!
...!
}
Rely on Runtime
Exceptions
void uploadPhoto(byte[] photo, String name, String type) {!
...!
}
What if photo is too big?	

What types are supported? RTFM?
void uploadPhoto(InputStream photo,!
String name, !
PhotoType type) {!
...!
}!
!
public enum PhotoType {!
JPEG, PNG!
}
Pass binaries as
InputStreams
Create enum for
parameters
PhotoService photoService = ...!
photoService.openTransaction();!
try {!
photoService.uploadPhoto(...);!
photoService.changeAttributes(...);!
} catch (Exception e) {!
photoService.rollbackTransaction();!
} finally {!
photoService.commitTransaction();!
}
Just boring...
PhotoService photoService = ...!
photoService.doInTransaction(new Execution() {!
public void work(Context context) {!
context.uploadPhoto(...);!
context.changeAttributes(...);!
}!
});!
!
public void doInTransaction(Execution execution) {!
Context context = openTransactionContext();!
try {!
execution.work(context);!
} catch (Exception e) {!
context.rollback();!
} finally {!
context.commit();!
}!
}
Writing it once
PhotoService photoService = ...!
photoService.doInTransaction(context -> {!
context.uploadPhoto(...);!
context.changeAttributes(...);!
});
Java 8
public Object someServiceMethod() {!
return transactionTemplate.execute(new TransactionCallback() {!
!
// the code in this method executes in a transactional context!
public Object doInTransaction(TransactionStatus status) {!
updateOperation1();!
return resultOfUpdateOperation2();!
}!
});!
}
Same approach in Spring Framework
I learned something
today!
All APIs operate on
single set of
rules & patterns
APIs have
fashion too
Java API	

from 1998
Java API	

from 2013
You have to follow
fashion trends to ride
APIs
• Treat all reusable classes you write as API	

• Use minimum API principle	

• Learn by example from open source
projects
Recommended Books
Developing Useful APIs

Developing Useful APIs

  • 1.
    Developing Useful APIs DmitryBuzdin October 2013, Riga
  • 2.
  • 3.
  • 4.
    API is thecode you use every day
  • 5.
    How many Jarsdo you have in your classpath? from 20 to100 jars?
  • 6.
    Each library has its ownAPI ! and personality
  • 7.
    Moreover, you create newreusable APIs inside your project may be even in a separate module
  • 8.
    APIs are writtenby developers for developers
  • 9.
  • 10.
    Frameworks are turning intomicro- frameworks
  • 11.
    I have to learn100 APIs? ! Is it possible at all?
  • 12.
  • 13.
    The best codein the world is the one I wrote yesterday!
  • 14.
  • 15.
    Are all APIsdifferent?
  • 16.
  • 17.
    What is aGood API • Easy to read • Easy to use • Hard to misuse • Easy to extend
  • 18.
    How to AchieveThat? • Lets take a look at some: • module/package level approaches • class level patterns • method/code level idioms
  • 19.
    Imagine building APIfor the next 10 years and 1000s of people
  • 20.
  • 21.
    Dependency Management • Putless transitive dependencies • Do you really need that commons-lang? • Do you remember about Guava incompatibilities Extreme example: OrientDB - zero dependencies!
  • 22.
  • 23.
  • 24.
  • 25.
    Lets build anAPI for a reusable gadget
  • 26.
    Gadget gadget =new Gadget(name, id, options);! // Gadget is connected at this point public Gadget(name, id, options) {! this.name = name;! this.id = id;! this.options = options;! connect(); // could throw an exception! } Gadgets should always be connected Can not create an instance for testing
  • 27.
    Create Gadget bystatic method or factory class public Gadget(name, id, options) {! this.name = name;! this.id = id;! this.options = options; ! }! ! public static Gadget newGadget(name, id, options) {! Gadget gadget = new Gadget(name, id, options);! gadget.connect();! return gadget;! }! ! public class GadgetFactory {! public Gadget newGadget(name, id, options) {! Gadget gadget = new Gadget(name, id, options);! gadget.connect();! return gadget;! } ! }
  • 28.
    public static GadgetnewGadget(name, id, options) {! Gadget gadget = new DefaultGadget(name, id, options);! gadget.connect();! return gadget;! }! ! public interface Gadget {! void connect();! }! ! public class DefaultGadget implements Gadget {! public void connect() {! }! } Hide your gadget behind interface Because you could change the implementation Details are well hidden
  • 29.
    public static GadgetnewGadget(name, id, options) {! Gadget gadget = new DefaultGadget(name, id, options);! gadget.connect();! return gadget;! }! ! public interface Gadget {! void connect();! }! ! public final class DefaultGadget implements Gadget {! DefaultGadget() {! }! public void connect() {! }! } Make it final with package-level constructor Disallow unsanctioned modification of your code
  • 30.
    Open Closed Principle "softwareentities (classes, modules, functions, etc.) ! should be open for extension, but closed for modification" public final class DefaultGadget implements Gadget {! public void setStrategy(BehaviorStrategy s) {! // changes the behavior of this Gadget;! }! } Allowing sanctioned modifications
  • 31.
    Gadget gadget =Gadgets.newGadget(name, id, options);! // Gadget is connected at this point! ! ! // Similar APIs! Files.createFile(...); // JDK 7! Lists.newArrayList(...); // Guava Resulting code
  • 32.
    Method Overloading Gadget gadget= Gadgets.newGadget(name, id, options);! Gadget gadget = Gadgets.newGadget(id, options);! Gadget gadget = Gadgets.newGadget(name, options);! Gadget gadget = Gadgets.newGadget(id, enabled);! Gadget gadget = Gadgets.newGadget(id, name, enabled);! What if different parameter combinations should be supported?
  • 33.
    public class GadgetBuilder(){! ! // ...! Long id;! String name;! ! GadgetBuilder withId(Long id) {! this.id = id;! return this;! }! ! GadgetBuilder withName(String name) {! this.name = name;! return this;! }! ! Gadget build() {! Gadget gadget = new GadgetImpl();! gadget.setId(id);! gadget.setName(name);! gadget.setOptions(options);! gadget.setEnabled(enabled)! }! } Covering all possibilities
  • 34.
    // Quartz TriggerBuilder Example! trigger = newTrigger()! .withIdentity("trigger3", "group1")! .withSchedule(cronSchedule("0 0/2 8-17 * * ?"))! .forJob("myJob", "group1")! .build(); // Constructing stuff using builder! Gadget gadget = new GadgetBuilder()! .withId(1)! .withName(“ok”)! .withOptions(options)! .build(); Much better now!
  • 35.
  • 36.
    Gadget Service public finalclass GadgetService {! ! private static final GadgetService instance = new GadgetService();! ! public static void getInstance() {! return instance;! }! ! public void saveGadget(Gadget gadget) {! ...! }! } Static fields may produce memory leaks Difficult to test code using that
  • 37.
    Gadget Service public classGadgetServiceImpl implements GadgetService {! ! // To be called by factory method/class! public GadgetServiceImpl() {}! ! public void saveGadget(Gadget gadget) {! ...! }! ! }! ! ! public class MyClass {! @Inject! GadgetService service;! } Everyone is using Dependency Injection now
  • 38.
    You do notknow which Dependency Injection framework developers will use! Spring, Guice, CDI, Dagger, PicoContainer etc.
  • 39.
    Abstract DI public interfaceBeanRegistry {! !   void register(Class<?> type);! !   <T> T getBean(Class<T> type);! !   <T> Collection<T> getBeans(Class<T> type);! ! } https://github.com/DozerMapper/dozer/blob/master/core/src/main/java/org/dozer/inject/ DozerBeanContainer.java
  • 40.
    Provide DI Bindings •Write bindings for other frameworks • Your beans are accessible • Ready for the next big thing public class SpringBeanRegistry implements BeanRegistry {! public SpringBeanRegistry(ApplicationContext context) {! //..! }! }
  • 41.
    Make your apiExtensible interface Plugin {! void init(Context context);! } How to allow people to contribute extensions?
  • 42.
    Service Provider Interface http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html ServiceLoader<Plugin>pluginLoader = ServiceLoader.load(Plugin.class);! for (Plugin plugin : pluginLoader) {! plugin.init(context);! } META-INF/services/lv.jug.api.Plugin lv.jug.api.plugin1.Plugin lv.jug.api.plugin2.Plugin! lv.jug.api.plugin3.Plugin class MyExtensionPlugin implements Plugin {! @Override! void init(Context context) {! System.out.println(“Hello”);! }! }
  • 43.
    SPI Benefits • Nostatic initialization • Automatic lookup in all Jars • Everything is initialized in one place
  • 44.
    Annotation Scanning • Markextensions with custom annotations • Use bytecode scanning library @Extension
  • 45.
    final TypeReporter reporter= new TypeReporter() {! ! @Override! public Class<? extends Annotation>[] annotations() {! return new Class[]{Extension.class};! }! ! @Override! public void reportTypeAnnotation(Class<? extends Annotation> annotation, String className) {! // do something! }! ! };! final AnnotationDetector cf = new AnnotationDetector(reporter);! cf.detect(); @Extension! class MyExtensionPlugin implements Plugin {! @Override! void init(Context context) {! System.out.println(“Hello”);! }! } Finds all annotated classess https://github.com/rmuller/infomas-asl
  • 46.
    Annotation Benefits • Instantiatingand using via reflection • Easy API to explain • Quite fast
  • 47.
  • 48.
    List<String> myList =new ArrayList<>();! updateList(myList);! return myList; void updateList(List<String> items) {! for (Iterator<String> iterator=items.iterator(); iterator.hasNext();) {! String item = iterator.next() {! if (item.startsWith(“//”)) {! iterator.remove();! }! }! } Modifying mutable parameters
  • 49.
    List<Item> myList =new ArrayList<>();! List<Item> updatedList = updateItems(myList);! return updatedList; List<String> updateList(final List<String> items) {! List<String> result = new ArrayList<>();! for (String item : items) {! if (!item.startsWith(“//”)) {! result.add(item);! }! }! return result;! } Considering all method arguments as immutable
  • 50.
    try {! downloadPhoto(id, path);! }catch(ConnectionNotAvailable | PhotoNotFound e) {! System.out.println(“WAT!?”);! } void downloadPhoto(String id, Path path) ! throws ConnectionNotAvailable, PhotoNotFound {! ...! } Have to handle all exceptions
  • 51.
    downloadPhoto(id, path); void downloadPhoto(Stringid, Path path) {! ...! } Rely on Runtime Exceptions
  • 52.
    void uploadPhoto(byte[] photo,String name, String type) {! ...! } What if photo is too big? What types are supported? RTFM?
  • 53.
    void uploadPhoto(InputStream photo,! Stringname, ! PhotoType type) {! ...! }! ! public enum PhotoType {! JPEG, PNG! } Pass binaries as InputStreams Create enum for parameters
  • 54.
    PhotoService photoService =...! photoService.openTransaction();! try {! photoService.uploadPhoto(...);! photoService.changeAttributes(...);! } catch (Exception e) {! photoService.rollbackTransaction();! } finally {! photoService.commitTransaction();! } Just boring...
  • 55.
    PhotoService photoService =...! photoService.doInTransaction(new Execution() {! public void work(Context context) {! context.uploadPhoto(...);! context.changeAttributes(...);! }! });! ! public void doInTransaction(Execution execution) {! Context context = openTransactionContext();! try {! execution.work(context);! } catch (Exception e) {! context.rollback();! } finally {! context.commit();! }! } Writing it once
  • 56.
    PhotoService photoService =...! photoService.doInTransaction(context -> {! context.uploadPhoto(...);! context.changeAttributes(...);! }); Java 8
  • 57.
    public Object someServiceMethod(){! return transactionTemplate.execute(new TransactionCallback() {! ! // the code in this method executes in a transactional context! public Object doInTransaction(TransactionStatus status) {! updateOperation1();! return resultOfUpdateOperation2();! }! });! } Same approach in Spring Framework
  • 58.
  • 59.
    All APIs operateon single set of rules & patterns
  • 60.
    APIs have fashion too JavaAPI from 1998 Java API from 2013
  • 61.
    You have tofollow fashion trends to ride APIs
  • 62.
    • Treat allreusable classes you write as API • Use minimum API principle • Learn by example from open source projects
  • 63.