Slide 1

Slide 1 text

ENFORCING 
 CODING 
 STANDARDS 
 in a JS PROJECT Sebastiano Armeli @sebarmeli 14/05/2015 - JSConf BD

Slide 2

Slide 2 text

to enforce verb (used with object), enforced, enforcing. to put or keep in force; to compel obedience to: “to enforce a rule; Traffic laws will be strictly enforced.”

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

standard noun a rule or principle that is used as a basis for judgment: “They tried to establish standards for a new approach.”

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

commit 111111 Author: Sebastiano Armeli Date: Sun Dec 21 22:08:00 2014 -0500 adding something commit 2222222 Author: Sebastiano Armeli Date: Thu Dec 18 15:35:39 2014 -0500 it will work, trust me

Slide 8

Slide 8 text

myProject | |— module1.js |— module2.js |— module_3.js |— module_4.js |— module5.js |— package.json

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

defined by your team Automate

Slide 11

Slide 11 text

http://facilitationjapan.com/wp-content/uploads/2013/09/consensus_building.jpg

Slide 12

Slide 12 text

AD LIBRARY

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

! IDE (Editorconfig) ! Quality & Style tools (JSHint, JSCS, ESLint) ! Git commits standards ! Build tools (Grunt, Gulp) ! Language - Transpiler (ES6 - Babel) ! Complexity tool (Plato) Summary 1/2

Slide 16

Slide 16 text

! Testing (Mocha, Karma) ! Automated Release Flow (Jenkins, NPM) ! Setup script ! Documentation Summary 2/2

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

root = true [*] indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true .editorconfig

Slide 19

Slide 19 text

Coding Style & Quality Tools

Slide 20

Slide 20 text

Prevent bugs Improve code maintainability 
 & readability Easy to use

Slide 21

Slide 21 text

function increment(a) { return a + 1; } increment(1); // undefined BUG!!

Slide 22

Slide 22 text

var x = y = z = "example"; Leaking Variables!!

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

{ "curly": true, "eqeqeq": false, "latedef": true, "newcap": true, "noarg": true, "sub": true, "boss": true, "indent": 2, "noempty": true, "expr": true, "eqnull": true, "esnext": true, "browser": true, "white": true, "undef": true, "predef": [ “require”, "module", “exports", "CustomEvent"] } .jshintrc

Slide 25

Slide 25 text

{ "curly": true, "eqeqeq": false, "latedef": true, "newcap": true, "noarg": true, "sub": true, "boss": true, "indent": 2, "noempty": true, "expr": true, "eqnull": true, "esnext": true, "browser": true, "white": true, "undef": true, "predef": [ “require”, "module", “exports", "CustomEvent"] } .jshintrc

Slide 26

Slide 26 text

{ "curly": true, "eqeqeq": false, "latedef": true, "newcap": true, "noarg": true, "sub": true, "boss": true, "indent": 2, "noempty": true, "expr": true, "eqnull": true, "esnext": true, "browser": true, "white": true, "undef": true, "predef": [ “require”, "module", “exports", "CustomEvent"] } .jshintrc

Slide 27

Slide 27 text

JSCS

Slide 28

Slide 28 text

{ "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try"], "disallowImplicitTypeConversion": ["string"], "disallowMultipleLineBreaks": true, "disallowMixedSpacesAndTabs": true, "disallowKeywords": ["with"], "disallowMultipleVarDecl": true, "disallowTrailingComma": true, "disallowTrailingWhitespace": true, "maximumLineLength": 80, "esnext": true } .jscsrc

Slide 29

Slide 29 text

{ "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try"], "disallowImplicitTypeConversion": ["string"], "disallowMultipleLineBreaks": true, "disallowMixedSpacesAndTabs": true, "disallowKeywords": ["with"], "disallowMultipleVarDecl": true, "disallowTrailingComma": true, "disallowTrailingWhitespace": true, "maximumLineLength": 80, "esnext": true } .jscsrc

Slide 30

Slide 30 text

{ "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try"], "disallowImplicitTypeConversion": ["string"], "disallowMultipleLineBreaks": true, "disallowMixedSpacesAndTabs": true, "disallowKeywords": ["with"], "disallowMultipleVarDecl": true, "disallowTrailingComma": true, "disallowTrailingWhitespace": true, "maximumLineLength": 80, "esnext": true } .jscsrc

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

--- parser: babel-eslint env: browser: true node: true mocha: true es6: true .eslintrc

Slide 33

Slide 33 text

rules: space-before-blocks: 2 eqeqeq: [2, 'smart'] curly: [2, 'multi-line'] quotes: [2, 'single'] space-after-keywords: 2 no-unused-vars: [2, args: none] no-comma-dangle: 2 no-unused-expressions: 0 no-multi-spaces: 2 …

Slide 34

Slide 34 text

rules: space-before-blocks: 2 eqeqeq: [2, 'smart'] curly: [2, 'multi-line'] quotes: [2, 'single'] space-after-keywords: 2 no-unused-vars: [2, args: none] no-comma-dangle: 2 no-unused-expressions: 0 no-multi-spaces: 2 …

Slide 35

Slide 35 text

no-unused-vars: [2, args: none] function test1(a, b) { var c, d = 2; return a + d; } test1(1, 2); Error!! function test2(a, b, c) { return a + b; } test2(1, 2); Ok

Slide 36

Slide 36 text

no-trailing-spaces: 2 no-mixed-spaces-and-tabs: 2 quotes: [2, ‘single’] indent: [2, 2]

Slide 37

Slide 37 text

"use strict”; module.exports = function(context) { return { "NewExpression": function(node) { if (node.callee.name === "Object") { context.report(node, “Error …”); } } }; }; no-new-object.js let obj = new Object(); let obj = {};

Slide 38

Slide 38 text

"use strict”; module.exports = function(context) { return { "NewExpression": function(node) { if (node.callee.name === "Object") { context.report(node, “Error …”); } } }; }; no-new-object.js let obj = {};

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

Git Commits (feat | fix | docs | style | refactor | test | chore)(): E.g. doc(readme): update with additional links.

Slide 41

Slide 41 text

Changelog conventional-changelog Changelog.md commit 7aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Author: Sebastiano Armeli Date: Tue Jan 6 11:48:59 2015 -0500 refactor(BaseAd): Removed addToStreamTime method from BaseAd commit 7bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb Author: Sebastiano Armeli Date: Tue Jan 6 00:04:49 2015 -0500 style(gpt): rearrange for better readability

Slide 42

Slide 42 text

CHANGELOG.md

Slide 43

Slide 43 text

Build tool gulp test / gulp dev

Slide 44

Slide 44 text

var gulp = require('gulp'); var plugins = require(‘gulp-load-plugins')(); … gulp.task('eslint', function() { return gulp.src(['src/**/*.js']) .pipe(plugins.eslint()) .pipe(plugins.eslint.format()) .pipe(plugins.eslint.failOnError()); }); … gulpfile.js

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

gulp es6 /src /dist ES6 ES5

Slide 47

Slide 47 text

Plato gulp plato

Slide 48

Slide 48 text

Testing

Slide 49

Slide 49 text

describe('#_onContainerResume', function() { it('should call play when container resumes', function() { videoAd.views.set(mockedVideoAdMetadata.id, { play: function() {}, hasBeenPlayed: true }); sinon.stub(videoAd.views.get(mockedVideoAdMetadata.id), 'play'); videoAd._onContainerResume(); expect(videoAd.views.get(mockedVideoAdMetadata.id).play).to.have .been.called; }); });

Slide 50

Slide 50 text

module.exports = function(config) { config.set({ basePath: '../', frameworks: ['mocha', 'fixture'], files: [ …. ], browsers: ‘Chrome’, singleRun: false, preprocessors: { '**/*.html': ['html2js'], '**/*.json': ['html2js'] }, sauceLabs: { … } }); }; karma.conf.js

Slide 51

Slide 51 text

module.exports = function(config) { config.set({ basePath: '../', frameworks: ['mocha', 'fixture'], files: [ …. ], browsers: ‘Chrome’, singleRun: false, preprocessors: { '**/*.html': ['html2js'], '**/*.json': ['html2js'] }, sauceLabs: { … } }); }; karma.conf.js

Slide 52

Slide 52 text

module.exports = function(config) { config.set({ basePath: '../', frameworks: ['mocha', 'fixture'], files: [ …. ], browsers: ‘Chrome’, singleRun: false, preprocessors: { '**/*.html': ['html2js'], '**/*.json': ['html2js'] }, sauceLabs: { … } }); }; karma.conf.js

Slide 53

Slide 53 text

Automated Release flow gulp test:ci gulp bump:path gulp bump:minor gulp bump:major Changelog.md

Slide 54

Slide 54 text

./setup.sh pre-commit hook + npm i && gulp test

Slide 55

Slide 55 text

Documentation README.md CONTRIBUTING.md

Slide 56

Slide 56 text

Documentation README.md CONTRIBUTING.md

Slide 57

Slide 57 text

/doc

Slide 58

Slide 58 text

Sebastiano Armeli <…@spotify.com> Brice Lin <[email protected]> <…@gmail.com> Jason Palmer <[email protected]> <[email protected]> Joseph Werle <[email protected]> <…@gmail.com> Olof Kihlberg <…@spotify.com> Sigfrido Chirinos <…@spotify.com> .mailmap

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

Sebastiano Armeli @sebarmeli