63

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

现在,我知道使用“只需一点 GOTO”而不是花时间重构为更易于维护的解决方案可能存在争议。问题是,这个孤立的“只有一点 GOTO”并不是那么孤立。至少每周一次左右添加一个新的“一个小 GOTO”。由于可追溯到 1984 年或之前的代码充满了 GOTO,因此使用此代码库已经很恐怖了,这会让许多意大利面食者相信它的灵感来自飞行意大利面怪物本身。

不幸的是,编写此语言的语言没有任何现成的重构工具,因此推动“以后进行重构以提高生产力”变得更加困难,因为短期胜利是这里唯一关注的胜利......

有没有其他人遇到过这个问题,每个人都同意我们不能添加新的 GOTO 来将 2000 行跳转到随机部分,但不断让 Anaylsts 坚持只做一次并让管理层批准?

tldr;

如何解决开发人员被迫(被迫)不断添加 GOTO 语句(通过添加,我的意思是添加以跳转到多行之外的随机部分)的问题,因为它“更快地获得了该功能”?

我开始担心我们可能会因此而失去有价值的开发人员给猛龙队......

学分:XKCD

澄清:

here

alsoThere:不,我说的是那种将 1000 行从一个子例程跳到另一个子例程中途进入 while 循环的 goto。 somewhereClose

there:我什至没有谈论您可以合理地阅读并确定程序在做什么的那种 goto。 alsoThere

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

here:在这个问题中,我不是在谈论偶尔可以使用 goto。去there

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

elsewhere:如果每次触碰程序都需要花费数周时间来破译程序在做什么,那么您的代码库就存在严重问题。hell:事实上,如果不是最新的 goto 4版本的规范goto goto,我实际上是由我自己决定的detail pointlessReturn: tacoBell

Jail:实际上,只是一个小小的更新,一个小小的胜利。我花了 4 个小时一次重构这个特定程序的一部分,一个标签,每次迭代都保存在 svn 中。每一步(大约 20 步)都很小、合乎逻辑,而且很容易通过某种奇怪的意大利面肉丸磁力自发地跳出你的饭菜,进入你的屏幕 Goto合理地验证它不应该引入任何逻辑更改。使用这个新的更具可读性的版本,我已经与分析师坐下来,现在完成了几乎所有的更改。bypass nextpoint: elseWhere bypass: end

4:第一个 *如果第一次在这里 goto hell,没有第二个如果第一次在这里 goto hell,没有第三个如果第一次在这里 goto hell第四个现在是最新的 goto hell

end:

4

10 回答 10

28

由于 GOTO 编写不正确而引入了多少错误?他们花了公司多少钱?把问题变成具体的东西,而不是“这感觉很糟糕”。一旦你可以让负责人认识到它是一个问题,就把它变成一个政策,比如“除了简化函数的退出逻辑之外,没有任何新的 GOTOs”,或者“没有任何功能没有新的 GOTOs”具有 100% 的单元测试覆盖率”。随着时间的推移,收紧政策。

于 2010-05-26T04:18:46.190 回答
12

GOTO 不能做出好的代码意大利面,还涉及许多其他因素。这个关于 linux 邮件列表的讨论可以帮助您了解一些事情(来自 Linus Torvalds 的关于使用 goto 的更大图景的评论)。

试图仅仅为了没有 goto 而制定“no goto 政策”从长远来看不会取得任何成果,也不会使您的代码更易于维护。这些变化需要更加微妙,并专注于提高代码的整体质量,考虑使用平台/语言的最佳实践、单元测试覆盖率、静态分析等。

于 2010-05-26T04:19:36.010 回答
4

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

你所拥有的只是一个例子。您对此的立场将决定您将来如何进行开发。我认为你有4个选择:

  1. 接受请求并接受你将永远这样做。

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

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

  4. 辞职。

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

于 2010-05-26T04:22:12.853 回答
4

也许你可以使用童子军模式:让这个地方比你找到的地方干净一点。因此,对于每个功能请求:不要引入新的 goto,而是删除一个。

这不会花费太多时间进行改进,会花更多时间来查找新引入的错误。如果您从零件中删除 goto 可能不会花费太多额外的时间,尽管这需要花时间理解并引入新功能。

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

于 2010-06-03T11:50:27.833 回答
3

回到原则:

  • 它可读吗?
  • 它有效吗?
  • 是否可维护?
于 2010-05-26T07:23:38.320 回答
3

这是经典的“管理”与“技术人员”的冲突。

尽管在“技术”团队中,多年来我已经坚定地解决了这场辩论的“管理”方面。

有许多的原因:

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

  2. 如果它是一团糟,那么如果您要进行完全重写,或者如果您正在对程序进行技术重构,那么提取您需要的业务规则将是一件非常痛苦的事情,您将永远无法确定重构程序的行为是“正确的”,即它与旧程序完全一样。

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

  4. 风险——重写和重构很难做到正确,需要对重构的代码进行广泛的测试,而且对于客户而言,看起来像“错误”的东西可能是“特性”。“改进”遗留代码的一个特殊问题是业务用户可能已经建立了依赖于存在错误的解决方法,或者利用错误的存在来更改业务过程而无需通知 IT 部门。

因此,总而言之,管理层面临着一个决定——“添加一个小 goto”测试更改并以双倍的速度将其投入生产,风险很小——或者——进行重大的编程工作并让业务尖叫当一组新的错误出现时。

如果你真的决定在五年内重构,那么一些鼻涕虫的大学毕业生会抱怨你重构的程序不再符合流行语,并要求允许他花数周时间重写它。

如果没坏就不要修了!

PS:即使乔尔也认为这是一个坏主意:你不应该做的事情

更新!-

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

基本问题是你对客户说“我想花 n 周的时间来开发这个程序,如果一切顺利,它会完全按照现在的方式进行。” - 至少可以说这是一个很难卖的东西。

您需要收集有关崩溃和中断次数的长期数据,分析和编程看似很小的更改所花费的时间,由于太难而未完成的更改请求的数量,由于系统无法快速更改而丢失的业务操作足够。还收集一些关于维护结构良好的程序与让它沉没成本的学术数据。

除非你有一个不漏水的案例要提交给 beancounter,否则你不会得到预算。你真的必须把它卖给企业管理层,而不是你的直属上司。

于 2010-05-31T02:05:46.863 回答
1

我最近不得不编写一些本身不是遗留代码的代码,但是以前的开发人员的习惯确实如此,因此 GOTO 无处不在。我不喜欢 GOTO 的;他们把事情搞得一团糟,让调试成为一场噩梦。更糟糕的是,用普通代码替换它们并不总是那么简单。

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

于 2010-05-26T04:20:42.827 回答
1

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

您没有具有宏功能的编辑器吗?你没有shell脚本吗?这些年来,我进行了大量的重构,其中很少有重构浏览器。

于 2010-07-18T20:10:18.897 回答
1

这里的根本问题似乎是您有“分析员”,他们在向某些代码添加 goto 方面描述了可能是必要的功能更改。然后你有“程序员”,他们的工作似乎仅限于输入该更改然后抱怨它。

为了有所不同,这些人之间功能失调的职责分配需要改变。拆分工作有很多不同的方法:经典的传统方法(很可能是您工作中的官方政策,但被忽略了)是让分析师编写独立于实现的规范文档,程序员将其实现为尽可能可维护。

这种理论方法的问题在于,在许多常见情况下,它实际上是不切实际的。特别是,“正确”地做这件事需要被视为初级员工的员工赢得与更资深、在办公室有更好社交关系、更精通业务的同事的争论。如果参数 'goto 不是独立于实现的,所以作为分析师,你根本不能说那个词'不会在你的工作区飞行,那么大概就是这种情况。

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

  1. 分析师编写面向客户的代码,开发人员编写基础设施。
  2. 分析师编写可执行规范,用作单元测试的参考实现。
  3. 开发人员创建了一种领域特定的语言,分析师使用该语言进行编程。
  4. 你放弃了一个和另一个之间的区别,只有一个混合体。
于 2010-07-18T20:54:05.133 回答
-1

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

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

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

于 2010-05-26T05:53:44.553 回答