Hi,SwiftGG 翻译组启用了新的域名:swiftgg.team今后翻译组的各项活动将会在新域名下开展,不要错过哦!

作者:Soroush Khanlou,原文链接,原文日期:2017-03-22
译者:TonyHan;校对:liberalismFirecrest;定稿:CMB

写代码的过程中,复杂性是最大的敌人。对于大型的软件项目来说,维护多层抽象并且让在代码库中工作的开发者正确的理解这些概念是很重要的。

注释可以对管理代码复杂性起到一定作用,但也会对代码产生不良影响。

我对注释的看法来自于两个事实:1)注释并不复杂。2)注释通常在语法高亮中使用柔和的色彩。因为它们不参与编译,并且因为它们并不醒目,所以在更改代码时,很容易忽略它们。如果更改了代码但不更新注释,便得到了一份无法准确描述代码功能的注释。

理想的情况下,可以在代码审查中对注释及时修正,但是实际开发中很难做到这一点。代码审查工具也会有语法高亮显示,这同样会让注释显得不醒目。另外,由于代码审查只会显示被改动的几行代码,只有当注释在改动的附近时,这些已经不适用的注释才会被观察到。如果在一个方法中不起眼的位置修改了一行代码,使得方法的前提条件发生了变化,审查代码的人则很难注意到,也不会告知你去更新注释。

这里有一些避免最常见注释误区的技巧,其中一些在我的老领导的博客中提到过,其他的安德鲁没有想到是因为他是 Ruby(一门动态类型的语言) 程序员。

  1. 良好的命名习惯!优秀注释的第一步就是避免使用单字母、抽象或模糊的名字。名字越精确,所需的注释就越少。

  2. 如果方法有前提条件,并且添加了一个断言,来使得传入非法参数的情况崩溃(至少在调试的时候!)。如果只接受正整数,则写一些类似这样的代码:precondition(int > 0)

  3. 编译时的断言比运行时的断言更好。如果方法仅接受非空数组,则可以提前使用判断:precondition(!array.isEmpty)。但是也可以使用一种永远不能表达为空数组的类型。调用你 API 时永远不可能传入空的组数作为参数。
    同样,如果是 bool 类型的参数,能不能通过命名两个枚举选项来更好的表达?你的选项是否以枚举的方式更好的表达出来?使用命名来表达意图。

  4. 标记出黑科技、临时代码和原型代码。我经常使用类似于 hack_ 的前缀代码来标记出此功能实现地并不完美。在 Swift 的方法命名中使用下划线显得不伦不类,我能感觉到我代码变得更糟,于是我会想要修复它。我们最近写了一个前缀为 shouldReallyBeInTheCoordinator_ 的函数,这是因为需要代码审查,但是代码并不在正确的类中。当糟糕的代码变成丑陋的代码,代码库的需求和你自己的感觉会统一起来。其他的好前缀比如:perf_temp_

  5. 你可以在方法名中添加 ID 来进行 bug 的追踪,这样它们就会在堆栈中出现。UIKit 框架在少数情况下也使用了数字。比如以下:

-[UIViewController _hackFor11408026_beginAppearanceTransition:animated:]
  1. 不要担心在方法名里描述为何如此命名。你可以将方法命名为 updateFrameOnNextTickBecauseAutoLayoutHasntCompletedYet(frame: CGRect)。编译器并不关心方法命名的长短,代码读的次数比写的次数多得多。注释只是文字,方法名也是。将来维护代码的人肯定会赞同你详细的命名。

  2. 设置一个辅助函数,例如 TODO(date: Date, message: String) ,如果 TODO 将来一直没有被修改,则会打印错误日志(甚至更进一步,在调试中崩溃)。可以参考 Jordan Rose 的另一个例子

  3. 将所有的算法需求编码到测试中。如果以上几条都无法使用,并且无法依赖前提条件、类型或方法名来解决某个问题,那就写一个测试用例。这对边界情况特别适用。如果有人重写这部分代码,测试将会失败,他便会知道需要在新代码也要处理此种情况。

切记:这并不是写复杂代码并且不加注释的借口。如果要跳过注释,那么代码必须清晰。对我而言,注释是最后的手段。如果我能找到任何其他的方式来将我的意图传达给下一个程序员,我都不会添加注释。

进一步阅读

本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 http://swift.gg

文章目录
  1. 1. 进一步阅读