当很多前辈教育后辈应当多写注释的时候,当网络上充满了有关程序员从不写注释的段子的时候,这是一个非常有争议的话题。作为一个标题党,容我先修正一下我的观点:我认为如果代码写得足够好,那么大多数注释是多余的,我们应该通过写出更好的代码来代替更多注释。
注释的确有其用途,但大部分情况下,程序员在滥用注释。我是反对夹杂在代码间的注释的,我认为注释应当从代码中独立出来——通常被称为文档。
请看下面一段代码。
/* /static/market/checkout.js2014.7.2 create by orzfly 2014.7.29 update by jysperm: fixbugs
TODO: 这段代码中注释太多了,需要移除一些 -- jysperm */
var raw_products = req.query['products'].split(',');
// 商品 ID 的数组 var products = []
// 过滤每个参数 for(var i = 0, i < raw_products.length, i++) { if (!raw_products[i]) return;
// 前端传来的数据中居然会有空格 if (!raw_products[i].trim()) return
/* 2014.7.22: 现在可以使用非数字 ID 了 // 略过非数字条目 if (isNan(raw_products[i].trim().toFixed())) return; */
products.push(raw_products[i].trim().toFixed()); }
// 总钱数 var sum = 0;
// 计算每个商品的总钱数 for(var i = 0, i < products.length, i++) { // 从数据库中查商品信息 var data = db.product.byID(products[i]);
// TODO: 谁来写一下没查到商品的情况
// 把商品的价格加到总钱数上, a += b 是 a = a + b 的缩写 sum += data.price; }
你居然花了一半的时间在读注释上面,这是多么浪费生命的事情,在代码中每加一行注释,都会增加代码的阅读成本——即使阅读者已经了解了注释所要传达的精神;同时也会增加维护成本:修改这段代码的人不得不连同注释一起修改——而且你不能确定他到底会不会这么做。
所以只有当非常必要的情况下,才应该添加注释,而且应当言简意赅。注释不应当解释一段代码在做什么,因为这是每个合格的程序员都应该知道的事情,而是应该解释这段代码为什么要这样做。
由此引出几种明显不应该添加的注释:
本应由版本控制系统记录的信息、对代码的评论,以及不是很重要的 TODO.
代码并不是全部,一个但凡靠谱一点的项目,都应当有自己的版本控制系统,除了记录代码差异之外,还应该有工单和 Issue 的功能。
阅读代码的人通常不需要了解几个程序员之间的恩怨,很多时候也不关心这段代码的历史,这些信息只会把代码拖得越来越长。
废弃的代码
被弃用的代码应该被删掉,这些代码会非常影响阅读,而且它们一般又很长。
在绝大多数情况下,被弃用的代码不会重新派上用场,即使出现了少数情况,你也可以从版本控制系统中找到它们。
对变量和函数名的解释
这种情况下显然你需要一个更恰当的名字,如果这个标识符有一个比较小的作用于,你可以使用一个比较长的名字以便容纳更多信息。
例如上文中的:
products 应改为 products_id
sum 应改为 total_amount
data 应改为 product_record
对语法的解释,以及显而易见的事情
例如上文中的「把商品的价格加到总钱数上, a += b 是 a = a + b 的缩写」,这显然是任何一个人都知道的事情。
也许有人愿意通过写这样的注释来梳理思路:
// 过滤参数: // 去掉 ID 里的空格 // 去掉非数字 ID // 循环每一个商品: // 去数据库查记录 // 把商品的价格加到总钱数上
但是当代码写完的时候记得删掉。
对逻辑块的概括
例如上文中的「过滤每个参数」和「计算每个商品的总钱数」,这情况下通常是你没有对逻辑进行抽象,具体表现就是像下面这样:
// 首先有 25 行代码去做事情 A // 然后有 5 行代码去做事情 B // 这里有 90 行代码去做事情 C // 最后有 45 行代码去做事情 D
这导致你需要一些注释来分割这四个部分。如果这四个部分都是一个函数调用的话,那么函数名本身就是对逻辑的一种解释,读者可以快速地找到函数 B, 而不必在前 25 行中搜索做事情 B 的五行代码。
综上,我对这段代码的改善意见如下:
var filterProductID = function(raw_products_id) { result = []raw_products_id.forEach(function(product_id) { if (product_id and product_id.trim()) products_id.push(product_id.trim().toFixed()); });
return result; };
var getPriceOfProduct = function(id) { var product_record = db.product.byID(products[i]);
if (product_record) return product_record.price; else return 0; };
var products_id = filterProductID(req.query['products'].split(',')); var tatol_amount = 0;
products_id.forEach(function(product_id) { tatol_amount += getPriceOfProduct(product_id); });
虽然我在以一段虚构的,刻意编造的代码来佐证我的观点,但我相信在实际的项目中,同样可以通过改善代码来减少注释,而且总体上来讲会节约更多的时间和精力。
我正在我的. Net Web应用程序上运行负载测试,使用Jeter。应用程序过程:启动-登录-开始测试-回答问题 直到500个用户或有时750个用户,测试才成功运行。但是当我增加负载时,我得到一个错误: 11.111.111.111是我的服务器IP地址。 我已经将jmeter.batch文件堆内存增加到HEAP=-Xms1g-Xmx4g-XX: MaxMetaspaceSize=256m Apac
我正在jMeter中执行负载测试,其中有两个线程组,每个线程组都有50个用户,上升周期为60秒。使用Blazemeter,我记录了一个填写和提交表格的会话,然后稍微修改了一下。其中一组是使用POST方法登录,然后提交表单,另一组是匿名用户填写的。当我运行测试时,我遇到了错误: 响应代码:非HTTP响应代码:org.apache.HTTP。ConnectionClosedException响应消息:
记录的Blazemeter脚本在JMeter中不工作,出现以下错误消息。 响应代码:非HTTP响应代码:java.net。SocketException响应消息:非HTTP响应消息:软件导致连接中止:recv失败
我有一个node app,它正在本地运行,没有任何问题,但当我尝试用heroku部署它时,我做不到。我得到的错误是: null procfile: package.json: 请让我知道,如果你有任何建议,因为我正在努力解决这几个小时。
问题内容: 我想构建一个聊天系统,并在进入窗口和收到新消息时自动滚动到底部。如何在React中自动滚动到容器的底部? 问题答案: 正如Tushar所提到的,您可以在聊天的底部保留一个虚拟div: 然后在组件更新时滚动到它(即,随着添加新消息而更新状态): 我在这里使用标准的Element.scrollIntoView方法。