JavaScript Module Pattern

Modules are needed in JavaScript to achieve modularity, which is to keep pieces of code that is unrelated to be independent from one another in a loosely coupled way (changes in one affects little to no effects to another).

These sort of module patterns are popular when module bundler like Webpack is still not a thing.

Modularity is considered by many to be well-structured code.

It's the idea of separation of concern. Revolves around the principle of high cohesion and low coupling.

Module provides encapsulation and avoid namespace collision. It acts as a replacement of class.

Encapsulation is something that JavaScript natively doesn't have. To counter this, we use something called closure. It provides private variable/method.

To sum that:

  • provide encapsulation

  • support modularity

  • avoid namespace collision

Module design pattern uses something referred to as IIFE (immediately invoked function expression), it's simply a function that wraps inside of a parentheses.

let iife = (function () {  
  ...
})();

or,

let iife = (function () {  
  ...
}());

The parentheses tells JavaScript engine that what's inside has to be an expression, therefore it knows when it encounters a function, the function has to be a function expression, not a function declaration.

There is also an important feature JavaScript has that you need to know, it is known as implied globals.

On a non global execution context, let's say something like this:

function foo () {  
  undeclaredVar = 3;
}
foo();  
console.log(undeclaredVar); // outputs 3  

Although undeclaredVar has not been declared prior, it still works!

JavaScript engine will check whether undeclaredVar is available in the current execution context, if not, then it will check it's parent execution context and see if it's there. If it's fruitless, then JavaScript engine will treats it as a global variable (freshly created with the corresponding assignment as the value).

Bear in mind that implied globals will not work in the global execution itself on strict mode!

a = 3; // throws error  
Revealing Module Pattern

This is the basic module pattern you'll use and often see to create a module. You probably saw it in another types of pattern (not just module pattern) such as factory.

let awesomeModule = (function () {  
  // private variable goes here
  return {
    // public variable goes here
  };
})()
Privilege Member

Privilege members are used to access private members indirectly. It's like a setter and getter. An advantage is to be able to filter and protect private members for being accidentally altered with an unexpected value or solely errors.

let awesomeModule = (function () {  
  let numFoods = 10;
  return {
    setFood(numFood) {
      if (typeof numFood !== 'number') {
        throw Error('setFood require number parameter');
      }
    }
  };
})()
Augmentation

This is a module pattern used to add additional properties to our current module. It is divided into two distinct variance:

  • Loose augmentation

  • Strict augmentation

Tight augmentation requires module to load synchronously (in order), while strict augmentation does not.

Tight Augmentation:
module = (function (module) {  
  module.newProp = 'bar';
  module.newMethod = () => {};
  return module;
})(module)

So it is no longer creating but instead adding.

Notice that is passes module, therefore module needs to already been initialized (otherwise it will be undefined).

I don't really know the importance of returning and reassigning the module on this pattern. I guess it's purpose is generally consistency.

Loose Augmentation:
let module = (function (module) {  
  module.newProp = 'bar';
  module.newMethod = () => {};
  return module;
})(module || {})

Loose augmentation does not requires you to provide an existing module.

Now in this case, it is important to return the module and reassign it, just in case that the module does not exist in the first place. Otherwise, no augmenting will ever takes place.

As for the expression module || {} it will returns {} when module is falsy. You can think {} as a default.

The only downside is incapability to overwrite methods.

Sub-Module

Nothing special here, creating a sub-module is as simple as creating a module:

module.subModule = (() => {  
  return {};
})()

Clean Function

I have learnt for a couple of days prior about how to write a clean function from Robert C. Martin or otherwise known as Uncle Bob.

The whole idea in my opinion always embarks on how expressive it needs to be. If your code is readable and easy to understand, then you have written a clean code.

Sometimes we as a programmer wants to show our co-workers and the readers of our code how smart we are. We tend to provide fancy ways of doing stuff. Making everything as one-liner as it can. If they can't comprehend what we have written, well, they are just plain dumb!

Uncle Bob said that this is a work of an amateur. Professional work the other way around.

Professional want their code to be expressive, understandable, and readable. It needs to be as concise and simple as much as possible!

Why? Because we work as a team, we want to ship fast avoid bugs! If you are the only person responsible for that part of code you written (because nobody understand it except you), then what happen if you leave?

Got the idea?

Let's dive in.

Naming

Naming function is critical to your program.

It should be a verb and it needs to clearly explain what is the intention of the function you are writing, so fellow programmers does not need to dive inside your function to see what it does, a glance from the name itself should be enough!

Do not present hidden implementation (side effects) that goes beyond the function name. Don't say that your function does A, but turns out it also does B.

Small

The first rule he aligns is that function has to be small! Functions needs to be two, three, or four lines long.

Do one thing

Function has to have one responsibility only! It needs to focus on one specific thing and abstract other implementation into a separate function.

Extract big function into smaller chunks, but do not over extract function if a restatement is the only effect it yields.

Sometimes it's hard to do it all from the beginning. Rule of thumb is, write all your implementation function first, then when you are finished, refactor it.

First make it work, then make it right!

Big function that polished into small abstracted steps seems to do more than one thing. It might look as follows:

function foo() {  
  doA();
  doB();
  doC();
}

This little abstractions made the function look like as if it does a lot.

So does it does one thing or three things?

One level of abstraction per function

Well, Uncle Bob state that if the statements within our functions are all at the same level of abstraction, they are definitely do "one thing".

What does it mean abstraction, anyway?

Well, each function you extract from the big function is an abstraction, because you are hiding it's implementation detail by wrapping it to a new function.

Making use of the function does not require you to know how it does it, only what it does (from the name).

So, what is level of abstraction?

appendToArray() and parseHTML() is two different level of abstraction. appendToArray() has simpler implementation therefore lower abstraction level. You certainly know how it does the way it does. Meanwhile parseHTML() is much more complex, more magic is going on, you are not entirely sure how it parse HTML.

Making sure your function has the same level of abstraction is key. One way to look level of abstraction is through LOC (lines of code) it has.

Another way is that a function and all it's extracted method should read well like a paragraph.

Here's the snippet from Clean Code book by Uncle Bob.

To include the setups and teardown, we include setups, then we include the test page content, and then we include the teardown.

To include the setups, we include the suite setup if this is a suite, then we include the regular setup.

To include the suite setup, we search the parent hierarchy for the “SuiteSetUp” page and add an include statement with the path of that page.

To search the parent. . .

Arguments

The best number of argument for a function is zero. More arguments means more confusion. You need to remember what to pass, the order of what to pass, and more testing.

Less is better.

Except, if the system you are trying to create has a natural order and requirements. For instance is a coordinate number setCoordinate(x, y).

Exceptions

Exceptions are beneficial since it's able to simplify error handling.

But handling error itself is a specific one thing of what a function does.

Uncle Bob wants you to extract your try/catch block.

function foo() {  
  try {
    doBar();
  } catch (err) {
    logError(err);
  }
}

Single Responsibility Principle

This is a brand new concept I just learnt. Having this concept in mind will generally make us able to design a more robust software architecture.

Single Responsibility Principle is deeply related to Coupling and Cohesion, which also relates to the idea of separating concerns (The separation of Concerns).

Uncle Bob states that SRP is the idea in which:

Each software modules should have one and only one reason to change.

Well, I did not grasp it instantly the first time I hear about it. Reason to change? What the heck it's suppose to mean?

Turns out it's not that complicated though. Theoretically.

Single Responsibility Principle is all about people.

Who do you think will likely to care about the method you wrote on class Foo?

Who do you think will likely to request changes on the method you wrote on class Bar?

If more than a single person or -- as stated by Uncle Bob -- a single tightly coupled group of people representing a single narrowly defined business function, it is likely that you violate Single Responsibility Principle!

For instance (example from here):

public class Employee {  
  public Money calculatePay();
  public void save();
  public String reportHours();
}

The financial department will likely to care about calculatePay() method.

The IT department will likely to care about save() method.

The operational department will likely to care about reportHours() method.

If, for instance, financial department request changes on calculatePay() and accidentally breaks reportHours(), whose fault is this!?

If each methods otherwise be separated to it's own class, this sort of accident would not have happened!

Concise Cohesion and Coupling

Cohesion and coupling is rather a common concept among programming languages. It derives several principles such as Single Responsibility Principle.

Cohesion

Cohesion simply means specific on what it's doing, or in other word, focus on one thing only!

It refers to all software entities: modules, classes, functions.

Cohesion is the degree to which elements of a whole belong together. Methods and fields in a single class and classes of a component should have high cohesion. High cohesion in classes and components results in simpler, more easily understandable code structure and design. - Robert C. Martin

Rule of thumb: high cohesion and low coupling.

But you will notice that low coupling and high cohesion are contradict to one and another. When you're trying to decouple an entity, you will find yourself having a low cohesive entity.

On classes or modules, it rather easier to identify either they are doing single or multiple things.

Low Cohesive:

public class Staff() {  
  public void checkEmail() {}
  public void sendEmail() {}
  public void emailValidate() {}
  public void printLetter() {}
}

Staff is responsible on multiple task, which violate cohesiveness.

High Cohesive:

public class Staff() {  
  private double salary;
  public void setSalary() {}
  public double getSalary() {}
  public void printLetter() {}

On a function, it's a bit tricky to see if a function is focused.

Large function that has been extracted to smaller pieces turns into function comprises set of steps.

It might seen as follows:

function foo() {  
  doA();
  doB();
  doC();
}

Clearly the function does three things.

According to Uncle Bob, we can say a function is focused if each steps contains the same level of abstraction.

What it means briefly is that the function has to be equal in terms of implementation detail! For instance, sum('2', '5') is a much lower abstraction level than renderPage(). Fastest way to notice abstraction level of a function is too see LOC (lines of code) it has. It does not matter if the next function also comprises of a set of steps as long as each steps has it's abstraction level equal to it's caller abstraction level.

So continuing the previous example, doA() might look like:

function doA() {  
  doD();
  doE();
  doF();
}

Another trick is, if you can't extract another function from it (nor extracting merely as a restatement*), then your function is focused.

*such as extracting an if statement to it's own function.

A function that receives a flag or ones which has a switch statement are likely to do a lot of things.

function receivesFlag(let isTrue) {  
  if (isTrue) {
    doSomething();
  } else {
    doSomethingElse();
  }
}
function handleCases(let case) {  
  switch(case) {
    case A: {
      doFoo();
    }
    case B: {
      doBar();
    }
  }
}

Coupling

Coupling is a concept for classes, modules, and component.

Two classes, components or modules are coupled when at least one of them uses the other. The less these items know about each other, the looser they are coupled. A component that is only loosely coupled to its environment can be more easily changed or replaced than a strongly coupled component. - Robert C. Martin

It refers to how related classes/modules and how dependent they are on each other, and the difficulty on replacing either entity.

High coupling would make your code being difficult to perform any changes (maintain) as well as being replaceable.

This is due to the fact that when you change your dependencies, it is likely that you need to update code that depends on it.

This is true for me, there are times when I import a community-driven module for my codebase, and when that module was being updated, it breaks my current code, therefore requiring my code to adapt to the latest version.

As for the replaceability issue, your code functionality depends on many of your dependencies. Changing your code functionality as a whole would be difficult without changing the dependencies itself, therefore hard to replace.

Low coupling is the preferred methodology.

Tightly coupled code experience much harder maintenance (because changing your dependencies means changing your code) and difficult to replace.

Some guy on the internet made an analogy on this using iPhone an another typical smartphone:

On an iPhone, if you ever find yourself having a broken battery, the cost to replace the battery is so expensive such that you're better to replace the entire iPhone itself, whereas on other smartphone you can easily replace it with a new battery.

Brief Note on JavaScript Promises and Async/Await

Promise has the following syntax:

new Promise((resolve, reject) => {  
  // code goes here...
});

Invoking resolve() will returns a resolved promise.

let resolvedPromise = new Promise((resolve, reject) => resolve());  

Invoking reject() will returns an rejected promise.

let resolvedPromise = new Promise((resolve, reject) => reject());  

Throwing an error inside a .then will returns a rejected promise:

  Promise.then(() => throw new Error());

.then() will be executed if prior promise resolves, returns a rejected promise if prior promise is rejected.

.catch() will be executed if prior promise rejected, returns a resolved .

An unhandled rejected promise will not stop execution context from running, and is not handled the way normal throws (in try catch block).

Async function must yield (await) a promise!

Invoking an async function will returns a promise that resolves when the async function returns (pop), resolved with the returned value from the async function itself.

async().then((resolvedVal) => console.log(resolvedVal))  

If the returned is a promise, then it will resolved when the returned promise as in:

.then(() => new Promise((res, rej) => 2))

If none is explicitly returned, then it returns undefined as the resolved value.

Async functions are generators, which means it yields, where yield is equivalent to await. And it must yield a promise.

If the yielded promise resolves, it will continue executing the async function and pass along the resolved value back to it.

If it yields a promise that is rejected, the async function will returns with a rejected promise.

I currently have no idea how a async as a generator knows when it is done internally. What I mean is:

async function a() {  
  await new Promise((resolve, reject) => resolve());
  console.log('foo');
}
a().then((res) => console.log('bar'));  

This will outputs foo and bar respectively.

I was thinking that when it yields an object where .done() is true, then the async function will resolved, but apparently that is not the case.

Contributing to Open Source

I've learn from a couple of articles & tips here and there might help you to contribute to open source as well:

A tip from Dan Abramov:

Open source tip: you’ll learn A LOT from taking a single project you actively use, “watching” it on GitHub and reading every issue and PR.

It won’t make a lot of sense at first but stick with it.

JavaScript Design Pattern

Pattern is something I heard a lot in the developer community. Might be awesome to get some deeper insight what it actually is.

Without further ado, lets dive together on learning Design Patterns! I'll be using Addy Osmani's book, Learning JavaScript Design Patterns*, as a reference.

What is a Pattern, anyway?

Patterns are proven approach on solving over a recurring problems we might encounter during code production.

It matters because it has been tested over and over again on lots of scenarios.

Rather than having to write our own approach only to realize that it's not working as you might expected. Not saying that you shouldn't, but it would be wiser in terms of efficiency and effectivity to use an existing pattern.

Addy Osmani state the following advantages of pattern on his book, JavaScript Design Patterns:

  • Preventing minor issues (edge cases).

  • Applicable to lots of scenarios (not tied to a specific problem).

  • May decrease file size by reducing repetition also known as DRY (don't repeat yourself).

  • Add to a developer's vocabulary.

  • Improved over time through collective experience.

Know It's Brother

Design Pattern has it's opposite, named anti-pattern.

Well, as you might guess, it is a pattern that sucks!

Apparently it has been known for quite some time that using an anti-pattern leads to destruction.

So it might be better to just avoid it.

An example of anti-pattern is using document.write due it's capability to overwrite your whole document. Disaster indeed.

Patterns Into Sections

Patterns generally divided into three major classifications:

  • Creational

  • Structural

  • Behavioral

Take a closer look of the following image (taken from Slideshare):
JavaScript Design Pattern

I'll be covering each and every one of these into several blog posts.

Pattern Table of Content

JavaScript Constructor Pattern

There are 3 ways to create an object in JavaScript:

let object1 = {};

let object2 = Object.create(Object.prototype);

let object3 = new Object({key: val, ... });  

The first option is an object literal where basically is a key-value pair.

The second lets you specify the prototype for the object you're trying to create. You'll able to see it by accessing object2.__proto__. You'll need to specify the prototype or otherwise it will throws.

Remember that every object inherits Object.prototype by default.

So for instance, object1.__proto__ will be equivalent to Object.prototype without be obliged to specify the prototype by yourself. But for the second option, you'll be needing to sepcify Object.prototype by yourself.

The following achieve the same result as the third option:

Object({key: val, ... });  
Accessing and Mutating Props

You'll mainly use either dot notation . or a bracket notation [].

For setting/assigning a new property, you can also use Object.defineProperty(), by the following syntax:

Object.defineProperty(obj, prop, descriptor)  

There are two type of descriptor, you can only choose either of these, otherwise it will throws.

  • data descriptor
  • accessor descriptor

Both have the following key:

  • configurable: are the descriptor mutable?
  • enumerable: will the property shows up during enumeration (for ... in and Object.keys).

For data descriptor:

  • value: well, the value for the property.
  • writable: is the property mutable?

Ex:

Object.defineProperty(obj, 'awesomeKey', {  
  enumerable: false,
  configurable: false,
  writable: false,
  value: 'Some random awesome value'
});

There are defaults for every of these descriptor keys, so you don't have to explicitly specify for each.

But if you don't, there is a possibility where the options are inherited from the prototype chain. I'm not really sure about this, though...

For accessor:

  • get
  • set

Both get and set are function that will be executed when you either assign or access the corresponding key. For instance:

let Cat = {};  
Object.defineProperty(Cat, 'age', {  
    get: function() {
      return this.age || 10;
    },
    set: function(value) {
      this.age = value;
    }
  });

console.log(Cat.age); // returns 10  
Cat.age = 12;  
console.log(Cat.age); //returns 12