在审查过程中,我该如何在技巧上建议改进其他人设计不良的代码?


130

我是干净代码和代码技巧的忠实拥护者,尽管我目前从事的工作不被视为重中之重。我有时会发现自己的处境是,同位人的代码充满混乱的设计,并且很少担心将来的维护,尽管它功能正常且几乎没有bug。

当您认为需要进行大量更改并且有最后期限时,您将如何在代码审查中提出改进建议?请记住,建议在截止日期之后进行改进可能意味着,随着新功能和错误修复的到来,它们将被完全取消优先级。


25
首先,请确保您的观点不是主观的。开发人员经常会注销其他人的代码,因为他们只是喜欢其他样式或方言。如果不是这种情况,请尝试一次提供一项改进。
编码器

由于许多软件开发都与权衡有关,并且由于我所说的代码工艺主要基于设计,因此许多代码审查评论最终都是主观的。这就是为什么我问“您如何提出改进建议 ”的原因。当然,我的目标不是决定什么。
Yony​​ 2012年

5
这个问题听起来好像在完成测试后就进行了代码审查。如果是这种情况,那么您要么浪费测试时间(任何更改都需要重新测试),要么由于代码审查而使更改变得更加困难(为什么更改代码已经起作用?)。
vaughandroid

3
@Baqueta-为什么不知道它是否有效,为什么还要审查代码并浪费多个人的时间?
Dunk

4
@Baqueta显然有不同类型的测试。如果它们有用,那么代码审查应该在初始测试(例如单元测试(这样就知道了))之后以及最终测试(例如用户验收测试)之前进行(这样所做的更改不会产生繁文tape节) 。
Caleb

Answers:


160
  1. 仔细检查你的动机。如果您认为代码应该改变,你应该能够清晰地说出一些理由,为什么你认为它应该改变。这个原因应该比“我本来会做得不同”或“丑陋”更具体。如果您不能指出拟议的更改会带来一些好处,那么花时间(也就是金钱)来进行更改就没有多大意义。

  2. 项目中的每一行代码都是必须维护的一行。代码应该只要能够完成工作并易于理解就可以,并且不再需要。如果您可以在不牺牲清晰度的情况下缩短代码,那很好。如果可以在提高清晰度的同时做到这一点,那就更好了。

  3. 代码就像具体的一样:坐了一段时间后,更改起来更加困难。如果可以,请尽早建议您进行更改,以使更改的成本和风险都最小化。

  4. 每次更改都会花费金钱。重写有效且不太可能需要更改的代码可能会浪费很多精力。将注意力集中在更容易更改或对项目最重要的部分上。

  5. 形式遵循功能,有时反之亦然。如果代码混乱,则很有可能还包含错误。寻找这些错误,并批评有缺陷的功能,而不是代码的美观。建议改进,使代码更好地工作使代码的操作更容易验证。

  6. 区分设计和实施。具有a脚界面的重要班级可以通过像癌症这样的项目传播。这不仅会降低项目其余部分的质量,而且会增加修复损坏的难度。另一方面,具有精心设计的接口但糟糕的实现的类应该没什么大不了的。您始终可以重新实现该类,以获得更好的性能或可靠性。或者,如果它可以正常工作并且足够快,则可以放心使用它,因为它的碎片被很好地封装了。

总结以上几点:确保建议的更改会增加价值。


3
确实,这归结为“出售”您的担忧。如前所述:指出收益和附加值。根据我的经验,这是一项艰巨的工作。
维瓦尼2011年

4
了解自己的动机不只是卖东西。您需要了解为什么喜欢某些技术而不喜欢其他技术,因此您可以知道经验法则何时有效,什么时候无效。经验丰富的程序员在错误的情况下应用正确的技术会产生许多很多问题。
约尔根·福格·

1
您的观点似乎表明打高尔夫球还不错... :-)
Florian Margaine 2015年

2
整个答案+1,但特别是对于“如果代码混乱,那么它还包含错误的可能性就更大”
Konamiman

2
有趣的是,指向(6)的推论似乎是接口质量比实现质量更重要
Brad Thomas

16

有一个通过重构增加价值的最佳选择。更改需要完成三件事:

  • 改进可能会更改的代码
  • 增加清晰度
  • 花费最少的精力

注意事项:

  1. 我们知道,干净的代码编写和维护成本较低,并且工作起来更有趣。您的工作是将该想法出售给公司中的人员。像推销员一样思考,而不是傲慢的脾气(即不像我)。
  2. 你赢不了,只能输得更少。
  3. 专注于增加真正的价值-不仅仅是美丽。我希望自己的代码看起来不错,但有时必须更多地接受那些廉价的事务。
  4. 找到最佳位置的一个好方法是遵循童子军原则-在编写代码区域时,始终保持其形状比发现的更好。
  5. 有一点改善总比没有改善好。
  6. 充分利用自动化工具。例如,刚刚收拾了一下格式化的工具,可以使世界不同。
  7. 出售其他偶然提高代码清晰度的想法。例如,单元测试鼓励将大型方法分解为较小的方法。

5
+1使用自动化工具。令人震惊的是,似乎很多商店都不在乎开发人员工具包的外观。仅仅因为您具有源代码控制,编辑器和编译器,并不能使您的工具包完整。
Spencer Rathbun

4
@Spencer:我完全同意。同时,由于对功能或福利的无知或懒惰,开发人员对那些不使用现有工具的开发人员感到沮丧。大多数现代IDE都具有内置的代码格式化功能,该功能仅需几次按键操作-但一些开发人员并未使用它。
Kramii

2
真正。但我将其包括在商店本身之下,不在乎。您的开发人员可能不了解当前工具集中的某些功能,尤其是如果管理人员从未费心创建标准的情况下。其次,许多IDE都非常大,具有巨大的功能集。我已经使用vim几年了,但是我仍然不知道我可以用它做什么所有不同的事情。如果您将我放到Visual Studio中,直到我有足够的时间来研究它之前,我都会保留90%的功能。那我可能不记得了。
Spencer Rathbun

14

如果代码运行时没有严重的错误,并且临近主要的截止日期(例如,损益表或公司PR),那么提出需要进行重大更改的改进建议为时已晚。甚至代码的改进也可能给项目部署带来风险。改进的时间早于项目,当时有更多时间投资于代码库的未来健壮性。


如果您到了那里,那么导致这一点的过程可能会使您失败。
蒂姆·艾伯

9

代码审查有3个目的:

  1. 检查错误

  2. 检查以查看代码可以改进的地方

  3. 编写代码的人的教学工具。

评估设计/代码质量当然与#2和#3有关。

远至#2:

  • 非常清楚地说明提议的变更与修复成本之间的关系。作为任何业务决策,这应该与成本/收益分析有关。

    例如,“ X的设计方法将显着减少进行更改Z时发生错误Y的可能性,而且我们知道这段代码每2周经历一次类型Z的更改。处理由于错误Y +查找错误而导致的生产中断的成本+修复并发布修复+通过不交付下一组功能而带来的机会成本为$A;而现在清理代码的成本和机会成本(例如,后期交付或功能较少的价格)为$B。现在,评估-或更确切地说有你的团队领导者/管理者-评估$AVS $B而定。

    • 这将帮助聪明的团队领导者有效地进行管理。例如,他们将使用全部信息做出合理的决定

    • 这将(特别是如果您说得好)会提高您的地位-例如,您是一个足够聪明的人,可以看到更好的设计的好处,并且足够聪明,不会在没有权衡商业考虑的情况下虔诚地要求它。

    • 并且,在可能发生错误Z的情况下,您可以在下一组建议中获得更多的利用。

远至#3:

  • 非常明显地将“必须修复”的错误/问题从“这是一种最佳实践,如果可以节省资源,则应该予以修复-请参阅附加的优点/缺点分析”设计改进(附加上面针对#2所述的内容)与“这些是我认为可以帮助您提高代码健壮性的常规准则,以便您可以更轻松地维护代码的可选更改。请注意该措辞-不是关于“使代码像我想要的那样”-是“如果这样做,您将获得a,b,c的好处”。语气和方法很重要。

2
在#3上,代码审查不仅仅用于教导代码作者。对于没有经验的开发人员以及对于团队中不熟悉的经验丰富的程序员而言,审查都是一种很好的方法,可以加快编码标准的速度。以小组形式讨论问题也可以导致对产品的见解。
卡雷布(Caleb)

1
@Caleb-好点。我不想提出太多要点,因此对这一要点进行了编辑,但这仍然是一个有效的要点。
DVK

#4对新功能进行交叉培训的开发人员
Juan Mendes

1
#5-代码审查的主要目的是确保(正确地)实施设计文档
Mawg 2015年

8

选择战斗,如果快要截止期限了,那就什么也不做。下次其他人正在审阅或维护代码时,他们仍然遇到麻烦,然后与他们联系,以为是一个团队,您在审阅代码时应更加专注于代码质量,这样以后就不会遇到太多麻烦了。

他们应该在进行额外工作之前先了解其价值。


5
期限不是总是在眼前吗?
FreeAsInBeer 2015年

8

我总是以“我愿意”开始我的评论,这表明我的观点只是众多观点之一。

我也总是包含一个原因。

我会提取这种成块的方法,因为可读性。”

我对一切都发表评论;大和小。有时候,我对一项更改发表了一百多条评论,在这种情况下,我还建议结对编程,并以自己为荣。

我出于某种原因试图建立一种通用语言。可读性,DRY,SRP等

我还创建了一个有关“干净代码和重构”的演示文稿,向我的同事解释了原因并展示了如何进行。到目前为止,我已经举行了三次,我们正在使用的一家咨询公司要求我再次为他们举行。

但是有些人还是不会听。然后我就离开了排名。我是设计负责人。代码质量是我的责任。在当前状态下,此更改不会在我的手表上显示。

请注意,我非常乐意拒绝我的任何评论;由于技术原因,截止日期,原型等原因,我还有很多要学习编码的知识,并且会一直听取推理。

哦,最近我提出要向团队中第一个吃午餐的人提出午餐,后者提出了一个不重要的变更,对此我没有任何评论。(嘿,你也必须玩得开心。:-)


5

我有时会发现自己的处境是,同位人的代码充满混乱的设计,并且很少担心将来的维护,尽管它可以正常工作并且几乎没有bug。

此代码已完成。在某个时候,重新设计的成本太高,无法证明其合理性。如果代码已经可以正常运行且几乎没有错误,那么这将是不可能的。建议一些方法以在将来进行清理并继续。如果/将来代码中断,请重新评估重新设计的价值。它可能永远不会中断,这将是很棒的。无论哪种方式,您都在赌博不中断的合理意义上,因为现在或以后的成本都是一样的:冗长,糟糕的重新设计。

将来您需要做的是更紧密的开发迭代。如果您能够在所有消除臭虫的工作都投入之前查看此代码,则建议重新设计是很有意义的。最后,除非以根本上无法维护的方式编写代码,并且可以肯定地知道在发布后不久就需要更改代码,否则进行大型重构绝对没有任何意义。

给定两个选项(重构还是不重构)之间的选择,考虑一下听起来更明智的卖出方法:

嗨,老板,我们按计划进行了所有工作,但现在我们要重建很多东西,以便将来可以添加功能X。

要么

嘿老板,我们准备释放。如果我们必须添加功能X,则可能要花几天的时间。

如果您选择其中一个,您的老板可能会说:

谁说了功能X?

底线是,如果您无法在便宜的时候(早期迭代)纠正某些缺陷,有时需要付出一些技术债务。随着您接近已完成的功能和截止日期,进行高质量的代码设计会减少收益。



怎么样了:“嗨,老板,您知道您想要的功能X,好,我们需要几天的时间才能开始使用它。” 他也想要那样。YAGNI并不是创建混乱代码或使代码混乱的借口。少量的技术债务不是大问题,但是必须偿还债务,越早偿还,债务越便宜。
2015年

5

[此答案比最初提出的问题要宽一些,因为这是代码审查中许多其他问题的重定向。]

以下是一些我认为有用的原则:

私下批评,公开赞美。 让某人一对一地了解代码中的错误。如果他们做了出色的工作或完成了没人要的任务,请在小组会议上或抄送给团队的电子邮件中称赞他们。

分享您自己的错误。 我与学生和初级同事分享我的灾难性的第一次代码审查(收到)的故事。我还让学生知道我这么快就发现了他们的错误,因为我已经在自己之前做到了。在代码审查中,结果可能是:“我认为您在这里错误地定义了索引变量。由于时间错误,我经常检查该错误并关闭了数据中心。” [是的,这是一个真实的故事。]

记住要发表正面评论。 简短的“不错!” 或“巧妙的把戏!” 可能会成为初级或不安全程序员的一天。

假设对方很聪明,但有时会粗心。 不要说:“如果您实际上没有返回值,您如何期望调用者获得返回值?!” 说:“好像您忘记了退货声明。” 请记住,您在早期就编写了糟糕的代码。正如有人曾经说过的那样:“如果一年前不为自己的代码感到羞耻,那么您就不会学习。”

不在您的工作场所为朋友保存嘲讽/嘲笑。 如果代码异常糟糕,请在其他地方开玩笑。(我发现与一位程序员程序员结婚很方便。)例如,我不会与同事分享以下漫画(或漫画)。

在此处输入图片说明 WTF /分钟


4

当一勺糖帮助药物消退时,错误的句子可以简洁地表达出来-没有20件事出现了错误-我将以一种表格形式提出,该表格表明我没有利益,没有自我投资我想要的东西被听到。通常是这样的:

我想知道是否会更好...

要么

对...有意义吗

如果原因很明显,我不作说明。这使其他人有机会承担该建议的某些知识,例如:

“是的,这是个好主意,因为< 您在这里明显的理由 >。”

如果改进是相当明显的,但是没有让我看起来是个白痴,没有想到它,并且这样做的原因反映了与听众共享的价值,那么有时我什至不建议这样做:

我想知道是否有办法... <共享价值声明在这里>

这仅用于与真正敏感的人打交道-与我的大多数同龄人一样,我就让他们拥有它!


1
我很少说“我想知道……这样做会更好吗”。我只是说,如果我不确定-在这种情况下,作者可以自由考虑是否更好,也可以自由更改。我通常会说“我会X”。(有时我会说“我会做X,但是您的方法更好”)。这意味着我认为X更好,但是您可以不同意。或者我会说“这不起作用”或“这很危险”,您最好更改一下。有时,我被告知“这是行不通的”,通常我看一下代码,然后说“ Oh shit”,然后修复它。
gnasher729

3

代码审查并不总是针对改进。

在项目即将结束时进行的检查似乎就是这样,以便所有人都知道从何时开始发现错误(或者对于更好设计的项目,什么可以在以后重用)。不管审核结果如何,根本没有时间进行任何更改。

要真正进行更改,您需要在项目中更早地讨论代码和进行设计-仅当谈论可能的方法时,代码才更容易更改。


3

您的问题是“如何对设计不良的代码进行代码审查?”:

IMO的答案很简单。讨论代码的设计以及设计有缺陷或不符合要求的方式。如果您指出有缺陷的设计或“不符合要求”,那么开发人员将被迫更改其代码,因为它没有执行所需的操作。

如果代码“功能上足够”和/或“符合规格”和/或“符合要求”:

如果您是此开发人员的对等方,则没有任何直接权力可以让您“告诉他”进行更改。

您还有两个选择:

  1. 您必须使用自己的个人“影响力”(一种间接的“权力”形式)和/或具有“说服力”的能力
  2. 加入组织的“代码处理”小组,并开始将“代码维护”作为更高的优先级。
  3. 硬着头皮,学习如何更快/更流畅地阅读糟糕的代码,以免被困在烂代码上(这听起来像是在遇到糟糕的代码时一直被困或放慢)。
    • 这也将使您成为一名更强大的程序员。
    • 当您处理糟糕的代码时,它将使您更正糟糕的代码。
    • 而且这也将使您可以处理更多项目,因为许多项目的代码功能很差,但是代码很多。
  4. 以身作则。使您的代码更好...但是不要试图成为完美主义者。
    • 因为那样,您将成为“无法按时完成任务的慢家伙,总是在批评,并认为自己比其他所有人都更好”。

我发现没有银弹。您必须使用所有这三个,并且必须创造性地使用这三个。


我希望我能学到#3,我得到可怜的代码,我有一个困难时期甚至试图了解它很沮丧......它的工作不断....
胡安·门德斯

设计有缺陷吗?什么设计?
gnasher729

1

万一设计糟糕透顶,您的重点应该放在最大化封装上。这样,就可以用设计更好的类替换各个类/文件/子例程。

集中精力确保组件的公共接口设计合理,并仔细隐藏内部工作原理。另外,数据存储包装器也是必不可少的。(存储的大量数据可能很难更改,因此,如果“实现流失”进入系统的其他区域,则很麻烦)。

克服了组件之间的障碍后,请集中精力处理最有可能引起重大问题的组件。

重复进行直到截止日期或系统“完美”为止。


1

与其直接对某人的代码进行直接批评,不如在代码审查过程中在我们的注释中给予帮助总是更好的。

我遵循的一种方法是

  1. 如果我们这样做,那将是最佳选择。
  2. 以这种方式编写将使其运行更快。
  3. 如果您执行“ this”,“ this”和“ this”,您的代码将更具可读性

即使您的截止日期临近,此类评论也将被认真对待。可能会在下一个开发周期中实施。


0

代码审查必须与文化和开发周期相结合才能起作用。在功能X的开发结束时安排大型代码审查不太可能会奏效。首先,进行更改将更加困难,并且某人可能会感到尴尬-对活动产生抵触感。

您应该提早提交和频繁提交,并在提交级别进行审查。有了代码分析工具,大多数审核将很快进行。诸如FindBugsPMD之类的自动化代码分析/审查工具将帮助您摆脱大量的设计错误。但是,它们不会帮助您解决体系结构级别的问题,因此您必须具有可靠的设计并根据该设计判断整个系统。


0

提高代码审查的质量。

除了要检查的代码的质量之外,还有代码检查本身的质量:

  • 提议的更改是否真的是对现有更改的改进
  • 还是只是见仁见智?
  • 除非很明显,否则审阅者是否已正确解释,为什么
  • 它花了多少时间?(我看到审查持续了几个月,而开发人员则负责解决所有众多合并冲突)。
  • 音?

接受高质量的代码审查要比一些最受质疑的自我修饰容易得多。


0

问题中有两个值得注意的问题,即机智部分和最后期限。这些是截然不同的问题-第一个是沟通和团队动力问题,第二个是计划和优先级问题。

机智地。我认为您想避免刷牙的自我和负面的评论。一些建议:

  • 对编码标准和设计原则有共同的了解。
  • 不要批评或评论开发人员,而只批评代码。避免使用“您”或“您的代码”一词,只需谈论与所有开发者分离的受审查的代码即可。
  • 请以已完成代码的质量为荣,以使评论评论有助于改善最终结果。
  • 建议改进而不是需求。如果您不同意,请始终进行对话。当您不同意时,请尝试理解另一种观点。
  • 让评论双向进行。即让您审核的人接下来检查您的代码。没有“单向”评论。

第二部分是优先级划分。您有很多改进建议,但由于临近截止日期,因此只有时间来申请一些建议。

好吧,首先,您首先要避免这种情况!您可以通过执行连续的增量审核来做到这一点。不要让开发人员在功能上工作数周,然后在最后一刻将其全部复习。其次,代码审查和实施审查建议的时间应作为任何任务的定期计划和估算的一部分。如果没有足够的时间进行适当的审查,则计划中出现了问题。

但是,让我们假设在此过程中出了点问题,现在您面临许多评论,而您没有时间实施所有评论。您必须确定优先级。然后进行更改,如果您推迟进行更改,那么这些更改将是最困难,最冒险的更改。

源代码中标识符的命名对于可读性和可维护性非常重要,但是将来更改也很容易且风险很小。与代码格式相同。所以不要专注于这些东西。另一方面,公开暴露的接口的健全性应该是最高优先级,因为它们在将来真的很难改变。持久性数据很难更改-如果您首先开始在数据库中存储不一致或不完整的数据,那么将来确实很难修复。

单元测试覆盖的区域是低风险的。您以后可以随时修复这些问题。没有但可以进行单元测试的区域的风险要低于不能进行单元测试的区域。

假设您有大量的代码,没有单元测试,并且存在各种代码质量问题,包括对外部服务的硬编码依赖。通过注入此依赖关系,可以使代码块可测试。这意味着您将来可以添加测试,然后再解决其余问题。使用硬编码的依赖项,您甚至无法添加测试。因此,请首先进行此修复。

但是,请首先避免在这种情况下结束!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.