Last Updated: April 03, 2016
· Brian Zeligson

Functional DI by default

Maybe more of a musing than a protip, but the format works.

When you boil DI down to it's degenerate case, it is nothing more than adding a parameter to a function.

If you take the process to an extreme, replacing any references to values and functions inside your functions with references to parameters that are passed to them, you will by default push dependencies further and further up the call stack.

There are of course more effective ways of doing this than manually threading dependencies through multiple function calls (such as a Reader monad,) but the thought exercise is still intriguing.

By pushing dependencies further up the call stack, you naturally arrive at a point where all of your specifics reside at the outer edges of the application. This is the kind of codebase where configuration can exist largely as code, and the behavior of the application is trivial to modify in extremely granular and subtle ways. This is a really nice kind of codebase to work with.

Taken from another angle the underlying conclusion might be, increasing abstraction in parallel with callstack depth is generally a sign that things going well.