Building Large Scale Javascript Application

14,624 views

Published on

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

Published in: Software, Technology

Building Large Scale Javascript Application

  1. 1. Building Large Scale Javascript Application It's a little different than traditional JS
  2. 2. 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
  3. 3. What do we actually mean by Large Scale Javascript Application? Large in size? Large in complexity? Large in developer count?
  4. 4. Why do we care? The ability of browsers have increased The load on the client, rather than on the server High level of interaction
  5. 5. What is the secret of building BIG things?
  6. 6. Aircrafts are amazing architecture!
  7. 7. How they made this crazy huge thing?
  8. 8. The secret to building large apps is never build large apps. Break up your applications into small pieces. Then, assemble those testable, bite-sized pieces into your big – Justin Meyer
  9. 9. Okay, Let's start As we generally start
  10. 10. 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 ... });         
  11. 11. 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 });         
  12. 12. Let's break them down Files++ Filesize--
  13. 13. Lots of files... Let’s Organise them
  14. 14. By feature By Layer
  15. 15. By feature By Layer
  16. 16. Lets call them Modules
  17. 17. Okay, but... What is a Module?
  18. 18. My Yahoo!
  19. 19. Modules made it!
  20. 20. Modules are (preferably) small, focused, purposeful portion of code that -
  21. 21. Modules ... portion of code that - Provides a specific feature
  22. 22. Modules ... portion of code that - Contains business logic
  23. 23. Modules ... portion of code that - Is decoupled (from other modules)
  24. 24. Modules ... portion of code that - Is reusable (context matters)
  25. 25. Modules ... portion of code that - Is testable
  26. 26. 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 );         
  27. 27. Module rules
  28. 28. Module Rule #1 Never access the DOM outside the module
  29. 29. Module Rule #2 Don't Create Global variables
  30. 30. Module Rule #3 Don’t Access Non-Native, Global objects
  31. 31. Module Rule #4 Inject Dependencies
  32. 32. Module Communation with other modules
  33. 33. Mediator Pattern Mediators are used when the communication between modules may be complex, but is still well defined.
  34. 34. Mediators and Modules
  35. 35. Mediator publish/subscribe example // example subscriber function var Subscriber = function ExampleSubscriber( myVariable ) {   console.log( myVariable ); }; // example usages var myMediator = new Mediator(); myMediator.subscribe( 'some event', Subscriber ); myMediator.publish( 'some event', 'foo bar' ); // console logs "foo bar"         
  36. 36. Well defined Interfacing
  37. 37. Dependencies Dependency on other code/Globals Dependency on other files Dependency on third party libraries
  38. 38. $('#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
  39. 39. 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
  40. 40. 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 :)
  41. 41. Dependency on other files/Modules
  42. 42. 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>     
  43. 43. How can we make it better? AMD COMMON.JS
  44. 44. Let's see a little bit more about AMD Using require.js
  45. 45. Using require.js Include Require JS <script data‐main="scripts/main" src="scripts/require.js"></script>
  46. 46. 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'     } });
  47. 47. 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 });         });     }); });
  48. 48. Asynchronous loading
  49. 49. 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));     }); }             
  50. 50. Dependency on third party libraries
  51. 51. http://bower.io/
  52. 52. list dependencies in bower.json // bower.json {     "dependencies": {         "angular": "~1.0.7",         "angular‐resource": "~1.0.7",         "jquery": "1.9.1" } }
  53. 53. MV* Frameworks
  54. 54. Seperation between Data and DOM M → Data | V → DOM | * → has many variations
  55. 55. MVC Controller → Mediates inputs and manipulates the model
  56. 56. MVP Presenter → all presentation logic is pushed to the presenter
  57. 57. MVVM ViewModel → exposes model so it can be easily managed and consumed
  58. 58. How to select the right one? Why they are this huge in nymbers? :(
  59. 59. Same todo app built around 70 times with different frameworks and approaches
  60. 60. Let's see how BackboneJS did it
  61. 61. 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')             });         }     }); })();
  62. 62. Create a Todo var todo = new app.Todo({   title: "Do something good!" });
  63. 63. 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
  64. 64. Create a Todo list var todoList = new Todos(     {title: 'Do something good'},     {title: 'Another Task'},     {title: 'This task is Done', completed: true}, );             
  65. 65. Who will create them actually? collection.fetch(); // Pulls list of items from server collection.create(); // Create new item in list // Sync a model model.fetch(); // Fetch an item from server model.save(); // Save changes to model model.destroy(); // Delete a model             
  66. 66. 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
  67. 67. 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
  68. 68. 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
  69. 69. 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
  70. 70. Start listning to url changes app.TodoRouter = new TodoRouter(); Backbone.history.start();     
  71. 71. Url change? reload?... NO http://the/app/url.com#a‐route http://the/app/url.com#another‐route http://the/app/url.com#a‐route/withParam/23     
  72. 72. No more today It was a lot of things... ain't it?
  73. 73. Wait... Do I really need aaall of these? Well, depends on your apps requirement
  74. 74. Resource http://superherojs.com/
  75. 75. 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"     } ]           
  76. 76. Questions?

×