SlideShare a Scribd company logo
1 of 49
codecentric d.o.o
Jovan Vidić, IT Consultant @ codecentric
Refactoring Java Script Applications
Motivation
Should We Refactor JavaScript?
Refactoring Sample Application
Beyond Refactoring
Agenda
~ 6 years of development
Java + DWR
732 JavaScript files
~ 20 000 lines of javascript code
Motivation - Legacy project
What was wrong?
- JavaScript in HTML
- Global functions
- Inline styles
- No coding style guidelines
- No tests
MOTIVATION - Legacy project
What was OK?
- OOP
- Throwing own errors
- Wrapping third party libraries
- Prototype.js
MOTIVATION - Legacy project
Should We Refactor JavaScript ?
“It is not necessary to change.
Survival is not mandatory”
W. Edwards Deming
W E Deming
What is Refactoring?
What is Refactoring?
a change made to the internal structure of software
to make it easier to understand and cheaper to modify
without changing its observable behavior
M. Fowler
This is not refactoring
agile manifesto 8th principle
Agile processes promote sustainable development.
The sponsors, developers, and users should be able
to maintain a constant pace indefinitely.
Refactoring Sample Application – v1 – index.html
</head>!
<body>!
<ul class="nav nav-pills">!
<li class="active"><a href="../../v1/client/index.html">V1</a></
li>!
<li><a href="../../v2/client/index.html">V2</a></li>!
<li><a href="../../v3/client/index.html">V3</a></li>!
<li><a href="../../v4/client/index.html">V4</a></li>!
<li><a href="../../v5/client/index.html">V5</a></li>!
</ul>!
<div class="page-header">!
<h1>Coding Serbia <small> Refactoring JavaScript Applications -
V1</small></h1>!
</div>!
<!-- Button trigger modal -->!
<button class="btn btn-primary btn-lg" data-toggle="modal"
onclick="createSpeaker()">!
Add Speaker!
</button>!
<script src="js/jquery.min.js"></script>!
<script src="js/bootstrap.min.js"></script>!
<script src="js/speakers.js"></script>!
!
<script type="text/javascript">!
load();!
</script>!
</body>!
Refactoring Sample Application – v1 – index.html
Refactoring Sample Application – v1 – speakers.js
function add() {!
var speakerId = $('#speakerId').val();!
!
$.ajax({!
type: speakerId == '' ? "POST" : "PUT",!
url: speakerId == '' ? "http://localhost:4730/speakers" : "http:/!
data: JSON.stringify({id: speakerId, firstName: $('#firstName').v!
contentType: "application/json; charset=utf-8",!
dataType: "json",!
success: function(data){ $('#speakerId').val(''); $('#firstName’)!
failure: function(errMsg) {alert(errMsg);}!
!
function load() {!
$.getJSON( "http://localhost:4730/speakers", function( data ) {!
var newRows = "";!
$.each(data, function(i,item) {!
var sessionTime = new Date(Date.parse(item.sessionTime));!
!
newRows += "<tr><td>" + sessionTime.toLocaleString() +"</td><!
});!
$(".table-striped tbody").html("");!
$(".table-striped tbody").append(newRows);!
});!
};!
Refactoring Sample Application – v1
It is a complete mess!
How should I start?
Refactoring Sample Application – v1 – selenium
Refactoring Sample Application – v1
What about JSLint/JSHIT?
It will scream at you!
Refactoring Sample Application – v2
Invert dependencies
Refactoring Sample Application – v2 - REQUIREJS
requirejs.config({!
paths: {!
"jquery": "lib/jquery.min",!
"bootstrap": "lib/bootstrap.min"!
},!
shim: {!
"bootstrap": {!
deps: ["jquery"]!
}!
}!
});!
!
require(["app/speakers","bootstrap"], function (speakers) {!
!
$("#btnSaveSpeaker").click(function() {!
speakers.save();!
});!
!
speakers.loadAll();!
});!
<script data-main="scripts/main" src="scripts/lib/require.js"></script>!
Refactoring Sample Application – V2 – SPEAKERS.JS & THEME.jS
define(["jquery","app/theme"], function ($, theme) {!
"use strict";!
!
var SpeakerControler = {!
loadAll : function () {!
$.getJSON("http://localhost:4730/speakers", function (data) {!
var speakersTable = $("." + theme.SPEAKERS_TABLE +" tbody")
define([], function () {!
"use strict";!
!
return {!
DELETE_BUTTON : "btn btn-danger glyphicon glyphicon-remove",!
EDIT_BUTTON : "btn btn-default glyphicon glyphicon-pencil",!
SPEAKERS_TABLE : "table-striped"!
};!
});!
Refactoring Sample Application – SPEAKERS.JS
define(["jquery","app/theme"], function ($, theme) {!
"use strict";!
!
var SpeakerControler = {!
loadAll : function () {!
cell.append($("<button class='"+theme.DELETE_BUTTON+"'></button>”)!
SpeakerControler.remove(item.id);!
}));
remove : function(id) {!
$.ajax({!
type: "DELETE",!
url: "http://localhost:4730/speaker/" + id,!
success: function() {!
SpeakerControler.loadAll();!
}!
});!
}!
return SpeakerControler;!
});
My code is isolated now
Can I write unit tests?
Refactoring Sample Application – v3
Manage dependencies
Refactoring Sample Application – v3 – bower.json
{!
"name": "javascript-refactoring",!
"version": "1.0",!
"authors": [!
"Jovan Vidic
<jovan.vidic@codecentric.de>"!
],!
"private": true,!
"ignore": [!
"node_modules",!
"bower_components",!
"test",!
"tests"!
],!
"dependencies": {!
"jquery": "1.11.1",!
"bootstrap" : "3.2.0",!
"requirejs" : "2.1.15"!
},!
!
"devDependencies": {!
!
}!
}!
Refactoring Sample Application – v4
Improve design
Introduce model objects & unit tests
Refactoring Sample Application – v4 – MODEL.JS
function Speaker(id, firstName, lastName, topic, sessionTime, track) {!
this.id = id;!
this.firstName = firstName;!
this.lastName = lastName;!
this.topic = topic;!
this.sessionTime = sessionTime;!
this.track = track;!
!
this.hasId = function () {!
return (this.id !== undefined) && (this.id !== null) !
&& (this.id !== "");!
};!
!
this.getFullName = function () {!
return this.firstName + " " + this.lastName;!
};!
}!
!
return {!
"Agenda" : {!
"Speaker" : Speaker!
}!
};!
Refactoring Sample Application – v4 – Speakers.JS
define(["jquery", "app/model", "app/theme"], function ($, model, theme) {!
"use strict";!
var SpeakerControler = {!
editSpeaker : function(id) {!
$.getJSON( "http://localhost:4730/speaker/" + id, !
function(speakerData) {!
if(speakerData) {!
var speaker = convertToModel(speakerData);!
showEditSpeakerPopup(speaker);!
}!
});!
}!
function showEditSpeakerPopup(speaker) {!
$('#myModalLabel').html('Edit speaker <strong>' !
+ speaker.getFullName() + "</strong>");!
}!
function convertToModel(speakerData) {!
return new model.Agenda.Speaker(speakerData.id,
speakerData.firstName, speakerData.lastName, speakerData.topic,
speakerData.sessionTime, speakerData.track);!
}
Refactoring Sample Application – v4 – jasmine
describe("Test model objects", function() {!
"use strict";!
!
var Model;!
!
beforeEach(function(done) {!
require(["app/model"], function (model) {!
Model = model;!
done();!
});!
});
it("should return Jovan Vidic when firstName is Jovan and lastName is
Vidic", function() {!
!
var speaker = new Model.Agenda.Speaker(1, "Jovan", "Vidic");!
!
expect(speaker.getFullName()).toBe("Jovan Vidic");!
});!
Refactoring Sample Application – v4
That's all cool but my code still stinks?!
Trust me I've been there
Refactoring Sample Application – v5
Improve design
&
automate
Refactoring Sample Application – v5 – SPEAKERS AJAX CLIENT
define(["jquery", "app/model"], function ($, model) {!
"use strict";!
!
var baseURL = requirejs.s.contexts._.config.cs["api-url"],!
speakersURL = baseURL + "speakers/",!
speakerURL = baseURL + "speaker/";!
!
function convertToModel(speakerData) {!
return new model.Agenda.Speaker(speakerData.id, speakerData.firstNa
}!
return {!
loadAllSpeakers : function (callbackHandle) {!
$.getJSON(speakersURL, function (speakersData) {!
var speakers = [];!
$.each(speakersData, function (index, speakerData) {!
var speaker = convertToModel(speakerData);!
speakers.push(speaker);!
});!
callbackHandle.success(speakers);!
});!
},
Refactoring Sample Application – v5 – Backend FACADE
define(["app/client/speakers_ajax_client"], function (speakersClient) {!
"use strict";!
!
return {!
loadAllSpeakers : function (callbackHandle) {!
speakersClient.loadAllSpeakers(callbackHandle);!
},!
!
saveSpeaker : function (speaker, callbackHandle) {!
speakersClient.saveSpeaker(speaker, callbackHandle);!
}!
Refactoring Sample Application – v5 - TesTS
define(["squire"], function (Squire) {!
"use strict";!
!
var injector = new Squire(),!
client = jasmine.createSpyObj("client", ["loadAllSpeakers",
"saveSpeaker", "removeSpeaker"]),!
callbackHandle = jasmine.createSpy("callback"),!
builder = injector.mock("app/client/speakers_ajax_client”, client);
!
describe("Test backend facade", function() {!
!
var backend;!
!
beforeEach(function(done) {!
builder.require(["app/backend_facade"], function(backendFacade)
backend = backendFacade;!
done();!
});!
});!
it("should loadAllSpeakers", function() {!
backend.loadAllSpeakers(callbackHandle);!
expect(client.loadAllSpeakers)!
.toHaveBeenCalledWith(callbackHandle);!
});!
!
!
Refactoring Sample Application – v5 - MVP
http://warren.chinalle.com/2010/12/18/model-view-presenter/
Refactoring Sample Application – v5 – speakers PRESENTER
define(["app/backend_facade", "app/speakers/speakers_view", !
"app/events"], function (backend, SpeakersView, events) {!
!
"use strict";!
!
var EventManager = events.EventManager,!
Actions = events.Actions;!
!
function SpeakerPresenter() { !
var view = new SpeakersView(),!
self;!
!
return {!
init : function () {!
self = this;!
EventManager.register(Actions.LOAD_ALL_SPEAKERS, this.loadAll);!
},!
loadAll : function () {!
backend.loadAllSpeakers({!
"success" : function (speakers) {!
view.showAll(speakers);!
}!
});!
},!
Refactoring Sample Application – v5 – Speakers view
define(["app/events", "app/components", "app/speakers/speakers_popup"], !
"use strict”;!
var EventManager = events.EventManager;!
!
function SpeakersView() {!
var speakersTable = new components.SpeakersTable(),!
createButton = new components.Button("btnAddSpeaker"),!
popup = new SpeakersPopup();!
!
function showCreateSpeakerDialog() {!
EventManager.fire(events.Actions.SHOW_CREATE_SPEAKER);!
}!
function init() {!
createButton.addClickListener(showCreateSpeakerDialog);!
}!
init();!
return {!
showAll : function (speakers) {!
var i, len;!
speakersTable.clear();!
for (i = 0, len = speakers.length; i < len; i += 1) {!
speakersTable.addSpeaker(speakers[i]);!
}!
}!
Refactoring Sample Application – v5 – SPEAKERS POPUP
define(["app/model", "app/events", "app/components"], function (model, even
!
function SpeakersPopup() {!
var speaker,!
popup = new components.Popup("myModal"),!
firstNameInput = new TextField("firstName"),!
!
function saveSpeaker() {!
speaker.firstName = firstNameInput.val();!
speaker.lastName = lastNameInput.val();!
speaker.topic = topicInput.val();!
!
if (speaker.hasId()) {!
EventManager.fire(events.Actions.EDIT_SPEAKER, speaker);!
} else {!
EventManager.fire(events.Actions.SAVE_SPEAKER, speaker);!
}!
}!
return {!
openAndSet : function (speakerToUpdate) {!
speaker = speakerToUpdate;!
firstNameInput.val(speaker.firstName);!
lastNameInput.val(speaker.lastName);!
!
Refactoring Sample Application – v5 – components
http://warren.chinalle.com/2010/12/18/model-view-presenter/
define(["jquery", "app/events", "app/theme"], function ($, events, theme)
!
function TextField(id) {!
var textField = $("#" + id);!
return {!
val : function (value) {!
if (value !== undefined) {!
textField.val(value);!
} else {!
return textField.val();!
}!
}!
};!
}!
!
function SimpleButton(id) {!
var button = $("#" + id);!
return {!
addClickListener : function (listener) {!
button.click(listener);!
}!
};!
}!
!
For the win
Refactoring Sample Application – v5 - GRUNT
grunt.initConfig({!
!
jslint: {!
src: [!
"scripts/**/*.js"!
],!
!
},!
!
karma: {!
unit: {!
configFile: "karma.conf.js"!
}!
},!
!
copy: {!
main: {!
files: [!
{expand: true, src: ["lib/bootstrap/dist/css/**"], dest: "dist/"},!
{expand: true, src: ["lib/bootstrap/dist/fonts/**"], dest: "dist/"}
{expand: true, src: ["lib/requirejs/require.js"], dest: "dist/"}!
]!
}!
}!
Refactoring Sample Application – v5 - GRUNT
requirejs: {!
compile: {!
options: {!
baseUrl: "scripts/",!
name: "main",!
out: "dist/app-built.js”,!
paths: {!
app: "app/",!
"jquery": "../lib/jquery/dist/jquery.min",!
"bootstrap": "../lib/bootstrap/dist/js/bootstrap"!
}!
}!
}!
},!
processhtml: {!
options: {!
data: { !
}!
},!
dist: {!
files: {!
"dist/index.html": ["index.html"]!
}!
}!
BEYOND REFACTORING
Coffeescript
define [], () ->!
!
class Speaker!
constructor: (@id, @firstName, @lastName, @topic, @sessionTime, @track)
->!
!
hasId: ->!
@id?.length != 0!
!
fullName: ->!
@firstName + " " + @lastName!
!
return {"Agenda": {"Speaker" : Speaker}} !
Literature
QUESTIONS
https://github.com/jovanvidic/javascript-refactoring
vidicj@gmail.com
@_yowan_
?

More Related Content

What's hot

Diseño de APIs con Ruby
Diseño de APIs con RubyDiseño de APIs con Ruby
Diseño de APIs con RubySoftware Guru
 
The Art and Science of Shipping Ember Apps
The Art and Science of Shipping Ember AppsThe Art and Science of Shipping Ember Apps
The Art and Science of Shipping Ember AppsJesse Cravens
 
Modern JavaScript, without giving up on Rails
Modern JavaScript, without giving up on RailsModern JavaScript, without giving up on Rails
Modern JavaScript, without giving up on RailsJonathan Johnson
 
A tour of React Native
A tour of React NativeA tour of React Native
A tour of React NativeTadeu Zagallo
 
*Webinar* Learn from the Experts: How to Boost Test Coverage with Automated V...
*Webinar* Learn from the Experts: How to Boost Test Coverage with Automated V...*Webinar* Learn from the Experts: How to Boost Test Coverage with Automated V...
*Webinar* Learn from the Experts: How to Boost Test Coverage with Automated V...Applitools
 
The Gist of React Native
The Gist of React NativeThe Gist of React Native
The Gist of React NativeDarren Cruse
 
Apache Cordova In Action
Apache Cordova In ActionApache Cordova In Action
Apache Cordova In ActionHazem Saleh
 
Spring Day | WaveMaker - Spring Roo - SpringSource Tool Suite: Choosing the R...
Spring Day | WaveMaker - Spring Roo - SpringSource Tool Suite: Choosing the R...Spring Day | WaveMaker - Spring Roo - SpringSource Tool Suite: Choosing the R...
Spring Day | WaveMaker - Spring Roo - SpringSource Tool Suite: Choosing the R...JAX London
 
[English version] JavaFX and Web Integration
[English version] JavaFX and Web Integration[English version] JavaFX and Web Integration
[English version] JavaFX and Web IntegrationKazuchika Sekiya
 
Java Core | JavaFX 2.0: Great User Interfaces in Java | Simon Ritter
Java Core | JavaFX 2.0: Great User Interfaces in Java | Simon RitterJava Core | JavaFX 2.0: Great User Interfaces in Java | Simon Ritter
Java Core | JavaFX 2.0: Great User Interfaces in Java | Simon RitterJAX London
 
Angularjs Tutorial for Beginners
Angularjs Tutorial for BeginnersAngularjs Tutorial for Beginners
Angularjs Tutorial for Beginnersrajkamaltibacademy
 
Continuous Visual Integration - RailsConf 2016 - Mike Fotinakis - Percy.io
Continuous Visual Integration - RailsConf 2016 - Mike Fotinakis - Percy.ioContinuous Visual Integration - RailsConf 2016 - Mike Fotinakis - Percy.io
Continuous Visual Integration - RailsConf 2016 - Mike Fotinakis - Percy.ioMike Fotinakis
 
Writing great documentation - CodeConf 2011
Writing great documentation - CodeConf 2011Writing great documentation - CodeConf 2011
Writing great documentation - CodeConf 2011Jacob Kaplan-Moss
 
Creating books app with react native
Creating books app with react nativeCreating books app with react native
Creating books app with react nativeAli Sa'o
 
BPM-2 Introduction to Advanced Workflows
BPM-2 Introduction to Advanced WorkflowsBPM-2 Introduction to Advanced Workflows
BPM-2 Introduction to Advanced WorkflowsAlfresco Software
 
Comparing Hot JavaScript Frameworks: AngularJS, Ember.js and React.js - Sprin...
Comparing Hot JavaScript Frameworks: AngularJS, Ember.js and React.js - Sprin...Comparing Hot JavaScript Frameworks: AngularJS, Ember.js and React.js - Sprin...
Comparing Hot JavaScript Frameworks: AngularJS, Ember.js and React.js - Sprin...Matt Raible
 

What's hot (20)

Diseño de APIs con Ruby
Diseño de APIs con RubyDiseño de APIs con Ruby
Diseño de APIs con Ruby
 
React Native
React NativeReact Native
React Native
 
The Art and Science of Shipping Ember Apps
The Art and Science of Shipping Ember AppsThe Art and Science of Shipping Ember Apps
The Art and Science of Shipping Ember Apps
 
Modern JavaScript, without giving up on Rails
Modern JavaScript, without giving up on RailsModern JavaScript, without giving up on Rails
Modern JavaScript, without giving up on Rails
 
A tour of React Native
A tour of React NativeA tour of React Native
A tour of React Native
 
*Webinar* Learn from the Experts: How to Boost Test Coverage with Automated V...
*Webinar* Learn from the Experts: How to Boost Test Coverage with Automated V...*Webinar* Learn from the Experts: How to Boost Test Coverage with Automated V...
*Webinar* Learn from the Experts: How to Boost Test Coverage with Automated V...
 
How to React Native
How to React NativeHow to React Native
How to React Native
 
The Gist of React Native
The Gist of React NativeThe Gist of React Native
The Gist of React Native
 
Apache Cordova In Action
Apache Cordova In ActionApache Cordova In Action
Apache Cordova In Action
 
Spring Day | WaveMaker - Spring Roo - SpringSource Tool Suite: Choosing the R...
Spring Day | WaveMaker - Spring Roo - SpringSource Tool Suite: Choosing the R...Spring Day | WaveMaker - Spring Roo - SpringSource Tool Suite: Choosing the R...
Spring Day | WaveMaker - Spring Roo - SpringSource Tool Suite: Choosing the R...
 
[English version] JavaFX and Web Integration
[English version] JavaFX and Web Integration[English version] JavaFX and Web Integration
[English version] JavaFX and Web Integration
 
Java Core | JavaFX 2.0: Great User Interfaces in Java | Simon Ritter
Java Core | JavaFX 2.0: Great User Interfaces in Java | Simon RitterJava Core | JavaFX 2.0: Great User Interfaces in Java | Simon Ritter
Java Core | JavaFX 2.0: Great User Interfaces in Java | Simon Ritter
 
Agile toolkit present 2012
Agile toolkit present 2012Agile toolkit present 2012
Agile toolkit present 2012
 
Angularjs Tutorial for Beginners
Angularjs Tutorial for BeginnersAngularjs Tutorial for Beginners
Angularjs Tutorial for Beginners
 
Continuous Visual Integration - RailsConf 2016 - Mike Fotinakis - Percy.io
Continuous Visual Integration - RailsConf 2016 - Mike Fotinakis - Percy.ioContinuous Visual Integration - RailsConf 2016 - Mike Fotinakis - Percy.io
Continuous Visual Integration - RailsConf 2016 - Mike Fotinakis - Percy.io
 
Writing great documentation - CodeConf 2011
Writing great documentation - CodeConf 2011Writing great documentation - CodeConf 2011
Writing great documentation - CodeConf 2011
 
Creating books app with react native
Creating books app with react nativeCreating books app with react native
Creating books app with react native
 
BPM-2 Introduction to Advanced Workflows
BPM-2 Introduction to Advanced WorkflowsBPM-2 Introduction to Advanced Workflows
BPM-2 Introduction to Advanced Workflows
 
React native
React nativeReact native
React native
 
Comparing Hot JavaScript Frameworks: AngularJS, Ember.js and React.js - Sprin...
Comparing Hot JavaScript Frameworks: AngularJS, Ember.js and React.js - Sprin...Comparing Hot JavaScript Frameworks: AngularJS, Ember.js and React.js - Sprin...
Comparing Hot JavaScript Frameworks: AngularJS, Ember.js and React.js - Sprin...
 

Viewers also liked

Redefining Projects For an Age of Complexity
Redefining Projects For an Age of ComplexityRedefining Projects For an Age of Complexity
Redefining Projects For an Age of ComplexityJovan Vidić
 
How To Start Agile Competence Center
How To Start Agile Competence CenterHow To Start Agile Competence Center
How To Start Agile Competence CenterJovan Vidić
 
5 Games for Effective Agile Coaching
5 Games for Effective Agile Coaching5 Games for Effective Agile Coaching
5 Games for Effective Agile CoachingJovan Vidić
 
La Higiene Postural
La Higiene PosturalLa Higiene Postural
La Higiene Posturalguest261b8
 
Higiene postural[1]
Higiene postural[1]Higiene postural[1]
Higiene postural[1]Henry Leiva
 
Enfermedades ocupacionales
Enfermedades ocupacionalesEnfermedades ocupacionales
Enfermedades ocupacionalesaguzmanvel
 
Higiene postural y pausas activas
Higiene postural y pausas activasHigiene postural y pausas activas
Higiene postural y pausas activasoscarruiz254
 
Principales enfermedades causadas por una mala postura corporal
Principales enfermedades causadas por una mala postura corporalPrincipales enfermedades causadas por una mala postura corporal
Principales enfermedades causadas por una mala postura corporalSuny Sanchez
 
Ergonomía higiene postural
Ergonomía  higiene posturalErgonomía  higiene postural
Ergonomía higiene posturalvicaaron
 
Taller de higiene postural
Taller de higiene posturalTaller de higiene postural
Taller de higiene posturaljuanjoreverte
 

Viewers also liked (14)

Redefining Projects For an Age of Complexity
Redefining Projects For an Age of ComplexityRedefining Projects For an Age of Complexity
Redefining Projects For an Age of Complexity
 
How To Start Agile Competence Center
How To Start Agile Competence CenterHow To Start Agile Competence Center
How To Start Agile Competence Center
 
LA COLUMNA VERTEBRAL
LA COLUMNA VERTEBRALLA COLUMNA VERTEBRAL
LA COLUMNA VERTEBRAL
 
5 Games for Effective Agile Coaching
5 Games for Effective Agile Coaching5 Games for Effective Agile Coaching
5 Games for Effective Agile Coaching
 
La Higiene Postural
La Higiene PosturalLa Higiene Postural
La Higiene Postural
 
Higiene Postural 2º ESO
Higiene Postural 2º ESOHigiene Postural 2º ESO
Higiene Postural 2º ESO
 
Higiene postural[1]
Higiene postural[1]Higiene postural[1]
Higiene postural[1]
 
Capacitacion higiene postural
Capacitacion higiene posturalCapacitacion higiene postural
Capacitacion higiene postural
 
Enfermedades ocupacionales
Enfermedades ocupacionalesEnfermedades ocupacionales
Enfermedades ocupacionales
 
Higiene postural
Higiene posturalHigiene postural
Higiene postural
 
Higiene postural y pausas activas
Higiene postural y pausas activasHigiene postural y pausas activas
Higiene postural y pausas activas
 
Principales enfermedades causadas por una mala postura corporal
Principales enfermedades causadas por una mala postura corporalPrincipales enfermedades causadas por una mala postura corporal
Principales enfermedades causadas por una mala postura corporal
 
Ergonomía higiene postural
Ergonomía  higiene posturalErgonomía  higiene postural
Ergonomía higiene postural
 
Taller de higiene postural
Taller de higiene posturalTaller de higiene postural
Taller de higiene postural
 

Similar to Refactoring JavaScript Applications

WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...Fabio Franzini
 
Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)Ran Mizrahi
 
Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)Ran Mizrahi
 
Coffee@DBG - Exploring Angular JS
Coffee@DBG - Exploring Angular JSCoffee@DBG - Exploring Angular JS
Coffee@DBG - Exploring Angular JSDeepu S Nath
 
BPM-4 Migration from jBPM to Activiti
BPM-4 Migration from jBPM to ActivitiBPM-4 Migration from jBPM to Activiti
BPM-4 Migration from jBPM to ActivitiAlfresco Software
 
Modular Test-driven SPAs with Spring and AngularJS
Modular Test-driven SPAs with Spring and AngularJSModular Test-driven SPAs with Spring and AngularJS
Modular Test-driven SPAs with Spring and AngularJSGunnar Hillert
 
Developing Java Web Applications
Developing Java Web ApplicationsDeveloping Java Web Applications
Developing Java Web Applicationshchen1
 
How I learned to stop worrying and love embedding JavaScript
How I learned to stop worrying and love embedding JavaScriptHow I learned to stop worrying and love embedding JavaScript
How I learned to stop worrying and love embedding JavaScriptKevin Read
 
Embedding V8 in Android apps with Ejecta-V8
Embedding V8 in Android apps with Ejecta-V8Embedding V8 in Android apps with Ejecta-V8
Embedding V8 in Android apps with Ejecta-V8Kevin Read
 
[JMaghreb 2014] Developing JavaScript Mobile Apps Using Apache Cordova
[JMaghreb 2014] Developing JavaScript Mobile Apps Using Apache Cordova[JMaghreb 2014] Developing JavaScript Mobile Apps Using Apache Cordova
[JMaghreb 2014] Developing JavaScript Mobile Apps Using Apache CordovaHazem Saleh
 
Play Support in Cloud Foundry
Play Support in Cloud FoundryPlay Support in Cloud Foundry
Play Support in Cloud Foundryrajdeep
 
Unlocking the power of the APEX Plugin Architecture
Unlocking the power of the APEX Plugin ArchitectureUnlocking the power of the APEX Plugin Architecture
Unlocking the power of the APEX Plugin ArchitectureMatt Nolan
 
WSO2Con Asia 2014 - WSO2 AppDev Platform for the Connected Business
WSO2Con Asia 2014 - WSO2 AppDev Platform for the Connected BusinessWSO2Con Asia 2014 - WSO2 AppDev Platform for the Connected Business
WSO2Con Asia 2014 - WSO2 AppDev Platform for the Connected BusinessWSO2
 
Developer Productivity with Forge, Java EE 6 and Arquillian
Developer Productivity with Forge, Java EE 6 and ArquillianDeveloper Productivity with Forge, Java EE 6 and Arquillian
Developer Productivity with Forge, Java EE 6 and ArquillianRay Ploski
 
Server Side JavaScript on the Java Platform - David Delabassee
Server Side JavaScript on the Java Platform - David DelabasseeServer Side JavaScript on the Java Platform - David Delabassee
Server Side JavaScript on the Java Platform - David DelabasseeJAXLondon2014
 
In Pursuit of the Holy Grail: Building Isomorphic JavaScript Apps
In Pursuit of the Holy Grail: Building Isomorphic JavaScript AppsIn Pursuit of the Holy Grail: Building Isomorphic JavaScript Apps
In Pursuit of the Holy Grail: Building Isomorphic JavaScript AppsSpike Brehm
 

Similar to Refactoring JavaScript Applications (20)

WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
 
Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)
 
Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)
 
Avatar 2.0
Avatar 2.0Avatar 2.0
Avatar 2.0
 
Coffee@DBG - Exploring Angular JS
Coffee@DBG - Exploring Angular JSCoffee@DBG - Exploring Angular JS
Coffee@DBG - Exploring Angular JS
 
Introduction to AngularJS
Introduction to AngularJSIntroduction to AngularJS
Introduction to AngularJS
 
BPM-4 Migration from jBPM to Activiti
BPM-4 Migration from jBPM to ActivitiBPM-4 Migration from jBPM to Activiti
BPM-4 Migration from jBPM to Activiti
 
Modular Test-driven SPAs with Spring and AngularJS
Modular Test-driven SPAs with Spring and AngularJSModular Test-driven SPAs with Spring and AngularJS
Modular Test-driven SPAs with Spring and AngularJS
 
Jsf2 overview
Jsf2 overviewJsf2 overview
Jsf2 overview
 
Developing Java Web Applications
Developing Java Web ApplicationsDeveloping Java Web Applications
Developing Java Web Applications
 
How I learned to stop worrying and love embedding JavaScript
How I learned to stop worrying and love embedding JavaScriptHow I learned to stop worrying and love embedding JavaScript
How I learned to stop worrying and love embedding JavaScript
 
Embedding V8 in Android apps with Ejecta-V8
Embedding V8 in Android apps with Ejecta-V8Embedding V8 in Android apps with Ejecta-V8
Embedding V8 in Android apps with Ejecta-V8
 
[JMaghreb 2014] Developing JavaScript Mobile Apps Using Apache Cordova
[JMaghreb 2014] Developing JavaScript Mobile Apps Using Apache Cordova[JMaghreb 2014] Developing JavaScript Mobile Apps Using Apache Cordova
[JMaghreb 2014] Developing JavaScript Mobile Apps Using Apache Cordova
 
Play Support in Cloud Foundry
Play Support in Cloud FoundryPlay Support in Cloud Foundry
Play Support in Cloud Foundry
 
Unlocking the power of the APEX Plugin Architecture
Unlocking the power of the APEX Plugin ArchitectureUnlocking the power of the APEX Plugin Architecture
Unlocking the power of the APEX Plugin Architecture
 
WSO2Con Asia 2014 - WSO2 AppDev Platform for the Connected Business
WSO2Con Asia 2014 - WSO2 AppDev Platform for the Connected BusinessWSO2Con Asia 2014 - WSO2 AppDev Platform for the Connected Business
WSO2Con Asia 2014 - WSO2 AppDev Platform for the Connected Business
 
WSO2 AppDev platform
WSO2 AppDev platformWSO2 AppDev platform
WSO2 AppDev platform
 
Developer Productivity with Forge, Java EE 6 and Arquillian
Developer Productivity with Forge, Java EE 6 and ArquillianDeveloper Productivity with Forge, Java EE 6 and Arquillian
Developer Productivity with Forge, Java EE 6 and Arquillian
 
Server Side JavaScript on the Java Platform - David Delabassee
Server Side JavaScript on the Java Platform - David DelabasseeServer Side JavaScript on the Java Platform - David Delabassee
Server Side JavaScript on the Java Platform - David Delabassee
 
In Pursuit of the Holy Grail: Building Isomorphic JavaScript Apps
In Pursuit of the Holy Grail: Building Isomorphic JavaScript AppsIn Pursuit of the Holy Grail: Building Isomorphic JavaScript Apps
In Pursuit of the Holy Grail: Building Isomorphic JavaScript Apps
 

Recently uploaded

%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benonimasabamasaba
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxAnnaArtyushina1
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...masabamasaba
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...masabamasaba
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park masabamasaba
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...masabamasaba
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...masabamasaba
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024VictoriaMetrics
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2
 

Recently uploaded (20)

%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaS
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 

Refactoring JavaScript Applications

  • 1. codecentric d.o.o Jovan Vidić, IT Consultant @ codecentric Refactoring Java Script Applications
  • 2. Motivation Should We Refactor JavaScript? Refactoring Sample Application Beyond Refactoring Agenda
  • 3. ~ 6 years of development Java + DWR 732 JavaScript files ~ 20 000 lines of javascript code Motivation - Legacy project
  • 4. What was wrong? - JavaScript in HTML - Global functions - Inline styles - No coding style guidelines - No tests MOTIVATION - Legacy project
  • 5. What was OK? - OOP - Throwing own errors - Wrapping third party libraries - Prototype.js MOTIVATION - Legacy project
  • 6. Should We Refactor JavaScript ?
  • 7. “It is not necessary to change. Survival is not mandatory” W. Edwards Deming W E Deming
  • 9. What is Refactoring? a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior M. Fowler
  • 10. This is not refactoring
  • 11. agile manifesto 8th principle Agile processes promote sustainable development. The sponsors, developers, and users should be able to maintain a constant pace indefinitely.
  • 12. Refactoring Sample Application – v1 – index.html </head>! <body>! <ul class="nav nav-pills">! <li class="active"><a href="../../v1/client/index.html">V1</a></ li>! <li><a href="../../v2/client/index.html">V2</a></li>! <li><a href="../../v3/client/index.html">V3</a></li>! <li><a href="../../v4/client/index.html">V4</a></li>! <li><a href="../../v5/client/index.html">V5</a></li>! </ul>! <div class="page-header">! <h1>Coding Serbia <small> Refactoring JavaScript Applications - V1</small></h1>! </div>! <!-- Button trigger modal -->! <button class="btn btn-primary btn-lg" data-toggle="modal" onclick="createSpeaker()">! Add Speaker! </button>!
  • 13. <script src="js/jquery.min.js"></script>! <script src="js/bootstrap.min.js"></script>! <script src="js/speakers.js"></script>! ! <script type="text/javascript">! load();! </script>! </body>! Refactoring Sample Application – v1 – index.html
  • 14. Refactoring Sample Application – v1 – speakers.js function add() {! var speakerId = $('#speakerId').val();! ! $.ajax({! type: speakerId == '' ? "POST" : "PUT",! url: speakerId == '' ? "http://localhost:4730/speakers" : "http:/! data: JSON.stringify({id: speakerId, firstName: $('#firstName').v! contentType: "application/json; charset=utf-8",! dataType: "json",! success: function(data){ $('#speakerId').val(''); $('#firstName’)! failure: function(errMsg) {alert(errMsg);}! ! function load() {! $.getJSON( "http://localhost:4730/speakers", function( data ) {! var newRows = "";! $.each(data, function(i,item) {! var sessionTime = new Date(Date.parse(item.sessionTime));! ! newRows += "<tr><td>" + sessionTime.toLocaleString() +"</td><! });! $(".table-striped tbody").html("");! $(".table-striped tbody").append(newRows);! });! };!
  • 15. Refactoring Sample Application – v1 It is a complete mess! How should I start?
  • 16. Refactoring Sample Application – v1 – selenium
  • 17. Refactoring Sample Application – v1 What about JSLint/JSHIT?
  • 18. It will scream at you!
  • 19. Refactoring Sample Application – v2 Invert dependencies
  • 20. Refactoring Sample Application – v2 - REQUIREJS requirejs.config({! paths: {! "jquery": "lib/jquery.min",! "bootstrap": "lib/bootstrap.min"! },! shim: {! "bootstrap": {! deps: ["jquery"]! }! }! });! ! require(["app/speakers","bootstrap"], function (speakers) {! ! $("#btnSaveSpeaker").click(function() {! speakers.save();! });! ! speakers.loadAll();! });! <script data-main="scripts/main" src="scripts/lib/require.js"></script>!
  • 21. Refactoring Sample Application – V2 – SPEAKERS.JS & THEME.jS define(["jquery","app/theme"], function ($, theme) {! "use strict";! ! var SpeakerControler = {! loadAll : function () {! $.getJSON("http://localhost:4730/speakers", function (data) {! var speakersTable = $("." + theme.SPEAKERS_TABLE +" tbody") define([], function () {! "use strict";! ! return {! DELETE_BUTTON : "btn btn-danger glyphicon glyphicon-remove",! EDIT_BUTTON : "btn btn-default glyphicon glyphicon-pencil",! SPEAKERS_TABLE : "table-striped"! };! });!
  • 22. Refactoring Sample Application – SPEAKERS.JS define(["jquery","app/theme"], function ($, theme) {! "use strict";! ! var SpeakerControler = {! loadAll : function () {! cell.append($("<button class='"+theme.DELETE_BUTTON+"'></button>”)! SpeakerControler.remove(item.id);! })); remove : function(id) {! $.ajax({! type: "DELETE",! url: "http://localhost:4730/speaker/" + id,! success: function() {! SpeakerControler.loadAll();! }! });! }! return SpeakerControler;! });
  • 23. My code is isolated now Can I write unit tests?
  • 24.
  • 25. Refactoring Sample Application – v3 Manage dependencies
  • 26. Refactoring Sample Application – v3 – bower.json {! "name": "javascript-refactoring",! "version": "1.0",! "authors": [! "Jovan Vidic <jovan.vidic@codecentric.de>"! ],! "private": true,! "ignore": [! "node_modules",! "bower_components",! "test",! "tests"! ],! "dependencies": {! "jquery": "1.11.1",! "bootstrap" : "3.2.0",! "requirejs" : "2.1.15"! },! ! "devDependencies": {! ! }! }!
  • 27. Refactoring Sample Application – v4 Improve design Introduce model objects & unit tests
  • 28. Refactoring Sample Application – v4 – MODEL.JS function Speaker(id, firstName, lastName, topic, sessionTime, track) {! this.id = id;! this.firstName = firstName;! this.lastName = lastName;! this.topic = topic;! this.sessionTime = sessionTime;! this.track = track;! ! this.hasId = function () {! return (this.id !== undefined) && (this.id !== null) ! && (this.id !== "");! };! ! this.getFullName = function () {! return this.firstName + " " + this.lastName;! };! }! ! return {! "Agenda" : {! "Speaker" : Speaker! }! };!
  • 29. Refactoring Sample Application – v4 – Speakers.JS define(["jquery", "app/model", "app/theme"], function ($, model, theme) {! "use strict";! var SpeakerControler = {! editSpeaker : function(id) {! $.getJSON( "http://localhost:4730/speaker/" + id, ! function(speakerData) {! if(speakerData) {! var speaker = convertToModel(speakerData);! showEditSpeakerPopup(speaker);! }! });! }! function showEditSpeakerPopup(speaker) {! $('#myModalLabel').html('Edit speaker <strong>' ! + speaker.getFullName() + "</strong>");! }! function convertToModel(speakerData) {! return new model.Agenda.Speaker(speakerData.id, speakerData.firstName, speakerData.lastName, speakerData.topic, speakerData.sessionTime, speakerData.track);! }
  • 30. Refactoring Sample Application – v4 – jasmine describe("Test model objects", function() {! "use strict";! ! var Model;! ! beforeEach(function(done) {! require(["app/model"], function (model) {! Model = model;! done();! });! }); it("should return Jovan Vidic when firstName is Jovan and lastName is Vidic", function() {! ! var speaker = new Model.Agenda.Speaker(1, "Jovan", "Vidic");! ! expect(speaker.getFullName()).toBe("Jovan Vidic");! });!
  • 31. Refactoring Sample Application – v4 That's all cool but my code still stinks?!
  • 32. Trust me I've been there
  • 33. Refactoring Sample Application – v5 Improve design & automate
  • 34. Refactoring Sample Application – v5 – SPEAKERS AJAX CLIENT define(["jquery", "app/model"], function ($, model) {! "use strict";! ! var baseURL = requirejs.s.contexts._.config.cs["api-url"],! speakersURL = baseURL + "speakers/",! speakerURL = baseURL + "speaker/";! ! function convertToModel(speakerData) {! return new model.Agenda.Speaker(speakerData.id, speakerData.firstNa }! return {! loadAllSpeakers : function (callbackHandle) {! $.getJSON(speakersURL, function (speakersData) {! var speakers = [];! $.each(speakersData, function (index, speakerData) {! var speaker = convertToModel(speakerData);! speakers.push(speaker);! });! callbackHandle.success(speakers);! });! },
  • 35. Refactoring Sample Application – v5 – Backend FACADE define(["app/client/speakers_ajax_client"], function (speakersClient) {! "use strict";! ! return {! loadAllSpeakers : function (callbackHandle) {! speakersClient.loadAllSpeakers(callbackHandle);! },! ! saveSpeaker : function (speaker, callbackHandle) {! speakersClient.saveSpeaker(speaker, callbackHandle);! }!
  • 36. Refactoring Sample Application – v5 - TesTS define(["squire"], function (Squire) {! "use strict";! ! var injector = new Squire(),! client = jasmine.createSpyObj("client", ["loadAllSpeakers", "saveSpeaker", "removeSpeaker"]),! callbackHandle = jasmine.createSpy("callback"),! builder = injector.mock("app/client/speakers_ajax_client”, client); ! describe("Test backend facade", function() {! ! var backend;! ! beforeEach(function(done) {! builder.require(["app/backend_facade"], function(backendFacade) backend = backendFacade;! done();! });! });! it("should loadAllSpeakers", function() {! backend.loadAllSpeakers(callbackHandle);! expect(client.loadAllSpeakers)! .toHaveBeenCalledWith(callbackHandle);! });! ! !
  • 37. Refactoring Sample Application – v5 - MVP http://warren.chinalle.com/2010/12/18/model-view-presenter/
  • 38. Refactoring Sample Application – v5 – speakers PRESENTER define(["app/backend_facade", "app/speakers/speakers_view", ! "app/events"], function (backend, SpeakersView, events) {! ! "use strict";! ! var EventManager = events.EventManager,! Actions = events.Actions;! ! function SpeakerPresenter() { ! var view = new SpeakersView(),! self;! ! return {! init : function () {! self = this;! EventManager.register(Actions.LOAD_ALL_SPEAKERS, this.loadAll);! },! loadAll : function () {! backend.loadAllSpeakers({! "success" : function (speakers) {! view.showAll(speakers);! }! });! },!
  • 39. Refactoring Sample Application – v5 – Speakers view define(["app/events", "app/components", "app/speakers/speakers_popup"], ! "use strict”;! var EventManager = events.EventManager;! ! function SpeakersView() {! var speakersTable = new components.SpeakersTable(),! createButton = new components.Button("btnAddSpeaker"),! popup = new SpeakersPopup();! ! function showCreateSpeakerDialog() {! EventManager.fire(events.Actions.SHOW_CREATE_SPEAKER);! }! function init() {! createButton.addClickListener(showCreateSpeakerDialog);! }! init();! return {! showAll : function (speakers) {! var i, len;! speakersTable.clear();! for (i = 0, len = speakers.length; i < len; i += 1) {! speakersTable.addSpeaker(speakers[i]);! }! }!
  • 40. Refactoring Sample Application – v5 – SPEAKERS POPUP define(["app/model", "app/events", "app/components"], function (model, even ! function SpeakersPopup() {! var speaker,! popup = new components.Popup("myModal"),! firstNameInput = new TextField("firstName"),! ! function saveSpeaker() {! speaker.firstName = firstNameInput.val();! speaker.lastName = lastNameInput.val();! speaker.topic = topicInput.val();! ! if (speaker.hasId()) {! EventManager.fire(events.Actions.EDIT_SPEAKER, speaker);! } else {! EventManager.fire(events.Actions.SAVE_SPEAKER, speaker);! }! }! return {! openAndSet : function (speakerToUpdate) {! speaker = speakerToUpdate;! firstNameInput.val(speaker.firstName);! lastNameInput.val(speaker.lastName);! !
  • 41. Refactoring Sample Application – v5 – components http://warren.chinalle.com/2010/12/18/model-view-presenter/ define(["jquery", "app/events", "app/theme"], function ($, events, theme) ! function TextField(id) {! var textField = $("#" + id);! return {! val : function (value) {! if (value !== undefined) {! textField.val(value);! } else {! return textField.val();! }! }! };! }! ! function SimpleButton(id) {! var button = $("#" + id);! return {! addClickListener : function (listener) {! button.click(listener);! }! };! }! !
  • 43. Refactoring Sample Application – v5 - GRUNT grunt.initConfig({! ! jslint: {! src: [! "scripts/**/*.js"! ],! ! },! ! karma: {! unit: {! configFile: "karma.conf.js"! }! },! ! copy: {! main: {! files: [! {expand: true, src: ["lib/bootstrap/dist/css/**"], dest: "dist/"},! {expand: true, src: ["lib/bootstrap/dist/fonts/**"], dest: "dist/"} {expand: true, src: ["lib/requirejs/require.js"], dest: "dist/"}! ]! }! }!
  • 44. Refactoring Sample Application – v5 - GRUNT requirejs: {! compile: {! options: {! baseUrl: "scripts/",! name: "main",! out: "dist/app-built.js”,! paths: {! app: "app/",! "jquery": "../lib/jquery/dist/jquery.min",! "bootstrap": "../lib/bootstrap/dist/js/bootstrap"! }! }! }! },! processhtml: {! options: {! data: { ! }! },! dist: {! files: {! "dist/index.html": ["index.html"]! }! }!
  • 46. Coffeescript define [], () ->! ! class Speaker! constructor: (@id, @firstName, @lastName, @topic, @sessionTime, @track) ->! ! hasId: ->! @id?.length != 0! ! fullName: ->! @firstName + " " + @lastName! ! return {"Agenda": {"Speaker" : Speaker}} !
  • 48.