Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Patterns of Large-Scale JavaScript Applications

Patterns of Large-Scale JavaScript Applications

JavaScript has come a long way in few years. As we no longer need to battle DOM differences we can focus on building our applications instead. Now, however, as more and more application logic move from the server to the client our main problem is that we need to unlearn our earlier DOM-centric approach to JavaScript. Tools such as Backbone and Angular help, but before we are able to use the effectively we have to change some of our neural pathways. In this talk I will look at a couple of patterns that will help you move away from jQuery spaghetti and get you started on a foundation for building large-scale JavaScript applications.

Kim Joar Bekkelund

June 12, 2013
Tweet

More Decks by Kim Joar Bekkelund

Other Decks in Programming

Transcript

  1. $

  2. jQuery(document).ready(function() { $(".user form").submit(function(e) { e.preventDefault(); $.ajax({ // ... success:

    function(data) { var name = data.name || "Unknown"; $(".user .info").append("<h1>" + name + "</h1>"); } }) }); });
  3. jQuery(document).ready(function() { $(".user form").submit(function(e) { e.preventDefault(); $.ajax({ // ... success:

    function(data) { var name = data.name || "Unknown"; $(".user .info").append("<h1>" + name + "</h1>"); } }) }); }); Page event User event Network I/O Network event Parsing response Templating Callback hell https://speakerdeck.com/bkeepers/the-plight-of-pinocchio
  4. we need to unlearn our DOM-centric approach The DOM is

    Inherently global and stateful hard to test and maintain
  5. we need to unlearn how we write JavaScript No more

    5k lines of code in a single file Watch out for global variables Learn from the backend
  6. we need to unlearn how we use jQuery “Our experience

    is that, when code is difficult to test, the most likely cause is that our design needs improving.” – Growing Object-Oriented Software, Guided by Tests
  7. – Justin Meyer “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 application.”
  8. MVC

  9. MV*

  10. “I hereby declare AngularJS to be MVW framework – Model-View-Whatever.

    Where Whatever stands for ‘whatever works for you’.” – Igor Minar
  11. “Actually how you partition your code has a lot to

    do with how you organize your project source code and how much easier it is to maintain as your project grows.” – Jim Lavin
  12. “A system is easier to change if its objects are

    context-independent; that is, if each object has no built-in knowledge about the system in which it executes.” – Growing Object-Oriented Software, Guided by Tests
  13. Module rules Never access the DOM outside the module Don’t

    create global variables http://www.slideshare.net/nzakas/scalable-javascript-application-architecture-2012
  14. Module rules Never access the DOM outside the module Don’t

    create global variables Don’t access global, non-native objects http://www.slideshare.net/nzakas/scalable-javascript-application-architecture-2012
  15. We depend on other code dependencies We depend on other

    files We depend on Third-party libraries
  16. We usually depend far too much on globals JavaScript makes

    this really easy We depend on other code
  17. 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 control the dependencies
  18. var UserView = function(el, user) { this.el = el; this.user

    = user; }; // let's just create a super simple user object var user = { image: 'http://example.com/image.png' }; // initialize with the element the view owns and a user var view = new UserView($('.user'), user);
  19. var UserView = function(el, user) { this.el = el; this.user

    = user; }; UserView.prototype.showImage = function() { this.el.append('<img src=' + this.user.image + '>'); }; // let's just create a super simple user object var user = { image: 'http://example.com/image.png' }; // initialize with the element the view owns and a user var view = new UserView($('.user'), user);
  20. var UserView = function(el, user) { this.el = el; this.user

    = user; }; UserView.prototype.showImage = function() { this.el.append('<img src=' + this.user.image + '>'); }; // let's just create a super simple user object var user = { image: 'http://example.com/image.png' }; // initialize with the element the view owns and a user var view = new UserView($('.user'), user); // ... and now we can do stuff which changes the DOM view.showImage();
  21. var MyController = function($scope, $http) { $http.get('https://api.github.com') .success(function(data) { $scope.emojis_url

    = data.emojis_url; }); } the ordering of these does not matter An example using AngularJS
  22. var MyController = function($http, $scope) { $http.get('https://api.github.com') .success(function(data) { $scope.emojis_url

    = data.emojis_url; }); } the ordering of these does not matter An example using AngularJS
  23. // Create an AngularJS module with no dependencies var ndc

    = angular.module('ndc', []); // Register a function ndc.factory('awesome', function() { return 'awesome conference'; });
  24. // Create an AngularJS module with no dependencies var ndc

    = angular.module('ndc', []); // Register a function ndc.factory('awesome', function() { return 'awesome conference'; }); // Get the injector (happens behind the scenes in AngularJS apps) var injector = angular.injector(['ndc', 'ng']);
  25. // Create an AngularJS module with no dependencies var ndc

    = angular.module('ndc', []); // Register a function ndc.factory('awesome', function() { return 'awesome conference'; }); // Get the injector (happens behind the scenes in AngularJS apps) var injector = angular.injector(['ndc', 'ng']);
  26. // Create an AngularJS module with no dependencies var ndc

    = angular.module('ndc', []); // Register a function ndc.factory('awesome', function() { return 'awesome conference'; }); // Get the injector (happens behind the scenes in AngularJS apps) var injector = angular.injector(['ndc', 'ng']); // Call a function with dependency injection injector.invoke(function(awesome) { console.log('awesome() == ' + awesome); });
  27. // Create an AngularJS module with no dependencies var ndc

    = angular.module('ndc', []); // Register a function ndc.factory('awesome', function() { return 'awesome conference'; }); // Get the injector (happens behind the scenes in AngularJS apps) var injector = angular.injector(['ndc', 'ng']); // Call a function with dependency injection injector.invoke(function(awesome) { console.log('awesome() == ' + awesome); });
  28. {{#if isExpanded}} <div class='body'>{{body}}</div> <button {{action contract}}>Contract</button> {{else}} <button {{action

    expand}}>Show More...</button> {{/if}} App.PostController = Ember.ObjectController.extend({ body: 'body', isExpanded: false, expand: function() { this.set('isExpanded', true); }, contract: function() { this.set('isExpanded', false); } });
  29. {{#if isExpanded}} <div class='body'>{{body}}</div> <button {{action contract}}>Contract</button> {{else}} <button {{action

    expand}}>Show More...</button> {{/if}} App.PostController = Ember.ObjectController.extend({ body: 'body', isExpanded: false, expand: function() { this.set('isExpanded', true); }, contract: function() { this.set('isExpanded', false); } }); no jquery!
  30. dependencies We depend on other code We depend on other

    files We depend on Third-party libraries
  31. CommonJS AMD var $ = require('jquery'); exports.myFn = function ()

    {}; define(['jquery'] , function ($) { return function () {}; });
  32. CommonJS AMD var $ = require('jquery'); exports.myFn = function ()

    {}; define(['jquery'] , function ($) { return function () {}; }); works better in current browsers
  33. AMD

  34. dependencies We depend on other code We depend on other

    files We depend on Third-party libraries