PicoContainer
  1. PicoContainer
  2. PICO-148

Variation on container dependency anti-pattern

    Details

    • Type: Test Test
    • Status: Closed Closed
    • Priority: Minor Minor
    • Resolution: Won't Fix
    • Affects Version/s: 1.0-RC-1
    • Fix Version/s: None
    • Component/s: PicoContainer (Java)
    • Labels:
      None
    • Environment:
      JDK 1.4.2
      Win2K
    • Number of attachments :
      3

      Description

      I've been struggling with what to do about the container dependency anti-pattern. I think I see some areas where it might be useful (other than linking parent and child containers), but perhaps some holes can be poked in my approach.

      What I've been thinking about is whether it would be useful to have a container manage persistent instances that are part of a domain model. Can/should domain objects be components and would it be worthwhile to allow them to be instantiated with outside dependencies, potentially coming from a hierarchy of containers?

      When you have domain objects in a container, they'd most likely be stored using the primary key/object ID as the component key, and thus getComponentInstance(Object key) allows for simple lookup based upon object ID. Now when considering service components that manage domain objects, they'd have a dependency on the domain object container for retrieval. So a question I have is how to structure a service component container in relation to the domain object container?

      a. Does the domain object container become a parent of the service component container? or
      b. Does the domain object container live inside of the service component container?

      The attached test case illustrates these two approaches. (a) corresponds to test 'testShirtQuality2' while (b) is represented by 'testShirtQuality1'. The example may be a bit contrived, but hopefully communicates the idea.

      1. DefaultPicoContainer.patch
        1 kB
        Nick Sieger
      2. ShirtFactoryTestCase.java
        6 kB
        Nick Sieger
      3. SiegerTestCase.java
        6 kB
        Nick Sieger

        Activity

        Nick Sieger made changes -
        Field Original Value New Value
        Attachment SiegerTestCase.java [ 11500 ]
        Hide
        Nick Sieger added a comment -

        Note that the 'testShirtQuality2' test case does not work in the current codebase without the attached patch. What I am trying to illustrate is a way to soften the container dependency by defining a focused interface and having the container implement that interface.

        Also, I like the idea of managing component dependencies by having parent containers (in this case the domain object container) manage components in a conceptually separate application layer that are dependencies for components in child containers (the service component container). Is this an appropriate way to structure a layered application?

        Show
        Nick Sieger added a comment - Note that the 'testShirtQuality2' test case does not work in the current codebase without the attached patch. What I am trying to illustrate is a way to soften the container dependency by defining a focused interface and having the container implement that interface. Also, I like the idea of managing component dependencies by having parent containers (in this case the domain object container) manage components in a conceptually separate application layer that are dependencies for components in child containers (the service component container). Is this an appropriate way to structure a layered application?
        Nick Sieger made changes -
        Attachment DefaultPicoContainer.patch [ 11501 ]
        Hide
        Paul Hammant added a comment -

        Nick,

        I'm stuggling to understand what you are requesting here.

        Could you work over the test cases and change the method names from

        testShirtQuality1 (and alike)

        to

        testFooExceptionNotThrownForPerculiarCurcumstances

        ( refer the lessons learned from Agiledox - http://joe.truemesh.com/blog//000047.html )

        Also, as a note, it is very unusual to extend DefaultPicoContainer for a business purpose (TShirts), rather that wrap/contain an instance.

        Thoughts?

        • Paul
        Show
        Paul Hammant added a comment - Nick, I'm stuggling to understand what you are requesting here. Could you work over the test cases and change the method names from testShirtQuality1 (and alike) to testFooExceptionNotThrownForPerculiarCurcumstances ( refer the lessons learned from Agiledox - http://joe.truemesh.com/blog//000047.html ) Also, as a note, it is very unusual to extend DefaultPicoContainer for a business purpose (TShirts), rather that wrap/contain an instance. Thoughts? Paul
        Hide
        Nick Sieger added a comment -

        I'll have a look at my test case again, rename the test methods and see if I can refocus the test based on my thoughts at the time. Should be able to have something for you to comment on in a couple of days. Thanks for taking an initial look.

        Show
        Nick Sieger added a comment - I'll have a look at my test case again, rename the test methods and see if I can refocus the test based on my thoughts at the time. Should be able to have something for you to comment on in a couple of days. Thanks for taking an initial look.
        Nick Sieger made changes -
        Attachment ShirtFactoryTestCase.java [ 11981 ]
        Hide
        Nick Sieger added a comment -

        Hey Paul,

        I think I've got this sorted out pretty much. I've attached a new streamlined test case which turned out to be just an exercise in pico wiring logic. Two tests in the previous test case turned out to be duplications. If you see any value in the test case (either as an example or as part of the test suite) feel free to adapt but otherwise it's probably superfluous.

        Let me see if I can explain my thinking. What I was originally shooting for was to use a picocontainer to manage/instantiate persistent objects or domain objects, but I wanted to put a pretty face on it (ShirtFactory) so that clients that wanted to look up a particular instance would have a properly typed method for doing so. Components that need to be able to look up shirts (the ShirtManager) wouldn't have to depend on the container, they could simply depend on the lookup interface. But as you point out it introduces the anti-pattern of extending DefaultPicoContainer in order to introduce this lookup interface on the container.

        What I ended up doing in the revamped test case is make the ShirtFactoryImpl a component inside of a DefaultPicoContainer that depended upon it. So in effect I've traded one anti-pattern for another, and neither solution feels quite right.

        I still haven't resolved for myself whether domain objects should live in a picocontainer – it seems to me that if domain objects don't either have the behavior on their own classes or through close neighbor references then they're probably doing too much or don't have enough behavior close to the object's data (e.g., if they depend on a service component). Fowler talks about a "Anemic domain model" and I think this could be a symptom of that. If this is the case then maybe picocontainers are not needed to wire domain objects together.

        In the back of my mind I'm trying to envision using picocontainers to represent different layers in a layered architecture. One container to hold domain objects (but maybe not based upon the previous paragraph), one to hold service components, one to hold model/view/controller components, etc. and the layered containers would be linked via the DefaultPicoContainer's parent link. This whole stack of containers would then be built/composed and placed into the servlet hierarchy (in the case of nanoservlet) or possibly wired by a groovy script (in the case of nanoweb) but I haven't taken this past the conceptual stage yet.

        Any thoughts?

        Cheers,
        /Nick

        Show
        Nick Sieger added a comment - Hey Paul, I think I've got this sorted out pretty much. I've attached a new streamlined test case which turned out to be just an exercise in pico wiring logic. Two tests in the previous test case turned out to be duplications. If you see any value in the test case (either as an example or as part of the test suite) feel free to adapt but otherwise it's probably superfluous. Let me see if I can explain my thinking. What I was originally shooting for was to use a picocontainer to manage/instantiate persistent objects or domain objects, but I wanted to put a pretty face on it (ShirtFactory) so that clients that wanted to look up a particular instance would have a properly typed method for doing so. Components that need to be able to look up shirts (the ShirtManager) wouldn't have to depend on the container, they could simply depend on the lookup interface. But as you point out it introduces the anti-pattern of extending DefaultPicoContainer in order to introduce this lookup interface on the container. What I ended up doing in the revamped test case is make the ShirtFactoryImpl a component inside of a DefaultPicoContainer that depended upon it. So in effect I've traded one anti-pattern for another, and neither solution feels quite right. I still haven't resolved for myself whether domain objects should live in a picocontainer – it seems to me that if domain objects don't either have the behavior on their own classes or through close neighbor references then they're probably doing too much or don't have enough behavior close to the object's data (e.g., if they depend on a service component). Fowler talks about a "Anemic domain model" and I think this could be a symptom of that. If this is the case then maybe picocontainers are not needed to wire domain objects together. In the back of my mind I'm trying to envision using picocontainers to represent different layers in a layered architecture. One container to hold domain objects (but maybe not based upon the previous paragraph), one to hold service components, one to hold model/view/controller components, etc. and the layered containers would be linked via the DefaultPicoContainer's parent link. This whole stack of containers would then be built/composed and placed into the servlet hierarchy (in the case of nanoservlet) or possibly wired by a groovy script (in the case of nanoweb) but I haven't taken this past the conceptual stage yet. Any thoughts? Cheers, /Nick
        Hide
        Jörg Schaible added a comment -

        Hi Nick,

        can we close this issue? Although the injection of a PicoContainer is in general an anti-pattern, it might be used for such kind of service levels as you describe. Personally I've used a hierarchy of Picos myself wrapped by an service interface that is implenented by my main class, that also has the start-up code and does the wiring.

        But we might continue with this discussion on the list and just close the issue here.

        • Jörg
        Show
        Jörg Schaible added a comment - Hi Nick, can we close this issue? Although the injection of a PicoContainer is in general an anti-pattern, it might be used for such kind of service levels as you describe. Personally I've used a hierarchy of Picos myself wrapped by an service interface that is implenented by my main class, that also has the start-up code and does the wiring. But we might continue with this discussion on the list and just close the issue here. Jörg
        Hide
        Nick Sieger added a comment -

        Joerg, yeah, please go ahead and close this. I was just bouncing around some ideas but since have come to agree with Paul's point that extension of DefaultPicoContainer is not the right way to go.

        Show
        Nick Sieger added a comment - Joerg, yeah, please go ahead and close this. I was just bouncing around some ideas but since have come to agree with Paul's point that extension of DefaultPicoContainer is not the right way to go.
        Hide
        Jörg Schaible added a comment -

        Closed at request.

        Show
        Jörg Schaible added a comment - Closed at request.
        Jörg Schaible made changes -
        Resolution Won't Fix [ 2 ]
        Status Open [ 1 ] Closed [ 6 ]

          People

          • Assignee:
            Unassigned
            Reporter:
            Nick Sieger
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: