I am now faced with integrating an inversion of control (IoC) container into an existing application, and I'm looking for some recommendations on how that can most easily be accomplished with the ultimate goal of reducing coupling, thereby increasing testability. Although I generally wouldn't classify most of the classes as god objects, each has too many responsibilities and hidden dependencies through statics, singletons, and lack of interfaces.Here is a bit of background some of the challenges that need to be faced:Dependency injection is infrequently usedStatic methods abound - both as factory and helper methodsSingletons are fairly prevalent Interfaces, when used, are not too granularObjects often pull in unneeded dependencies through base classesOur intent is that the next time we need to make changes in a particular area, that we try to tease out dependencies which, in actuality, exist but are hidden behind globals such as singletons and statics.I suppose that makes the IoC container secondary to the introduction of dependency injection, but I would expect that there is a set of practices and recommendations that could be followed or considered that will help us break out these dependencies.
Recommendations on integrating DI/IoC container into an existing application
design;dependency injection;maintenance
In order to pull off something like this, you will have to work in steps, each one of these is not trivial but they can be accomplished.  Before you begin, you have to understand that you cannot rush this process.Define the major subsystems of the application and an interface for each of them.  This interface should only define the methods that other parts of the system will use to talk to it.  NOTE: you may have to take more than one pass at this.Provide a wrapper implementation of that interface that delegates to the existing code.  The purpose of this exercise is to avoid rewriting en mass, but to refactor the code to use the new interfaces--i.e. reducing the coupling in your system.Set up the IoC container to build up the system using the interfaces and implementations you created.  At this stage you want to take care of instantiating the IoC container so that it can bring up the application.  I.e. if you are in a servlet environment, make sure you can get/create the container in the servlet init() method.Do the same thing within each subsystem again, this time when you refactor, you are turning your stub implementation into the real thing which in turn uses interfaces to talk to it's components.Repeat as necessary until you have a good balance of component size to functionality.When you are done, the only static methods you should have in your system are ones that are truly functions--for example look at the Collections class or the Math class.  No static method should attempt to directly access other components.This is something that will take a lot of time, plan accordingly.  Make sure that as you perform your refactoring you are becoming more SOLID in your design approach.  In the beginning it will be painful.  You are drastically changing the design of your application iteratively.