SlideShare ist ein Scribd-Unternehmen logo
1 von 196
Downloaden Sie, um offline zu lesen
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

Weitere ähnliche Inhalte

Andere mochten auch

API first approach for frontend developers
API first approach for frontend developersAPI first approach for frontend developers
API first approach for frontend developersFDConf
 
Использование API Яндекс.Карт
Использование API Яндекс.КартИспользование API Яндекс.Карт
Использование API Яндекс.КартFDConf
 
Testing web APIs
Testing web APIsTesting web APIs
Testing web APIsFDConf
 
«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»​FDConf
 
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 LevelFDConf
 
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.jsFDConf
 
Как верстать сайты быстрее, чем их рисуют
Как верстать сайты быстрее, чем их рисуютКак верстать сайты быстрее, чем их рисуют
Как верстать сайты быстрее, чем их рисуютFDConf
 

Andere mochten auch (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
 
Как верстать сайты быстрее, чем их рисуют
Как верстать сайты быстрее, чем их рисуютКак верстать сайты быстрее, чем их рисуют
Как верстать сайты быстрее, чем их рисуют
 

Mehr von FDConf

Антон Киршанов - «Квант изменения. Реактивные реакции на React.
Антон Киршанов - «Квант изменения. Реактивные реакции на React.Антон Киршанов - «Квант изменения. Реактивные реакции на React.
Антон Киршанов - «Квант изменения. Реактивные реакции на React.FDConf
 
Игорь Еростенко - Создаем виртуальный тур
Игорь Еростенко - Создаем виртуальный турИгорь Еростенко - Создаем виртуальный тур
Игорь Еростенко - Создаем виртуальный турFDConf
 
Илья Климов - Reason: маргиналы против хайпа
Илья Климов - Reason: маргиналы против хайпаИлья Климов - Reason: маргиналы против хайпа
Илья Климов - Reason: маргиналы против хайпаFDConf
 
Максим Щепелин - Доставляя веб-контент в игру
Максим Щепелин - Доставляя веб-контент в игруМаксим Щепелин - Доставляя веб-контент в игру
Максим Щепелин - Доставляя веб-контент в игруFDConf
 
Александр Черноокий - Как правило "победитель получает все" работает и не раб...
Александр Черноокий - Как правило "победитель получает все" работает и не раб...Александр Черноокий - Как правило "победитель получает все" работает и не раб...
Александр Черноокий - Как правило "победитель получает все" работает и не раб...FDConf
 
Михаил Волчек - Что такое Цифровая мастерская?
Михаил Волчек - Что такое Цифровая мастерская?Михаил Волчек - Что такое Цифровая мастерская?
Михаил Волчек - Что такое Цифровая мастерская?FDConf
 
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 ApolloFDConf
 
Виктор Русакович - Выборы, выборы, все фреймворки… приторны
Виктор Русакович - Выборы, выборы, все фреймворки… приторныВиктор Русакович - Выборы, выборы, все фреймворки… приторны
Виктор Русакович - Выборы, выборы, все фреймворки… приторныFDConf
 
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 FDConf
 
Тимофей Лавренюк - Почему мне зашел PWA?
Тимофей Лавренюк - Почему мне зашел PWA?Тимофей Лавренюк - Почему мне зашел PWA?
Тимофей Лавренюк - Почему мне зашел PWA?FDConf
 
Если у вас нету тестов...
Если у вас нету тестов...Если у вас нету тестов...
Если у вас нету тестов...FDConf
 
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 ReduxFDConf
 
Dart: питание и сила для вашего проекта
Dart: питание и сила для вашего проектаDart: питание и сила для вашего проекта
Dart: питание и сила для вашего проектаFDConf
 
Scalable Angular 2 Application Architecture
Scalable Angular 2 Application ArchitectureScalable Angular 2 Application Architecture
Scalable Angular 2 Application ArchitectureFDConf
 
JavaScript: прошлое, настоящее и будущее.
JavaScript: прошлое, настоящее и будущее.JavaScript: прошлое, настоящее и будущее.
JavaScript: прошлое, настоящее и будущее.FDConf
 
CSSO — сжимаем CSS
CSSO — сжимаем CSSCSSO — сжимаем CSS
CSSO — сжимаем CSSFDConf
 
Redux. From twitter hype to production
Redux. From twitter hype to productionRedux. From twitter hype to production
Redux. From twitter hype to productionFDConf
 
Будь первым
Будь первымБудь первым
Будь первымFDConf
 
"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 "FDConf
 
"Пиринговый веб на JavaScript"
"Пиринговый веб на JavaScript""Пиринговый веб на JavaScript"
"Пиринговый веб на JavaScript"FDConf
 

Mehr von 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"
 

Kürzlich hochgeladen

From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rick Flair
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityIES VE
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesKari Kakkonen
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch TuesdayIvanti
 
Manual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditManual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditSkynet Technologies
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfIngrid Airi González
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesThousandEyes
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsRavi Sanghani
 

Kürzlich hochgeladen (20)

From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a reality
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examples
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch Tuesday
 
Manual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditManual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance Audit
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdf
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and Insights
 

ZombieCode