December 24th, 2014
(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: email@example.com
In the example above, it’s disturbing that simple and intuitively harmless changes introduced such drastic errors. Experientially, it’s kind of like executing print 2 + 2 and seeing 5. What was it about that logging API that turned us into such bad programmers?
The specification of a typical callback-based API is simple: pass in any function and it will get called when the relevant event happens. Unfortunately, this simple specification doesn’t reflect reality. You can’t just call any function at any time and expect your program to be correct. The context in which a function is called matters. The context information required for correctness isn’t usually part of a callback-based API’s formal specification.
An important implication of not including this context information as part of the API’s specification is that when an error occurs, it’s not clear if the caller or callee is at fault. This can lead to inelegant and/or incomplete solutions.
Another characteristic of callback-based APIs is that natural evolution of the encapsulating system (due to refactoring and enhancement) causes the context in which callbacks are invoked to change. This in turn causes the specification of the API to change, even if the API’s apparent interface or internal implementation doesn’t change. Callback-based APIs are inherently unstable as long as their specification is dependent on external conditions that are subject to change.