自动化测试成本和收益
与软件开发中的大多数事情一样,进行评论的最终货币是时间。 我们必须投资多少?它们为我们节省了多少? 换句话说:
评论的成本和收益是什么?
费用
初始组成
显然,要使注释在将来对您有所帮助,必须在某个时候编写该注释。 同样清楚的是,评论写得越早,撰写的速度就越快,并且包含的信息也就越多,因为它们在作者的脑海中是新鲜的。
成本与代码的复杂性和注释的质量相关。
编写有意义的注释的复杂度(以及因此的成本)与注释代码中隐藏的复杂度和所得文本的质量相关。 如果发生了非常简单的事情(例如获取或设置字段),则注释将易于编写(可能不太有用,但我们将在下面进一步讨论)。 对于更复杂的代码,将涉及更多注释。 但是,如果代码提供了设计良好的抽象,则相关性将受到限制。
有趣的是,编写文档可以刺激重新设计:简化复杂的API比尝试完全记录更容易。
— Mike Bostock(@mbostock) 2015年12月28日
根据我的经验,与其他注释成本以及设计和编写注释代码及其测试的其他成本相比,最初撰写注释所需的时间几乎可以忽略不计。 在花了一些时间设计,测试,实现和重构一段代码后,通常只需要一分钟左右的时间就可以添加一个全面的注释。
保养
当代码更改时,注释将产生以下三种成本之一:
- 更新它们将花费一些时间
- 使其保持不变(并因此而出现故障)将在将来的某个时候引起混乱
- 删除它们会招致丢失有用评论的机会成本(也就是说,如果它们首先是有用的)
通常,更新单个评论所需的时间比初始撰写所需的时间更少。 除非评论的频率很高(逐行考虑),否则实际成本就是寻找所有相关点进行更新所需的工作。 如果不支持注释的局部性,这可能会成为一项耗时,容易出错且令人讨厌的任务。 当然,每次代码更改都会产生此成本,因此维护注释会扩大稳定代码与不稳定代码之间的成本差距。
任何注释模式都必须解决维护问题!
如果没有适当的维护,代码和注释会Swift分开,从而大大降低了任何类型文档的收益。 因此,任何注释架构都必须解决维护问题,因为这就是一切的关键!
但是,并非所有类型的评论都需要相同的努力。 旁白和合同评论必须是最新的。 如果您无法维护它们(不管它们的频率和初始质量如何),最好删除它们并完成它。 提供技术背景的注释所需的勤奋工作和历史注释更少,因为它通常是“保留或删除”。
混乱
如果不保留评论,则将来可能会引起混乱。 但是,如果它们的质量较差,例如由于模棱两可或缺少细节,也会发生同样的情况。
混乱将招致无法预料但潜在的巨大成本。
当基于错误的假设开发代码时,混乱将招致无法预料的代价,但可能带来巨大的成本。 通过灌输疑问,它也减少了其他评论的好处,通常被认为是失败的。
混乱的可能性最大是由于错误的合同,因为通常会读取合同而不是代码。 如果旁白和代码不一致,则可能需要一些时间才能弄清这一点,但在那种情况下,代码总是正确的。 因此,从一开始就简单地忽略叙述是很常见的。 如果上下文注释本身是可以识别的,则它们引起混淆的可能性是有限的。
问题的严重程度还取决于评论的质量,尤其是局部性以及保持评论的严格性。 尽职调查将使成本最小化,但是如果可以完全避免,我会感到惊讶。
有趣的是,良好的开发技术(尤其是测试)将减少混淆的成本,因为它们有助于快速识别要求保护的行为与实际行为之间的矛盾。
梗阻
注释需要屏幕空间,因此无法显示代码。 现代IDE通过允许最初折叠块注释来最小化此问题。 通常,可以改为在按需弹出窗口中查看API文档,也可以始终显示第二屏视图。
好处
注释具有各种好处,但通常会带来收益递减 :谨慎地放置一些注释会很有帮助,但是详细讨论每个可能的角度,无论相关的成本如何,都不会带来线性的帮助。
解释发生了什么
特别是旁白和在一定程度上的合同注释说明了代码的作用。 当然,这在本质上是多余的,因为代码包含相同的信息,即使编写得不好也会使可读性差。
当然,依靠注释而不是代码本身是有风险的(请参阅上面的混淆 ),并且干净的编码技术会通过使代码具有足够的表达力而努力使其不必要。 如果使用了非常不寻常的语言功能或对代码进行了高度优化,这可能很难做到,在这种情况下,旁白仍然可以增加价值。
保持抽象完整
每个代码单元(从方法/函数到类,包,模块,库等)都应提供抽象。 它应该做一件事并且做好。 而且它应该使客户对其执行的精确性一无所知。 理想情况下,它不需要超越抽象。 这是将解决方案模块化以解决任何非平凡问题的核心。
抽象是模块化解决方案的核心。
抽象的价值是双重的:它防止开发人员复制功能并要求开发人员完全理解抽象的问题。
利用现有代码
由于缺乏知识传播,第一利益可能会完全丧失。 一个单元可能无法发现或未被识别为解决了手头的问题,这将导致重新实现功能。
良好的知识分配和协作工作流程(如结对编程)将在很大程度上防止这种情况的产生,但是评论也可以发挥重要作用。 记录大型代码单元(例如,程序包)的中央抽象及其提供的服务,可以更轻松地本地化现有功能。
利用现有的理解
理解抽象所需的任何工作都会逐渐降低其价值。 每次开发人员必须努力了解该单元的使用方式时,都会发生这种情况。 当然,不能完全防止此过程,但是良好的合同注释是减少所需时间的有效机制,从而大大提高了抽象的好处。
合同注释允许开发人员停留在遇到单元的上下文中。 除了表达性命名,其他任何机制都没有该功能! 在阅读单元的代码或测试时,开发人员必须建立一个全新的上下文,以了解子系统的内部而不是子系统的内部。 如果单位使用其他同样未注释的单位,则可能很快退化为俄罗斯套娃。 在一个始终专注于上下文和流程的行业中,这是一个很大的缺点。
换句话说:当干净的代码和出色的测试大放异彩时,开发人员已经介入了抽象,从而失去了一些好处。
自上而下与自下而上
上面的观点着重于理解单个单元,但是在构建更大的(子)系统的心理模型时也是如此。 在我看来,大多数人比从下至上更擅长于自上而下的理解。
合同和上下文注释是有价值的路标。
根据顶部的高度,其他类型的文档可能必须带头,例如体系结构图。 但是,从上到下的合同和上下文注释可能是有价值的路标,使开发人员处于预期的抽象级别。
像以前一样:干净的代码和测试很棒,但是根据我的经验,期望它们能够始终如一地指导开发人员通过对系统的理解,这是绝对乐观的,因为它们正在强制采用自下而上的方法。
记录意图
当必须理解,评估或更改非平凡的代码时, 技术和历史背景是无价的。
上下文可以由外部文档,问题跟踪器,代码检查工具或版本控制提供,但每个仅包含部分信息。 合并它们可能容易出错,并且可能需要花费大量精力,因为一些Wiki文章,故障单描述,注释线程,代码审阅或提交可能与某个代码单元有关。 不幸的是,结果是短暂的,另一个开发人员将不得不重做所有工作以了解同一单元。
注释的主要优点是可以在源代码中轻松获得它们。 尽管它们甚至无法完全涵盖上述所有信息,但它们可能是理解之旅的第二步(当然是在代码本身之后)。 上下文注释将减少侦探工作量,因此每次开发人员尝试理解该代码单元时都会受益。
结论
叙述很烂!
让我们从一个结论开始,该结论确认我们已经知道的内容: 叙述很烂!
它们易于编写,但维护成本高昂,出现混乱的风险很高,并且存在阻塞的现实,因为它逐行增加了很多噪音。 唯一的好处是向开发人员解释了代码的作用,而这正是干净的代码至少在绝大多数情况下也是如此。 因此,它们成本高昂,几乎没有收益。
预期的重用量越大,则向合同转移的规模就越大。
评判合同的评论更加细微。 如果措辞正确并用于干净的抽象,它们可以通过阻止开发人员为他们正在研究的代码(干净的代码通常需要)创建新的思维环境而获得实质性的好处。 但是,如果频繁更改代码,则维护成本和混乱的可能性会很重。
因此,代码的使用和稳定性应该成为编写多少合同以及详细程度的指导原则。 预期的受众越多,越倾向于使用文档:该代码将被频繁使用,并且有很强的动力来保持其稳定性。 此外,好的文档可以提高发现能力和采用率。
但是,即使没有重用潜力的代码也将被更改,并且合同可以帮助促进所需的理解。 在这种情况下,对抽象的高级描述(例如解释类或包的中心抽象的段落)会走很长一段路。 在更改期间它仍然需要勤奋,但所需的工作量很小。
上下文注释无疑是赢家。
上下文注释,无论是技术性的还是历史性的 ,显然是赢家。 如果以强调其短暂性的方式措辞或格式化它们,它们几乎没有成本(维护或混乱),但可以在寻找错误和重构期间用作有价值的面包屑 。
反射
评论必须组成和维护,如果后者不能正确执行,将会引起混乱。 它们可能被认为是嘈杂的,IDE功能可以大大减少它们。 从好的方面来说,他们可以通过讲述发生的事情,保持抽象完整并启用自上而下的方法来研究代码,来帮助开发人员理解代码(duh!)。 它们对于记录意图非常宝贵。
比较不同类型的评论,我们发现旁白的表现很差,这并不奇怪,这是因为几乎没有任何好处,但需要很高的维护。 应认真考虑合同,但应根据预期的重用程度选择详细程度。 最后但并非最不重要的一点是,故意的上下文注释是保持者。
翻译自: https://www.javacodegeeks.com/2016/02/costs-benefits-comments.html
自动化测试成本和收益