summaryrefslogtreecommitdiff
path: root/reviews/blog-roll.md
diff options
context:
space:
mode:
authorKévin Le Gouguec <kevin.legouguec@gmail.com>2019-09-13 23:56:42 +0200
committerKévin Le Gouguec <kevin.legouguec@gmail.com>2019-09-13 23:56:42 +0200
commit652d82d4404ee7fd3917e6a422c200d52b06c5ce (patch)
treedc81ed609a3137cecdf201b95baab4e08f5b77c3 /reviews/blog-roll.md
parentb586fd87fc90fda40b1927ec1b88984de9e7d9ea (diff)
downloadmemory-leaks-652d82d4404ee7fd3917e6a422c200d52b06c5ce.tar.xz
Take notes on Joe Duffy's Error Model
Diffstat (limited to 'reviews/blog-roll.md')
-rw-r--r--reviews/blog-roll.md114
1 files changed, 114 insertions, 0 deletions
diff --git a/reviews/blog-roll.md b/reviews/blog-roll.md
index d7b7dd8..3fa4d93 100644
--- a/reviews/blog-roll.md
+++ b/reviews/blog-roll.md
@@ -171,3 +171,117 @@ Satirical websites fighting [web bloat] with minimalist designs.
Think of internationalization
[web bloat]: https://idlewords.com/talks/website_obesity.htm
+
+# [Joe Duffy's Blog]
+
+[The Error Model]
+: An in-depth look at what "errors" are in the context of software,
+ how some languages choose to deal with them, and what model the
+ Midori team implemented.
+
+ > Our overall solution was to offer a two-pronged error model. On
+ > one hand, you had fail-fast – we called it abandonment – for
+ > programming bugs. And on the other hand, you had statically
+ > checked exceptions for recoverable errors.
+
+ Starts by outlining the "performance metrics" for a good error
+ model, then goes over unsatisfactory models:
+
+ - **Error codes** clutter a function's signature with an extra
+ return value, and the resulting branches degrade performance;
+ they do not automatically interrupt execution, thus when bugs
+ finally show up, it can be hard to track their origin down.
+ - Though they did provide their developers with an escape
+ hatch that lets them ignore return values, their `ignore`
+ keyword is at least auditable.
+
+ - **Unchecked exceptions** make it hard to reason about a
+ program's flow. They persist because in the grand scheme of
+ things, they stay out of the way When Things Work™.
+
+ - **Exceptions in general** tend to come with some performance
+ baggage (e.g. symbols for stack traces), and encourage coarse
+ error-handling (i.e. throwing a `try` blanket spanning several
+ statements instead of focusing on individual calls).
+
+ All of these models conflate *recoverable errors* (e.g. invalid
+ program inputs) that the application can act on (by telling users
+ about their mistakes, assuming a transient environment failure and
+ re-trying, or ignoring the error) with *bugs*, i.e. unexpected
+ conditions that, when unhandled, create bogus states and
+ transitions in the program, and may only have visible impacts
+ further down the line.
+
+ As these bugs are "unrecoverable", the team chose the
+ "**abandonment**" strategy (aka "fail-fast") to deal with them.
+
+ > My impression is that, largely because of the continued success
+ > of monolithic kernels, the world at large hasn’t yet made the
+ > leap to “operating system as a distributed system” insight.
+ > Once you do, however, a lot of design principles become
+ > apparent.
+
+ > As with most distributed systems, our architecture assumed
+ > process failure was inevitable.
+
+ The micro-kernel architecture, where basic kernel features such as
+ "the scheduler, memory manager, filesystem, networking stack, and
+ even device drivers" are all run as isolated user-mode processes,
+ encourages "wholesale abandonment" as an error-handling stragegy,
+ since the failure remains contained and does not bring down the
+ whole system.
+
+ They implemented **contracts** using dedicated syntax and made
+ them part of a function's interface. Delegating contract-checking
+ to a library would have buried pre- and post-conditions as regular
+ calls inside a function's definition, whereas they wanted them to
+ become part of the function's metadata, where they can be analyzed
+ by optimizers, IDEs, etc.
+
+ > Contracts begin where the type system leaves off.
+
+ Contract violations trigger (at worst) program abandonment;
+ **type-system** violations plainly prevent the program from
+ existing.
+
+ Since "90%" of their contracts were either null or range checks,
+ they found a way to encode nullability and ranges in the
+ type-system, reducing this:
+
+ public virtual int Read(char[] buffer, int index, int count)
+ requires buffer != null
+ requires index >= 0
+ requires count >= 0
+ requires buffer.Length - index < count {
+ ...
+ }
+
+ To this:
+
+ public virtual int Read(char[] buffer) {
+ ...
+ }
+
+ While preserving the same guarantees, checked at compile-time.
+
+ **Nullable** types were designated with `T?`; `T` implicitly
+ converted to `T?`, but conversion from `T?` to `T` required noisy
+ (i.e. auditable) operators which would trigger abandonment when
+ needed.
+
+ *Recoverable errors* were handled with checked exceptions, which
+ were part of a function's signature. Since most bugs were dealt
+ with through abandonment, most of their APIs didn't throw.
+
+ To make it easier to reason about control flow, callers had to
+ explicitly say `try` before calling a function that might throw,
+ which did what Rust's deprecated `try!()` did: yield the return
+ value on the happy path, else re-throw.
+
+ Covers performance concerns, composition with concurrency; muddies
+ the waters somewhat with "aborts" which kind of look like
+ `longjmp`s to me? Except it runs the code in `catch` blocks it
+ finds while crawling back the stack?
+
+[Joe Duffy's Blog]: http://joeduffyblog.com/
+[The Error Model]: http://joeduffyblog.com/2016/02/07/the-error-model/