被压迫去黑暗面

时间:2010-05-26 04:13:48

标签: legacy goto

我们遇到了一种情况,即在已经感染了意大利面条代码的现有代码中添加新功能时,处理遗留(核心)系统的开发人员正在被迫使用GOTO语句。

现在,我知道可能存在使用“只需一个小GOTO”的论据,而不是花时间重构一个更易于维护的解决方案。问题是,这个孤立的“只有一点GOTO”并不是那么孤立。每周至少一次左右有一个新的“一点GOTO”要添加。由于代码可以追溯到1984年或之前的GOTO,这使得很多Pastafarians认为它受到了飞行意大利面怪物本身的启发,因此这个代码库已经令人恐惧了。

不幸的是,这里编写的语言没有任何现成的重构工具,因此更难以推动'Refactor以后提高生产力',因为短期胜利是这里唯一值得关注的胜利。

是否有其他人经历过这个问题,即每个人都同意我们不能添加新的GOTO来将2000行跳到随机区域,但是Anaylsts一直坚持这样做并且让管理层批准它?

tldr;

如何解决开发人员被迫(强制)不断添加GOTO语句的问题(通过添加,我的意思是添加跳转到随机区域多行),因为它' >功能更快'?

我开始担心我们可能会失去有价值的开发人员而不是这个......

Credit: XKCD

澄清:

转到 here

alsoThere:不,我在谈论那种从一个子程序中跳出1000行到另一个子程序中途的goto。 转到 somewhereClose

there:我甚至没有谈论你可以合理地阅读的那种类型,并确定一个程序正在做什么。 转到 alsoThere

somewhereClose:这是制作肉丸的代码midpoint: 如果第一次来这里转到 nextpoint detail:(每个人几乎完全不同) )转到 pointlessReturn

here:在这个问题中,我并没有谈论偶尔使用goto。转到there

tacoBell:它刚刚回到绘图板。 转到 Jail

elsewhere:当分析师每周花一些时间去解决程序正在做什么时,你的代码库就会出现严重问题。事实上,我实际上取决于我的hell: ,如果不是最新的goto 4版本规范 goto {{1 }} detail 转到 pointlessReturn:

tacoBell实际上,只是一个小小的更新,只有一个小小的胜利。我花了4个小时一次重构这个特定程序的一部分单个标签,因为我去了svn中的每次迭代。每个步骤(大约20个)都很小,合乎逻辑且很容易 goto Jail: bypass自发地跳出你的餐点并通过一些奇怪的意大利面进入你的屏幕 - 球状磁力。 转到 nextpoint:  elseWhere合理地验证它不应引入任何逻辑更改。使用这个新的更易读的版本,我与分析师坐下来,现在几乎完成了所有这些变化。 转到 bypass:

end首先*如果第一次来这里转到4:,没有第二次如果第一次来这里转到 hell,没有第三次如果第一次来这里转到 hell第四个现在最新转到 hell

hell

10 个答案:

答案 0 :(得分:28)

由于错误编写的GOTO引入了多少错误?他们花了多少钱给公司带来了多少钱?将问题变成具体的问题,而不是“这感觉很糟糕”。一旦你能够被负责人认为是一个问题,就把它变成一个政策,比如“除了简化功能的退出逻辑之外没有新的GOTO”,或“没有新的GOTO用于任何不能执行的功能”拥有100%的单元测试覆盖率“。随着时间的推移,收紧政策。

答案 1 :(得分:12)

GOTO没有制作好的代码意大利面,还涉及很多其他因素。 This linux mailing list discussion可以帮助我们了解一些事情(Linus Torvalds关于使用gotos的更大图景的评论)。

为了没有得到而试图制定一个“无goto政策”,从长远来看不会产生任何影响,也不会使你的代码更易于维护。这些变化需要更加微妙,并专注于提高代码的整体质量,按照使用平台/语言,单元测试覆盖率,静态分析等最佳实践的方式思考。

答案 2 :(得分:4)

发展的现实是,尽管所有关于以正确的方式做到这一点的花言巧语,但大多数客户对更快地做到这一点更感兴趣。代码库的概念迅速走向崩溃点,以及由此产生的业务后果,这是他们无法理解的,因为这意味着必须超越今天。

你所拥有的只是一个例子。你如何坚持这一点将决定你将来如何进行开发。我认为你有4种选择:

  1. 接受请求并接受您将始终这样做。

  2. 接受请求,并立即开始寻找新工作。

  3. 拒绝做,并准备好去解决这个烂摊子。

  4. 辞职。

  5. 您选择哪个选项取决于您对自己的工作和自尊的重视程度。

答案 3 :(得分:4)

也许你可以使用boyscout模式:让这个地方比你发现它更干净。所以对于每个featurerequest:不要引入新的gotos,而是删除一个。

这不会花太多时间进行改进,会给更多时间,找到新引入的bug。也许它不会花费太多额外的时间,如果你从部分删除goto,虽然必须花时间理解,并带来新功能。

争辩说,2小时的重构将在未来15分钟内节省20倍,并允许更快更深入的改进。

答案 4 :(得分:3)

回到原则:

  • 可读吗?
  • 有用吗?
  • 可维护吗?

答案 5 :(得分:2)

这是典型的“管理”与“技术”冲突。

尽管我是“技术”团队的成员,但多年来我一直坚定地支持这场辩论的“管理”方面。

这有很多原因:

  1. 很有可能使用gotos编写易于阅读的结构良好的程序!问任何汇编程序员;条件分支和原始do循环都是他们必须使用的。仅仅因为“风格”不是最新的,并不意味着它写得不好。

  2. 如果它是一团糟,那么如果您要进行完整的重写,或者如果您正在对该程序进行技术重构,那么提取您需要的业务规则真的很痛苦你永远不会确定重构程序的行为是否“正确”,即它确实与旧程序的行为完全相同。

  3. 投资回报 - 坚持原始的编程风格并进行最小的更改将花费最少的精力并快速满足客户的要求。花费大量的时间和精力进行重构将更加昂贵并且需要更长的时间。

  4. 风险 - 重写和重构很难做到,需要对重构代码进行大量测试,就客户而言,看起来像“错误”的东西可能是“功能”。 “改进”遗留代码的一个特殊问题是,业务用户可能已经完全依赖于存在错误的工作,或利用错误的存在来更改业务流程,而无需通知IT部门。

  5. 因此,所有管理层都面临着一个决定 - “添加一点goto”测试变更,并在双倍快速时间内投入生产,风险很小 - 或者 - 进行主要的编程工作并且当一系列新的虫子出现时,他们会尖叫着。

    如果你决定在五年内重构,一些鼻涕大学毕业生会呻吟你的重构程序不再符合流行语,并且要求他被允许花几周重写它。

    如果没有破坏,请不要修理它!

    PS:即使乔尔认为这是一个坏主意:things you should never do

    更新 - !

    好的,如果你想重构和改进你需要正确的代码。

    基本问题是你要对客户说“我想花费n周时间来完成这个程序,如果一切顺利的话,它将完全按照它现在做的那样。” - - 至少可以说这是一个很难卖的东西。

    您需要收集有关崩溃和停机次数的长期数据,分析和编程看似微不足道的变更所花费的时间,因为太难而未完成的变更请求数量,因为系统可能导致业务机会丢失变化不够快。还收集了一些关于维护结构良好的程序的成本的乙腈数据,而不是让它下沉。

    除非您有一个不透水的案例要提交给beancounters,否则您将无法获得预算。你真的必须把这个卖给业务管理人员,而不是你的直接老板。

答案 6 :(得分:1)

我最近不得不处理一些非传统本身的代码,但前开发人员的习惯当然是因为GOTO无处不在。我不喜欢GOTO的;他们制造了一堆可怕的东西,让调试成为一场噩梦。更糟糕的是,用普通代码替换它们并不总是直截了当。

如果您无法放松您的GOTO,我当然建议您不再使用它们。

答案 7 :(得分:1)

  

不幸的是,编写的语言没有任何现成的重构工具

您是否拥有具有宏功能的编辑器?你有shell脚本吗?多年来我做了大量的重构,很少使用重构浏览器。

答案 8 :(得分:1)

这里的根本问题似乎是你有“分析师”,他们在为某些代码添加goto方面描述了可能必要的功能变化。然后你就有了“程序员”,他们的工作似乎只限于输入那个变化然后抱怨它。

要做出与众不同的事情,那些人之间责任分配的功能失调需要改变。分解工作有很多不同的方法:经典的,传统的(在您的工作中很可能是官方的,但被忽略的政策)是让分析师编写一个与实现无关的规范文档,程序员将其实现为尽可能保持稳定。

理论方法的问题在于它在许多常见情况下实际上是不切实际的。特别是,“正确”地做到这一点需要被视为初级的员工与更高级的同事争辩,在办公室中拥有更好的社交关系,以及更多的商业头脑。如果参数'goto不是与实现无关的,那么作为分析师,你根本就不能说这个词'不会在你的工作空间中飞行,那么可能就是这种情况。

在许多情况下,更好的选择是:

  1. 分析师编写面向客户端的代码,开发人员编写基础架构。
  2. 分析师编写可执行规范,用作单元测试的参考实现。
  3. 开发人员创建分析程序编程的特定于域的语言。
  4. 你只有一个混合体,才能区分彼此。

答案 9 :(得分:-1)

如果对程序的更改需要“只需要一点点”,我会说代码非常易于维护。

这是处理遗留代码时的常见问题。坚持程序最初编写的风格或“现代化”代码。对我来说,答案通常是坚持原始风格,除非你有一个非常大的改变,证明完全重写是正确的。

另外请注意,几个“现代”语言功能,如java的“throw”语句,或SQL“ON ERROR”,实际上是伪装成“GO TO”。