Simplifying dependency injection with closures

Photo by Quaritsch Photography on Unsplash

As developers, we are creating code every day. The code we write does not live on its own — it needs to use other code. Often the code we need to use is heavy in terms of the interface it is exposing. One could say, such code does not follow the Interface Segregation Principle. Too bad, it would be great if we could fix all those over-bloated classes, but the world is not ideal. How to deal with heavy dependencies then? Let’s try.

Interface Segregation Principle

I’m not going to explain what ISP is about. I assume you are familiar with it, but just for the record, let’s begin with a short reminder:

no client should be forced to depend on methods it does not use

On daily basis, ISP is treated as follows: Make your interfaces as simple/small as possible — which might be good enough. However, the word isn’t perfect. Last-year-ourselves weren’t writing that good code that today’s-ourselves do. Some code we considered simple enough a few weeks ago, today may seem complicated. And still — any SOLID rule (probably any of rule treating about good coding practices) do have a solid border. What’s more — our code changes, some assumptions we made last month may not be correct in today’s task. That being said let’s move to an example.

Define a problem

So, let’s assume, in our project, there is a class that is a repository for some kind of data. Something like below:

I’m not going to discuss if that class is breaking ISP or not. I think it could be there in any project.

Now a task for today: We need to create a class that will convert stored data to string on demand.

The straightforward approach

So, since we’re already around SOLID principles, we know we should not just use the repository inside our class, but inject it. Having that in mind, we might have that piece of code:

Is that valid solution? I guess it is. We did not say if the interface for the repository is following ISP rule or not, but now, having a consumer we see, that it does use only one property from the protocol.

Of course, it is not a big deal. But this is only a simple example, which can be more complex. What if an interface has tree elements? Or four? This is still not a big deal for code itself, but you may (should?) think about unit tests as well, and there it gets more complicated. You need to mock the whole protocol you are injecting, which in long term may be annoying.

On the other side, we have a solution where we are restricting protocols to only have one property or function. That does not sound like being easy to maintain. You may think on separate this protocol only when needed, but that also smells like some refactoring to do. Time to find a better approach.

A better approach — inject only what you need

So, let’s think about a solution, where we do not modify the existing repository’s interface, and still we do not need to inject the whole repository to our class.

If we think about that — our class do not need a repository. Or to be more precise — our class do not care, where MyData comes from. That sounds like we can define our class like this:

So, yes, we can just inject closure returning the current value of stored data. How to use it? How about below:

What did we do? Without changing existing repository we still use it as a valid source of data we need. But from our class perspective, we inject only part we do need. Perfect!

Unit testing

I do like, how this approach shines when writing unit tests. How a unit test for MyDataPrinter_InjectClosure may look like? Take a look:

We tested that the class is doing what it supposed to do, without creating any mock class. If you never tried writing mock-free unit tests, trust me, that’s something that really simplifies the whole process!

Summary

Dependency Injection is an essential part of clean programming, so it should be done the best way possible. I hope you liked this article and — what’s more important — you learned something from it. And if you did, do not forget to leave a clap!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Tomasz Załoga

Tomasz Załoga

I'm an iOS developer with 7 years of experience, recently happily learning SwiftUI and Vapor. Enjoyed being part of the team developing mobile apps for Toyota.