software, programming, computers, technology

Menu

Ruby and dependency injection in a dynamic world

It’s been many years I’ve been teaching Java and advocating dependency injection. It makes me design more loosely coupled modules/classes and generally leads to more extensible code.

But, while programming in Ruby and other dynamic languages, the different mindset always intrigued me. Why the reasons that made me love dependency injection in Java and C# don’t seem to apply to dynamic languages? Why am I not using DI frameworks (or writing simple wiring code as I did many times before) in my Ruby projects?

DI frameworks are unnecessary. In more rigid environments, they have value. In agile environments like Ruby, not so much. The patterns themselves may still be applicable, but beware of falling into the trap of thinking you need a special tool for everything. Ruby is Play-Doh, remember! Let’s keep it that way.

– Jamis Buck

Even being a huge fan of DI frameworks in the Java/C# world (particularly the lightweights), I completely agree with Jamis Buck (read his post, it’s very good!). This is a recurrent subject in talks with really smart programmers I know and I’ve tried to explain my point many times. I guess it’s time to write it down.

The whole point about Dependency Injection is that it is one of the best ways to achieve Inversion of Control for object dependencies. Take the Carpenterobject: his responsibility is to make and repair wooden structures.

The problem is that saws could be complicated to get, to assemble, or even to build. The saw itself may have some dependencies (PowerSource), which in turn may also have some dependencies… Everyone who needs a saw must know where to find it, and potencially how to assemble it. What if saw technology changes and some would rather to use hydraulic saws? Every object who needs saws must then be changed.

When some change requires you to mess with code everywhere, clearly it’s a smell.

Have you also noticed that the carpenter has spent a lot of time doing stuff which isn’t his actual job? Finding power sources and assembling saws aren’t his responsibilities. His job is to repair wooden structures! (Separation of Concerns)

One of the possible solutions is the Inversion of Control principle. Instead of going after their dependencies, objects receive them somehow. Dependency Injection is the most common way:

Now, the code is more testable. In unit tests where you don’t care about testing saws, but only about testing the carpenter, a mock of the saw can be provided (injected in) to the carpenter.

In the application code, you can also centralize and isolate code which decides what saw implementation to use. In other words, you now may be able to give the responsibility to do wiring to someone else (and only to him), so that objects can focus on their actual responsibilities (again Separation of Concerns). DI framework configuration is a good example of wiring centralized somewhere. If the saw implementation changes somehow you have just one place to modify (Factories help but don’t actually solve the problem – I’ll leave this discussion for another post).

Sure you might do dependency injection in Ruby (and its dynamic friends) exactly the same way as we did in Java. But, it took some time for me to realize that there are other ways of doing Inversion of Control in Ruby. That’s why I never needed a DI framework.

First, let’s use a more realistic example: repositories that need database connections:

Our problem is that many places need a database connection. Then, we inject the database connection as a dependency in everywhere it is needed. This way, we avoid replicating database-connection-retrieval code in such places and we may keep the wiring code centralized somewhere.

In Ruby, there is another way to isolate and centralize common behavior which is needed in many other places. Modules!

module ConnectionProvider
def connection
# open a database connection and return it
end
end

This module can now be mixed, or injected in other classes, providing them its functionality (wiring). The “module injection” process is to some degree similar to what we did with dependency injection, because when a dependency is injected, it is providing some functionality to the class too.

Together with Ruby open classes, we may be able to centralize/isolate the injection of this module (perhaps even in the same file it is defined):

# connection_provider.rb
module ConnectionProvider
def connection
# open a database connection and return it
end
end
# reopening the class to mix the module in
class Repository
include ConnectionProvider
end

The effect inside the Repository class is very similar to what we did with dependency injection before. Repositories are able to simply use database connections without worrying about how to get or to build them.

Now, the method that provides database connections exists because the ConnectionProvider module was mixed in this class. This is the same as if the dependency was injected (compare with the Java code for this Repository class):

The code is also very testable. This is due to the fact that Ruby is a dynamic language and the connection method of Repository objects can be overridden anywhere. Particularly inside tests or specs, the connection method can be easily overridden to return a mock of the database connection.

I see it as a different way of doing Inversion of Control. Of course it has its pros and cons. I can tell that it’s simpler (modules are a feature of the Ruby language), but it may give you headaches if you have a multithreaded application and must use different implementations of database connections in different places/threads, i.e. to inject different implementations of the dependency, depending on where and when it’s being injected.

Opening classes and including modules inside them is a global operation and isn’t thread safe (think of many threads trying to include different versions of the module inside the class). I’m not seeing this issue out there because most of Ruby applications aren’t multithreaded and run on many processes instead; mainly because of Rails.

Regular dependency injection still might have its place in Ruby for these cases where plain modules aren’t enough.

IMO, it’s just much harder to justify. In my experience modules and metaprogramming are usually just enough.

Great article! And apparently you are not alone thinking about this in a non-Java world. In Scala people talk about those things too and the solution is pretty similar (use traits and “include” them inside classes that need that dependency). It seems simpler, like you said, because you don’t need a framework and it’s a language feature (in Scala, the wiring is done in compile time and is also strong typed). An interesting article about DI in Scala:

But both those solutions make me think if those are really Inversion of Control approaches, or only some new kind of dependency resolution pattern. According do Fowler, IoC stands for code being called for you, not you calling everything (the famous Hollywood pattern):

In the first example, using traditional Java DI with some framework, it’s clear that our code never invokes constructors. All constructors, all dependency resolution and injection is done by a framework that call our code (IoC). Traditional Dependency Injection is a Inversion of Control way of doing dependency resolution. There are other dependency resolution patterns, like Service Locator, that solves the dependency problem but aren’t Inversion of Control.

Fowler talks about this distinction between DI and IoC in his famous article:

In that article, there is an excerpt where he explains what is Inversion of Control and what is not:

“The fundamental choice is between Service Locator and Dependency Injection. The first point is that both implementations provide the fundamental decoupling that’s missing in the naive example – in both cases application code is independent of the concrete implementation of the service interface. The important difference between the two patterns is about how that implementation is provided to the application class. With service locator the application class asks for it explicitly by a message to the locator. With injection there is no explicit request, the service appears in the application class – hence the inversion of control.”

That is: both solutions have dependency decoupling (which is good) but only DI is IoC.

Maybe it’s just pedantry, but my point is that your solution to Ruby dependencies and my solution to Scala’s are not IoC. They’re just some dependency resolution pattern.

Sergio, I understand your point of view. But being pragmatic, it makes no difference in the Ruby world, mainly because open classes enable objects that require dependencies to not include anything extra.

Looking at my final example, you can see the Repository isn’t going after its connection dependency. I know that under the hood, the connection method behaves as a Service Locator. But it just “appears” inside the Repository class, then it could also be seen as a kind of Inversion of Control, as you pointed in the Fowler’s article:

“With service locator the application class asks for it explicitly by a message to the locator. With injection there is no explicit request, the service appears in the application class – hence the inversion of control.

– Martin Fowler”

My point is that in my example (and I’m being specific about Ruby and languages which allow open classes here), there is no explicit message requiring the dependency. Then, using Fowler’s definition it’s Inversion of Control.

As Joel Lobo said, the mixins and traits approach of injecting dependencies seems more like aspects (non bloated AOP) than Service Locators. But as I said, I understand your point and the connection method is just a Service Locator under the hood. What I’m saying also doesn’t apply to every language, but in Ruby I see few practical differences (mixing in modules is a global operation, concurrency issues, …).

Now I see, you’re right about the last code being IoC (reading the first time I thought the ‘include’ line was always mandatory ). The problem I pointed about this not being IoC was all about that ‘include’ line – similar to the ‘with’ statement in my previous scala example. Without that explicit mixin call and open classes I agree with you.

But it’s always good to remember that a good DI framework does a lot more than just dependency assembly. There is lifecycle management, scope resolution and even proxies/decorators/interceptors.

I totally agree that in a open class world, inversion of control gets easier and you drop the requirement for a DI framework.

At the same time, this ease of use gives developers the same power that the DI frameworks do: its just so easy to inject, mix in, things, that unaware developers might cross layers that sometimes shouldnt be crossed.

This problem is not related to the language (Ruby in this case) or the DI framework (any of them that makes easy to do it), its a matter of, if its too easy to do something wrong, unaware people will do it :)

I am a big fan of it all and totally agree with you… and that’s why we need to find out a way to avoid people to use this power in the wrong way.

I think if we don’t create dependences in Java or C#, we shouldn’t create dependencies em Ruby (or anywhere object-oriented language) too. Just it changes the language, the context and principles are the same.

Of course the way to do this in Ruby is easier than Java and C#. The Ruby way gives us this facility, jointly with responsibility.

I agree with Guilherme’s point about to use the power of dynamic languages in the wrong way. In my short experience in Ruby, I have already seen people using this power because is cool and not for really needs.

The dynamic features of Ruby can help quite a lot. But I´m still rather ignorant of the trade-offs of using Ruby modules. They deal well with hierarchical issues but can suffer from name clashing…(though Ruby address this in a deterministic way by looking for things in a determined order).

I’ve been contemplating this problem recently and almost got there. Being able to reopen classes and inject modules into them was the link I’ve been missing.

It is not for the faint hearted though. With dynamic languages if you are not incredible disciplined you can quite quickly create a huge mess! With a static language, the use of an IoC container will at least encourage you down a consistent path.. If you are confused where a class is coming from you know to just look in the IoC container.. With Ruby its time for a global search!

First off, I found this to be a very well written article, and it has given me some things to think about with regard to DI and Ruby. However (uh oh), there are a couple issues I see with your solution of mixing in a module.

I believe it would become overwhelming in a larger project to specify this include for every class that has a database dependency. And this is just one “interface” in the system. Every other provider of some such service will require similar code to include its interface in every class that requires it.

Also, I would now be specifying the dependencies for these classes somewhere far removed from the class itself. Call me sentimental, but I like to keep those sorts of things close to home. I want to keep the class’s specification in (or at least near) the class itself. It has been my experience that spreading that sort of info around too much makes maintenance more difficult.

I’ll admit that my experience with dynamic languages is somewhat limited. I’ve done some work with Python, and I’ve gone through the Ruby koans exercises. I would certainly like to hear your (or anyone’s) thoughts on these points. Maybe it’s not as much of a problem as it seems.

I’m not sure I understand your comments correctly, but they seem a bit controversial to me.

Either you declare those dependencies in your classes that require them, or you declare them in a central place, away from your classes. You can at some level mix both approaches, but It’s always a tradeoff in the end.