robotlegs / robotlegs-framework

An ActionScript 3 application framework for Flash and Flex
https://robotlegs.tenderapp.com/
MIT License
967 stars 261 forks source link

RL2 Modularity #38

Closed darscan closed 12 years ago

darscan commented 13 years ago

An issue to discuss the API and implementation of modularity in Robotlegs 2.

joelhooks commented 13 years ago

Message scoping is a big concern when it comes to modularity. Basically you need to make the decision between two defaults:

Global Local

Defaulting to global provides maximum up front convenience up until the point that you have multiple contexts of the same type handling the same message types. Now you run into ambiguity issues that need to be solved with an alternative scope. One solution for this, if you have global as the default, is to allow context's to override the default scope. For contexts that will have multiple same-type instances, developers would easily be able to provide any scope they wanted (including custom scopes)

Local is "safer" in that you won't end up getting surprised by the ambiguity, but you'd likely need to override the default more often. This is intentional, but when you start needing to override a default more often than not, it begs the question of the sensibility of the default.

tschneidereit commented 13 years ago

I'm still not sure why you would need to have lots of chatter on a global bus in many cases. Can you give an example for use-cases for that that aren't better catered for by specific extensions installed into the root context (and soft-bound in the inner contexts)?

Regarding local-default, global-by-explicit-choice contexts, one easy way to implement them would be for the default messaging extension to define the local message bus's mapping as soft. Then, you can switch to a global default bus by overriding that mapping in the outermost context.

I'm not sure whether that's a good idea, though. It would mean that the contexts by default enable meddling with one of their most important aspects from the outside. At least, the meddling would have to be deliberate, though.

joelhooks commented 13 years ago

global by default is convenient. When I am writing an application, I am very granular with Contexts. They almost always need to talk back and forth. Global removes the thought process around scope and everything just works. I only have to think about scope in cases closer to the edge.

darscan commented 13 years ago

Yeh, I wasn't feeling the whole global-by-default thing until now. If we are encouraging people to break their apps up into context-per-feature slices then cross-context chatter becomes the norm. Then again, if this is default:

[Inject] public var dispatcher:IEventDispatcher;

Then going global really isn't that hard:

[Inject(name="global")] public var dispatcher:IEventDispatcher;

Or to chat with your parent:

[Inject(name="parent")] public var dispatcher:IEventDispatcher;

Or to chat on an arbitrary bus:

[Inject(name="lazer")] public var dispatcher:IEventDispatcher;

But I'm sure I'm overlooking things again. What am I missing?

joelhooks commented 13 years ago

I don't think it is "hard" - just in my experience you usually want contexts to talk to one another, so being restrictive forces me to always bust out the awesome strings in my metadata instead of having to just not modify it and seeing it work.

As long as I can make the choice in regards to application-wide scope, I am a happy developer irrespective of the intentions of the framework defaults :>

pixels4nickels commented 13 years ago

My biggest hurdle in my latest project was trying to get item renderers and poopups(no typo) to be able to get injections in a granular module context. I pass the system manager into my global app context to get their injections handled but they are then chattering too much. The easy/ugly solution is to make a lot more signals and create insulation by naming (ick). I am very excited about being able to have more control over contexts. I have externals swfs as well as modules that are embedded in the main app.

What I would like to be able to do is name a different parent context for a laoded module besides my current global context. It looks like this will be possible and that is badass.

On a side note, thanks for the modular and signal map work. Great stuff.

darscan commented 13 years ago

Ah, yeh RL2 will handle popups much more cleanly.

Stray commented 13 years ago

In my app around 10% of comms are between modules, the rest are inside modules. Global-by-default encourages the wrong approach I think - you should be snacking functionality off into modules and only having cross-chatter on a limited range of high level requests / responses. If all messages are open to everybody then have you really encapsulated features?

darscan commented 13 years ago

This is true also.

pixels4nickels commented 13 years ago

Indeed. If it were not for the popups and item renderers ( we have a few with a lot of "in-item" features and controls) my app context would be pretty much empty.
The only thing I really would use a "global" context for is comms between module. I have a few "global" signals related to showing errors/exceptions, dialogs and executing a few commands. I solved the item issue by assigning mediation to the item when it is selected...similar to how I handled using 1 mediator for many tabs with PureMVC (using dynamic mediator assignment). I would like to kill this because we are not really using a MVC pattern, but more of a presentationModel approach. I do not really want to mix overarching approaches.

I was a big fan of PureMVC pipes because wiring was uber flexible for external modules. I am looking forward to the same kind of approach to contexts in RL2 (if that is kind of the plan).

pixels4nickels commented 13 years ago

I love the way Joel's Modular packages works. Expanding on that approach to controlling signal scope would rock.

joelhooks commented 13 years ago

I like the clean separation of global and local scope the Modular utils provide. That is the general idea, without the hard coded API.

On Oct 31, 2011, at 18:37, Ken Rogersreply@reply.github.com wrote:

I love the way Joel's Modular packages works. Expanding on that approach to controlling signal scope would rock.

Reply to this email directly or view it on GitHub: https://github.com/robotlegs/robotlegs-framework/issues/38#issuecomment-2584944

joelhooks commented 13 years ago

I agree, the encapsulation is a great point. Robotlegs should lead you on The Path™

On Oct 31, 2011, at 17:42, Strayreply@reply.github.com wrote:

In my app around 10% of comms are between modules, the rest are inside modules. Global-by-default encourages the wrong approach I think - you should be snacking functionality off into modules and only having cross-chatter on a limited range of high level requests / responses. If all messages are open to everybody then have you really encapsulated features?

Reply to this email directly or view it on GitHub: https://github.com/robotlegs/robotlegs-framework/issues/38#issuecomment-2584443

darscan commented 12 years ago

Modularity has been addressed by the following extensions:

https://github.com/robotlegs/robotlegs-framework/blob/version2/src/robotlegs/bender/extensions/modularity/ModularityExtension.as

https://github.com/robotlegs/robotlegs-framework/blob/version2/src/robotlegs/bender/extensions/scopedEventDispatcher/ScopedEventDispatcherExtension.as

The first one allows contexts to expose and/or inherit dependencies from other contexts in a hierarchy.

The second one allows contexts to share named event dispatchers in that same hierarchy.