多年来有没有办法避免意大利面条代码? [关闭]

Posted

技术标签:

【中文标题】多年来有没有办法避免意大利面条代码? [关闭]【英文标题】:Is there a way to avoid spaghetti code over the years? [closed] 【发布时间】:2008-12-15 21:00:12 【问题描述】:

我做过几份编程工作。每个有 20-50 名开发人员,项目进行 3-5 年。

每次都是一样的。有些程序员很聪明,有些程序员很普通。每个人都有自己的 CS 学位,每个人都读过设计模式。意图是好的,人们正在努力编写好的代码,但几年后代码还是变成了意大利面条。模块 A 的更改突然破坏了模块 B。代码中总是有这些部分,除了编写它的人之外,没有人能理解。更改基础架构是不可能的,并且向后兼容性问题会阻止好的功能进入。有一半的时间您只想从头开始重写所有内容。

比我更有经验的人认为这是正常的。是吗?它必须是吗?我可以做些什么来避免这种情况,或者我应该接受它作为生活的事实吗?

编辑:伙计们,我对这里的回复数量和质量印象深刻。这个网站和它的社区摇滚!

【问题讨论】:

我喜欢这个问题被标记为“绝望”。 :) 我删除了 despair 标签 - 抱歉! 【参考方案1】:

无情的勤奋与不断的单元测试相结合是防止意大利面条式代码的唯一方法。即便如此,这也只是一个创可贴的解决方案。一旦你不再注意,意大利面就会出现。

我经常发现引入意大利面条代码是因为那天有人很懒惰。他们知道有更好的方法可以做到这一点,只是没有时间。当你看到这种情况发生时,只有一件事要做。

打电话给他们并要求他们改变它

我发现在代码审查期间指出更好的方法通常足以让人们继续前进。如果他们签入并且我感觉很强烈,我会自己重构它。

我是否偶尔会显得有点古怪?我确定我会的。坦率地说,虽然我不介意。我不是一个混蛋,并以最好的社交方式处理这个问题。然而,让错误的代码被签入几乎可以确保我在未来的某个时候必须对其进行调试。我宁愿现在稍事休息,然后输入正确的代码。

我还觉得单元测试文化也有助于防止意大利面条式代码。对分解良好的代码的意大利面条代码进行单元测试要困难得多。随着时间的推移,这迫使人们在一定程度上保留他们的代码。

【讨论】:

我真的很喜欢你的建议。甚至幻想雇用一个特殊的人加入一个小组,该小组的唯一工作职责是检查提交的代码并召集他们。也许这是一种合理的做法。 如果只有 1 个人发出呼唤,他们会受到反感,人们会在他们周围工作。尝试在团队领导和后来的每个编码人员之间轮换职责。代码审查是每个人的责任,否则当审查员被解雇时,坏习惯就会卷土重来。【参考方案2】:

我相信避免代码腐烂的关键在于健全的自下而上的设计和实现方法(我坚信这一点,因此我将我的业务命名为 - Think Bottom Up - 在它之后!)。这里选择的工具是:

按合同编程 分层设计 专注于解耦 构建时始终牢记重用,寻找通用解决方案 让框架保持轻量、简单和专注

正如其他受访者所建议的,您需要尽早发现问题。对于绿色开发人员,这意味着指导(结对编程在这里很棒)和审查(代码和设计审查)。对于更高级的开发人员,这意味着要保持警惕。

最重要的是,不要害怕重构。如果重构让你感到害怕,那么你已经沉没了。如果重构被视为“不好”,那么您的业务就有问题。

当你修复某些东西时,正确地修复它。我使用术语“fux”来描述以错误方式完成的修复:它只是“fux”了您的代码库。

干杯,

【讨论】:

+1 表示“fux”。 :))) 它非常创新和直观...... 为什么谢谢你 - 我知道如果这个“软件工程”演出不成功,我总是可以求助于单口喜剧。我更喜欢 +1 以自下而上地思考,但是嘿,一切都很好! 也许是书呆子单口喜剧。也许你应该开始写博客:) 书呆子喜剧?我相信我的风格是“为有眼光的极客准备的喜剧”。【参考方案3】:

20 到 50 名开发人员可能是问题所在。这是相当高的,需要大量的管理和资源来控制一切。

我会考虑将项目拆分成更小的可重复使用的部分。从核心系统中抽象出某些层。

【讨论】:

嗯,在这些情况下需要 20-50 名开发人员,因为项目相对较大。由于公司没有其他产品,因此模块的重用并不是真正的。黑盒模块测试很困难,因为您必须为每个模块模拟系统的其余部分。但是谢谢:-) 你能详细说明它是什么吗?这似乎是一个巨大的项目,尤其是“不可分割” +1 答案中的“可重复使用”一词似乎引起了混淆,您甚至可以将其删除。拆分将有助于管理复杂性,因为模块 A 很难以模糊的方式耦合到模块 B。如果接口是精心设计的。 DDD 在这里很有帮助,可以在有界上下文中拆分并拥有更清晰的界面。无论是单体架构还是微服务架构。【参考方案4】:

在代码的不同区域之间创建“防火墙”。为此,您可以定义不同的区域或代码层,并定义每个层响应的单个 API(在 Java 中,这通常通过接口完成)。应该有 API 使用的基本接口或类,但它们对这些层的内部“一无所知”。例如,gui 不应该知道或关心您如何存储数据,并且您的数据库不应该知道或关心数据如何呈现给最终用户。

这些 API 不必一成不变 - 只要确保不污染防火墙,您应该能够根据需要添加内容。

【讨论】:

我理解并尊重您所说的,但这并不总是可行的。如果我为模块 A 提供基础设施,那么模块 A 依赖它来进行正确的工作/测试。为这个基础设施实现一个模拟就像为了测试目的再次实现基础设施一样。 正确,但这通常在实践中发生。有时可以通过使用模拟框架来最大程度地减少工作量。【参考方案5】:

我认为重点是你说的时候

你只想从头开始重写所有内容

接受它。尽可能多地使用单元测试,然后让重构成为一种常见的做法。 自动化和单元测试将确保更改不会引入回归;将一定比例的时间用于重构旧代码(这意味着新功能更少!)确保现有代码库不会变旧,或者至少不会那么快。

【讨论】:

重构必须意味着更多新功能而不是更少,否则这是一个坏主意。这可能意味着,现在没有新功能,但很快会比我现在投入更多的新功能。技术债务是一个有用的概念。 同时对设计不佳的系统进行单元测试可能需要大量工作/不可能/脆弱【参考方案6】:

代码审查、编码标准和公司政策。

以下适用于我们的店铺-由于我不知道您的店铺类型,您的里程可能会有所不同。在迁移到 Team Foundation Server 时,我们的大部分重点是保持代码质量 - 或至少以任何可能的方式帮助保持质量。我们正在添加的一些示例:

代码审查工作流程 - 强制执行代码审查作为流程的一部分。包含一项政策,如果代码未经审核,将阻止签入。 TeamReview - 通过提供完整的“IDE 内部”体验,减少代码审查的痛苦。 签入策略(一般) - 许多很酷的好东西可用于控制代码流。例如确保在签入之前记录公共和受保护的方法,以确保在没有相应工作项的情况下无法签入任何工作。

就像我说的,如果您使用的是不同的平台,那么可用的工具和您可以做的可能会有所不同。但不排除以任何可能的方式提供帮助的工具。如果您可以使用它来改进、控制和审核您的工作流程以及在其中移动的项目,那么它至少应该值得考虑。

请记住,流程中的任何更改都将涉及回退。我们帮助缓解这一问题的方法是将策略构建到培训中,以便从旧的版本控制/缺陷跟踪系统过渡。

【讨论】:

很棒的建议。特别是对于 .net 商店【参考方案7】:

听起来很多人没有遵循封装和良好设计的一些基本原则。

保持事物隔离并且不依赖于其他部分对于避免您描述的问题至关重要。您可能需要一些更高级别的设计师或架构师。这是一个典型的场景,人们已经证明了一些严厉的流程和变更管理是合理的。 (我不提倡)

您需要避免依赖和相互关系,并且只定义和使用公共接口。这当然是过于简单化了,但你可能会通过一些关于代码的指标——类的复杂性、公共方法、从逆向工程代码构建的 UML 图等方面学到很多东西。

【讨论】:

【参考方案8】:

我认为完全使用依赖注入可以获得的松散耦合是一项非常有用的技术特性。当您拆分应用程序的各个部分时,您就不太可能因为“有趣的”重用而产生意大利面条。

相反,您可能会走向过度碎片化,但这是另一个问题,而不是全球结构问题。

【讨论】:

【参考方案9】:

软件行业最大的问题是编程代码的质量被视为一个主观问题。如果没有一些定义明确的指标,仅仅保持整洁和遵循惯例并不足以确保质量是可以接受的。

有人尝试改变this,但它们不太可能获得足够的兴趣或接受,主要是因为长期以来形成的程序员文化是非常努力地远离任何类似于工程的东西。编程的“纯艺术”哲学意味着你的 20 到 50 名开发人员都会以自己独特的方式对代码进行攻击,因此无论单个编码人员多么优秀,团队努力的总和总是会达到成为“大泥球”。

为避免这种情况,要么将所有编码人员放在同一个“页面”上,将规范化代码作为惯例的一部分,要么在开发团队较小(1-3 人)而您是大人物的情况下追逐工作卡胡纳总有一天,大团队可能会找到一种方法来构建更好的东西,但在那之前,即使是最优秀的团队也非常幸运,如果他们能接近 10 个中的 6 个。我们构建低质量的软件,因为这就是我们已经建立的我们的行业要做...

保罗。

【讨论】:

【参考方案10】:

在至少有两双眼睛看到之前,不允许提交代码。

【讨论】:

【参考方案11】:

您必须密切关注软件开发实践。必须进行代码审查和单元测试,以不断确保更新会影响系统中的其他内容。 20 - 50 名开发人员很多,但可以做到。实施良好的流程是在这种环境中拯救您的唯一方法。强制编码标准也是关键。

【讨论】:

【参考方案12】:

Refactoring

尽量保持设计简洁。这并不容易,但值得付出努力。

【讨论】:

【参考方案13】:

我不认为这是正常的。当它在那里存在几年时,它真的很难与之抗争。

避免它的唯一方法是改变态度:

“敏捷开发人员对软件设计的态度与外科医生对无菌手术的态度相同。无菌程序使手术成为可能。没有它,感染的风险将高得无法忍受。敏捷开发人员对他们的设计也有同样的感受。即使是最微小的腐烂开始的风险也太高了,无法容忍。” 马丁·C·罗伯特 “C# 中的敏捷原则、模式和实践”

我强烈建议您阅读本书以获取建议。它命名了所有“设计气味”,它们存在的原因以及离开它们的后果。愿这将帮助您说服您的管理层当前情况不合适。

祝你好运!

【讨论】:

【参考方案14】:

更多代码审查,也许还有代码所有权。

如果您只是破解一些随机代码,那么您不会像您“拥有”的代码那样关心。如果您有责任维护项目的一个模块,那么您希望大放异彩。

代码审查是您展示代码的时候。

【讨论】:

【参考方案15】:

跟踪系统各个部分的缺陷和性能将使您能够发现问题。随着系统的更改,设计不良或编写不良的功能或模块将具有更高的缺陷率。当识别出“问题”模块时,可以做出重写模块(而不是应用程序)的决定。

【讨论】:

【参考方案16】:

持续重构。您必须随时进行重构,尤其是在设计级别。当您看到损坏的代码或设计时,请准备好修复它。这通常是修复未损坏的东西本身的情况。除了它是......它只是没有表现出它的破碎......但是。

【讨论】:

【参考方案17】:

Shore and Warden's The Art of Agile Development 是一本很棒的书,其中有一节是关于“将 XP 应用于现有项目”(在第 4 章中)。除非您努力奋斗,否则项目会随着时间的推移变得更糟:克服此类技术债务很难,并且会越来越难以发布可接受的版本。唯一的解决方案是降低交付新功能的速度,并将节省的时间用于提高测试覆盖率和重构。

通常,项目没有太多的测试覆盖率,也没有选择运行一个 10 分钟的自动化脚本来非常彻底地构建和运行您的代码。相反,大多数代码都是结构化的,因此很难测试。最好的选择是在可能的情况下添加简单的测试覆盖,同时开始重构以使代码抽象化,以便更容易测试。

尽管团队需要花时间改进代码以使其干净且可测试,但您可能无法在“完成”清理所需的时间内停止交付。因此,您必须逐步完成,同时还要添加新功能。没关系,先选择最糟糕的领域,不要指望马上有明显的好处。坚持下去,因为最终你会到达那里。不要听那些说所有大项目都不好的声音。

简而言之,每周花一点时间整理一下,确保下周的代码比本周好。

【讨论】:

【参考方案18】:

开始创建单元测试,这将帮助您解耦代码并避免错误修复的后续错误。如果你有很好的覆盖范围,它也会让你更容易删除未使用的代码。

【讨论】:

以上是关于多年来有没有办法避免意大利面条代码? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

缩短多余的 switch 语句

Vala 和 Genie 的生产准备好了吗? [关闭]

带开始按钮的烹饪倒计时

硬编码数组和对象还是从数据库中填充? [关闭]

将所有 CSS/JS 链接打包到包含的 PHP 文件中?

QTest 覆盖漆法