Passing dependencies into ring handlers ... on request map, or `partial`ed into the handler?

We have code that uses both approaches at work. Most of our apps inject the (Application) Component via middleware. A couple of our apps use the second approach, or a variant of it (that has a component for each handler, essentially). My preference is #1, my teammate’s preference is #2. Both approaches have pros and cons – and you summarized those pretty well.

Over time, as maintenance has extended the number of Components needed in some handlers, the second approach does indeed become tedious, especially when you have to track down the call chain whether a Component is available or not. But it does at least make you think a bit more about whether you really should be using that new Component or whether restructuring your code would be a better idea.

Overall, I still prefer the simplicity of the first approach because the “wiring” is in just one place – the middleware – so it’s easier to reason about and it’s easier to do maintenance when a new Component is needed by something deep in the call tree (although you lose the “prod” about refactoring to keep Component use closer to the edges of your code). Our applications are very database-heavy, so the Database Component tends to be widely used throughout the call tree – which is a pragmatic decision. We did, at one point, fully separate read/process/write but with the high level of DB writes in our system and the complexity of several of the updates, the code became very monadic in style and we found it harder to maintain and to reason about.

2 Likes