Thursday, April 19, 2012

Why I can’t grok RobotLegs


Warning:  I try to stay away from rants and philosophical posts on my blog, especially long ones. I’m violating all of these practices here.

I remember taking looking at RobotLegs two or so years ago. I also remember being a bit puzzled by it. I was a Parsley user at the time (and still am) because I had that “instant gratification” of how it could help me build larger and more complex applications more easily. I never got that feeling with RobotLegs… at least not instantly. Maybe I didn’t give it enough time.

What must a framework do to provide that feeling of instant gratification? It simply needs to solve a common problem I run into during development, or, at the least, make a common development strategy easier. That’s what design patterns are for, right? And that’s really what a framework does – enables you to employ design patterns to solve common problems. And that’s where RobotLegs was failing me. It’s not that I was failing to understand it, or what it was trying to do and achieve, it’s just that it was trying to solve problems I was not having.

It was never the dependency injection or event bus that bothered me… those aspects are great. It’s just that you can get that functionality from anywhere. The bothersome aspect was what RobotLegs referred to as the mediators. I have no issue with the mediator pattern. In fact, I think the pattern is great. I use mediators all the time, everywhere during Flex development. And I bet you do too whether you realize it or not. My issue was that what I was seeing from RobotLegs was not the mediator design pattern.

I’m no expert with design patterns and never have been.  But I have done enough research, experimentation, and real world usage to recognize, implement, and understand the benefits of the more popular ones out there. When it comes to mediators, I’m referring to what is represented by the Gang of Four. A mediator is simply a class that mediates the communication between two or more “colleagues” (components, views, etc.) in order to keep those colleagues decoupled and knowing nothing of each other. That’s not a quote, rather, just my understanding of them.

Have you ever implemented a container that has two or more child components in which the container facilitates the communication between those children? Of course you have. You probably do it all the time. The container is acting as the mediator to its children. Even the spark component architecture implements a mediator pattern in which the host component mediates the skin parts.
The recommended usage of mediators in RobotLegs is something…. different. I’m not quite sure what pattern it’s following, which is why I’m not sure what problem it’s trying to solve. From every example and real-world application I’ve seen running on RobotLegs, each “mediator” has a reference to a view, but just a single view. That would seem to mean that it’s mediating the communication between that view, and… I don’t know… the rest of the application, maybe? Shouldn’t that be the role of events or a messaging framework? The mediator needs a reference to two or more views to facilitate some mediation, in order to operate the way I understand the pattern and to solve the problem it’s meant to solve.

This one-view-to-mediator structure reminds me a lot more of presentation models. However, when you Google the proper usage of mediators in RobotLegs, you’ll find overwhelming opinions that they should not hold state. I would agree with that in the case of true mediators, but that would also disqualify them from acting as presentation models.

This brings me back full circle to the question of “How am I supposed to be using these mediators and how do they benefit my development?” Again, I completely understand how the documentation is suggesting I use them, but after implementing it that way, I have to take a step back and figure out how it was beneficial to the application versus implementing the architecture without using RobotLeg’s version of mediators. That’s the key feature I’m missing.

In any case, this was all in the past. Mostly just experimentation in an attempt to learn new ways of application development which resulted in a framework that wasn’t for me. No big deal. I moved on as a continued happy Parsley user. However, fast forward to current times and I ended up in a situation in that two contracts in a row involved development using RobotLegs. I thought maybe that enough time has passed that the framework may have matured into something “a bit more” than what I was seeing previously. Or maybe this time a light switch in my brain would turn on allowing me to see some crucial aspect I failed to see the first time around. Unfortunately, no such thing happened.

The first of the two contracts that I needed to utilize RobotLegs wasn’t much of an issue.  The application was mostly complete and I was brought in to help finalize it. That meant that most of the architecture was already in place. What little interaction I needed with the framework was a simple matter of following the guidelines, checking in the code, and calling it a day. The application definitely had an over-engineered feel to it and my estimates tended to be a bit under-estimated do to the additional implementation required to follow the suggested RobotLegs architecture, but so be it.

The second of the two contracts was a bit more problematic. This was another application that was far in development by the time I was added to it and it was far more complex than the previous (but I’d still label it as a small-to-medium sized application compared to others I’ve worked with) and followed the RobotLegs-way of development fairly close to the suggested guidelines as far as I understood them. Never-the-less, the application started to get out of hand to the point that an entire iteration was planned just for refactoring. I’m certainly not putting all the blame on RobotLegs, for a lot of it had to do with unrealistic deadlines, scope creep, and just about every other common issue that leads to application failure. However, it was also filled with so many view/mediator class combinations (which probably made up two-thirds of the entire application) that were doing absolutely nothing except making simple tasks more complicated and time consuming. The hardest part for me was being asked my opinion on how we could simplify things. I tend to be in more of a mentor role with magical answers to these types of questions, but in this situation, I had nothing to offer. With so much already implemented and dependent upon RobotLeg’s suggested architecture combined with a deadline looming, I knew that a major architectural change was out of the question. The only thing I could have recommended was to keep on doing things the RobotLegs way and get through it.

So, is anything I’ve said up until now valid? I believe so. Could a seasoned RobotLegs developer show me where I’m going wrong and lead me to the light? Perhaps. If anything, this just goes to show that no single architecture will fit every developer’s preferred style. I think that’s why I’ve always preferred “frameworks” to “micro-architectures”. Like Cairngorm before it, RobotLegs is a self-described micro-architecture in that it provides suggestions on how to property architect your applications. I specifically use the word “suggestions” because, obviously, you can use RobotLegs however you want. But if you’re not going to use it the RobotLeg’s way, then why use RobotLegs in the first place? As I’ve said before, you can get DI and messaging buses and host of other nifty utilities from other frameworks – frameworks that are specifically designed with no architecture style embedded (which was always one of the leading cons with Cairngorm) allowing you to use presentation models, mediators (and in a way that makes sense to you) or any other pattern, or nothing at all. No reason to beat around the bush… I’m specifically referring to Swiz, Parsley, and SpringActionscript (it’s been too long since I’ve looked at Mate to categorize it one way or another).

Maybe one day I will, but for now, I simply don’t grok RobotLegs.

9 comments:

  1. The beauty of robotlegs is that you don't have to use what you don't like.
    You want your views to dispatch command mapped events, and hence, completely bypass mediators? You can.
    Robotlegs will usually push you to create twice or thrice as much classes as you would normally, but when time comes to finalise unit testing, you *like* having a lot of classes. ^^
    My two cents anyway.

    Robotlegs 2, for what I've seen about it, allows you to bootstrap whatever feature you want up and running and ignore the others.

    ReplyDelete
  2. Nice post.

    "That would seem to mean that it’s mediating the communication between that view, and… I don’t know… the rest of the application, maybe?"

    Yes, that's exactly right. The mediator is there to mediate between a view (presentation layer) and the application (business layer). The idea is to ensure that the view has absolutely no references to the app.

    Personally, I find this overkill myself. For Flex projects I way prefer the Presentation Model pattern. For plain Flash projects however, a lot of developers enjoy the ability to give a designer complete control of an "assets" FLA that produces a SWC. The developer can then do integration in the mediator without needing to touch the view classes or introduce app coupling into those view classes (which might prevent the designers from being able to compile said view components).

    Different strokes :)

    ReplyDelete
    Replies
    1. Shaun, that's the part that puzzles me. Generally, a view is already decoupled from its parent and siblings, and only knows of its children. That view can dispatch a regular event to be handled by its parent container (mediator), and the parent container can do whatever it wants with it (such as sending another message to an event bus).

      The two areas of confusion for me are:

      1) If that RobotLegs mediator isn't directly coordinating the results of that event with another view/component (which it can't since it doesn't know about any other view/component), then it doesn't feel like the "mediator pattern" to me. Simply delegating that view's event to a messaging bus is something else, possibly still a pattern of some type, if not just "good decoupled architecture". However, I'm completely open to accepting the fact that my understanding of mediation isn't broad enough.

      2) Doing what is described above is simple to do naturally in Flex without a micro-architecture. That goes back to the "solving a problem that doesn't need solved" aspect. An event bus is needed, sure. But again, I'd feel weird using RobotLegs if I weren't using its version of mediation which seems to be one of its primary purposes of existence.

      Delete
    2. "That view can dispatch a regular event to be handled by its parent container (mediator), and the parent container can do whatever it wants with it (such as sending another message to an event bus)."

      Sure, but now your parent container has a reference to application entities (the concrete, translated event, and the message dispatcher), and you can't compile it without pulling those classes in. And you can't change the nesting without breaking references in the parent container. Your application becomes bound to the structure of the UI, and the UI becomes bound to concrete application classes.

      The point of the mediator pattern, as implemented in RL, is to be able to bridge arbitrary view classes back into the application, regardless of how they are nested, without coupling those classes to the application in any way. This is configured externally, and no matter where a view lands, a mediator is spawned to wrap it, poke its API and translate events back and forth between the UI and application domains.

      "If that RobotLegs mediator isn't directly coordinating the results of that event with another view/component (which it can't since it doesn't know about any other view/component), then it doesn't feel like the "mediator pattern" to me."

      It's still a mediator - it just mediates between a view and the application. Another view component would have its own mediator that would listen to application events and translate them into api calls on that view. This way each mediator only needs to know how to translate events for one component, yet they can still communicate, indirectly, by way of a shared event dispatcher.

      Looking at the Wiki page for the Mediator Pattern we see: "With the mediator pattern, communication between objects is encapsulated with a mediator object. Objects no longer communicate directly with each other, but instead communicate through the mediator."

      Your parent container approach achieves the same goal, but introduces structural coupling as it relies on the display list hierarchy. That may or may not matter.

      "I'd feel weird using RobotLegs if I weren't using its version of mediation which seems to be one of its primary purposes of existence."

      I use RL without mediation when doing Flex. I make use of the command map, shared event dispatcher, injector, etc.

      All that being said, I feel a lot of projects abuse mediation (and de-coupling techniques in general). We want appropriate de-coupling. When de-coupling radically obscures intent then it does more harm than good. I feel a lot of projects would benefit from making their dependencies more explicit, and only relying on strong de-coupling when it is actually needed.

      Also, as I mentioned previously, RL's mediator pattern is more useful for plain Flash than for Flex projects. With Flex you can couple your components to your app, and hand off the skins to your designers to work on. The skinning architecture in Flex 4 mitigates most of the issues that the RL mediator was designed to solve.

      Delete
    3. Shaun

      You're explanation makes perfect sense, and does a great deal in helping me understand its use - as implemented by RL.

      I tend to take a slightly different approach with views, and when I mention "views" I'm referring to something other than "components" (even though components live in the view layer of a MVC pattern and part of my confusion may be due to others classifying everything in the view layer, including components, as a "view").

      Components should certainly be mediated, for, they are the things that that live in their own little bubble and are not aware of their surroundings -- can often be moved around in the application, reused in the application, or even reused in different applications.

      Views, to me, are top-level classes acting as containers for major sections of the application, which also makes them very application specific. I don't see them moving around too much, and certainly not portable across applications. Being application specific, I don't see the problems with making them application aware, including being aware architectural and framework choices and being tightly coupled to specific implementations of event dispatchers (or possibly, injecting event dispatchers using metadata or other fairly agnostic means).

      If an application was designed with views nested in views nested in views, then RL makes a lot more sense. The approach I take is more like components nested in components nested in a view... with the "components" naturally mediated by their parent components without a framework. And my top-level view, well, it mediates its children, but no reason for it to be mediated itself, and hense my confusion as to why I would benefit for letting RL mediate it.

      Delete
  3. Parsley can be easily extended to accomodate mediator stuffs. Have you seen Michel Boudreau's contribution? It's worth a look...

    https://github.com/mboudreau/Parsley-Mediator

    I agree with the sentiment... architectural 'bits' need to make sense at a glance. If you find yourself squinting at the code in front of you during a code review - you aren't getting juice for the squeeze.

    With regard to the 'more classes' comment... someone needs to hit that dev with a sock full of nickels.

    ReplyDelete
    Replies
    1. Absolutely, the extension points in Parsley are amazing.

      Delete
  4. You can mediate an interface instead of a view and not have that coupling if you wanted to. I do it all the time to run automated testing where I use dummy views instead of the real view.

    ReplyDelete
  5. You don't need to use Mediators in Robotlegs. You can build using the presentation model pattern for example. See this discussion in the official Robotlegs knowledge base:
    http://knowledge.robotlegs.org/discussions/suggestions/6-presentation-model-vs-mediator-design-pattern

    ReplyDelete