我是干净代码和代码技巧的忠实拥护者,尽管我目前从事的工作不被视为重中之重。我有时会发现自己的处境是,同位人的代码充满混乱的设计,并且很少担心将来的维护,尽管它功能正常且几乎没有bug。
当您认为需要进行大量更改并且有最后期限时,您将如何在代码审查中提出改进建议?请记住,建议在截止日期之后进行改进可能意味着,随着新功能和错误修复的到来,它们将被完全取消优先级。
我是干净代码和代码技巧的忠实拥护者,尽管我目前从事的工作不被视为重中之重。我有时会发现自己的处境是,同位人的代码充满混乱的设计,并且很少担心将来的维护,尽管它功能正常且几乎没有bug。
当您认为需要进行大量更改并且有最后期限时,您将如何在代码审查中提出改进建议?请记住,建议在截止日期之后进行改进可能意味着,随着新功能和错误修复的到来,它们将被完全取消优先级。
Answers:
仔细检查你的动机。如果您认为代码应该改变,你应该能够清晰地说出一些理由,为什么你认为它应该改变。这个原因应该比“我本来会做得不同”或“丑陋”更具体。如果您不能指出拟议的更改会带来一些好处,那么花时间(也就是金钱)来进行更改就没有多大意义。
项目中的每一行代码都是必须维护的一行。代码应该只要能够完成工作并易于理解就可以,并且不再需要。如果您可以在不牺牲清晰度的情况下缩短代码,那很好。如果可以在提高清晰度的同时做到这一点,那就更好了。
代码就像具体的一样:坐了一段时间后,更改起来更加困难。如果可以,请尽早建议您进行更改,以使更改的成本和风险都最小化。
每次更改都会花费金钱。重写有效且不太可能需要更改的代码可能会浪费很多精力。将注意力集中在更容易更改或对项目最重要的部分上。
形式遵循功能,有时反之亦然。如果代码混乱,则很有可能还包含错误。寻找这些错误,并批评有缺陷的功能,而不是代码的美观。建议改进,使代码更好地工作和使代码的操作更容易验证。
区分设计和实施。具有a脚界面的重要班级可以通过像癌症这样的项目传播。这不仅会降低项目其余部分的质量,而且会增加修复损坏的难度。另一方面,具有精心设计的接口但糟糕的实现的类应该没什么大不了的。您始终可以重新实现该类,以获得更好的性能或可靠性。或者,如果它可以正常工作并且足够快,则可以放心使用它,因为它的碎片被很好地封装了。
总结以上几点:确保建议的更改会增加价值。
有一个通过重构增加价值的最佳选择。更改需要完成三件事:
注意事项:
代码审查有3个目的:
检查错误
检查以查看代码可以改进的地方
编写代码的人的教学工具。
评估设计/代码质量当然与#2和#3有关。
远至#2:
非常清楚地说明提议的变更与修复成本之间的关系。作为任何业务决策,这应该与成本/收益分析有关。
例如,“ X的设计方法将显着减少进行更改Z时发生错误Y的可能性,而且我们知道这段代码每2周经历一次类型Z的更改。处理由于错误Y +查找错误而导致的生产中断的成本+修复并发布修复+通过不交付下一组功能而带来的机会成本为$A
;而现在清理代码的成本和机会成本(例如,后期交付或功能较少的价格)为$B
。现在,评估-或更确切地说有你的团队领导者/管理者-评估$A
VS $B
而定。
这将帮助聪明的团队领导者有效地进行管理。例如,他们将使用全部信息做出合理的决定
这将(特别是如果您说得好)会提高您的地位-例如,您是一个足够聪明的人,可以看到更好的设计的好处,并且足够聪明,不会在没有权衡商业考虑的情况下虔诚地要求它。
并且,在可能发生错误Z的情况下,您可以在下一组建议中获得更多的利用。
远至#3:
选择战斗,如果快要截止期限了,那就什么也不做。下次其他人正在审阅或维护代码时,他们仍然遇到麻烦,然后与他们联系,以为是一个团队,您在审阅代码时应更加专注于代码质量,这样以后就不会遇到太多麻烦了。
他们应该在进行额外工作之前先了解其价值。
我总是以“我愿意”开始我的评论,这表明我的观点只是众多观点之一。
我也总是包含一个原因。
“ 我会提取这种成块的方法,因为可读性。”
我对一切都发表评论;大和小。有时候,我对一项更改发表了一百多条评论,在这种情况下,我还建议结对编程,并以自己为荣。
我出于某种原因试图建立一种通用语言。可读性,DRY,SRP等
我还创建了一个有关“干净代码和重构”的演示文稿,向我的同事解释了原因并展示了如何进行。到目前为止,我已经举行了三次,我们正在使用的一家咨询公司要求我再次为他们举行。
但是有些人还是不会听。然后我就离开了排名。我是设计负责人。代码质量是我的责任。在当前状态下,此更改不会在我的手表上显示。
请注意,我非常乐意拒绝我的任何评论;由于技术原因,截止日期,原型等原因,我还有很多要学习编码的知识,并且会一直听取推理。
哦,最近我提出要向团队中第一个吃午餐的人提出午餐,后者提出了一个不重要的变更,对此我没有任何评论。(嘿,你也必须玩得开心。:-)
我有时会发现自己的处境是,同位人的代码充满混乱的设计,并且很少担心将来的维护,尽管它可以正常工作并且几乎没有bug。
此代码已完成。在某个时候,重新设计的成本太高,无法证明其合理性。如果代码已经可以正常运行且几乎没有错误,那么这将是不可能的。建议一些方法以在将来进行清理并继续。如果/将来代码中断,请重新评估重新设计的价值。它可能永远不会中断,这将是很棒的。无论哪种方式,您都在赌博不中断的合理意义上,因为现在或以后的成本都是一样的:冗长,糟糕的重新设计。
将来您需要做的是更紧密的开发迭代。如果您能够在所有消除臭虫的工作都投入之前查看此代码,则建议重新设计是很有意义的。最后,除非以根本上无法维护的方式编写代码,并且可以肯定地知道在发布后不久就需要更改代码,否则进行大型重构绝对没有任何意义。
给定两个选项(重构还是不重构)之间的选择,考虑一下听起来更明智的卖出方法:
嗨,老板,我们按计划进行了所有工作,但现在我们要重建很多东西,以便将来可以添加功能X。
要么
嘿老板,我们准备释放。如果我们必须添加功能X,则可能要花几天的时间。
如果您选择其中一个,您的老板可能会说:
谁说了功能X?
底线是,如果您无法在便宜的时候(早期迭代)纠正某些缺陷,有时需要付出一些技术债务。随着您接近已完成的功能和截止日期,进行高质量的代码设计会减少收益。
[此答案比最初提出的问题要宽一些,因为这是代码审查中许多其他问题的重定向。]
以下是一些我认为有用的原则:
私下批评,公开赞美。 让某人一对一地了解代码中的错误。如果他们做了出色的工作或完成了没人要的任务,请在小组会议上或抄送给团队的电子邮件中称赞他们。
分享您自己的错误。 我与学生和初级同事分享我的灾难性的第一次代码审查(收到)的故事。我还让学生知道我这么快就发现了他们的错误,因为我已经在自己之前做到了。在代码审查中,结果可能是:“我认为您在这里错误地定义了索引变量。由于时间错误,我经常检查该错误并关闭了数据中心。” [是的,这是一个真实的故事。]
记住要发表正面评论。 简短的“不错!” 或“巧妙的把戏!” 可能会成为初级或不安全程序员的一天。
假设对方很聪明,但有时会粗心。 不要说:“如果您实际上没有返回值,您如何期望调用者获得返回值?!” 说:“好像您忘记了退货声明。” 请记住,您在早期就编写了糟糕的代码。正如有人曾经说过的那样:“如果一年前不为自己的代码感到羞耻,那么您就不会学习。”
不在您的工作场所为朋友保存嘲讽/嘲笑。 如果代码异常糟糕,请在其他地方开玩笑。(我发现与一位程序员程序员结婚很方便。)例如,我不会与同事分享以下漫画(或本漫画)。
当一勺糖帮助药物消退时,错误的句子可以简洁地表达出来-没有20件事出现了错误-我将以一种表格形式提出,该表格表明我没有利益,没有自我投资我想要的东西被听到。通常是这样的:
我想知道是否会更好...
要么
对...有意义吗
如果原因很明显,我不作说明。这使其他人有机会承担该建议的某些知识,例如:
“是的,这是个好主意,因为< 您在这里明显的理由 >。”
如果改进是相当明显的,但是没有让我看起来是个白痴,没有想到它,并且这样做的原因反映了与听众共享的价值,那么有时我什至不建议这样做:
我想知道是否有办法... <共享价值声明在这里>
这仅用于与真正敏感的人打交道-与我的大多数同龄人一样,我就让他们拥有它!
您的问题是“如何对设计不良的代码进行代码审查?”:
IMO的答案很简单。讨论代码的设计以及设计有缺陷或不符合要求的方式。如果您指出有缺陷的设计或“不符合要求”,那么开发人员将被迫更改其代码,因为它没有执行所需的操作。
如果代码“功能上足够”和/或“符合规格”和/或“符合要求”:
如果您是此开发人员的对等方,则没有任何直接权力可以让您“告诉他”进行更改。
您还有两个选择:
我发现没有银弹。您必须使用所有这三个,并且必须创造性地使用这三个。
问题中有两个值得注意的问题,即机智部分和最后期限。这些是截然不同的问题-第一个是沟通和团队动力问题,第二个是计划和优先级问题。
机智地。我认为您想避免刷牙的自我和负面的评论。一些建议:
第二部分是优先级划分。您有很多改进建议,但由于临近截止日期,因此只有时间来申请一些建议。
好吧,首先,您首先要避免这种情况!您可以通过执行连续的增量审核来做到这一点。不要让开发人员在功能上工作数周,然后在最后一刻将其全部复习。其次,代码审查和实施审查建议的时间应作为任何任务的定期计划和估算的一部分。如果没有足够的时间进行适当的审查,则计划中出现了问题。
但是,让我们假设在此过程中出了点问题,现在您面临许多评论,而您没有时间实施所有评论。您必须确定优先级。然后进行更改,如果您推迟进行更改,那么这些更改将是最困难,最冒险的更改。
源代码中标识符的命名对于可读性和可维护性非常重要,但是将来更改也很容易且风险很小。与代码格式相同。所以不要专注于这些东西。另一方面,公开暴露的接口的健全性应该是最高优先级,因为它们在将来真的很难改变。持久性数据很难更改-如果您首先开始在数据库中存储不一致或不完整的数据,那么将来确实很难修复。
单元测试覆盖的区域是低风险的。您以后可以随时修复这些问题。没有但可以进行单元测试的区域的风险要低于不能进行单元测试的区域。
假设您有大量的代码,没有单元测试,并且存在各种代码质量问题,包括对外部服务的硬编码依赖。通过注入此依赖关系,可以使代码块可测试。这意味着您将来可以添加测试,然后再解决其余问题。使用硬编码的依赖项,您甚至无法添加测试。因此,请首先进行此修复。
但是,请首先避免在这种情况下结束!