Next-Generation JavaScript Language Tooling

Next-Generation JavaScript Language Tooling

Engineers4Engineers, http://engineers4engineers.org, Jun 28, 2013

Web applications written in JavaScript rapidly grow in size and complexity. Ensuring and tracking the quality of such large-scale complex applications is daunting, especially given the lack of proper language tooling. Even in 2013 our tricks of the trade are unfortunately still at the level of “missing semicolon” check.

In this presentation, a new trend in emerging composeable JavaScript language tools will be highlighted. Armed with these tools, a wide range of development and maintenance workflows, designed for the new breed of web applications, can be established: Simple static analysis, run-time complexity profiling, syntax augmentation/transformation, dynamic code analysis, as well as an end-to-end strategy for application testing.

0284b8950e0f4a57bcc092d4dbb98d97?s=128

Ariya Hidayat

June 28, 2013
Tweet

Transcript

  1. Next-Generation JavaScript Language Tooling @ariyahidayat June 28, 2013

  2. /usr/bin/whoami

  3. Front-end development team Single-page applications

  4. Static analysis Inspection Dynamic analysis Transformation

  5. Every tool is open-source Tweak/customize/run with it! There are links

    (everywhere) to detailed articles/blog posts
  6. Multi-Layer Defense

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

  8. Placement of Layers Code Editor CI Server VCS Hooks Smoke

    Tests Pull Request Build Tasks
  9. Feedback is Important Engineer Tools Feedback Cycle Boring Repetitive Time-

    consuming
  10. Track Quality Metrics Application revision Execution time Baseline

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

  12. Composable Tools

  13. 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
  14. JavaScript in the Browser User Interface Browser Engine Graphics Stack

    Data Persistence Render Engine JavaScript Engine Networking I/O
  15. JavaScript Engine Virtual Machine/ Interpreter Parser Runtime Source Syntax Tree

    Built-in objects, host objects, ... Fast and conservative
  16. Parser var answer = 42 keyword equal sign identifier number

    Variable Declaration Identifier Literal Constant Tokenization → Tokens Parsing → Syntax Tree
  17. { 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
  18. Syntax Visualization http://esprima.org/demo/parse.html Try online! http://ariya.ofilabs.com/2012/04/javascript-syntax-tree-visualization-with-esprima.html

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

  20. Building Blocks → Tools https://speakerdeck.com/constellation/escodegen-and-esmangle-using-mozilla-javascript-ast-as-an-ir Parser Code Generator Source Syntax

    Tree Source Obvious examples: minifier, obfuscator, ...
  21. Another Case: CoffeeScriptRedux JavaScript Parser Code Generator JavaScript Syntax Tree

    Generated JavaScript JavaScript Source CoffeeScript Source CoffeeScript Parser + Transformer
  22. Consistency Convention Scalability Bring Your Own Tool (BYOT)

  23. Inspection

  24. 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, ...
  25. 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
  26. 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
  27. 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
  28. None
  29. 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
  30. Editing Autocomplete http://ariya.ofilabs.com/2013/03/javascript-editing-with-autocomplete.html http://esprima.org/demo/autocomplete.html Try online!

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

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

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

  34. Static Analysis

  35. 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
  36. 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
  37. 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
  38. 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
  39. “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
  40. Code Complexity http://jscomplexity.org/ if (true) "foo"; else "bar"; Control Flow

    Graph 6 edges 6 nodes 1 exit Cyclomatic Complexity = 2
  41. 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); });
  42. Continuous Monitoring of Complexity http://ariya.ofilabs.com/2013/05/continuous-monitoring-of-javascript-code-complexity.html

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

  44. Dynamic Analysis

  45. 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/
  46. 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
  47. 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);
  48. 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
  49. 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
  50. Buster.JS buster-istanbul Mocha mocha-istanbul Karma (née Testacular) built-in Intern built-in

    Grover built-in Istanbul vs Test Libraries
  51. If you think JSLint hurts your feelings, wait until you

    use Istanbul. @davglass
  52. ...I gave you my heart But the very next day

    you gave it away...
  53. Performance Tweaks

  54. 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
  55. Measurement Confidence Accuracy Precision http://ariya.ofilabs.com/2013/06/javascript-timing-accuracy-vs-precision.html

  56. 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
  57. Fast = Enough? Alice Bob Chuck Dan ... Bob Alice

    Dan Chuck ... Address Book Application Sort How’s the speed? 2 ms to sort 10 contacts
  58. 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 ???
  59. Profile-Guide Optimization http://ariya.ofilabs.com/2011/11/matching-a-decimal-digit.html function isDigit(ch) { return '0123456789'.indexOf(ch) >= 0;

    } function isDigit(ch) { return ch !==' ' && '0123456789'.indexOf(ch) >= 0; } Letters Digits Spaces
  60. 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
  61. 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
  62. 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!
  63. 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
  64. 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
  65. Transformation

  66. Source Transformation Parser Code Generator Source Syntax Tree Source In-place

    Modification Modified Source Regenerative Non-Destructive
  67. 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
  68. 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
  69. Rename Refactoring Assistant http://ariya.ofilabs.com/2013/04/rename-refactoring-for-javascript-code.html http://esprima.org/demo/rename.html Try online!

  70. 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
  71. Parametrized Coding http://nornagon.github.com/scrubby/

  72. Embrace the Future

  73. Adaptive Tools Explicit Implicit Customize analysis options Define new sets

    of rules Infer from high-quality sample Observe the engineer’s behavior
  74. Tools: The Final Frontier To boldly analyze what no man

    has analyzed before...
  75. Thank You ariya.hidayat@gmail.com @AriyaHidayat ariya.ofilabs.com/highlights Credits: Some artworks are from

    http://openclipart.org speakerdeck.com/ariya