tag:robotlegs.tenderapp.com,2009-10-18:/discussions/questions/559-communicating-between-mediatorsRobotlegs: Discussion 2018-10-18T16:35:27Ztag:robotlegs.tenderapp.com,2009-10-18:Comment/74333472011-05-25T07:34:54Z2011-05-25T07:35:59ZCommunicating between Mediator's.<div><p>As you say</p>
<blockquote>
<p>an action may happen in one view, that I want to trigger an
event in another SPECIFIC view</p>
</blockquote>
<p>this has nothing to do with mediators but view-to-view
communication. There's a bunch of solutions for that: you could let
an event bubble through the display list, or have the views tightly
coupled, or...<br>
Mediators are only for framework-to-view and vice versa
communication.</p>
<p>IMO if you have a situation where multiple display objects MUST
communicate directly with each other, chances are they actually
constitute one view with one mediator.</p>
<p>Your example of multiple views of the same type showing
different data sets, can (should?) be solved w/o view-to-view
communication, but by letting the mediator decide whether it needs
to update its corresponding views dataset or not (based on a
setting in the view)</p></div>creynderstag:robotlegs.tenderapp.com,2009-10-18:Comment/74333472011-05-25T07:40:19Z2011-05-25T07:40:19ZCommunicating between Mediator's.<div><p>Hi Shawn,</p>
<p>(Just saw creyender's reply - which is also good!)</p>
<p>a mediator shouldn't have an API, because the mediator is just a
short-lived hook on the application layer for getting your view
involved.</p>
<p>Mediators should be state-free because of the
disposal/re-creation when the view is removed and re-added. Don't
think of the mediator is part of your view layer - the stateless,
disposable, new-instance-each-time nature of mediators makes them
unsuitable for use as view controllers.</p>
<p>If you want to communicate between 2 mediators directly then
presumably that's because you need to communicate between 2 views.
It would sometimes be better to simply communicate between those
views within the view layer - depending on the parent/child nature
of those views.</p>
<p>On the 'can't use events issue' - is there no way to use a more
specific event? Or add a filtering property to those events? Many
people have solved the 'targeting a specific instance' problem
without resorting to wiring the mediators together.</p>
<p>Finally - mediators are not singletons, they're disposable, so
injection can result into a situation where the instance is no
longer available for garbage collection (having been injected into
another mediator), and then the instance that is created when the
view hits the stage a second time is a new instance and is no
longer the one you've injected.</p>
<p>This leads to memory leaks, multiple-listener bugs and
hard-to-diagnose bugs. It also - inevitably - leads to
race-condition problems, because the mediators have to be created
in a specific order so that the injection value is available. It's
not trivial - for example - to inject a child view mediator into a
parent view mediator, because the parent view mediator is created
and requires the injection before the child view mediator is
created.</p>
<p>In addition, if you inject (into another mediator) a mediator
for a view of which there are multiple instances, which of the many
mediators of that class should be injected?</p>
<p>For all those reasons, as of 1.7 (to be released shortly)
mediators won't event be available for injection (you can inject
into a mediator, but you can't inject the mediator into anything
else) - we've already completely cleaned that from the mediatorMap
in development forks (it was a side-effect and never intended
behaviour).</p>
<p>If you're still wishing to go down this path then may I suggest
that you check out and adopt AS3 signals instead - they'll allow
you to use a request-response pattern which opens up the
possibility of more focussed communication. Search for
request/response on here and you'll find quite a few descriptions
of how to implement it using signals and/or events.</p>
<p>Hopefully that's helpful (even if it doesn't fit with what you
had wanted to hear),</p>
<p>Thanks,</p>
<p>Stray</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/74333472011-05-25T14:13:12Z2011-05-25T14:13:12ZCommunicating between Mediator's.<div><p>The reason I think it makes sense to talk to the mediator's
directly, is<br>
because in our app the Mediator's are responsible for initiating
and<br>
receiving service calls.</p>
<p>I know Stray, that you advocate like "pure" mediators, but we're
using them<br>
to also be our control layer in a lot of cases (seems to work
fine).</p>
<p>So, we have a set up where mediator's can catch framework event,
start a<br>
service call, and pass the appropriate set of data back to the
view. There<br>
are some cases where a view might trigger an event, which we want
to<br>
triggers a load event in another sibling mediator, and it seems a
waste to<br>
be dispatching that over the global event bus when I can get just
grab the<br>
mediator for that specific view instance from the mediatorMap, and
make a<br>
call on it.</p>
<p>View > View communication doesn't really work, basically we
would need to<br>
tell the view to dispatch en event, so the mediator could catch it,
and then<br>
perform a load. That seems backwards.</p>
<p>On Wed, May 25, 2011 at 1:40 AM, Stray <<br>
<a href=
"mailto:tender+d414de95a5ee485859e1f65d27d6435b39ebdc3ca@tenderapp.com">
tender+d414de95a5ee485859e1f65d27d6435b39ebdc3ca@tenderapp.com</a>>
wrote:</p></div>Shawn Blaistag:robotlegs.tenderapp.com,2009-10-18:Comment/74333472011-05-25T14:17:35Z2011-05-25T14:17:35ZCommunicating between Mediator's.<div><p>For an example, think of one parent view, with 3 complex child
views. When<br>
an event happens in one of the child views, we need to:<br>
1. Tell the parent mediator to switch views<br>
2. Tell the sibling mediator to start loading it's data</p>
<p>What I'm proposing is that the parent mediator would catch the
view event,<br>
switch views in the viewStack, and then grab the mediator for the
new child,<br>
and say mediator.loadData(id);</p>
<p>This is nice because when you look at the parent mediator class,
you can<br>
easily tell what's going on, rather than this super loose coupling,
where<br>
the parent dispatches an event to the global bus, which it's
intended for<br>
one of it's immediate descendants.</p>
<p>On Wed, May 25, 2011 at 1:40 AM, Stray <<br>
<a href=
"mailto:tender+d414de95a5ee485859e1f65d27d6435b39ebdc3ca@tenderapp.com">
tender+d414de95a5ee485859e1f65d27d6435b39ebdc3ca@tenderapp.com</a>>
wrote:</p></div>Shawn Blaistag:robotlegs.tenderapp.com,2009-10-18:Comment/74333472011-05-25T14:41:20Z2011-05-25T14:41:20ZCommunicating between Mediator's.<div><p>Hi Shawn,</p>
<p>You're absolutely free to architect any way you like - just be
aware that the next RL release doesn't support injecting mediators
into other classes at all - it continues to be outside of how the
framework was intended to work, and, having fully appreciated how
unstable it is, we're now completely cleaning up those mediator
mappings on the injector.</p>
<p>The workaround will be to either patch your own version of the
mediator map to reintroduce it, or do your own injector mapping in
a command (you can get the mediator for that view from the
mediatorMap). Or of course you can stick with the version you're
running now - there's no really significant reason to update.</p>
<p>It seems like the architecture you're going for is largely
dictated by your earlier decision to bypass the command layer. If
it works for you then it works - the guidelines are only based on
our best attempt to lead people down a path that won't get them
into trouble. We don't have any evangelical-style messages to
preach - we're just basing them on our own experiences in building
our own projects and in helping out on other projects that have run
into trouble.</p>
<p>You kind of pitched your question as if you wanted a discussion
- but then it seems that really you're happy with what you're doing
and not that interested in thinking about other ways to do it and
why they might be useful... so I'm confused about what you were
asking?</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/74333472011-05-25T15:19:42Z2011-05-25T15:19:43ZCommunicating between Mediator's.<div><p>Yep, we definately have our hands tied a bit because of previous
architectural decisions, but there's no reason we cant use events
to communicate between view tiers, I'm just not convinced as to the
benefits. I'm looking for a discussion, but not a one sided one
;)</p>
<p>I guess I was looking for a better explanation of the "why"
behind why we should never access a mediator directly from another
mediator. The FAQ's are little more than "don't do this", which
doesn't work for me.</p>
<p>I can see where using [Inject] of mediator's would be a complete
mess, I'm not talking about that at all, I'm talking about
retrieving a specific mediator for a specific instance of a view.
Are you saying that the "mediatorMap.retrieveMediator(view);" API
is going to be removed completely?</p></div>Shawntag:robotlegs.tenderapp.com,2009-10-18:Comment/74333472011-05-25T15:23:12Z2011-05-25T15:23:13ZCommunicating between Mediator's.<div><p>And just to clarify, we are currently using a fully event based
communication model, and can totally continue to do so.</p>
<p>It's just that some members of the team have expressed concern
that in some cases, this is excessive decoupling, and I kinda of
agree ...</p></div>Shawntag:robotlegs.tenderapp.com,2009-10-18:Comment/74333472011-05-25T15:43:24Z2011-05-25T15:43:24ZCommunicating between Mediator's.<div><p>The mediatorMap.retrieveMediator(view) is staying - it's only
the ability to inject a mediator into another mediator that is
going.</p>
<p>So, I've already explained the garbage collection, memory leak,
wrong-instance and repeated-handlers issues that are part of the
'don't do it' reasoning. Did those explanations not make sense? You
didn't really respond to any of them.</p>
<p>If your view never leaves the stage, and these mediators never
get removed, these are of less concern. If your view does leave the
stage, and your mediator is destroyed and a new one created, then
you'll run into all of these problems. The specific instance you
grab at one point in time is not guaranteed to be the same specific
instance that is currently mediating this view.</p>
<p>Retrieving and working with a specific mediator is appropriate
within the short-lived thread of a Command executing, but it's
dodgy outside of that situation, so creating persistent references
is dangerous... do it at your peril.</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/74333472011-05-25T15:51:29Z2011-05-25T15:51:29ZCommunicating between Mediator's.<div><p>Well, I didn't respond cause I think most of those only would
apply if we<br>
were lazily injecting mediator's all over the place...?</p>
<p>We wouldn't have GC issues since we would not even be storing a
reference to<br>
the mediator anywhere, simple grabbing it inside a function, and
making a<br>
call on it, we can't get the wrong view, since again we're not
injecting,<br>
we're grabbing the mediator for the specific child instance we
want, at<br>
runtime, and making a call on it.</p>
<p>I guess what I'm getting from this is, you need to be careful,
but if done<br>
properly there's nothing really inherently wrong with calling a
function on<br>
a mediator. You just need to implement it in a way that will not
cause any<br>
sideeffects (which is pretty damn easy to do really).</p>
<p>The only side effect that I can see that would apply to our
implementation,<br>
is the coupling, and this is the one I just don't get, what's the
big deal<br>
if you create a top-down one-way mediator coupling...</p>
<p>On Wed, May 25, 2011 at 9:43 AM, Stray <<br>
<a href=
"mailto:tender+d414de95a5ee485859e1f65d27d6435b39ebdc3ca@tenderapp.com">
tender+d414de95a5ee485859e1f65d27d6435b39ebdc3ca@tenderapp.com</a>>
wrote:</p></div>Shawn Blaistag:robotlegs.tenderapp.com,2009-10-18:Comment/74333472011-05-25T17:11:38Z2011-05-25T17:11:38ZCommunicating between Mediator's.<div><p>TBH and with all respect, but this does sound a bit like someone
who builds his house w/o inner walls, then uses some iron bars to
hold the floors from crashing and wonders why that's really so bad,
since - it holds, doesn't it?<br>
I mean, yeah sure, you can reference mediators from other
mediators, you can basically do anything you want with RL, but
what's the use of using a dependency injection framework if you're
going for tight coupling anyway??</p>
<p>Look, the reason why it's bad to call services directly from
mediators is because it brings you into problems. What if another
mediator needs that same data? Or if at some point in the future
you actually need to call another service before that one? You'll
be refactoring, refactoring and refactoring. You'll sink deeper and
deeper, and sure, there are patches. There always are, just like
having mediator-to-mediator communication is a patch, but it's
nothing more than that.<br>
The idea behind avoiding tight coupling is NOT to make it easy
while you're coding the use case as first defined. It's intended to
avoid problems along the way, when use cases change, requirements
change, services get ported, merged or split up, when customers
decide they really prefer to have the views on a page-per-page
basis instead of all together on one screen, et cetera ad
infinitum. All of the above changes will bring you into troubles
when you start using mediator-to-mediator communication.</p>
<p>My sincere advice is - and I know it's a hard one - refactor it
to use commands. Do it now, because the mess will only become worse
and worse and worse and you'll end up with an application that
behaves erratically, is not reusable, nor scalable, nor portable.
And, yes, I had to learn it the hard way too, until I really
understood that it's not about getting things done NOW, but it
really is about having something that is flexible enough that
future changes are easily made. These days I almost never refactor.
I ADD things. That's only possible if none of your mediators have
direct references to services and/or models.</p></div>creynderstag:robotlegs.tenderapp.com,2009-10-18:Comment/74333472011-05-25T18:50:17Z2011-05-25T18:50:19ZCommunicating between Mediator's.<div><p>Unfortunately thats just not an option, we don't have the QA
resources to handle such a major refactor, even if I wanted to I
wouldn't get permission. The app is live, and doing well, and
there's no way we can tear it apart at this point.</p>
<p>I think you're exagerating what I'm proposing, I'm not saying
lets couple everything together, I'm saying in specific instances,
under a specific use case, it might make sense to call an API on
the mediator itself. Thats all.</p>
<p>And just to be clear, no where in the app currently do we do any
mediator coupling at all. I'm just floating the idea...</p>
<p>I'm not happy with our current service > mediator
implementation either, but I'm stuck with it. For the most part it
works fine, and the app is actually fairly robust and scalable. The
nature of the app is that views almost never share data, so we
haven't run into many issues. The biggest issue we have with this
approach is when services complete, and the mediator is no longer
in existence, definitely a major design flaw on my part.</p></div>Shawntag:robotlegs.tenderapp.com,2009-10-18:Comment/74333472011-05-26T07:37:13Z2011-05-26T07:37:13ZCommunicating between Mediator's.<div><p>Obviously if it's already released it would be hardly worth it,
unless if it's an ongoing project.<br>
And yes, I did exaggerate - I've been known to do that once in a
while :) - but it's a bit like using a global variable: you can get
away with it, and it works faster, but you know it can get you into
trouble.</p></div>creynders