Examples of Inversion of Control

In the post Inversion of Control (IoC), I described what was. Here I describe several examples of Inversion of Control.

Dependency Injection

When creating a class or module, it is good practice to reduce concrete dependencies when possible (Dependency Inversion Principle) . Concrete means having a hard dependency on another piece of code rather than a dependency on an abstraction.

This can be illustrated by defining a class. For example, a BillingForm may depend on a PaymentProcessor:

class BillingForm {
  constructor() {
    this.processor = new PaymentProcessor();
  }
  processForm(...) {
    this.processor.process(...);
  }
}

Contrast above with the following example where the dependency is added as an argument when constructing a BillingForm instance.

class BillingForm {
  constructor(paymentProcessor) {
    this.processor = paymentProcessor;
  }
  processForm(...) {
    this.processor.process(...);
  }
}
const paymentProcessor = new PaymentProcessor();
const billingForm = new BillingForm(paymentProcessor);

This is an example of IoC because the control of when a dependency is added is controlled by when the BillingForm is instantiated rather than immediately during the BillingForm instantiation.

React Lifecycle Methods

The Javascript frontend framework React.js has component lifecycle methods for components. Examples like componentWillMount, componentDidMount, and componentWillUnmount are defined in a component. These methods can be overridden by a component. The methods are then called at the appropriate time by the React.js framework.

Other examples includes: Command Line Interface, Javascript callbacks, Route Handlers, Object oriented class frameworks, and User Interfaces

Inversion of Control

Inversion of Control (IoC) is usually foundin programming, but it is a general concept. The concept relates to a program’s flow of control.

A program’s flow of control can be thought of as the direction a program executes. The simplest illustration of this is top-to-bottom line-by-line execution of a program.

console.log(1); 
console.log(2); 
console.log(3);

The numbers 1, 2, 3 will be logged into the console in this order. The written program has control of what and when the numbers are shown.

Contrast the above example with:

document.querySelector('.button-1')
.addEventListener('click', function(e) {
  console.log(1);
});
document.querySelector('.button-2')
.addEventListener('click', function(e) {
  console.log(2);
});

This code add event listeners to 2 buttons button-1 and button-2. The program describes what will happen (logging a number), but it has left when to the browser which in turn leaves it to the user of the browser. It is said that the control has been inverted away from the application/program (the code which defines the number logging) to the framework (the browser)

The word “framework” is an abstract and necessary concept when dealing with IoC since it would decide when certain methods shall be called.

To read more, check out Examples of Inversion of Control

The difference between -> and => in CoffeeScript

I had this following code:

@collection.each (post) ->
  $(@el).append @template(post.attributes)
@

I was running in an issue where @el and @template were returning Uncaught TypeError: undefined is not a function. I even created a StackOverflow question about it.

I got the template to render by using jQuery directly like so,

$('#posts').append _template.( $('#home-post-template').html() ).

So this told me that the el or template was not within the scope of the each function. I remembered I was originally referencing one of Buzzstarter’s Backbone files and I had => instead of the -> I had now. Just trying things, I switched out -> for =>. Now it was working. Of course I couldn’t switch it out without understanding why it made a difference. So to the CoffeeScript documentation about the fat-arrow. It basically passes another function passing the outer context of this into an argument. This can be better illustrated with the conversion of CoffeeScript to normal Javascript

Old CoffeeScript

    @collection.each (post) ->
      $(@el).append(@template(post.attributes))
    @

Javascript Equivalent

    this.collection.each(function(post) {
      return $(this.el).append(this.template(post.attributes));
    });
    return this;

New CoffeeScript

    @collection.each (post) =>
      $(@el).append(@template(post.attributes))
    @

Javascript Equivalent

    this.collection.each((function(_this) {
      return function(post) {
        return $(_this.el).append(_this.template(post.attributes));
      };
    })(this));
    return this;

Once I saw the Javascript of the CoffeeScript with =>, it was painfully obvious what I was doing wrong and how => solved the problem. This error was due to my unfamiliarity to CoffeeScript, but Js2Coffee is quite useful in learning the differences.