(the other title: Your Application has a Wiring Problem)
In My main() Method Is Better Than Yours we looked into what a main() method should look like. There we introduced a clear separation between (1) the responsibility of constructing the object graph and (2) the responsibility of running the application. The reason that this separation is important was outlined in How to Think About the “new” Operator. So let us look at where have all of the new operators gone…
Before we go further I want you to visualize your application in your mind. Think of the components of your application as physical boxes which need to be wired together to work. The wires are the references one component has to another. In an ideal application you can change the behavior of the application just by wiring the components differently. For example instead of instantiating LDAPAuthenticator you instantiate KerberosAuthenticator and you wire the KerberosAuthenticator to appropriate components which need to know about Authenticator. That is the basic idea. By removing the new operators from the application logic you have separated the responsibility of wiring the components from the application logic, and this is highly desirable. So now the problem becomes, where have all the new operators gone?
First lets look at a manual wiring process. In the main() method we asked the ServerFactory to build us a Server (in our case a Jetty Web Server) Now, server needs to be wired together with servlets. The servlets, in turn, need to be wired with their services and so on. Notice that the factory bellow is full of “new” operators. We are new-ing the components and we are passing the references of one component to another to create the wiring. This is the instantiation and wiring activity I asked you to visualize above. (Full source):
public Server buildServer() { Server server = new Server(); SocketConnector socketConnector = new SocketConnector(); socketConnector.setPort(8080); server.addConnector(socketConnector); new ServletBuilder(server) .addServlet("/calc", new CalculatorServlet( new Calculator())) .addServlet("/time", new TimeServlet( new Provider() { public Date get() { return new Date(); } })); return server; }
When I first suggest to people that application logic should not instantiate its own dependencies, I get two common objections which are myths:
- “So now each class needs a factory, therefore I have twice as many classes!” Heavens No! Notice how our ServerFactory acted as a factory for many different classes. Looking at it I counted 7 or so classes which we instantiated in order to wire up our application. So it is not true that we have one to one correspondence. In theory you only need one Factory per object lifetime. You need one factory for all long-lived objects (your singletons) and one for all request-lifetime objects and so on. Now in practice we further split those by related concepts. (But that is a discussion for a separate blog article.) The important thing to realize is that: yes, you will have few more classes, but it will be no where close to doubling your load.
- “If each object asks for its dependencies, than I will have to pass those dependencies through all of the callers. This will make it really hard to add new dependencies to the classes.” The myth here is that call-graph and instantiation-graph are one and the same. We looked into this myth in Where have all the Singletons Gone. Notice that the Jetty server calls the TimeServlet which calls the Date. If the constructor of Date or TimeServlet all of a sudden needed a new argument it would not effect any of the callers. The only code which would have to change is factory class above. This is because we have isolated the instantiation/wiring problem into this factory class. So in reality this makes it easier to add dependencies not harder.
Now there are few important things to remember. Factories should have no logic! Just instantiation/wiring (so you will probably not have any conditionals or loops). I should be able to call the factory to create a server in a unit test without any access to the file-system, threads or any other expensive CPU or I/O operations. Factory creates the server, but does not run it. The other thing you want to keep in mind is that the wiring process is often controlled by the command line arguments. This makes is so that your application can behave differently depending what you pass in on a command line. The difference in behavior is not conditionals sprinkled throughout your code-base but rather a different way of wiring your application up.
Finally, here are few thoughts on my love/hate of Singletons (mentioned here and here) First a little review of singletons. A singleton with a lower case ‘s’ is a good singleton and simply means a single instance of some class. A Singleton with an upper case ‘S’ is a design pattern which is a singleton (one instance of some class) with a global “instance” variable which makes it accessible from anywhere. It is the global instance variable which makes it globally accessible , which turns a singleton into a Singleton. So singleton is acceptable, and sometimes very helpful for a design, but Singleton relies on mutable global state, which inhibits testability and makes a brittle, hard to test design. Now notice that our factory created a whole bunch of singletons as in a single instance of something . Also notice how those singletons got explicitly passed into the services that needed them. So if you need a singleton you simply create a single instance of it in the factory and than pass that instance into all of the components which need them. There is no need for the global variable.
For example a common use of Singleton is for a DB connection pool. In our example you would simply instantiate a new DBConnectionPool class in the top-most factory (above) which is responsible for creating the long-lived objects. Now lets say that both CalculatorServlet and TimeServlet would need a connection pool. In that case we would simply pass the same instance of the DBConnectionPool into each of the places where it is needed. Notice we have a singleton (DBConnectionPool) but we don’t have any global variables associated with that singleton.
public Server buildServer() { Server server = new Server(); SocketConnector socketConnector = new SocketConnector(); socketConnector.setPort(8080); server.addConnector(socketConnector); DBConnectionPool pool = new DBConnectionPool(); new ServletBuilder(server) .addServlet("/calc", new CalculatorServlet( pool, new Calculator())) .addServlet("/time", new TimeServlet( pool, new Provider() { public Date get() { return new Date(); } })); return server; }
7 responses so far ↓
Great post. Along with your singletons-are-pathological-liars stuff and the main() post I think you’ve just changed the way I code in about ten minutes flat. I thought I was a pretty good coder, but my whole view of dependencies just flipped on its head. Thanks for sharing.
Application Wiring on Auto-Pilot | Miško Hevery // Sep 24, 2008 at 10:36 am
[...] to separate the new operators from the application logic. This separation forces your code to have factories which are responsible for wiring your application together. By separating this responsibility the tests can always wire together a subset of an [...]
Another great post. I’ve been going through your articles over the past month or so and I feel like a light has switched on, in terms of my understanding of dependency injection, and singletons (which I was always unconfortable with, since they resembled so strongly the global variables I learned to hate long ago).
However, could you please write an article to clarify your position on what the boundaries between different factories should be?
Also, It would be nice to see a discussion on how you handle logging and non-member functions (or static methods in java).
Also, you seem to have a bunch of articles that mention GUICE, and I’ve seen a lot of other people excited about dependency injection frameworks, but I must say I could care less. I work in many languages, not just java, and I want a design pattern that works across languages, not some library that everyone who looks at my code will need to learn how to use.
Dependency Injection Myth: Reference Passing | Miško Hevery // Oct 21, 2008 at 8:01 am
[...] (the design anti-pattern) and how they are really global variables and dependency injection suggestion to simply pass in the reference to the singleton in a constructor (instead of looking them up in [...]
Testable (small) application with basic initialisation using dependency injection | Coding Answers // May 13, 2011 at 8:02 am
[...] function calls, and for the needed singletons such as app-wide DB connection, trying to apply Mr Hevery’s suggestions in this post and contain/wrap it in an object that will be passed along with other needed objects [...]
“(But that is a discussion for a separate blog article.) ” > Does that separate blog article exists ? I’m facing the same questions nowadays, and I can get what the proper level of factory is …
Hi Miško. I really enjoy reading your articles and I can say I learned a lot from them.
I would like to ask you something about factories. You say that “Factories should have no logic” and I agree that in most cases they shouldn’t. But, if wiring process is controlled by the command line arguments, wouldn’t there be code somewhere in factory that looks like this:
if (args[0].equals(“aaa”)) {return new ObjA()} else if (args[1].equals(“bbb”)) {return new ObjB()}?
Thanks.
Leave a Comment