Talk given at JSConf Budapest (Budapest, Hungary) - May 2015
ENFORCING CODING STANDARDS in a JS PROJECTSebastiano Armeli@sebarmeli 14/05/2015 - JSConf BD
View Slide
to enforceverb (used with object), enforced, enforcing.to put or keep in force; to compel obedience to:“to enforce a rule; Traffic laws will be strictlyenforced.”
standardnouna rule or principle that is used as a basis for judgment:“They tried to establish standards for a new approach.”
commit 111111Author: Sebastiano ArmeliDate: Sun Dec 21 22:08:002014 -0500adding somethingcommit 2222222Author: Sebastiano ArmeliDate: Thu Dec 18 15:35:392014 -0500it will work, trust me
myProject||— module1.js|— module2.js|— module_3.js|— module_4.js|— module5.js|— package.json
defined by your teamAutomate
http://facilitationjapan.com/wp-content/uploads/2013/09/consensus_building.jpg
AD LIBRARY
! 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
! Testing (Mocha, Karma)! Automated Release Flow (Jenkins, NPM)! Setup script! DocumentationSummary 2/2
root = true[*]indent_style = spaceindent_size = 2end_of_line = lfcharset = utf-8trim_trailing_whitespace = trueinsert_final_newline = true.editorconfig
Coding Style& Quality Tools
Prevent bugsImprove code maintainability & readabilityEasy to use
function increment(a) {returna + 1;}increment(1); // undefinedBUG!!
var x = y = z = "example";Leaking Variables!!
{"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
JSCS
{"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
---parser: babel-eslintenv:browser: truenode: truemocha: truees6: true.eslintrc
rules:space-before-blocks: 2eqeqeq: [2, 'smart']curly: [2, 'multi-line']quotes: [2, 'single']space-after-keywords: 2no-unused-vars: [2, args: none]no-comma-dangle: 2no-unused-expressions: 0no-multi-spaces: 2…
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
no-trailing-spaces: 2no-mixed-spaces-and-tabs: 2quotes: [2, ‘single’]indent: [2, 2]
"use strict”;module.exports = function(context) {return {"NewExpression": function(node) {if (node.callee.name === "Object") {context.report(node, “Error …”);}}};};no-new-object.jslet obj = new Object(); let obj = {};
"use strict”;module.exports = function(context) {return {"NewExpression": function(node) {if (node.callee.name === "Object") {context.report(node, “Error …”);}}};};no-new-object.jslet obj = {};
Git Commits(feat | fix | docs | style | refactor | test | chore)():E.g.doc(readme): update with additional links.
Changelogconventional-changelog Changelog.mdcommit 7aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAuthor: Sebastiano Armeli Date: Tue Jan 6 11:48:59 2015 -0500refactor(BaseAd): Removed addToStreamTime method fromBaseAdcommit 7bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbAuthor: Sebastiano Armeli Date: Tue Jan 6 00:04:49 2015 -0500style(gpt): rearrange for better readability
CHANGELOG.md
Build toolgulp test / gulp dev
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
gulp es6/src /distES6 ES5
Platogulp plato
Testing
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;});});
module.exports = function(config) {config.set({basePath: '../',frameworks: ['mocha', 'fixture'],files: [….],browsers: ‘Chrome’,singleRun: false,preprocessors: {'**/*.html': ['html2js'],'**/*.json': ['html2js']},sauceLabs: {…}});};karma.conf.js
Automated Release flowgulp test:ci gulp bump:pathgulp bump:minorgulp bump:majorChangelog.md
./setup.shpre-commit hook+npm i && gulp test
DocumentationREADME.mdCONTRIBUTING.md
/doc
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
Sebastiano Armeli@sebarmeli