Discussions

News: Examining the Validity of Inversion of Control

  1. Examining the Validity of Inversion of Control (72 messages)

    Inversion of Control (IOC) is a new pattern that has been gaining popularity recently. In a new article on TSS, Sony Mathew challenges injection-based IOC as a contradiction to object encapsulation and instead proposes Context IOC, a new approach that attempts to capture IOC as a pure design pattern, "without any baggage".

    Read: Examining the validity of Inversion of Control

    Threaded Messages (72)

  2. Am I missing something?[ Go to top ]

    How is "Context IoC", as you describe it, different than simply injecting a service locator? I really don't get what using a inner interface called "Context" to express an objects dependencies buys you. It seems a bit too generic for my tastes. I also think many inner interfaces all called "Context" would get confusing, both to me and my IDE auto-import.

    Several other things stood out me with this approach:

    I didn't really like how some of the examples are tied to hard coded implementation classes. For example, the JobServiceImpl instantiates a MatchStrategyFactory implementation directly. Why not make MatchStrategyFactory an interface and inject it, or inject a locator interface (possibly segregated) that can find a configured MatchStrategyFactory instance?

    I don't really like how the 'upper' service layers of the system seem to inheritenly know about the the implementation details of all the lower layers. For example, the highest layer example -- the JobServiceEJB -- knows about the DAO implementation, the persistence connection details, etc.)

    I also don't get the compile time disadvantage argument when referring to IoC. Interfaces passed into an object are strongly typed; any change to those interfaces is caught at compile time. Glue code to wire up the configuration of an application (selecting which implementations to use at startup) can also be done in javacode and verified at compile time--use of "IoC" doesn't preclude that.

    In general, I consider use of an IoC container to wire extremely fine-grained dependencies for an object both an abuse of the container and a design smell. The first question to answer is why that brittle object has a million dependencies (it's probably doing too many things), and then seriously rethink your design. You don't need a IoC container to achieve a sound OO design: IoC containers are there to help manage the configuration and layering of an application in a consistent (and often externalized) manner, and (hopefully) in the process promote loose coupling, high cohesion, re-use, easy testing, blah blah.

    IMO to create an effective system design you need two things above all else: a good understanding of the problem domain, and developer worth his or her salt :-)
  3. Am I missing something?[ Go to top ]

    +1
  4. Am I missing something?[ Go to top ]

    +1
  5. Am I missing something?[ Go to top ]

    In general, I consider use of an IoC container to wire extremely fine-grained dependencies for an object both an abuse of the container and a design smell.

    In my opinion, IoC should not be used to configure every aspect of a given object, but only those which will have to change if you want to modify the behaviour of the instance (e.g., strategies). Making all dependencies configurable not only breaks encapsulation, but also violates the KISS principle, why I'd consider this a breach of agile methodology.

    Cheers,
    Lars
  6. Am I missing something?[ Go to top ]

    I agree with Lars. That's why I favor constructor injection. A public setter is communicating that you can externally change the state of an object at runtime, while IoC is usually meant to configure the initial state of an object. Very different semantics.

    Maurizio
  7. Constructor injected IoC[ Go to top ]

    I agree with Lars. That's why I favor constructor injection. A public setter is communicating that you can externally change the state of an object at runtime, while IoC is usually meant to configure the initial state of an object.

    That's why I didn't opt for Spring framework early on (I know they support Constructor injected now). In terms of IoC framework I just use PicoContainer (not Nano as of yet) because I noticed that I had constructors that looked like.

    <code>new A(new B(new C(new D(), new E()))</code> and I create a separate class that just took the whole constructor chain into one class that just did the constructor that knew about all the classes which I didn't really like to do. PicoContainer also does it in one class, but I find it cleaner because I just dump the whole set of classes into the container.
  8. Am I missing something?[ Go to top ]

    That's why I favor constructor injection. A public setter is communicating that you can externally change the state of an object at runtime, while IoC is usually meant to configure the initial state of an object. Very different semantics.
    I agree.
    Annotations could help on this. If, for example, we can mark some setters as being of the kind "dependency injector", it's possible to detect the problems at (pre)compilation time.
  9. Am I missing something?[ Go to top ]

    I have no experience with IoC, I only know that when I have things that I want to have configurable, I usually use a Factory pattern.

    I need something that can persist a poolgame, but the implementation can vary? Use a factory to generate something that implements the poolPersist interface and let the factory decide which implementation to return. I don't like having external configuration files wiring up my code.
  10. Am I missing something?[ Go to top ]

    Use a factory to generate something that implements the poolPersist interface and let the factory decide which implementation to return.
    (Emphasis mine.)

    So, how do you let the factory decide? By hardwiring the configuration into your factory code? And if another implementation of the said interface is added? (Hint: You'll have to change the factory.) And by the way: How will you retrieve a reference to the factory?

    Just askin',
    Lars :-)
  11. What's the problem with the factory?[ Go to top ]

    Hmm, what's the problem with the factory based on a config file and late instantiation? I would also directly reference the factory ...

    Br,
    Deyan
  12. What's the problem with the factory?[ Go to top ]

    Hmm, what's the problem with the factory based on a config file and late instantiation?

    Essentially, nothing. This solves one of the irritating problems with using interface seperation in the design. Something has to know about the actually implementing class at some point (instansiation). You have choosen to use the factory pattern to hide creation from your dependant code and use a config file as the part of the software that 'knows' about the actual implementation class.

    So, now you set to work decoupling your design. Interfaces everywhere...GREAT! Factories everywhere.... HMMM not so great. You have factories and configuration files for everything.

    Perhaps you decide that enough is enough and have your factories 'create' method take a interface name as a parameter and implement a single factory that just returns instances of the interface name passed to it. Now you have cut down on factory classes, but the system can only ever deal with 1 type of instance. If you ask for a datasource, you will always get the same one. What about when your web controller wants a 'view' instance. Do you ask for the logon view by name?

    Factories work, and for simple stuff are totally sufficient. As things become more complex IoC becomes a better choice because of the flexibility. There is no need for factories of the kind you mention. You can provide 10 different DAOs with 10 different Datasources, all with the same, or anywhere inbetween without reimplementing a line of code or having the DAO know it is talking to a different datasource.

    Its a flexibility thing.

    In short, nothing wrong with factories, they are just a few stops back down the line for this particualar thought train :o).
  13. SPI[ Go to top ]

    Essentially, nothing. This solves one of the irritating problems with using interface seperation in the design. Something has to know about the actually implementing class at some point (instansiation). You have choosen to use the factory pattern to hide creation from your dependant code and use a config file as the part of the software that 'knows' about the actual implementation class.So, now you set to work decoupling your design. Interfaces everywhere...GREAT! Factories everywhere.... HMMM not so great. You have factories and configuration files for everything. Perhaps you decide that enough is enough and have your factories 'create' method take a interface name as a parameter and implement a single factory that just returns instances of the interface name passed to it. Now you have cut down on factory classes, but the system can only ever deal with 1 type of instance. If you ask for a datasource, you will always get the same one. What about when your web controller wants a 'view' instance. Do you ask for the logon view by name? Factories work, and for simple stuff are totally sufficient. As things become more complex IoC becomes a better choice because of the flexibility. There is no need for factories of the kind you mention. You can provide 10 different DAOs with 10 different Datasources, all with the same, or anywhere inbetween without reimplementing a line of code or having the DAO know it is talking to a different datasource. Its a flexibility thing. In short, nothing wrong with factories, they are just a few stops back down the line for this particualar thought train :o).
    Look at Sun's SPI, such as the the ServiceRegistry in the Image IO API in around since Java 1.4. I've looked into this from time to time and like it so much, I emulate it myself.

    You're basically saying, for some interface, give me *all* of the implementations of it using the lookupProvider methods. Your "providers" should either be quick and snappy, or ligthweight proxies to the real class (i.e. a factory).

    My favorite part about the way Sun did it (and I copied) is that you can configure simply by dropping jars in/out of the classpath. Want to use implementation A? Drop its jar in the classpath. Prefer implementation B? Drop it in the classpath instead now.

    This doesn't solve all of the configuration problems (i.e. your service providers may still need to be configured themselves), but it is a nice way to decouple your work from specific implementations.
  14. I have a couple of issues with the factory pattern:

    1. I think actively looking up dependencies (via factories) mucks up the code of my objects. This is probably a personal reason rather than a technical reason. I just find that having objects' dependencies injected keeps them "cleaner".

    2. Testing is a little tricker for object that use factories. Suppose you you want to unit test an object that depends on antother object (perhaps a DAO object) that is obtained from a factory. You probably will want to mock this DAO object, right? Well, since this object is obtained from a factory, you will have to configure this factory in your test case as well, configuring it to return the mocked version of you DAO. That's just more set up. With dependency injection, you simply configure the object you are testing directly with any mocked dependencies - much more straightforward.

    On a side note, as we started introducing IoC (Spring in our case) into our major applications, we were "phasing out" custom factories at the same time. So that this did not have to be an all-or-nothing thing, we actually retrofitted our factories to be dependency injected by Spring, so all of our configurations could be managed in one place.

    Ryan
  15. I use Spring on a day to day basis and I also use the factory pattern.

    Sometimes I'll make use of Spring's FactoryBean feature (which is leveraged heavily by the extensions to core IoC framework, see all the implementations in the JavaDoc or your IDE). Like a traditional factory, A FactoryBean encapsulates object creation and lookup logic (it may implement that logic directly or delegate to a POJO Factory decoupled from any Spring implementation). The result produced by the FactoryBean is then injected to the collaborators that need it. The key point is the collaborating objects that need a custom-factory-produced object never know that the factory existed in the first place...

    But I've also developed my own custom factories, particularly when they serve a core business logic function, and other object(s) needs to be aware of them. And in that case, a IoC container can configure them, too, and pass them to clients. Or they can be instantiated directly in code by hand, if you know their implemnetation is unlikely to change or that they serve a internal implementation detail--it all depends.
  16. Interesting point in development...[ Go to top ]

    hey there!

    I find this article interesting b/c even before i read any replies - it was obvious to me that this is certainly another way to design code that might otherwise be encapsulated objects that use factories.

    In a system i recently designed, i effectively made the business objects live in a flat layer denoted as *Service objects. These objects used factories most often to get their biz logic done off of a stateless EJB facade. The service objects are completely independent of any "top-level" classes, and require only Strings and Integers for parameters. These services objects are used by a layer that is controlled by - you guessed it ;) a servlet! The servlet implements an "Action" interface which is passed to IOC classes that know which business objects to call - depending on the properties of the passed implemented interface class. Our action interface is effectively like the Context interface that is described in the article.

    The reason i find this appropriate for the article is b/c we maintain encapsulation of our business objects, but found it appropriate to use the Context IOC type pattern for the purpose of a "contract" (ie interface time) between the action and the delegation of the business logic. It was also most appropriate b/c the servlet uses a single point of exit to maintain a consistent logging point for the result of the object graph.

    This make sense to anyone?
    Anyone use something along these lines?

    I guess what i am saying is that when necessary - if one keeps in mind reuse (decoupling) of their biz objects - then encapsulization and Context IOC are a very natural pair

    I think this real world ex might be a bit better than the pool example? I think the fact that the params come from the servlet as String and Integer also make it very easy on the interface and i think that although my example points out how the two are complimentary - it also points out that i do not pretend to put biz logic in a class that is coupled to a higher level object

    Sorry for my lack of "the whole brevity thing", but i read all of your posts too!

    Thanks!
  17. quick fix -[ Go to top ]

    *quick fix - the servlet does not actually "implement" the interface - i should have used a diff word - it sets the properties on the concrete class and injects it into a class called *ControlDelegate. The *ControlDelegate(s) are actually built from an xml descriptor file that connects the appropriate actions to the delegate code classes - kind of my own annotation machine for code that always does the same thing - get the params - figure out how they should be ordered - figure out where they are going - and send them along!
  18. Am I missing something?[ Go to top ]

    I think you guys are missing these key points:

    Context Extention as a way to propogate dependencies upstream.

    The Context interface is unique to the class like for JobConfig.Context and therefore that object can only see the isolated view of its needs and not the needs of other objects in the graph.

    Enterprise examples (a version of which was implemented in the real world and works great). PoolGame was just a simple example to demonstrate the use of Context.

    Context IOC in essence incorporates every pattern. Injecting a ServiceLocator captures a small sliver of what its capable of.

    Context IOC is a general purpose IOC design pattern requiring only Java language expression - without the need for Containers and provides strong type-safety. Generic containers loading Java classes as generic descriptors will be like any other descriptor file - essentially a descirption with quoted strings - the container cannot be generic otherwise.

    Context interfaces will not be any more ballooing than a bunch of setters. They organize the needs into a proper location that can be extended, propogated and implemented in a strong type-safe manner.
  19. Am I missing something?[ Go to top ]

    +1
  20. Am I missing something?[ Go to top ]

    Keith,

    You are suggesting that I add another indirection to the already existing indirection that is the MatchStrategyFactory. How would I get an implementation to the MatchStrategyFactoryFactory or maybe the MatchStrategyFactoryFactoryFactory.

    In anycase, If the Service didn't construct the MatchStrategyFactory then it would have to be constructed by the top-usecase assember. I talk about distributing the work of assembly to large grained intermediary units like a Service - otherwise you have a bloated assembly at the top breaking all kinds of encapsulation i.e leaning towards the extreme horizontal dimension of IOC.
  21. Am I missing something?[ Go to top ]

    Keith,You are suggesting that I add another indirection to the already existing indirection that is the MatchStrategyFactory.

    I'm just admitting seeing this in the code raised my eyebrow:

    <code>
    public class JobServiceImpl {
         ...
         new MatchStrategyFactoryImpl(...);
         ...
    }
    </code>

    JobServiceImpl is selecting her MatchStrategyFactory implementation, and now has hard-coded herself to that implementation and the creation logic coded within it. All I'm saying is if you remove JobServiceImpl's responsibility from being a creator of its own MatchStrategyFactory, but instead a collaboator with an existing implementation (through a well-defined interface), it's a lot easier to vary implementations and thus behaivior (as well as mock or stub.) You can achieve this by injecting a reference to a MatchStrategyFactory, or a reference to a locator which knows how to find a MatchStrategyFactory.

    One last issue I had with this article: the terminolgy. You say Store where most people say DAO. You say Context IoC where most people say Service Locator (or dependency lookup). And your "context extension" term seems like a form of a segregated interface, a term Martin Fowler used in his article on dependency injection vs. lookup. Building on pre-existing terminology is essential!
  22. Am I missing something?[ Go to top ]

    Keith,

    Yes, I thought about using DAO instead of Store but I wanted to pay homage to a name I have been using for this purpose long before DAOs ever became popular.

    ServiceLocator has been generally used as singletons to lookup heavyweights like EJBs. It was generally also accessed directly by anyone including low level objects that wanted a service and therefore was the antithesis of IOC. Giving the name a facelift now to incorporate it into IOC even if proposed by a popular guru is not something I agree with.

    Context IOC is really an IOC twist on the already popular Context pattern that accesses contextual needs in a generic way rather than a type-safe manner. Context Extention merely refers to object extention of Contexts which is a concept that existed long before "segrated interfaces" - what the hell ???

    Yes, you can declare the MatchStrategyFactory in the Context of JobMatchServiceImpl thereby relegating to a higher authority on which instance is created. But, I felt that testing the logic of large grained units should test its assembly work as well as its flow. After all, all objects assemble some group of objects into some flow.
  23. Am I missing something?[ Go to top ]

    Sony,

    Here are two articles discussing dependency inversion (IoC) and the term 'segregated interface':

    http://www.objectmentor.com/resources/articles/isp.pdf
    http://www.martinfowler.com/articles/injection.html
  24. Am I missing something?[ Go to top ]

    +1
  25. First of all, I think this is a great article. Even for a person not so well-versed with the IoC concept it brings out it's benefits nicely. More importantly, it is not tied to an IoC container, which to me is a great plus because it helps introduce IoC without introducing another container in an existing framework.

    I think I understand what Sony is saying about the responsibility of each Interface implementation being pushed down the heirarchy.
    The business interfaces improve some clutter but you have essentially pushed the clutter down to the implementations - swept it under the rug as it were.
    However, I dont see an example of this. In the example given, the ServiceContext class (in the top level service class) implements ALL the interfaces. I thought the idea was that each class would implement the relevant interface. At whatever level it exists. But looking at this example it seems difficult to achieve because it all comes together at the top level. (Cannot implement JobMatchServiceImpl.Context at because the connection is not available there). But, if at all, this was possible, in a deeper heirarchy of objects, would this approach be advisable? Wasn't that the intent of that original quote?

    Thanks again for a great article and discussion.

    Pankaj
  26. I don't like the traditional Constructor Injection when configuration files are used to wire up objects. The problem is that such configuration relies on position and type of constructor arguments, but not on argument names. Because of this reason configuration file looks pretty puzzled and hard to understand without consulting the object’s documentation (e.g. JavaDoc).

    The problem is perfectly solved by using Setter Injection; however Setter Injection exposes two much more serious problems. The first problem is that often it is not obviously clear which setter methods of the object are supposed to be used only by IOC container to initialize object and which setter methods are allowed to be used further in object's lifecycle. By incautiously using setters which are there just to perform object's initialization one can easily corrupt the object's state further in object’s lifecycle. The second problem is that one can easily miss to set a setter, which must be set during object’s initialization, leaving the object not completely initialized. Both problems can be minimized by good documentation and proper implementation of object's internal logic; however they are much more elegantly solved by Context IOC.

    Context IOC uses Constructor Injection to initialize object. This solves both problems exposed by Setter Injection and described above. The object’s constructor can check the given context to see that all required setters are really set and after that it can copy/clone the context to its internal state which cannot be further changed by changing the context. That Context IOC uses Setter Injection to construct the context, but it doesn’t have any drawbacks, and the configuration file doesn’t look puzzled since the configuration file relies on property names which are normally quite expressive by themselves.

    Dominik
  27. I would have to agree with Keith that Context IoC is really just a different strategy for the Service Locator pattern. Instead of a public singleton we have a private, component-specific version.

    Setter injection does expose dependencies alongside methods for component behavior, but this strikes me as something easily solved with traditional interface separation. The component implements the business interface, adds any number of additional setters for configuration and client components only ever communicate with the component via the business interface.

    A private service locator is more testable than a public singleton to be sure, but I don't think it qualifies as a completely separate pattern. In fact all of these techniques seem to boil down into two strategies to solve a general Dependency Management problem. We have Bean Managed Dependencies (singleton service locator, private service locator) and Container Managed Dependencies (constructor, setter and field injection). The latter are much more test friendly while the former give complete control to the component over when dependencies need to be acquired or re-acquired.

    The author's C++ background is really showing through in this design. Dogmatic use of delegation to preserve "binary interface compatibility" has the "pimpl" pattern written all over it.

    Merrick
  28. Setter injection does expose dependencies alongside methods for component behavior, but this strikes me as something easily solved with traditional interface separation. The component implements the business interface, adds any number of additional setters for configuration and client components only ever communicate with the component via the business interface.

    Perfectly stated. This is exactly why, although there are sound theoretical objections to setter-based dependency injection, in practice it becomes a non-issue.
    The approach shown here seems to balloon up the code.

    That's putting it mildly. When Mr. Mathew suggests ways to 'improve the design' of our services by making them harder to write, harder to read and maintain, and less portable across popular Dependency Injection frameworks, I get the impression that he could benefit from a bit more real-world project experience.
  29. +1
  30. Setter injection does expose dependencies alongside methods for component behavior, but this strikes me as something easily solved with traditional interface separation. The component implements the business interface, adds any number of additional setters for configuration and client components only ever communicate with the component via the business interface.

    I agree with Merrick that business interfaces resolve the encapsulation issue. Setter injection also allows you to define delegate objects in a manner that preserves and enhances separation of concerns.

    I believe Context IoC violates separation of concerns by requiring the top-level service context to implement all of the lower-level delegate interfaces. This creates one large Uber-object that becomes the service container. So in essence you implement a new container for every service.

    I much prefer the Setter Injection method with a container specialized to that purpose.

    Chuck
  31. Chuck,

    Any break in encapsulation as you suggest with Context IOC will also appear in Injection IOC within your descriptor file.

    The Uber object you are talking about is a specific Context implementation for a specific usecase and can contain system level logic. The Context Impls can be analysed, refactored, reused etc. and can have their own object heirarchy with their own tests. Essentially, they can be un-uberized with proper object analysis. Not so easily done with a generic container that attempts to read a descriptor file.
  32. Sony, I agree the service context could be refactored into multiple implementation classes that provide separation of concerns but, because the service context is required to implement all of the subordinate context interfaces, you would have to add delegation methods for the parts you factored out of each intermediate context. This results in additional dependencies and extra levels of indirection.

    The deep interface inheritance hierarchy of Context IoC has more downside, in my opinion, than the small loss of encapsulation in Injection IoC.

    Another downside for me is that there is no cross reference showing the linkage between the context implementations and the business objects. The XML context file used by Spring provides this cross referencing.

    Chuck
  33. Generic Container and Context IOC[ Go to top ]

    A core point people keep missing is that Context IOC is meant to be a general purpose IOC pattern requiring only Java Language Expression and not a container.

    People that need a generic container with a descriptor file can easily get one. A generic container can easily implement an Xyz.Context interface using a dynamic proxy and read a descriptor file. The descriptor file will be clearer as well - expressed as a Java Bean proprerties of the Xyz.Context. Each property descriptor can additionally include directives of scope and handling to the container. You still maintain a high level of type-safety.
  34. Dominik, thank you for a great supporting comment. I hope some of the others have had a chance to read it. I should have expressed some of your points in my article - maybe on the next one.
  35. Inversion of Control (IOC) is a new pattern

    No it's not.
  36. The article is a lot interesting... but much more interesting is the argument that is derived!

     It compliments to everyone that it has contributed!

    Every observation capture an aspect of the common problem, the true problem: the dependency between objects!

    I would want to propose one idea: to develop pattern language... "Big M. Fowler " has opened the way... we must follow it! The starting point, to me, is composed of two forces: Object Encapsulation and Protected Variation(Larman' s GRASP)...

    I speak about these two factors inasmuch as the unit testing it needs of the objects in isolation... It's necessary also to protect from the "net of collaborations" and therefore we have need of the techniques of Protectd Variation...

    Cleared these concepts... We can characterize two main categories: passive protection and active protection!
      
    Passive protection:

     - creation process (factories, config file,...)
     - search process (locators...)
     - wiring of objects (observers, builders,...)

    Active Protection: it is divided in directed and filtered

     directed:
                - Constructor IOC
                - Setter IOC
     filtered:
                - Interface IOC
                - Context IOC (please read this:http://www.allankelly.net/patterns/encapsulatecontext.pdf)
                - AOP IOC

    The directed and filtered distinction between is born from the fact that in the first case is had, generally, "direct" passage of objects while in filtered there are (can be) preprocess and/or postprocess to alter objects!

    Last observation! To entrust itself too much to a presumed "light container" and to have many small services, not us door to the risk to return to a procedural approach? Why instead that focus only on IOC, we do not improve or create tools to express executable models of the facts?
    Sorry for my english e for the time lost!
    You are Fantastic People!

    STEFANO FAGO
  37. hi!

    The article provides an interesting view on IoC.

    It seems that this article describes a way of IoC that is very much in the spirit of how a component describes it's dependencies on the outside world: sticking with the PoolGame example, the PoolGame defines that it needs an implementation of draw() and savePoolGame(), among other methods, and these methods are then simply combined in the context-interface of the PoolGame component. Thus the PoolGame component pretends that it does not know which objects in the application implement this desired functionality but rather it describes in a self-centred way what it needs.

    With the currently common interpretation of IoC, however, it would be more common for the PoolGame to describe it's dependencies to (within the application) well-known interfaces that provide the required functionality, e.g. a Canvas for draw() and a PoolGameDAO for savePoolGame(). This couples PoolGame much more to these other interfaces, but it also expresses the fact that PoolGame is "just" an object in a web of co-operating objects that's wired-up by the IoC container.

    I prefer the latter approach as it seems more direct.

    The article cites cluttering of interfaces with getters/setters/constructor-arguments as a problem of current IoC. This problem is largely avoided if this "dependency clutter" is pushed down to the implementation class, whereas the interface that this class implements just contains the essential business methods.

    Regarding compile-time safety of wiring-up an object graph: I suppose one could write an implementation of a (e.g.) Spring BeanFactory that uses a dynamically loaded Java class rather than an XML file to define objects and their dependencies. I need to think about whether this makes sense...

      cheers,
      gerald

    --
    http://www.gerald-loeffler.net
  38. hi!The article provides an interesting view on IoC.It seems that this article describes a way of IoC that is very much in the spirit of how a component describes it's dependencies on the outside world

    Exactly. To me, if in need of a way to describe your dependencies (not satisfy them), you could use annotations, couldn't you. Personally I wouldn't like it, so I stick with getters and setters and the occasional constructor. The distinction between getters and setters needed to express dependencies and those important to actual functionality of the class can be made by correctly using interfaces!

    I don't think we should overemphasize the need for IoC to become a first-class design pattern and go all about how to best implement 'it'. Personally I think sticking to framework-agnostics techniques (getters/setters or constructors and also annotations) is the best way to go forward.
  39. Personally I think sticking to framework-agnostics techniques (getters/setters or constructors and also annotations) is the best way to go forward.

    I agree. There is no real need to see IoC as a design pattern, because it has little impact on you application code other than the requirement for a few JavaBean-style setters which have the nice side effect of making the code more testable.

    The solution proposed here seems like an application-specific version of Contextualised Dependency Lookup. In a standard CDL setup the Context is similar to the Spring BeanFactory and dependencies are accessed via String keys. In this approach the Context has application specific extensions. This seems like an awful lot of extra code to create and manage for no tangible benefit.


    Rob
  40. Gerald,

    Context interfaces can be analyzed and improved to any degree. I mention this clearly in the article.

    If you find certain methods like draw() are best represented in a an interface called Canvas - then do so - however you still need an implementation of the Canvas and the Context would then declare a getCanvas() instead of draw().

    This is what is done with methods of findXyz() and saveXyz() type nature ... they are grouped into a Store or StoreReadable interface and then objects declare their dependency to these.
  41. The author has confused validity with type safety. Validity is can only be proven using tests (and experience).

    Whether you call them lightweight containers, Inversion Of Control (IOC) or Dependency Injection (DI) ... the point is to simplify and reduce the amount of code.

    The approach shown here seems to balloon up the code.

    Further, this "context" is, to my eyes, just another collaborating service, and is almost certainly a facade around other services ... how is it created? It is telling that for all the code samples cluttering this article, we never see an implementation of a Context or the code that would create an instance of one.

    So, instead of directly injecting collaborating services, we inject just one facade around collaborating services. Great ... yet another interface! And this doesn't make the PoolGame code correct ... how do we know that it is retaining the context and using it correct? By testing. What have we gained with the extra abstraction? Nothing.

    I have seen a common thread among people who "don't get IOC" that they confuse an object constructor with the construction of a service.

    The object is not the service (it's a key part of the service, but not the service itself). The object's constructor is not the service's constructor.

    Adding more code never makes things simpler! This kind of heavy weight approach just shifts the design towards more heavyweight, monolithic services. I prefer the opposite ... small, easily testable services with minimal dependencies.

    In Tapestry 3.1 (which is built on the HiveMind microkernel), most of my services inject fewer than three collaborators, often just one or two. So, even though there are dozens of individual services, testing is under control because no single service is that complicated. I know the system works because I do very complete unit testing, plus a good amount of automated integration testing.
  42. Howard,

    From my view, ServiceContext is the Context implementation in the JobServiceEJB. Yes, it's essentially a facade/service locator implementation that exports selected implementations of the services the other objects of this example system need. This single facade is pushed down to the lower layers, where lower-layer components then use segregated locator interfaces that express just what they need access to.

    While the approach is interesting and creative, I agree it does balloon up the code some, and for sure, the ServiceContext implementation is quite ad-hoc and not any where as powerful as an optimized, specialized IoC container. That's a key point I think--IoC containers are really good at object assembly and configuration and service lookup providers - why not use one, even with this example design?

    My primary concern with this design is it seems to push a single big facade object down to the lower layers. I'd rather that each of the components of the lower layers (JobService, JobStore, etc.) be configured independently with explicitly what they need to work, and then be built upon by a higher-layer facade, instead of the other way around.

    Keith
  43. I agree. In addition I think the context IoC obscures the service dependencies. It sounds like a service will be torn apart into multiple contexts and will be littered thoughout the system and in contrast to the claim, convolutes the entire problem space. And I am not sure how these contexts are wired together either.
  44. More missed points[ Go to top ]

    Another key point being missed is that with Injection IOC an object declares a bunch of setter methods. For each of these setters you need member variables etc. to hold on to these. With Context IOC these just turn into getters that are grouped into the object's own personalized Context interface. Your object has less work to do since you now just hold "one" context member variable. Getters can be implemented outside with lazy instantiation logic - not as easiy with Injection - since all dependencies have to be injected before the object can work. The same getter and its lazy initialization can be used by many objects in the graph.

    Most of all, by capturing your getters into a Context vs. having the same number of setters for Injection you can now extend and reuse Contexts.
  45. More missed points[ Go to top ]

    For each of these setters you need member variables etc. to hold on to these. With Context IOC these just turn into getters that are grouped into the object's own personalized Context interface. ... Getters can be implemented outside with lazy instantiation logic - not as easiy with Injection - since all dependencies have to be injected before the object can work.

    Existing IoC solutions already offer something like this: lookup methods. Define getters only (if you like you can make them abstract) and have the IoC solution implement them, anyway you like (pooled, threadlocal, whatever). I generally don't like this solution since you have to rely on a specific solution (in this case Spring) to generate the implementations doing the lookup for you and furthermore you have to do extra stuff to get it to work in your unit test.

    Yes, the Context IoC pattern (again, I don't think we should generalize IoC into a design pattern) removes the need to generate getters and setters and groups dependencies into a single interface, but except for the reuse of groups of dependencies (what about YAGNI) I don't see the real difference between Context IoC and the proper use of interfaces, inheritance, etcetera.
  46. More missed points[ Go to top ]

    but except for the reuse of groups of dependencies (what about YAGNI) I don't see the real difference between Context IoC and the proper use of interfaces, inheritance, etcetera.

    Err, yes I do see a difference:
    Basically, I feel like this pattern is attempting to solve a problem that isn't there. Introducing this Context interface everywhere just adds additional complexity and I don't see any real benefits to doing so.
  47. More missed points[ Go to top ]

    Alef,

    Do read the reply I placed for Jacob.
    Also, the comment on how you can easily use a generic container with Context IOC if people desire.

    Propogating dependencies upstream is a very important feature of IOC and it is very crude to do so with constructors and setters.

    Context Extention is a great mechanism to propogate a helper's dependency upstream. It is also a solid contract.

    If you flatten out your object graph with no nesting whatsoever i.e. no object constructs another then you have a very bloated assembler at the top who knows every little detail of every object - throwing out encapsulation altogether. The top assembler should only be managing large grained objects that need cross object boundary managment and let other dependencies be completely encapsulated.
  48. In Tapestry 3.1 (which is built on the HiveMind microkernel), most of my services inject fewer than three collaborators, often just one or two. So, even though there are dozens of individual services, testing is under control because no single service is that complicated. I know the system works because I do very complete unit testing, plus a good amount of automated integration testing.

    I agree the author is confused between validity of his code and type safety.

    For the most part we can guarantee type safety in Java, because we would need to extend the language to support new construct.
    EmployeeBean expectedBean = foo-construct<EmployeeBean> as IoC_Assembler.getBean( "Johnny Depp" );

    Of course this is a made up construct, a type of self-fulling compile and run-time checking cast does not exist. In the same way that Java expanded the byte code
    in the class with annotations, it would need big support
    and proof to open up the object creation and garbage
    collection hooks into the language proper. Those of the
    C++ background with now of the hook methods for <code> new</code> and <code>delete</code>. Instead developer extended the language (aspectj) or built IoC/AOP frameworks

    I do not agree with the lost of encapsulation. Because even if C++ there is such of thing as a <code>friend</code> to get out the mess that would made if you were writing a <code>Momento</code> class.

    I am very confused by the article. With all these context interface and especially the last part where there is a MatchStrategyFactory with context that extends a half a dozen context. When I looked at this code on the way home on a train I kept thinking K.I.S.S and also Albert Einstein famous anecdote ("Close but no closer"). In fact I read page one to four quicker, but then I was unconvinced on the paragraph "Context Extension".

    On Tapestry 3.1 you claim that the services inject fewer than three collaborators. On claim I can give to the author of the article, that the XML configuration for IoC is not the same as programming an Object in Java. I think for some types of IoC this is like the constant K ( a problem in the great IoC and AOP and ServiceLocator unification ). Does Tapestry 3.1 improve the XML descriptor hell in any way?
  49. I believe the article is refering to the validity of IOC in general regardles of implementation and then later the type-safety of Injection IOC.
  50. Howard,

    Validity vs. type-safety - I don't understand why people are mixing up the two concepts.

    The article focuses on distinct features. On the one hand I was examining the validity of IOC in general regardless of implementation (Context or Injection) and on the other hand, I was pointing out the type-safety issues of Injection IOC.
      
    I read your article Howard about IOC being like the garbage collection initiative. Garbage collectors don't need a descriptor file to tell them what to collect. Garbage collectors also don't work to their hype, memory leaks are just deadlier now - harder to detect. It is however better for the momment cause we just point the finger at someone else when our apps are misbehaving and we have learned to accept the consequences.

    I would like to compare Context IOC vs. Injection IOC to object-oriented vs. procedural. There is nothing that OO can provide that procedural languages can't provide. Infact, that was the case made for a decade that inhibited OO from reaching its full potential. But when you organize a group of procedures into an unit - its clearer -and provides better encapsulation and extention for reuse. Similarily, when you organize a bunch of setters used for injection into a logical unit that delivers the contextual needs of an object - you get all kinds of new functionality in terms reuse and encapsulation.

    I know full well that anything that can be done with Context IOC can be achieved with Injection IOC - they are both IOC but I think Context IOC provides better features.

    Context IOC is just IOC in a different format, one thats a pure design pattern and does not need a container. But it does not mean a container cannot be used.

    People that need a generic container with a descriptor file can easily get one. A generic container can easily implement an Xyz.Context interface using a dynamic proxy and read a descriptor file. The descriptor file will be clearer as well - expressed as a Java Bean proprerties of the Xyz.Context. Each property descriptor can additionally include directives of scope and handling for the container. You will still maintain a high level of type-safety.
  51. solid example of rewiring?[ Go to top ]

    Is there a solid example of the need for completely rewiring objects from a configuration file? It seems like you aren't gonna need it to me.

    Also, setters are needed when services are only available at certain points in a state machine. Not all services are ready at construction, espcially if there is bootstrapping going on.
  52. named arguments for Java[ Go to top ]

    I wish Java had named arguments so that the issues pertaining to constructor IoC could be pretty much solved. Then could use that instead of setters in conjunction to an Init method.

    I like declaring members as final that should be treated as read-only after initialization phase. Finals can be set in constructors but not in setters or in Init methods. Okay, perhaps minor to some but I like using Java language features to enforce various characteristics of the design and implementation.

    Admittedly constructors with arguments would still be an issue when doing concrete inheritance - is one problem that the setter approach doesn't have.
  53. named arguments for Java[ Go to top ]

    I wish Java had named arguments so that the issues pertaining to constructor IoC could be pretty much solved.

    Java does have named arguments. They are called parameter annotations.

    public @interface Attribute {
       String value();
    }

    public Foo {
       private int myField;
       
       public Foo(
             @Attribute("myField") int val
       ) {
          myField = val;
       }

    }
  54. I don't see it[ Go to top ]

    The article cites several valid complaints about Injection IoC:
    1. ... it clutters an object and overwhelms the real functional purposes of the constructor and Java bean properties
    2. It also forces the caller to perform a lot of assembly i.e glue work
    3. ... untyped descriptor files which are not easily extensible and do not provide any compile time verification
    4. people are thrown off by the injection clutter and most of all by the "perception" that IOC implies ZERO encapsulation

    The cluttering complaint (1) is fairly weak. As others have mentioned, you can easily overcome the "cluttering" problem by separating your business interface from the implementation class.

    As the article mentions, you can solve complaint #2 by using a generic IoC container like Spring or Pico. This reduces the "glue code" to some configuration files (a la beans.xml). Even if you don't use a generic IoC container, the "caller" should never have to perform the "glueing". Proper separation of concerns would dictate that you have an "Assembler" that would encapsulate dependency information and would implement all of the "glue code"
    Compaint #3 is the most reasonable complaint. It is true that any errors in your injected IoC configuration files will not be caught until runtime. However, I would argue that if you don't like the type "unsafety" of the generic IoC container, then you cana always use Java code to assemble your object graph.
    I've never heard anyone complain that IoC implies ZERO encapsulation. As long as you program interfaces, you can easily preserve encapsulation. Your business services' clients never need to know about the implementation class or the implementation's dependencies. These details are handled by the container.
    Basically, I feel like this pattern is attempting to solve a problem that isn't there. Introducing this Context interface everywhere just adds additional complexity and I don't see any real benefits to doing so.
  55. I don't see it[ Go to top ]

    Jacob,

    You should read some of the other comments I have alread posted.

    If you introduce any object nesting where objects construct some helper objects then propogation of dependency is crude via Injection since each object in the intermediary layer must declare within its constructor or setters all its helper's dependencies and so on.

    If you do not nest objects then I believe you are suggesting an extreme horizontal dimension of IOC were all objects are assembled by the top assembler. You will have an extremely bloated assembly at the top which is not as easily reused or extended. And you do completely throw out encapsulation here since the top assembler knows every detail of every object instead of just knowing large grained units that need cross object boundary management. If you compare this to a corporation - it would be like an Engineer going to the CEO for every little thing he/she needs.

    The business interfaces improve some clutter but you have essentially pushed the clutter down to the implementations - swept it under the rug as it were.
  56. ??[ Go to top ]

    If you introduce any object nesting where objects construct some helper objects then propogation of dependency is crude via Injection since each object in the intermediary layer must declare within its constructor or setters all its helper's dependencies and so on.

    I don't know that this is correct. If object A needs object B which needs object C (the nesting you describe), then an instance of C gets injected into B, and then B is injected in A. It doesn't at all seem to be the case that A would need to declare all of its own dependencies and all of B's.

    Am I wrong on this? That's all least how Spring works, in my limited exposure to it.
  57. Yes[ Go to top ]

    You are correct, and that's the whole point. Object A never has to know C exists; as such, A stays a small, manageable, independently testable component with a pluggable B collaborator. Likewise, B is also a small, manageable, independently testable component itself, with a pluggable C collaborator.

    More specifically, the Spring container will instantiate/configure C's implementation first (assuming it has no other dependencies on other objects managed by Spring), then B, inject C into B, then instantiate A, and inject B into A. A doesn't know more about B than B's public interface tells it...

    That's how Spring and other IoC containers help effectively layer/compose a system from its component parts...
  58. Tight/Loose coupling[ Go to top ]

    I notice three points worth annotating.

    If A depends on B and B depends on C, then A depends on C to be present. However, if A depends on B and B-impl depends on C, then A does not depend on C.

    Even though some objects are late bound, does not mean they are loose coupled. The easiest way to prove this would be to use another Model for a View, and see if it works.

    In a traditional GUI, the MVC objects are tightly coupled because of how the operate. They may have separate collaborative dependencies, but in order for the gui component to be resolved, it requires the sum of dependencies (eg DAO, labels, themes, security, gesture-detection).

    These comments seems to slip and slide on coupling/binding issues, and I believed the author just tried to illustrate coarse grained dependencies.

    Now, the second thing is the Context injection.

    I can specify my dependencies as fields (Remembering EEJBs), but unable to differentiate from my other fields.
       public MyDAO mydao;
       public Transaction transaction;

    I can specify my dependencies as setters, but still unable to differentiate from other setter-like runtime methods.
       public void setMyDAO(MyDAO m) {...}
       public void setTransaction(Transaction t) {...}

    I can specify my dependencies as constructor arguments, but I cannot create namebound injection. I do however, have some notion of lifecycle needs.
      public Entity(MyDAO mydao, Transaction t) {...}

    I can create a context interface which describes the sum of services, reducing the construction argument to one. Now since the context interface might be a dynamic Spring proxy or other, it would be no difference really, but easier to resolve:
    interface Context {
      MyDAO getMyDao();
      Transaction getTransaction();
    }
    public Entity(Context c) {...}

    None of these approaches cannot be thought of as "breach-less", regarding null for instance, hence all my fail miserably once a very specific dynamic situation arises (As always).

    The sole point why I would favour the idea "A Cool Thing Which May Be Handy In Some Cases" is that I can specify my lifetime dependencies as a single unit, even though I do not need to reference them before actually needed.

    Now whether the to inline the dao and transaction services in the Context object or not, and hence be more service-specific. I wouldn't. Any other might.

    Then the fact of having hierarchical dependencies in the "bloat" uberobject.

    If A depends on B and I have A.context and B.context, I would create UberObjectEncapsulator E with E.context extends A.context, B.context. I would never use A.context extends B.context, because of the semantics of inheritance.
  59. Tight/Loose coupling[ Go to top ]

    The sole point why I would favour the idea "A Cool Thing Which May Be Handy In Some Cases" is that I can specify my lifetime dependencies as a single unit, even though I do not need to reference them before actually needed.

    BTW, I do not necessarily enfavour the subject in all cases, but in some cases. Most of my own projects has as HiveMind used few collaborators, and I hardly had any problems distincting them in any context.
  60. ??[ Go to top ]

    The nesting I'm referring to is object A constructing B constructing C. Now I understand that you guys believe construction is BAD and leave it all upto the container to inject C into B and B into A. But I'm refereing to B and C being helpers of A encapsulated by A just as the logic within A is encapsulated.

    Complex objects generally partition their logic into less complex objects not neccessarily for reuse but for mitigating complexity and their life-cycles don't always fit into request, session etc - they can be complex.

    Its would be nice to propogate the externally managed dependencies of an encapsulated unit as one Context via Context Extention.

    The article was trying to elevate IOC to a general purpose design pattern that just needs language expression for those that are turned off by IOC because of descriptor files and generic containers that assemble a large object graph and force every object to expose all their inner objects.
  61. The basic IoC concept is very simple. I like it for that reason. It's simplicity makes it very flexible. However, its flexibility makes it prone to poor implementation. Patterns Happy people going crazy - classes with a silly number of IoC setter methods, or constructors with a silly number of arguments etc etc.

    Like a number of other people posting here, the problem I'd have with an implementation like this is the effect it would have on bloating my code - X.Context implementations, Y.Context implementations, anonymous inner classes ....

    I would have thought that many projects use an approach similar to this already (using Context objects of sorts) rather than 20 constructor params or 20 setter methods. I know we have. The difference might be the level of granularity people work at. Context IoC "seems" to suggest that the Context interfaces exist at the Object level only. Where I've used it I've tended to take a more case by case approach where Context interfaces can be at Application/Component or Object level. Of cource Application/Component level contexts mean more general purpose contexts but it also means you're less likely to have the code blow out. I've found this to be a practical enough approach which has worked well so far.

    Also - I agree with however said the idea of using Spring (Pico etc) to plum absolutely everyting together is nuts.
  62. "lint" tool for AOP[ Go to top ]

    I don't understand why none of the major AOP framework solutions have thought to implement and provide an AOP "lint" tool that could be run as an ant task and does a "type safe" verification of a resulting application build. It would parse the xml config files and verify those declarations against the compiled Java class files.

    In the end I prefer a declarative language (xml is indeed a declarative language) for expressing declarative concepts.

    All that's thus missing is a compile phase or build phase process of verifying the xml declaration stuff against the compiled language stuff.

    Such an AOP "lint" tool should be standalone too. A person that is in charge of deployment should be able to run this tool to check applications that are about to be deployed in the event any configuration changes have been made at deployment time.

    Actually this AOP "lint" tool could also be integrated into a specialized deployment editor. This xml savvy editor would be specialized specifically for the purpose of making alterations to applications that are about to be deployed. (Hence it would be a slimmed down lean and mean editor that is not associated with heavy developer IDEs like Eclipse. This editor and AOP "lint" tool should be able to fit on a floppy disk.)
  63. Inversion Of Control is an old design priciple. In the 60'ies it was a basic ability in Smalltalk - the name was dependency. It is used in all framworks - EJBs included - often named the Hollywood Principle.
                                                                                    
    What it realy does, is to invert dependency between modules and so often is used to provide a loose coupling that would not be possible otherwise. As such it is a very important design tool, because dependency is what software design realy is about (google for Jdepend).
                                                                                    
    What Sony does, as I see it, is to take IOC to the extreme. Because every object only depends on its own internal interface, every object is in the bottom of the dependency hierarchy, which means maximum stability, reuseability and testability.
                                                                                    
    So far, sehr gut.
    But nothing comes for free - and this counts for IoC in general too. Dependency is not a first class instrument in current languages and is not supported by IDE's. That means, browsing and refactoring does not work upstream.
    (Another term for using frameworks with IoC is: 'Programming in the Fog')
                                                                                    
    15 years ago I designed a system totally based on these priciples. All objects were created and tied together based on a configuration file. Was it a succes ? I guess not - some loved it others hated it.
                                                                                    
    It is surely very exiting to search for other and better ways to do things. Better does mean more productive, BUT more productive more often means simpler than smarter.
                                                                                    
    At the moment, I work on an EJB based project, I love Test Driven Development, 90% of the time I'm TDDing POJO's. Entity beans are just a shallow interface to the databases and Stateless Session Beans are a shallow interface to the clients. EJB is not simple, but using delegators and mock objects, it is not a big problem. What would realy be a problem is if browsing and refactoring was harder.
                                                                                    
    My feeling is that IoC is overhyped at the moment, often promoted as a solution to all problems and no dowsides. Projects are different, and what may be problems in one project is no big deal in another. My concern here was to point out one problem with IoC, which means something to me: lack of support for browsing and refactoring. And, before we all get too exited by smart designs, remember KISS.

    Thanks to all for initiating and participating in a very a interesting discussion - it is not my intention to be a match spoiler.

    regards
    Hardy Henneberg
  64. pluggable adapter[ Go to top ]

    BTW:
    Context IoC as a design pattern may already be covered by GangOf4's 'Plugable adapter'.
  65. problem solved already[ Go to top ]

    Hi Sony, people,

    This 'problem' has already been solved quite well I think. Previously I've looked at similar 'Context' indirection, but I think IoC containers such as Spring have now enabled much better solutions.


    Point 1).

    'Context' objects add two layers of indirection to do their job. One from the the requesting class, one at the context impl.

    Setter or constructor-based IoC achieve the same result without these unnecessary layers, and without the overhead of producing, tracking and maintaining a skeleton class/ type system parallel to your actual functional types.

    Rather than 'inverted' Context objects which only have very specific applicability, I would strongly recommend 'positive' Service objects which have wide & general applicability.

    This way, your dependent object gets its context in *general* form - maybe 2 or 3 Service references and a few properties - and you're working effectively with positive, general functionality.

    By comparison 'inverted' setups require much more coding and are much less effective - because you're deliberately restricting yourself with extremely client-specific/ decoupled/ inverted code.

    Naturally the number of such highly-specific items to be implemented is vastly more than the number of broadly-categorized and generally-applicable items, to cover the same area of functionality.


    Point 2).

    Having been down the same path with OO-theory techniques, I've already investigated some number of approaches involving encapsulation/ inversion/ decoupling.

    Basically neither is OO theory perfect, nor is this indirection free. In fact, working thru indirection layers is extremely expensive. (by several multiples).

    It's much more effective to work with 'positive' functionality, have this 'directly' addressable and keep this broadly-categorized for wide availability.

    ---

    Anyway Sony, you've come up with a 'correct' answer in one sense, according to OO theory.

    But practically, we need to deliver functionality and structure this in a useful and still-effective way. This is about the point that OO theory has run out.

    Anyway, neither am I sure that the extreme proliferation of highly-specific Context impls is strictly in accordance with OO guidelines. I guess you'd be meant to set up a type system for these, partly parallel with your impl types, partly parallel with their external requirements...

    Parallel typing between heirarchies is another common OO problem area, and here you've got two heirarchies to try and be parallel with :-). Isn't this going to be a complete and utter nightmare ?


    Cheers,
    Thomas Whitmore
    www.powermapjdo.com
  66. problem solved already[ Go to top ]

    You can perform object analysis on Contexts i.e generalize them, refactor them etc. into other types that can yeild Factory, Locator and a slew of other patterns. So attempting to pin this down to one type of pattern is misguided - Contexts can be blossomed into any pattern with the appropriate generalization.

    Now X.Context, Y.Context are simple interfaces that are well scoped to their parent type - to me a natural and elegant solution.

    On the other hand private inner class ContextImpls need not exist - it is just one way. The JobMatchServiceEJB could have implemented the JobMatchService.Context instead of using a private inner class. Then generalization and refactoring of the EJBs will automatically yeild a proper refactoring of the Context Impls as well. I probably should have shown this approach in the article.

    Thanks
    Sony
  67. Compile time v's runtime checking[ Go to top ]

    Compile time v's runtime checking.
    IOC in XML is rubbish because of the useless format of specifying the 'wiring'. It's like the worst kind of scripted make system - easy to write, and add to when you wrote it. Impossible to comprehend when you come into a large IOC system with hundreds of objects all autowired.

    As opposed to a 'context' system which is compile time checked. Factories (or whatever) can create concrete implementation or test implementations, which is ace, all checked at compile time. They can still be configured using tiny, focused configs - the db config, the logging config, and user login mechanism sums up most systems.

    I loathe the xml unchecked format of the configs. Lots of folks are writing tools to make them checked, or use attributes or some other piece of misthinking - they are solving a problem that simply should not exist in modern IT.

    So I like contexts because the compiler is your friend. BUT, I've also seen the simple context grow into a horrible system destroying singleton horrow. IOC via XML stops rubbish people doing rubbish coding... Which is why they did it I guess. Protect coders from themselves (but that never works).

    Jonathan
    MicroSpring - IOC in 30k
  68. Hi Jonathan,

    Yep, compile time wins over vs runtime checking. My use of IoC is for explicit wiring. I have little need or desire for autowiring, for the exact reasons you say.

    Let's use electrical wiring in a house as an analogy, to understand what we're talking about better.


    0) Glue code. Wires are built-onto switches and lamps. Different models of switch are required to connect coloured lights.

    1) Explicit IoC. Electrician connects wires between switches and lamps, as specifically needed. Works great, clear and simple.

    2) Autowired IoC. Electrican brings correct number of cables and blind apprentice has a go. Works great, or not. When you do need to fix it you have to communicate braille to the blind guy.

    3) Contexts. Plugs and sockets are specific to different classes of lamp. Electrician hand-crafts said plugs and sockets after crafting hand-crafting lamps, thus taking twice as long. Possible refactorings become apparent later and also take twice as long.


    This analogy isn't a joke -- it's the direct correspondence of what we're talking about here. There's a real difference between *constructive* functionality, eg connecting a cable or an explicit IoC ref; versus crafting an *inverse* eg a cable which only works between RedLamp and DimmerControl.

    The work involved is proportional to the number of artifacts required. The number of artifacts required is increased by the number of restrictions. Negative implementations, as opposed to positive, are constructed by their very nature of restrictions. (This is a RedLampContext, and this is a DimmerControlProvider).

    eg. count
    (RedLampContext, DimmerControlProvider)
    (RedLampContext, SwitchControlProvider)
    (BlueLampContext, DimmerControlProvider)
    (BlueLampContext, SwitchControlProvider)
    (HotWaterContext, SwitchControlProvider)
    (LowVoltageContext, SwitchControlProvider)

    vs count
    (Wire)
    (LowVoltageWire)

    Just use a wire and specify it explicitly.


    > IOC in XML is rubbish because of the useless format of
    > specifying the 'wiring'

    Well, it could be a lot more compact 'fact-based' format.

    <bean id="red1" class="RedLamp">
      <ref power="dimmer2"/>
      <ref placement="diningCeiling"/>
      </bean>

    But that's XML and Spring for you, all that extra clutter of repetitive attribute/ value tagging.

    I vastly prefer it, despite this overhead. And if you don't rely on automagic, it is fairly well type-checked; incorrect property/ value assignments will throw at init time.

    > configured using tiny, focused configs - the db config,
    > the logging config, and user login mechanism sums up most
    > systems.

    Precisely. But why not configure these as Typed References, which they are, rather than building a whole lot of indirection which is completely unnecessary ?

    <bean id="downloadSvc" class="DownloadService">
      <ref dbAccess="dbAccess"/>
      <ref regSvc="regSvc"/>
      <ref logger="logger"/>
      </bean>

    > So I like contexts because the compiler is your friend

    I like Contexts when I first thought of them. Now I have reached the conclusion that OO theory is not a correct guide to practical practice.

    First-class vs Indirect is a hugely important point here.


    Cheers,
    Thomas
    www.powermapjdo.com
  69. I appreciate all the effort that Sony Mathew put into this article: thinking it through and giving many relevant examples. Thanks, Sony.

    I do have to say that I've been using my IoC container (Spring) in this style for some time. Well, what I did was "solve" the problem of getter/setter clutter by slurping all those variables into a separate class. And then, done. So, yeah, I call it "Context", but it's just a C-style struct of object references...all dangling out there for any dependent classes to make use of in a type-safe way.

    While defining inner classes is sexy, I've found that my IoC contexts are generally passed around (IoC is a bunch of objects participating in a configurable context). So, that's why I *start* by defining a separate class....it's generally not owned by any one participant.

    I guess I'm saying is either there's something I'm missing or this is just good Dependency Injection technique.

    To be brutally honest, if I discovered it on my own, it's probably not that earth-shattering. :)

    I'm gonna go check out Spring's docs to see if Rod Johnson and crew have already identified and documented this "pattern".

    ----
    For IoC newies: here's the bottom-line; just learn how to use your IoC container with the instructions that came in the box. THEN, instead of injecting dependenices one-at-a-time, bundle them into a single object (i.e. define a pure bean that holds all those dependencies) and inject that. At that point, you get the most bang for your buck.

    - The 'Tig
  70. Now wait a minute...I think I was a little too quick to dismiss your use of an inner-interface to describe the object's dependencies. I dig it. You can have a wider "context" object that holds all the reference, but this object is only interested in 2 of those, so define an interface to make that explicit. Nice! Okay. :)

    I'm still not convinced this is a paradigm shift... ;)
  71. no paradigm shift[ Go to top ]

    Hi John,

    Thanks for your input. I do get what you're saying, the Context becomes a sensible container for a bunch of relevant services.

    I'd definitely agree with the intent of this. Bundling up the low-level items into service beans, bundling up the services into a higher-level 'group bean' of domain-specific services, etc can make sense.

    I like to think of this and design this in terms of 'positive utility'. That is, identify the domain and functionality and place 1-3 broadly-effective artifacts there. This avoids needlessly fragmenting the solution space.

    Mainly I identify things like Business Services, Application Settings and Infrastructure eg email and JDO storage.


    Cheers,
    Thomas
    www.powermapjdo.com
  72. The following links provide some examples of the aplication of Context-IOC in the DPML Metro [1] platform. Minimal Example http://www.dpml.net/metro/tutorials/context.html Primitives, Complex-types, and Arrays http://www.dpml.net/metro/tutorials/context-examples.html Service Lookup via Context http://www.dpml.net/metro/tutorials/lookup.html Cheers, Steve. [1] DPML Metro, http://www.dpml.net/metro
  73. http://sesat.no/projects/sesat-commons/commons-ioc/ A light-weight, framework independant, addition to the Contextual Inversion of Control pattern. Uses the contextual approach where classes with dependency requirements define an inner "Context" interface extending the BaseContext interface and accept an implementation of it in the constructor. This allows a pure separation of dependencies from the class, and the possibility to add dependencies into the context over time. Classes may also inject the context through a method rather than the constructor if it suits better. For projects with a deep IoC rather than a broad but shallow chain, where common dependencies are defined and used at each level the utility class ContextWrapper allows BaseContext implementations to be 'wrapped' into a different BaseContext implementation. This provides an ordered Proxy stack on contexts where the first matching method signature is used for any method invocation. Reflection results are cached per proxy instance to improve performance(~10%). Because compile-time safety is lost against this proxy stack, by enabling assertions it is possible to check that all methods that the top-level Proxy is intended to implement are infact found somewhere down the stack on the first invocation call on the Proxy. The primary benefit of using this library over other IoC libraries is that it is incredibly light-weight, and completely framework independant, unlike implementations from Spring, Plexus, and JBoss. A secondary benefit is its simplity. With only two public classes and only one public method in total it is a straight forward API to use.