代码质量与重构

  • 当你写了一大堆代码,你没有意识到里面有一大堆重复。
  • 当你写了一大堆测试,却不知道覆盖率有多少。

这就是个问题了,于是偶然间看到了一个叫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
A lib/coap/coap_request_handler.js 24 0 6 2.6 46.4%
A lib/coap/coap_result_helper.js 14 0 2 3.4 80.0%
A lib/coap/coap_server.js 16 0 5 5.2 44.0%
A lib/database/db_factory.js 8 0 3 3.8 92.3%
A lib/database/iot_db.js 7 0 6 1.0 58.8%
A lib/database/mongodb_helper.js 63 0 11 4.5 35.0%
C lib/database/sqlite_helper.js 32 86 10 4.5 35.0%
B lib/rest/rest_helper.js 19 62 3 4.7 37.5%
A lib/rest/rest_server.js 17 0 2 8.6 88.9%
A lib/url_handler.js 9 0 5 2.2 94.1%

分享得到的最后的结果是:

[Coverage][1]

代码的坏味道

于是我们就打开lib/database/sqlite_helper.js,因为其中有两个坏味道

Similar code found in two :expression_statement nodes (mass = 86)

在代码的 lib/database/sqlite_helper.js:58…61 < >

  1. SQLiteHelper.prototype.deleteData = function (url, callback) {
  2. 'use strict';
  3. var sql_command = "DELETE FROM " + config.table_name + " where " + URLHandler.getKeyFromURL(url) + "=" + URLHandler.getValueFromURL(url);
  4. SQLiteHelper.prototype.basic(sql_command, callback);

lib/database/sqlite_helper.js:64…67 < >

  1. SQLiteHelper.prototype.getData = function (url, callback) {
  2. 'use strict';
  3. var sql_command = "SELECT * FROM " + config.table_name + " where " + URLHandler.getKeyFromURL(url) + "=" + URLHandler.getValueFromURL(url);
  4. SQLiteHelper.prototype.basic(sql_command, callback);

只是这是之前修改过的重复。。

原来的代码是这样的

  1. SQLiteHelper.prototype.postData = function (block, callback) {
  2. 'use strict';
  3. var db = new sqlite3.Database(config.db_name);
  4. var str = this.parseData(config.keys);
  5. var string = this.parseData(block);
  6. var sql_command = "insert or replace into " + config.table_name + " (" + str + ") VALUES (" + string + ");";
  7. db.all(sql_command, function (err) {
  8. SQLiteHelper.prototype.errorHandler(err);
  9. db.close();
  10. callback();
  11. });
  12. };
  13. SQLiteHelper.prototype.deleteData = function (url, callback) {
  14. 'use strict';
  15. var db = new sqlite3.Database(config.db_name);
  16. var sql_command = "DELETE FROM " + config.table_name + " where " + URLHandler.getKeyFromURL(url) + "=" + URLHandler.getValueFromURL(url);
  17. db.all(sql_command, function (err) {
  18. SQLiteHelper.prototype.errorHandler(err);
  19. db.close();
  20. callback();
  21. });
  22. };
  23. SQLiteHelper.prototype.getData = function (url, callback) {
  24. 'use strict';
  25. var db = new sqlite3.Database(config.db_name);
  26. var sql_command = "SELECT * FROM " + config.table_name + " where " + URLHandler.getKeyFromURL(url) + "=" + URLHandler.getValueFromURL(url);
  27. db.all(sql_command, function (err, rows) {
  28. SQLiteHelper.prototype.errorHandler(err);
  29. db.close();
  30. callback(JSON.stringify(rows));
  31. });
  32. };

说的也是大量的重复,重构完的代码

  1. SQLiteHelper.prototype.basic = function(sql, db_callback){
  2. 'use strict';
  3. var db = new sqlite3.Database(config.db_name);
  4. db.all(sql, function (err, rows) {
  5. SQLiteHelper.prototype.errorHandler(err);
  6. db.close();
  7. db_callback(JSON.stringify(rows));
  8. });
  9. };
  10. SQLiteHelper.prototype.postData = function (block, callback) {
  11. 'use strict';
  12. var str = this.parseData(config.keys);
  13. var string = this.parseData(block);
  14. var sql_command = "insert or replace into " + config.table_name + " (" + str + ") VALUES (" + string + ");";
  15. SQLiteHelper.prototype.basic(sql_command, callback);
  16. };
  17. SQLiteHelper.prototype.deleteData = function (url, callback) {
  18. 'use strict';
  19. var sql_command = "DELETE FROM " + config.table_name + " where " + URLHandler.getKeyFromURL(url) + "=" + URLHandler.getValueFromURL(url);
  20. SQLiteHelper.prototype.basic(sql_command, callback);
  21. };
  22. SQLiteHelper.prototype.getData = function (url, callback) {
  23. 'use strict';
  24. var sql_command = "SELECT * FROM " + config.table_name + " where " + URLHandler.getKeyFromURL(url) + "=" + URLHandler.getValueFromURL(url);
  25. SQLiteHelper.prototype.basic(sql_command, callback);
  26. };

重构完后的代码比原来还长,这似乎是个问题~~