mirror of
https://github.com/phodal/github
synced 2026-05-23 00:58:59 +00:00
update title
This commit is contained in:
parent
bf41b3926a
commit
5d6af08c47
4 changed files with 1060 additions and 15 deletions
|
|
@ -1,4 +1,4 @@
|
|||
#Github项目分析
|
||||
#Github流行项目分析
|
||||
|
||||
之前曾经分析过一些Github的用户行为,现在我们先来说说Github上的Star吧。(截止: 2015年3月9日23时。)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
今天就来说说是怎样做的。
|
||||
|
||||
##Github项目组成
|
||||
|
||||
以之前造的[Lettuce](https://github.com/phodal/lettuce)为例,里面有:
|
||||
|
||||
- 代码质量(Code Climate)
|
||||
|
|
@ -25,7 +23,7 @@
|
|||
|
||||
等等。
|
||||
|
||||
##Skillock模块化
|
||||
###Skillock模块化
|
||||
|
||||
在SkillTree的源码里,大致分为三部分:
|
||||
|
||||
|
|
@ -122,8 +120,6 @@ return {
|
|||
|
||||
当然函数也是一个对象。
|
||||
|
||||
##Skillock测试
|
||||
|
||||
###自动化测试
|
||||
|
||||
一直习惯用Travis CI,于是也继续用Travis Ci,``.travis.yml``配置如下所示:
|
||||
|
|
@ -161,7 +157,7 @@ branches:
|
|||
|
||||
最后的``test/spec``是指定测试的目录。
|
||||
|
||||
##Jshint
|
||||
###Jshint
|
||||
|
||||
> JSLint定义了一组编码约定,这比ECMA定义的语言更为严格。这些编码约定汲取了多年来的丰富编码经验,并以一条年代久远的编程原则 作为宗旨:能做并不意味着应该做。JSLint会对它认为有的编码实践加标志,另外还会指出哪些是明显的错误,从而促使你养成好的 JavaScript编码习惯。
|
||||
|
||||
|
|
@ -254,7 +250,7 @@ it('should return book label & url', function () {
|
|||
|
||||
这就是个问题了,于是偶然间看到了一个叫code climate的网站。
|
||||
|
||||
##Code Climate
|
||||
###Code Climate
|
||||
|
||||
> Code Climate consolidates the results from a suite of static analysis tools into a single, real-time report, giving your team the information it needs to identify hotspots, evaluate new approaches, and improve code quality.
|
||||
|
||||
|
|
@ -284,11 +280,11 @@ A | lib/url_handler.js | 9 | 0 | 5 | 2.2 | 94.1% | 0
|
|||
|
||||
![Coverage][1]
|
||||
|
||||
##代码的坏味道
|
||||
###代码的坏味道
|
||||
|
||||
于是我们就打开``lib/database/sqlite_helper.js``,因为其中有两个坏味道
|
||||
|
||||
###Similar code found in two :expression_statement nodes (mass = 86)
|
||||
Similar code found in two :expression_statement nodes (mass = 86)
|
||||
|
||||
在代码的 ``lib/database/sqlite_helper.js:58…61 < >``
|
||||
|
||||
|
|
|
|||
540
github-roam.md
540
github-roam.md
|
|
@ -1133,7 +1133,7 @@ def get_points(usernames):
|
|||
|
||||
真看不出来两者有什么相似的地方 。。。。
|
||||
|
||||
#Github项目分析
|
||||
#Github流行项目分析
|
||||
|
||||
之前曾经分析过一些Github的用户行为,现在我们先来说说Github上的Star吧。(截止: 2015年3月9日23时。)
|
||||
|
||||
|
|
@ -1199,12 +1199,550 @@ C | 2
|
|||
|
||||
#构建Github项目
|
||||
|
||||
##从模块分离到测试
|
||||
|
||||
在之前说到
|
||||
|
||||
> 奋斗了近半个月后,将fork的代码读懂、重构、升级版本、调整,添加新功能、添加测试、添加CI、添加分享之后,终于almost finish。
|
||||
|
||||
今天就来说说是怎样做的。
|
||||
|
||||
以之前造的[Lettuce](https://github.com/phodal/lettuce)为例,里面有:
|
||||
|
||||
- 代码质量(Code Climate)
|
||||
- CI状态(Travis CI)
|
||||
- 测试覆盖率(96%)
|
||||
- 自动化测试(npm test)
|
||||
- 文档
|
||||
|
||||
按照[Web Developer路线图](https://github.com/phodal/awesome-developer)来说,我们还需要有:
|
||||
|
||||
- 版本管理
|
||||
- 自动部署
|
||||
|
||||
等等。
|
||||
|
||||
###Skillock模块化
|
||||
|
||||
在SkillTree的源码里,大致分为三部分:
|
||||
|
||||
- namespace函数: 故名思意
|
||||
- Calculator也就是TalentTree,主要负责解析、生成url,头像,依赖等等
|
||||
- Skill 主要是tips部分。
|
||||
|
||||
而这一些都在一个js里,对于一个库来说,是一件好事,但是对于一个项目来说,并非如此。
|
||||
|
||||
依赖的库有
|
||||
|
||||
- jQuery
|
||||
- Knockout
|
||||
|
||||
好在Knockout可以用Require.js进行管理,于是,使用了``Require.js``进行管理:
|
||||
|
||||
```html
|
||||
<script type="text/javascript" data-main="app/scripts/main.js" src="app/lib/require.js"></script>
|
||||
```
|
||||
|
||||
``main.js``配置如下:
|
||||
|
||||
```javascript
|
||||
require.config({
|
||||
baseUrl: 'app',
|
||||
paths:{
|
||||
jquery: 'lib/jquery',
|
||||
json: 'lib/json',
|
||||
text: 'lib/text'
|
||||
}
|
||||
});
|
||||
|
||||
require(['scripts/ko-bindings']);
|
||||
|
||||
require(['lib/knockout', 'scripts/TalentTree', 'json!data/web.json'], function(ko, TalentTree, TalentData) {
|
||||
'use strict';
|
||||
var vm = new TalentTree(TalentData);
|
||||
ko.applyBindings(vm);
|
||||
});
|
||||
```
|
||||
|
||||
text、json插件主要是用于处理web.json,即用json来处理技能,于是不同的类到了不同的js文件。
|
||||
|
||||
.
|
||||
|____Book.js
|
||||
|____Doc.js
|
||||
|____ko-bindings.js
|
||||
|____Link.js
|
||||
|____main.js
|
||||
|____Skill.js
|
||||
|____TalentTree.js
|
||||
|____Utils.js
|
||||
|
||||
加上了后来的推荐阅读书籍等等。而Book和Link都是继承自Doc。
|
||||
|
||||
```javascript
|
||||
define(['scripts/Doc'], function(Doc) {
|
||||
'use strict';
|
||||
function Book(_e) {
|
||||
Doc.apply(this, arguments);
|
||||
}
|
||||
Book.prototype = new Doc();
|
||||
|
||||
return Book;
|
||||
});
|
||||
```
|
||||
|
||||
而这里便是后面对其进行重构的内容。Doc类则是Skillock中类的一个缩影
|
||||
|
||||
```javascript
|
||||
define([], function() {
|
||||
'use strict';
|
||||
var Doc = function (_e) {
|
||||
var e = _e || {};
|
||||
var self = this;
|
||||
|
||||
self.label = e.label || (e.url || 'Learn more');
|
||||
self.url = e.url || 'javascript:void(0)';
|
||||
};
|
||||
|
||||
return Doc;
|
||||
});
|
||||
```
|
||||
|
||||
或者说这是一个AMD的Class应该有的样子。考虑到this的隐性绑定,作者用了self=this来避免这个问题。最后Return了这个对象,我们在调用的就需要new一个。大部分在代码中返回的都是对象,除了在Utils类里面返回的是函数:
|
||||
|
||||
```javascript
|
||||
return {
|
||||
getSkillsByHash: getSkillsByHash,
|
||||
getSkillById: getSkillById,
|
||||
prettyJoin: prettyJoin
|
||||
};
|
||||
```
|
||||
|
||||
当然函数也是一个对象。
|
||||
|
||||
###自动化测试
|
||||
|
||||
一直习惯用Travis CI,于是也继续用Travis Ci,``.travis.yml``配置如下所示:
|
||||
|
||||
```yml
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
branches:
|
||||
only:
|
||||
- gh-pages
|
||||
```
|
||||
|
||||
使用gh-pages的原因是,我们一push代码的时候,就可以自动测试、部署等等,好处一堆堆的。
|
||||
|
||||
接着我们需要在``package.json``里面添加脚本
|
||||
|
||||
```javascript
|
||||
"scripts": {
|
||||
"test": "mocha"
|
||||
}
|
||||
```
|
||||
|
||||
这样当我们push代码的时候便会自动跑所有的测试。因为mocha的主要配置是用``mocha.opts``,所以我们还需要配置一下``mocha.opts``
|
||||
|
||||
--reporter spec
|
||||
--ui bdd
|
||||
--growl
|
||||
--colors
|
||||
test/spec
|
||||
|
||||
最后的``test/spec``是指定测试的目录。
|
||||
|
||||
###Jshint
|
||||
|
||||
> JSLint定义了一组编码约定,这比ECMA定义的语言更为严格。这些编码约定汲取了多年来的丰富编码经验,并以一条年代久远的编程原则 作为宗旨:能做并不意味着应该做。JSLint会对它认为有的编码实践加标志,另外还会指出哪些是明显的错误,从而促使你养成好的 JavaScript编码习惯。
|
||||
|
||||
当我们的js写得不合理的时候,这时测试就无法通过:
|
||||
|
||||
line 5 col 25 A constructor name should start with an uppercase letter.
|
||||
line 21 col 62 Strings must use singlequote.
|
||||
|
||||
这是一种驱动写出更规范js的方法。
|
||||
|
||||
|
||||
###Mocha
|
||||
|
||||
> Mocha 是一个优秀的JS测试框架,支持TDD/BDD,结合 should.js/expect/chai/better-assert,能轻松构建各种风格的测试用例。
|
||||
|
||||
最后的效果如下所示:
|
||||
|
||||
Book,Link
|
||||
Book Test
|
||||
✓ should return book label & url
|
||||
Link Test
|
||||
✓ should return link label & url
|
||||
|
||||
###测试用例
|
||||
|
||||
简单地看一下Book的测试:
|
||||
|
||||
```javascript
|
||||
/* global describe, it */
|
||||
|
||||
var requirejs = require("requirejs");
|
||||
var assert = require("assert");
|
||||
var should = require("should");
|
||||
requirejs.config({
|
||||
baseUrl: 'app/',
|
||||
nodeRequire: require
|
||||
});
|
||||
|
||||
describe('Book,Link', function () {
|
||||
var Book, Link;
|
||||
before(function (done) {
|
||||
requirejs(['scripts/Book'、], function (Book_Class) {
|
||||
Book = Book_Class;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Book Test', function () {
|
||||
it('should return book label & url', function () {
|
||||
var book_name = 'Head First HTML与CSS';
|
||||
var url = 'http://www.phodal.com';
|
||||
var books = {
|
||||
label: book_name,
|
||||
url: url
|
||||
};
|
||||
|
||||
var _book = new Book(books);
|
||||
_book.label.should.equal(book_name);
|
||||
_book.url.should.equal(url);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
因为我们用``require.js``来管理浏览器端,在后台写测试来测试的时候,我们也需要用他来管理我们的依赖,这也就是为什么这个测试这么从的原因,多数情况下一个测试类似于这样子的。(用Jasmine似乎会是一个更好的主意,但是用习惯Jasmine了)
|
||||
|
||||
```javascript
|
||||
describe('Book Test', function () {
|
||||
it('should return book label & url', function () {
|
||||
var book_name = 'Head First HTML与CSS';
|
||||
var url = 'http://www.phodal.com';
|
||||
var books = {
|
||||
label: book_name,
|
||||
url: url
|
||||
};
|
||||
|
||||
var _book = new Book(books);
|
||||
_book.label.should.equal(book_name);
|
||||
_book.url.should.equal(url);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
最后的断言,也算是测试的核心,保证测试是有用的。
|
||||
|
||||
##Code Climate来clean code与重构
|
||||
|
||||
- 当你写了一大堆代码,你没有意识到里面有一大堆重复。
|
||||
- 当你写了一大堆测试,却不知道覆盖率有多少。
|
||||
|
||||
这就是个问题了,于是偶然间看到了一个叫code climate的网站。
|
||||
|
||||
###Code Climate
|
||||
|
||||
> Code Climate consolidates the results from a suite of static analysis tools into a single, real-time report, giving your team the information it needs to identify hotspots, evaluate new approaches, and improve code quality.
|
||||
|
||||
Code Climate整合一组静态分析工具的结果到一个单一的,实时的报告,让您的团队需要识别热点,探讨新的方法,提高代码质量的信息。
|
||||
|
||||
简单地来说:
|
||||
|
||||
- 对我们的代码评分
|
||||
- 找出代码中的坏味道
|
||||
|
||||
于是,我们先来了个例子
|
||||
|
||||
Rating | Name | Complexity | Duplication | Churn | C/M | Coverage | Smells
|
||||
--------|------|--------------|-------------|----------|---------|---------------------
|
||||
A | lib/coap/coap_request_handler.js | 24 | 0 | 6 | 2.6 | 46.4% | 0
|
||||
A | lib/coap/coap_result_helper.js | 14 | 0 | 2 | 3.4 | 80.0% | 0
|
||||
A | lib/coap/coap_server.js | 16 | 0 | 5 | 5.2 | 44.0% | 0
|
||||
A | lib/database/db_factory.js | 8 | 0 | 3 | 3.8 | 92.3% | 0
|
||||
A | lib/database/iot_db.js | 7 | 0 | 6 | 1.0 | 58.8% | 0
|
||||
A | lib/database/mongodb_helper.js | 63 | 0 | 11 | 4.5 | 35.0% | 0
|
||||
C | lib/database/sqlite_helper.js | 32 | 86 | 10 | 4.5 | 35.0% | 2
|
||||
B | lib/rest/rest_helper.js | 19 | 62 | 3 | 4.7 | 37.5% | 2
|
||||
A | lib/rest/rest_server.js | 17 | 0 | 2 | 8.6 | 88.9% | 0
|
||||
A | lib/url_handler.js | 9 | 0 | 5 | 2.2 | 94.1% | 0
|
||||
|
||||
分享得到的最后的结果是:
|
||||
|
||||
![Coverage][1]
|
||||
|
||||
###代码的坏味道
|
||||
|
||||
于是我们就打开``lib/database/sqlite_helper.js``,因为其中有两个坏味道
|
||||
|
||||
Similar code found in two :expression_statement nodes (mass = 86)
|
||||
|
||||
在代码的 ``lib/database/sqlite_helper.js:58…61 < >``
|
||||
|
||||
```javascript
|
||||
SQLiteHelper.prototype.deleteData = function (url, callback) {
|
||||
'use strict';
|
||||
var sql_command = "DELETE FROM " + config.table_name + " where " + URLHandler.getKeyFromURL(url) + "=" + URLHandler.getValueFromURL(url);
|
||||
SQLiteHelper.prototype.basic(sql_command, callback);
|
||||
```
|
||||
|
||||
lib/database/sqlite_helper.js:64…67 < >
|
||||
|
||||
与
|
||||
|
||||
```javascript
|
||||
SQLiteHelper.prototype.getData = function (url, callback) {
|
||||
'use strict';
|
||||
var sql_command = "SELECT * FROM " + config.table_name + " where " + URLHandler.getKeyFromURL(url) + "=" + URLHandler.getValueFromURL(url);
|
||||
SQLiteHelper.prototype.basic(sql_command, callback);
|
||||
```
|
||||
|
||||
只是这是之前修改过的重复。。
|
||||
|
||||
原来的代码是这样的
|
||||
|
||||
```javascript
|
||||
SQLiteHelper.prototype.postData = function (block, callback) {
|
||||
'use strict';
|
||||
var db = new sqlite3.Database(config.db_name);
|
||||
var str = this.parseData(config.keys);
|
||||
var string = this.parseData(block);
|
||||
|
||||
var sql_command = "insert or replace into " + config.table_name + " (" + str + ") VALUES (" + string + ");";
|
||||
db.all(sql_command, function (err) {
|
||||
SQLiteHelper.prototype.errorHandler(err);
|
||||
db.close();
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
SQLiteHelper.prototype.deleteData = function (url, callback) {
|
||||
'use strict';
|
||||
var db = new sqlite3.Database(config.db_name);
|
||||
var sql_command = "DELETE FROM " + config.table_name + " where " + URLHandler.getKeyFromURL(url) + "=" + URLHandler.getValueFromURL(url);
|
||||
db.all(sql_command, function (err) {
|
||||
SQLiteHelper.prototype.errorHandler(err);
|
||||
db.close();
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
SQLiteHelper.prototype.getData = function (url, callback) {
|
||||
'use strict';
|
||||
var db = new sqlite3.Database(config.db_name);
|
||||
var sql_command = "SELECT * FROM " + config.table_name + " where " + URLHandler.getKeyFromURL(url) + "=" + URLHandler.getValueFromURL(url);
|
||||
db.all(sql_command, function (err, rows) {
|
||||
SQLiteHelper.prototype.errorHandler(err);
|
||||
db.close();
|
||||
callback(JSON.stringify(rows));
|
||||
});
|
||||
};
|
||||
```
|
||||
说的也是大量的重复,重构完的代码
|
||||
|
||||
```javascript
|
||||
SQLiteHelper.prototype.basic = function(sql, db_callback){
|
||||
'use strict';
|
||||
var db = new sqlite3.Database(config.db_name);
|
||||
db.all(sql, function (err, rows) {
|
||||
SQLiteHelper.prototype.errorHandler(err);
|
||||
db.close();
|
||||
db_callback(JSON.stringify(rows));
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
SQLiteHelper.prototype.postData = function (block, callback) {
|
||||
'use strict';
|
||||
var str = this.parseData(config.keys);
|
||||
var string = this.parseData(block);
|
||||
|
||||
var sql_command = "insert or replace into " + config.table_name + " (" + str + ") VALUES (" + string + ");";
|
||||
SQLiteHelper.prototype.basic(sql_command, callback);
|
||||
};
|
||||
|
||||
SQLiteHelper.prototype.deleteData = function (url, callback) {
|
||||
'use strict';
|
||||
var sql_command = "DELETE FROM " + config.table_name + " where " + URLHandler.getKeyFromURL(url) + "=" + URLHandler.getValueFromURL(url);
|
||||
SQLiteHelper.prototype.basic(sql_command, callback);
|
||||
};
|
||||
|
||||
SQLiteHelper.prototype.getData = function (url, callback) {
|
||||
'use strict';
|
||||
var sql_command = "SELECT * FROM " + config.table_name + " where " + URLHandler.getKeyFromURL(url) + "=" + URLHandler.getValueFromURL(url);
|
||||
SQLiteHelper.prototype.basic(sql_command, callback);
|
||||
};
|
||||
```
|
||||
|
||||
重构完后的代码比原来还长,这似乎是个问题~~
|
||||
|
||||
#创建项目文档
|
||||
|
||||
#测试
|
||||
|
||||
#重构
|
||||
|
||||
或许你应该知道了,重构是怎样的,你也知道重构能带来什么。在我刚开始学重构和设计模式的时候,我需要去找一些好的示例,以便于我更好的学习。有时候不得不创造一些更好的场景,来实现这些功能。
|
||||
|
||||
有一天,我发现当我需要我一次又一次地重复讲述某些内容,于是我就计划着把这些应该掌握的技能放到Github上,也就有了[Artisan Stack](https://github.com/artisanstack) 计划。
|
||||
|
||||
每个程序员都不可避免地是一个Coder,一个没有掌握好技能的Coder,算不上是手工艺人,但是是手工人。
|
||||
|
||||
艺,需要有创造性的方法。
|
||||
|
||||
#[前端技能训练: 重构一](http://www.phodal.com/blog/frontend-improve-refactor-javascript-code/)
|
||||
|
||||
##为什么重构?
|
||||
|
||||
> 为了更好的代码。
|
||||
|
||||
在经历了一年多的工作之后,我平时的主要工作就是修Bug。刚开始的时候觉得无聊,后来才发现修Bug需要更好的技术。有时候你可能要面对着一坨一坨的代码,有时候你可能要花几天的时间去阅读代码。而,你重写那几十代码可能只会花上你不到一天的时间。但是如果你没办法理解当时为什么这么做,你的修改只会带来更多的bug。修Bug,更多的是维护代码。还是前人总结的那句话对:
|
||||
|
||||
> 写代码容易,读代码难。
|
||||
|
||||
假设我们写这些代码只要半天,而别人读起来要一天。为什么不试着用一天的时候去写这些代码,让别人花半天或者更少的时间来理解。
|
||||
|
||||
如果你的代码已经上线,虽然是一坨坨的。但是不要轻易尝试,``没有测试的重构``。
|
||||
|
||||
从前端开始的原因在于,写得一坨坨且最不容易测试的代码都在前端。
|
||||
|
||||
让我们来看看我们的第一个训练,相当有挑战性。
|
||||
|
||||
##重构uMarkdown
|
||||
|
||||
代码及setup请见github: [js-refactor](https://github.com/artisanstack/js-refactor)
|
||||
|
||||
###代码说明
|
||||
|
||||
``uMarkdown``是一个用于将Markdown转化为HTML的库。代码看上去就像一个很典型的过程代码:
|
||||
|
||||
```javascript
|
||||
/* code */
|
||||
while ((stra = micromarkdown.regexobject.code.exec(str)) !== null) {
|
||||
str = str.replace(stra[0], '<code>\n' + micromarkdown.htmlEncode(stra[1]).replace(/\n/gm, '<br/>').replace(/\ /gm, ' ') + '</code>\n');
|
||||
}
|
||||
|
||||
/* headlines */
|
||||
while ((stra = micromarkdown.regexobject.headline.exec(str)) !== null) {
|
||||
count = stra[1].length;
|
||||
str = str.replace(stra[0], '<h' + count + '>' + stra[2] + '</h' + count + '>' + '\n');
|
||||
}
|
||||
|
||||
/* mail */
|
||||
while ((stra = micromarkdown.regexobject.mail.exec(str)) !== null) {
|
||||
str = str.replace(stra[0], '<a href="mailto:' + stra[1] + '">' + stra[1] + '</a>');
|
||||
}
|
||||
```
|
||||
|
||||
选这个做重构的开始,不仅仅是因为之前在写[EchoesWorks](https://github.com/phodal/echoesworks)的时候进行了很多的重构。而且它更适合于,``重构到设计模式``的理论。让我们在重构完之后,给作者进行pull request吧。
|
||||
|
||||
Markdown的解析过程,有点类似于``Pipe and Filters``模式(架构模式)。
|
||||
|
||||
Filter即我们在代码中看到的正规表达式集:
|
||||
|
||||
```javascript
|
||||
regexobject: {
|
||||
headline: /^(\#{1,6})([^\#\n]+)$/m,
|
||||
code: /\s\`\`\`\n?([^`]+)\`\`\`/g
|
||||
```
|
||||
|
||||
他会匹配对应的Markdown类型,随后进行替换和处理。而``str```,就是管理口的输入和输出。
|
||||
|
||||
接着,我们就可以对其进行简单的重构。
|
||||
|
||||
###重构
|
||||
|
||||
(ps: 推荐用WebStrom来做重构,自带重构功能)
|
||||
|
||||
作为一个示例,我们先提出codeHandler方法,即将上面的
|
||||
|
||||
```javascript
|
||||
/* code */
|
||||
while ((stra = micromarkdown.regexobject.code.exec(str)) !== null) {
|
||||
str = str.replace(stra[0], '<code>\n' + micromarkdown.htmlEncode(stra[1]).replace(/\n/gm, '<br/>').replace(/\ /gm, ' ') + '</code>\n');
|
||||
}
|
||||
```
|
||||
|
||||
提取方法成
|
||||
|
||||
```javascript
|
||||
codeFilter: function (str, stra) {
|
||||
return str.replace(stra[0], '<code>\n' + micromarkdown.htmlEncode(stra[1]).replace(/\n/gm, '<br/>').replace(/\ /gm, ' ') + '</code>\n');
|
||||
},
|
||||
```
|
||||
|
||||
while语句就成了
|
||||
|
||||
```javascript
|
||||
while ((stra = regexobject.code.exec(str)) !== null) {
|
||||
str = this.codeFilter(str, stra);
|
||||
}
|
||||
```
|
||||
|
||||
然后,运行所有的测试。
|
||||
|
||||
```
|
||||
grunt test
|
||||
```
|
||||
|
||||
同理我们就可以``mail``、``headline``等方法进行重构。接着就会变成类似于下面的代码,
|
||||
|
||||
```javascript
|
||||
/* code */
|
||||
while ((execStr = regExpObject.code.exec(str)) !== null) {
|
||||
str = codeHandler(str, execStr);
|
||||
}
|
||||
|
||||
/* headlines */
|
||||
while ((execStr = regExpObject.headline.exec(str)) !== null) {
|
||||
str = headlineHandler(str, execStr);
|
||||
}
|
||||
|
||||
/* lists */
|
||||
while ((execStr = regExpObject.lists.exec(str)) !== null) {
|
||||
str = listHandler(str, execStr);
|
||||
}
|
||||
|
||||
/* tables */
|
||||
while ((execStr = regExpObject.tables.exec(str)) !== null) {
|
||||
str = tableHandler(str, execStr, strict);
|
||||
}
|
||||
```
|
||||
|
||||
然后你也看到了,上面有一堆重复的代码,接着让我们用JavaScript的``奇技浮巧``,即apply方法,把上面的重复代码变成。
|
||||
|
||||
```javascript
|
||||
['code', 'headline', 'lists', 'tables', 'links', 'mail', 'url', 'smlinks', 'hr'].forEach(function (type) {
|
||||
while ((stra = regexobject[type].exec(str)) !== null) {
|
||||
str = that[(type + 'Handler')].apply(that, [stra, str, strict]);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
进行测试,blabla,都是过的。
|
||||
|
||||
```javascript
|
||||
Markdown
|
||||
✓ should parse h1~h3
|
||||
✓ should parse link
|
||||
✓ should special link
|
||||
✓ should parse font style
|
||||
✓ should parse code
|
||||
✓ should parse ul list
|
||||
✓ should parse ul table
|
||||
✓ should return correctly class name
|
||||
```
|
||||
|
||||
快来试试吧, [https://github.com/artisanstack/js-refactor](https://github.com/artisanstack/js-refactor)
|
||||
|
||||
#Github连击
|
||||
|
||||
##100天
|
||||
|
|
|
|||
519
index.html
519
index.html
|
|
@ -117,16 +117,35 @@ code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Inf
|
|||
</ul></li>
|
||||
<li><a href="#邻近算法">邻近算法</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#github项目分析">Github项目分析</a></li>
|
||||
<li><a href="#github流行项目分析">Github流行项目分析</a></li>
|
||||
<li><a href="#创建pull-request">创建Pull Request</a><ul>
|
||||
<li><a href="#第一个">第一个</a></li>
|
||||
<li><a href="#google-ngx-pagespeed">Google Ngx Pagespeed</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#创建你的项目">创建你的项目</a></li>
|
||||
<li><a href="#构建github项目">构建Github项目</a></li>
|
||||
<li><a href="#构建github项目">构建Github项目</a><ul>
|
||||
<li><a href="#从模块分离到测试">从模块分离到测试</a><ul>
|
||||
<li><a href="#skillock模块化">Skillock模块化</a></li>
|
||||
<li><a href="#自动化测试">自动化测试</a></li>
|
||||
<li><a href="#jshint">Jshint</a></li>
|
||||
<li><a href="#mocha">Mocha</a></li>
|
||||
<li><a href="#测试用例">测试用例</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#code-climate来clean-code与重构">Code Climate来clean code与重构</a><ul>
|
||||
<li><a href="#code-climate">Code Climate</a></li>
|
||||
<li><a href="#代码的坏味道">代码的坏味道</a></li>
|
||||
</ul></li>
|
||||
</ul></li>
|
||||
<li><a href="#创建项目文档">创建项目文档</a></li>
|
||||
<li><a href="#测试-1">测试</a></li>
|
||||
<li><a href="#重构-1">重构</a></li>
|
||||
<li><a href="#前端技能训练-重构一"><a href="http://www.phodal.com/blog/frontend-improve-refactor-javascript-code/">前端技能训练: 重构一</a></a><ul>
|
||||
<li><a href="#为什么重构">为什么重构?</a></li>
|
||||
<li><a href="#重构umarkdown">重构uMarkdown</a><ul>
|
||||
<li><a href="#代码说明">代码说明</a></li>
|
||||
<li><a href="#重构-2">重构</a></li>
|
||||
</ul></li>
|
||||
</ul></li>
|
||||
<li><a href="#github连击">Github连击</a><ul>
|
||||
<li><a href="#天">100天</a><ul>
|
||||
<li><a href="#天的提升">40天的提升</a></li>
|
||||
|
|
@ -973,7 +992,7 @@ pipe.execute()</code></pre></div>
|
|||
0. 0. 0. 0. 0. 0. 0.
|
||||
0. 0. 0. 0. ]</code></pre>
|
||||
<p>真看不出来两者有什么相似的地方 。。。。</p>
|
||||
<h1 id="github项目分析">Github项目分析</h1>
|
||||
<h1 id="github流行项目分析">Github流行项目分析</h1>
|
||||
<p>之前曾经分析过一些Github的用户行为,现在我们先来说说Github上的Star吧。(截止: 2015年3月9日23时。)</p>
|
||||
<table>
|
||||
<thead>
|
||||
|
|
@ -1100,9 +1119,501 @@ pipe.execute()</code></pre></div>
|
|||
fi</code></pre>
|
||||
<h1 id="创建你的项目">创建你的项目</h1>
|
||||
<h1 id="构建github项目">构建Github项目</h1>
|
||||
<h2 id="从模块分离到测试">从模块分离到测试</h2>
|
||||
<p>在之前说到</p>
|
||||
<blockquote>
|
||||
<p>奋斗了近半个月后,将fork的代码读懂、重构、升级版本、调整,添加新功能、添加测试、添加CI、添加分享之后,终于almost finish。</p>
|
||||
</blockquote>
|
||||
<p>今天就来说说是怎样做的。</p>
|
||||
<p>以之前造的<a href="https://github.com/phodal/lettuce">Lettuce</a>为例,里面有:</p>
|
||||
<ul>
|
||||
<li>代码质量(Code Climate)</li>
|
||||
<li>CI状态(Travis CI)</li>
|
||||
<li>测试覆盖率(96%)</li>
|
||||
<li>自动化测试(npm test)</li>
|
||||
<li>文档</li>
|
||||
</ul>
|
||||
<p>按照<a href="https://github.com/phodal/awesome-developer">Web Developer路线图</a>来说,我们还需要有:</p>
|
||||
<ul>
|
||||
<li>版本管理</li>
|
||||
<li>自动部署</li>
|
||||
</ul>
|
||||
<p>等等。</p>
|
||||
<h3 id="skillock模块化">Skillock模块化</h3>
|
||||
<p>在SkillTree的源码里,大致分为三部分:</p>
|
||||
<ul>
|
||||
<li>namespace函数: 故名思意</li>
|
||||
<li>Calculator也就是TalentTree,主要负责解析、生成url,头像,依赖等等</li>
|
||||
<li>Skill 主要是tips部分。</li>
|
||||
</ul>
|
||||
<p>而这一些都在一个js里,对于一个库来说,是一件好事,但是对于一个项目来说,并非如此。</p>
|
||||
<p>依赖的库有</p>
|
||||
<ul>
|
||||
<li>jQuery</li>
|
||||
<li>Knockout</li>
|
||||
</ul>
|
||||
<p>好在Knockout可以用Require.js进行管理,于是,使用了<code>Require.js</code>进行管理:</p>
|
||||
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html"><span class="kw"><script</span><span class="ot"> type=</span><span class="st">"text/javascript"</span><span class="ot"> data-main=</span><span class="st">"app/scripts/main.js"</span><span class="ot"> src=</span><span class="st">"app/lib/require.js"</span><span class="kw">></script></span></code></pre></div>
|
||||
<p><code>main.js</code>配置如下:</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">require</span>.<span class="at">config</span>(<span class="op">{</span>
|
||||
<span class="dt">baseUrl</span><span class="op">:</span> <span class="st">'app'</span><span class="op">,</span>
|
||||
<span class="dt">paths</span><span class="op">:{</span>
|
||||
<span class="dt">jquery</span><span class="op">:</span> <span class="st">'lib/jquery'</span><span class="op">,</span>
|
||||
<span class="dt">json</span><span class="op">:</span> <span class="st">'lib/json'</span><span class="op">,</span>
|
||||
<span class="dt">text</span><span class="op">:</span> <span class="st">'lib/text'</span>
|
||||
<span class="op">}</span>
|
||||
<span class="op">}</span>)<span class="op">;</span>
|
||||
|
||||
<span class="at">require</span>([<span class="st">'scripts/ko-bindings'</span>])<span class="op">;</span>
|
||||
|
||||
<span class="at">require</span>([<span class="st">'lib/knockout'</span><span class="op">,</span> <span class="st">'scripts/TalentTree'</span><span class="op">,</span> <span class="st">'json!data/web.json'</span>]<span class="op">,</span> <span class="kw">function</span>(ko<span class="op">,</span> TalentTree<span class="op">,</span> TalentData) <span class="op">{</span>
|
||||
<span class="st">'use strict'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> vm <span class="op">=</span> <span class="kw">new</span> <span class="at">TalentTree</span>(TalentData)<span class="op">;</span>
|
||||
<span class="va">ko</span>.<span class="at">applyBindings</span>(vm)<span class="op">;</span>
|
||||
<span class="op">}</span>)<span class="op">;</span></code></pre></div>
|
||||
<p>text、json插件主要是用于处理web.json,即用json来处理技能,于是不同的类到了不同的js文件。</p>
|
||||
<pre><code>.
|
||||
|____Book.js
|
||||
|____Doc.js
|
||||
|____ko-bindings.js
|
||||
|____Link.js
|
||||
|____main.js
|
||||
|____Skill.js
|
||||
|____TalentTree.js
|
||||
|____Utils.js</code></pre>
|
||||
<p>加上了后来的推荐阅读书籍等等。而Book和Link都是继承自Doc。</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="at">define</span>([<span class="st">'scripts/Doc'</span>]<span class="op">,</span> <span class="kw">function</span>(Doc) <span class="op">{</span>
|
||||
<span class="st">'use strict'</span><span class="op">;</span>
|
||||
<span class="kw">function</span> <span class="at">Book</span>(_e) <span class="op">{</span>
|
||||
<span class="va">Doc</span>.<span class="at">apply</span>(<span class="kw">this</span><span class="op">,</span> arguments)<span class="op">;</span>
|
||||
<span class="op">}</span>
|
||||
<span class="va">Book</span>.<span class="at">prototype</span> <span class="op">=</span> <span class="kw">new</span> <span class="at">Doc</span>()<span class="op">;</span>
|
||||
|
||||
<span class="cf">return</span> Book<span class="op">;</span>
|
||||
<span class="op">}</span>)<span class="op">;</span> </code></pre></div>
|
||||
<p>而这里便是后面对其进行重构的内容。Doc类则是Skillock中类的一个缩影</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="at">define</span>([]<span class="op">,</span> <span class="kw">function</span>() <span class="op">{</span>
|
||||
<span class="st">'use strict'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> Doc <span class="op">=</span> <span class="kw">function</span> (_e) <span class="op">{</span>
|
||||
<span class="kw">var</span> e <span class="op">=</span> _e <span class="op">||</span> <span class="op">{};</span>
|
||||
<span class="kw">var</span> self <span class="op">=</span> <span class="kw">this</span><span class="op">;</span>
|
||||
|
||||
<span class="va">self</span>.<span class="at">label</span> <span class="op">=</span> <span class="va">e</span>.<span class="at">label</span> <span class="op">||</span> (<span class="va">e</span>.<span class="at">url</span> <span class="op">||</span> <span class="st">'Learn more'</span>)<span class="op">;</span>
|
||||
<span class="va">self</span>.<span class="at">url</span> <span class="op">=</span> <span class="va">e</span>.<span class="at">url</span> <span class="op">||</span> <span class="st">'javascript:void(0)'</span><span class="op">;</span>
|
||||
<span class="op">};</span>
|
||||
|
||||
<span class="cf">return</span> Doc<span class="op">;</span>
|
||||
<span class="op">}</span>)<span class="op">;</span></code></pre></div>
|
||||
<p>或者说这是一个AMD的Class应该有的样子。考虑到this的隐性绑定,作者用了self=this来避免这个问题。最后Return了这个对象,我们在调用的就需要new一个。大部分在代码中返回的都是对象,除了在Utils类里面返回的是函数:</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="cf">return</span> <span class="op">{</span>
|
||||
<span class="dt">getSkillsByHash</span><span class="op">:</span> getSkillsByHash<span class="op">,</span>
|
||||
<span class="dt">getSkillById</span><span class="op">:</span> getSkillById<span class="op">,</span>
|
||||
<span class="dt">prettyJoin</span><span class="op">:</span> prettyJoin
|
||||
<span class="op">};</span></code></pre></div>
|
||||
<p>当然函数也是一个对象。</p>
|
||||
<h3 id="自动化测试">自动化测试</h3>
|
||||
<p>一直习惯用Travis CI,于是也继续用Travis Ci,<code>.travis.yml</code>配置如下所示:</p>
|
||||
<pre class="yml"><code>language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
branches:
|
||||
only:
|
||||
- gh-pages</code></pre>
|
||||
<p>使用gh-pages的原因是,我们一push代码的时候,就可以自动测试、部署等等,好处一堆堆的。</p>
|
||||
<p>接着我们需要在<code>package.json</code>里面添加脚本</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="st">"scripts"</span><span class="op">:</span> <span class="op">{</span>
|
||||
<span class="st">"test"</span><span class="op">:</span> <span class="st">"mocha"</span>
|
||||
<span class="op">}</span></code></pre></div>
|
||||
<p>这样当我们push代码的时候便会自动跑所有的测试。因为mocha的主要配置是用<code>mocha.opts</code>,所以我们还需要配置一下<code>mocha.opts</code></p>
|
||||
<pre><code>--reporter spec
|
||||
--ui bdd
|
||||
--growl
|
||||
--colors
|
||||
test/spec </code></pre>
|
||||
<p>最后的<code>test/spec</code>是指定测试的目录。</p>
|
||||
<h3 id="jshint">Jshint</h3>
|
||||
<blockquote>
|
||||
<p>JSLint定义了一组编码约定,这比ECMA定义的语言更为严格。这些编码约定汲取了多年来的丰富编码经验,并以一条年代久远的编程原则 作为宗旨:能做并不意味着应该做。JSLint会对它认为有的编码实践加标志,另外还会指出哪些是明显的错误,从而促使你养成好的 JavaScript编码习惯。</p>
|
||||
</blockquote>
|
||||
<p>当我们的js写得不合理的时候,这时测试就无法通过:</p>
|
||||
<pre><code>line 5 col 25 A constructor name should start with an uppercase letter.
|
||||
line 21 col 62 Strings must use singlequote.</code></pre>
|
||||
<p>这是一种驱动写出更规范js的方法。</p>
|
||||
<h3 id="mocha">Mocha</h3>
|
||||
<blockquote>
|
||||
<p>Mocha 是一个优秀的JS测试框架,支持TDD/BDD,结合 should.js/expect/chai/better-assert,能轻松构建各种风格的测试用例。</p>
|
||||
</blockquote>
|
||||
<p>最后的效果如下所示:</p>
|
||||
<pre><code>Book,Link
|
||||
Book Test
|
||||
✓ should return book label & url
|
||||
Link Test
|
||||
✓ should return link label & url</code></pre>
|
||||
<h3 id="测试用例">测试用例</h3>
|
||||
<p>简单地看一下Book的测试:</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="co">/* global describe, it */</span>
|
||||
|
||||
<span class="kw">var</span> requirejs <span class="op">=</span> <span class="at">require</span>(<span class="st">"requirejs"</span>)<span class="op">;</span>
|
||||
<span class="kw">var</span> assert <span class="op">=</span> <span class="at">require</span>(<span class="st">"assert"</span>)<span class="op">;</span>
|
||||
<span class="kw">var</span> should <span class="op">=</span> <span class="at">require</span>(<span class="st">"should"</span>)<span class="op">;</span>
|
||||
<span class="va">requirejs</span>.<span class="at">config</span>(<span class="op">{</span>
|
||||
<span class="dt">baseUrl</span><span class="op">:</span> <span class="st">'app/'</span><span class="op">,</span>
|
||||
<span class="dt">nodeRequire</span><span class="op">:</span> require
|
||||
<span class="op">}</span>)<span class="op">;</span>
|
||||
|
||||
<span class="at">describe</span>(<span class="st">'Book,Link'</span><span class="op">,</span> <span class="kw">function</span> () <span class="op">{</span>
|
||||
<span class="kw">var</span> Book<span class="op">,</span> Link<span class="op">;</span>
|
||||
<span class="at">before</span>(<span class="kw">function</span> (done) <span class="op">{</span>
|
||||
<span class="at">requirejs</span>([<span class="st">'scripts/Book'</span>、]<span class="op">,</span> <span class="kw">function</span> (Book_Class) <span class="op">{</span>
|
||||
Book <span class="op">=</span> Book_Class<span class="op">;</span>
|
||||
<span class="at">done</span>()<span class="op">;</span>
|
||||
<span class="op">}</span>)<span class="op">;</span>
|
||||
<span class="op">}</span>)<span class="op">;</span>
|
||||
|
||||
<span class="at">describe</span>(<span class="st">'Book Test'</span><span class="op">,</span> <span class="kw">function</span> () <span class="op">{</span>
|
||||
<span class="at">it</span>(<span class="st">'should return book label & url'</span><span class="op">,</span> <span class="kw">function</span> () <span class="op">{</span>
|
||||
<span class="kw">var</span> book_name <span class="op">=</span> <span class="st">'Head First HTML与CSS'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> url <span class="op">=</span> <span class="st">'http://www.phodal.com'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> books <span class="op">=</span> <span class="op">{</span>
|
||||
<span class="dt">label</span><span class="op">:</span> book_name<span class="op">,</span>
|
||||
<span class="dt">url</span><span class="op">:</span> url
|
||||
<span class="op">};</span>
|
||||
|
||||
<span class="kw">var</span> _book <span class="op">=</span> <span class="kw">new</span> <span class="at">Book</span>(books)<span class="op">;</span>
|
||||
<span class="va">_book</span>.<span class="va">label</span>.<span class="va">should</span>.<span class="at">equal</span>(book_name)<span class="op">;</span>
|
||||
<span class="va">_book</span>.<span class="va">url</span>.<span class="va">should</span>.<span class="at">equal</span>(url)<span class="op">;</span>
|
||||
<span class="op">}</span>)<span class="op">;</span>
|
||||
<span class="op">}</span>)<span class="op">;</span>
|
||||
<span class="op">}</span>)<span class="op">;</span></code></pre></div>
|
||||
<p>因为我们用<code>require.js</code>来管理浏览器端,在后台写测试来测试的时候,我们也需要用他来管理我们的依赖,这也就是为什么这个测试这么从的原因,多数情况下一个测试类似于这样子的。(用Jasmine似乎会是一个更好的主意,但是用习惯Jasmine了)</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="at">describe</span>(<span class="st">'Book Test'</span><span class="op">,</span> <span class="kw">function</span> () <span class="op">{</span>
|
||||
<span class="at">it</span>(<span class="st">'should return book label & url'</span><span class="op">,</span> <span class="kw">function</span> () <span class="op">{</span>
|
||||
<span class="kw">var</span> book_name <span class="op">=</span> <span class="st">'Head First HTML与CSS'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> url <span class="op">=</span> <span class="st">'http://www.phodal.com'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> books <span class="op">=</span> <span class="op">{</span>
|
||||
<span class="dt">label</span><span class="op">:</span> book_name<span class="op">,</span>
|
||||
<span class="dt">url</span><span class="op">:</span> url
|
||||
<span class="op">};</span>
|
||||
|
||||
<span class="kw">var</span> _book <span class="op">=</span> <span class="kw">new</span> <span class="at">Book</span>(books)<span class="op">;</span>
|
||||
<span class="va">_book</span>.<span class="va">label</span>.<span class="va">should</span>.<span class="at">equal</span>(book_name)<span class="op">;</span>
|
||||
<span class="va">_book</span>.<span class="va">url</span>.<span class="va">should</span>.<span class="at">equal</span>(url)<span class="op">;</span>
|
||||
<span class="op">}</span>)<span class="op">;</span>
|
||||
<span class="op">}</span>)<span class="op">;</span></code></pre></div>
|
||||
<p>最后的断言,也算是测试的核心,保证测试是有用的。</p>
|
||||
<h2 id="code-climate来clean-code与重构">Code Climate来clean code与重构</h2>
|
||||
<ul>
|
||||
<li>当你写了一大堆代码,你没有意识到里面有一大堆重复。</li>
|
||||
<li>当你写了一大堆测试,却不知道覆盖率有多少。</li>
|
||||
</ul>
|
||||
<p>这就是个问题了,于是偶然间看到了一个叫code climate的网站。</p>
|
||||
<h3 id="code-climate">Code Climate</h3>
|
||||
<blockquote>
|
||||
<p>Code Climate consolidates the results from a suite of static analysis tools into a single, real-time report, giving your team the information it needs to identify hotspots, evaluate new approaches, and improve code quality.</p>
|
||||
</blockquote>
|
||||
<p>Code Climate整合一组静态分析工具的结果到一个单一的,实时的报告,让您的团队需要识别热点,探讨新的方法,提高代码质量的信息。</p>
|
||||
<p>简单地来说:</p>
|
||||
<ul>
|
||||
<li>对我们的代码评分</li>
|
||||
<li>找出代码中的坏味道</li>
|
||||
</ul>
|
||||
<p>于是,我们先来了个例子</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
<th style="text-align: left;">Rating</th>
|
||||
<th style="text-align: left;">Name</th>
|
||||
<th style="text-align: left;">Complexity</th>
|
||||
<th style="text-align: left;">Duplication</th>
|
||||
<th style="text-align: left;">Churn</th>
|
||||
<th style="text-align: left;">C/M</th>
|
||||
<th style="text-align: left;">Coverage</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td style="text-align: left;">A</td>
|
||||
<td style="text-align: left;">lib/coap/coap_request_handler.js</td>
|
||||
<td style="text-align: left;">24</td>
|
||||
<td style="text-align: left;">0</td>
|
||||
<td style="text-align: left;">6</td>
|
||||
<td style="text-align: left;">2.6</td>
|
||||
<td style="text-align: left;">46.4%</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td style="text-align: left;">A</td>
|
||||
<td style="text-align: left;">lib/coap/coap_result_helper.js</td>
|
||||
<td style="text-align: left;">14</td>
|
||||
<td style="text-align: left;">0</td>
|
||||
<td style="text-align: left;">2</td>
|
||||
<td style="text-align: left;">3.4</td>
|
||||
<td style="text-align: left;">80.0%</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td style="text-align: left;">A</td>
|
||||
<td style="text-align: left;">lib/coap/coap_server.js</td>
|
||||
<td style="text-align: left;">16</td>
|
||||
<td style="text-align: left;">0</td>
|
||||
<td style="text-align: left;">5</td>
|
||||
<td style="text-align: left;">5.2</td>
|
||||
<td style="text-align: left;">44.0%</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td style="text-align: left;">A</td>
|
||||
<td style="text-align: left;">lib/database/db_factory.js</td>
|
||||
<td style="text-align: left;">8</td>
|
||||
<td style="text-align: left;">0</td>
|
||||
<td style="text-align: left;">3</td>
|
||||
<td style="text-align: left;">3.8</td>
|
||||
<td style="text-align: left;">92.3%</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td style="text-align: left;">A</td>
|
||||
<td style="text-align: left;">lib/database/iot_db.js</td>
|
||||
<td style="text-align: left;">7</td>
|
||||
<td style="text-align: left;">0</td>
|
||||
<td style="text-align: left;">6</td>
|
||||
<td style="text-align: left;">1.0</td>
|
||||
<td style="text-align: left;">58.8%</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td style="text-align: left;">A</td>
|
||||
<td style="text-align: left;">lib/database/mongodb_helper.js</td>
|
||||
<td style="text-align: left;">63</td>
|
||||
<td style="text-align: left;">0</td>
|
||||
<td style="text-align: left;">11</td>
|
||||
<td style="text-align: left;">4.5</td>
|
||||
<td style="text-align: left;">35.0%</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td style="text-align: left;">C</td>
|
||||
<td style="text-align: left;">lib/database/sqlite_helper.js</td>
|
||||
<td style="text-align: left;">32</td>
|
||||
<td style="text-align: left;">86</td>
|
||||
<td style="text-align: left;">10</td>
|
||||
<td style="text-align: left;">4.5</td>
|
||||
<td style="text-align: left;">35.0%</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td style="text-align: left;">B</td>
|
||||
<td style="text-align: left;">lib/rest/rest_helper.js</td>
|
||||
<td style="text-align: left;">19</td>
|
||||
<td style="text-align: left;">62</td>
|
||||
<td style="text-align: left;">3</td>
|
||||
<td style="text-align: left;">4.7</td>
|
||||
<td style="text-align: left;">37.5%</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td style="text-align: left;">A</td>
|
||||
<td style="text-align: left;">lib/rest/rest_server.js</td>
|
||||
<td style="text-align: left;">17</td>
|
||||
<td style="text-align: left;">0</td>
|
||||
<td style="text-align: left;">2</td>
|
||||
<td style="text-align: left;">8.6</td>
|
||||
<td style="text-align: left;">88.9%</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td style="text-align: left;">A</td>
|
||||
<td style="text-align: left;">lib/url_handler.js</td>
|
||||
<td style="text-align: left;">9</td>
|
||||
<td style="text-align: left;">0</td>
|
||||
<td style="text-align: left;">5</td>
|
||||
<td style="text-align: left;">2.2</td>
|
||||
<td style="text-align: left;">94.1%</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>分享得到的最后的结果是:</p>
|
||||
<p>[Coverage][1]</p>
|
||||
<h3 id="代码的坏味道">代码的坏味道</h3>
|
||||
<p>于是我们就打开<code>lib/database/sqlite_helper.js</code>,因为其中有两个坏味道</p>
|
||||
<p>Similar code found in two :expression_statement nodes (mass = 86)</p>
|
||||
<p>在代码的 <code>lib/database/sqlite_helper.js:58…61 < ></code></p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"> <span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">deleteData</span> <span class="op">=</span> <span class="kw">function</span> (url<span class="op">,</span> callback) <span class="op">{</span>
|
||||
<span class="st">'use strict'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> sql_command <span class="op">=</span> <span class="st">"DELETE FROM "</span> <span class="op">+</span> <span class="va">config</span>.<span class="at">table_name</span> <span class="op">+</span> <span class="st">" where "</span> <span class="op">+</span> <span class="va">URLHandler</span>.<span class="at">getKeyFromURL</span>(url) <span class="op">+</span> <span class="st">"="</span> <span class="op">+</span> <span class="va">URLHandler</span>.<span class="at">getValueFromURL</span>(url)<span class="op">;</span>
|
||||
<span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">basic</span>(sql_command<span class="op">,</span> callback)<span class="op">;</span></code></pre></div>
|
||||
<p>lib/database/sqlite_helper.js:64…67 < ></p>
|
||||
<p>与</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">getData</span> <span class="op">=</span> <span class="kw">function</span> (url<span class="op">,</span> callback) <span class="op">{</span>
|
||||
<span class="st">'use strict'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> sql_command <span class="op">=</span> <span class="st">"SELECT * FROM "</span> <span class="op">+</span> <span class="va">config</span>.<span class="at">table_name</span> <span class="op">+</span> <span class="st">" where "</span> <span class="op">+</span> <span class="va">URLHandler</span>.<span class="at">getKeyFromURL</span>(url) <span class="op">+</span> <span class="st">"="</span> <span class="op">+</span> <span class="va">URLHandler</span>.<span class="at">getValueFromURL</span>(url)<span class="op">;</span>
|
||||
<span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">basic</span>(sql_command<span class="op">,</span> callback)<span class="op">;</span></code></pre></div>
|
||||
<p>只是这是之前修改过的重复。。</p>
|
||||
<p>原来的代码是这样的</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">postData</span> <span class="op">=</span> <span class="kw">function</span> (block<span class="op">,</span> callback) <span class="op">{</span>
|
||||
<span class="st">'use strict'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> db <span class="op">=</span> <span class="kw">new</span> <span class="va">sqlite3</span>.<span class="at">Database</span>(<span class="va">config</span>.<span class="at">db_name</span>)<span class="op">;</span>
|
||||
<span class="kw">var</span> str <span class="op">=</span> <span class="kw">this</span>.<span class="at">parseData</span>(<span class="va">config</span>.<span class="at">keys</span>)<span class="op">;</span>
|
||||
<span class="kw">var</span> string <span class="op">=</span> <span class="kw">this</span>.<span class="at">parseData</span>(block)<span class="op">;</span>
|
||||
|
||||
<span class="kw">var</span> sql_command <span class="op">=</span> <span class="st">"insert or replace into "</span> <span class="op">+</span> <span class="va">config</span>.<span class="at">table_name</span> <span class="op">+</span> <span class="st">" ("</span> <span class="op">+</span> str <span class="op">+</span> <span class="st">") VALUES ("</span> <span class="op">+</span> string <span class="op">+</span> <span class="st">");"</span><span class="op">;</span>
|
||||
<span class="va">db</span>.<span class="at">all</span>(sql_command<span class="op">,</span> <span class="kw">function</span> (err) <span class="op">{</span>
|
||||
<span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">errorHandler</span>(err)<span class="op">;</span>
|
||||
<span class="va">db</span>.<span class="at">close</span>()<span class="op">;</span>
|
||||
<span class="at">callback</span>()<span class="op">;</span>
|
||||
<span class="op">}</span>)<span class="op">;</span>
|
||||
<span class="op">};</span>
|
||||
|
||||
<span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">deleteData</span> <span class="op">=</span> <span class="kw">function</span> (url<span class="op">,</span> callback) <span class="op">{</span>
|
||||
<span class="st">'use strict'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> db <span class="op">=</span> <span class="kw">new</span> <span class="va">sqlite3</span>.<span class="at">Database</span>(<span class="va">config</span>.<span class="at">db_name</span>)<span class="op">;</span>
|
||||
<span class="kw">var</span> sql_command <span class="op">=</span> <span class="st">"DELETE FROM "</span> <span class="op">+</span> <span class="va">config</span>.<span class="at">table_name</span> <span class="op">+</span> <span class="st">" where "</span> <span class="op">+</span> <span class="va">URLHandler</span>.<span class="at">getKeyFromURL</span>(url) <span class="op">+</span> <span class="st">"="</span> <span class="op">+</span> <span class="va">URLHandler</span>.<span class="at">getValueFromURL</span>(url)<span class="op">;</span>
|
||||
<span class="va">db</span>.<span class="at">all</span>(sql_command<span class="op">,</span> <span class="kw">function</span> (err) <span class="op">{</span>
|
||||
<span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">errorHandler</span>(err)<span class="op">;</span>
|
||||
<span class="va">db</span>.<span class="at">close</span>()<span class="op">;</span>
|
||||
<span class="at">callback</span>()<span class="op">;</span>
|
||||
<span class="op">}</span>)<span class="op">;</span>
|
||||
<span class="op">};</span>
|
||||
|
||||
<span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">getData</span> <span class="op">=</span> <span class="kw">function</span> (url<span class="op">,</span> callback) <span class="op">{</span>
|
||||
<span class="st">'use strict'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> db <span class="op">=</span> <span class="kw">new</span> <span class="va">sqlite3</span>.<span class="at">Database</span>(<span class="va">config</span>.<span class="at">db_name</span>)<span class="op">;</span>
|
||||
<span class="kw">var</span> sql_command <span class="op">=</span> <span class="st">"SELECT * FROM "</span> <span class="op">+</span> <span class="va">config</span>.<span class="at">table_name</span> <span class="op">+</span> <span class="st">" where "</span> <span class="op">+</span> <span class="va">URLHandler</span>.<span class="at">getKeyFromURL</span>(url) <span class="op">+</span> <span class="st">"="</span> <span class="op">+</span> <span class="va">URLHandler</span>.<span class="at">getValueFromURL</span>(url)<span class="op">;</span>
|
||||
<span class="va">db</span>.<span class="at">all</span>(sql_command<span class="op">,</span> <span class="kw">function</span> (err<span class="op">,</span> rows) <span class="op">{</span>
|
||||
<span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">errorHandler</span>(err)<span class="op">;</span>
|
||||
<span class="va">db</span>.<span class="at">close</span>()<span class="op">;</span>
|
||||
<span class="at">callback</span>(<span class="va">JSON</span>.<span class="at">stringify</span>(rows))<span class="op">;</span>
|
||||
<span class="op">}</span>)<span class="op">;</span>
|
||||
<span class="op">};</span></code></pre></div>
|
||||
<p>说的也是大量的重复,重构完的代码</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">basic</span> <span class="op">=</span> <span class="kw">function</span>(sql<span class="op">,</span> db_callback)<span class="op">{</span>
|
||||
<span class="st">'use strict'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> db <span class="op">=</span> <span class="kw">new</span> <span class="va">sqlite3</span>.<span class="at">Database</span>(<span class="va">config</span>.<span class="at">db_name</span>)<span class="op">;</span>
|
||||
<span class="va">db</span>.<span class="at">all</span>(sql<span class="op">,</span> <span class="kw">function</span> (err<span class="op">,</span> rows) <span class="op">{</span>
|
||||
<span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">errorHandler</span>(err)<span class="op">;</span>
|
||||
<span class="va">db</span>.<span class="at">close</span>()<span class="op">;</span>
|
||||
<span class="at">db_callback</span>(<span class="va">JSON</span>.<span class="at">stringify</span>(rows))<span class="op">;</span>
|
||||
<span class="op">}</span>)<span class="op">;</span>
|
||||
|
||||
<span class="op">};</span>
|
||||
|
||||
<span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">postData</span> <span class="op">=</span> <span class="kw">function</span> (block<span class="op">,</span> callback) <span class="op">{</span>
|
||||
<span class="st">'use strict'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> str <span class="op">=</span> <span class="kw">this</span>.<span class="at">parseData</span>(<span class="va">config</span>.<span class="at">keys</span>)<span class="op">;</span>
|
||||
<span class="kw">var</span> string <span class="op">=</span> <span class="kw">this</span>.<span class="at">parseData</span>(block)<span class="op">;</span>
|
||||
|
||||
<span class="kw">var</span> sql_command <span class="op">=</span> <span class="st">"insert or replace into "</span> <span class="op">+</span> <span class="va">config</span>.<span class="at">table_name</span> <span class="op">+</span> <span class="st">" ("</span> <span class="op">+</span> str <span class="op">+</span> <span class="st">") VALUES ("</span> <span class="op">+</span> string <span class="op">+</span> <span class="st">");"</span><span class="op">;</span>
|
||||
<span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">basic</span>(sql_command<span class="op">,</span> callback)<span class="op">;</span>
|
||||
<span class="op">};</span>
|
||||
|
||||
<span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">deleteData</span> <span class="op">=</span> <span class="kw">function</span> (url<span class="op">,</span> callback) <span class="op">{</span>
|
||||
<span class="st">'use strict'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> sql_command <span class="op">=</span> <span class="st">"DELETE FROM "</span> <span class="op">+</span> <span class="va">config</span>.<span class="at">table_name</span> <span class="op">+</span> <span class="st">" where "</span> <span class="op">+</span> <span class="va">URLHandler</span>.<span class="at">getKeyFromURL</span>(url) <span class="op">+</span> <span class="st">"="</span> <span class="op">+</span> <span class="va">URLHandler</span>.<span class="at">getValueFromURL</span>(url)<span class="op">;</span>
|
||||
<span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">basic</span>(sql_command<span class="op">,</span> callback)<span class="op">;</span>
|
||||
<span class="op">};</span>
|
||||
|
||||
<span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">getData</span> <span class="op">=</span> <span class="kw">function</span> (url<span class="op">,</span> callback) <span class="op">{</span>
|
||||
<span class="st">'use strict'</span><span class="op">;</span>
|
||||
<span class="kw">var</span> sql_command <span class="op">=</span> <span class="st">"SELECT * FROM "</span> <span class="op">+</span> <span class="va">config</span>.<span class="at">table_name</span> <span class="op">+</span> <span class="st">" where "</span> <span class="op">+</span> <span class="va">URLHandler</span>.<span class="at">getKeyFromURL</span>(url) <span class="op">+</span> <span class="st">"="</span> <span class="op">+</span> <span class="va">URLHandler</span>.<span class="at">getValueFromURL</span>(url)<span class="op">;</span>
|
||||
<span class="va">SQLiteHelper</span>.<span class="va">prototype</span>.<span class="at">basic</span>(sql_command<span class="op">,</span> callback)<span class="op">;</span>
|
||||
<span class="op">};</span></code></pre></div>
|
||||
<p>重构完后的代码比原来还长,这似乎是个问题~~</p>
|
||||
<h1 id="创建项目文档">创建项目文档</h1>
|
||||
<h1 id="测试-1">测试</h1>
|
||||
<h1 id="重构-1">重构</h1>
|
||||
<p>或许你应该知道了,重构是怎样的,你也知道重构能带来什么。在我刚开始学重构和设计模式的时候,我需要去找一些好的示例,以便于我更好的学习。有时候不得不创造一些更好的场景,来实现这些功能。</p>
|
||||
<p>有一天,我发现当我需要我一次又一次地重复讲述某些内容,于是我就计划着把这些应该掌握的技能放到Github上,也就有了<a href="https://github.com/artisanstack">Artisan Stack</a> 计划。</p>
|
||||
<p>每个程序员都不可避免地是一个Coder,一个没有掌握好技能的Coder,算不上是手工艺人,但是是手工人。</p>
|
||||
<p>艺,需要有创造性的方法。</p>
|
||||
<h1 id="前端技能训练-重构一"><a href="http://www.phodal.com/blog/frontend-improve-refactor-javascript-code/">前端技能训练: 重构一</a></h1>
|
||||
<h2 id="为什么重构">为什么重构?</h2>
|
||||
<blockquote>
|
||||
<p>为了更好的代码。</p>
|
||||
</blockquote>
|
||||
<p>在经历了一年多的工作之后,我平时的主要工作就是修Bug。刚开始的时候觉得无聊,后来才发现修Bug需要更好的技术。有时候你可能要面对着一坨一坨的代码,有时候你可能要花几天的时间去阅读代码。而,你重写那几十代码可能只会花上你不到一天的时间。但是如果你没办法理解当时为什么这么做,你的修改只会带来更多的bug。修Bug,更多的是维护代码。还是前人总结的那句话对:</p>
|
||||
<blockquote>
|
||||
<p>写代码容易,读代码难。</p>
|
||||
</blockquote>
|
||||
<p>假设我们写这些代码只要半天,而别人读起来要一天。为什么不试着用一天的时候去写这些代码,让别人花半天或者更少的时间来理解。</p>
|
||||
<p>如果你的代码已经上线,虽然是一坨坨的。但是不要轻易尝试,<code>没有测试的重构</code>。</p>
|
||||
<p>从前端开始的原因在于,写得一坨坨且最不容易测试的代码都在前端。</p>
|
||||
<p>让我们来看看我们的第一个训练,相当有挑战性。</p>
|
||||
<h2 id="重构umarkdown">重构uMarkdown</h2>
|
||||
<p>代码及setup请见github: <a href="https://github.com/artisanstack/js-refactor">js-refactor</a></p>
|
||||
<h3 id="代码说明">代码说明</h3>
|
||||
<p><code>uMarkdown</code>是一个用于将Markdown转化为HTML的库。代码看上去就像一个很典型的过程代码:</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="co">/* code */</span>
|
||||
<span class="cf">while</span> ((stra <span class="op">=</span> <span class="va">micromarkdown</span>.<span class="va">regexobject</span>.<span class="va">code</span>.<span class="at">exec</span>(str)) <span class="op">!==</span> <span class="kw">null</span>) <span class="op">{</span>
|
||||
str <span class="op">=</span> <span class="va">str</span>.<span class="at">replace</span>(stra[<span class="dv">0</span>]<span class="op">,</span> <span class="st">'<code></span><span class="sc">\n</span><span class="st">'</span> <span class="op">+</span> <span class="va">micromarkdown</span>.<span class="at">htmlEncode</span>(stra[<span class="dv">1</span>]).<span class="at">replace</span>(<span class="ss">/</span><span class="sc">\n</span><span class="ss">/gm</span><span class="op">,</span> <span class="st">'<br/>'</span>).<span class="at">replace</span>(<span class="ss">/</span><span class="sc">\ </span><span class="ss">/gm</span><span class="op">,</span> <span class="st">'&nbsp;'</span>) <span class="op">+</span> <span class="st">'</code></span><span class="sc">\n</span><span class="st">'</span>)<span class="op">;</span>
|
||||
<span class="op">}</span>
|
||||
|
||||
<span class="co">/* headlines */</span>
|
||||
<span class="cf">while</span> ((stra <span class="op">=</span> <span class="va">micromarkdown</span>.<span class="va">regexobject</span>.<span class="va">headline</span>.<span class="at">exec</span>(str)) <span class="op">!==</span> <span class="kw">null</span>) <span class="op">{</span>
|
||||
count <span class="op">=</span> stra[<span class="dv">1</span>].<span class="at">length</span><span class="op">;</span>
|
||||
str <span class="op">=</span> <span class="va">str</span>.<span class="at">replace</span>(stra[<span class="dv">0</span>]<span class="op">,</span> <span class="st">'<h'</span> <span class="op">+</span> count <span class="op">+</span> <span class="st">'>'</span> <span class="op">+</span> stra[<span class="dv">2</span>] <span class="op">+</span> <span class="st">'</h'</span> <span class="op">+</span> count <span class="op">+</span> <span class="st">'>'</span> <span class="op">+</span> <span class="st">'</span><span class="sc">\n</span><span class="st">'</span>)<span class="op">;</span>
|
||||
<span class="op">}</span>
|
||||
|
||||
<span class="co">/* mail */</span>
|
||||
<span class="cf">while</span> ((stra <span class="op">=</span> <span class="va">micromarkdown</span>.<span class="va">regexobject</span>.<span class="va">mail</span>.<span class="at">exec</span>(str)) <span class="op">!==</span> <span class="kw">null</span>) <span class="op">{</span>
|
||||
str <span class="op">=</span> <span class="va">str</span>.<span class="at">replace</span>(stra[<span class="dv">0</span>]<span class="op">,</span> <span class="st">'<a href="mailto:'</span> <span class="op">+</span> stra[<span class="dv">1</span>] <span class="op">+</span> <span class="st">'">'</span> <span class="op">+</span> stra[<span class="dv">1</span>] <span class="op">+</span> <span class="st">'</a>'</span>)<span class="op">;</span>
|
||||
<span class="op">}</span></code></pre></div>
|
||||
<p>选这个做重构的开始,不仅仅是因为之前在写<a href="https://github.com/phodal/echoesworks">EchoesWorks</a>的时候进行了很多的重构。而且它更适合于,<code>重构到设计模式</code>的理论。让我们在重构完之后,给作者进行pull request吧。</p>
|
||||
<p>Markdown的解析过程,有点类似于<code>Pipe and Filters</code>模式(架构模式)。</p>
|
||||
<p>Filter即我们在代码中看到的正规表达式集:</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript">regexobject<span class="op">:</span> <span class="op">{</span>
|
||||
<span class="dt">headline</span><span class="op">:</span> <span class="ss">/</span><span class="sc">^(\#{1,6})([^\#\n]+)$</span><span class="ss">/m</span><span class="op">,</span>
|
||||
<span class="dt">code</span><span class="op">:</span> <span class="ss">/</span><span class="sc">\s\`\`\`\n?([^`]+)\`\`\`</span><span class="ss">/g</span></code></pre></div>
|
||||
<p>他会匹配对应的Markdown类型,随后进行替换和处理。而``str```,就是管理口的输入和输出。</p>
|
||||
<p>接着,我们就可以对其进行简单的重构。</p>
|
||||
<h3 id="重构-2">重构</h3>
|
||||
<p>(ps: 推荐用WebStrom来做重构,自带重构功能)</p>
|
||||
<p>作为一个示例,我们先提出codeHandler方法,即将上面的</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="co">/* code */</span>
|
||||
<span class="cf">while</span> ((stra <span class="op">=</span> <span class="va">micromarkdown</span>.<span class="va">regexobject</span>.<span class="va">code</span>.<span class="at">exec</span>(str)) <span class="op">!==</span> <span class="kw">null</span>) <span class="op">{</span>
|
||||
str <span class="op">=</span> <span class="va">str</span>.<span class="at">replace</span>(stra[<span class="dv">0</span>]<span class="op">,</span> <span class="st">'<code></span><span class="sc">\n</span><span class="st">'</span> <span class="op">+</span> <span class="va">micromarkdown</span>.<span class="at">htmlEncode</span>(stra[<span class="dv">1</span>]).<span class="at">replace</span>(<span class="ss">/</span><span class="sc">\n</span><span class="ss">/gm</span><span class="op">,</span> <span class="st">'<br/>'</span>).<span class="at">replace</span>(<span class="ss">/</span><span class="sc">\ </span><span class="ss">/gm</span><span class="op">,</span> <span class="st">'&nbsp;'</span>) <span class="op">+</span> <span class="st">'</code></span><span class="sc">\n</span><span class="st">'</span>)<span class="op">;</span>
|
||||
<span class="op">}</span></code></pre></div>
|
||||
<p>提取方法成</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript">codeFilter<span class="op">:</span> <span class="kw">function</span> (str<span class="op">,</span> stra) <span class="op">{</span>
|
||||
<span class="cf">return</span> <span class="va">str</span>.<span class="at">replace</span>(stra[<span class="dv">0</span>]<span class="op">,</span> <span class="st">'<code></span><span class="sc">\n</span><span class="st">'</span> <span class="op">+</span> <span class="va">micromarkdown</span>.<span class="at">htmlEncode</span>(stra[<span class="dv">1</span>]).<span class="at">replace</span>(<span class="ss">/</span><span class="sc">\n</span><span class="ss">/gm</span><span class="op">,</span> <span class="st">'<br/>'</span>).<span class="at">replace</span>(<span class="ss">/</span><span class="sc">\ </span><span class="ss">/gm</span><span class="op">,</span> <span class="st">'&nbsp;'</span>) <span class="op">+</span> <span class="st">'</code></span><span class="sc">\n</span><span class="st">'</span>)<span class="op">;</span>
|
||||
<span class="op">},</span> </code></pre></div>
|
||||
<p>while语句就成了</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="cf">while</span> ((stra <span class="op">=</span> <span class="va">regexobject</span>.<span class="va">code</span>.<span class="at">exec</span>(str)) <span class="op">!==</span> <span class="kw">null</span>) <span class="op">{</span>
|
||||
str <span class="op">=</span> <span class="kw">this</span>.<span class="at">codeFilter</span>(str<span class="op">,</span> stra)<span class="op">;</span>
|
||||
<span class="op">}</span></code></pre></div>
|
||||
<p>然后,运行所有的测试。</p>
|
||||
<pre><code>grunt test</code></pre>
|
||||
<p>同理我们就可以<code>mail</code>、<code>headline</code>等方法进行重构。接着就会变成类似于下面的代码,</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="co">/* code */</span>
|
||||
<span class="cf">while</span> ((execStr <span class="op">=</span> <span class="va">regExpObject</span>.<span class="va">code</span>.<span class="at">exec</span>(str)) <span class="op">!==</span> <span class="kw">null</span>) <span class="op">{</span>
|
||||
str <span class="op">=</span> <span class="at">codeHandler</span>(str<span class="op">,</span> execStr)<span class="op">;</span>
|
||||
<span class="op">}</span>
|
||||
|
||||
<span class="co">/* headlines */</span>
|
||||
<span class="cf">while</span> ((execStr <span class="op">=</span> <span class="va">regExpObject</span>.<span class="va">headline</span>.<span class="at">exec</span>(str)) <span class="op">!==</span> <span class="kw">null</span>) <span class="op">{</span>
|
||||
str <span class="op">=</span> <span class="at">headlineHandler</span>(str<span class="op">,</span> execStr)<span class="op">;</span>
|
||||
<span class="op">}</span>
|
||||
|
||||
<span class="co">/* lists */</span>
|
||||
<span class="cf">while</span> ((execStr <span class="op">=</span> <span class="va">regExpObject</span>.<span class="va">lists</span>.<span class="at">exec</span>(str)) <span class="op">!==</span> <span class="kw">null</span>) <span class="op">{</span>
|
||||
str <span class="op">=</span> <span class="at">listHandler</span>(str<span class="op">,</span> execStr)<span class="op">;</span>
|
||||
<span class="op">}</span>
|
||||
|
||||
<span class="co">/* tables */</span>
|
||||
<span class="cf">while</span> ((execStr <span class="op">=</span> <span class="va">regExpObject</span>.<span class="va">tables</span>.<span class="at">exec</span>(str)) <span class="op">!==</span> <span class="kw">null</span>) <span class="op">{</span>
|
||||
str <span class="op">=</span> <span class="at">tableHandler</span>(str<span class="op">,</span> execStr<span class="op">,</span> strict)<span class="op">;</span>
|
||||
<span class="op">}</span></code></pre></div>
|
||||
<p>然后你也看到了,上面有一堆重复的代码,接着让我们用JavaScript的<code>奇技浮巧</code>,即apply方法,把上面的重复代码变成。</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript">[<span class="st">'code'</span><span class="op">,</span> <span class="st">'headline'</span><span class="op">,</span> <span class="st">'lists'</span><span class="op">,</span> <span class="st">'tables'</span><span class="op">,</span> <span class="st">'links'</span><span class="op">,</span> <span class="st">'mail'</span><span class="op">,</span> <span class="st">'url'</span><span class="op">,</span> <span class="st">'smlinks'</span><span class="op">,</span> <span class="st">'hr'</span>].<span class="at">forEach</span>(<span class="kw">function</span> (type) <span class="op">{</span>
|
||||
<span class="cf">while</span> ((stra <span class="op">=</span> regexobject[type].<span class="at">exec</span>(str)) <span class="op">!==</span> <span class="kw">null</span>) <span class="op">{</span>
|
||||
str <span class="op">=</span> that[(type <span class="op">+</span> <span class="st">'Handler'</span>)].<span class="at">apply</span>(that<span class="op">,</span> [stra<span class="op">,</span> str<span class="op">,</span> strict])<span class="op">;</span>
|
||||
<span class="op">}</span>
|
||||
<span class="op">}</span>)<span class="op">;</span></code></pre></div>
|
||||
<p>进行测试,blabla,都是过的。</p>
|
||||
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"> Markdown
|
||||
✓ should parse h1<span class="op">~</span>h3
|
||||
✓ should parse link
|
||||
✓ should special link
|
||||
✓ should parse font style
|
||||
✓ should parse code
|
||||
✓ should parse ul list
|
||||
✓ should parse ul table
|
||||
✓ should <span class="cf">return</span> correctly <span class="kw">class</span> name</code></pre></div>
|
||||
<p>快来试试吧, <a href="https://github.com/artisanstack/js-refactor" class="uri">https://github.com/artisanstack/js-refactor</a></p>
|
||||
<h1 id="github连击">Github连击</h1>
|
||||
<h2 id="天">100天</h2>
|
||||
<p>我也是蛮拼的,虽然我想的只是在Github上连击100~200天,然而到了今天也算不错。</p>
|
||||
|
|
@ -1308,7 +1819,7 @@ pipe.execute()</code></pre></div>
|
|||
<h3 id="编程的基础能力">编程的基础能力</h3>
|
||||
<p>虽说算法很重要,但是编码才是基础能力。算法与编程在某种程度上是不同的领域,算法编程是在编程上面的一级。算法写得再好,如果别人很难直接拿来复用,在别人眼里就是shit。想出能work的代码一件简单的事,学会对其重构,使之变得更易读就是一件有意义的事。</p>
|
||||
<p>于是,在某一时刻在Github上创建了一个组织,叫<a href="https://github.com/artisanstack">Artisan Stack</a>。当时想的是在Github寻找一些JavaScript项目,对其代码进行重构。但是到底是影响力不够哈,参与的人数比较少。</p>
|
||||
<h4 id="重构-2">重构</h4>
|
||||
<h4 id="重构-3">重构</h4>
|
||||
<p>如果你懂得如何写出高可读的代码,那么我想你是不需要这个的,但是这意味着你花了更多的时候在思考上了。当谈论重构的时候,让我想起了TDD(测试驱动开发)。即使不是TDD,那么如果你写着测试,那也是可以重构的。(之前写过一些利用Intellij IDEA重构的文章:<a href="https://www.phodal.com/blog/intellij-idea-refactor-extract-method/">提炼函数</a>、<a href="https://www.phodal.com/blog/intellij-idea-refactor-replace-temp-with-query/">以查询取代临时变量</a>、<a href="https://www.phodal.com/blog/thoughtworks-refactor-and-intellij-idea/">重构与Intellij Idea初探</a>、<a href="https://www.phodal.com/blog/intellij-idea-refactor-inline-method/">内联函数</a>)</p>
|
||||
<p>在各种各样的文章里,我们看到过一些相关的内容,最好的参考莫过于《重构》一书。最基础不过的原则便是函数名,取名字很难,取别人能读懂的名字更难。其他的便有诸如长函数、过大的类、重复代码等等。在我有限的面试别人的经历里,这些问题都是最常见的。</p>
|
||||
<h4 id="测试-2">测试</h4>
|
||||
|
|
|
|||
Loading…
Reference in a new issue