- Rules from Practice of Programming Chapter 4: Interfaces:
- Hide implementation details.
- Choose a small orthogonal set of primitives.
- Don't reach behind the user's back.
- Do the same thing the same way everywhere.
- Free a resource in the same layer that allocated it.
- Detect errors at a low level, handle them at a high level.
- Use exceptions only for exceptional situations.
- (You need to read the book to fully understand the rules in context)
- How to Design a Good API & Why it Matters -- Joshua Bloch
- The Little Manual of API Design (with examples from QT)
- How Do I Make This Hard to Misuse? -- Rusty Russell: Kernel hacker Rusty Russell has some thoughts on how to make APIs hard to misuse. The idea is that in addition to making APIs easier to use, that they also be made hard to misuse. "So I've created a 'best' to 'worst' list: my hope is that by putting 'hard to misuse' on one axis in our mental graphs, we can at least make informed decisions about tradeoffs like 'hard to misuse' vs 'optimal'."
- What If I Don't Actually Like My Users? -- Rusty Russell
- Rusty Russell: Valid Uses of C Macros -- Rusty Russell
- On C Library Implementation: "3. Context creation and destruction are common patterns, so stick with "mylib_new()" and "mylib_free()" and everyone should understand what to do. There's plenty of bikeshedding over the names, but these are the shortest ones with clear overtones to the user. [...] 14. There's a standard naming scheme for C, and it's all lower case with underscores as separators. Don't BumpyCaps."
- Make Interfaces Easy to Use Correctly and Hard to Use Incorrectly -- Scott Meyers
- Atomic context and kernel API design [LWN.net]
- The Java Fluent API Designer Crash Course, Jan 2012 -- method chaining
Resource Management and Error Handling
- Robust Design Techniques for C Programs by David Turner (freetype)
- See also: C++ RAII, PEP 343
- gerror from glib
- Cairo error handling: "All major cairo objects retain an error status internally which can be queried anytime by the users using cairo*_status() calls. In the mean time, it is safe to call all cairo functions normally even if the underlying object is in an error status. This means that no error handling code is required before or after each individual cairo function call."
- Another error handling approach: NaN propagation in IEEE754
C Programming Language
- C Interfaces and Implementations: Techniques for Creating Reusable Software by David R. Hanson (lcc) -- the C interface style is quite different from the Linux kernel
Resources I Haven't Read
- Practical API Design, Confessions of a Java Framework Architect by JaroslavTulach (NetBeans)
- On API Design Guidelines 1
- A Google search on "API Design" returns mostly Java focused links in 2009. Users of other programming languages need to actively compensate while reading the materials.
- The solutions to interface design problems are often programming language specific (e.g. error handling) but the problems are similar (e.g. make interface hard to misuse).
- See Why Functional Programming Matters higher order functions and lazy evaluation greatly effect API design.
- Work with the standard library and idioms of the language. Especially important if you don't personally know the language well. e.g. many Python bindings to C libraries are problematic in this area.
- Maintaining an interface with many implementations has a very real cost. If there's only ever going to be one useful implementation of a plugin interface, don't bother having a plugin architecture at all.
- Concurrency adds other issues, e.g. what functions can I call from the callback I just registered? (c.f. async signal safe functions and signal handlers in POSIX)
- Documenting concurrency contracts like lock ordering is often omitted.
- Lock based software are not composable.
- Examples involving concurrency, resource management and API design: pthread_atfork, thread cancellation.