Building Large Scale Javascript Application

Post on 27-Aug-2014

1082 Views

Category:

Software

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

In recent years a number of libraries for building large JavaScript applications has appeared. As we no longer need to battle DOM differences between browsers we can finally focus on building highly interactive front-end applications instead. But before we can do a good job with these new libraries we need unlearn our previous DOM-centric approach and need to be aware of good practices and patterns of developing modern javascript app. It will start with jQuery based old style practices and try to discuss on how can we approach to a modular, decoupled, scalable application architecture. This slide was prepared in very short time for technical session series of Digital World 2014 (http://www.digitalworld.org.bd/technical-session). The event video is here - https://www.youtube.com/watch?v=Gpw7l27MUUc (slide was not properly covered in video). It has taken inspiration, ideas (, even some contents) from the following sources - * http://addyosmani.com/largescalejavascript/ * http://addyosmani.com/resources/essentialjsdesignpatterns/book/ * https://www.youtube.com/watch?v=vXjVFPosQHw * https://www.youtube.com/watch?v=qWr7x9wk6_c * https://speakerdeck.com/kimjoar/patterns-of-large-scale-javascript-applications-1

Transcript

Building Large ScaleJavascript Application

It's a little different than traditional JS

Who are the target audience?What is Javascript?

I use JS to do form validation

Javascript is the interactive tool that I use for user intraction

I write the full app in JS

What do we actually mean by Large Scale JavascriptApplication?

Large in size?

Large in complexity?

Large in developer count?

Why do we care?The ability of browsers have increased

The load on the client, rather than on the server

High level of interaction

What is the secret of building BIG things?

Aircrafts are amazing architecture!

How they made this crazy huge thing?

The secret to building large apps is never build largeapps. Break up your applications into small pieces.

Then, assemble those testable, bite-sized pieces intoyour big– Justin Meyer

Okay, Let's startAs we generally start

We have a good main.js

function somethingGood() {    // Good code}

// few other functions ...

$( document ).ready(function() {    $('#aButton').onClick(function(e) {        // Do something    });

    // few event bindings ...});        

But at the end, it become bad!

function somethingGood() {    // ## Bad code, full of mess ##}

// 39 strange functions with 40% repetation

$( document ).ready(function() {    $('#aButton').onClick(function(e) {        // Do something ## became 60 lines! ##    });

    // ## 33 bindings ## , some event may bound multiple times});        

Let's break them down

Files++

Filesize--

Lots of files...

Let’s Organise them

By feature By Layer

By feature By Layer

Lets call them Modules

Okay, but...

What is a Module?

My Yahoo!

Modules made it!

Modules are (preferably) small, focused, purposefulportion of code that -

Modules ... portion of code that -

Provides a specific feature

Modules ... portion of code that -

Contains business logic

Modules ... portion of code that -

Is decoupled (from other modules)

Modules ... portion of code that -

Is reusable (context matters)

Modules ... portion of code that -

Is testable

A simple module looks like -

var MyModule = ( function( window, $ ) {  function aPrivateMethod() {    $('catchSomething').load('http://...');  }

  function myPublicMethod() {    privateMethod();    alert( 'my other method' );  }

  // explicitly return public methods when this object is instantiated  return {    someMethod : myPublicMethod  };} )( window, jQuery );        

Module rules

Module Rule #1

Never access the DOM outside the module

Module Rule #2

Don't Create Global variables

Module Rule #3

Don’t Access Non-Native, Global objects

Module Rule #4

Inject Dependencies

Module Communationwith other modules

Mediator PatternMediators are used when the communication between modules may be complex, but is still

well defined.

Mediators and Modules

Mediator publish/subscribe example

// example subscriber functionvar Subscriber = function ExampleSubscriber( myVariable ) {  console.log( myVariable );};

// example usagesvar myMediator = new Mediator();myMediator.subscribe( 'some event', Subscriber );myMediator.publish( 'some event', 'foo bar' ); // console logs "foo bar"        

Well defined Interfacing

Dependencies

Dependency on other code/Globals

Dependency on other files

Dependency on third party libraries

$('#my‐button').click(function() {    $.get('https://api.github.com', function(data) {        $('#res').html(data.emojis_url);    });});        

Closure cannot be reused

Closure cannot be tested

$.get and $('#res') using global object

var downloadEmojis = function() {    $.get('https://api.github.com', function(data) {        $('#res').html(data.emojis_url);    });};

$('#my‐button').click(downloadEmojis);        

Difficult to test

$.get and $('#res') using global object

var downloadEmojis = function(ajax, $el) {    ajax.get('https://api.github.com', function(data) {        $el.html(data.emojis_url);    });};

$('#my‐button').click(function() {    downloadEmojis($, $('#res'));});        

Now we can controle dependencies :)

Dependency on other files/Modules

Scripts behind this presentation

<script src="bower_components/bespoke.js/dist/bespoke.min.js"></script><script src="bower_components/bespoke‐keys/dist/bespoke‐keys.min.js"></script><script src="bower_components/bespoke‐touch/dist/bespoke‐touch.min.js"></script><script src="bower_components/bespoke‐bullets/dist/bespoke‐bullets.min.js"></script><script src="bower_components/bespoke‐scale/dist/bespoke‐scale.min.js"></script><script src="bower_components/bespoke‐hash/dist/bespoke‐hash.min.js"></script><script src="bower_components/bespoke‐progress/dist/bespoke‐progress.min.js"></script><script src="bower_components/bespoke‐state/dist/bespoke‐state.min.js"></script><script src="bower_components/prism/prism.js"></script><script src="bower_components/prism/components/prism‐php.min.js"></script><script src="scripts/main.js"></script>    

How can we make it better?

AMD

COMMON.JS

Let's see a little bit more about AMDUsing require.js

Using require.js

Include Require JS

<script data‐main="scripts/main" src="scripts/require.js"></script>

Using require.js

Configure Paths

require.config({    baseUrl: 'js/lib',    paths: {        jquery: 'jquery‐1.9.0'        parse : 'parse‐1.2.18.min',        underscore: 'underscore',        backbone: 'backbone',        marionette: 'backbone.marionette'    }});

Using require.js

Define modules

define([    'app',    'marionette'], function(app, Marionette){

    return ExampleModule = app.module("Example", function(Example) {        this.startWithParent = false;

        this.addInitializer(function(){            console.log('Module:Example => initialized');            this.router = new Router({ controller: Controller });        });    });});

Asynchronous loading

On demand script loading

 if(teamProfile) {    // Load and show team profile    require(['views/TeamProfileView'], function(TeamProfileView) {        var teamInfo = { model : app.reqres.request('core:team', shortName) }        app.main.show(new TeamProfileView(teamInfo));    });}            

Dependency on third party libraries

http://bower.io/

list dependencies in bower.json

// bower.json{    "dependencies": {        "angular": "~1.0.7",        "angular‐resource": "~1.0.7",        "jquery": "1.9.1"} }

MV* Frameworks

Seperation between Data and DOMM → Data | V → DOM | * → has many variations

MVCController → Mediates inputs and manipulates the model

MVPPresenter → all presentation logic is pushed to the presenter

MVVMViewModel → exposes model so it can be easily managed and consumed

How to select the right one?Why they are this huge in nymbers? :(

Same todo app built around 70 times with different frameworks and approaches

Let's see how BackboneJS did it

Todo Model

(function () {    app.Todo = Backbone.Model.extend({        // and ensure that each todo created has title and completed keys.        defaults: {            title: '',            completed: false        },

        toggle: function () {            this.save({                completed: !this.get('completed')            });        }    });})();

Create a Todo

var todo = new app.Todo({  title: "Do something good!"});

What about list of Todos?

var Todos = Backbone.Collection.extend({        model: app.Todo,

        // Filter down the list of all todo items that are finished.        completed: function () {            return this.filter(function (todo) {                return todo.get('completed');            });        },

        // Many other functions related to list ...    });

Collections

Create a Todo list

var todoList = new Todos(    {title: 'Do something good'},    {title: 'Another Task'},    {title: 'This task is Done', completed: true},);            

Who will create them actually?

collection.fetch(); // Pulls list of items from servercollection.create(); // Create new item in list

// Sync a modelmodel.fetch(); // Fetch an item from servermodel.save(); // Save changes to modelmodel.destroy(); // Delete a model            

Template

<script type="text/template" id="item‐template">    <div class="view">        <input class="toggle" type="checkbox" <%= completed ? 'checked' : '' %>>        <label><%= title %></label>        <button class="destroy"></button>    </div>    <input class="edit" value="<%‐ title %>"></script>            

The DOM to render models or collection

Views

app.TodoView = Backbone.View.extend({    tagName:  'li',    template: _.template($('#item‐template').html()),

    initialize: function () {        this.listenTo(this.model, 'change', this.render);        this.listenTo(this.model, 'visible', this.toggleVisible);    },

    render: function () {        this.$el.html(this.template(this.model.toJSON()));        return this;    }});            

Takes models, Render them, listning to events

Views cont.

events: {    'click .toggle': 'toggleCompleted',    'dblclick label': 'edit'},

toggleCompleted: function () {    this.model.toggle();},

edit: function () {    this.$el.addClass('editing');    this.$input.focus();},        

Handling to DOM events and manipulate model

Routers

var TodoRouter = Backbone.Router.extend({        routes: {            '*filter': 'setFilter',            'url/pattern': 'handlerFunction'            'url/pattern/:param': 'handlerFunction'        },

        setFilter: function (param) {            // Trigger a collection filter event            app.todos.trigger('filter');        }    });        

Handles the routing with url changes

Start listning to url changes

app.TodoRouter = new TodoRouter();Backbone.history.start();    

Url change? reload?... NO

http://the/app/url.com#a‐routehttp://the/app/url.com#another‐routehttp://the/app/url.com#a‐route/withParam/23    

No more todayIt was a lot of things... ain't it?

Wait... Do I really need aaall of these?Well, depends on your apps requirement

Resource

http://superherojs.com/

About us

[    {        "name": "Mohammad Emran Hasan",        "mail": "phpfour@gmail.com",        "blog": "http://emranhasan.com"    },    {        "name": "Anis Uddin Ahmad",        "mail": "anisniit@gmail.com",        "blog": "http://ajaxray.com"    }]          

Questions?

top related