Search code examples
apiapi-design

How do you define a good or bad API?


Background:

I am taking a class at my university called "Software Constraints". In the first lectures we were learning how to build good APIs.

A good example we got of a really bad API function is the socket public static void Select(IList checkRead, IList checkWrite, IList checkError, int microseconds); in C#. The function receives 3 lists of sockets, and destroys them making the user have to clone all the sockets before feeding them into the Select(). It also has a timeout (in microseconds) which is an int, that sets the maximum time the server can wait for a socket. The limits of this is +/-35 minutes (because it is an int).


Questions:

  1. How do you define an API as 'bad'?
  2. How do you define an API as 'good'?

Points to consider:

  • Function names that are hard to remember.
  • Function parameters that are hard to understand.
  • Bad documentation.
  • Everything being so interconnected that if you need to change 1 line of code you will actually need to change hundreds of lines in other places.
  • Functions that destroy their arguments.
  • Bad scalability due to "hidden" complexity.
  • It's required from the user/dev to build wrappers around the API so that it can be used.

Solution

  • In API design I've always found this keynote very helpful:
    How to Design a Good API and Why it Matters - by Joshua Bloch

    Here's an excerpt, I'd recommend reading the whole thing / watching the video.

    II. General Principles

    • API Should Do One Thing and Do it Well
    • API Should Be As Small As Possible But No Smaller
    • Implementation Should Not Impact API
    • Minimize Accessibility of Everything
    • Names Matter–API is a Little Language
    • Documentation Matters
    • Document Religiously
    • Consider Performance Consequences of API Design Decisions
    • Effects of API Design Decisions on Performance are Real and Permanent
    • API Must Coexist Peacefully with Platform

    III. Class Design

    • Minimize Mutability
    • Subclass Only Where it Makes Sense
    • Design and Document for Inheritance or Else Prohibit it

    IV. Method Design

    • Don't Make the Client Do Anything the Module Could Do
    • Don't Violate the Principle of Least Astonishment
    • Fail Fast - Report Errors as Soon as Possible After They Occur
    • Provide Programmatic Access to All Data Available in String Form
    • Overload With Care
    • Use Appropriate Parameter and Return Types
    • Use Consistent Parameter Ordering Across Methods
    • Avoid Long Parameter Lists
    • Avoid Return Values that Demand Exceptional Processing