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

The Future of JavaScript Language Tooling

The Future of JavaScript Language Tooling

Silicon Valley Code Camp 2013:
http://www.siliconvalley-codecamp.com/Session/2013/the-future-of-javascript-language-tooling

It is inevitable that future JavaScript applications will grow to be more complex. Keeping the quality of such a complex system is far from trivial. Unfortunately, our JavaScript tools recently still move at a glacial speed. Many code analyzers scream at you when a semicolon is omitted, yet they are totally oblivious to a copy-paste mistake. This talk will discuss the development of emerging JavaScript language tooling designed to solve:
* code inspection: autocomplete, code outline
* static analysis: code metrics, API harness, cyclomatic complexity
* dynamic analysis: code coverage, execution tracing, run-time scalability
* source transformation: coding style, language extension (module, class, macro, …)

Ariya Hidayat

October 06, 2013
Tweet

More Decks by Ariya Hidayat

Other Decks in Programming

Transcript

  1. The Future of
    JavaScript Language Tooling
    @ariyahidayat
    October 6, 2013

    View Slide

  2. /usr/bin/whoami

    View Slide

  3. Front-end development team
    Single-page applications

    View Slide

  4. Static analysis
    Inspection Dynamic analysis
    Transformation

    View Slide

  5. Every tool is open-source
    Tweak/customize/run with it!
    There are links (everywhere) to
    detailed articles/blog posts

    View Slide

  6. Multi-Layer Defense

    View Slide

  7. Defensive = Paranoid
    http://ariya.ofilabs.com/2012/12/quality-code-via-multiple-layers-of-defense.html

    View Slide

  8. Placement of Layers
    Code Editor
    CI Server
    VCS Hooks
    Smoke Tests
    Pull Request
    Build Tasks

    View Slide

  9. Feedback is Important
    Engineer
    Tools
    Feedback
    Cycle
    Boring
    Repetitive
    Time-
    consuming

    View Slide

  10. Track Quality Metrics
    Application revision
    Execution time
    Baseline

    View Slide

  11. Metrics Quadrant
    http://ariya.ofilabs.com/2012/11/optimization-journey-vs-destination.html

    View Slide

  12. Be Reasonable
    “First Things First”, Steven Covey
    “The Big Rock”

    View Slide

  13. Composable Tools

    View Slide

  14. This is the Unix Philosophy
    Write programs that do one thing and do it well.
    Write programs to work together.
    Write programs to handle text streams,
    because that is a universal interface.
    Doug McIlroy, the inventor of Unix pipes and
    one of the founders of the Unix tradition

    View Slide

  15. JavaScript in the Browser
    User Interface
    Browser Engine
    Graphics Stack
    Data Persistence
    Render Engine
    JavaScript
    Engine
    Networking I/O

    View Slide

  16. JavaScript Engine
    Virtual
    Machine/
    Interpreter
    Parser
    Runtime
    Source
    Syntax
    Tree
    Built-in objects,
    host objects, ...
    Fast and
    conservative

    View Slide

  17. Parser
    var answer = 42
    keyword equal sign
    identifier number
    Variable
    Declaration
    Identifier Literal
    Constant
    Tokenization →
    Tokens
    Parsing → Syntax Tree

    View Slide

  18. {
    type: "Program",
    body: [
    {
    type: "VariableDeclaration",
    declarations: [
    {
    type: "VariableDeclarator",
    id: {
    type: "Identifier",
    name: "answer"
    },
    init: {
    type: "Literal",
    value: 42,
    raw: "42"
    }
    }
    ],
    kind: "var"
    }
    ]
    }
    Syntax Tree
    Mozilla Parser API
    var answer = 42;
    Terms → ECMAScript 5.1 Specification
    https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API

    View Slide

  19. Syntax Visualization http://esprima.org/demo/parse.html
    Try online!
    http://ariya.ofilabs.com/2012/04/javascript-syntax-tree-visualization-with-esprima.html

    View Slide

  20. Execution Visualization
    http://int3.github.io/metajs/

    View Slide

  21. Building Blocks → Tools
    Parser
    Code
    Generator
    Source
    Syntax Tree
    Source
    Obvious examples: minifier, obfuscator, ...

    View Slide

  22. Another Case: CoffeeScriptRedux
    JavaScript
    Parser
    Code
    Generator
    JavaScript
    Syntax Tree
    Generated
    JavaScript
    JavaScript
    Source
    CoffeeScript
    Source
    CoffeeScript
    Parser +
    Transformer

    View Slide

  23. Consistency
    Convention
    Scalability
    Bring Your Own Tool (BYOT)

    View Slide

  24. Inspection

    View Slide

  25. Syntax Validation
    http://ariya.ofilabs.com/2012/10/javascript-validator-with-esprima.html
    http://esprima.org/demo/validate.html
    Try online!
    Also available:
    Grunt plugin, Ant task, ...

    View Slide

  26. Strict Mode Validator
    'use strict';
    block = {
    color: 'blue',
    height: 20,
    width: 10,
    color: 'red'
    };
    Duplicate data property in
    object literal not allowed in
    strict mode
    http://ariya.ofilabs.com/2012/10/validating-strict-mode.html

    View Slide

  27. Linter vs Validator
    Validator
    Linter
    Looks for specification violations
    Does not care about coding style
    Works well on generated/minified code
    Searches for suspicious pattern
    Warns on style inconsistencies
    Works well on hand-written code

    View Slide

  28. Protection Layers, Again
    JUnit XML + Jenkins
    files=$(git diff-index --name-
    only HEAD | grep -P '\.js$')
    for file in $files; do
    esvalidate $file
    if [ $? -eq 1 ]; then
    echo "Syntax error: $file"
    exit 1
    fi
    done
    Git Precommit Hook
    http://ariya.ofilabs.com/2012/03/git-pre-commit-hook-and-smoke-testing.html

    View Slide

  29. View Slide

  30. Application Structure
    MyApp.create('MyApp.Person', {
    name: 'Joe Sixpack',
    age: 42,
    constructor: function(name) {},
    walk: function(steps) {}
    run: function(steps) {}
    });
    {
    objectName: 'MyApp.Person',
    functions: ['walk', 'run'],
    properties: ['name', 'age']
    }
    Metadata

    View Slide

  31. Editing Autocomplete
    http://ariya.ofilabs.com/2013/03/javascript-editing-with-autocomplete.html
    http://esprima.org/demo/autocomplete.html
    Try online!

    View Slide

  32. Type Annotation
    http://esprima.org/demo/autocomplete.html
    Try online!

    View Slide

  33. Scope Visualization
    http://mazurov.github.io/eslevels-demo/

    View Slide

  34. Scope and Highlight
    http://ariya.ofilabs.com/2013/04/javascript-variable-scope-and-highlight.html
    http://esprima.org/demo/highlight.html
    Try online!

    View Slide

  35. Static Analysis

    View Slide

  36. Polluting Variables
    var height;
    // some fancy processing
    heigth = 200;
    Leaks to
    global
    test.js:3
    heigth = 200;
    ^
    LeakError: global leak
    detected: heigth
    https://github.com/kesla/node-leaky
    http://ariya.ofilabs.com/2012/11/polluting-and-unused-javascript-variables.html

    View Slide

  37. Unused Variables
    var height;
    // some fancy processing
    heigth = 200;
    http://ariya.ofilabs.com/2012/11/polluting-and-unused-javascript-variables.html
    Declared
    but not used
    test.js
    height - on
    line 1
    https://github.com/Kami/node-unused

    View Slide

  38. Stray Logging
    function detect_console(code) {
    function check(node) {
    if (node.type === 'CallExpression') {
    if (node.callee.type === 'MemberExpression') {
    if (node.callee.object.name === 'console') {
    alert('console call at line', node.loc.start.line);
    }
    }
    }
    }
    var tree = esprima.parse(code, { loc: true });
    estraverse.traverse(tree, { enter:check });
    }
    var answer = 42;
    console.log(answer);
    http://ariya.ofilabs.com/2013/04/automagic-removal-of-javascript-logging.html

    View Slide

  39. Nested Ternary Conditionals
    var str = (age < 1) ? "baby" :
    (age < 5) ? "toddler" :
    (age < 18) ? "child": "adult";
    http://ariya.ofilabs.com/2012/10/detecting-nested-ternary-conditionals.html

    View Slide

  40. “Boolean Trap” Finder
    Can you make up your mind? treeItem.setState(true, false);
    event.initKeyEvent("keypress", true, true, null, null,
    false, false, false, false, 9, 0);
    The more the merrier?
    Obfuscated choice var volumeSlider = new Slider(false);
    Double-negative
    component.setHidden(false);
    filter.setCaseInsensitive(false);
    http://ariya.ofilabs.com/2012/06/detecting-boolean-traps-with-esprima.html

    View Slide

  41. Code Complexity http://jscomplexity.org/
    if (true) "foo"; else "bar";
    Control Flow Graph
    6 edges
    6 nodes
    1 exit
    Cyclomatic Complexity = 2

    View Slide

  42. Most Complex Function
    http://ariya.ofilabs.com/2013/05/continuous-monitoring-of-javascript-code-complexity.html
    var cr = require('complexity-report'),
    content = require('fs').readFileSync('index.js', 'utf-8'),
    list = [];
    cr.run(content).functions.forEach(function (entry) {
    list.push({ name: entry.name, value:
    entry.complexity.cyclomatic });
    });
    list.sort(function (x, y) {
    return y.value - x.value;
    });
    console.log('Most cyclomatic-complex functions:');
    list.slice(0, 6).forEach(function (entry) {
    console.log(' ', entry.name, entry.value);
    });

    View Slide

  43. Continuous Monitoring of Complexity
    http://ariya.ofilabs.com/2013/05/continuous-monitoring-of-javascript-code-complexity.html

    View Slide

  44. Complexity Visualization with Plato
    https://ariya.ofilabs.com/2013/01/javascript-code-complexity-visualization.html
    https://github.com/jsoverson/plato

    View Slide

  45. Dynamic Analysis

    View Slide

  46. Dynamic Code Coverage via Instrumentation
    var answer = 42;
    alert(answer);
    var __cov_l$4m7m$L464yvav5F$qhNA =
    __coverage__['hello.js'];
    __cov_l$4m7m$L464yvav5F$qhNA.s['1']++;
    var answer = 42;
    __cov_l$4m7m$L464yvav5F$qhNA.s['2']++;
    alert(answer);
    http://gotwarlost.github.io/istanbul/

    View Slide

  47. Latent Trap of Statement Coverage
    function inc(p, q) {
    if (q == undefined) q = 1;
    return p + q/q;
    }
    assert("inc(4) must give 5", inc(4) == 5);
    Does not catch the
    missing code
    sequence
    http://ariya.ofilabs.com/2012/09/the-hidden-trap-of-code-coverage.html

    View Slide

  48. Workaround: Explicit Path
    function inc(p, q) {
    if (q == undefined)
    return p + 1;
    return p + q/q;
    }
    assert("inc(4) must give 5", inc(4) == 5);

    View Slide

  49. Branch Coverage
    http://ariya.ofilabs.com/2012/12/javascript-code-coverage-with-istanbul.html
    function inc(p, q) {
    if (q == undefined) q = 1;
    return p + q/q;
    }
    assert("inc(4) must give 5", inc(4) == 5);
    E = Else is not
    taken

    View Slide

  50. Hard Thresholds on Code Coverage
    http://ariya.ofilabs.com/2013/05/hard-thresholds-on-javascript-code-coverage.html
    istanbul check-coverage --statement -5 --branch -3 --function 100

    View Slide

  51. Buster.JS buster-istanbul
    Mocha mocha-istanbul
    Karma (née Testacular) built-in
    Intern built-in
    Grover built-in
    Istanbul vs Test Libraries

    View Slide

  52. Code Coverage for Jasmine Tests
    Specs
    Karma Istanbul
    http://ariya.ofilabs.com/2013/10/code-coverage-of-jasmine-tests-using-istanbul-and-karma.html
    INFO [karma]: Karma v0.10.2 server started at http://localhost:9876/
    INFO [launcher]: Starting browser PhantomJS
    INFO [PhantomJS 1.9.2 (Linux)]: Connected on socket N9nDnhJ0Np92NTSPGx-X
    PhantomJS 1.9.2 (Linux): Executed 1 of 1 SUCCESS (0.029 secs / 0.003 secs)

    View Slide

  53. If you think JSLint hurts your feelings,
    wait until you use Istanbul.
    @davglass

    View Slide

  54. ...I gave you my heart
    But the very next day you gave it away...

    View Slide

  55. Performance Tweaks

    View Slide

  56. http://ariya.ofilabs.com/2012/12/javascript-performance-analysis-sampling-tracing-and-timing.html
    Timing
    Prepare the stopwatch
    Mark the start and the end
    Sampling
    Periodically check which function
    is being executed
    Tracing Track all function calls and exits

    View Slide

  57. Measurement Confidence
    Accuracy
    Precision
    http://ariya.ofilabs.com/2013/06/javascript-timing-accuracy-vs-precision.html

    View Slide

  58. What you write Optimized by the engine
    function test() {
    var a = 0, b = 0;
    for (var i = 0; i < 100; i++) {
    a += i;
    b += i * i;
    }
    return a;
    }
    function test() {
    var a = 0;
    for (var i = 0; i < 100; i++) {
    a += i;
    }
    return a;
    }
    Dead Code Elimination

    View Slide

  59. Fast = Enough?
    Alice
    Bob
    Chuck
    Dan
    ...
    Bob
    Alice
    Dan
    Chuck
    ...
    Address Book Application
    Sort
    How’s the speed?
    2 ms to sort 10 contacts

    View Slide

  60. Array.prototype.swap = function (i, j) {
    var k = this[i]; this[i] = this[j]; this[j] = k;
    }
    function sort(list) {
    var items = list.slice(0), swapped = false, p, q;
    for (p = 1; p < items.length; ++p) {
    for (q = 0; q < items.length - p; ++q) {
    if (items[q + 1] < items[q]) {
    items.swap(q, q + 1);
    swapped =true;
    }
    }
    if (!swapped) break;
    }
    return items;
    }
    Bubble Sort ???

    View Slide

  61. Profile-Guide Optimization
    function isDigit(ch) {
    return '0123456789'.indexOf(ch) >= 0;
    }
    function isDigit(ch) {
    return ch !==' ' &&
    '0123456789'.indexOf(ch) >= 0;
    }
    Letters
    Digits Spaces
    http://ariya.ofilabs.com/2013/07/profile-guided-javascript-optimization.html

    View Slide

  62. View Slide

  63. Object in a Set
    http://ariya.ofilabs.com/2012/08/determining-objects-in-a-set-examples-in-javascript.html
    var valid_words = {
    'foobar': true,
    'bar': true,
    'baz': true,
    'quux': true
    };
    function is_valid(word) {
    return valid_words.hasOwnProperty(word);
    }
    is_valid('fox'); // false
    Dictionary
    Spell checker Alternatives:
    array lookup,
    switch case,
    prefix/suffix tree,
    perfect hash

    View Slide

  64. Tiered Conditionals
    function is_valid(word) {
    switch (word.length) {
    case 3:
    return word === 'bar' || word === 'baz';
    case 4:
    return word === 'quux';
    case 6:
    return word === 'foobar';
    }
    return false;
    }
    Filter #1: Length
    http://ariya.ofilabs.com/2012/08/determining-objects-in-a-set-examples-in-javascript.html

    View Slide

  65. Empirical Run-time Complexity
    Array.prototype.swap = function (i, j) {
    var k = this[i]; this[i] = this[j]; this[j] = k;
    }
    Array.prototype.swap = function (i, j) {
    Log({ name: 'Array.prototype.swap', lineNumber: 1,
    range: [23, 94] });
    var k = this[i]; this[i] = this[j]; this[j] = k;
    }
    http://esprima.org/demo/functiontrace.html
    Try online!

    View Slide

  66. Run-time Analysis
    0
    250000
    500000
    0 500 1000
    Calls to swap()
    Input Size
    http://ariya.ofilabs.com/2012/01/scalable-web-apps-the-complexity-issue.html

    View Slide

  67. Execution Tracing
    http://ariya.ofilabs.com/2012/02/tracking-javascript-execution-during-startup.html
    https://gist.github.com/1823129
    jQuery Mobile startup log
    4640 function calls
    jquery.js 26 jQuery
    jquery.js 103 init undefined, undefined,
    [object Object]
    jquery.js 274 each (Function)
    jquery.js 631 each [object Object],
    (Function), undefined
    jquery.js 495 isFunction [object Object]
    jquery.js 512 type [object Object]
    jquery.mobile.js 1857 [Anonymous]
    jquery.mobile.js 642 [Anonymous]
    jquery.mobile.js 624 enableMouseBindings
    jquery.mobile.js 620 disableTouchBindings

    View Slide

  68. Transformation

    View Slide

  69. Source Transformation
    Parser
    Code
    Generator
    Source
    Syntax Tree
    Source
    In-place
    Modification
    Modified Source
    Regenerative
    Non-Destructive
    http://ariya.ofilabs.com/2013/06/javascript-source-transformation-non-destructive-vs-regenerative.html

    View Slide

  70. String Literal Quotes
    [
    { type: "Identifier", value: "console", range: [0, 7] },
    { type: "Punctuator", value: ".", range: [7, 8] },
    { type: "Identifier", value: "log", range: [8, 11] },
    { type: "Punctuator", value: "(", range: [11, 12] },
    { type: "String", value: "\"Hello\"", range: [12, 19] },
    { type: "Punctuator", value: ")", range: [19, 19] }
    ]
    console.log('Hello')
    console.log("Hello")
    List of tokens
    http://ariya.ofilabs.com/2012/02/from-double-quotes-to-single-quotes.html

    View Slide

  71. Style Formatter
    CodePainter
    Source
    Sample code
    Formatted
    Infer coding
    styles
    Indentation
    Quote for string literal
    Whitespace
    esformatter
    Source Formatted
    Style options
    Indentation
    Line breaks
    Whitespaces
    https://github.com/millermedeiros/esformatter

    View Slide

  72. Rename Refactoring Assistant
    http://ariya.ofilabs.com/2013/04/rename-refactoring-for-javascript-code.html
    http://esprima.org/demo/rename.html
    Try online!

    View Slide

  73. function f() {
    var j = data.length;
    console.log(j, 'items');
    for (var i = 0; i < j; ++i) {
    var j$0 = data[i] * data[i];
    console.log(j$0); // squares
    }
    }
    Lexical Block Scope
    function f() {
    let j = data.length;
    console.log(j, 'items');
    for (let i = 0; i < j; ++i) {
    let j = data[i] * data[i];
    console.log(j); // squares
    }
    }
    https://github.com/olov/defs
    New in ECMAScript 6
    http://ariya.ofilabs.com/2013/05/es6-and-block-scope.html

    View Slide

  74. Parametrized Coding
    http://nornagon.github.com/scrubby/

    View Slide

  75. Embrace the Future

    View Slide

  76. Adaptive Tools
    Explicit Implicit
    Customize analysis options
    Define new sets of rules
    Infer from high-quality sample
    Observe the engineer’s behavior

    View Slide

  77. Tools: The Final Frontier
    To boldly analyze what no man has
    analyzed before...

    View Slide

  78. Thank You
    [email protected]
    @ariyahidayat
    ariya.ofilabs.com/highlights
    Credits: Some artworks are from http://openclipart.org
    speakerdeck.com/ariya

    View Slide