No results found.
We can solve any problem by introducing an extra level of indirection.1
...except the problem of too much indirection.2
And too much indirection is the third root of all evil.3
- Indirection refers to dispatch of communications via an intermediary. The intermediary is the cause of indirection, and is (strictly) an entity capable of examining a message and making a decision regarding it (e.g. on whether to forward it or answer it, or on where to forward it, etc.). There may be a chain of such intermediaries along a communications path, each constituting one level of indirection. ↩
- For instance, to fix a slow storage system, one may reckon:
- To add caching, an indirection of access. On each request, the cache manager decides whether to serve the request from the cache or to forward it to the storage system.
- To parallelize and distribute access, an indirection over a load balancer. On each request, the load balancer decides which storage node to forward the request to.
- To reduce iterated strength4 — such as by refactoring logic out of loops or functions when computed effects can be shared across iterations or function calls (a sort of caching?).
- At this scale of complexity, one perhaps needs yet another indirection in the form of a compiler (even real programmers need a compiler!).
As the system complexity explodes, one reckons the collective ought to be refactored into smaller, "atomic" components, each abstracting away specific complexities and exposing a reasonable API for the next level of indirection to consume. But the complexity of each subsystem soon matches that of the original system. Voilà: the original pain is rediscovered, and recursion2 beckons. ↩ ↩2 - The first two are premature optimization, atrocious naming, and off-by-one errors. ↩
- Made up our own terminology, have we? ↩