Dependency injection and other Java necessary evils
Lately, I often find myself thinking about how much I have changed my mind about Java. For a long time I have been interested in the Java Platform, and I have tried to be educated on its good practices, patterns, and trends. Today, I can say I am not interested in the Java platform anymore. In the process, I have learned the wonders of Ruby, Rails, true Behavioral-Driven Development and a community full of brilliant developers who consider that beautiful code is a primary goal and that software development has to be fun.
In this post I would like to talk about three recurrent Java features I have changed my mind about in recent times: from loving them, I have finished considering them as necessary evils you have to live with.
- Dependency injection
- Strong type system
- Object disorientation
Dependency injection
The dependency injection (DI) pattern is about separation of concerns. The concern of wiring object dependencies is extracted from objects and centralized in some factory facility that, using some configuration information on how object are wired together, instantiates and configure these objects for you. This pattern is in the core of Spring and is implemented by Google Guice.
So why are DI solutions so important in Java? I think the main reason is that they are the only way to enable good unit testing. Sure there are other benefits, like minimizing coupling between objects or avoiding to write the same wiring boilerplate code again and again, but these are not as important as testing. While you will hardly find yourself in need of changing a JDBC DAO for a JPA one, you will always need to mock dependencies when writing unit tests. And for doing so, you need to isolate these dependencies first.
And the Java new
operator makes this task tough. It is just so rigid. You don’t have any mechanism for faking it once it is coded within your objects. The alternative usually implies implementing a full ecosystem of interfaces, their implementations enabling the dependency injection (in the form of constructors or setter methods), and factories for instantiating the configured objects. And since the boilerplate code this approach implies is considerable, you would rather use an external DI library that makes the work for you. So external DI solutions are good but, from a testing perspective, they solve a problem created by the Java new operator.
I realized this problem when I tried to build something serious with Rails. The first thing I did was to look which dependency-injection solutions were available for Rails. If you look for DI in Rails there is a good chance you end up reading this article by Jamis Buck. That post summarized his clarifying experience with DI libraries in Ruby:
- He first created Copland: a port of the Java Hivemind.
- He created Needle as a more Ruby-like approach to a DI solution.
- He finally concluded that DI frameworks are unnecessary in Ruby (he talks about DI tools, not about the pattern itself).
In my opinion, Ruby examples used by Jamis are not the best. I think a key aspect in Ruby is that new
is just a class method. This means that classes in Ruby are by definition factories, and you can fake them directly when testing. Let me show you an example with a Person
class that depends on Mouth
since to say something, a person has to open his mouth.
class Mouth
def open
"Very complex, slow and sophisticated processing here"
end
end
class Person
def say_hi
Mouth.new.open
end
end
If you want to test this behavior with RSpec, you would do something like:
describe "Person" do
it "should open the mouth to say hi" do
@person = Person.new mouth = mock("mouth") mouth.should \ _receive(:open) Mouth.should \ _receive(:new).and \ _return(mouth) @person.say \ _hi
end
end
Since the Ruby new
method is just a class method, it can be stubbed the way you want to inject the dependencies. This is a key aspect when testing with Ruby. You get used to it quickly because it is a natural thing from the programmer point of view. What is difficult is to go back to Java after knowing it, because of the big mess you have to create to achieve the same thing.
Another nice feature of Java DI solutions is that they manage the scope of objects for you. The usual default approach is to create an object each time is requested. But sometimes it is needed to have a singleton scope for some objects. Spring or Guice let you configure the scope in a declarative way, and they manage the scope for you. The scope management is a production thing. For testing, you just create the objects you want to test directly.
If you hardcode a singleton object in Java, you have to take care of cleaning its state between test cases. And this is just laborious and not elegant. DI frameworks offers a very nice solution for this problem. In Ruby, you still can test singleton classes because you can modify the Singleton module to expose a reset method that regenerates the single instance each time. This solution is possible by dynamic capabilities of Ruby. Again, I think it is nice just to be able to use the singleton object directly.
Another approach for the singleton problem is to have a global configuration object as a simple hash. In testing time you can override the contents of the hash. Again, Ruby syntax and symbols make to look nice something that seems scary if you come from the Java World.
Regarding the scope problem, the solution offered by DI frameworks is probably purer. They are also more complete. For example, Guice let you specify how the injected objects are created through the concept of providers. The thing is that with power comes complexity. Having many options is never for free. Even if you say: “I will only use a 10% of Guice” the rest of options are still there in the form of documentation and code. For example, they make you choose what approach to take. And my point is that with a pure Ruby approach, without external tools, you can solve the most common cases in a much simpler way. I suppose it is a matter of taste, but I enjoy that approach much more.
Strong types system
I don’t intend to talk about advantages and disadvantages of dynamic-typing and static-typing. But I would like to show an example of something that in my opinion is wrong. It is related to GWT concept of overlay types. It is a solution for managing JSON data as Java objects with GWT. This approach proposes to create a Java replication of the JSON data with getters/setters for the properties. The Java code has to be mixed with the javascript code to be executed via JSNI. An example taken from the GWT page:
class Customer extends JavaScriptObject {
// Overlay types always have protected, zero-arg constructors
protected Customer() { }
// Typically, methods on overlay types are JSNI
public final native String getFirstName() /*-{ return this.FirstName; }-*/;
public final native String getLastName() /*-{ return this.LastName; }-*/;
}
To me, it is like an implementation of the RY (Repeat Yourself) principle. I mean, do we need strong types that much? If this is the best abstraction you can do with Java of JSON data (and probably it is),
there must be something wrong with the language because JSON data is only about structures of key/value pairs that can be nested.
Parsing JSON data with Ruby or Javascript is trivial. I will use the former in the next example. It shows how one line of javascript code can convert a JSON string into a plain Javascript object (using the JSON parsing utility of Jquery).
var personJSON = '{"name": "Jorge"}';
var person = $.parseJSON(personJSON);
person.name; //Jorge
Object disorientation
The JSON example is a concrete example where dynamic typing just makes more sense. But to me, the essential problem of strong types is that they make more difficult to represent mental abstractions with code because every single piece must fit in a very strict puzzle of types. And this means that you are forced to code a lot of things that have nothing to do with your domain, but with the type system of the language.
Take for example the next GWT design. In GWT, widgets that trigger click events implements an interface HasClickHandler. This interface defines the contract of registering ClickHandler objects, which are responsible for processing click events. This is a materialization of the Passive View pattern: a view without any state with controllers performing all the work. The idea is to have a very thin view that can be faked in controllers tests.
Discussions about the pattern apart, there is no any possible human explanation that justify the existence of HasClickHandler
. And by “human” I am not being sarcastic. From a human point of view, it makes no sense. It makes sense under the constraints imposed by testing tools and, especially, by the Java language itself, where the only way to specify behavior in a modular way is through the addition of interfaces defining the contract.
Object disorientation is what happens when you go from “My view has a button I have to test” to “My view is stupid, I am going to create a HasClickHandler
getter in its interface so I can fake it when testing.” As of today, no technical choice is free of this problem, but in the case of Java, I think its effects are just overwhelming.
When considering using GWT a project I am working on, I was impressed by this presentation of Ray Ryan. I loved the principles and patterns discussed there for architecting the client part of a web application. The good thing about the presentation it that it focused on the concepts. The bad thing it that he showed very little example code.
It was when I saw how an example implementing those principles looked, that I decided I was going to study javascript hard. And it wasn’t because the authors didn’t make an excellent work with the example, but because I understood I wasn’t going to have fun programming that way. The bad thing is not that implementing the basic GWT “hello world” in the proposed way took 600 lines of code (without tests). The bad thing was how ugly everything looked, from top to bottom. And since having fun and beautiful code are two very important things to me, I discarded GWT, I studied javascript and Jquery hard, and worked a lot learning how to mount a good testing environment for this technology and a Rails backend. And I don’t regret at all of how things are going. Of course, there are other problems but those will be for another post.
It is curious. 7 years ago, Eric Evan’s warned the world about how important was to focus on the domain on his seminar Domain-Driven Design book. Both design and code should reflect it as much as possible. In this time, despite the big impact the book had in the Java community and all the discussions surrounding it, there is no still a mainstream implementation of many of the concepts he proposed. I wouldn’t say it is only due to Java being a poor language for representing the domain with code, but I think it has something to do with it.
Conclusion
I always find very difficult to explain what do I think is wrong with Java to other people. After writing this post, I still think the best way to understand it is to study other platforms and paradigms. In fact, the Java Platform offers nowadays a variety of languages, and some of them, like Groovy or Scala, are starting to attract a lot of attention. I still don’t know anything about Scala but I have used Groovy quite extensively and, although it has the same new
operator problem that Java, it is a very nice alternative.