Do we really need THAT much metadata in AS3? Not with Robotlegs…

There was a time in the push for a Robotlegs 1.0 that a nometa implementation existed. Robert Penner still uses it, if I’m not mistaken. It doesn’t have as much convenience as the regular meta-loving MVCS implementation, meaning it doesn’t inject a bunch of classes into the MVCS base classes. Is that bad? Not really. I find myself rarely using the injected classes anyway. At the time I pushed back on the nometa implementation and its inclusion in the core. I still think that is proper, because it would just tend to cloud the implementation and make it more difficult to document and support, both of these being key pillars in making Robotlegs a successful project that people will actually use. The concept of using as little metadata as possible in my applications is very appealing.


SwiftSuspenders beautifully supports constructor injection. This means that you don’t need to annotate any methods or the class with metadata for it to honor injection into the constructor. With the [Inject] tag, you are marking required dependencies. They aren’t optional. If there is no rule to supply the injection you will get a runtime error saying as such. So, given these non-optional dependencies, injecting them into the constructor makes a lot of sense. One drawback to this approach is that if you are injecting a lot of dependencies your constructor might get really big. In fact, the limit is 10 parameters. Guess what? If your class requires that many dependencies, it already smells bad. Clean it up and think single responsibility. For the love of Uncle Bob, keep it clean.

To illustrate this point I have refactored the Image Gallery example. It was my first example for Robotlegs almost a year ago. The original version resides in the Robotlegs Demo Bundle. In this refactoring I removed all occurrences of the [Inject] metadata tag. In addition, I removed all of the extensions of Robotlegs mvcs implementation sub-classes with the exception of Mediator. There are no Actor or Command subclasses. So what you end up with is a Command, Model, and Service tier that is completely meta and framework free. That rocks. It is just AS3 code doing its job. I love that.

Get Adobe Flash player

Here’s a link to the source for this project on Github.

Tooling is very lacking for metadata in all of the IDEs currently available. The SourceMate plugin from ElementRiver is a nice addition to Flash Builder if you make use of metadata. It actually gives you code completion, which in and of itself is a huge improvement over… nothing. I hope to see more IDE support for metadata soon. It would really make it a lot easier to manage.

In my professional life, I use all of the Actionscript DI frameworks (Robotlegs, Swiz, and Parsley). They are all great, when used appropriately within a defined set of patterns and practices. I worry about the trend for increased use of metadata. I think the complexity overhead is large. Sure, you get it, but there is a responsibility to build systems that can be understood by a wide range of developers without weeks of remedial training on a complex metadata based DSL. The less complex we make our complex systems the better. They are easier to train for, document, and build.

  • https://twitter.com/ianmclean Ian McLean

    Metadata isn't required to make this happen if RL triggers the constructor injector on commands automatically but isn't what happens there even more magical than what happens when you use [Inject]?

    [Inject] is somewhat self documenting in that you know that the values are being filled by an injector somewhere. For someone who isn't familiar with this feature of RL just looking at constructor parameters its non-obvious that those values are automatically being looked at by the injector and filled.

    Also, what is the case for being able to specify params in a constructor that have no mapping but don't generate an error? If an injection hasn't been mapped for a param then there is no other way for value to be set and it doesn't have much business being there. I think error thrown when using [Inject] are very helpful as things can silently fail otherwise.

    Just a bit of devils advocate, although I do agree about the flagrant overuse of metadata in some frameworks.

  • https://twitter.com/stray_and_ruby stray

    You totally get it. The complexity curve I mean.

    Coding for a coder who isn't as sharp as you are isn't just helpful to others – it's helpful to yourself. There *will* come a day when your kid puked 6 times in the night and you've got to hit the deadline, and on those days it's very useful to have designed your software so that you don't have to be at the top of your game to work with it!

  • https://joelhooks.com Joel Hooks

    You still get the awesome error checking with SwiftSuspenders:

    exception, information=Error: Injector is missing a rule to handle injection into target [class GalleryLabelMediator]. Target dependency: String, method: constructor, parameter: 3

    (I threw in a string param to test it out)

    I'm not rewriting the best practices here. Property injection is still recommended, but constructor injection is nice and NOT having meta at all is very appealing.

    No, it isn't more magical. It is very mechanical. All three DI types are of the same level of wizardry.

  • https://twitter.com/mattupstate Matt W

    Can you explain why you didn't remove inheritance for mediators?

  • https://joelhooks.com Joel Hooks

    I didn't want to implement IMediator. Actors/Commands don't have a lot going on, where mediators do. It would have required more thought, and I am mostly interested in portable service/model tiers so I left it at that for this example.

  • https://twitter.com/ianmclean Ian McLean

    Well my point being that the [Inject] marker is an indication that something is special about the properties that its assigned to whereas no such indication for constructor params – you would assume they're as ordinary as anything else and not receiving injections (at least just by looking at code examples).

  • https://twitter.com/ianmclean Ian McLean

    you want to see the framework attempt to inject eventMap/evenDispatcher rather than inherit them? whats the need? easier migration of mediators from projects built on other frameworks?

  • https://joelhooks.com Joel Hooks

    There is nothing special about the properties though, and in fact, making them private and initializing them via non-optional constructor arguments is a lot more special than mutable public properties.

    I don't disagree about newcomers.

  • https://twitter.com/mattupstate Matt W

    Thanks for the explanation. I tend to forget mediators are never really portable.

  • Glidias

    The Command /Service/Actor base classes in RobotLegs which are mostly optional and I seldom use those as well. (which isn't the best reason). Models could to dispatch events to act as a suitable bindable data source, and extending from Actor prevents one form natively doing so.

    I didn't know RobotLegs/Swiftsuspenders automatically inject into constructor arguments without requiring the [Inject] metadata above the class. This means it's possible to code classes in Haxe without having to rely on metadata, and just use consturctor arguments to clearly define core dependencies (which was what I had wished..and thought it wasn't possible). Especially so in game development, a given game engine/manager should not involve too many dependencies, just what it's needed for it to run. Haxe is great for inlining core engine-related settings/alchemy byte assemblies, while RobotLegs is good for the application-end bootstrapping. But I digress..

    The use of metadata is more for convenient wiring “in the last-minute” due to “unexpectedly” required-to-add features (and often many numerous models/services/etc. required within a class). As such, it's more hackish, though it works in allowing one to conveniently declare additional resources to be injected to your class, the mediator (or injected class thereof), will definitely end up doing too many things “for-the-application”, violating single responsibility and preventing the class to be used elsewhere simply because it's handles many models/services/etc. across different tiers in an app. However, I must say metadata helps deliver many injections for fast deliver of application requirements, even though it's pretty much “dead” at that point and would only work “for the project”. In most cases, a application-specific mediator will have to “mediate” lots of stuff across a more complicated (and changing) application anyway, thus the use of metadata is useful for such cases. (Generally, mediators only fall within this non-reusable category). However, I must say such a practice is more out of a result of last-minute changes/additional requirements, and not for long-term good application design.

  • Nikos

    Excellent mate im gonna download and try now

  • Nikos

    wow youve got a bunch of libs in there. Are all those adobe ones you put in there external from the flex/flash sdk?

  • https://joelhooks.com Joel Hooks

    yes.

  • Nikos

    Would you reccomend studing these and adding to my own master source repo? thx

  • Nikos

    I've just almost gotton used to the syntax with [inject] and now I don't ned it lol

  • Nikos

    Any chance you could explain why you need to do this:

    this.searchTermInput.validateNow();

    in the code for the GallerySearch view

    protected function handleSearch():void
    {
    this.dispatchEvent(new GallerySearchEvent(GallerySearchEvent.SEARCH, this.searchTermInput.text));
    this.searchTermInput.text = “”;
    this.searchTermInput.validateNow();
    }

  • Iki_xx

    What about this:
    As stated in the Robotlegs Internals document (excerpt):
    No metadata! And, the property is available immediately. Brilliant, except that there is a bug in most versions of the Flash Player (pre 10.1) that throws a spanner in the works: the constructor argument information that we need is not available until after at least one instance of that class has been constructed. This means that the DI container has to create a dummy, throw-away instance whenever it encounters such a class for the first time. It’s not a big deal, but it’s something to be aware of – especially if your constructors perform actual work.

    What is the best way to handle this?

  • https://twitter.com/StimuliTV Doug Gray

    Hey Joel,

    I'm looking over the code for this example and i like the idea of not adding features i wont use but still keeping with the framework using more explicit code. I'm new to Robotlegs so my understanding of all the DI options is not great at the moment so my question is this.

    Is there a specific swc or (preferably) source folder i can use (and learn from) currently available where these dependencies have been removed or can you explain what i would need to remove from the last source on github?

    Cheers
    Doug

  • Anthony McCormick

    Hi nice post, I too think that if an element is required then it should be injected through the constrictor
    I do have one question however you said that
    “your constructor might get really big. In fact, the limit is 10 parameters.”
    Do you mean that this is a restriction imposed by robotlegs?
    Thanks for the post
    Anthony

  • https://joelhooks.com Joel Hooks

    It is a limit imposed by SwiftSuspenders.

    https://github.com/tschneidere…

    Looks nuts, but that is how you have to do it in AS3.