我们的代码糟透了,我无力修复它。救命!

时间:2010-09-01 13:32:18

标签: c++ unit-testing refactoring scrum maintainability

我们的代码太糟糕了。实际上,让我澄清一下。我们的代码很糟糕。它很难调试,并且充满了很少人理解甚至记住的抽象概念。就在昨天,我花了一个小时在一个我已经为工作超过一年的地区进行调试,发现自己在想,“哇,这真的很痛苦。”这不是任何人的错 - 我确信这一切最初都是完全合理的。最糟糕的部分通常是它正常工作......只要你不要求它在其舒适区之外做任何事情。

我们的新代码非常好。我想我们在那里做了很多好事。它清晰,一致,(希望)可维护。我们有一台Hudson服务器正在运行以进行持续集成,我们已经开始使用单元测试套件了。问题是我们的管理层专注于编写新代码。没有时间给Old Code(甚至旧的新代码)提供它迫切需要的TLC。在任何特定时刻,我们的scrum积压(针对六个开发人员)有大约140个项目和大约十几个缺陷。这些数字并没有太大变化。我们正在尽可能快地添加东西。

那么我该怎样做才能避免陷入Old Code深陷的马拉松调试会话的麻烦?每个sprint都充满了新的发展和showstopper缺陷。具体地说...

  • 我可以做些什么来帮助维护和重构任务获得足够高的优先级来工作?
  • 您采用了哪些特定于C ++的策略来帮助防止新代码快速腐烂?

10 个答案:

答案 0 :(得分:22)

您的管理层可能专注于将工作功能融入产品中,并使其保持正常运行。在这种情况下,你需要做一个商业案例来重构旧的东西,因为通过X投入的时间和精力,你可以减少Y在Z期间的必要维护时间。或者你的管理层可能从根本上一无所知(这种情况发生,但是大多数开发人员似乎都认为不常见,在这种情况下,你永远不会获得许可。

您需要查看业务观点。对于最终用户来说,代码是丑陋的还是优雅的只是软件的作用并不重要。不良代码的成本是潜在的不可靠性和更改它的额外困难;它对程序员造成的情绪困扰很少被考虑。

如果你无法获得进入和重构的许可,你可以随时自己尝试一下。每当你修复一个bug时,做一点改写以使事情更清楚。这可能会比最小可能的修复更快,特别是在验证代码现在有效时。即使不是这样,通常也可以花一点时间修复bug而不会遇到麻烦。只是不要被带走。

如果你每次进去都可以让代码稍好一些,那么你会感觉好多了。

答案 1 :(得分:12)

答案 2 :(得分:2)

从您提供的信息中很难说清楚。我想要的一些问题是编写新代码的逻辑原因是替换旧代码。如果这是你正在做的,放弃旧的代码。

它是旧代码还有showstopper缺陷吗?如果是这样,他们来自哪里?旧代码没有“showstopper”缺陷,它只是越来越接近停止通常。毕竟它是旧代码 - 它应该具有相同的旧缺陷和相同的旧限制,而不是必须立即查看的东西。 Showstopper缺陷是新的代码缺陷。听起来旧代码中有积极的开发。

如果您在旧代码之上编写所有这些新代码,并且没有计划一劳永逸地修复它,抱歉,当您太忙于埋葬自己挖掘自己时,您只能做很多事情进行。

如果是后者的话。你应该认识到自己要去哪里,并试着分开一点。如果你计划在周围拯救你的力量进行一场有价值的战斗,那么它最终会崩溃。

在此期间尝试选择一些设计模式。有几个可以至少帮助保护新代码免受旧代码的影响,但最终还是很难编写好的代码来防止恶意代码。

你的冲刺声可能会混淆。没有整体方向吗?这应该决定你有多少积压,虽然事情可能每个月都在变化,是不是有明确的意识朝着某个最终目标前进?

新代码腐烂了吗?你预防的方式是你有一个有意义的设计,一个有意义的方向,一个致力于工作质量和设计愿景的质量团队。如果你有,那么纪律是保持质量的。如果您没有抱歉,那么您基本上是在编写没有任何用途的代码。它基本上腐烂在葡萄藤上。

不是批评,只是想说实话。深吸一口气。慢一点。你似乎需要它。看看你在这里写的东西。它什么都没说。你谈到重构,scrums,showstoppers,缺陷,旧代码,新代码。这有什么意思?这一切都混乱了。

“新计划与遗留系统”有何关系? “需要根据最新的理解等重构早期冲刺周期代码”实际上是showstoppers“当前企业计划的早期组件已经发布但遇到了问题,并且由于新的开发而没有时间预算”。

这些将是有意义的概念。你没有给我们任何东西。我知道这很激烈。我的冲刺也是疯狂的,我们添加了大量的支持;因为我们无法预先获得许多要求(我的许多新要求因为不得不与外部监管机构竞争而导致,正常的业务流程并非始终可用)。

但与此同时,由于必须做的事情的巨大规模和时间,我才被打倒。添加到我的待办事项中的所有内容都需要存在。这很疯狂,但与此同时,我非常清楚地知道我去过哪里,我需要去哪里,以及为什么这条路变得更难。

退一步,清除你的想法,弄明白 - 你去过的地方和你去的地方。因为如果你知道,那肯定不是很明显。如果您无法与同事交流任何信息,那么您与业务经理的距离会有多远?

答案 3 :(得分:2)

旧代码总是很糟糕。可能有一些罕见的例外由Kernighan或Thompson这样的人写的,但对于典型的“写在办公室的代码”的东西,随着时间的推移,它会发臭。开发人员获得更多经验。较新的实践,如持续集成,改变了游戏。东西被遗忘了。新的维护者无法掌握设计并希望重写。所以最好接受这一点。

一些可能有帮助的随机事情......

  • 与您的团队讨论。分享您的经验和您的顾虑,同时避免“男人你的旧代码糟透了”(出于显而易见的原因),看看共识是什么。你可能并不孤单。
  • 忘记你的经理。不要将它们暴露在这种详细程度 - 他们不需要考虑新旧代码,如果他们这样做可能不会理解。这对您的团队来说是一个问题,如果有必要,可以让您的PO了解
  • 要有可能把东西丢掉。一些旧代码可能与用户首先不再使用或未能被采用的功能有关。为了让这项工作更加有效,你真的需要更高一些,并考虑代码真正提供用户或业务价值的地方,而不仅仅是一个没有人勇于做出决定的泥潭。谁敢,胜利。
  • 放松您对建筑一致性的看法。总有一种方法可以在某个地方使用新代码进入工作系统,这可能会让您慢慢迁移到更新,更智能的方法,同时保留旧的时间不会破坏现有的东西。

总体而言,在这种情况下获胜不仅仅是编码技巧,还有更多关于智能选择和处理人性方面的问题。

希望有所帮助。

答案 4 :(得分:1)

我建议跟踪您的“旧代码”中涉及的错误和代码更改的数量,并在下次团队会议上将其呈现给您的经理或其他开发人员。有了这个,它应该足够简单,让他们相信,需要做更多的工作来重构你的“旧代码”并使其与你的“新代码”相提并论。

记录最难以理解的“旧代码”部分也应该谨慎。这些也是您的“旧代码”的一部分,您应该在获得批准后首先进行重构。

答案 5 :(得分:1)

要尝试的事情:将你的班级分组 - 比如说 - 最差的10%,最好的10%,其余的。将清单发送给您的管理层,说:“我预测下一季度的大部分漏洞将在第一组中找到。”根据长度,cyclomatic complexity,测试覆盖率 - 任何工具都方便,舒适。然后坐下来观察 - 并且正确。现在你已经有了一些可信度,当你说“我想投入一些资源来改善我们的错误代码,减少错误和维护成本 - 我知道在哪里投入这些能量,看到了吗?” / p>

答案 6 :(得分:0)

您可以创建新代码如何工作以及类和函数如何相互关联的图表和草图。你可以使用FreeMind或Dia。我绝对同意记录和评论您的代码。 我曾经也遇到过这个问题。我为自己的语言编写了J2ME的字体类。由于这些原因,您可能也会在代码中看到它,这很糟糕。

  • 没有评论或文档
  • 少面向对象
  • 错误的变量/函数名称
  • ...

但几个月后我被迫再写一遍。现在我学会了使用有时很长的有意义的变量名。写评论比写代码更多。并使用图表来表示项目的课程及其关系。

我不知道如果这是一个真正的答案,但它肯定对我有用。对于旧代码,您可能实际上必须重读整个内容并在记住功能时添加注释。

希望它有所帮助。

答案 7 :(得分:0)

与您的产品负责人交谈!说明一旦这个障碍被消除,投入重构旧代码的时间将使他在新功能上获得更高的团队速度。

答案 8 :(得分:0)

除了上述提到的方法之外,您还可以尝试以下方法:

保持未来代码清洁

  • 尝试结对编程,至少对于有意义的部分。这是一种将经过审核,重构的代码作为实践的有效方法。
  • 尝试重构“完成”的定义。然后它将成为估算过程的一部分并相应地分配。因此,完成的定义可能包括:编码,单元测试,功能测试,性能测试,代码审查,重构和集成(或类似的东西)。

用于清理旧代码:

  • 单元测试非常适合帮助您重构并弄清楚工作原理。
  • 我同意有关大规模重构需要商业案例的意见。但是,小规模的重构可以很容易地包含在估算中,并将立即提供回报。即:我花了2个小时重写一块,但无论如何我都会花时间寻找虫子。

您可能还需要考虑让产品所有者和scrummaster为旧代码与新代码捕获单独的速度,并相应地使用它。

答案 9 :(得分:0)

如果有一个理想的新功能,并且您可以描绘一个非压倒性的代码块,那么您可能能够获得管理层的祝福,用具有所需新功能的新代码替换旧代码。当我这样做时,我不得不写一个有点丑陋的垫片层来满足我不打算触摸的软件部分的旧接口。还有一个可以运用现有代码并运用新代码的测试工具,以确保通过填充层看到的新代码可以欺骗应用程序的其余部分,使其认为没有任何改变。通过重新设计我们重新设计的部分,我们能够显示出巨大的性能优势,与所需新硬件的兼容性,减少我们每个现场网站对管理应用程序空间的专业知识的需求 - 以及新代码 更可维护。最后一点对用户来说并不重要,但返工的其他优点足以吸引用户“出售”数据转换有点痛苦的优点。

另一个更为温和的成功故事:我们有一个体面的故障跟踪系统,已经有多年的历史了。我们的应用程序中有一个子系统,它以其烧毁维护程序员的速度而闻名。很明显(很明显,在我看来)它需要重大的重写,但管理层并不热衷于此。我们能够深入了解故障跟踪数据中的历史记录,以显示维护此模块的人员配备水平,并且尽管如此,每月针对该模块的故障单继续以恒定速率达到。当面对这样的实际数据时,即使那些长期以来一直对该子系统的人员重新工作紧张的不情愿的管理者也可以看到指派员工重新修改该模块的优点。

以前的方法是单独留下该模块的输入和输出。好消息是,在新代码中使用其新颖的数据结构投入虚拟内存确实为模块带来了显着的性能提升。坏消息是,在我们真正了解原始实施中的错误之前,我们几乎完成了重新实施,这样它在大多数情况下都可以正常工作,但在某些日子里成功地失败了。第一次切割忠实地再现了那些错误,但是在重新编写的代码中更容易理解错误,所以我们现在有机会真正解决这个问题。回想起来,也许我们更聪明地捕获产生问题的数据,并且已经更好地注意确保重新设计的版本不会重现该问题。但事实是,在重写之前,我们还没有理解这个问题。因此,重写为用户提供了更好的性能,并提高了对当前程序员的理解,从而真正解决了真正的问题。

一个失败的例子:还有另一个令人难以置信的丑陋模块,一直是一个痛处。唉,我不够聪明,能够理解这个特殊的可怜的人渣和恶棍蜂巢的事实界面,至少不是在名义上的发布时间表的时间范围内。我想相信,如果有更多的时间,我们可以找到一个合适的计划来重新处理系统的这一部分,也许一旦我们理解了它,我们甚至可以确定用户所需的改进,我们可以适应改写。但我不能保证你会在每个盒子里找到奖品。如果盒子对你来说完全不明显,那么切掉一大块并用干净的代码替换那块就很难了。负责该模块的那个人可能是最能确定攻击计划的人,但他看到频繁的崩溃和来自现场的呼叫作为“工作保障”。我不认为管理层真的认识到他需要放弃一边渴望改变的人,但这可能是需要的。

德鲁