Communication and resource access within the client application

Communication within the client application and how to access some of it's features/resource is an important topic. This is why this page has been separated from the JS standard one eventhough briefly discussed in it.

Since the client application is the backbone of Toyota client code it is important to understand how to communicate with its modules, how to access certain of its feature and when it is ok to access it. The following topics are essential for developers working on the application itself and developers from third parties that are dependent on it.

Event driven and Postal JS

The only standard way for communicating with the client application and using it's functionalities is PostalJS. Non-safe direct access to module's function/resources is discouraged especially from outside the client application(third party applications).

Postal.js has been chosen by Toyota enterprise architect in an early stage of the project, the library is going to be used to avoid tightly coupled modules as much as possible and help communication between co-existing application within Toyota webpages.

How it works

Whenever an external functionality has to be triggered or retrieved an event is published with some optional data. So for instance module X is going to publish an event without the need of knowing the existance of module Y which is going to handle the event in a subscription:

//in module Y:
Postal.subscribe('event', function(msg, data) {
    console.log(data);
});
//in module X:
Postal.publish('event', 'hello world!');

Here is another example where module X is expecting some data to be "returned":

//in module Y:
Postal.subscribe('event', function(msg, data) {
    data.response = 'hello world';
});
//in module X:
var data = {response:''}
Postal.publish('event', data);
console.log(data.response); // will log 'hello world'

Safe communication and functionality use within the Toyota webpages

Since multiple application have to co-exist on each page of the Toyota sites(backbone application/carconfigurator/customer portal app/...), some communication is sometimes required to check the state of an application, accessing it's resource etc... Since each respective application code is a moving target -a new version is being released every two weeks- directly accessing another application functionality highly increases the risks of errors as the code evolves a lot.

Postal.js is going to allow applications to safely publish an event that a subscriber -if it exists- will handle. This approach is "error proof": if you are expecting something to occur when publishing a certain event and it doesn't, you'll end up with a non-functional code BUT no javascript errors will triggered. This is a huge improvement compared to a JS errors that might stop your application from working and break parts of the page code.

Here is a small illustration of the "error proof" approach VS direct access to a modules functionality:


/** 
* A recent update in module Y was made on the subscription event name, it changed from "show-helloworld" to 
* "show_helloworld"
* **/ 

//in module Y:
Postal.subscribe('show_helloworld', function(msg, data) {
    console.log(data);
});

/** 
* It seems like who ever worked on module X wasn't aware of the event name change and still uses "show-helloworld", 
* as a result the message will simply not be displayed when module X publishes the event but no errors will be triggered.
* **/ 

//in module X:
Postal.publish('show-helloworld', 'hello world!');

The risky non error proof approach:


/** 
* A recent update in module Y was made on a function name, it changed from "showhelloworld" to 
* "showHelloWorld"
* **/ 

//in module Y:
T1.moduleY.showHelloWorld = function(data){
    console.log(data);
}

/** 
* It seems like who ever worked on module X wasn't aware of the function name change and still uses the lowercase "showhelloworld".
* 
* **/ 

//in module X:
T1.moduleY.showhelloworld('hello world'); //An error is triggered => "Uncaught TypeError: T1.moduleY.showhelloworld is not a function"

Of course, there are other approaches to achieve this without using the event driven paradigm but for cross application communication on Toyota sites this is the standard.

Decoupled modules

The module decoupling idea is that each module is independent from the rest of the application and can be attached or detached from it without impacting the rest of the application. This is important because there are actually multiple versions of the application used by different sites Toyota owns.

For instance the carconfigurator application is using a lighter version of the client application than the one used on Toyota sites. This lighter version only uses the core modules of the complete application, this means that if any modules part of the core is trying to directly access a function from a non-core module you will get in trouble with a tightly coupled application.

Here's a quick illustration of the tighly coupled issue for the core application:

From there you probably understand why it is essential to decouple modules and safely access certain functionalities/resources.

Check if a resource is accessible

In such a big application where a lot of code is triggered asynchronously, it is important to be sure a resource is accessible whenever it is required and this is essential for third parties trying to access core functionalities from the T1 application!

Again, a simple usage of postal.js should be enough to make sure a resource is available whenever it is needed. For instance, if I want to communicate with some modules part of the T1 global namespace I can use this approach:

    //check if all modules have been initialized
    var queryObj = {response:false};
    Postal.publish('t1.loaded.query', queryObj);

    //If a subscriber is present on the page and knows the state of the application it will be able to set the response to true
    if(queryObj.response){
        //T1 is already loaded I can communicate with it        
       }else{
        Postal.subscribe('t1.loaded', function(){
            //T1 is now loaded I can communicate with it
        });
    }

This previous example clearly indicates the benefits of Postal.js whenever some resource availability check must be done(event driven paradigm).

The accepted direct function calls within the client application

IMPORTANT NOTE: the following topic only concerns modules created within the client app and not third party modules or scripts

One downside of a fully decoupled module approach via the event driven paradigm is that it can complicate and cumbersome a lot functionality access. For instance, instead of one direct getter method call to an external module you will need an emitter, a subscriber and an object with the future response. It can make the tracability of code execution quite complex in certain cases and way less explicit than direct calls.

Here's an illustration of the cumbersome downside of fully decoupled modules:

//In module T1.A we simply want to get the breakpoint from the breakpoints module
var data = {response:null}, 
breakpoint; 
Postal.publish('getBreakpoint', data);
breakpoint = data.response;

//In module T1.breakpoints
Postal.subscribe('getBreakpoint', function(data){
    var breakpoint = _private.currentBP();
    data.response = breakpoint;
});

This is why an alternative has been introduced: the jquery $.safe function extension. It allows you to do direct function calls on modules in a "safe way". The main benefit is that it is explicit and keeps the "error proof" function calls that we also had with event driven paradigm. On the other hand it couples modules(but in a safe way).

Here is an example:

//The safe function is simply going to make sure the object exists
var currentBreakpoint = $.safe('T1.breakpoints.currentBP')() || ''; //if T1.breakpoints.currentBP exists it will trigger otherwise undefined is returned(or a fallback function result provided as second param)

Safe pros:

Safe cons:

When not to use:

When is it ok to use