44
Built to last – JavaScript for Enterprise Reference architecture GUIDE

Built to last javascript for enterprise

Embed Size (px)

DESCRIPTION

Common pattern, practices and optimizations for Enterprise Web Applications.

Citation preview

Page 1: Built to last   javascript for enterprise

Built to last – JavaScript for Enterprise

Reference architecture GUIDE

Page 2: Built to last   javascript for enterprise

[email protected]/marjan.nikolovski

Marjan Nikolovski

A professional senior software engineer and conference speaker who is mainly hooked on the .NET platform as development platform and its derivatives, but from time to time knows to kill some time with open source software.Usually spends his time writing systems backend and testing cutting edge technologies. In spare time actively participating in holding technical presentations on conferences and researching. Specially interested in Distributed programming, Software architecture, Middleware, SOA, Non-relational databases and Workflow driven systems.

Page 3: Built to last   javascript for enterprise

Agenda Word-Two; JavaScript mistakes from the C# programmer Solution structure; Solution architecture; Product modules; UI Components; Event Driven Messaging; Localization; Logging Optimizations

Page 4: Built to last   javascript for enterprise

Word-Two Enterprise JavaScript app - heavy data app that is hard to be maintained; Development time increase as the complexity and the codebase grows up; Frontend development usually not taken seriously; Frontend development always underestimated and without certain

development plan and architecture;

Page 5: Built to last   javascript for enterprise

JavaScript mistakes from the C# programmer Writing jQuery still requires knowledge of JavaScript; Using global variables and functions; Object literal; Self-Executing Anonymous Function; Revealing Module Pattern; Array and object declaration gone bad; False value understanding; Default value testing; Using wrong comparison operators; Misusing For..in statement on Arrays; Function and Object Scope in JavaScript; Not aware of JSLint;

Page 6: Built to last   javascript for enterprise

Using global variables and functionsvar invalid_username = "Username exists";function log_in() { //Placed in global scope when executed invalid_username = "Really Bad";}//Bad way to prevent namespace clashingfunction namespace_log_out() {}//Functionswindow.log_in();window.namespace_log_out();//Global variables are available off window objectconsole.log(window.invalid_username);console.log(window.log_in);console.log(window.namespace_log_out);

Page 7: Built to last   javascript for enterprise

Object literal Similar to JSON syntax; Provide properties and function by choice; Everything defined in the object literal is public;

Pros ConsRemove global namespaces to properties, variables and methods

Difficult to maintain and understand

Functionality can be added at a later point

No way to have private properties and/or methods

All properties and methods are public

//Object Literal declaring properties and methodsvar user_model = { //public property username: "Some user", //public method login: function() {}};

Page 8: Built to last   javascript for enterprise

Self-Executing Anonymous Function Non name function that executes after it is defined; Isolate variables and functions from global namespace;

//Self-Executing Anonymous Function:(function() { //private variable var username = "Some username"; //private function function login() {} login();}());

Pros ConsHide implementation from external code

All information is hidden

The code runs only once

Complicated on first sight

Not using object literal notation

Page 9: Built to last   javascript for enterprise

Revealing Module Pattern Uses the concept of the Self-Executing Anonymous Function; Store the result into a variable;//Revealing Module Pattern (Public & Private)var user_proxy = (function() { var me = {}, //Private property

username = "Some username"; //Public property me.message = "A message"; //Public method me.Login = function() { pvtLogin(); }; //Private method function pvtLogin() { //Do something... } //Return just the public parts return me;}());

Pros ConsAllow private and public properties and methodsEasy to understand

Page 10: Built to last   javascript for enterprise

Array and object declaration gone bad Many ways to create an object, but only one is the correct one; Hesitate the temptation to use the new keyword;

// bad practicevar user = new Object();

// good practicevar user = {};

// bad practicefunction User(uname){ this.username = uname;}

var user = new User(‘test’);user.username == ‘test’

var user = User(‘test’);user.username != ‘test’user.username == window. username

Page 11: Built to last   javascript for enterprise

False value understanding Same goes for arrays. Many ways to create an array, but only one

is the correct one;

// bad practicevar userList = new Array(10);userList[0] === undefined;userList.length == 10;

// good practicevar userList = [];

Page 12: Built to last   javascript for enterprise

Default value testing

C#

If(user != null && user.Length > 0){ // do something}

JavaScript

If(user){ // do something}

OR

user = user || ‘default value’;

Page 13: Built to last   javascript for enterprise

Using wrong comparison operators JavaScript ninja behavior can sometimes gives us unexpected

results; Sometime value comparison is not what it looks like; Always use === or !== when doing comparison in JavaScript;

// Unexpected comparisons0 == '‘ //true0 == ‘0’ //truefalse == '0‘ //truenull == undefined //true' \t\r\n ' == 0 //true

0 === '' //false0 === '0' //falsefalse === '0' //falsenull === undefined //false' \t\r\n ' === 0 //false

Page 14: Built to last   javascript for enterprise

Misusing For..in statement on Arrays Does not guarantee the order of the items that are going to be

retrieved by the iterator; The iterator can iterate both array and objects; Bad declaration can result in incorrect iterator execution;

var user = { username: ‘Test’, name:’Some name’};

for(var data in user){ alert(data);}// outputs username, name

var userArray = [];userArray.push(‘data’)userArray.name = ‘Test’;

for(var data in user){ alert(data); alert(user[data]);}// outputs 0, name// outputs data, Test

Page 15: Built to last   javascript for enterprise

Function and Object Scope in JavaScript Variable scope visible in the

function; All internal closures or

functions will see the defined variables in the parent function scope;

function login() {    var user = "test",        isWrongCaptcha = true;    if (isWrongCaptcha) {        var timeToWait = 10;         console.log( "Waiting " + timeToWait + " minutes" );        internal_log_in();    }     function internal_log_in() {         //The chew function also has access to the        //timeToWait variable because it is part of the        //eat function's scope        console.log("After waiting " + timeToWait +            " minutes, " + "I am going to login to the system");    }} login();//Waiting 10 minutes//After waiting 10 minutes, I am going to login to the system

Page 16: Built to last   javascript for enterprise

Not aware of JSLint JSLint is a static code analysis tool used in software development for

checking if JavaScript source code complies with coding rules; Provided primarily as an online tool, but there are also command-line

adaptations;

Page 17: Built to last   javascript for enterprise

Solution structure Large scale JavaScript development involves different source types and

formats; Presentation code; Proxy code; Third party libs;

Solution structure is tightly coupled with the solution architecture approach;

Physical structure should match the solution architecture abstraction;

Page 18: Built to last   javascript for enterprise

Solution structure /scripts

/utils /controllers /models /modules /bootstrappers /libs

/components /external

/content /images /css /media

/scripts Development helpers Proxy classes to the server methods Models used for the client and server side Modules per functionality Application/module/plugin initializers /libs

Custom developed components External libraries

/content /images /css /media

Page 19: Built to last   javascript for enterprise

Solution architecture Plan before execute; Questions to be answered before the design:

What will be reused? How many modules depend on other modules? Are your module sandboxed?

Page 20: Built to last   javascript for enterprise

Solution architecture Break your application into small single-purpose parts - modules; Module pattern gives you implementation privacy, state and code

organization; Provide a way to handle private and public methods and variables; Protects the code to leak into the global namespace;

Page 21: Built to last   javascript for enterprise

Solution architecturenamespace.modulename = function(module) { var privateVar = 'some data'; module.init = function(){ }; module.doSomething = function(){

internalDoSomething(); }; function internalDoSomething(){ }; return module;}(namespace.modulename || {});

Page 22: Built to last   javascript for enterprise

Solution architecture In some point there will be a need to establish module communication; In order to avoid tight coupling we can utilize the mediator pattern; The mediator pattern encapsulates how a set of modules interact;

Page 23: Built to last   javascript for enterprise

Solution architecture

Page 24: Built to last   javascript for enterprise

Solution architecture Utilized via Pub/Sub; Modules communicates via message publishing;

;(function ($) { var o = $({}); $.subscribe = function () { o.on.apply(o, arguments); }; $.unsubscribe = function () { o.off.apply(o, arguments); }; $.publish = function () { o.trigger.apply(o, arguments); };} (jQuery));

$.subscribe('namespace/action', function (data) {

alert(data);});

$.publish('namespace/action', 'data')

Page 25: Built to last   javascript for enterprise

Solution architecture Wrapping it all together; The modules publish events which inform the application that

something is happening; The modules in the system are subscribed to certain events; The mediator enables the modules to communicate via the

PubSub mechanism;

Page 26: Built to last   javascript for enterprise

Solution architecture

Page 27: Built to last   javascript for enterprise

Product modules Utilizing the module pattern; JavaScript coding pattern; Module pattern implementation with anonymous closures; Should be considered:

Every module should be part of a namespace; Every module can contains sub modules; What will be the global import of the module; What will the module export;

Page 28: Built to last   javascript for enterprise

Product modulesvar namespace.module = (function (import) {

var me = {};// private propertyvar somePrivateVar = 'Test data';// public propertyme.publicProperty = 'Public data';// private methodfunction privateMethod() {

somePrivateVar = 'executed pvt method';}// publicmethodme.publicMethod = function () {

return me.publicProperty;};// the module exportreturn me;

}(GLOBAL_IMPORT));

Page 29: Built to last   javascript for enterprise

Product modules Module inheritance can be done with module import;

namespace.module = (function (baseModule) {var me = {};// inherit the methods and propertiesfor (key in baseModule) {

if (baseModule.hasOwnProperty(key)) {me[key] = baseModule[key];

}}

var base_publicMethod = baseModule.publicMethod;

// public method overrideme.publicMethod = function () {

return base_publicMethod();};// the module exportreturn me;

}(module));

Page 30: Built to last   javascript for enterprise

UI Components Build your UI components in jQuery plugin fashion; jQuery plugin pattern is well known and understood by most of the UI

developers; Offers simple implementation syntax and offers extensibility;

Page 31: Built to last   javascript for enterprise

UI Components$.fn.pluginName = function(options){ // Create some defaults, extending them with any options that were provided var settings = $.extend( { 'location' : 'top', 'background-color' : 'blue' }, options);

// return the object back to the chained call flow return this.each(function() // This is the main processor // function that executes on // each selected element // (e.g: jQuery("div")) { var $this = $(this); alert($this); });};})(jQuery);

// usage$(document).ready(function() { // create a new instance of the plugin $(‘selector’).pluginName(options);});

Page 32: Built to last   javascript for enterprise

Event Driven Messaging Allow communication between modules via event publishing managed by

pub/sub component; Each module can publish events, subscribe and unsubscribe to events;

Page 33: Built to last   javascript for enterprise

Event Driven Messagingapp.usermodule = (function () {

var me = {};

me.onNewFriendNotificaion = function(notification){

alert(notification.from);};

me.init = function(){$.subscribe('on-new-friend-

notificaion', me.onNewFriendNotificaion);};

me.destroy = function(){$.unsubscribe('on-new-

friend-notificaion', me.onNewFriendNotificaion);

};

return me;}());

app.streammodule = (function () {var me = {};

me.post = function(){// do some client logic and

notify the other modules$.publish('on-new-friend-

notificaion', { from:'user' });};

return me;}());

Page 34: Built to last   javascript for enterprise

Localization String localization; Dates, times, numbers, and currencies; Use jQuery Globalize plugin for Dates, times, numbers, and currencies;

Page 35: Built to last   javascript for enterprise

Localization Store string resources in JSON format so they would be native to client; Server string resources per culture; Build language manager for the string resources; Load the JSON resources into the language manager; User the language manager to translate plugins, DOM elements and

strings;

Page 36: Built to last   javascript for enterprise

Logging Useful for tracking modules state, variables and processes while in

development; Natively supported in all of the new modern browsers; Use an existing logging framework or wrap your logger around the existing

browsers logger;

Page 37: Built to last   javascript for enterprise

Loggingvar logger = function(){

var logger = {};window.onerror = function(message, file, line) {

logError(file + ':' + line + '\n\n' + message);};logger.log = function(message){

logError(message);};function logError(message){

if(console && console.log){console.log(message);

}};return logger;

}();

Page 38: Built to last   javascript for enterprise

Optimizations – End of tunnel Add style sheets in the HEAD Add scripts at the bottom of the <BODY> Add favicon Create CSS sprites Enable GZIP and static resource Caching Minimize CSS and JavaScript files Set cookie less domain for static resources

Page 39: Built to last   javascript for enterprise

Add favicon

routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });

Page 40: Built to last   javascript for enterprise

Create CSS sprites Put all of your icons and assets that you are using for your design into one

file. Create CSS file to access the resources. You will minimize n*request per resource time that the browser would call for the separate assets. 

Check out Sprite cow – http://www.spritecow.com

Page 41: Built to last   javascript for enterprise

Enable GZIP and static resource Caching<system.webServer><staticContent><remove fileExtension=".js" /><remove fileExtension=".css" /><mimeMap fileExtension=".js" mimeType="text/javascript" /><mimeMap fileExtension=".css" mimeType="text/css" /><clientCache cacheControlCustom="public" cacheControlMode="UseMaxAge" cacheControlMaxAge="500.00:00:00" /></staticContent><urlCompression doStaticCompression="true" doDynamicCompression="true" /></system.webServer>

Page 42: Built to last   javascript for enterprise

Minimize CSS and JavaScript files@(Bundle.Css().Add("~/Content/base.css").Add("~/Content/CSS/Plugins/BootstrapDatepicker/daterangepicker-bs3.css").MvcRender("~/Content/CSS/min/combined_#.css"))------------------------@(Bundle.JavaScript().Add(@"~/Scripts/lib/jquery-2.0.2.min.js").Add(@"~/Scripts/lib/jquery.slimscroll.min.js").Add(@"~/Scripts/lib/jquery-ui-1.10.3.custom.min.js").Add(@"~/Scripts/lib/typeahead.min.js").Add(@"~/Scripts/lib/daterangepicker.js").Add(@"~/Scripts/lib/moment.min.js").MvcRender("~/Scripts/min/combined_#.js"))

Page 43: Built to last   javascript for enterprise

Set cookie less domain for static resources Go to your domain hosting account and set a subdomain that point to your

web application

Set your static resources to point to the subdomain to avoid cookie data transfer

Page 44: Built to last   javascript for enterprise

QUESTIONS ?