Slide 1

Slide 1 text

Improving JavaScript Code Quality: Strategies and Tools Ariya Hidayat @ariyahidayat 1

Slide 2

Slide 2 text

whoami 2

Slide 3

Slide 3 text

Multi-Layer Defense 3

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

Feedback is Important Engineer Tools Feedback Cycle Boring Repetitive Time-consuming 6

Slide 7

Slide 7 text

Track Quality Metrics Application revision Execution time Baseline 7

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

Foundation 10

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

JavaScript Engines SpiderMonkey Firefox JavaScriptCore/Nitro Safari V8 Node.js, Chrome JScript/Chakra Internet Explorer Carakan Opera 12

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

Live Coding/Editing http://nornagon.github.com/scrubby/ 17

Slide 18

Slide 18 text

Composition: Chains of Responsibilities 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, ... 18

Slide 19

Slide 19 text

Quasi-Endless Possibilities Static analysis Inspection Dynamic analysis Transformation 19

Slide 20

Slide 20 text

Standard, Off-the-Shelf Tools 20

Slide 21

Slide 21 text

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, ... 21

Slide 22

Slide 22 text

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 22

Slide 23

Slide 23 text

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 23

Slide 24

Slide 24 text

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 24

Slide 25

Slide 25 text

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 25

Slide 26

Slide 26 text

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 26

Slide 27

Slide 27 text

27

Slide 28

Slide 28 text

Code Complexity if (true) "foo"; else "bar"; ◦ Maintainability index: 139.99732896539635 ◦ Physical LOC: 1 ◦ Logical LOC: 4 ◦ Aggregate cyclomatic complexity: 2 http://jscomplexity.org/ 28

Slide 29

Slide 29 text

Continuous Monitoring of Complexity 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); }); 29

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

Source Transformation Parser Code Generator Source Syntax Tree Source In-place Modification Modified Source Regenerative Non-Destructive 35

Slide 36

Slide 36 text

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/ 36

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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 38

Slide 39

Slide 39 text

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 39

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

BYOT (Bring Your Own Tools) 41

Slide 42

Slide 42 text

Consistency Convention Scalability 42

Slide 43

Slide 43 text

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 43

Slide 44

Slide 44 text

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 44

Slide 45

Slide 45 text

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 45

Slide 46

Slide 46 text

Custom Linting var fs = require('fs'), esprima = require('./esprima'), files = process.argv.splice(2); files.forEach(function (filename) { var content = fs.readFileSync(filename, 'utf-8'), syntax = esprima.parse(content, { loc: true }); JSON.stringify(syntax, function (key, value) { if (key === 'test' && value.operator === '==') console.log('Line', value.loc.start.line); return value; }); }); if (x == 9) { // do Something } Not a strict equal 46

Slide 47

Slide 47 text

“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 47

Slide 48

Slide 48 text

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 48

Slide 49

Slide 49 text

Performance: Measurement Confidence Accuracy Precision 49

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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 ??? 51

Slide 52

Slide 52 text

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! 52

Slide 53

Slide 53 text

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 53

Slide 54

Slide 54 text

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 54

Slide 55

Slide 55 text

Embrace the Future 55

Slide 56

Slide 56 text

Copy Paste (Mistake) Detector function inside(point, rect) { return (point.x >= rect.x1) && (point.y >= rect.y1) && (point.x <= rect.x2) && (point.y <= rect.y1); } Wrong check 56

Slide 57

Slide 57 text

Syntax Augmentation ES.Future: Polyfills, Transpiler, ... Exoskeleton: LLJS, Sweet.js, ... 57

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

Syntax Query if (x = 0) { /* do Something */ } IfStatement.test AssigmentExpression[operator='='] Which syntax family should be the model? CSS selector? XPath? SQL? 59

Slide 60

Slide 60 text

And Many More... Semantic Diff Symbolic execution Informative syntax error Declarative transformation Pattern Matching 60

Slide 61

Slide 61 text

Her five-year mission: to explore strange new worlds, to seek out new lifeforms and new civilizations; to boldly go where no one has gone before. 61

Slide 62

Slide 62 text

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