Where do Failures Come From?
Once programmers have gained a certain amount of experience, most of us realize that failures and invalid data are brought to production systems by the stork. But where does the stork get them?
Leema Failure types already include a concept of tracing the origin of the failure. If a failure originates in one function, we want to be able to see where that failure originated if we try to use it as a value. If response.body
in the fetch_qty
function has invalid JSON, this should be an immediate failure that Leema should identify before attempting to call subtract_items
.
func fetch_qty:Int :: client:ApiClient item_id:Str ->
let response := client.get_item_data(item_id)
let item_data := ItemData.parse_json(response.body)
item_data.quantity
--
func handle_order :: client:ApiClient item_id:Str num_items:Int ->
let qty := fetch_qty(client, item_id)
let remaining_qty := subtract_items(qty, num_items)
... more logic
--
Some Failures are Latent
However, sometimes a value may be valid in one context and invalid in another. In this case, a quantity of 0 or even 5 in fetch_qty
is perfectly valid. It’s only until we combine the quantity with the number of items to subtract that we know if both of these values are valid. Was it strictly bad inputs? Was there a previous calculation that was wrong? When debugging cases like this, it’s often helpful to know where the component values of a calculation came from.
func fetch_qty:Int :: client:ApiClient item_id:Str ->
let response := client.get_item_data(item_id)
let item_data := ItemData.parse_json(response.body)
item_data.quantity
--
func subtract_items:Int :: initial_qty:Int num_items:Int ->
if num_items > initial_qty ->
fail(#insufficient_qty).with_context(initial_qty, num_items)
--
initial_qty - num_items
--
func handle_order :: client:ApiClient item_id:Str num_items:Int ->
let qty := fetch_qty(client, item_id)
let remaining_qty := subtract_items(qty, num_items)
... more logic
--
In this case, it’s fairly obvious where initial_qty
comes from. But where did num_items
come from? Leema should be able to trace the origin of both of these values to where they originated. In this case, the failure should report that initial_qty
originated in the last line of function fetch_qty
and should also report the origin of num_items
.