Dependency injection in Clojure webapps

I’m writing a series which could be seen as a critique of Stuart Sierras Component system, which it is not.
https://slipset.github.io/posts/dependency-injection-perhaps
https://slipset.github.io/posts/config

The next instalment will be on the somewhat harder topic of how do you deal with the database.

5 Likes

I think some of the translation has been lost, and often usefully. However component is a system for managing dependent relationships between all the non-functional bits (as opposed to stateful). These non-functional bits can be JVM resources, representations of resources on a network, plain state, state from previous IO (config). But it is also a composition mechanism, and this is a key point. Because we will build the internal-API level constructs of our programs as abstractions over these resources.

For example, an app will always need configuration let’s say. On day 1, this might a flat file, day 90 a resource, day 1000 an AWS service. More realistically it will be a composition of those things. However allowing all these little bits to interact with the other parts of one’s application makes future refactors error prone. And that turns into debt caused when outside forces demand we change a system’s dependencies. We need to evolve code smoothly under these conditions. We would want a configuration component that represents all the stuff our app needs to know in order to function. The interface to this one config component is used in the app, and hides the implementation.

Now as our sources, and methods of configuration change we write and deprecate the non-functional components that make up our higher level config abstraction. The clear representation of config data to the rest of the program remains the same. (And can be tested at this API-level interface).

Clojure has given us a way to forget the complexity of Class Objects, Dagger or Guice based dependency injection, or (gasp) Spring with XML. But the same organization and thoughtfulness of isolation and design is required in programs that will change their implementing technology often. Especially now that we have moved to making services from lots of connecting services. If we don’t, we replicate the debt causing structures that prevent program evolution and cost our enterprises precious capital.

That Clojure does this with the barest minimal amount of structure and fanfare is a liberation. Furthermore the implementation of things like component are made of other small usable pieces and totally comprehendible. Oh and they don’t need to be updated every second. But the system of organizing resources into hierarchical object-like things with interfaces models the non-functional parts of the internals of our server processes very nicely.

PS: And to this point about configuration you might want to check out Integrant. An nice refinement of Component.

1 Like