I am old and have written many apps with and without DI. I sometimes wonder if DI is a a big waste of time. This post explains why.

DI was kind of born in the world of Java and OOP, at a time when we were possibly over-obsessed with OOP. I am a big fan of OOP. It really is the preferred paradigm for many cases. But not all.

One pattern that seems to be popular in Java, but less so in other language ecosystems, is using objects as “services”. That is, grouping service-type functions into a service class and then passing dependencies (like a jdbc DataSource) into the service class’s constructor (or worse, using setters).

I find that these service classes are a “wash”: that is they have pros and cons that equal each other out. And possibly, less than a wash.

I am starting to go back to just using plain functions for “services”. If I need a datasource, I just pass it in as an argument to the function (not to the whole class). No object. No class. No DI. No DI framework. Just passing arguments to functions.

I will acknowledge that if you have 9 functions that all need the same dependency, passing that dependency once to the constructor might save a bit of time (as opposed to passing it to all nine functions). But that is a pretty minor gain.

Much more common is the opposite phenomenon. You awkwardly group functions into a service class. Then you need to use one of those functions. But you can’t because you need the whole class. And all of its dependencies. And all of its dependency’s dependencies. And so on. This becomes such a pain in the ass that you need a DI framework to deal with it.

Service classes almost always unnecessarily increase coupling.

Testing and Mocking

Testing this tangled web of service classes become almost impossible. So again, we need a whole plethora of complicated tools and techniques to deal with this: separating your service classes into interface and implementation, mocking, mocking frameworks and, of course, DI frameworks.

You know what’s easy to test? Plain functions. You may still need to mock some, but much less. You only need the dependencies needed for that one function.

Some would argue that DI and DI frameworks make testing easier. But I would phrase it differently: service classes make testing harder. DI, DI frameworks, Mocking and Mocking Frameworks help alleviate this problem.

But using plain functions for your services also alleviates the problem. It’s easy. It’s low-tech. It works great.

Semantics

Some of this is a matter of semantics. If you define DI to simply mean “passing in” dependencies rather than “looking them up” from some kind of global registry or global variable, then it’s pretty hard to argue with that. Passing in dependencies is almost always preferred over globals.

So I guess what I am really arguing against is the need for service classes. And the DI and mocking frameworks that make using service classes easier.

Summary

Many language ecosystems do not use service classes or DI frameworks. Try asking a rust or python programmer what their preferred DI framework is. So they are certainly not necessary. The real question is, do they make your life harder or easier? And the answer to that question is certainly not a slam dunk. In my opinion, it’s at-best a wash.

I may be wrong

I am open to being proven wrong. I went with a rather provocative title to spark a little debate. I would love to hear what others think.



Credit goes to the respective owner!

Leave a Reply

Your email address will not be published. Required fields are marked *