Classical Inheritance vs Modular Patterns



Classical Inheritance vs Modular Patterns

0 2


Classical-Inheritance-vs-Modular-Patterns

Slides from my conference on Classical Inheritance, Prototypical Inheritance and Modular Patterns at Itnig, Barcelona.

On Github fmvilas / Classical-Inheritance-vs-Modular-Patterns

Classical Inheritance vs Modular Patterns

Yes! In Javascript!

Ola! Ke ase!

Today i'll speak about:

  • Software Design Patterns (an overview)
  • Classical Inheritance
  • Prototypical Inheritance
  • Modular Patterns

So, let's start!

Software Design Patterns

(an overview)

A design pattern is a general reusable solution to a commonly occurring problem within a given context in software design.
- Wikipedia

Software Design Patterns

(an overview)

Usually, patterns are grouped by:

  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns
  • Concurrency Patterns

Software Design Patterns

(an overview)

Creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to the design. Creational design patterns solve this problem by somehow controlling this object creation.

Software Design Patterns

(an overview)

Some examples of creational patterns are:

  • Abstract Factory Pattern
  • Factory Method Pattern
  • Prototype Pattern
  • Singleton Pattern

Software Design Patterns

(an overview)

var vehicle = {
  getModel: function () {
    console.log( "The model of this vehicle is.." + this.model );
  }
};
 
var car = Object.create(vehicle, {
  "id": {
    value: MY_GLOBAL.nextId(),    
    enumerable: true // writable:false, configurable:false by default
  },
 
  "model": {
    value: "Ford",
    enumerable: true
  }
});
                        

Prototype Pattern in JavaScript - Code example extracted from Addy Osmani's Learning JavaScript Design Patterns book.

Software Design Patterns

(an overview)

Structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities (i.e. classes or objects).

Software Design Patterns

(an overview)

Some examples of structural patterns are:

  • Adapter Pattern
  • Composite Pattern
  • Facade Pattern
  • Decorator Pattern

Software Design Patterns

(an overview)

var myModule = (function() {
    
    var _queryDOM = function() {
        // your code here
    };

    var _renderMap = function() {
        google.maps.render();
    };

    return {
        queryDOM: _queryDOM,
        renderMap: _renderMap
    };

})();

myModule.renderMap();
                        

Software Design Patterns

(an overview)

Behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication.

Software Design Patterns

(an overview)

Some examples of behavioral patterns are:

  • Chain of Responsibility Pattern
  • Observer a.k.a. Publish/Subscribe Pattern
  • Mediator Pattern
  • Memento Pattern

Software Design Patterns

(an overview)

var myModule = function() {
    ...
    Observer.observe('dom.element.select', function(el) {
        console.log('Element %s was selected.', el.getAttribute('id'));
    });
    ...
};

var anotherModule = function() {
    ...
    Observer.publish('dom.element.select', document.getElementById('anId'));
    ...
};
                        

Software Design Patterns

(an overview)

Concurrency design patterns are those types of design patterns that deal with the multi-threaded programming paradigm.

Software Design Patterns

(an overview)

Some examples of behavioral patterns are:

  • Active Object Pattern
  • Monitor Object Pattern
  • Scheduler Pattern
  • Reactor Pattern

This is the one used by Node.js.

Classical Inheritance

Classical Inheritance

The Big Win

Why classical inheritance succeeded that way?

  • It's easy to understand. But, why?
  • Because you can solve problems by comparing them with daily life. Think about it!
  • Classes are like molds to create objects. And these objects have properties, can make actions (methods) and things can happen to them (events).
  • It's simply that! Just like real objects!
  • Well, not just like that but this way of thinking covers 90% of object oriented programming.

Classical Inheritance

The Big Win

...and then you think: "That's pretty nice Fran, but the slide title says Classical Inheritance!"

Classical Inheritance

The Big Win

No, really. We all know how inheritance works.

You inherit properties from your parents.

But you don't make actions nor you react in a concrete way because you inherit it.

So, okay, it's not exactly as real life. It's even better.

But, wait! Are these things exclusive for classical inheritance?

NO

It's object oriented programming.

Classical Inheritance

JavaScript

But OOP is not only made of classical inheritance!

Remember the creational patterns?

We also have Prototypical Inheritance (Prototype Pattern).

And now is when JavaScript comes to the scene.

Classical Inheritance

JavaScript

JavaScript is an object oriented language but not a Class-based object oriented language.

It's a Prototype-based object oriented language.

Classical Inheritance

JavaScript

It means that there are no classes in JavaScript.

Everything is an object and objects have prototypes which, at the same time are objects.

WTF!

Classical Inheritance

JavaScript

That's it! You can simulate classes with Function's objects but they are not, and the primary evidence is that you can modify these "classes" at runtime, which is completely the opposite to the definition of a Class.

Prototypical Inheritance

JavaScript

What we have in JavaScript is Prototypical Inheritance.

Let's see an example!

Prototypical Inheritance

var Animal = {
    bornIn: Date.now,
    
    eat: function() {
        console.log('Eating...');
    }
};

var Dog = function() {
    this.bark = function() {
        console.log('Guau!');
    };

    this.bornIn = new Date(this.bornIn());
};

Dog.prototype = Animal;

var myDog = new Dog();

myDog.eat(); // Outputs: Eating...
myDog.bark(); // Outputs: Guau!
console.log(myDog.bornIn); // Outputs something like: Tue Jun 17...
                        

Prototypical Inheritance

Let's explain it step by step.

var Animal = {
    bornIn: Date.now, // That's a reference to the built-in function
    
    eat: function() {
        console.log('Eating...');
    }
};

...
                            

Animal will have two functions, bornIn() and eat().

Prototypical Inheritance

...
var Dog = function() {
    // Here, "this" will point to the newly created instance,
    // not to Dog itself.
    this.bark = function() {
        console.log('Guau!');
    };

    // That's called 'property shadowing'
    this.bornIn = new Date(this.bornIn());
};
...
                            

Notice the "this.bornIn = ..." line. At the time of creating a Dog instance, this.bornIn refers to Animal.bornIn but, after this line, it will be "hidden" with an own property with the same name. We can still have a reference to Animal.bornIn through Dog.prototype.bornIn.

Prototypical Inheritance

Dog.prototype = Animal;
                            

That's the key part. Here we are telling to JavaScript that, when creating a new Dog, our instance should have a reference to the properties and methods of Animal. But how?

By inspecting the prototype chain.

Proto... WHAAAT?

Let's continue with the example.

Prototypical Inheritance

var myDog = new Dog();
                            

Here we are creating an instance of a Dog. Let's dig inside the resulting object.

// console.dir(myDog);
{
    bark: function () { ... }
    bornIn: Tue Jun 1... // A Date instance
    __proto__: Object
}
                    

Where is the eat function? In the __proto__ object.

Here, __proto__, is a reference to the Animal object, and JavaScript looks into it to search for inherited members, such as the eat function.

Prototypical Inheritance

// console.dir(myDog);
{
    bark: function () { ... },
    bornIn: Tue Jun 1..., // Our own bornIn function
    __proto__: {
        bornIn: function now() { [native code] },
        eat: function () { ... },
        __proto__: Object
    }
}
                    

Because of this we can do something like myDog.eat().

And notice the two bornIn functions. The second one is the Animal.bornIn function.

And also notice the second __proto__. It's a reference to the native Object.prototype.

Prototypical Inheritance

// console.dir(myDog);
{
    bark: function () { ... },
    bornIn: Tue Jun 1..., // Our own bornIn function
    __proto__: {
        bornIn: function now() { [native code] },
        eat: function () { ... },
        __proto__: Object
    }
}
                    

So, the prototype chain looks like this:

Dog --> Animal --> Object --> null

Yes, an instance of a native Object has no prototype because it's the first one in the chain. And, if you check for the __proto__ property, it exists, but you will get a null value.

Prototypical Inheritance

Performance

Now that you know how inheritance works in JavaScript, you must take care of the prototype chain, because it's as powerful as dangerous.

Try to not make large chains. It will give your app a better performance.

Prototypical Inheritance

Why we should not imitate Classical Inheritance in Javascript?

I know it's hard, because almost all developers come from Class-based languages, but I guarantee you that using prototypes will give you more power and flexibility while developing.

Prototypes are dynamic, Classes are static. Prototypes can change during runtime but it could also be a problem if you don't develop carefully.

But the main reason to don't use classes is that JavaScript doesn't have Classes and trying to imitate it will cause a loss of performance and you will also lose the good parts of using prototypes.

Modular Patterns

AMD, CommonJS, etc.

Modular Patterns

Introduction

In a short, Modular Patterns dictates how to structure our code, namely in modules that are reusable pieces and let us develop loose coupled applications.

In JavaScript there are, primarily, 3 modular patterns definitions:

  • AMD (Asyncrhonous Module Definition)
  • CommonJS
  • ES Harmony

Modular Patterns

Introduction

It's important to note that, in the current iteration of JavaScript (ECMA-262), it's impossible to define modules without the need of a script loader.

Fortunately, the next version, JavaScript Harmony is coming and it's already available in some environments, such as Node.js.

In the meantime we can use nice script loader libraries like RequireJS and curl.js.

Modular Patterns

Lego

I always recommend to start thinking in modules as Lego pieces.

By themselves, they are so simple but, by combining them, you can create amazing things.

Modular Patterns

Facade

Remember the Facade pattern?

It defines the way the pieces connect each other.

And by controlling it we can maintain our application loose-coupled.

Modular Patterns

Loose Coupling

What are the benefits of loose-coupling?

You can easily reuse your modules everywhere in the application or even outside it.

If a module changes or crashes, the application could continue working and you only lose the features of these modules.

And testing! It's easier to test a simple module than testing the whole application.

Modular Patterns

Loose Coupling

How modular patterns help with this?

We remove unnecessary dependecies.

The truly needed dependencies are well defined and, if you don't define them, your code will not work.

We can use optimizers like r.js to maintain it clean and controlled.

We can have different versions of the same module running in our application. Say, i.e. some module needs jQuery 1.x and another one needs jQuery 2.x.

Modular Patterns

Communicating Modules

Remember the Observer pattern?

By subscribing and publishing messages we can have our application decoupled and well communicated.

Messages are like events, but the difference is that events are attached to objects while messages are not. They can live on their own.

Modular Patterns

Is Classical Inheritance dead?

Of course not.

Classical Inheritance, or its emulation in JS, has its own niche. Sometimes the application performance is not critical and you can benefit from the expertise about Class-based thinking of your team.

Modular Patterns

Is Classical Inheritance dead?

Are Modular Patterns and Classical Inheritance compatible?

Yes, they are!

Is this architecture the best way of structuring your app?

The answer is: "It depends".

Depends on your app needs.

Modular Patterns

Is Classical Inheritance dead?

Module Patterns define a way to organize your code but, it's important to note that inside a module you can create objects, or define multiple "classes" or just create a "class" inheriting from another one defined in another module.

What I want to emphasize is that it's not a battle between Classical Inheritance and Module Patterns. They don't play in the same league.

So, after all...

Classical Inheritance vs Modular Patterns

Classical Inheritance and Modular Patterns

Hope you liked it!

Thank you!