From the Trenches: APIs

Background

  • Almost every (probably well over 99%) project uses an API
  • Lots of APIs are terrible
  • It's not hard to just do it the Right Way™
  • API and library can be thought of interchangably
  • Programming in PHP? You're using an API

Objectives

  • Discuss what an API should do
  • Discuss problems around designing an API
  • Discuss problems around implementing an API
  • Educate on how to solve these issues.

Qualifications

Who is this Guy?

"Devon H. O'Dell <devon.odell@messagesystems.com>"

Software Engineer - Team Lead; Message Systems, Inc.

Experience

  • 11+ years PHP experience
  • 11 years professional experience
  • Many open source contributions (FreeBSD, Google's Go, PHP, more)
  • Author; Professional PHP4 Programming, Professional PHP4 Multimedia Programming
  • Software development lifecycle in C, PHP, Python, Perl, Java

Contact:

@dhobsd, twitter; LinkedIn; probably anywhere else you see dhobsd.

What Prompted this Talk?

  • I've used a lot of really, really, really bad APIs
  • Nobody talks about how to do it right
  • Universally applicable (not just REST/SOAP -- framework APIs benefit, too)
  • Too much information about API implementation
  • Not enough focus on making the API actually work
  • Old hats can compare experience and heckle
  • The Internet is full of bad (and some good) information
  • You will write an API at some point, please do it the Right Way™

The Good

What Makes a Good API?

  • Easy to learn and use
  • Conversely (but distinct!): hard to misuse
  • Solves a problem as minimally as possible (but no less)
  • Solves a problem
  • Reusable

The Bad and The Ugly

What Makes a Bad API?

  • Side-effects
  • Lack of documentation
  • Inconsistency in interfaces
  • Over-engineering
  • Bulk

Side-effects

Definition

In computer science, a function or expression is said to have a side effect if, in addition to returning a value, it also modifies some state or has an observable interaction with calling functions or the outside world.

Practical Examples

  • Causing the calling code to exit
  • Causing calling code to perform unacceptably poorly
  • Changing state of a program
  • Closing resources associated with user-supplied data

Point

  • Don't Do This

Lack of Documentation

  • Nobody will use it if they can't figure it out
  • You won't remember how to use it in a year
  • Documentation should clarify functionality, not explain it.
  • Principle of least astonishment

Interface Inconsistencies

  • Don't mix-and-match coding conventions
  • Don't mix-and-match return value types
  • Don't mix-and-match input types
  • Don't mix-and-match...

Over-Engineering and Bulk

  • Your API solves one problem, and solves it well
  • Less is more; "when it doubt, leave it out"
  • Performance is important, but not at the cost of an incomprehensible interface.

Making Your API Usable

Usability: Error early

 1 <?php
 2   class Foo {
 3     public function process_file($filename) {
 4       if (!is_readable($filename)) {
 5         return null;
 6       }
 7 
 8       $fp = fopen($filename, 'r');
 9       if ($fp == false) {
10         return null;
11       }
12 
13       /* ... */
14 
15       return $processed_file
16     }

Usability: Consistent naming

1 <?php
2   class Foo {
3     public function camelCase() {}
4     public function under_scored() {}
5     public function reallylongname() {}
6   }

Usability: Long parameter lists

1 <?php
2   class Foo {
3     public function bar($path, $mode, $outdir, $outmode,
4       $flags, $reverse) {}
5   }

Usability: Consistency in params

PHP itself is in horrific violation of this. Does this look familiar to anyone?

1 <?php
2   class Foo {
3     public function array_search($needle, $haystack) {}
4     public function string_search($haystack, $needle) {}
5   }

Usability: Consistency in retvals

 1 <?php
 2   class Foo {
 3     public function sort($array) {
 4       if (!is_array($array)) {
 5         return false;
 6       }
 7 
 8       return usort($array, array('Foo', 'do_sort'));
 9     }
10 
11     public function min($array) {
12       asort($array);
13 
14       if (!is_numeric($array[0])) {
15         return false;
16       }
17 
18       return $array[0];
19     }
20   }

Usability: Avoid "God Objects"

  • Call ordering can be obfuscated
  • Requires new object instances or reference passing to modify new data
  • Confuses traditional object models
  • Almost requires side-effects to the underlying object
  • Inefficient for a language like PHP

Usability: Final Suggestions

  • Versioning is vital
  • Start out with a good idea of what you're doing
  • Determine what problem you are trying to solve
  • Don't solve problems you're not trying to solve
  • Prototype early
  • Consider use cases when prototyping
  • Implement use cases when prototyping

Questions?