Hub and Sandbox concepts

82 views
Skip to first unread message

Yevgeniy Vaskevich

unread,
Apr 22, 2013, 10:46:03 AM4/22/13
to kern...@googlegroups.com
Hi,

I want to ask the following question:

Are Hub and Sandbox the same things?

Why I ask about this? Please look at an example:

Kernle.register([
{id: 'module-a', 'ModuleA'},
{id: 'module-b', 'ModuleB'}
]);

Kernel.module.define('ModuleA', 
{
fieldValue: '',

init: function()
{


}
});

Kernel.module.define('ModuleB', 
{
init: function()
{
$('.btn-addItem').click( this.onAddItem );
},

onAddItem: function()
{
// need get ModuleA.fieldValue
// something code...
}

});

I do not know how to get fieldValue properly. 
ModuleA can not be inherited by ModuleB, because they are different system components.

============================================================

thinking.....maybe Hub (implementation kerneljs) and Sandbox are different concepts? 

Sandbox - get public Modules interface;
Hub     - only event hub.

============================================================

Example:

Kernel.module.define('ModuleA', 
{
fieldValue: '',

init: function()
{


},

getFieldValue: function()
{
return fieldValue;
}
});

Kernel.sandbox.define('module-a', {
getFieldValue: function()
{
               var moduleA = Kernel.module.get( 'module-a' );
               return moduleA.getFieldValue();
}
});

Kernel.module.define('ModuleB', 
{
init: function()
{
$('.btn-addItem').click( this.onAddItem );
},

onAddItem: function()
{
                // get public ModuleA interface
var fieldValue = this.sandbox.get('module-a').getFieldValue();
}
});

I'll be pleased for the clarification.


alindsay55661

unread,
Apr 22, 2013, 11:30:14 AM4/22/13
to kern...@googlegroups.com
Yevgeniy,

Conceptually Kernel modules are by definition not supposed to know or care about each other. If a module needs information from another module then that information should be exposed via the hub. In my case I typically separate modules that provide data ("service" modules) from other modules. Then I wrote an extension that allows me to export module methods to the hub so other modules can access them. This is by design, to prevent the need for module dependency. 

However, it is technically possible to break this paradigm. Just use the following:

Kernel.module.define('moduleB', {
  init: function() {
    this.moduleAReference = Kernel.module.get('moduleA');
  }

});

I do not encourage this, however. If you find yourself needing to access information from another module I suggest refactoring your code so that information is available through the hub. Otherwise you are introducing module dependencies, something Kernel is not meant to handle. Since there is no dependency management built into Kernel your app could get quite ugly over time.

As far as introducing another interface, Sandbox, to provide public access to modules goes, this is not something I am planning on doing. As mentioned above, you can already do this with Hub. But the real reason is that the design pattern behind Kernel is purposely isolating modules from each other. Modules are meant to communicate only through "interesting events" and they should not know about other modules. That is not to say that modules can't make api calls to the hub and ask for things, they can, they are not totally reactive. But by thinking in a more event driven manner you can make the best use of Kernel. Here is an example:

Scenario 1 (non event driven): 
ModuleB needs fieldValue from ModuleA. ModuleB asks ModuleA for fieldValue when ModuleB needs it. 

Scenario 2 (event driven):
ModuleB needs fieldValue from ModuleA. ModuleB listens for 'field-value-updated' event and receives fieldValue when ModuleB updates it.

The second case is probably what you want anyway, it's unlikely you will want ModuleB to have to know the details of when ModuleA is updating its fieldValue. Kernel handles this for you, just have ModuleA broadcast an update event and ModuleB will get what it needs without ever knowing ModuleA even exists. The beauty here is that there is no dependency between the modules. If ModuleA fails to load for example, ModuleB continues to work, albeit the 'field-value-updated' event will never fire so ModuleB will never react to it. But again, this is by design and isolates the source of the problem, ModuleA.

Hope this helps.

Alan

Yevgeniy Vaskevich

unread,
Apr 22, 2013, 6:11:01 PM4/22/13
to kern...@googlegroups.com
(sorry my english)

Alan, thanks for your cases

Unfortunately, event driven case, does not work for me.
The cause: ModuleA initialize at startup application, but ModuleB later and on demand. When ModuleA send event 'field-value-updated', ModuleB yet ready listen this event.

This is not ideal and poorly scalable case, however...

Kernel.module.define('ModuleA', 
{
fieldValue: '',

init: function()
{


},

getFieldValue: function()
{
   return fieldValue;
}
});

// extended hub
Kernel.hub.define('main',
    getFieldValue: function()
    {
        return Kernel.module.get( 'module-a').getFieldValue();
    }
});

Kernel.module.define('ModuleB', 
{
init: function()
{
$('.btn-addItem').click( this.onAddItem );
},

onAddItem: function()
{
return this.hub.getFieldValue();
}

});

понедельник, 22 апреля 2013 г., 18:30:14 UTC+3 пользователь alindsay55661 написал:

alindsay55661

unread,
Apr 22, 2013, 6:51:47 PM4/22/13
to kern...@googlegroups.com
Actually this is a valid case. It just so happens that I am not dynamically loading my modules so I haven't run into this. This situation could be potentially be resolved by allowing modules that are initialized to retroactively listen for events that have already fired, much like jQuery Deferreds. In that case the module would receive the events when it initializes. I will have to think about the implications for this but I can see some benefits.

What you have done is valid but as you say not quite so scalable. You could make this more scalable by abstracting ALL module methods behind a SINGLE hub method. Here is an example:

Kernel.hub.define('main', {

  _apis: {},

  registerApi: function(namespace, api) {

    var my = this;

    my._api[namespace] = my._api[namespace] || {};

    Kernel.extend(my._api[namespace], api, true);

  },

  api: function() {
    
    var my = this, api, namespace, method,
        args = Array.prototype.slice.call(arguments);

    api = args.shift();
    namespace = api.split('.')[0];
    method = api.split('.')[1];

    if (my._api[namespace][method]) return my._api[namespace][method].apply(my, args);

    return undefined;   // Throwing an error here creates too much dependency in my view, better to return something negative.

  }
});

Then you would export the ModuleA method like so:

Kernel.module.define('ModuleA', {
  init: function() {

    this.hub.registerApi('foo', {
      getFieldValue: this.getFieldValue
    });

  },
  getFieldValue: function() { ... }
});

And you would access the method like so:

Kernel.module.define('ModuleB', {
  init: function() {

    var fieldValue = this.hub.api('foo.getFieldValue');

    // Optionally with arguements
    // var fieldValue = this.hub.api('foo.getFieldValue', 123, 'test');

  }
});

Note that I explicitly created a namespace rather than using the module name. This is by design and meant to illustrate that you are not calling a module directly, but rather a method that was made available publicly on the hub. Also, doing so allows you to register methods from multiple modules into the same namespace on the hub. Also take note that the above implementation (untested) will only work for synchronous methods. If you want to make it work for synchronous methods you'll have to use deferreds.

Hope this helps.

Alan

Yevgeniy Vaskevich

unread,
Apr 22, 2013, 7:58:25 PM4/22/13
to kern...@googlegroups.com
Perfect solution
Thank you very much!

>> This situation could be potentially be resolved by allowing modules that are initialized to retroactively listen for events that have already fired, much like jQuery Deferreds. In that case the module would receive the events when it initializes.

Deffered events queue...very interesting



вторник, 23 апреля 2013 г., 1:51:47 UTC+3 пользователь alindsay55661 написал:
Reply all
Reply to author
Forward
0 new messages