Your SlideShare is downloading. ×
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Writing Usable APIs in Practice by Giovanni Asproni
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Writing Usable APIs in Practice by Giovanni Asproni

176

Published on

Explicitly or implicitly, when working on complex systems, end up designing some APIs to accomplish their tasks, either because the product itself is some kind of general purpose library or because …

Explicitly or implicitly, when working on complex systems, end up designing some APIs to accomplish their tasks, either because the product itself is some kind of general purpose library or because they need to write some libraries and packages to put some common code of their applications.

There is plenty of information available about how to write clean and maintainable code, but not a lot about writing usable APIs. The two things are related, but they are not the same. In fact, clean code is code that is clean from the point of view of its maintainers, usable APIs, on the other hand, refer to code that programmers (other than the original author) find easy to use. We'll see how usable APIs help in writing clean code (and vice-versa).

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
176
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Writing usable APIs in practice SyncConf 2013 Giovanni Asproni gasproni@asprotunity.com @gasproni
  • 2. Summary• API definition• Two assumptions• Why bother with usability• Some usability concepts• Some techniques to improve usability
  • 3. API“Any well-defined interface that definesthe service that one component, module,or application provides to other softwareelements” From: “Sometimes You Need to See Through Walls — A Field Study of Application Programming Interfaces”, Cleidson R. B. de Souza et al., http://www.ufpa.br/cdesouza/ pub/p390-desouza.pdf
  • 4. Package java.io Provides for system input and output through data streams, serialization and the file system. See: Description Interface Summary Interface Description Closeable A Closeable is a source or destination of data that can be closed. DataInput The DataInput interface provides for reading bytes from a binary stream and reconstructing from them data in any of the Java primitive types. DataOutput The DataOutput interface provides for converting data from any of the Java primitive types to a series of bytes and writing these bytes to a binary stream. Externalizable Only the identity of the class of an Externalizable instance is written in the serialization stream and it is the responsibility of the class to save and restore the contents of its instances. FileFilter A filter for abstract pathnames. FilenameFilter Instances of classes that implement this interface are used to filter filenames. Flushable A Flushable is a destination of data that can be flushed. ObjectInput ObjectInput extends the DataInput interface to include the reading of objects. ObjectInputValidation Callback interface to allow validation of objects within a graph. ObjectOutput ObjectOutput extends the DataOutput interface to include writing of objects. ObjectStreamConstants Constants written into the Object Serialization Stream. Serializable Serializability of a class is enabled by the class implementing the java.io.Serializable interface. Class Summary Class Description BufferedInputStream A BufferedInputStream adds functionality to another input stream-namely, the ability to buffer the input and to support the mark and reset methods. BufferedOutputStream The class implements a buffered output stream. BufferedReader Reads text from a character-input stream, buffering characters so as to provide for the efficient reading of characters, arrays, and lines. BufferedWriter Writes text to a character-output stream, buffering characters so as to provide for the efficient writing of single characters, arrays, and strings. ByteArrayInputStream A ByteArrayInputStream contains an internal buffer that contains bytes that may be read from the stream. ByteArrayOutputStream This class implements an output stream in which the data is written into a byte array. CharArrayReader This class implements a character buffer that can be used as a character-input stream. CharArrayWriter This class implements a character buffer that can be used as an Writer. Console Methods to access the character-based console device, if any, associated with the current Java virtual machine. DataInputStream A data input stream lets an application read primitive Java data types from an underlying input stream in a machine-independent way. DataOutputStream A data output stream lets an application write primitive Java data types to an output stream in a portable way. File An abstract representation of file and directory pathnames. FileDescriptor Instances of the file descriptor class serve as an opaque handle to the underlying machine-specific structure representing an open file, an open socket, or another source or sink of bytes. FileInputStream A FileInputStream obtains input bytes from a file in a file system. FileOutputStream A file output stream is an output stream for writing data to a File or to a FileDescriptor. FilePermission This class represents access to a file or directory. FileReader Convenience class for reading character files. FileWriter Convenience class for writing character files. FilterInputStream A FilterInputStream contains some other input stream, which it uses as its basic source of data, possibly transforming the data along the way or providing additional functionality. FilterOutputStream This class is the superclass of all classes that filter output streams. FilterReader Abstract class for reading filtered character streams. FilterWriter Abstract class for writing filtered character streams. InputStream This abstract class is the superclass of all classes representing an input stream of bytes. InputStreamReader An InputStreamReader is a bridge from byte streams to character streams: It reads bytes and decodes them into characters using a specified charset. LineNumberInputStream Deprecated This class incorrectly assumes that bytes adequately represent characters. LineNumberReader A buffered character-input stream that keeps track of line numbers. ObjectInputStream An ObjectInputStream deserializes primitive data and objects previously written using an ObjectOutputStream. ObjectInputStream.GetField Provide access to the persistent fields read from the input stream. ObjectOutputStream An ObjectOutputStream writes primitive data types and graphs of Java objects to an OutputStream. ObjectOutputStream.PutField Provide programmatic access to the persistent fields to be written to ObjectOutput. ObjectStreamClass Serializations descriptor for classes. ObjectStreamField A description of a Serializable field from a Serializable class. OutputStream This abstract class is the superclass of all classes representing an output stream of bytes. OutputStreamWriter An OutputStreamWriter is a bridge from character streams to byte streams: Characters written to it are encoded into bytes using a specified charset. PipedInputStream A piped input stream should be connected to a piped output stream; the piped input stream then provides whatever data bytes are written to the piped output stream. PipedOutputStream A piped output stream can be connected to a piped input stream to create a communications pipe. PipedReader Piped character-input streams. PipedWriter Piped character-output streams. PrintStream A PrintStream adds functionality to another output stream, namely the ability to print representations of various data values conveniently. PrintWriter Prints formatted representations of objects to a text-output stream. PushbackInputStream A PushbackInputStream adds functionality to another input stream, namely the ability to "push back" or "unread" one byte. PushbackReader A character-stream reader that allows characters to be pushed back into the stream. RandomAccessFile Instances of this class support both reading and writing to a random access file. Reader Abstract class for reading character streams. SequenceInputStream A SequenceInputStream represents the logical concatenation of other input streams. SerializablePermission This class is for Serializable permissions. StreamTokenizer The StreamTokenizer class takes an input stream and parses it into "tokens", allowing the tokens to be read one at a time. StringBufferInputStream Deprecated This class does not properly convert characters into bytes. StringReader A character stream whose source is a string. StringWriter A character stream that collects its output in a string buffer, which can then be used to construct a string. Writer Abstract class for writing to character streams. Exception Summary Exception Description CharConversionException Base class for character conversion exceptions. EOFException Signals that an end of file or end of stream has been reached unexpectedly during input. FileNotFoundException Signals that an attempt to open the file denoted by a specified pathname has failed. InterruptedIOException Signals that an I/O operation has been interrupted. InvalidClassException Thrown when the Serialization runtime detects one of the following problems with a Class. InvalidObjectException Indicates that one or more deserialized objects failed validation tests. IOException Signals that an I/O exception of some sort has occurred. NotActiveException Thrown when serialization or deserialization is not active. NotSerializableException Thrown when an instance is required to have a Serializable interface. ObjectStreamException Superclass of all exceptions specific to Object Stream classes. OptionalDataException Exception indicating the failure of an object read operation due to unread primitive data, or the end of data belonging to a serialized object in the stream. StreamCorruptedException Thrown when control information that was read from an object stream violates internal consistency checks. SyncFailedException Signals that a sync operation has failed. UnsupportedEncodingException The Character Encoding is not supported. UTFDataFormatException Signals that a malformed string in modified UTF-8 format has been read in a data input stream or by any class that implements the data input interface. WriteAbortedException Signals that one of the ObjectStreamExceptions was thrown during a write operation. Error Summary Error Description IOError Thrown when a serious I/O error has occurred. Package java.io Description Provides for system input and output through data streams, serialization and the file system. Unless otherwise noted, passing a null argument to a constructor or method in any class or interface in this package will cause a NullPointerException to be thrown. Package Specification Java Object Serialization Specification Related Documentation For overviews, tutorials, examples, guides, and tool documentation, please see: Serialization Enhancements Since: JDK1.0 Java™ PlatformOverview Package Class Use Tree Deprecated Index Help Standard Ed. 7Prev Package Next Package Frames No Frames All ClassesSubmit a bug or feature
  • 5. Public and private APIs• Public APIs • Given to third parties• Private APIs • For internal use
  • 6. First assumptionAny non trivial software applicationinvolves writing one or more APIs
  • 7. Second assumptionWhen we talk about good codewe always mean usable code aswell
  • 8. Why bother (company’s perspective)• APIs can be among a companys greatest assets• Can also be among companys greatest liabilities Adapted from: “How to Design a Good API and Why it Matters”, Joshua Bloch, http://lcsd05.cs.tamu.edu/slides/ keynote.pdf
  • 9. Why bother (programmer’s perspective)• Fewer bugs to take care of• Code of higher quality• More productivity
  • 10. AffordancesAn affordance is a quality of an object, oran environment, that allows an individualto perform an action. From: http://en.wikipedia.org/wiki/Affordance
  • 11. Affordances: processing file line by line (Java 6)BufferedReader reader;try { reader = new BufferedReader(new FileReader(“filename“)); while (true) { String line = reader.readLine(); if (line == null) { break; } processLine(line); }}catch (Exception exc) { // Do something here...}finally { if (reader != null) { reader.close(); }}
  • 12. Affordances that are easier to see (Java 7)try { Path filePath = FileSystems.getDefault().getPath("filename"); Charset charset = Charset.defaultCharset(); for (String line : Files.readAllLines(filePath, charset)) { processLine(line); }} catch (IOException e) { // Do something here}
  • 13. And even easier (Python 3) with open("filename") as infile: for line in infile.readlines(): processLine(line)
  • 14. Some cognitive dimensions• Abstraction level. The minimum and maximum levels of abstraction exposed by the API• Working framework. The size of the conceptual chunk (developer working set) needed to work effectively• Progressive evaluation. To what extent partially completed code can be executed to obtain feedback on code behaviour• Penetrability. How the API facilitates exploration, analysis, and understanding of its components• Consistency. How much of the rest of an API can be inferred once part of it is learned Adapted from: “Measuring API Usability”, Steven Clarke, http://drdobbs.com/windows/184405654
  • 15. BufferedReader reader;try { reader = new BufferedReader(new FileReader(“filename“)); while (true) { String line = reader.readLine(); if (line == null) { break; } processLine(line); }} • Abstractioncatch (Exception exc) { level. // Do something here...} • Working framework.finally { if (reader != null) { • Progressive reader.close(); evaluation. }} • Penetrability. • Consistency.
  • 16. try { Path filePath = FileSystems.getDefault().getPath("filename"); Charset charset = Charset.defaultCharset(); for (String line : Files.readAllLines(filePath, charset)) { processLine(line); }} catch (IOException e) { • Abstraction level. // Do something here} • Working framework. • Progressive evaluation. • Penetrability. • Consistency.
  • 17. with open("filename") as infile: for line in infile.readlines(): processLine(line) • Abstraction level. • Working framework. • Progressive evaluation. • Penetrability. • Consistency.
  • 18. “Make Interfaces Easy to Use Correctlyand Hard to Use Incorrectly” Scott Meyers, “97 Things Every Programmer Should Know”
  • 19. Some techniques• User’s perspective• Naming• Give control to the caller• Explicit context• Error reporting• Logging as a feature• Incremental design
  • 20. • User’s perspective• Naming• Give control to the caller• Explicit context• Error reporting• Logging as a feature• Incremental design
  • 21. “Ask, ‘What Would the UserDo?’ (You Are Not the User)” Giles Colborne, “97 Things Every Programmer Should Know”
  • 22. Golden Rule of API Design“It’s not enough to write tests for an API you develop; youhave to write unit tests for code that uses your API. Whenyou follow this rule, you learn firsthand the hurdles thatyour users will have to overcome when they try to testtheir code independently.” Michael Feathers, “97 Things Every Programmer Should Know”
  • 23. TDD• It puts you in the shoes of an user • If writing a test is painful, the design may be wrong• Tests will provide up to date documentation and examples of use
  • 24. TDD helps with• Abstraction level. It helps to limit the number of abstractions in mainline scenarios• Working framework• Progressive evaluation• Penetrability. It provides examples on how the various components interact with each other• Consistency. It is maintained by refactoring the code Adapted from: “Measuring API Usability”, Steven Clarke, http://drdobbs.com/windows/184405654
  • 25. File file = new File(“filename“));try { for (String line : file.readLines()) { processLine(line); }}finally { file.close()}
  • 26. BufferedReader reader;try { reader = new BufferedReader(new FileReader(“filename“)); while (true) { String line = reader.readLine(); if (line == null) { break; } processLine(line); }}catch (Exception exc) { // Do something here...}finally { if (reader != null) { reader.close(); }}
  • 27. • User’s perspective• Naming• Give control to the caller• Explicit context• Error reporting• Logging as a feature• Incremental design
  • 28. • Reserve the simplest and most intuitive names names for the entities used in the most common scenarios• Pick one word per concept• Don’t be cute!
  • 29. • User’s perspective• Naming• Give control to the caller• Explicit context• Error reporting• Logging as a feature• Incremental design
  • 30. What’s wrong with these?public interface Startable { Startable start() throws AlreadyStartedException;}public interface Stoppable { Stoppable stop() throws AlreadyStoppedException;}
  • 31. A better alternativepublic interface Service { void start() throws AlreadyStartedException; void stop() throws AlreadyStoppedException; boolean isStarted();}
  • 32. • User’s perspective• Naming• Give control to the caller• Explicit context• Error reporting• Logging as a feature• Incremental design
  • 33. Explicit context• Assumptions about the external environment• There are two kinds of context we are interested in • Deployment context • Runtime context
  • 34. Deployment context• Dependencies on other APIs• Assumptions on deployment paths• User permissions• etc.
  • 35. Runtime context• Preconditions for calling methods (or functions) or instantiating classes• Initialisation (and finalisation) steps• etc.
  • 36. Global state• Difficult to use in a concurrent environment• Can make test setup extremely hard• Can make functionality difficult to use by hiding dependencies
  • 37. • User’s perspective• Naming• Give control to the caller• Explicit context• Error reporting• Logging as a feature• Incremental design
  • 38. Error reporting• Error reporting code is important for usability• Users need to know • How errors are reported • What is reported when • What they can do about them
  • 39. Error recovery• Make recovery easy to do • Error codes • Exception classes • A mix of the above• Text messages are usually not good enough
  • 40. What is an error at one level.......May not be an error at another one
  • 41. • User’s perspective• Naming• Give control to the caller• Explicit context• Error reporting• Logging as a feature• Incremental design
  • 42. Two types of logging• Support logging (errors and info) is part of the user interface of the application. These messages are intended to be tracked by support staff and operators to monitor the running system• Diagnostic logging (debug and trace) is infrastructure for programmers. Not for production Adapted from: “Growing Object Oriented Code Driven by Tests”, Steve Freeman and Nat Pryce, Addison Wesley
  • 43. Location location = tracker.getCurrentLocation();for (Filter filter : filters) { filter.selectFor(location); if (logger.isInfoEnabled()) { logger.info("Filter " + filter.getName() + ", " + filter.getDate() + " selected for " + location.getName() + ", is current: " + tracker.isCurrent(location)); }} From: “Growing Object Oriented Code Driven by Tests”, Steve Freeman and Nat Pryce, Addison Wesley
  • 44. Location location = tracker.getCurrentLocation();for (Filter filter : filters) { filter.selectFor(location); support.notifyFiltering(tracker, location, filter);} From: “Growing Object Oriented Code Driven by Tests”, Steve Freeman and Nat Pryce, Addison Wesley
  • 45. Give the programmer a choice• It should be possible to turn logging on and off• When on, give programmers a chance to use logging on their own terms
  • 46. • User’s perspective• Naming• Give control to the caller• Explicit context• Error reporting• Logging as a feature• Incremental design
  • 47. Conceptual integrityI will contend that conceptual integrityis the most important consideration insystem design. It is better to have asystem omit certain anomalousfeatures and improvements, but toreflect one set of design ideas, than tohave one that contains many good butindependent and uncoordinated ideas. Fred Brooks, “The Mythical Man Month”
  • 48. Start specific and small• Start with the 80% case first• It is easier to remove constraints rather than to add them later• YAGNI
  • 49. A caveat• Public APIs are more difficult to refactor. In fact, some errors may actually become features• Techniques to refactor them usually involve some form of deprecation and versioning
  • 50. • User’s perspective• Naming• Give control to the caller• Explicit context• Error reporting• Logging as a feature• Incremental design
  • 51. Links• http://www.apiusability.org• “Sometimes You Need to See Through Walls — A Field Study of Application Programming Interfaces”, Cleidson R. B. de Souza et al., http://www.ufpa.br/ cdesouza/pub/p390-desouza.pdf• “Measuring API Usability”, Steven Clarke, http://drdobbs.com/windows/ 184405654• http://en.wikipedia.org/wiki/Affordance• “How to Design a Good API and Why it Matters”, Joshua Bloch, http:// lcsd05.cs.tamu.edu/slides/keynote.pdf• “What Makes APIs Difficult to Use?”, Minhaz Fahim Zibran, http:// paper.ijcsns.org/07_book/200804/20080436.pdf• http://www.codeproject.com/Articles/8707/API-Usability-Guidelines-to- improve-your-code-ease
  • 52. Books ptg6931361From the Library of Giovanni Asproni

×