Subcontexts in a large, modular application

Jeremy Ruppel's Avatar

Jeremy Ruppel

10 Dec, 2009 06:06 PM

So here's the setup: I'm in the process of building a rather large application which must be completely dynamic. RobotLegs has been a huge help in keeping the app organized and testable, but I'm having trouble determining what the best practice is for using sub-contexts in an application, keeping in mind that those sub-contexts may share some mappings with the original super-context.

Example: The main context of the application uses mapSingletonOf to control, say, the content model to one instance. When I create a sub-context within this app, I could use mapSingletonOf again to fill any dependencies within that context, but they would not be filled with the same instance of the content model. Or think of this in terms of a queue-loader service. There should ideally be one queue loader instance to manage loading items within the app, but every context would receive its own instance, thereby making the queue loader useless.

I've been fighting with the best way to tackle this issue. I can solve it by passing in the injector, reflector, and so on into a custom sub-context class and assigning them before the default SwiftSuspendersInjector et al are created, but this technique seems far too clunky, and actually also demolishes the testability I've grown so fond of with this framework.

I know in the best practices documentation you've mentioned that it is possible to build modular applications with multiple contexts, but the document is clearly concerned with a simpler sort of application. Hopefully I'm missing an easier, cleaner way to make data or services available safely in an application with multiple contexts.

Has anyone else run into this problem? How did you end up solving it?

  1. Support Staff 1 Posted by Till Schneidere... on 10 Dec, 2009 07:06 PM

    Till Schneidereit's Avatar

    Hey Jeremy,

    if you're willing to use a beta version of SwiftSuspenders, you might
    be interested in the newly added support for child injectors. These
    can contain their own mappings, but in addition, they automatically
    delegate all unknown injection requests to their parent injector,
    enabling you to share mappings for all contexts while still
    configuring your contexts with their individual mappings.

    As this feature of SwiftSuspenders is pretty new, there's no currently
    no real documentation, but for some usage examples, you can see the
    unit tests here:
    http://github.com/tschneidereit/SwiftSuspenders/blob/childinjectors/test/org/swiftsuspenders/ChildInjectorTests.as

    To use the new version of SwiftSuspenders, you have to clone the
    "childinjectors" branch from github and compile from source. I'll try
    to put up a beta release of the swc in the coming days, so using that
    should become much simpler.

    cheers,
    till

  2. 2 Posted by levi.strope on 10 Dec, 2009 07:53 PM

    levi.strope's Avatar

    Hello, what kinda timeframe can we expect this kind of feature to roll out of beta?

    I would love to experiment with this feature and provide feedback, but I would need proper documentation that I can distribute to my team and also reference myself when they ask questions.

    Thanks and regards,
    Levi

  3. Support Staff 3 Posted by Till Schneidere... on 10 Dec, 2009 09:59 PM

    Till Schneidereit's Avatar

    hey levi,

    Honestly, I,m mostly waiting for some feedback before rolling it out
    for real. but obviously, I should write some documentation for that to
    happen.
    I do that tomorrow and think it should be up pretty quickly. the
    feature is quite complex conceptually, but it has a really minimal
    interface.

  4. 4 Posted by Jeremy Ruppel on 10 Dec, 2009 10:37 PM

    Jeremy Ruppel's Avatar

    Thanks for the quick response! Looks like this will be very powerful indeed, exactly the idea I was looking for. I'm having a tough time conceptualizing how it will be integrated smoothly into RobotLegs though, especially since the Injector.createChildInjector will not implement IInjector or be adapted. In fact, I'm still trying to come up with an acceptable implementation of this within RobotLegs' Contexts that doesn't couple the two libraries together any more than they need to be. Have you had any luck talking this great new feature over with Shaun?

    Thanks again,

    Jeremy

  5. Support Staff 5 Posted by Till Schneidere... on 10 Dec, 2009 10:49 PM

    Till Schneidereit's Avatar

    I'm not at my desk anymore so I can't give you an example right now,
    but child injectors do implement IInjector and using them works
    without any changes to robotlegs.

    will write documentation and an example tomorrow.

  6. Support Staff 6 Posted by Till Schneidere... on 11 Dec, 2009 04:32 PM

    Till Schneidereit's Avatar

    I've added some documentation and example for using child injectors to
    the SwiftSuspenders documentation:
    http://github.com/tschneidereit/SwiftSuspenders/blob/master/README.textile
    Also, I just added a build of the first 1.5 beta to the github downloads:
    http://github.com/tschneidereit/SwiftSuspenders/downloads

    If you download this build and drop the contained swc into your
    projects' libs folder, you should be able to use the child injectors
    feature with the current Robotlegs release.

    Looking back at what I wrote yesterday, I have to admit that what I
    wrote about the child injectors implementing IInjector was simply
    false, sorry about that! Alcohol and playing Poker just don't go well
    with technical discussions ;)

    Still, the actual behavior is no problem in practice: Just inject the
    injector itself typed as Injector, not IInjector into your
    configuration command and use it directly:

    //in your context:
    injector.mapValue(Injector, injector);

    //in your startup command:
    [Inject] public var injector : Injector;

    Now to your use-case:
    for each subcontext, supply the main (or parent, if you're going to
    have multiple levels of nesting) injector in the constructor. Then
    create the child injector for the current context before calling
    super, and you're done:

    class ChildContext extends Context
    {
        public function ChildContext(contextView : DisplayObjectContainer,
    parentInjector : Injector)
        {
            injector = parentInjector.createChildInjector();
            super();
        }
    }

    Now, all mappings in the parent injector are still available in the
    current context, but you can add additional mappings that are specific
    to this context and don't affect the parent or any other contexts.

    I'll create an example of this over the next few days, but I hope this
    helps you get started right now.

    cheers,
    till

  7. Support Staff 7 Posted by Ondina D.F. on 11 Dec, 2009 05:00 PM

    Ondina D.F.'s Avatar

    Great!!!
    Actually the documentation is here (under childinjectors):
    http://github.com/tschneidereit/SwiftSuspenders/tree/childinjectors

  8. 8 Posted by Jeremy Ruppel on 11 Dec, 2009 05:33 PM

    Jeremy Ruppel's Avatar

    Thanks again for the quick response, Till! Still, the same problem exists where the ContextBase's definition of injector is limited to IInjector, so the line...

    injector = parentInjector.createChildInjector( );

    ...would still run into conflicts. I suspect that the changes necessary to make this feature available within sub-contexts will have to happen mostly in the RobotLegs side of things, namely:

    1. Have IInjector include the createChildInjector() method.
    2. We're in a little bit of a tricky spot here. We can either have the SwiftSuspenders version of Injector implement IInjector directly (tying the two libraries together perhaps too closely) or expose getParentMapping, setParentInjector, etc as protected and override them in the SwiftSuspendersInjector adapter to provide a suitable Injector subclass when using createChildInjector.

    I think for the time being I may write a quick adapter to help with assigning the child injector to the sub-context, but what are your thoughts on the above?

    Thanks again for the help on this issue, really appreciate it.

    Jeremy

  9. Support Staff 9 Posted by Till Schneidere... on 11 Dec, 2009 05:49 PM

    Till Schneidereit's Avatar

    @Ondina: Thanks for correcting that mistake!

    @Jeremy: Serves me right for writing examples in emails instead of
    testable projects - sorry for that!

    You're completely right about the need to implement IInjector. I think
    I have a workable approach in mind, I'll work on that over the
    weekend. As a quick outline, exposing Injector#setParentInjector as a
    public method should enable using the injector created by the Context,
    without changing anything in Robotlegs.

    cheers,
    till

  10. Support Staff 10 Posted by Shaun Smith on 11 Dec, 2009 06:12 PM

    Shaun Smith's Avatar

    @Jeremy: We have to be careful with what we put into RL's IInjector interface - we need to support as many DI solutions as possible. The idea is that IInjector represents what RL needs access to in order to do it's job, but the app developer is free to work directly with the underlying DI solution (in this case SwiftSuspenders).

  11. Support Staff 11 Posted by Shaun Smith on 11 Dec, 2009 06:16 PM

    Shaun Smith's Avatar

    @Levi: it's a catch-22! Till needs someone to test out the Child Injector stuff before he can roll it out (and before we roll that into Robotlegs).

    @Till: Sorry that I haven't had a chance to play with that stuff yet - and it's looking like I won't have any time to do so for quite a while :'<

  12. Support Staff 12 Posted by Till Schneidere... on 11 Dec, 2009 06:46 PM

    Till Schneidereit's Avatar

    @Shaun: I'm more and more of the opinion that Robotlegs should only
    support the most basic functionality of whatever DI solution is used.
    Everything else should be used by adding a mapping to the concrete
    injector implementation in the context and a matching injection in a
    startup command. Adding IInjector#mapRule was a regrettable mistake on
    my part.

    No worries about not being able to play with child injectors - I get
    that you have a day job ;)

    @everyone: Shaun is completely right: I need feedback from real
    world-usage before I can release a new version of SwiftSuspenders that
    I can call "stable" with any confidence. I hope that releasing a
    proper build of the beta version makes this easy enough.

  13. 13 Posted by levi.strope on 11 Dec, 2009 07:20 PM

    levi.strope's Avatar

    I understand the catch 22.

    I do have a need for this in our project, I'll see if I can't start implementing it.

  14. Till Schneidereit closed this discussion on 14 Jan, 2011 09:29 AM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac