28
Practices and Tools for Building Better APIs Peter Hendriks - IT Architect, Info Support BV CON4374

Practices and Tools for Building Better APIs

Embed Size (px)

DESCRIPTION

The most important part of well-designed Java code is a nice API. A good API helps developers be more productive and write high-quality code quickly. API design matters for any developer, especially in building larger systems with a team. Modern coding tools such as Eclipse and FindBugs contain advanced tooling to help with designing an API and checking for bad usage. This session demonstrates the latest innovations, including new capabilities in Java 8, by presenting realistic examples based on real experiences in large codebases. They show that just a few Java tricks and simple annotations can make all the difference for building a great API.

Citation preview

Page 1: Practices and Tools for Building Better APIs

Practices and Tools for Building Better APIs

Peter Hendriks - IT Architect, Info Support BVCON4374

Page 2: Practices and Tools for Building Better APIs

About Peter

• Working at Info Support…• In a country, far, far away…• Netherlands, Europe

• Coding on challengingJava applications

Page 3: Practices and Tools for Building Better APIs

Objectives of this talk

• Focus on Java application developer perspective

• What is an API and why should you care about it• How you can identify and build better APIs• Measuring API in an existing codebase

Page 4: Practices and Tools for Building Better APIs

What is an API

• Code that is directly used to connect two software modules• “API Consumer”: module that calls the API• “API Implementer”: module that provides behavior for API

public class CollectionsDemo { public static void main(String args[]) { // create an array of string objs String init[] = { "One", "Two", "Three" }; // create one list List list = new ArrayList(Arrays.asList(init)); System.out.println("List value before: "+list); // sort the list Collections.sort(list); System.out.println("List value after: "+list); }}

// Load expected data from an XML datasetIDataSet expectedDataSet = new FlatXmlDataSetBuilder() .build(new File("expectedDataSet.xml"));

<dataset> <PERSON NAME="Bob" LAST_NAME="Doe" AGE="18"/> <PERSON NAME="Alice" LAST_NAME="Foo" AGE="23"/> <PERSON NAME="Charlie" LAST_NAME="Brown" AGE="42"/></dataset>

Page 5: Practices and Tools for Building Better APIs

API is key to a successful module designEssential for building large-scale software:• Reuse• Independent change• Separation of concerns

Modular design key to support agile practices at scaleShared code

Customer Front-End

Warehouse Front-End

Order Management

Page 6: Practices and Tools for Building Better APIs

You are using a lot of APIs

• Modern software development relies on reuse of modules• OS, Java Platform, Libraries, Application

Server, etc.

• System to System APIs increasingly important• Many public APIs like Twitter, Google,

Facebook, SalesForce, etc.• SOA

Java SE

Java EE

Log4j Spring

Module

Module Module

OS

Twitter Auth

Database

SOA

Page 7: Practices and Tools for Building Better APIs

Distance to API implementation increasing• API quality matters more when implementation becomes a black box

You

Same team Different team Open source Binary only Other datacenter

API Impl

Page 8: Practices and Tools for Building Better APIs

The API we use shapes our code

• Most code we write calls an API• Code that calls an API is shaped to fit the API• Therefore, APIs determine the shape of application code• In some ways, even more impactful than high level design, test driven

development or code craftsmanship

Page 9: Practices and Tools for Building Better APIs

http://docs.oracle.com/javaee/1.4/tutorial/examples/jaxp/xslt/samples/TransformationApp04.java

public class TransformationApp04 { public static void main(String[] argv) { if (argv.length != 1) { System.err.println("Usage: java TransformationApp filename"); System.exit(1); }

// Create the sax "parser". AddressBookReader02 saxReader = new AddressBookReader02();

try { File f = new File(argv[0]);

// Use a Transformer for output TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer();

// Use the parser as a SAX source for input FileReader fr = new FileReader(f); BufferedReader br = new BufferedReader(fr); InputSource inputSource = new InputSource(fr); SAXSource source = new SAXSource(saxReader, inputSource); StreamResult result = new StreamResult(System.out); transformer.transform(source, result); } catch (TransformerConfigurationException tce) { // Error generated by the parser System.out.println("\n** Transformer Factory error"); System.out.println(" " + tce.getMessage());

// Use the contained exception, if any Throwable x = tce;

if (tce.getException() != null) { x = tce.getException(); }

x.printStackTrace(); } catch (TransformerException te) { // Error generated by the parser System.out.println("\n** Transformation error"); System.out.println(" " + te.getMessage());

// Use the contained exception, if any Throwable x = te;

if (te.getException() != null) { x = te.getException(); }

x.printStackTrace(); } catch (IOException ioe) { // I/O error ioe.printStackTrace(); } } // main }

Doing stuff with XML…

var json_data = JSON.stringify(obj);

Page 10: Practices and Tools for Building Better APIs

Trademarks of a better API

Page 11: Practices and Tools for Building Better APIs

Trademarks of a better API

1. Valuable (always important)• Value = benefits - costs

2. Usable (more important if used more)• Easy to learn, productive, error-proof

3. Stable (more important if used more and longer)• Able to enhance and grow features without breaking existing consumer code

Page 12: Practices and Tools for Building Better APIs

API Design == Human Interface design• Although API is for machine/machine interaction, APIs are interpreted

by programmers to write the code• Programmers are humans!

API is not just about capability and structural design, but also about human understanding

Page 13: Practices and Tools for Building Better APIs

API Usability quantified

Generic usability model by Ben Shneiderman:• Learnability: How easy is it to accomplish basic tasks the first time?• Efficiency: Once users learned the design, how quickly can they

perform tasks?• Memorability: When users return after a while, how easily can they

re-establish proficiency?• Errors: How many errors do users make, how severe are these errors,

and how easily can they recover from the errors?• Satisfaction: How pleasant is it to use the design?

Page 14: Practices and Tools for Building Better APIs

Building Better APIs

Page 15: Practices and Tools for Building Better APIs

Designing an API: multiple perspectives

public class Document {

private List<Page> pages = new ArrayList<>();

public Page addPage() { Page page = new Page(); pages.add(page); page.setPageNumber(pages.size()); return page; } public void report() {...}}

document.addPage().setContents("Once upon a time...");

UML: Names, Completeness, Grouping

Implementation: can it be built

API usage: how usable is it

Page 16: Practices and Tools for Building Better APIs

Initial design: examples first

• Examples most important in API documentation• Concrete use case, usability check

• Make examples exemplary• Example code will be copy-pasted

• Create a cheat sheet• Improves learnability• Shows design issues

Full Java EE cheat sheet on: http://www.physics.usyd.edu.au/~rennie/javaEEReferenceSheet.pdf

Page 17: Practices and Tools for Building Better APIs

When in doubt leave it out

• Smaller APIs are easier to use and maintain• Less classes• Less methods• Less parameters/return values

• Easier to add API later vs removing or changing it• Having a small API increases stability

Page 18: Practices and Tools for Building Better APIs

Limit API consumer code to a minimum• Some API constructs lead to verbose consumer code• Extending class/implementing interface• Checked Exception• Required casting• Required Generic Type• Hard coded parameter value• Required if, for, while, try• Required synchronization/locking

Page 19: Practices and Tools for Building Better APIs

Example: limiting logging code

// classic debug call (log4j 1.x)// check debug to prevent string creationif(logger.isDebugEnabled()) { logger.debug("The new entry is " + entry + ".");}

// parameterized logging (slf4j)logger.debug("The new entry is {}.", entry);

public void debug(Object message) { if (isDebugEnabled()) { // .. implementation }}

public void debug(String format, Object arg) { if (isDebugEnabled()) { // .. implementation }}

Using Log4J API Using SLF4J API

SLF4J ImplementationLog4J Implementation

Better

Page 20: Practices and Tools for Building Better APIs

Java 8 Lambda expressions

List<Integer> numbers = Arrays.asList(1, 2);

for (int number : numbers) { if (numbers % 2 == 0) {  System.out.println(number); }}

forEachEven(numbers, value -> System.out.println(value));

forEachEven(numbers, new Consumer<Integer>() {  public void accept(Integer value) {    System.out.println(value);  }});

Without Lambda expressions With Lambda

Better

Page 21: Practices and Tools for Building Better APIs

Be predictable and obvious

• Methods should be able to be called in any order• Constructor should only construct• Don’t have surprising side effects

public class TopicListener { public TopicListener(Topic topic) { if (!topic.register(this)) throw new SystemException("error!"); }}

public class TopicListener { private final Topic topic; public TopicListener(Topic topic) { this.topic = topic; } public void start() { if (!topic.register(this)) throw new SystemException("error!"); }}

Better

Page 22: Practices and Tools for Building Better APIs

Predictable state

• Limit the use of null as input or output• Fail fast, fail hard on wrong input

public void save(String filename) { Objects.requireNonNull(filename); ... // save happens here}

public void save(String filename) { if (filename == null) { return; // bad api: error is ignored! } ... // save happens here}

Better

Page 23: Practices and Tools for Building Better APIs

FindBugs and JSR 305

• JSR 305: Annotations for Software Defect Detection (Dormant)• @Nonnull: may never be null• @CheckForNull: should always be checked before dereferenced• @Nullable: caller decides if null check is needed

• Alternatives: Checker framework, Eclipse, IntelliJ IDEA

Page 24: Practices and Tools for Building Better APIs

FindBugs demo in Eclipse

Page 25: Practices and Tools for Building Better APIs

Investigating existing codebases

• People• Team knowledge• Policy, “best practices”, conventions• Elaborate explanation necessary, “hard to do”• Bug list/exceptions/stack traces

• Tools:• Finding most used API: Dependency Structure Matrix (DSM)

Page 26: Practices and Tools for Building Better APIs

Dependency Structure Matrix

Document Page TextBlock

Document -

Page 2 -

TextBlock 10 -

Classes/Packages

# of direct dependencies from Document to Page

Page 27: Practices and Tools for Building Better APIs

Demo: SonarQube DSM matrix

Page 28: Practices and Tools for Building Better APIs

API design cheat sheet (Q & A)

A Better API is:1. Valuable 2. Usable 3. Stable

API usability:• Learnability• Efficiency• Memorability• Error rate• Satisfaction

API Design Perspectives:UML: names, completeness, groupingImplementation: can it be builtAPI usage: how usable is itExamples First

API Design practices:When in doubt leave it outLimit API consumer code to a minimum• Extending class/implementing interface• Checked Exception• Required casting• Required Generic Type• Hard coded parameter value• Required if, for, while, try• Required synchronization/locking

Be predictable and obvious• Methods should be calleable in any order• Constructor should only construct• Don’t have surprising side effects• Limit the use of null as input or output• Fail fast, fail hard on wrong input

Document Page TextBlock

Document -

Page 2 -

TextBlock 10 -

DSM: finding most used API

JSR 305/FindBugs:@Nonnull: may never be null@CheckForNull: always check@Nullable: caller decides null check

When API matters:• Modular design• Reuse 3rd party• Distance to impl.