Background
We have a fairly complex Silverlight client which we are rewriting in HTML/Javascript/CSS, built on top of the same web services. Actually we have two Silverlight different clients which we are porting, which share some common functionality.
I read the article on http://addyosmani.com/largescalejavascript/ and am planning to use the proposed architecture, and in particular the mediator pattern.
A 10000 feet overview of the pattern described by Addy:
code is divided into small Modules
Modules are only aware of a mediator object; Modules cannot communicate directly with other modules
the mediator has a simple interface for publishing and subscribing to messages
Modules can subscribe to messages (through the mediator API), giving a callback function
Modules can publish messages to the mediator, with a parameter object, and the mediator calls the callback method of any modules subscribed to the message, passing the parameter object
One of the main goals here is to achieve loose coupling between modules. So we can reuse the modules in the two clients. And test the modules in isolation. And the mediator should be the only global object we need, which has got to be good.
But although I like the idea, I have the feeling it is overly complicated in some cases, and that some of my team members will not be convinced. Let me explain by example:
Assume we have a helper function which performs a calculation - lets say it formats a string - and assume this function should be available to any module. This function could belong in a 'tools' or 'helper' module which is then reusable and testable.
To call this function from an arbitrary module I have to post a message, something like formatString with my input string as parameter. And the helper function has subscribed to the formatString message. But before I post the formatString message I first have to subscribe to a message like formatStringResult, with a callback function which can receive the result. And then once I get the result back, I unsubscribe from the formatStringResult message.
Question(s)
Should the mediator rather offer this type of helper functionality directly in it's own interface?
Or should I extend the publish interface to allow an optional result parameter, where helper methods can directly write a result?
Is the tradeoff of having an extra mediator layer really worth the
benefit of achieving loose coupling?
I'd really appreciate advice from developers with experience of achieving loose-coupling in 'complex' JavaScript applications.
You actually perfectly described the BarFoos application Framework:
https://github.com/jAndreas/BarFoos
I don't think that mediator is the pattern what you are looking for, at least not for what you described.
Just think of 2 object triggering formatString the same time. What each would get back in their formatStringResult?
Mediator is for broadcasting events to everyone who is listening. Publishers don't want to broadcast requests (e.g. formatString) rather want to notify others about a change in their own state. Note how the source and consumer of the information is different. Having a mediator means those parties don't have to have a reference to each other to communicate, thereby its lowering the coupling.
Related
Let's imagine, in a OO world, I want to build a Torrent object which listens to the network and lets me interact with it. It would inherit an EventEmitter and would look something like this:
var torrent = new Torrent(opts)
torrent.on('ready', cb) // add torrent to the UI
torrent.on('metadata', cb) // update data in the UI
and I can also make it do things:
torrent.stop()
torrent.resume()
Then of course if I want to do delete the torrent from memory I can call torrent.destroy().
The cool thing about this OO approach is that I can easily package this functionality in its own npm module, test the hell out of, and give users a nice clean reusable API.
My question is, how do I achieve this with Cycle.js apps?
If I create a driver it's unclear how I would go about creating many torrents and having their own independent listeners. Also consider I'd like to package functionality in a way that others get to easily reuse it in other Cycle.js apps.
It seems to me that you are trying to solve a problem thinking about it as you would write "imperative code".
I think creating Torrent instances with their own listeners is not something you should be using in cycle components.
I would go about it differently - creating Torrent module and figuring out what would be its sources and sinks. If this module should be reusable and published, you can create it as a function that would receive streams as arguments. Maybe something similar to TodoMVC Task component (which is then used in its parent component).
Since this module can be created as a pure function, testing it should be at least just as easy.
This implementation of course depends on your requirements but communication with the module would then be done only with streams and since it would be declarative there would be no need for methods like stop() and destroyed() which you would call from elsewhere.
How do I test it?
In cycle.js you'd write a component with intent model and view functions.
You'd test intent(), for given input Streams, produces Streams of actions that you want. For models, you'd test that given http and action streams, you get the state you want, and for view, you test that given a state you get the VDom you want.
One tricky bit with cycle.js is that since it passes functions around, normal JavaScript objects that use the 'this' keyword are not worth the trouble due to 'this' context problems. If you are working with cycle.js and you think you might write a JS class for use with Isolate, Onionify, or Collections most likely, you are going in the wrong direction. See MDN docs about 'this'
how I would go about creating many torrents
The Cycle.js people have several ways to deal with groups of things like this.
This ticket describes some things that might work for that:
Wrap subapp in Web Component
Stanga and similars.
Cycle Collections
Cycle Onionify
i'm studying how nodejs module system works.
I've found so far this literature:
https://nodejs.org/api/modules.html
http://fredkschott.com/post/2014/06/require-and-the-module-system/
http://www.bennadel.com/blog/2169-where-does-node-js-and-require-look-for-modules.htm
It helps me to understand a few points however is still have these questions:
If i have a expensive resource (let's say database pooling connection) inside a module, how can i make sure that by requiring the module again i am not re-evaluating the resource?
How can i dynamically unload a disposable resource once i already called the 'require' on it?
It's important because i have some scenarios that demands me to make sure that i have a single instance of database pool. because of this i'm exporting modules which are able to receive parameters instead of just require the expensive resource.
Any guidance is very appreciated.
Alon Salont has written an EXCELLENT guide to understanding exports in NodeJS (which is what you're accessing when you call require()) here:
http://bites.goodeggs.com/posts/export-this/#singleton
If you study the list of options for what a module can export, you'll see that the answer to your question depends on how the module is written. When you call require, NodeJS will look for the module loaded in its cache and return it if it already had it loaded elsewhere.
That means if you choose to export a Singleton pattern, are monkey-patching, or creating global objects (I recommend only the first one in your case), only ONE shared object will be created / will exist. Singleton patterns are good for things like database connections that you want to be shared by many modules. Although some argue that "injecting" these dependencies via a parent/caller is better, this is a philosophical view not shared by all, and singletons are widely used by software developers for shared-service tasks like this.
If you export a function, typically a constructor, require() will STILL return just one shared reference to that. However, in this case, the reference is to a function, not something the function returns. require() doesn't actually CALL the function for you, it just gives you a reference to it. To do any real work here, you must now call the function, and that means each module that requires this thing will have its own instance of whatever class the module provides. This pattern is the more traditional one where a class instance is desired / is the goal. Most NPM modules fit this category, although that doesn't mean a singleton is a bad idea in your case.
I'm trying to understand the Flux example chat app. The authors mention this unidirectional data flow:
However, in the example app there are dependencies between Action Creators (ChatMesssageActionCreator) and Stores (MessageStore), and between Stores (MessageStore, ThreadStore) and Web API Utils (ChatMessageUtils), which seems to be against the unidirectional data flow rule:
Is it recommended to follow the given example, or should one design a better pattern?
Update
I figured out that the ChatMessageUtils doesn't belong to Web API Utils, so the two arrows from store shouldn't point there, therefore maybe they're okay.
However the connection between the ActionCreators and the Store seems still strange.
The example is a bit forced, and it was created with the purpose of trying to show how waitFor() works. The WebAPI aspect of the example is pretty half-baked and really should be revised.
However, even though MessageStore.getCreatedMessageData(text) passes a value to the store, it's still a getter. It's not setting data on the store. It's really being used as a utility method, and a good revision (pull request?) would be to move that method to a Utils module.
To improve upon the example for the real world, you might do a couple things:
Call the WebAPIUtils from the store, instead of from the ActionCreators. This is fine as long as the response calls another ActionCreator, and is not handled by setting new data directly on the store. The important thing is for new data to originate with an action. It matters more how data enters the system than how data exits the system.
Alternatively, you might want to have separate client-side vs. server-side IDs for the messages. There might be few advantages of this, like managing optimistic renderings. In that case, you might want to generate a client-side id in a Utils module, and pass that id along with the text to both the dispatched action and the WebAPIUtils.
All that said, yes the example needs revision.
I am investigating the pub/sub pattern because I am reading a book that highly advocates event driven architecture, for the sake of loose coupling. But I feel that the loose coupling is only achieved by sacrificing readability/transparency.
I'm having trouble understanding how to write easily-understood pub/sub code. The way I currently write my code results in a lot of one-to-one channels, and I feel like doing so is a bad practice.
I'm using require.js AMD modules, which means that I have many smaller-sized files, so I feel like it would be very difficult for someone to follow the flow of my publishes.
In my example code below, there are three different modules:
The UI / Controller module, handling user clicks
A translator module
A data storage module
The gist is that a user submits text, it gets translated to english, then stored into a database. This flow is split into three modules in their own file.
// Main Controller Module
define(['pubSub'] function(pubSub) {
submitButton.onclick(function() {
var userText = textArea.val();
pubSub.publish("userSubmittedText", userText);
});
});
// Translator module
define(['pubSub'] function(pubSub) {
function toEnglish(text) {
// Do translation
pubSub.publish("translatedText", translatedText);
};
pubSub.subscribe("userSubmittedText", toEnglish);
});
// Database module
define(['pubSub'] function(pubSub) {
function store(text) {
// Store to database
};
pubSub.subscribe("translatedText", store);
});
For a reader to see the complete flow, he has to switch between the three modules. But how you would make clear where the reader should look, after seeing the first pubSub.publish("userSubmittedText", userText);?
I feel like publishes are like a cliff hanger, where the reader wants to know what is triggered next, but he has to go and find the modules with subscribed functions.
I could comment EVERY publish, explaining what modules contain the functions that are listening, but that seems impractical. And I don't think that is what other people are doing.
Furthermore, the above code uses one-to-one channels, which I think is bad style, but I'm not sure. Only the Translator module's toEnglish() function will ever subscribe to the pubSub channel "userSubmittedText", yet I have to create the new channel for what is basically a single function call. While this way my Controller module doesn't have to have Translator as a dependency, it just doesn't feel like true decoupling.
This lack of function flow transparency is concerning to me, as I have no idea how someone reading such source code would know how to follow along. Clearly I must be missing something important. Maybe I'm not using a helpful convention, or maybe my publish event names are not descriptive enough?
Is the loose coupling of pub/sub only achieved by sacrificing of flow transparency?
The idea of the publish subscribe pattern is that you don't make any assumptions about who has subscribed to a topic or who is publishing. From Wikipedia (http://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern):
[...] Instead, published messages are characterized into classes,
without knowledge of what, if any, subscribers there may be.
Similarly, subscribers express interest in one or more classes, and
only receive messages that are of interest, without knowledge of what,
if any, publishers there are.
If your running code doesn't make any assumptions, your comments shouldn't do either. If you want a more readable way of module communication, you can use requirejs' dependency injection instead, which you already do with your pubsub module. This way, you could make it easier to read the code (which brings other disadvantages). It all depends on what you want to achieve...
I am currently reading http://addyosmani.com/resources/essentialjsdesignpatterns/book/#mediatorpatternjavascript
I understand the mediator pattern as some sort of object which sets up publish and subscribe functionality.
Usually I am setting up objects which already provide subscribe(), publish() methods. Concrete Objects extend this base object so that subscribe() and publish() are always registered as prototype attributes.
As I understand right the mediator pattern is used to add the publish-subscribe-methods to an object.
What is the benefit of this practice? Isn't it a better practice to provide a base object with publish and subscribe functions than letting a mediator set up at construction?
Or have I understood the mediator pattern wrong?
As what I have learned from similar posts some time ago:
The mediator pattern provides a standard API for modules to use.
Let's have an example:
Your app's thousands of modules heavily rely on jQuery's $.post. If suddenly, your company had licensing issues and decided to move over to, for example, MooTools or YUI, would your look for all the code that uses $.post and replace them with something like MooTools.post?
The mediator pattern solves this crisis by normalizing the API. What the modules know is that your mediator has a post function that can do AJAX post regardless of what library was used.
//module only sees MyMediator.post and only knows that it does an AJAX post
//How it's implemented and what library is used is not the module's concern
jQuery.post -> MyMediator.post -> module
MooTools.post -> MyMediator.post -> module
YUI.post -> MyMediator.post -> module
The mediator serves as the "middle-man" for intermodule communication.
One problem in newbie JS development is when modules are interdependent. That is when:
MyClassA.something = MyClassB.method();
MyClassB.something = MyClassA.method();
But what if something is wrong in MyClassB and the developer took it out of the build. Would you look for and strip out all code in MyClassA that uses MyClassB so that it does not break due to the absence of MyClassB?
The mediator pattern's publish and subscribe pattern solves this by making the module subscribe to an event instead of directly interfacing with the other modules. The mediator acts as a collection of callbacks/subscriptions that are fired when events are published.
This "anonymous" subscribing results in partial loose-coupling. Modules would still need to know which modules to listen to or at least a set of events to listen to, but they are connected in a way that won't result in breakage if any one of them is taken out. All they know is that they subscribed to the event and will execute when that event happens - regardless of who fires it, if it fires at all, or if the trigger exists.
You can achieve mediation without using eventing (pub/sub).
In complex/sophisticated flows, it can be challenging to debug or reason about code that is purely event driven.
For an example on how you can create a mediator without pub/sub, you can take a look at my project jQueryMediator:
https://github.com/jasonmcaffee/jQueryMediator