SlideShare une entreprise Scribd logo
1  sur  196
Télécharger pour lire hors ligne
TALK
Zombie Code
Zombie Code
how to survive a Javascript
Zombiecodeapocalypse
First things first
my name is
@cedmax
I work for Shazam
I organize
conferences with
From The Front
DISCLAIMER
DISCLAIMER
I’m strongly opinionated
DISCLAIMER
I’m strongly opinionated
it’s a gift and a curse
Basically
Zombies?
Basically
Zombies?
Zombies!
“Brains, BRAINS, BRains, brains, BRAINS.
BRaiNS, brains, Brains, BRAINS, BRains,
brains, BRAINS.
BRAINS, BRains, brains, BRAINS, brains.”
Ryan Mecum
ZOMBIE CODE?
it’s not dead code
http://alfasin.com/i-see-dead-code-homage-for-intellij-idea/
How to identify
Zombie CODE?
What I can tell is..
It may seems harmless
http://couchpotatofiles.wordpress.com/2012/03/20/the-walking-dead-ups-the-death-count-and-the-ratings/
http://couchpotatofiles.wordpress.com/2012/03/20/the-walking-dead-ups-the-death-count-and-the-ratings/
but it’s NOT
and it will, eventually
http://imgur.com/r/SRDBroke/JimqK
CODE
during estimation
during debugging
during development
It is dumb code
that makes you dumb as well
Hopefully it’s not too late
http://tacticaltshirts.com/shop/shirt-zombies-eat-brains/
What's that smell?
Zombies smell worse than
anything you can imagine
Lilith Saintcrow, Strange Angels
TIp #1
Code should be appealing
function validate( options ) {
// if nothing is selected, return nothing; can't chain anyway
if ( !this.length ) {
if ( options && options.debug && window.console ) {
console.warn( "Nothing selected, can't validate, returning nothing." );
}
return;
}
// check if a validator for this form was already created
var validator = $.data( this[0], "validator" );
if ( validator ) {
return validator;
}
// Add novalidate tag if HTML5.
this.attr( "novalidate", "novalidate" );
validator = new $.validator( options, this[0] );
$.data( this[0], "validator", validator );
if ( validator.settings.onsubmit ) {
this.validateDelegate( ":submit", "click", function( event ) {
if ( validator.settings.submitHandler ) {
validator.submitButton = event.target;
}
// allow suppressing validation by adding a cancel class to the
submit button
if ( $(event.target).hasClass("cancel") ) {
validator.cancelSubmit = true;
}
// allow suppressing validation by adding the html5 formnovalidate
attribute to the submit button
if ( $(event.target).attr("formnovalidate") !== undefined ) {
validator.cancelSubmit = true;
}
});
// validate the form on submit
this.submit( function( event ) {
if ( validator.settings.debug ) {
// prevent form submit to be able to see console output
event.preventDefault();
}
function handle() {
var hidden;
if ( validator.settings.submitHandler ) {
if ( validator.submitButton ) {
// insert a hidden input as a replacement for the missing
submit button
hidden = $("<input type='hidden'/>").attr("name",
validator.submitButton.name).val( $
(validator.submitButton).val() ).appendTo(validator.currentForm);
}
validator.settings.submitHandler.call( validator,
validator.currentForm, event );
if ( validator.submitButton ) {
// and clean up afterwards; thanks to no-block-scope, hidden
can be referenced
hidden.remove();
}
return false;
}
return true;
}
// prevent submit for invalid forms or custom submit handlers
if ( validator.cancelSubmit ) {
validator.cancelSubmit = false;
return handle();
}
if ( validator.form() ) {
if ( validator.pendingRequest ) {
validator.formSubmitted = true;
return false;
}
return handle();
} else {
validator.focusInvalid();
return false;
}
});
}
return validator;
}
HOW LONG IS THAT?
function validate( options ) {
// if nothing is selected, return nothing; can't chain anyway
if ( !this.length ) {
if ( options && options.debug && window.console ) {
console.warn( "Nothing selected, can't validate, returning nothing." );
}
return;
}
// check if a validator for this form was already created
var validator = $.data( this[0], "validator" );
if ( validator ) {
return validator;
}
// Add novalidate tag if HTML5.
this.attr( "novalidate", "novalidate" );
validator = new $.validator( options, this[0] );
$.data( this[0], "validator", validator );
if ( validator.settings.onsubmit ) {
this.validateDelegate( ":submit", "click", function( event ) {
if ( validator.settings.submitHandler ) {
validator.submitButton = event.target;
}
// allow suppressing validation by adding a cancel class to the submit button
if ( $(event.target).hasClass("cancel") ) {
validator.cancelSubmit = true;
}
// allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
if ( $(event.target).attr("formnovalidate") !== undefined ) {
validator.cancelSubmit = true;
}
});
// validate the form on submit
this.submit( function( event ) {
if ( validator.settings.debug ) {
// prevent form submit to be able to see console output
event.preventDefault();
}
function handle() {
var hidden;
if ( validator.settings.submitHandler ) {
if ( validator.submitButton ) {
// insert a hidden input as a replacement for the missing submit button
hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val( $
(validator.submitButton).val() ).appendTo(validator.currentForm);
}
validator.settings.submitHandler.call( validator, validator.currentForm, event );
if ( validator.submitButton ) {
// and clean up afterwards; thanks to no-block-scope, hidden can be referenced
hidden.remove();
}
return false;
}
return true;
}
// prevent submit for invalid forms or custom submit handlers
if ( validator.cancelSubmit ) {
validator.cancelSubmit = false;
return handle();
}
if ( validator.form() ) {
if ( validator.pendingRequest ) {
validator.formSubmitted = true;
return false;
}
return handle();
} else {
validator.focusInvalid();
return false;
}
});
}
return validator;
}
14 (FOURTEEN!) ifs
function validate( options ) {
// if nothing is selected, return nothing; can't chain anyway
if ( !this.length ) {
if ( options && options.debug && window.console ) {
console.warn( "Nothing selected, can't validate, returning nothing." );
}
return;
}
// check if a validator for this form was already created
var validator = $.data( this[0], "validator" );
if ( validator ) {
return validator;
}
// Add novalidate tag if HTML5.
this.attr( "novalidate", "novalidate" );
validator = new $.validator( options, this[0] );
$.data( this[0], "validator", validator );
if ( validator.settings.onsubmit ) {
this.validateDelegate( ":submit", "click", function( event ) {
if ( validator.settings.submitHandler ) {
validator.submitButton = event.target;
}
// allow suppressing validation by adding a cancel class to the submit button
if ( $(event.target).hasClass("cancel") ) {
validator.cancelSubmit = true;
}
// allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
if ( $(event.target).attr("formnovalidate") !== undefined ) {
validator.cancelSubmit = true;
}
});
// validate the form on submit
this.submit( function( event ) {
if ( validator.settings.debug ) {
// prevent form submit to be able to see console output
event.preventDefault();
}
function handle() {
var hidden;
if ( validator.settings.submitHandler ) {
if ( validator.submitButton ) {
// insert a hidden input as a replacement for the missing submit button
hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val( $
(validator.submitButton).val() ).appendTo(validator.currentForm);
}
validator.settings.submitHandler.call( validator, validator.currentForm, event );
if ( validator.submitButton ) {
// and clean up afterwards; thanks to no-block-scope, hidden can be referenced
hidden.remove();
}
return false;
}
return true;
}
// prevent submit for invalid forms or custom submit handlers
if ( validator.cancelSubmit ) {
validator.cancelSubmit = false;
return handle();
}
if ( validator.form() ) {
if ( validator.pendingRequest ) {
validator.formSubmitted = true;
return false;
}
return handle();
} else {
validator.focusInvalid();
return false;
}
});
}
return validator;
}
are comments a bad thing?
TIp #2
Code should talk to you
_$ = (function(_) {
return {
pub: function(a, b, c, d) {
for (d=-1, c=[].concat(_[a]); c[++d];) c[d](b)
},
sub: function(a, b) {
(_[a] || (_[a] = [])).push(b)
}
}
})({})
_$ = (function(_) {
return {
pub: function(a, b, c, d) {
for (d=-1, c=[].concat(_[a]); c[++d];) c[d](b)
},
sub: function(a, b) {
(_[a] || (_[a] = [])).push(b)
}
}
})({})
#140bytes
_$ = (function() {
var registered = {};
return {
pub: function(event, memo) {
if (registered[event] instanceof Array){
var handlers = [].concat(registered[event]);
for (var i=0, handler; (handler = handlers[i]); i++){
handler.call(this, memo);
}
}
},
sub: function(event, handler) {
if (typeof registered[event] === "undefined"){
registered[event] = [];
}
registered[event].push(handler);
}
};
})();
don’t use comments as an
excuse to write bad code
//used translate3d to trigger hardware acceleration in webViews
//http://www.youtube.com/watch?v=IKl78ZgJzm4
.animated {
translate: translate3d(0,0,0)
}
/**
* Returns a unique ID for use in HTML id attribute.
* @param {String/Number} nr A name or number of the ID.
* @param {String} [prefix="id-"] The prefix for the ID.
* @return {String} the new ID
*/
function createId(nr, prefix){
//TODO implementation
}
//used translate3d to trigger hardware acceleration in webViews
//http://www.youtube.com/watch?v=IKl78ZgJzm4
.animated {
translate: translate3d(0,0,0)
}
/**
* Returns a unique ID for use in HTML id attribute.
* @param {String/Number} nr A name or number of the ID.
* @param {String} [prefix="id-"] The prefix for the ID.
* @return {String} the new ID
*/
function createId(nr, prefix){
//TODO implementation
}
un-avoidable
hacks explanation
//used translate3d to trigger hardware acceleration in webViews
//http://www.youtube.com/watch?v=IKl78ZgJzm4
.animated {
translate: translate3d(0,0,0)
}
/**
* Returns a unique ID for use in HTML id attribute.
* @param {String/Number} nr A name or number of the ID.
* @param {String} [prefix="id-"] The prefix for the ID.
* @return {String} the new ID
*/
function createId(nr, prefix){
//TODO implementation
}
un-avoidable
hacks explanationAUTOMATED DOC
GENERATION
//used translate3d to trigger hardware acceleration in webViews
//http://www.youtube.com/watch?v=IKl78ZgJzm4
.animated {
translate: translate3d(0,0,0)
}
/**
* Returns a unique ID for use in HTML id attribute.
* @param {String/Number} nr A name or number of the ID.
* @param {String} [prefix="id-"] The prefix for the ID.
* @return {String} the new ID
*/
function createId(nr, prefix){
//TODO implementation
}
un-avoidable
hacks explanationAUTOMATED DOC
GENERATION
TODOs
TIp #3
Code should have boundaries
Single
responsibility
principle
your best tool
against Zombie Code
since1902
(guaranteed 20 years)
No global
pollution
http://leosabanganii.blogspot.co.uk/2012/10/zombie-dressed-activists-protest.html
No coupling
http://leosabanganii.blogspot.co.uk/2012/10/zombie-dressed-activists-protest.html
http://ajandcharli.blogspot.co.uk/2011/05/we-dont-do-dead-people.html
worst case smell
worst case smell
Long methods
worst case smell
Long methods
Deep Level of Indentation
worst case smell
Long methods
Deep Level of Indentation
Hard to tell what it does
worst case smell
Long methods
Deep Level of Indentation
Hard to tell what it does
Lack of portability
worst case smell
Long methods
Deep Level of Indentation
Hard to tell what it does
Lack of portability
Hardcoded style/templating
worst case smell
Long methods
Deep Level of Indentation
Hard to tell what it does
Lack of portability
Hardcoded style/templating
Logic block duplication
worst case smell
Long methods
Deep Level of Indentation
Hard to tell what it does
Lack of portability
Hardcoded style/templating
Logic block duplication
Callback hell
And now what?
Play cool!
Basically
Quarantine
Basically
Quarantine
QUARANTINE
Most teams are trying to stop further
spread only through quarantines. It's a good
short-term solution, but it won't prevent
long-term population loss.
http://cdmx.it/quarantinequote
The broken window
“Don't leave "broken windows" (bad
designs, wrong decisions, or poor code)
unrepaired. Fix each one as soon as it is
discovered.”
Programming is insanely detail oriented, and perhaps this is why:
if you're not on top of the details, the perception is that things
are out of control, and it's only a matter of time before your
project spins out of control. Maybe we should be sweating the
small stuff.
Jeff Atwood
http://www.codinghorror.com/blog/2005/06/the-broken-window-theory.html
The broken window
Maybe we should be sweating
the small stuff.
Jeff Atwood
http://www.codinghorror.com/blog/2005/06/the-broken-window-theory.html
The broken window
Isolate the Zombies
define style guidelines
function Zombie(personName)
{
function do_something() {
console.log(personName + " just ate a brain!");
}
return {
doSomethingZombiesDo: do_something
};
}
var adam = new Zombie("Adam");
adam.doSomethingZombiesDo();
function Zombie(personName)
{
function do_something() {
console.log(personName + " just ate a brain!");
}
return {
doSomethingZombiesDo: do_something
};
}
var adam = new Zombie("Adam");
adam.doSomethingZombiesDo();
function Zombie(personName)
{
function do_something() {
console.log(personName + " just ate a brain!");
}
return {
doSomethingZombiesDo: do_something
};
}
var adam = new Zombie("Adam");
adam.doSomethingZombiesDo();
function Zombie(personName)
{
function do_something() {
console.log(personName + " just ate a brain!");
}
return {
doSomethingZombiesDo: do_something
};
}
var adam = new Zombie("Adam");
adam.doSomethingZombiesDo();
define style guidelines
start linting your code
Inversion of control freakness
AM I A CONTROL FREAK?
start testing your code
Unit or Functional?
Do both
What to test
Unit testing is
supposed to test a
single atomic “unit” of
functionality without
dependencies on
anything else
What to test
Unit testing is
supposed to test a
single atomic “unit” of
functionality without
dependencies on
anything else
This is where you start
to run into serious
dependency problems
due to the interrelation
HTML and CSS
What to test
Unit testing is
supposed to test a
single atomic “unit” of
functionality without
dependencies on
anything else
This is where you start
to run into serious
dependency problems
due to the interrelation
HTML and CSS
What do you test?
Usually how the user
interface responds to
user input.
Actually, the realm of
functional testing
No matter which toolset
Grunt
PhantomJS
JsTestDriver
Buster.js
Karma
Chutzpah
Testem
Qunit
Mocha
Jasmine
No matter which toolset
Grunt
PhantomJS
JsTestDriver
Buster.js
Karma
Chutzpah
Testem
Qunit
Mocha
Jasmine
As long as it can be automated
share
identify
build
make it
continuous
Make it part of the process
Make it part of the process
http://rosarioconsulting.net/inspiredtoeducate/?p=706 http://powerbuilder.us/
Estimate testing
http://malyn.edublogs.org/2011/10/16/process-tools-people/
Make it part of the process
Do code review
http://rosarioconsulting.net/inspiredtoeducate/?p=706 http://powerbuilder.us/
http://malyn.edublogs.org/2011/10/16/process-tools-people/
Make it part of the process
http://rosarioconsulting.net/inspiredtoeducate/?p=706 http://powerbuilder.us/
Involve people
http://malyn.edublogs.org/2011/10/16/process-tools-people/
Fear the living? DON’T
The team
DEVOPS PRODUCT OWNER
qa
QA
QA
Crucial role in the
process
QA
Crucial role in the
process
Quality should be your
goal too
QA
Crucial role in the
process
Quality should be your
goal too
Get help for functional
test coverage not to
screw up refactoring
Devops
Devops
The tough guy
Devops
The tough guy
It could be hard to deal
with
Devops
The tough guy
It could be hard to deal
with
Get help setting up the
automated process
Product owner
Product owner
The less interested in
code itself
Product owner
The less interested in
code itself
Bring numbers, not
theories
Product owner
The less interested in
code itself
Bring numbers, not
theories
Get help not wasting
time, staying focused on
functionalities
Others in the team
juniors
externallobbyist
Juniors
Juniors
Pair with them, code
review their (and your)
code
Juniors
Pair with them, code
review their (and your)
code
Involve them during the
whole process definition
Juniors
Pair with them, code
review their (and your)
code
Involve them during the
whole process definition
Get help keeping things
easy and accessible
Lobbyists
Lobbyists
They will slow you
down, your brain will be
more prone to be eaten
Lobbyists
They will slow you
down, your brain will be
more prone to be eaten
Redirect them to the
product owner
Basically
KILL ‘EM ALL (AGAIN?)
Basically
KILL ‘EM ALL (AGAIN?)
KILL ‘EM ALL (AGAIN?)
“Nothing is impossible to kill.”
Mira Grant, Feed
but
“Without requirements or design,
programming is the art of adding bugs
to an empty text file”
Louis Srygley
Design for your goal
Design for your goal
Modular Architecture
Scalable JavaScript
Application
Architecture
by Nicholas Zakas
core.register("module-name", function(sandbox){
return {
init:function(){
},
destroy:function(){
}
};
});
core.register("module-name", function(sandbox){
return {
init:function(){
},
destroy:function(){
}
};
});
core.register("module-name", function(sandbox){
return {
init:function(){
},
destroy:function(){
}
};
});
core.register("module-name", function(sandbox){
return {
init:function(){
var user = sandbox.getUser();
},
destroy:function(){
}
};
});
core.register("module-name", function(sandbox){
return {
init:function(){
var user = sandbox.getUser();
},
destroy:function(){
}
};
});
core.register('module-name', function(sandbox){
return {
init:function(config){
console.log(config.id);
}
};
});
core.configure('module-name', {
id: 'container',
});
core.start('module-name');
core.stop('module-name');
core.register('module-name', function(sandbox){
return {
init:function(config){
console.log(config.id);
}
};
});
core.configure('module-name', {
id: 'container',
});
core.start('module-name');
core.stop('module-name');
core.register('module-name', function(sandbox){
return {
init:function(config){
console.log(config.id);
}
};
});
core.configure('module-name', {
id: 'container',
});
core.start('module-name');
core.stop('module-name');
core.register('module-name', function(sandbox){
return {
init:function(config){
console.log(config.id);
}
};
});
core.configure('module-name', {
id: 'container',
});
core.start('module-name');
core.stop('module-name');
core.register('module-name', function(sandbox){
return {
init:function(config){
console.log(config.id);
}
};
});
core.configure('module-name', {
id: 'container',
});
core.start('module-name');
core.stop('module-name');
core.register('module-name', function(sandbox){
return {
init:function(config){
console.log(config.id);
}
};
});
core.configure('module-name', {
id: 'container',
});
core.start('module-name');
core.stop('module-name');
Event Driven Pattern
core.register("module-name", function(sandbox){
return {
init:function(){
sandbox.layer("an error occured");
}
};
});
core.register("module-name", function(sandbox){
return {
init:function(){
sandbox.layer("an error occured");
}
};
});
sandbox.layer("an error occured");
sandbox.publish("error", {
msg: "an error occured"
});
sandbox.publish("error", {
msg: "an error occured"
});
core.register("errManager", function(sandbox){
return {
init:function(){
sandbox.subscribe("error", function(err) {
console.log(err.msg)
});
}
};
});
sandbox.publish("error", {
msg: "an error occured"
});
core.register("errManager", function(sandbox){
return {
init:function(){
sandbox.subscribe("error", function(err) {
console.log(err.msg)
});
}
};
});
sandbox.publish("error", {
msg: "an error occured"
});
core.register("errManager", function(sandbox){
return {
init:function(){
sandbox.subscribe("error", function(err) {
console.log(err.msg)
});
}
};
});
sandbox.publish("error", {
msg: "an error occured"
});
core.register("errManager", function(sandbox){
return {
init:function(){
sandbox.subscribe("error", function(err) {
console.log(err.msg)
});
}
};
});
sandbox.publish("error", {
msg: "an error occured"
});
core.register("errManager", function(sandbox){
return {
init:function(){
sandbox.subscribe("error", function(err) {
console.log(err.msg)
});
}
};
});
sandbox.publish("error", {
msg: "an error occured"
});
core.register("errManager", function(sandbox){
return {
init:function(){
sandbox.subscribe("error", function(err) {
console.log(err.msg)
});
}
};
});
sandbox.publish("error", {
msg: "an error occured"
});
core.register("errManager", function(sandbox){
return {
init:function(){
sandbox.subscribe("error", function(err) {
console.log(err.msg)
});
}
};
});
sandbox.publish("error", {
msg: "an error occured"
});
core.register("errManager", function(sandbox){
return {
init:function(){
sandbox.subscribe("error", function(err) {
console.log(err.msg)
});
}
};
});
sandbox.subscribe("error", function(payload){
console.log(payload.msg);
});
Advantages
sandbox.subscribe("error", function(payload){
console.log(payload.msg);
});
Advantages
SEMANTIC
sandbox.subscribe("error", function(payload){
console.log(payload.msg);
});
Advantages
SEMANTIC
flexibility
Advantages
DECOUPLING
“The key is to acknowledge from the
start that you have no idea how this will
grow.When you accept that you don’t
know everything, you begin to design
the system defensively.”
Nicholas Zakas
Overengineering?
AMD
icon by http://www.deleket.com/
jQuery
Mustache
Libraries Plugins Your scripts
icon by http://www.deleket.com/
jQuery
Mustache
Libraries Plugins Your scripts
<script src="jquery.min.js"></script>
<script src="mustache.js"></script>
<?php if ($env == "prod") : ?>
<script src="my-code-bundle.js"></script>
<?php else: ?>
<script src="jquery.plugin_1.js"></script>
<script src="jquery.plugin_2.js"></script>
<script src="my-code_1.js"></script>
<script src="my-code_2.js"></script>
<script src="my-code_3.js"></script>
<script src="my-code_4.js"></script>
<script src="my-code_5.js"></script>
<?php endif; ?>
var MyNamespace = {};
MyNamespace.MyAwesomeLibrary = function() {
//implementation
};
MyNamespace.AnotherCoolOne = function() {
//implementation
};
MyNamespace.SlightlyCrappyLibrary = function() {
//implementation
};
MyNamespace.BestLibEver = function() {
//implementation
};
//API: define(id?, dependencies?, factory);
define("My-Module", ["Another-Module"], function(AnotherModule){
// Do Something
});
one define to rule them all
//API: define(id?, dependencies?, factory);
define("My-Module", ["Another-Module"], function(AnotherModule){
// Do Something
});
one define to rule them all
//app/config.js
define([], function() {
return {
url: "http://whatever.it/is/",
debug: true
};
});
//app/config.js
define([], function() {
return {
url: "http://whatever.it/is/",
debug: true
};
});
//app/config.js
define({
url: "http://whatever.it/is/",
debug: true
});
//app/config.js
define([], function() {
return {
url: "http://whatever.it/is/",
debug: true
};
});
//app/config.js
define({
url: "http://whatever.it/is/",
debug: true
});
//app/config.js
define([], function() {
return {
url: "http://whatever.it/is/",
debug: true
};
});
//app/config.js
define({
url: "http://whatever.it/is/",
debug: true
});
//app/myProduct.js
define(["app/config"], function(config) {
return function(id){
return {
getProductUrl: function(){
var prodPath = config.url + "product/" + id;
if (config.debug){
console.log(prodPath)
}
return prodPath;
}
};
};
});
//app/myProduct.js
define(["app/config"], function(config) {
return function(id){
return {
getProductUrl: function(){
var prodPath = config.url + "product/" + id;
if (config.debug){
console.log(prodPath)
}
return prodPath;
}
};
};
});
//app/myProduct.js
define(["app/config"], function(config) {
return function(id){
return {
getProductUrl: function(){
var prodPath = config.url + "product/" + id;
if (config.debug){
console.log(prodPath)
}
return prodPath;
}
};
};
});
//app/myProduct.js
define(["app/config"], function(config) {
return function(id){
return {
getProductUrl: function(){
var prodPath = config.url + "product/" + id;
if (config.debug){
console.log(prodPath)
}
return prodPath;
}
};
};
});
//app/myProduct.js
define(["app/config"], function(config) {
return function(id){
return {
getProductUrl: function(){
var prodPath = config.url + "product/" + id;
if (config.debug){
console.log(prodPath)
}
return prodPath;
}
};
};
});
//app/myProduct.js
define(["app/config"], function(config) {
return function(id){
return {
getProductUrl: function(){
var prodPath = config.url + "product/" + id;
if (config.debug){
console.log(prodPath)
}
return prodPath;
}
};
};
});
//app/myProduct.js
define(["app/config"], function(config) {
return function(id){
return {
getProductUrl: function(){
var prodPath = config.url + "product/" + id;
if (config.debug){
console.log(prodPath)
}
return prodPath;
}
};
};
});
//app/myProduct.js
define(["app/config"], function(config) {
return function(id){
return {
getProductUrl: function(){
var prodPath = config.url + "product/" + id;
if (config.debug){
console.log(prodPath)
}
return prodPath;
}
};
};
});
//app/myProduct.js
define(["app/config"], function(config) {
return function(id){
return {
getProductUrl: function(){
var prodPath = config.url + "product/" + id;
if (config.debug){
console.log(prodPath)
}
return prodPath;
}
};
};
});
<script data-main="app/main" src="require.js"></script>
<script data-main="app/main" src="require.js"></script>
//app/main.js
require(["jQuery", "app/myProduct"], function($, Product) {
$(".product").on("click", function(){
var prodID = $(this).data("id");
var prod = new Product(prodID);
document.location.href = prod.getProductUrl();
})
});
<script data-main="app/main" src="require.js"></script>
//app/main.js
require(["jQuery", "app/myProduct"], function($, Product) {
$(".product").on("click", function(){
var prodID = $(this).data("id");
var prod = new Product(prodID);
document.location.href = prod.getProductUrl();
})
});
<script data-main="app/main" src="require.js"></script>
//app/main.js
require(["jQuery", "app/myProduct"], function($, Product) {
$(".product").on("click", function(){
var prodID = $(this).data("id");
var prod = new Product(prodID);
document.location.href = prod.getProductUrl();
})
});
<script data-main="app/main" src="require.js"></script>
//app/main.js
require(["jQuery", "app/myProduct"], function($, Product) {
$(".product").on("click", function(){
var prodID = $(this).data("id");
var prod = new Product(prodID);
document.location.href = prod.getProductUrl();
})
});
<script data-main="app/main" src="require.js"></script>
//app/main.js
require(["jQuery", "app/myProduct"], function($, Product) {
$(".product").on("click", function(){
var prodID = $(this).data("id");
var prod = new Product(prodID);
document.location.href = prod.getProductUrl();
})
});
Pulling all together
define(function(){
'use strict';
return function(sandbox){
//the logic of the module
function doSomething(){
//do something
}
return {
init:function(config){
//the initialization code
sandbox.subscribe('myEventName', doSomething)
},
destroy: function(){
//optional destroy method
}
};
};
});
define(function(){
'use strict';
return function(sandbox){
//the logic of the module
function doSomething(){
//do something
}
return {
init:function(config){
//the initialization code
sandbox.subscribe('myEventName', doSomething)
},
destroy: function(){
//optional destroy method
}
};
};
});
define(function(){
'use strict';
return function(sandbox){
//the logic of the module
function doSomething(){
//do something
}
return {
init:function(config){
//the initialization code
sandbox.subscribe('myEventName', doSomething)
},
destroy: function(){
//optional destroy method
}
};
};
});
define(function(){
'use strict';
return function(sandbox){
//the logic of the module
function doSomething(){
//do something
}
return {
init:function(config){
//the initialization code
sandbox.subscribe('myEventName', doSomething)
},
destroy: function(){
//optional destroy method
}
};
};
});
define(function(){
'use strict';
return function(sandbox){
//the logic of the module
function doSomething(){
//do something
}
return {
init:function(config){
//the initialization code
sandbox.subscribe('myEventName', doSomething)
},
destroy: function(){
//optional destroy method
}
};
};
});
require(["akase"], function(core) {
core.start("module1");
core.start("module2", {
config: {
debug: true
}
});
core.start("module3", { event: "audio:stop" });
});
require(["akase"], function(core) {
core.start("module1");
core.start("module2", {
config: {
debug: true
}
});
core.start("module3", { event: "audio:stop" });
});
require(["akase"], function(core) {
core.start("module1");
core.start("module2", {
config: {
debug: true
}
});
core.start("module3", { event: "audio:stop" });
});
require(["akase"], function(core) {
core.start("module1");
core.start("module2", {
config: {
debug: true
}
});
core.start("module3", { event: "audio:stop" });
});
require(["akase"], function(core) {
core.start("module1");
core.start("module2", {
config: {
debug: true
}
});
core.start("module3", { event: "audio:stop" });
});
ākāśe
sanskrit for "in the sky"/"to the sky"
https://github.com/cedmax/akase
No such this thing!
Basically
Happy Endings?
Basically
Happy Endings?
you are going to write zombie code
zombie code will always be out there
live with it, embrace it, have a strategy to deal with it

Contenu connexe

En vedette

En vedette (7)

API first approach for frontend developers
API first approach for frontend developersAPI first approach for frontend developers
API first approach for frontend developers
 
Использование API Яндекс.Карт
Использование API Яндекс.КартИспользование API Яндекс.Карт
Использование API Яндекс.Карт
 
Testing web APIs
Testing web APIsTesting web APIs
Testing web APIs
 
«The Illusion of Time. When 60 sec is not 1 minute»​
«The Illusion of Time. When 60 sec is not 1 minute»​«The Illusion of Time. When 60 sec is not 1 minute»​
«The Illusion of Time. When 60 sec is not 1 minute»​
 
Rich Media Banners — Take Your Knowledge to the Next Level
Rich Media Banners — Take Your Knowledge to the Next LevelRich Media Banners — Take Your Knowledge to the Next Level
Rich Media Banners — Take Your Knowledge to the Next Level
 
Writing RESTful web services using Node.js
Writing RESTful web services using Node.jsWriting RESTful web services using Node.js
Writing RESTful web services using Node.js
 
Как верстать сайты быстрее, чем их рисуют
Как верстать сайты быстрее, чем их рисуютКак верстать сайты быстрее, чем их рисуют
Как верстать сайты быстрее, чем их рисуют
 

Plus de FDConf

Антон Киршанов - «Квант изменения. Реактивные реакции на React.
Антон Киршанов - «Квант изменения. Реактивные реакции на React.Антон Киршанов - «Квант изменения. Реактивные реакции на React.
Антон Киршанов - «Квант изменения. Реактивные реакции на React.
FDConf
 
Redux. From twitter hype to production
Redux. From twitter hype to productionRedux. From twitter hype to production
Redux. From twitter hype to production
FDConf
 

Plus de FDConf (20)

Антон Киршанов - «Квант изменения. Реактивные реакции на React.
Антон Киршанов - «Квант изменения. Реактивные реакции на React.Антон Киршанов - «Квант изменения. Реактивные реакции на React.
Антон Киршанов - «Квант изменения. Реактивные реакции на React.
 
Игорь Еростенко - Создаем виртуальный тур
Игорь Еростенко - Создаем виртуальный турИгорь Еростенко - Создаем виртуальный тур
Игорь Еростенко - Создаем виртуальный тур
 
Илья Климов - Reason: маргиналы против хайпа
Илья Климов - Reason: маргиналы против хайпаИлья Климов - Reason: маргиналы против хайпа
Илья Климов - Reason: маргиналы против хайпа
 
Максим Щепелин - Доставляя веб-контент в игру
Максим Щепелин - Доставляя веб-контент в игруМаксим Щепелин - Доставляя веб-контент в игру
Максим Щепелин - Доставляя веб-контент в игру
 
Александр Черноокий - Как правило "победитель получает все" работает и не раб...
Александр Черноокий - Как правило "победитель получает все" работает и не раб...Александр Черноокий - Как правило "победитель получает все" работает и не раб...
Александр Черноокий - Как правило "победитель получает все" работает и не раб...
 
Михаил Волчек - Что такое Цифровая мастерская?
Михаил Волчек - Что такое Цифровая мастерская?Михаил Волчек - Что такое Цифровая мастерская?
Михаил Волчек - Что такое Цифровая мастерская?
 
Radoslav Stankov - Handling GraphQL with React and Apollo
Radoslav Stankov - Handling GraphQL with React and ApolloRadoslav Stankov - Handling GraphQL with React and Apollo
Radoslav Stankov - Handling GraphQL with React and Apollo
 
Виктор Русакович - Выборы, выборы, все фреймворки… приторны
Виктор Русакович - Выборы, выборы, все фреймворки… приторныВиктор Русакович - Выборы, выборы, все фреймворки… приторны
Виктор Русакович - Выборы, выборы, все фреймворки… приторны
 
Slobodan Stojanovic - 8 1/2 things about serverless
Slobodan Stojanovic - 8 1/2 things about serverless Slobodan Stojanovic - 8 1/2 things about serverless
Slobodan Stojanovic - 8 1/2 things about serverless
 
Тимофей Лавренюк - Почему мне зашел PWA?
Тимофей Лавренюк - Почему мне зашел PWA?Тимофей Лавренюк - Почему мне зашел PWA?
Тимофей Лавренюк - Почему мне зашел PWA?
 
Если у вас нету тестов...
Если у вас нету тестов...Если у вас нету тестов...
Если у вас нету тестов...
 
Migrate your React.js application from (m)Observable to Redux
Migrate your React.js application from (m)Observable to ReduxMigrate your React.js application from (m)Observable to Redux
Migrate your React.js application from (m)Observable to Redux
 
Dart: питание и сила для вашего проекта
Dart: питание и сила для вашего проектаDart: питание и сила для вашего проекта
Dart: питание и сила для вашего проекта
 
Scalable Angular 2 Application Architecture
Scalable Angular 2 Application ArchitectureScalable Angular 2 Application Architecture
Scalable Angular 2 Application Architecture
 
JavaScript: прошлое, настоящее и будущее.
JavaScript: прошлое, настоящее и будущее.JavaScript: прошлое, настоящее и будущее.
JavaScript: прошлое, настоящее и будущее.
 
CSSO — сжимаем CSS
CSSO — сжимаем CSSCSSO — сжимаем CSS
CSSO — сжимаем CSS
 
Redux. From twitter hype to production
Redux. From twitter hype to productionRedux. From twitter hype to production
Redux. From twitter hype to production
 
Будь первым
Будь первымБудь первым
Будь первым
 
"Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native ""Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native "
 
"Пиринговый веб на JavaScript"
"Пиринговый веб на JavaScript""Пиринговый веб на JavaScript"
"Пиринговый веб на JavaScript"
 

Dernier

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
Earley Information Science
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
Enterprise Knowledge
 

Dernier (20)

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 

ZombieCode