This document discusses error-driven development (EDD) and handling errors in programming. It recommends considering possible error conditions before implementing normal workflows. Errors should be categorized and handled appropriately. Functions should validate arguments, assert constraints, and fail fast on programmer errors. Library code should not write to stdout or surface errors to users, instead propagating errors. Programs that do not handle operational errors are incorrect. Handling errors properly makes programs more robust.
2. Consider the ways in which you system can go wrong
Categorize these error conditions
Programmer Error - Mistyped variable, null reference, type mismatch
Operational Error - Invalid user input, service outage, invalid user input
Determine how to handle these errors
Determine how to (or whether to) surface this error to the user
Write test cases for these error scenarios (error was thrown, message was logged, message was
displayed to user, etc.)
I - Think through error conditions before writing
the “happy path”
3. type Maybe a = Nothing | Just a
type alias User = {name: String, age: Maybe
Int}
Java:
Elm:
I (Cont.) - This Concept in Practice
public void writeList throws IOException, IndexOutOfBoundsException () {
type Result err val = Err err | Ok val
case String.toInt userInputAge of
Err msg -> span [class "error"] [text msg]
Ok age ->
if age < 0 then
span [class "error"] [text "Nuh Uh!"]
else if age > 140 then
span [class "error"] [text "Unlikely"]
else
text "OK!"
case user.age of
Nothing -> False
Just age -> age >= 21
4. Writing robust functions:
Assert arguments (and types) it expects
Assert additional constraints (e.g. must be a valid IP address)
Document all errors delivered by the function and throw as early as
possible, while providing all needed information to higher levels of the
stack
II - Design public functions to fail early on
programmer error
5. Side-Note: App-Code vs. Library-Code
Library-Code:
Never write to stdout! Instead,
allow the caller to configure a
logging function, or just throw an
exception with helpful information
Never surface relevant errors to
user. Instead, propagate them to
caller and let them handle
messaging
App-Code:
Write to stdout if that’s what your
logging solution requires
Surface relevant errors to user
6. Programs which do not handle operational errors are incorrect
The best way to recover from programmer errors is to crash immediately;
otherwise this error may propagate to other parts of the program with
unexpected results (most of us do this one really well already) 😉
If you don't know what errors can happen in your program, then it cannot be
correct except by accident
Other Takeaways
7. A function may deliver errors either synchronously or asynchronously, but
not both
If you receive something other than what a function is documented to accept,
that's a programmer error (i.e. it could have been avoided at compile-time)
Other Takeaways (Cont.)
9. BONUS ROUND DESIGNER TIP!!!
Try to include basic error messaging locations in your
mockups. This lowers friction for lazy programmers who skip
good error messaging because “they don’t know where to
show them.”