Commissioned for this museum · after Gamma, Helm, Johnson & Vlissides, 1994

Chain of Responsibility

TypeScript·1994·34 lines·1083 bytes

Curator’s note

You have used this today. It is the middleware stack in every web framework written in the last twenty years — Express, Koa, Rack, Django, the routing layer of whatever is serving this page — and it is one of the few patterns from 1994 that arrived at ubiquity under its own name rather than dissolving into a language feature.

The book drew it as a linked list of handlers, each holding a reference to its successor, each deciding whether to handle a request or forward it. The version that won is subtly more powerful: because next is a function the handler calls rather than a pointer it delegates to, a handler runs code *before and after* the rest of the chain. That is how timing, logging, transactions and error boundaries are written. The linked list can only decline; the closure can wrap.

The cost is that the control flow becomes invisible. Look at auth: whether anything happens after it depends on a value it received, and nothing in the file tells you what next leads to — that was decided in the array passed to chain, possibly in another module, possibly at runtime. Every framework built on this has the same two bug reports for the same reason: somebody forgot to call next and the request hangs or silently 404s, or somebody called it twice and the rest of the chain ran twice.

Notice also that the chain has no idea whether anyone will handle the request. step bottoms out in a 404, and that fallback is not decoration — a chain where nothing is guaranteed to answer needs an answer for when nothing does.

Elsewhere in the museum