Agile software development using Kanban & Scrum. We code Flex & Ruby on Rails in Auckland, New Zealand.

  • Why Boiler is better than Robotlegs. Pt. 1

    Haha! That’s gunna turn some heads.. I hope.

    Herein I set out to explain why I’m building Boiler. Other than the obvious fun of writing a framework, I have some very specific reasons.

    I could be wrong of course, Robotlegs is so good (and it’s well past the alpha stage, unlike Boiler) that it’s a tough call. However, why would I bother if I wasn’t trying to improve on something awesome?

    Doubling intent

    Imagine this is a mediator I just wrote:

    package views {
        public class WidgetMediator {
    
        [Inject]
        public var notifier:IEventDispatcher;
    
            private var view:Widget;
    
            public function register(view:Widget):void {
                this.view = view;
    
                view.addEventListener(MouseEvent.Click, handleClick);
            }
    
            public function deregister():void {
                view.removeEventListener(MouseEvent.Click, handleClick);
            }
    
            protected function handleClick(event:MouseEvent):void {
                notifier.dispatchEvent(event);
            }
        }
    }
    

    I consider this class to have all the markings of a mediator. It’s name ends in mediator, that should be enough… But there’s more. It’s in the views folder where a lot of folk stash their mediators. It expects to be registered against a view:

    register(view:Widget)
    

    Despite not inheriting from a Mediator Interface, it’s a mediator. In the land of Ruby, they call it ‘duck-typing’. It looks like a duck, quacks like a duck, it’s a duck.

    So in Boiler, we use conventions to invert control. When you start using Steam, you follow convention to describe the intent for a class. Steam, by the way, is the reference desktop framework for Boiler, like MVCS is for Robotlegs.

    The above mediator needs only be ‘Mapped’ using SwiftSuspenders and Steam will configure injections and view mappings ‘because it looks like a mediator’.

    In Boiler:

    lifetime.mapClass(WidgetMediator,WidgetMediator); // A little note on the first param later.
    

    In Robotlegs:

    mediatorMap.mapMediator(WidgetMediator);
    

    It’s a tiny difference, really, except now we don’t have to inherit from anything to look like something. Later I’ll show that we also don’t let ourselves get caught by inheriting from sugar classes.

    The first thing that Boiler gives you, is no more polymorphic dependencies that only serve to duplicate intent.

    When you want to extend the framework behavior, remove behavior, or use certain behavior in only some modules, the benefits of avoiding framework polymorphism become clear. Later on, I’ll demonstrate this with examples that extend or modify the framework.

    About that first parameter

    Why does SwiftSuspenders require an interface separate from the class to instance? This example is a mediator, all of it’s dependencies are injected. It’s never injected into another class. Where it’s built is where it’s stored, in a generic, testable class… So I can’t see a problem with lifetime.mapClass(widgetMediator);

    1. vworkdev posted this