Writing usableap isinpractice
-
Upload
gasproni -
Category
Technology
-
view
212 -
download
0
description
Transcript of Writing usableap isinpractice
© Asprotunity Ltd
email: [email protected] twitter: @gasproni linkedin: http://www.linkedin.com/in/gasproni
Writing usable APIs in practice
/dev/summer/2014
Have you been a victim of bad APIs?
© Asprotunity Ltd
© Asprotunity Ltd
When we talk about good code we always mean usable code as well
© Asprotunity Ltd
API
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
“Any well-defined interface that defines the service that one component, module, or application provides to other software elements”
© Asprotunity Ltd
Example: java.io package (Java 7)
• Interfaces: Closeable, DataInput, DataOutput, Externalizable, FileFilter, FilenameFilter, Flushable, ObjectInput, ObjectInputValidation, ObjectOutput, ObjectStreamConstants, Serializable
• Classes: BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter, ByteArrayInputStream, ByteArrayOutputStream, CharArrayReader, CharArrayWriter, Console, DataInputStream, DataOutputStream, File, FileDescriptor, FileInputStream, FileOutputStream, FilePermission, FileReader, FileWriter, FilterInputStream, FilterOutputStream, FilterReader, FilterWriter, InputStream, InputStreamReader, LineNumberInputStream, LineNumberReader, ObjectInputStream, ObjectInputStream.GetField, ObjectOutputStream, ObjectOutputStream.PutField, ObjectStreamClass, ObjectStreamField, OutputStream, OutputStreamWriter, PipedInputStream, PipedOutputStream, PipedReader, PipedWriter, PrintStream, PrintWriter, PushbackInputStream, PushbackReader, RandomAccessFile, Reader, SequenceInputStream, SerializablePermission, StreamTokenizer, StringBufferInputStream, StringReader, StringWriter, Writer
• Exceptions: CharConversionException, EOFException, FileNotFoundException, InterruptedIOException, InvalidClassException, InvalidObjectException, IOException, NotActiveException, NotSerializableException, ObjectStreamException, OptionalDataException, StreamCorruptedException, SyncFailedException, UnsupportedEncodingException, UTFDataFormatException, WriteAbortedException
• Errors: IOError
© Asprotunity Ltd
Any non trivial software application involves writing one or more APIs
© Asprotunity Ltd
Usability
• Efficiency
• Effectiveness
• Error prevention
• Ease of learning
© Asprotunity Ltd
Giovanni’s usability equation
• u is the usability
• b > 0. The brain power necessary to achieve your goals
• c > 0. A constant value
u = cb
© Asprotunity Ltd
Why bother (company’s perspective)
• APIs can be among a company's greatest assets
• Can also be among company's greatest liabilities
Adapted from: “How to Design a Good API and Why it Matters”, Joshua Bloch, http://lcsd05.cs.tamu.edu/slides/keynote.pdf
© Asprotunity Ltd
Why bother (programmer’s perspective)
• Fewer bugs to take care of
• Code of higher quality
• Solve more interesting problems
• More productivity
© Asprotunity Ltd
Public and private APIs
• Public APIs
• Given to third parties
• Private APIs
• For internal use
© Asprotunity Ltd
Affordances
An affordance is a quality of an object, or an environment, that allows an individual to perform an action.
From: http://en.wikipedia.org/wiki/Affordance
© Asprotunity Ltd
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
…
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(); } }
…
© Asprotunity Ltd
import java.nio.file.Path;
import java.nio.FileSystems;
import java.nio.charset.Charset;
…
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
}
…
© Asprotunity Ltd
import java.io.File;
import java.util.Scanner;
…
File file = new File("filename");
try {
Scanner scanner = new Scanner(file);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
processLine(line);
}
scanner.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
…
© Asprotunity Ltd
with open("filename") as infile: for line in infile.readlines(): processLine(line)
© Asprotunity Ltd
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. The extent to which a developer must understand the underlying implementation details of an API
• 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
© Asprotunity Ltd
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
…
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(); } }
…
• Abstraction level
• Working framework
• Progressive evaluation
• Penetrability
• Consistency
© Asprotunity Ltd
• Abstraction level
• Working framework
• Progressive evaluation
• Penetrability
• Consistency
import java.nio.file.Path;
import java.nio.FileSystems;
import java.nio.charset.Charset;
…
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
}
…
© Asprotunity Ltd
• Abstraction level
• Working framework
• Progressive evaluation
• Penetrability
• Consistency
import java.io.File;
import java.util.Scanner;
…
File file = new File("filename");
try {
Scanner scanner = new Scanner(file);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
processLine(line);
}
scanner.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
…
© Asprotunity Ltd
• Abstraction level
• Working framework
• Progressive evaluation
• Penetrability
• Consistency
with open("filename") as infile: for line in infile.readlines(): processLine(line)
“None of the ideas presented here are new; they are just forgotten from time to time.”
!
Alan J. Perlis, 1966 Turing Award Lecture.
© Asprotunity Ltd
© Asprotunity Ltd
• User’s perspective
• Naming
• Explicit context
• Error reporting
• Incremental design
© Asprotunity Ltd
• User’s perspective
• Naming
• Explicit context
• Error reporting
• Incremental design
© Asprotunity Ltd
“Ask, ‘What Would the User Do?’ (You Are Not the User)”
!
Giles Colborne, “97 Things Every Programmer Should Know”
Use language constructs to make intent clear
© Asprotunity Ltd
makeTV(true, false);
© Asprotunity Ltd
From: “API Design Matters”, Michi Henning, http://queue.acm.org/detail.cfm?id=1255422
void makeTV(bool isColor, bool isCrt);
© Asprotunity Ltd
From: “API Design Matters”, Michi Henning, http://queue.acm.org/detail.cfm?id=1255422
enum ColorType { Color, BlackAndWhite } !
enum ScreenType { CRT, FlatScreen };
void makeTV(ColorType col, ScreenType st);
© Asprotunity Ltd
From: “API Design Matters”, Michi Henning, http://queue.acm.org/detail.cfm?id=1255422
makeTV(Color, FlatScreen);
© Asprotunity Ltd
From: “API Design Matters”, Michi Henning, http://queue.acm.org/detail.cfm?id=1255422
© Asprotunity Ltd
What’s wrong with these?
public interface Startable { Startable start() throws AlreadyStartedException; } !
public interface Stoppable { Stoppable stop() throws AlreadyStoppedException; }
© Asprotunity Ltd
A better alternative
public interface Service { void start() throws AlreadyStartedException; !
void stop() throws AlreadyStoppedException; !
boolean isStarted(); }
© Asprotunity Ltd
TDD
• It puts you in the shoes of an user
• Outside-in development
• If writing a test is painful, the design may be wrong
• Tests will provide up to date documentation and examples of use
© Asprotunity Ltd
TDD helps with• Abstraction level. It helps to limit the number of
abstractions in mainline scenarios
• Working framework. It helps in keeping it smaller
• Progressive evaluation. The tests themselves are written in a progressive way
• Penetrability. It provides examples on how the various components interact with each other
• Consistency. It is maintained by refactoring the code
© Asprotunity Ltd
Back to the first example: potential test with TDD
… List<String> expectedLines = …; File file = new File(“testfile“)); assertEquals(file.readLines(), expectedLines);…
More likely outcome
© Asprotunity Ltd
File file = new File(“filename“)); try { for (String line : file.readLines()) { processLine(line);
} }
finally { file.close() }
© Asprotunity Ltd
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(); } }
Less likely outcome
© Asprotunity Ltd
• User’s perspective
• Naming
• Explicit context
• Error reporting
• Incremental design
"There are only two hard problems in Computer Science: cache invalidation, naming things and off-by-one errors.” !
Variation on a Phil Karlton quote
© Asprotunity Ltd
© Asprotunity Ltd
Naming
• Reserve the simplest and most intuitive names for the entities used in the most common scenarios
• Pick one word per concept
• Use easy to remember conventions
• Don’t be cute!
© Asprotunity Ltd
What not to do (1/2)
• java.io.ObjectStreamConstants
• Constants written into the Object Serialization Stream
© Asprotunity Ltd
• User’s perspective
• Naming
• Explicit context
• Error reporting
• Incremental design
© Asprotunity Ltd
Explicit context
• Assumptions about the external environment
• There are two kinds of context we are interested in
• Deployment context
• Runtime context
© Asprotunity Ltd
Deployment context
• Dependencies on other APIs
• Assumptions on deployment paths
• User permissions
• etc.
© Asprotunity Ltd
Runtime context
• Initialization (and finalization) steps
• Preconditions for calling methods (or functions) or instantiating classes
• Assumptions about global application state
© Asprotunity Ltd
Global state
• Difficult to use in a concurrent environment
• Can make test setup extremely hard
• Can make penetrability really hard by hiding dependencies
© Asprotunity Ltd
• User’s perspective
• Naming
• Explicit context
• Error reporting
• Incremental design
© Asprotunity Ltd
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
© Asprotunity Ltd
Error recovery
• Make recovery easy to do
• Error codes
• Exception classes
• A mix of the above
• Text messages are usually not good enough
Error management and reporting need careful design from the very beginning
© Asprotunity Ltd
© Asprotunity Ltd
What is an error at one level....
...May not be an error at another one
© Asprotunity Ltd
• User’s perspective
• Naming
• Explicit context
• Error reporting
• Incremental design
© Asprotunity Ltd
I will contend that conceptual integrity is the most important consideration in system design. It is better to have a system omit certain anomalous features and improvements, but to reflect one set of design ideas, than to have one that contains many good but independent and uncoordinated ideas. !Fred Brooks, “The Mythical Man Month”
ptg6931361
From the Library of Giovanni Asproni
© Asprotunity Ltd
Start specific and small
• Start with the 80% case first
• It is easier to remove constraints rather than to add them later
• YAGNI
© Asprotunity Ltd
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
© Asprotunity Ltd
A user study comparing the usability of the factory pattern and constructors in API designs found highly significant results indicating that factories are detrimental to API usability in several varied situations. The results showed that users require significantly more time (p = 0.005) to construct an object with a factory than with a constructor while performing both context-sensitive and context free tasks
From: “The Factory Pattern in API Design: A Usability Evaluation”
Factory pattern
© Asprotunity Ltd
It was hypothesized that required parameters would create more usable and self documenting APIs by guiding programmers toward the correct use of objects and preventing errors. However, in the study, it was found that, contrary to expectations, programmers strongly preferred and were more effective with APIs that did not require constructor parameters. Participants’ behavior was analyzed using the cognitive dimensions framework, and revealing that required constructor parameters interfere with common learning strategies, causing undesirable premature commitment. !From: “Usability Implications of Requiring Parameters in Objects’ Constructors”
Constructors
© Asprotunity Ltd
Conclusion
• User’s perspective
• Naming
• Explicit context
• Error reporting
• Incremental design
© Asprotunity Ltd
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
• “API Design Matters”, Michi Henning, http://queue.acm.org/detail.cfm?id=1255422
• 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
• “Usability Implications of Requiring Parameters in Objects’ Constructors”, Jeffrey Stylos and Steven Clarke, http://www.cs.cmu.edu/~NatProg/papers/Stylos2007CreateSetCall.pdf
• “The Factory Pattern in API Design: A Usability Evaluation”, Brian Ellis, Jeffrey Stylos, and Brad Myers, http://www.cs.cmu.edu/~NatProg/papers/Ellis2007FactoryUsability.pdf
© Asprotunity Ltd
Books
ptg6931361
From the Library of Giovanni Asproni