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

Javascript as a programming language - Paris Web

Javascript as a programming language - Paris Web

How to setup up a stable javascript continuous integration environment and why you need it. Through a real life example, the talk explains all the benefits of having a development process that brings real control over javascript codebase. A deep analysis of developer and webapps needs and of the tools that fit those requirements.

Paris Web (Paris, 14 October 2011)
@cedmax
http://cedmax.com

Marco Cedaro

October 14, 2011
Tweet

More Decks by Marco Cedaro

Other Decks in Programming

Transcript

  1. Javascript As A
    Programming Language

    View Slide

  2. Javascript As A
    Programming Language
    Versioning, Test Driven Development & Continuous Integration
    IS

    View Slide

  3. Javascript As A
    Programming Language
    Versioning, Test Driven Development & Continuous Integration
    IS

    View Slide

  4. Hello, who’s speaking?

    View Slide

  5. Hello, who’s speaking?
    Marco Cedaro
    @cedmax

    View Slide

  6. They said I am a...
    Frontend Cowboy
    Nicola Vitto Jr.
    Javascript Pervert
    Roberto Felter
    Perfect Stranger
    basically anyone else
    Hello, who’s speaking?
    Marco Cedaro
    @cedmax

    View Slide

  7. Actually I am:
    a Frontend Developer at
    Spreaker.com
    Hello, who’s speaking?
    Marco Cedaro
    @cedmax

    View Slide

  8. Actually I am:
    a Frontend Developer at
    Spreaker.com
    a conference organizer
    with From The Front
    Hello, who’s speaking?
    Marco Cedaro
    @cedmax

    View Slide

  9. Actually I am:
    a Frontend Developer at
    Spreaker.com
    a conference organizer
    with From The Front
    and a javascript pervert
    Hello, who’s speaking?
    Marco Cedaro
    @cedmax

    View Slide

  10. Bologna, Italy

    View Slide

  11. something in common with
    Robert Nyman

    View Slide

  12. something in common with
    Robert Nyman

    View Slide

  13. I believe I can fly

    View Slide

  14. I believe I can fly

    View Slide

  15. I believe I can fly
    Be brave. Take risks.
    Nothing can substitute
    experience.
    Paulo Coelho

    View Slide

  16. once upon a time

    View Slide

  17. we had no control
    once upon a time

    View Slide

  18. we had no control
    javascript was the land of the brave
    once upon a time

    View Slide

  19. we had no control
    javascript was the land of the brave
    we were fearless and unconscious
    once upon a time

    View Slide

  20. we had no control
    javascript was the land of the brave
    we were fearless and unconscious
    we were proud of being like that
    once upon a time

    View Slide

  21. just like them

    View Slide

  22. kitty hawk

    View Slide

  23. but life goes on

    View Slide

  24. web engineer
    had a very bad
    opinion of us
    once upon a time

    View Slide

  25. but it wasn't fair

    View Slide

  26. we didn't have IDEs & tools they did
    but it wasn't fair

    View Slide

  27. we didn't have IDEs & tools they did
    actually it was our own fault
    but it wasn't fair

    View Slide

  28. we didn't have IDEs & tools they did
    actually it was our own fault
    we were not ready
    but it wasn't fair

    View Slide

  29. we didn't have IDEs & tools they did
    actually it was our own fault
    we were not ready
    and javascript was neither
    but it wasn't fair

    View Slide

  30. but, again, life goes on...

    View Slide

  31. ...and on...

    View Slide

  32. and on..

    View Slide

  33. it's not about the language itself

    View Slide

  34. GREAT POWERS...

    View Slide

  35. Frontend developers
    have to claim their role
    in development roadmap and
    business strategy

    View Slide

  36. Javascript is a serious business

    View Slide

  37. how serious?

    View Slide

  38. something we can achieve
    less bandwidth and
    server load loading
    resources and content
    when needed

    View Slide

  39. something we can achieve
    less bandwidth and
    server load loading
    resources and content
    when needed
    performance boosts
    that can lead to better
    conversion rates

    View Slide

  40. something we can achieve
    less bandwidth and
    server load loading
    resources and content
    when needed
    performance boosts
    that can lead to better
    conversion rates
    cross platform
    development: less
    maintenance costs

    View Slide

  41. less bandwidth and
    server load loading
    resources and content
    when needed
    performance boosts
    that can lead to better
    conversion rates
    cross platform
    development: less
    maintenance costs
    money

    View Slide

  42. how serious?

    View Slide

  43. this serious

    View Slide

  44. what's missing?

    View Slide

  45. what's missing?

    View Slide

  46. what's missing?
    If I had nine of my fingers
    missing I wouldn't type any
    slower.
    Mitch Hedberg

    View Slide

  47. IDEs & Tools

    View Slide

  48. the attitude

    View Slide

  49. a strategy

    View Slide

  50. the small web agency
    The designer
    introduces a slider on
    some websites:
    ”it’s cool on apple store”.
    The developer gets a jQuery
    plugin online

    View Slide

  51. the small web agency
    The designer
    introduces a slider on
    some websites:
    ”it’s cool on apple store”.
    The developer gets a jQuery
    plugin online
    Major release of the
    most used browser.
    A small fix has been
    released, they have to change
    5 files in 5 different projects.

    View Slide

  52. the small web agency
    The designer
    introduces a slider on
    some websites:
    ”it’s cool on apple store”.
    The developer gets a jQuery
    plugin online
    Major release of the
    most used browser.
    A small fix has been
    released, they have to change
    5 files in 5 different projects.
    Oh damn! There’s no
    mouse wheel
    integration!
    should they ask for support
    or should they change the
    library by themself?

    View Slide

  53. am I the only one or there’s
    something wrong?

    View Slide

  54. the big corp
    The client-side
    architecture has been
    built on the most
    known and supported
    framework
    2006

    View Slide

  55. the big corp
    The client-side
    architecture has been
    built on the most
    known and supported
    framework
    2006
    Everything seems to be
    fine, except that the
    well known framework
    was being replaced by a
    powerful new one
    2008 - 2010

    View Slide

  56. the big corp
    The client-side
    architecture has been
    built on the most
    known and supported
    framework
    2006
    Everything seems to be
    fine, except that the
    well known framework
    was being replaced by a
    powerful new one
    2008 - 2010
    They were forced to
    change the whole
    codebase at once to
    reduce maintenance
    and development costs
    2011

    View Slide

  57. here we are again

    View Slide

  58. attitude, strategy...

    View Slide

  59. ...and foresight

    View Slide

  60. WARNING!

    View Slide

  61. continuous integration

    View Slide

  62. continuous integration

    View Slide

  63. continuous integration
    A software development
    practice where members of a
    team integrate their work
    frequently [...] to detect
    integration errors as quickly
    as possible.
    Martin Fowler

    View Slide

  64. I Build So Consistently

    View Slide

  65. I Build So Consistently
    identify

    View Slide

  66. I Build So Consistently
    identify
    write a build
    script

    View Slide

  67. I Build So Consistently
    share
    identify
    write a build
    script

    View Slide

  68. I Build So Consistently
    share
    identify
    write a build
    script
    make it
    continuous

    View Slide

  69. How can we take
    advantages from a
    continuous integration
    process?

    View Slide

  70. rationalize your workflow

    View Slide

  71. deploy stable versions

    View Slide

  72. Separate the codebase

    View Slide

  73. unit test your code

    View Slide

  74. basically

    View Slide

  75. basically

    View Slide

  76. basically
    ie7

    View Slide

  77. choose your tools

    View Slide

  78. choose your tools

    View Slide

  79. choose your tools
    A man cannot be too careful
    in the choice of his enemies
    Oscar Wilde

    View Slide

  80. View Slide

  81. JSHINT

    View Slide

  82. a code quality tool

    View Slide

  83. like Douglas Crockford's JSLint
    a code quality tool

    View Slide

  84. like Douglas Crockford's JSLint
    but
    a code quality tool

    View Slide

  85. like Douglas Crockford's JSLint
    but
    customizable
    a code quality tool

    View Slide

  86. a tool for stupid?

    View Slide

  87. JS HINT

    View Slide

  88. JS TEST DRIVER
    JS HINT

    View Slide

  89. once upon a time

    View Slide

  90. jsTestDriver

    View Slide

  91. jsTestDriver
    works from console

    View Slide

  92. jsTestDriver
    works from console
    runs a server

    View Slide

  93. jsTestDriver
    works from console
    runs a server
    opens browsers

    View Slide

  94. jsTestDriver
    works from console
    runs a server
    opens browsers
    runs test suites

    View Slide

  95. jsTestDriver
    works from console
    runs a server
    opens browsers
    runs test suites
    retrieves results in console

    View Slide

  96. build server

    View Slide

  97. build server

    View Slide

  98. build server

    View Slide

  99. how does testing works?

    View Slide

  100. have you seen Lost?

    View Slide

  101. how does it work?

    View Slide

  102. how does it work?
    write a test

    View Slide

  103. how does it work?
    write a test let it fail

    View Slide

  104. how does it work?
    write a test let it fail write the code

    View Slide

  105. how does it work?
    write a test let it fail write the code
    run the test
    again

    View Slide

  106. how does it work?
    write a test let it fail write the code
    run the test
    again
    refactor

    View Slide

  107. the environment

    View Slide

  108. It's the browser, baby

    View Slide

  109. It's the browser, baby

    View Slide

  110. The curious case of
    Javascript unit testing
    Unit testing is
    supposed to test a
    single atomic “unit” of
    functionality without
    dependencies on
    anything else

    View Slide

  111. The curious case of
    Javascript unit testing
    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
    with HTML and CSS

    View Slide

  112. The curious case of
    Javascript unit testing
    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
    with HTML and CSS
    What do you test?
    Usually how the user
    interface responds to
    user input.
    Actually, the realm of
    functional testing

    View Slide

  113. keep it real

    View Slide

  114. keep it real

    View Slide

  115. keep it real
    To all my homies working
    on the 9 to 5
    Shaggy

    View Slide

  116. #140bytes

    View Slide

  117. I used to work with these guys

    View Slide

  118. _$ = (function() {
    var registered = {};
    return {
    ! ! pub: function(event, memo) {
    ! ! ! if (registered[event] instanceof Array){
    ! ! ! ! var handlers = [].concat(registered[event]);
    ! ! ! ! for (var i=0, h; (h = handlers[i]); i++){
    ! ! ! ! ! h.call(this, memo);
    ! ! ! ! }
    ! ! ! }
    ! ! },
    ! ! sub: function(event, handler) {
    ! ! ! if (typeof registered[event] === "undefined"){
    ! ! ! ! registered[event] = [];
    ! ! ! }
    ! ! ! registered[event].push(handler);
    ! ! }
    };
    })();

    View Slide

  119. _$ = (function() {
    var registered = {};
    return {
    ! ! pub: function(event, memo) {
    ! ! ! if (registered[event] instanceof Array){
    ! ! ! ! var handlers = [].concat(registered[event]);
    ! ! ! ! for (var i=0, h; (h = handlers[i]); i++){
    ! ! ! ! ! h.call(this, memo);
    ! ! ! ! }
    ! ! ! }
    ! ! },
    ! ! sub: function(event, handler) {
    ! ! ! if (typeof registered[event] === "undefined"){
    ! ! ! ! registered[event] = [];
    ! ! ! }
    ! ! ! registered[event].push(handler);
    ! ! }
    };
    })();

    View Slide

  120. _$.sub("customEvent", function(obj) {
    ! //DO STUFF
    });
    _$.pub("customEvent");
    _$.pub("customEvent", { prop : "value" });

    View Slide

  121. _$.sub("customEvent", function(obj) {
    ! //DO STUFF
    });
    _$.pub("customEvent");
    _$.pub("customEvent", { prop : "value" });

    View Slide

  122. _$.sub("customEvent", function(obj) {
    ! //DO STUFF
    });
    _$.pub("customEvent");
    _$.pub("customEvent", { prop : "value" });

    View Slide

  123. _$ = (function() {
    var registered = {};
    return {
    ! ! pub: function(event, memo) {
    ! ! ! if (registered[event] instanceof Array){
    ! ! ! ! var handlers = [].concat(registered[event]);
    ! ! ! ! for (var i=0, h; (h = handlers[i]); i++){
    ! ! ! ! ! h.call(this, memo);
    ! ! ! ! }
    ! ! ! }
    ! ! },
    ! ! sub: function(event, handler) {
    ! ! ! if (typeof registered[event] === "undefined"){
    ! ! ! ! registered[event] = [];
    ! ! ! }
    ! ! ! registered[event].push(handler);
    ! ! }
    };
    })();

    View Slide

  124. _$ = (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)
    ! ! }
    ! }
    })({})

    View Slide

  125. _$ = (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

    View Slide

  126. _$ = (function() {
    var registered = {};
    return {
    ! ! pub: function(event, memo) {
    ! ! ! if (registered[event] instanceof Array){
    ! ! ! ! var handlers = [].concat(registered[event]);
    ! ! ! ! for (var i=0, h; (h = handlers[i]); i++){
    ! ! ! ! ! h.call(this, memo);
    ! ! ! ! }
    ! ! ! }
    ! ! },
    ! ! sub: function(event, handler) {
    ! ! ! if (typeof registered[event] === "undefined"){
    ! ! ! ! registered[event] = [];
    ! ! ! }
    ! ! ! registered[event].push(handler);
    ! ! }
    };
    })();

    View Slide

  127. _$ = (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

    View Slide

  128. _$ = (function() {
    var registered = {};
    return {
    ! ! pub: function(event, memo) {
    ! ! ! if (registered[event] instanceof Array){
    ! ! ! ! var handlers = [].concat(registered[event]);
    ! ! ! ! for (var i=0, h; (h = handlers[i]); i++){
    ! ! ! ! ! h.call(this, memo);
    ! ! ! ! }
    ! ! ! }
    ! ! },
    ! ! sub: function(event, handler) {
    ! ! ! if (typeof registered[event] === "undefined"){
    ! ! ! ! registered[event] = [];
    ! ! ! }
    ! ! ! registered[event].push(handler);
    ! ! }
    };
    })();

    View Slide

  129. _$ = (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

    View Slide

  130. _$ = (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

    View Slide

  131. [...]
    testPub: function(){! !
    ! ! var a = 0;!
    ! ! _$.sub('testNotify', function(){ a = 1; });
    ! ! _$.pub('testNotify');
    ! ! assertEquals(1, a);
    ! },
    ! ! !
    ! testNotifyWithMemo: function(){!!
    ! ! var a = 0 ;!
    ! ! _$.sub('testNotify', function(memo){
    ! ! ! ! a = memo.test;
    ! ! });
    ! ! _$.pub('testNotify', {test: 1});
    ! ! assertEquals(1, a);
    ! },
    [...]

    View Slide

  132. [...]
    testPub: function(){! !
    ! ! var a = 0;!
    ! ! _$.sub('testNotify', function(){ a = 1; });
    ! ! _$.pub('testNotify');
    ! ! assertEquals(1, a);
    ! },
    ! ! !
    ! testNotifyWithMemo: function(){!!
    ! ! var a = 0 ;!
    ! ! _$.sub('testNotify', function(memo){
    ! ! ! ! a = memo.test;
    ! ! });
    ! ! _$.pub('testNotify', {test: 1});
    ! ! assertEquals(1, a);
    ! },
    [...]

    View Slide

  133. [...]
    testPub: function(){! !
    ! ! var a = 0;!
    ! ! _$.sub('testNotify', function(){ a = 1; });
    ! ! _$.pub('testNotify');
    ! ! assertEquals(1, a);
    ! },
    ! ! !
    ! testNotifyWithMemo: function(){!!
    ! ! var a = 0 ;!
    ! ! _$.sub('testNotify', function(memo){
    ! ! ! ! a = memo.test;
    ! ! });
    ! ! _$.pub('testNotify', {test: 1});
    ! ! assertEquals(1, a);
    ! },
    [...]

    View Slide

  134. [...]
    testPub: function(){! !
    ! ! var a = 0;!
    ! ! _$.sub('testNotify', function(){ a = 1; });
    ! ! _$.pub('testNotify');
    ! ! assertEquals(1, a);
    ! },
    ! ! !
    ! testNotifyWithMemo: function(){!!
    ! ! var a = 0 ;!
    ! ! _$.sub('testNotify', function(memo){
    ! ! ! ! a = memo.test;
    ! ! });
    ! ! _$.pub('testNotify', {test: 1});
    ! ! assertEquals(1, a);
    ! },
    [...]

    View Slide

  135. [...]
    testPub: function(){! !
    ! ! var a = 0;!
    ! ! _$.sub('testNotify', function(){ a = 1; });
    ! ! _$.pub('testNotify');
    ! ! assertEquals(1, a);
    ! },
    ! ! !
    ! testNotifyWithMemo: function(){!!
    ! ! var a = 0 ;!
    ! ! _$.sub('testNotify', function(memo){
    ! ! ! ! a = memo.test;
    ! ! });
    ! ! _$.pub('testNotify', {test: 1});
    ! ! assertEquals(1, a);
    ! },
    [...]

    View Slide

  136. [...]
    testPub: function(){! !
    ! ! var a = 0;!
    ! ! _$.sub('testNotify', function(){ a = 1; });
    ! ! _$.pub('testNotify');
    ! ! assertEquals(1, a);
    ! },
    ! ! !
    ! testNotifyWithMemo: function(){!!
    ! ! var a = 0 ;
    ! ! _$.sub('testNotify', function(memo){
    ! ! ! ! a = memo.test;
    ! ! });
    ! ! _$.pub('testNotify', {test: 1});
    ! ! assertEquals(1, a);
    ! },
    [...]

    View Slide

  137. [...]
    testPub: function(){! !
    ! ! var a = 0;!
    ! ! _$.sub('testNotify', function(){ a = 1; });
    ! ! _$.pub('testNotify');
    ! ! assertEquals(1, a);
    ! },
    ! ! !
    ! testNotifyWithMemo: function(){!!
    ! ! var a = 0 ;!
    ! ! _$.sub('testNotify', function(memo){
    ! ! ! ! a = memo.test;
    ! ! });
    ! ! _$.pub('testNotify', {test: 1});
    ! ! assertEquals(1, a);
    ! },
    [...]

    View Slide

  138. easy, uh?

    View Slide

  139. you will, eventually

    View Slide

  140. JS TEST DRIVER
    JS HINT

    View Slide

  141. JS TEST DRIVER
    SINON.JS
    JS HINT

    View Slide

  142. a mock library

    View Slide

  143. a mock library
    SPIES
    a function that records
    arguments, return
    value, the value of this
    and exception thrown
    (if any) for all its calls.

    View Slide

  144. a mock library
    SPIES
    a function that records
    arguments, return
    value, the value of this
    and exception thrown
    (if any) for all its calls.
    STUBS
    functions (spies) with
    pre-programmed
    behavior.

    View Slide

  145. a mock library
    SPIES
    a function that records
    arguments, return
    value, the value of this
    and exception thrown
    (if any) for all its calls.
    STUBS
    functions (spies) with
    pre-programmed
    behavior.
    MOCKS
    functions (spies) with
    pre-programmed
    behavior (stubs) as well
    as pre-programmed
    expectations.

    View Slide

  146. [...]
    testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! var spy = sinon.spy(_$, 'watch');!
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! assertTrue(spy.calledWith('SysyemOn'));
    ! },
    ! ! !
    ! testMyLibLoggedNotLogged: function(){!!
    ! ! var stub = sinon.stub(User, 'isLogged');!
    ! ! stub.returns(true);
    ! ! //DO STUFF && ASSERTIONS
    ! ! stub.returns(false);
    ! ! //DO STUFF && ASSERTIONS
    ! },
    [...]

    View Slide

  147. [...]
    testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! var spy = sinon.spy(_$, 'watch');!
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! assertTrue(spy.calledWith('SystemOn'));
    ! },
    ! ! !
    ! testMyLibLoggedNotLogged: function(){!!
    ! ! var stub = sinon.stub(User, 'isLogged');!
    ! ! stub.returns(true);
    ! ! //DO STUFF && ASSERTIONS
    ! ! stub.returns(false);
    ! ! //DO STUFF && ASSERTIONS
    ! },
    [...]
    SPY

    View Slide

  148. [...]
    testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! var spy = sinon.spy(_$, 'watch');!
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! assertTrue(spy.calledWith('SystemOn'));
    ! },
    ! ! !
    ! testMyLibLoggedNotLogged: function(){!!
    ! ! var stub = sinon.stub(User, 'isLogged');!
    ! ! stub.returns(true);
    ! ! //DO STUFF && ASSERTIONS
    ! ! stub.returns(false);
    ! ! //DO STUFF && ASSERTIONS
    ! },
    [...]
    SPY

    View Slide

  149. [...]
    testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! var spy = sinon.spy(_$, 'watch');!
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! assertTrue(spy.calledWith('SystemOn'));
    ! },
    ! ! !
    ! testMyLibLoggedNotLogged: function(){!!
    ! ! var stub = sinon.stub(User, 'isLogged');!
    ! ! stub.returns(true);
    ! ! //DO STUFF && ASSERTIONS
    ! ! stub.returns(false);
    ! ! //DO STUFF && ASSERTIONS
    ! },
    [...]
    SPY

    View Slide

  150. [...]
    testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! var spy = sinon.spy(_$, 'watch');!
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! assertTrue(spy.calledWith('SystemOn'));
    ! },
    ! ! !
    ! testMyLibLoggedNotLogged: function(){!!
    ! ! var stub = sinon.stub(User, 'isLogged');!
    ! ! stub.returns(true);
    ! ! //DO STUFF && ASSERTIONS
    ! ! stub.returns(false);
    ! ! //DO STUFF && ASSERTIONS
    ! },
    [...]
    SPY

    View Slide

  151. [...]
    testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! var spy = sinon.spy(_$, 'watch');!
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! assertTrue(spy.calledWith('SystemOn'));
    ! },
    ! ! !
    ! testMyLibLoggedNotLogged: function(){!!
    ! ! var stub = sinon.stub(User, 'isLogged');!
    ! ! stub.returns(true);
    ! ! //DO STUFF && ASSERTIONS
    ! ! stub.returns(false);
    ! ! //DO STUFF && ASSERTIONS
    ! },
    [...]
    STUB

    View Slide

  152. [...]
    testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! var spy = sinon.spy(_$, 'watch');!
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! assertTrue(spy.calledWith('SystemOn'));
    ! },
    ! ! !
    ! testMyLibLoggedNotLogged: function(){!!
    ! ! var stub = sinon.stub(User, 'isLogged');!
    ! ! stub.returns(true);
    ! ! //DO STUFF && ASSERTIONS
    ! ! stub.returns(false);
    ! ! //DO STUFF && ASSERTIONS
    ! },
    [...]
    STUB

    View Slide

  153. [...]
    testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! var spy = sinon.spy(_$, 'watch');!
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! assertTrue(spy.calledWith('SystemOn'));
    ! },
    ! ! !
    ! testMyLibLoggedNotLogged: function(){!!
    ! ! var stub = sinon.stub(User, 'isLogged');!
    ! ! stub.returns(true);
    ! ! //DO STUFF && ASSERTIONS
    ! ! stub.returns(false);
    ! ! //DO STUFF && ASSERTIONS
    ! },
    [...]
    STUB

    View Slide

  154. [...]
    testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! var spy = sinon.spy(_$, 'watch');!
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! assertTrue(spy.calledWith('SystemOn'));
    ! },
    ! ! !
    ! testMyLibLoggedNotLogged: function(){!!
    ! ! var stub = sinon.stub(User, 'isLogged');!
    ! ! stub.returns(true);
    ! ! //DO STUFF && ASSERTIONS
    ! ! stub.returns(false);
    ! ! //DO STUFF && ASSERTIONS
    ! },
    [...]
    STUB

    View Slide

  155. [...]
    testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! var spy = sinon.spy(_$, 'watch');!
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! assertTrue(spy.calledWith('SystemOn'));
    ! },
    [...]
    MOCK

    View Slide

  156. [...]
    //testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! //var spy = sinon.spy(_$, 'watch');!
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! //assertTrue(spy.calledWith('SysyemOn'));
    ! //},
    !
    ! testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! var mock = sinon.mock(_$);
    ! ! mock.expect('watch').calledWith('SysyemOn');
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! mock.verify();
    ! },
    [...]
    MOCK

    View Slide

  157. [...]
    //testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! //var spy = sinon.spy(_$, 'watch');!
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! //assertTrue(spy.calledWith('SysyemOn'));
    ! //},
    !
    ! testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! var mock = sinon.mock(_$);
    ! ! mock.expect('watch').calledWith('SysyemOn');
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! mock.verify();
    ! },
    [...]
    MOCK

    View Slide

  158. [...]
    //testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! //var spy = sinon.spy(_$, 'watch');!
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! //assertTrue(spy.calledWith('SysyemOn'));
    ! //},
    !
    ! testMyLibRegistersToSystemOnEvent: function(){! !
    ! ! var mock = sinon.mock(_$);
    ! ! mock.expect('watch').calledWith('SysyemOn');
    ! ! //DO STUFF TO INIT YOUR LIB
    ! ! mock.verify();
    ! },
    [...]
    MOCK

    View Slide

  159. [...]
    testOnSuccessCallback: function(){! !
    var server = sinon.useFakeServer();
    server.respondWith("GET", "/art/12/comments.json",
    [200, {"Content-Type":"application/json"},
    "[{ id:12, text:'Hello'}]"]);
    ! ! var spy = sinon.spy();
    ! ! myLib.getCommentsFor("/art/12", spy);
    ! ! server.respond();
    ! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));
    ! },
    [...]
    AJAX CALL

    View Slide

  160. [...]
    testOnSuccessCallback: function(){! !
    var server = sinon.useFakeServer();
    server.respondWith("GET", "/art/12/comments.json",
    [200, {"Content-Type":"application/json"},
    "[{ id:12, text:'Hello'}]"]);
    ! ! var spy = sinon.spy();
    ! ! myLib.getCommentsFor("/art/12", spy);
    ! ! server.respond();
    ! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));
    ! },
    [...]
    AJAX CALL

    View Slide

  161. [...]
    testOnSuccessCallback: function(){! !
    var server = sinon.useFakeServer();
    server.respondWith("GET", "/art/12/comments.json",
    [200, {"Content-Type":"application/json"},
    "[{ id:12, text:'Hello'}]"]);
    ! ! var spy = sinon.spy();
    ! ! myLib.getCommentsFor("/art/12", spy);
    ! ! server.respond();
    ! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));
    ! },
    [...]
    AJAX CALL

    View Slide

  162. [...]
    testOnSuccessCallback: function(){! !
    var server = sinon.useFakeServer();
    server.respondWith("GET", "/art/12/comments.json",
    [200, {"Content-Type":"application/json"},
    "[{ id:12, text:'Hello'}]"]);
    ! ! var spy = sinon.spy();
    ! ! myLib.getCommentsFor("/art/12", spy);
    ! ! server.respond();
    ! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));
    ! },
    [...]
    AJAX CALL

    View Slide

  163. [...]
    testOnSuccessCallback: function(){! !
    var server = sinon.useFakeServer();
    server.respondWith("GET", "/art/12/comments.json",
    [200, {"Content-Type":"application/json"},
    "[{ id:12, text:'Hello'}]"]);
    ! ! var spy = sinon.spy();
    ! ! myLib.getCommentsFor("/art/12", spy);
    ! ! server.respond();
    ! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));
    ! },
    [...]
    AJAX CALL

    View Slide

  164. [...]
    testOnSuccessCallback: function(){! !
    var server = sinon.useFakeServer();
    server.respondWith("GET", "/art/12/comments.json",
    [200, {"Content-Type":"application/json"},
    "[{ id:12, text:'Hello'}]"]);
    ! ! var spy = sinon.spy();
    ! ! myLib.getCommentsFor("/art/12", spy);
    ! ! server.respond();
    ! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));
    ! },
    [...]
    AJAX CALL

    View Slide

  165. [...]
    testOnSuccessCallback: function(){! !
    var server = sinon.useFakeServer();
    server.respondWith("GET", "/art/12/comments.json",
    [200, {"Content-Type":"application/json"},
    "[{ id:12, text:'Hello'}]"]);
    ! ! var spy = sinon.spy();
    ! ! myLib.getCommentsFor("/art/12", spy);
    ! ! server.respond();
    ! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));
    ! },
    [...]
    AJAX CALL

    View Slide

  166. [...]
    testOnSuccessCallback: function(){! !
    var server = sinon.useFakeServer();
    server.respondWith("GET", "/art/12/comments.json",
    [200, {"Content-Type":"application/json"},
    "[{ id:12, text:'Hello'}]"]);
    ! ! var spy = sinon.spy();
    ! ! myLib.getCommentsFor("/art/12", spy);
    ! ! server.respond();
    ! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));
    ! },
    [...]
    AJAX CALL

    View Slide

  167. [...]
    testOnSuccessCallback: function(){! !
    var server = sinon.useFakeServer();
    server.respondWith("GET", "/art/12/comments.json",
    [200, {"Content-Type":"application/json"},
    "[{ id:12, text:'Hello'}]"]);
    ! ! var spy = sinon.spy();
    ! ! myLib.getCommentsFor("/art/12", spy);
    ! ! server.respond();
    ! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));
    ! },
    [...]
    AJAX CALL

    View Slide

  168. [...]
    testOnSuccessCallback: function(){! !
    var server = sinon.useFakeServer();
    server.respondWith("GET", "/art/12/comments.json",
    [200, {"Content-Type":"application/json"},
    "[{ id:12, text:'Hello'}]"]);
    ! ! var spy = sinon.spy();
    ! ! myLib.getCommentsFor("/art/12", spy);
    ! ! server.respond();
    ! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));
    ! },
    [...]
    AJAX CALL

    View Slide

  169. [...]
    testOnSuccessCallback: function(){! !
    var server = sinon.useFakeServer();
    server.respondWith("GET", "/art/12/comments.json",
    [200, {"Content-Type":"application/json"},
    "[{ id:12, text:'Hello'}]"]);
    ! ! var spy = sinon.spy();
    ! ! myLib.getCommentsFor("/art/12", spy);
    ! ! server.respond();
    ! ! assert(spy.calledWith([{ id:12, text:"Hello"}]));
    ! },
    [...]
    AJAX CALL

    View Slide

  170. JS TEST DRIVER
    SINON.JS
    JS HINT

    View Slide

  171. JS TEST DRIVER
    SINON.JS
    JS HINT
    YUI COMPRESSOR

    View Slide

  172. Everyone should be happy

    View Slide

  173. in the wild

    View Slide

  174. in the wild

    View Slide

  175. IN THE WILD
    In the wild, there is
    no health care.
    Dwight Schrute (the office)

    View Slide

  176. drawbacks
    at the beginning

    View Slide

  177. cost of change

    View Slide

  178. LOOKING FORWARD

    View Slide

  179. LOOKING FORWARD

    View Slide

  180. LOOKING FORWARD

    View Slide

  181. LOOKING FORWARD

    View Slide

  182. LOOKING FORWARD

    View Slide

  183. the further we look at,
    the more control we need
    LOOKING FORWARD

    View Slide

  184. the further we look at,
    the more control we need
    LOOKING FORWARD

    View Slide

  185. the further we look at,
    the more control we need
    LOOKING FORWARD
    let's get ready

    View Slide

  186. the further we look at,
    the more control we need
    LOOKING FORWARD
    let's get ready
    javascript is a programming language

    View Slide

  187. the further we look at,
    the more control we need
    LOOKING FORWARD
    let's get ready
    javascript is a programming language
    javascript is a serious business.

    View Slide

  188. the further we look at,
    the more control we need
    LOOKING FORWARD
    let's get ready
    javascript is a programming language
    javascript is a serious business.
    and, most of all...

    View Slide

  189. javascript kicks asses

    View Slide

  190. javascript kicks asses
    http://spkr8.com/t/8718
    http://cedmax.com
    @cedmax
    any question?

    View Slide