agile4js
2014-01-12
可通过添加微信帐号
geek32
,或者微博帐号姜志辉iS
与我讨论
Clean Code:编写干净整洁的JS代码
发现异味
怎么写出干净整洁的代码呢?嗯。这个问题我们可以说上一整天...
首先,咱得有分辨异味的能力。
JS更是如此。Douglas Crockford专门为此写了一本《JavaScript:The Good Parts》.在这本书里不仅仅是提到了JavaScript中的优美特性,而且还罗列出了JavaScript中的毒瘤和糟粕。JSLint是老道提供的一个JavaScript的代码质量检查工具。它读取源文本进行扫描。被发现的问题往往是语法错误,也有一些代码风格及结构上的问题。
它不会证明我们的程序是正确的,只是提供了一种建议。
JSHint是JSLint的一个分支,他比JSLint更加的便捷。可以通过npm安装:
npm install jshint -g
安装完成后,即可以使用jshint
来检测代码(jshint xxx.js
,或者jshint .
)。
如果使用Sublime Text,可以安装两个插件:
测试驱动开发
编程风格有很多种:祈祷式编程、撞大运式编程、屠宰式编程...
我最喜欢的编程风格是测试驱动开发。从User Story,到BDD,再到TDD一气呵成。
Mocha无论是名称还是其自身所散发的气质都让我爱不释手。可通过npm安装:
npm install -g mocha
TDD风格
可以新建一个js文件,然后使用mocha xxx.js
测试它:
var assert = require("assert");
var Class = {
define: function(options) {
var klass = function() {};
for (var prop in options) {
klass.prototype[prop] = options[prop];
}
return klass;
}
};
describe('Class', function() {
describe('define()', function() {
it('should return class when use Class.define', function() {
var Person = Class.define({
sayHello: function() {
return 'hello';
}
});
var jobs = new Person();
assert.equal('hello', jobs.sayHello());
});
});
});
BDD风格
mocha同样支持BDD风格。BDD风格的插件也很多,推荐should:
var assert = require("assert"),
should = require('should');
var Class = {
define: function(options) {
var klass = function() {};
for (var prop in options) {
klass.prototype[prop] = options[prop];
}
return klass;
}
};
describe('Class', function() {
describe('define()', function() {
it('should return class when use Class.define', function() {
var Person = Class.define({
sayHello: function() {
return 'hello';
}
});
var jobs = new Person();
jobs.sayHello().should.eql('hello');
});
});
});
使用-R spec
可以查看spec风格的测试报告mocha -R spec xxx.js
覆盖率测试
配合mocha使用blanket进行覆盖率测试:
mocha --require blanket -R html-cov>coverage.html xxx.js
使用blanket,需要配置一下package.json:
{
"config":{
"blanket":{
"pattern":"xxx.js"
}
}
}
运行mocha,测试的结果会以html-cov的形式输出到converage.html中。
Grunt
很多人都应该使用过Jenkins+Maven的CI组合。Grunt更像Gradle, 是一个基于JavaScript任务的命令行构建工具,可以用来执行合并、压缩和校验,运行单元测试以及启动静态服务器等任务。
可以使用npm来安装命令行工具:
npm install -g grunt-cli
grunt-cli,是指Grunt's command line interface。这里安装的是命令行而不是Grunt。在执行时,Grunt会自动寻找当前目录的gruntfile.js文件。可以手写这个文件,也可以通过grunt-init引导生成。
安装grunt-init:
npm install -g grunt-init
可选的模板很多,gruntfile生成模板是最常用的:
git clone https://github.com/gruntjs/grunt-init-gruntfile.git ~/.grunt-init/gruntfile
使用grunt-init gruntfile
依据引导生成gruntfile.js文件。
grunt为我们默认提供了一些常见的插件:
"devDependencies": {
"grunt": "~0.4.2",
"grunt-contrib-jshint": "~0.7.2",
"grunt-contrib-watch": "~0.5.3",
"grunt-contrib-qunit": "~0.3.0",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-uglify": "~0.2.7"
}
更新package.json,使用npm install
安装依赖。
合并、压缩
尽量减少网络IO带来的负担。
合并多个文件,减少网络的请求数量。通过精简压缩减小每次传输的大小。UglifyJS被认为是第一个基于NodeJS的压缩工具,UglifyJS是由Mihai Bazon用JavaScript编写的基于JavaScript的解析器。它会去除注释和额外的空格,替换变量名,合并var表达式,并进行一些其他方式的优化。
可以使用npm install uglify-js -g
安装uglify-js。
使用grunt,默认会选择uglify-js作为文件压缩工具。如果我们使用grunt-init自动生成了gruntfile文件,会发现关于合并、压缩的部分阅读起来没有什么难度,根据项目的要求自行修改即可。
更改gruntfile的结尾:grunt.registerTask('default', ['concat', 'uglify']);
,将concat和uglify的任务节点注册为默认的grunt文件。当在命令行中使用grunt
,会自动执行合并和压缩任务。
代码检查
可以在grunt中配置jshint的选项。并加jshint添加到默认的grunt任务:
grunt.registerTask('default', ['jshint','concat', 'uglify']);
可以使用grunt jshint
运行指定任务,也可以直接使用grunt
运行一系列js任务。
单元测试
grunt使用qunit作为默认的单元测试模块。这让我有些诧异。虽然qunit非常不错,不过业界...好吧。我,更喜欢使用mocha作为单元测试框架。
可以使用grunt-mocha-test
模块来代替qunit测试模块。
将grunt-mocha-test
添加到package.json的依赖模块中:
"devDependencies": {
"grunt": "~0.4.2",
"grunt-contrib-jshint": "~0.7.2",
"grunt-contrib-watch": "~0.5.3",
"grunt-contrib-qunit": "~0.3.0",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-uglify": "~0.2.7",
“grunt-mocha-test”:"*"
}
通过npm install
安装。
注册grunt-mocha-test
使用mochaTest任务替换qunit任务的配置项:
mochaTest: {
test: {
options: {
reporter: 'spec'
},
src: ['*.js']
}
},
并在grunt中调用grunt-mocha-test
模块:
grunt.loadNpmTasks('grunt-mocha-test');
可以使用grunt mochaTest
执行单元测试任务。也可以将mochaTest添加到默认的grunt任务中,这样在运行grunt时,会按照顺序执行jshint、mochaTest、concat、uglify四个任务。
grunt.registerTask('default', ['jshint','mochaTest','concat', 'uglify']);
将覆盖率测试添加进mochaTest任务
grunt-mocha-test
支持blanket的覆盖率测试配置:
mochaTest: {
test: {
options: {
reporter: 'spec',
require: 'coverage/blanket'
},
src: ['class_test.js']
},
coverage: {
options: {
reporter: 'html-cov',
quiet: true,
captureFile: 'coverage.html'
},
src: ['class_test.js']
}
},
mochaTest.test.options.require
选项会请求coverage
目录下的blanket.js
文件。这需要我们创建coverage目录,并在其中添加blanket.js文件:
require('blanket')({
pattern: 'class_test.js'
});
这个文件用来取代mocha --require blanket
中的blanket。并且通过代码的方式代替在package.json中定义的配置项。如此,在执行grunt命令时,就不需要在package.json中进行配置了。
执行grunt,可以在同级目录中查看到coverage.html测试覆盖率文件。
在创建一个可维护的项目时,使用构建系统仅仅是第一步,接下来是把构建系统集成到一个CI系统中。CI系统是建立在某些操作或者定期间隔的基础上自动运行生成的。这里有一些可以考虑的免费的CI系统:
- Jenkins
- Continuum
- BuildBot
- Cruise Control
- Gradle