Just a quick note about the meaning and design between directly grabbing
method like:

    Service.request('InputWindowManager.releaseWindowFocus')

And

    this.publish('release-window-focus')

are different. The first one, although now it's somewhat popular in System
app, is very close to what we have tried to avoid in the past. Since the
coupling among methods caused lots of troubles when the methods are
unintentionally exposed. For example, the method to manipulate device
locking, is to grab the LockScreen component and to call it's method that
was not intentional for that

  // the oldest way
  window.LockScreen.lock()

The problem is, although the `Service.request` interface already solved the
issue about global instances, while there were some necessary refactoring
ongoing, these de facto interfaces also needed to be changed since the
original designs had become messy after the project grew. For the cases, it
in fact would become:

  // What the Service.request('lock') actually does:
  window.lockScreen.lock();                                // To turn inner
states
  window.lockScreenWindowManager.closeApp();               //
LockScreenWindow
  window.lockScreenInputManager.state.instance.close();    // To hide the
keypad

You can see if we don't have good interface to expose them at once, it
would be messy to manipulate these by each component. And not to mention if
we didn't decouple the direct method calling way to lock the device, it
would be a risky progress to refactor them.

Therefore, I think the real issue is whether we have a strong convention,
design principles, or language facilities to define these
interfaces/contracts clearly and reasonably (to have a great
`Service.request` mechanism cannot save the case of exposing immature
methods or even properties), no matter whether it's from message passing
pattern (`this.publish`) or the method-like one. Moreover, this is also
good for our extensions.


2015-11-19 5:52 GMT+08:00 Marcus Cavanaugh <[email protected]>:

> ("Kessler Syndrome <https://en.wikipedia.org/wiki/Kessler_syndrome>" is
> that thing where space satellites cascade into each other, making orbit a
> giant mess.)
>
> *tldr:* We often dispatch events to trigger *required* interactions
> between different modules. This is fragile. We should not use events for
> these cases; we should use Service.request() or similar.
>
> Often, a module needs to perform an action in response to triggers from
> other modules. In an effort to reduce coupling, the system app relies
> heavily on events for this purpose. For instance, if we need
> InputWindowManager to do something in response to SomeWidget's opening, we
> often do something like this:
>
> // in SomeWidget.js:
> this.publish('somewidget-opening')
>
> // in InputWindowManager.js:
> InputWindowManager.prototype.handleEvent = function(e) {
>   switch(e.type) {
>       case 'actionmenuhide':
>       case 'activityclosing':
>       case 'attentionrequestopen':
>       case 'attentionrecovering':
>       *case 'somewidget-opening': // this line added*
>         // Do things that release the current window focus or whatever
>   }
> }
>
> Here, InputWindowManager must respond the same way to a bunch of events
> from different sources. While decoupling the modules with an event is a
> good idea, it obscures an important module dependency. In this case, there
> are a few problems:
>
>    1. From SomeWidget's perspective, it's not clear why we emit the
>    event. (Here, the sole reason we emit the event is to ensure
>    InputWindowManager handles the hook at the right time.)
>
>    2. From InputWindowManager's perspective, we now have a group of logic
>    that needs to run in response to a bunch of different events. Rather than
>    reducing coupling, we've just moved the explicit dependency to
>    InputWindowManager, disguised as an event.
>
>    3. This pattern contributes to "event spaghetti", wherein code becomes
>    difficult to refactor and rationalize about due to the hidden entanglement
>    and cascading nature of event dispatching.
>
>
> For cases like this, where we _need_ a specific action to be performed, I
> think we should be more explicit about what, precisely, we want to happen:
>
> // SomeWidget.js:
> Service.request('InputWindowManager.releaseWindowFocus')
>
> Or, alternatively, dispatch an event that semantically represents our
> need, no matter which module it originates from:
>
> // SomeWidget.js:
> this.publish('release-window-focus')
> // ActivityWindow.js:
> this.publish('release-window-focus')
>
> There are times when it makes sense for a module to consider itself alone
> and decoupled, blissfully ignorant about whether or not other modules
> respond to its emitted events. However, we often *do* expect a module to
> interact in a specific, well-defined way with core system facilities, like
> input and window management. In these cases, there is a *necessary*
> coupling between modules. Using module-specific events obscures the
> coupling and leaves the system brittle.
>
>
> _______________________________________________
> dev-fxos mailing list
> [email protected]
> https://lists.mozilla.org/listinfo/dev-fxos
>
>


-- 
<http://about.me/snowmantw>Greg Weng

http://about.me/snowmantw

*Understand y f = f [ y f ] ; lose last remaining non-major friend*

*    -- Anonymous*
_______________________________________________
dev-fxos mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-fxos

Reply via email to