Please consider the Javascript code excerpt at the bottom. Roughly it consists of two modules, one for handling messages. What is the benefit of the filtersUpdateSuccess method within the messages module?
Currently it merely delegates to the overwriteAll method of the tplPanels module. One idea that strikes me is that within the filtersUpdateSuccess method, the call to tplPanels.overwriteAll could be wrapped in a try/catch. Could this benefit me, and are there any other benefits to the extra level of indirection?
PS .... I am familiar with the following question and have consulted it and followed the links within it, but now I want an answer in a specific context as opposed to the more general: Level of Indirection solves every Problem
function msgHandlers() {
var scope
,msgs;
return {
SET_CONTEXT: function(context) {
scope = context.scope;
msgs = context.messages;
}
,SUBSCRIBE_ALL: function() {
me.subscribe(scope, msgs.FILTERS_UPDATE_SUCCESS, this.filtersUpdateSuccess);
//me.subscribe(scope, msgs.FILTERS_UPDATE_SUCCESS, tpl.overwriteAll);
}
,filtersUpdateSuccess: function(filterValues) {
tplPanels().overwriteAll(filterValues);
}
}
}
function tplPanels() {
var instances = {};
return {
locationInstance: function() {
if (!instances.locationPanel) {
instances.locationPanel = locationPanel();
}
return instances.locationPanel;
}
//more instances, etcetera
,overwriteAll: function(filterValues) {
//do something useful
}
}
//etcetera
The case here seems to be one of abstraction of interface, not extra layers of reference indirection.
Interface abstraction serves several purposes:
To cause a piece of code to fit an interface required by one generic client or one client whose shape is out of your control.
To cause a piece of code to fit an interface shared by multiple clients.
To cause a piece of code to fit a maintainer's mental model by abstracting away implementation details.
To cause a piece of code to fit an interface required by a planned (not just possible) future use-case.
If another module in your system already takes different inputs with the context-setting-subscribing-filtering interface then it can be valuable because it allows your code to plug in there: (1) or (2) above.
If you have concreate plans to have multiple providers or consumers of this interface, then it can be valuable to just make it conform to the interface now since you've already done the work to page the code into memory: (4) above.
If other modules are already structured this way, or if filtering is a common operation other modules use, then code maintainers can leverage that to learn your code quickly: (3) above.
If none of those apply, then, since filtersUpdateSuccess doesn't close over anything that tplPanels doesn't, there's no value in the interface abstraction.
Related
I'm working on a large CMS system where a particular module and its submodules take advantage of the same backend API. The endpoint is exactly the same for each submodule aside from its "document type".
So a pattern like this is followed:
api/path/v1/{document-type}
api/path/v1/{document-type}/{id}
api/path/v1/{document-type}/{id}/versions
As time goes on the number of modules that use this API grows and I am left with many, many redundant api services that implement 7 CRUD methods:
getAllXs() {...}
getX(id) {...}
getXVersion(id, versionId) {...}
etc...
with an individual method looking like this
getAllXs() {
let endpoint = BASE.URL + ENDPOINTS.X;
let config = ...
return http.get(endpoint, config)
.then(response => response.data);
.catch(...);
}
Where X would be the name of a particular Document Type.
I came to a point where I decided to make a single service and do something like this:
const BASE_URL = window.config.baseUrl + Const.API_ENDPOINT;
const ENDPOINTS = {
"W": "/v1/W/",
"X": "/v1/X/",
"Y": "/v1/Y/",
"Z": "/v1/Z/",
}
getAllDocuments(docType, config={}) {
let endpoint = BASE_URL + ENDPOINTS[docType];
return http.get(endpoint, config)
.then(response => response.data);
.catch(...);
}
...other methods
Where a type is specified and a mapped endpoint is used to build the path.
This reduces all of the document api services down to one. Now this is more concise code wise, but obviously now requires an extra parameter and the terminology is more generic:
getAllXs() --> getAllDocuments()
and it's a bit less 'idiot-proof'. What makes me insecure about the current way it is written is that there are 6 modules that use this API and the same 7 methods in each service.
The questions I keep asking myself are:
Am I bordering anti-pattern with the dynamic functions?
What if I had 10+ modules using the same API?
Your question made me think of a common Object Relational Mapping design problem.
There are no single source of truth when it comes to design, but if your recognize an ORM in what you are building and value object oriented design principles, I have some inspiration for you.
Here's an over simplification of my own vanilla ES6 ORM I have used on many projects (reusing your code snippets for relatability). This deisgn is inspired by heavy ORM frameworks I have used in other languages.
class ORM {
constructor() {
this.BASEURL = window.config.baseUrl + Const.API_ENDPOINT
this.config = {foo:bar} // default config
}
getAll() {
let endpoint = this.BASEURL + this.ENDPOINT
return http.get(endpoint, this.config)
.then(response => response.data)
.catch(...)
}
get(id) {
// ...
}
}
And examples of extension of that class (notice the one with a special configuration)
class XDocuments extends ORM {
static endpoint = '/XDocument/'
constuctor() {
super()
}
otherMethod() {
return 123
}
}
class YDocuments extends ORM {
static endpoint = '/YDocument/'
constuctor() {
super()
}
getAll() {
this.config = {foo:not_bar}
super.getAll()
}
}
Since you are specifically asking if this is bordering anti-patterns. I would suggest reading about SOLID and DRY principles, and ORM designs in general. You will also find code smells about global constants, but this would only be true if you are in a window context. I see you are already on the right path trying to avoid code duplication smell and the shotgun surgery smell. :-)
Good luck and don't hesitate to ask further questions and add additional details in comments!
If you'd provide more of your original version of code, that'd be more points to point to.
At the moment I just can say that the DRY principle is generally a good idea (not always but... well it's a complicated topic). There's a lot of articles about DRY. Google it.
You're afraid that your code became more complex. Don't be. In my experience, novice programmers fail miserably exactly because they discard the DRY principle. And only after a while, when they become stronger they start to fail at the KISS principle. And only one extra argument in addition to the 3 that already there doesn't add much to the complexity.
Am I bordering anti-pattern with the dynamic functions?
To be "dynamic" - that's the reason functions exist
What if I had 10+ modules using the same API?
Exactly! 10+ more chances to make a typo, to forget something, to misread, etc and 10+ more work to do if you'll need to change something. That is if you don't DRY your code.
PS. And the name getAllDocuments is actually better than getAllDocType1s if that's the real name from your original code.
While I share most of x00's answer, I would take into account how static your endpoints really.
Is there no chance module "X" can change any of its endpoints definitions? For instance, you need to pass one more query param. Are your modules all exactly the same with no room for change?
If the answer is no, there you go. To make that simple change you would have to refactor your whole code base (if you would implement it the way you propose, that is).
If the answer is yes, well, I see no reason for you to not implement your proposed dynamic functions. Personally, I would lean towards a service that my modules extend and use, just in case I do want to make minimal changes to them. For instance:
class MyGenericService {
constructor() {
this.url = window.config.baseUrl;
}
async getAllDocuments(config) {
return http.get(this.url, config)
.then(response => response.data);
.catch(...);
};
// ...and so on
}
This allows my code to scale and be modifiable, with just one takeaway which is you would need to maintain one file per module, that has something like this:
class XService extends MyGenericService {
constructor() {
this.url = window.config.baseUrl + '/v1/x';
}
}
If maintaining this extra files is too much overhead, you could receive the endpoint's URL in the constructor, on the MyGenericService, and you would just need to do stuff like this in your controllers:
const myXService = new MyGenericService('/v1/x');
const myYService = new MyGenericService('/v1/y');
// ...or it could use your endpoint url mapping
// I don't really know how is your code structured, just giving you ideas
There you have some options, hope it helps!
I am just trying to get my head around event driven JS, so please bear with me. There are different kinds of modules within my app. Some just encapsulate data, others manage a part of the DOM. Some modules depend on others, sometimes one module depends on the state of multiple other modules, but I don't want them to communicate directly or pass one module to the other just for easy access.
I tried to create the simplest scenario possible to illustrate my problem (the actual modules are much more complex of course):
I have a dataModule that just exposes some data:
var dataModule = { data: 3 };
There is a configModule that exposes modifiers for displaying that data:
var configModule = { factor: 2 };
Finally there is a displayModule that combines and renders the data from the two other modules:
var displayModule = {
display: function(data, factor) {
console.log(data * factor);
}
};
I also have a simple implementation of pub-sub, so I could just mediate between the modules like this:
pubsub.subscribe("init", function() {
displayModule.display(dataModule.data, configModule.factor);
});
pubsub.publish("init"); // output: 6
However this way I seem to end up with a mediator that has to know all of the module-instances explicitly - is there even a way to avoid that? Also I don't know how this would work if there are multiple instances of these modules. What is the best way to avoid global instance-variables? I guess my question is what would be the most flexible way to manage something like that? Am I on the right track, or is this completely wrong? Sorry for not being very precise with my question, I just need someone to push me in the right direction.
You are on the right track, I'll try to give you that extra push you're talking about:
It you want loose coupling, pub-sub is a good way to go.
But, you don't really need that "mediator", each module should ideally be autonomous and encapsulate its own logic.
This is done in the following way: each module depends on the pubsub service, subscribe to all relevant events and act upon them. Each module also publishes events which might be relevant to others (code samples in a minute, bear with me).
I think the bit you might be missing here is that modules, which use events, will hardly never be just plain models. They will have some logic in them and can also hold a model (which they update when receiving events).
So instead of a dataModule you are more likely to have a dataLoaderModule which will publish the data model (e.g. {data: 3}), once he finishes loading.
Another great requirement you set is sharing data while avoiding global instance-variables - this is a very important concept and also a step in the right direction. What you miss in your solution for this is - Dependency Injection or at least a module system which allows defining dependencies.
You see, having an event driven application doesn't necessarily mean that every piece of the code should communicate using events. An application configuration model or a utility service is definitely something I would inject (when using DI, like in Angular), require (when using AMD/CommonJS) or import (when using ES6 modules).
(i.e. rather then communicating with a utility using events).
In your example it's unclear whether configModule is a static app configuration or some knob I can tweak from the UI. If it's a static app config - I would inject it.
Now, let's see some examples:
Assuming the following:
Instead of a dataModule we have a dataLoaderModule
configModule is a static configuration model.
We are using AMD modules (and not ES6 modules, which I prefer), since I see you stuck to using only ES5 features (I see no classes or consts).
We would have:
data-loader.js (aka dataLoaderModule)
define(['pubsub'], function (pubsub) {
// ... load data using some logic...
// and publish it
pubsub.publish('data-loaded', {data: 3});
});
configuration.js (aka configModule)
define([], function () {
return {factor: 2};
});
display.js (aka displayModule)
define(['configuration', 'pubsub'], function (configuration, pubsub) {
var displayModule = {
display: function (data, factor) {
console.log(data * factor);
}
};
pubsub.subscribe('data-loaded', function (data) {
displayModule.display(data, configuration.factor);
});
});
That's it.
You will notice that we have no global variables here (not even pubsub), instead we are requiring (or injecting) our dependencies.
Here you might be asking: "and what if I meant for my config to change from the UI?", so let's see that too:
In this case, I rather rename configModule to settingsDisplayModule (following your naming convention).
Also, in a more realistic app, UI modules will usually hold a model, so let's do that too.
And lets also call them "views" instead of "displayModules", and we will have:
data-loader.js (aka dataLoaderModule)
define(['pubsub'], function (pubsub) {
// ... load data using some logic...
// and publish it
pubsub.publish('data-loaded', {data: 3});
});
settings-view.js (aka settingsDisplayModule, aka config)
define(['pubsub'], function (pubsub) {
var settingsModel = {factor: 2};
var settingsView = {
display: function () {
console.log(settingsModel);
// and when settings (aka config) changes due to user interaction,
// we publish the new settings ...
pubsub.publish('setting-changed', settingsModel);
}
};
});
data-view.js (aka displayModule)
define(['pubsub'], function (pubsub) {
var model = {
data: null,
factor: 0
};
var view = {
display: function () {
if (model.data && model.factor) {
console.log(model.data * model.factor);
} else {
// whatever you do/show when you don't have data
}
}
};
pubsub.subscribe('data-loaded', function (data) {
model.data = data;
view.display();
});
pubsub.subscribe('setting-changed', function (settings) {
model.factor = settings.factor;
view.display();
});
});
And that's it.
Hope it helps :)
If not - comment!
You do not need a mediator. Just import data, config, and display and call display(data, config) where you need to.
// import data
// import config
function render(){
display(data, config)
}
Consider, if you will, an app with a few unique views/states - let's call it a game. You have an overworld screen, a battle screen, a multiplayer interface, and maybe a minigame or two.
For the sake of argument, there isn't a lot of code in common between each view, so it lends itself well to AMD - a central controller/dispatcher, and each game state split into a separate file/view.
dispatcher.core.js
> overworld.view.js
> battle.view.js
> tournament.view.js
> minigame.view.js
Input and key commands get routed to the dispatcher, and trickle down to the current active view, which in turn manipulates the DOM as needed. One-way AMD relationships, so far so good.
The thing I'm getting hung up on is the response flow. The API response data that goes through the system is diverse, often affecting multiple views at the same time. Consider this case:
User presses buttons to move
Key commands gets routed to map view for movement animation
Map sends AJAX request to server for movement result
AJAX returns "battle commence" response to dispatcher
Dispatcher tells map view to disable itself, then battle view to init
The dispatcher was designed for this - to receive instruction and distribute. It seems like the obvious choice, much more than letting views affect each other directly.
However, there's a fundamental flaw here - the one-way relationship between the dispatcher and the views is violated as soon as the AJAX result is sent from the view to the dispatcher. You can either use the dispatcher for your AJAX callback, or you can instruct the dispatcher to make the AJAX call for you - but either way the view requires a way to reference the dispatcher, which as I understand it, violates the core tenet of AMD. For the life of me, I can't figure out how this would be implemented correctly!
My question is this - how would one implement such a structure correctly? Is this a limitation of AMD, or am I misunderstanding it's use on a deeper level?
This question is intended to be for more of the general case, but if it affects answers at all, I'm using Require and jQuery for AMD and AJAX, respectively.
Is this a limitation of AMD, or am I misunderstanding it's use on a deeper level?
AMD does not by any means impose one way relationship between object instances in general. What it does strongly recommend to avoid (because even this is not an absolute requirement) is circular dependencies between modules. And the type of dependencies that matter for AMD are loading dependencies.
You can certainly have a module named dispatcher that goes:
define(function () {
function Dispatcher(views) {
this.views = views;
for (var ix = 0, view; (view = views[ix]); ++ix)
view.init(this);
}
return Dispatcher;
});
And viewA, viewB, that are structured like this:
define(function () {
function View() {
// ...
}
View.prototype.init = function (dispatcher) {
this.dispatcher = dispatcher;
};
// Etc...
return View;
});
Your main module could do:
define(['dispatcher', 'viewA', 'viewB'], function (Dispatcher, ViewA, ViewB) {
var viewA = new ViewA();
var viewB = new ViewB();
var dispatcher = new Dispatcher([viewA, viewB]);
});
The above is meant to be a schematic example of what is possible, not a prescription for a good design. At any rate, the point is that is is perfectly feasible as far as AMD is concerned to have circular references between objects.
There's nothing about AMD that is limiting here; it's entirely about the design of your modules themselves.
A common way to handle this is with an event-emitter.
The dispatcher can call methods directly on a view, but the view emits events which the dispatcher can listen and respond to, removing the need for a circular reference (as the view doesn't care where the events go, so it doesn't require a reference to the dispatcher.)
Fitted to your example workflow, it might look like this:
overworld tracks keypress
overworld animates in response to keypress
overworld emits 'move' event for dispatcher
// overworld.view
this.emit('move', {data});
// dispatcher
overworld.on('move', getMoveResult) // getMoveResult fires AJAX request
response tells dispatcher it's time to battle
dispatcher updates views
overworld.hide()
battle.show()
So I'm writing a whole bunch of vendor-specific files in node which all have a similar controller pattern, so it makes sense for me to cut them out and put into a common file.
You can see my common controller file here: https://gist.github.com/081a04073656bf28f46b
Now when I use them in my multiple modules, each consecutively loaded module is overwriting the first. This is because the file is only required once and passed dynamically through to each module on load (this allows me to add extra modules and these modules are able to add their own routes, for example). You can see an example module here: https://gist.github.com/2382bf93298e0fc58599
You can see here on line 53 I've realised that we need to create a seperate instance every time, so I've tried to create a new instance by copying the standardControllers object into a new object, then initialising the new object. This has zero impact on the code, and the code behaves in exactly the same way.
Any ideas guys? I'm in a bit of a jam with this one!
First thing I'd do is try to make things simpler and reduce coupling by invoking the single responsibility principle, et al.
http://www.codinghorror.com/blog/2007/03/curlys-law-do-one-thing.html
Put those Schemas into their own files, eg
models/client.js
models/assistant.js
models/contact.js
I've also found that embedded docs + mongoose is generally a PITA. I'd probably promote all those to top level docs.
You don't need to enclose your object's keys in quotes.
routes = {
list: function() {} // no quotes is aok
}
Also 'list' in typical REST apps is called 'index'. Anyway.
Ok, I'd break this up differently. Since you're requiring stuff from the index.js file in the middleware, they become tightly coupled, which is bad. in fact, I think I'd rewrite this whole thing so it was tidier. Sorry.
I'd probably replace your 'middleware' file with an express-resource controller
https://github.com/visionmedia/express-resource (built by author of express). This is a good framework for restful controllers, such as what you're building. The auto-loader is really sweet.
You may also want to look at: http://mcavage.github.com/node-restify/ It's new, I haven't tried it out, but I've heard good things.
Since what you're building is basically an automated mongoose-crud system, with optional overriding, I'd create an express-resource controller as your base
/controllers/base_controller.js
and it might look like
var BaseController = function() {} // BaseController constructor
BaseController.prototype.index = function() {
// copy from your middleware
}
BaseController.prototype.show = function() {
// copy from your middleware
}
BaseController.prototype.create = function() {
// copy from your middleware
}
// etc
module.exports = BaseController
Then I'd do something like:
/controllers/some_resource_controller.js
which might look something like:
var BaseController = require('./base_controller')
var NewResourceController = function() {
// Apply BaseController constructor (i.e. call super())
BaseController.apply(this, arguments)
}
NewResourceController.prototype = new Base()
NewResourceController.prototype.create = function() {
// custom create method goes here
}
module.exports = NewResourceController
Then to use it, you can do:
var user = app.resource(myResourceName, new ResourceController());
…inside some loop which sets myResourceName to be whatever crud you're trying to set up.
Here's some links for you to read:
http://tobyho.com/2011/11/11/js-object-inheritance/
http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/
Also, it sounds like you're not writing tests. Write tests.
http://www.codinghorror.com/blog/2006/07/i-pity-the-fool-who-doesnt-write-unit-tests.html
When a GUI is composed of several subcomponents that I treat as individual Views with their own Presenter and Models, is there a pattern for gluing them together? Some subcomponents are persistently on the screen while others would get swapped in and out.
What would be a good factory pattern for instantiating the respective MVP triad for a subcomponent that gets added to the GUI at runtime?
How do you glue the subcomponents with the persistent "container" part of the GUI and with each other? Would there be a "God Presenter" that ties other presenters together?
Update: I'm now shooting for something similar to Eclipse's extension mechanism. Plug-ins register themselves to a global registry for the functionality that they provide. When a functionality such as returning data or rendering a View is needed, the registry is queried and the returned functions are invoked (this is pure JavaScript, so I'm not using interfaces). I'm going with a pure-plug-in approach where everything (even the main View) is a plug-in. I might also use an Event Bus to let the various Presenters communicate agnostically.
Now my more specific question becomes, when a plug-in is about to contribute a View, how should I go about initializing the MVP triad and getting the View rendered into a parent container (outside the module). I probably need to let the View render itself into a container passed from outside and inject the View and Model (if needed) into the Presenter. An alternative would be for the View to return a component that can be placed inside a container, but this would be against my tentative ideal of keeping everything that is GUI-framework-specific inside View implementations. I prefer if the factory/glue mechanism can be framework-agnostic.
OK I'll stop yammering now and wait for some feedback, and then perhaps add more clarifications on where exactly I'm stuck...
I think the design pattern you're about is mediator.
I've written a javascript framework that consisted of a mediator.
It works like this:
You create a global instance of the
mediator,
register objects under
certain names,
use the mediator in your implementation to call methods
from registered objects within any of
the objects.
If something isn't present - no errors fly around.
If there are multiple instances - they all get the call.
This is the basic code for that:
(An extract of my code. I will make a jquery plugin including that in a while. If you're willing to use it push me to do it faster ;) )
function Mediator(){
function log(a){
try {console.log(a);} catch(e){
try {opera.postError(a);} catch(e){
//alert(a);
}
}
}
var __reg={}; // { "what": [object, ...], ... } //registers an object
//what=key that will identify, obj=an object
this._register = function(what,obj){
if(__reg[what]===undefined){
__reg[what]=[];
}
__reg[what].push(obj);
} //unregisters multiple objects and deletes a key
this._unregisterAll = function(what){
if(__reg[what]===undefined){log('Overlord:_unregisterAll - no registers'); return false; }
__reg[what]=null;
return true;
}
//unregisters a single element key
this._unregister = function(what){
if(this._countRegisters()==1){
__reg[what]=null;
return true;
} else { log('Overlord:_unregister - no registers'); return false; }
}
//unregisters last added element
this._unregisterLast = function(what){
var cnt=this._countRegisters(what);
if(cnt==0) { log('Overlord:_unregisterLast - no registers'); return false; }
if(cnt==1) {
__reg[what]=null;
return true;
} else {
__reg[what][cnt-1]=null;
return true;
}
}
//returns number of registered items
this._countRegisters = function(what){
try{
return __reg[what].length;
} catch(e){log(e);
return 0;
}
} //calls a method from all objects registered under 'what' with an array of parameters. returns true if there was at least one successful call
this._call = function(what,method,params){
var occured=false;
for(var i in __reg[what]) {
try {
__reg[what][i][method](params);
occured=true;
} catch(e) {log(e);//auto reakcja
}
}
return occured;
}
//does the call, but also returns an array of values retuurned by function
this._returnAll = function(what,method,params){
var re=[];
for(var i in __reg[what]){
try {
re.push(__reg[what][i][method](params));
} catch(e) {log(e);//auto reakcja
}
}
return re;
}
//runs a method from first object for a given key
this._returnFirst = function(what,method,params){
try {
return __reg[what][0][method](params);
} catch(e) {log(e);//auto reakcja
return null;
}
}
}
I guess that "keeping the GUI-framework-specific inside View implementations" is an overall application-level design choice, rather than an absolute must (at least when you think to "view implementation" as "plugin view implementation").
You could - for example - have a very thin view layer at plugin level, and implement a super-view layer within the parent that calls the plugins: thinking to a system of plugins that all add a column to a table, you could well have the bulk of the view code at parent level ("table") and have your plugins to just pass little more than raw data: you would avoid to repeat yourself and would make your code more flexible and maintainable.
On the other hand, if your plugins provide very different types of functionality that never interact directly (for example if they are the different subsystems of a flight simulator) you will want to keep everything that is related to views at plugin level, so that the parent object would not have to even know what a given plugin deals with, but just place it's returned value somewhere in the GUI.
Other factors that would probably influence your choice are the language and framework (if any) that you are using: in my personal experience, design patterns tend to be far from language-agnostic, as each language (and framework) has its own strengths / weaknesses which make certain choices obvious and certain others very difficult to implement.
Just my 2¢ to the discussion, anyhow! :)
For now, I'm going with this approach:
An extender (an extension implementation that a plug-in exposes) that is contributing a GUI component has a getTriad (will come up with a better name later) method that instantiates, wires and returns a MVP triad. The View has a getComponent method that renders and returns a framework-specific GUI element container that can be added to a parent container (the framework-specific details of which are encapsulated within the parent Views). I'm not letting the View render itself into a container but instead letting the parent View render the child into itself. I think this is better in terms of ensuring child Views don't directly mess with parent Views.