Voice Of A Developer: Decoupling Your Application - Part 35


Before moving further, let us look at the previous articles of the series


Javascript is the language of the Web. This series of articles will talk about my observations learned during my decade of software development experience with JavaScript. 

What is coupling?

In computer systems, coupling refers to the degree of direct knowledge that one component/class has of another. In a way, it is the degree of interdependence between the software modules. Our Application quality metrics depend upon the degree of interdependence components.

Types of coupling

Primarily, there are two types of coupling, i.e., loose and tight. 
                                 Source: Wikipedia
Loose coupling is a better design, as it promotes single-responsibility and separation of the concerns principle. A loosely coupled module can be consumed and tested independently of other modules. In OOPS programming languages, interface is a powerful tool to use decoupling. Classes communicate via interface rather than other concrete classes.
In general, tight coupling is bad and not preferred because the modules are dependent on each other. If you want to change one module then it is not easy if it is tightly coupled with the other modules.

What is modularity?

An Application is modular, when it is composed of decoupled pieces stored in the modules. As developers, we shall aspire for loose coupling. Hence, our Application will be easy to maintain, update code, and make changes.

Module writing in JavaScript

If you remember, I mentioned in ES6 v2 (article 20), that we have a module available where we can export and import JavaScript functions. The popular concept in loading the module is AMD.

Asynchronous Module Definition (AMD)

The overall goal for the AMD format is to provide a solution for the modular JavaScript, that the developers can use today. It loads the module and dependencies asynchronously. There are many advantages associated with AMD and these are:
  • Improved performance loads files when require/needed.
  • Define dependencies: Allow the developers to define dependencies that must load before a module is executed.
  • This pattern is useful, where synchronous loading of the modules incurs performance issues.

                                   Source: Wikipedia
There are various implementations of AMD, i.e., CommonJS, RequireJS, Dojo Toolkit.

Key concepts with the Modules

Here are the key concepts.
The loader loads the JavaScript code that handles the logic behind defining & loading modules. You need an AMD loader like dojo.js or require.js
Define function Here is the signature of this function.
define (id?, dependencies?, factory);
  • Id is an optional string literal.
  • Dependencies is an array which defines dependencies required by the module. These dependencies must be resolved prior to the execution of the next factory function. It is also optional to say if this module is not dependent on any other module. It loads the dependencies asynchronously.
  • The factory Mandatory argument is executed only once.
  1. define    
  2. ([    
  3.     'require',    
  4.     'dependency'    
  5. ], function(require, factory)     
  6.  {    
  7.     'use strict';    
  8. });   

Require function

The require() function takes two arguments: an array of the dependencies and a callback function to execute once, all the dependencies are loaded.
  1. require(['calc''math'], function(calc, math)    
  2. {    
  3.     // you code     
  4.     calc.getData();    
  5.     math.calculate();    
  6. });  

Play with RequireJS

RequireJS is the most widely used implementation of AMD. It is a JS file and a module loader. You can download RequireJS from here.
You can refer to my GitHub repository https://github.com/sumitjolly/create-template and the structure of the project is:
Download above repository using below command:
git clone https://github.com/sumitjolly/create-template.git

Project explanation

The intent is to showcase how RequireJS is useful and how we can write better code with it. There are various directories, underneath www folder, i.e., app, js, lib. The lib is where I have kept the require.js file. Let us deep dive into the other details which are as follows:

Load JavaScript files

Generally, we use <script src> format to add all our JavaScript files. RequireJS takes a different approach to load the modules. Look at Page1.html,
Page1.html  is an HTML, that includes require.js and passes value js/page1 to the attribute. 
The three components are,
  • Script the script tag to load JavaScript
  • data-main entry point attribute which refers to load a javascript file
  • src base URL for require.js file
In our directory structure, you can see three files,
  • common.js
  • page1.js
  • page2.js
Now data-main attribute will load js/page1.js.
Note- RequireJS assumes that file ends with .js. Both js/page1 & js/page1.js work fine.

Define module

There is a module that we created messages.js in and defined a dependency in lib/print.js file. The purpose of the messages is to include dependency and return a callback function. 
print.js file returns a callback print function.

Calling module

Page1.js- This page1.js has a dependency on App/messages and uses require() form, that just uses the string name of the module to fetch it.
Run www/page1.html in your Browser and review Network & Console Developer (F12).

Network tab
Network tab
You can also try www/page2.html and check the Console & Network tab to see page2.html related files only.


Please share your feedback/comments.