残酷地重构还是舍弃一个?

时间:2020-03-05 18:57:36  来源:igfitidea点击:
Where a new system concept or new technology is used, one has to build a
  system to throw away, for even the best planning is not so omniscient as
  to get it right the first time. Hence plan to throw one away; you will, anyhow.
  
  -- Fred Brooks, The Mythical Man-Month [Emphasis mine]

建立一个扔掉。那就是他们告诉我的。然后他们告诉我我们现在都敏捷了,所以我们应该毫不留情地重构。是什么赋予了?

重构摆脱困境的方式总是更好吗?如果没有,谁能建议一个经验法则来帮助我决定什么时候坚持,什么时候放弃并重新开始?

解决方案

回答

如果我们足够残酷,那么重构的最终结果将与我们从头开始重建时获得的结果非常接近,但是在此过程中我们不会被无法正常工作的系统所困扰。

回答

当我尝试解决新问题或者新功能时,我将进行原型设计。之后,我将根据所学知识对其进行重建。实际上,这听起来很像重构……什么?也许是同一回事?嗯...

回答

如果我们要进行测试驱动的开发,则几乎可以避免任何麻烦地重构自己的方式。我已经在没有多大麻烦的情况下更改了主要的设计决策,并挽救了已有十年历史的代码库。

唯一的例外是当我们发现架构从头到尾完全错误时。例如,如果我们使用线程编写应用程序,但是发现我们想要一堆异步状态机。此时,继续进行并丢弃第一稿。

回答

有一种观点认为,重构是浪费时间。我们只需要从头开始。如果我们保持设计的灵活性,并且意识到我们还不了解所有内容,则无需扔掉任何东西。当然,一个类可能变得多余,但是我们不会丢弃整个系统。

必须具有灵活的设计才能正确重构。没有设计或者没有僵化的设计意味着我们将因为无法重构或者因为持续重构而降低代码库的可维护性而最终丢掉某些东西。很少有人能做到足够细致和严格的纪律,以能够完成长期的次要重构以保持完整性。除非我们有一支全明星球队,否则这种降级会发生!

TL; DR:我们可以摆脱大多数麻烦而重构自己的方式。但是,有时候,我们将无法重构某些设计元素。发生这种情况时,就该重新开始了,尽管希望我们可以重复使用一些已有的组件。

回答

我认为,丢掉某物有时是最好的方法,但可能会造成伤害。我发现行之有效的一件事就是扔掉一个,但是选择合适的技术。

例如,我已经在Ruby on Rails中编写了一个大型代码库,并且在过去2-3年中,RoR取得了很大进步。我还对体系结构中的一些决策进行了修正。因此,我要扔掉一个,然后从头开始构建一个新的。但是,由于我仍在用Ruby和Rails编写代码,因此我仍然可以使用大约70-80%的旧代码。

造成这种情况的主要因素是,Rails迫使我们编写具有业务逻辑和表示层分离的结构良好的代码。第一次我并没有使其完美,但是由于所有内容都已经很好地分离和干燥,因此将代码移植到Rails v2.1,重新设计问题区域并重新编写一些"问题"功能已经成为一个难题。相当无痛的体验。

因此,通过从一开始就选择了一项出色的技术,我已经可以放弃一项技术,但是仍然可以带走70-80%仍然有效的旧技术。

回答

在后来的《神话人月》中,布鲁克斯警告说,他发现如果我们确实打算扔掉1个,最终将扔掉2个!

我个人认为这是在现实生活中发生的;我们将项目的版本1分配给了普通的程序员,因为"我们计划稍后将其丢弃-无论如何,"。我们最终不得不为版本2重写它,但是那个也被扔掉了。我从未见过该公司倒闭的版本3.

我认为,当布鲁克斯说"计划扔掉一个,无论如何,我们都会这么做"的时候,它更像是这样的说法:"尚待发现的错误数量为'n + 1'"。就是说,这是关于墨菲定律的严肃说明,而不是实际建议。从中学到的教训是,原型很有价值,好的写作就是重写,不要害怕放弃不起作用的东西。

但是,它必须归结为一个判断电话,因为正如Joel Spolsky在几篇文章中所谈到的,选择抛弃并重新开始是很诱人的,因为代码比编写更容易阅读,而且编写比维护更有趣,因此即使并非真正最好的选择,我们也总是会从头开始。

回答

早点扔掉,以后重构

对于小型系统来说,扔掉是可以的,但是如果系统的规模很大,那么我们根本就没有资源这样做。

但是,我们可以创建一个小型的试点项目,该项目仅实现实际项目的非常必要的功能。经过一番尝试和错误,学习并扔掉了东西,我们最终获得了坚实的核心,并对实际项目有了更好的理解。然后,通过添加所需的所有功能来扩大项目的规模。但是,一旦到达那里,就无法丢弃核心。仅重构。

回答

不同的情况需要不同的方法。就个人而言,我尽可能地重构为更好的设计。重构所导致的错误少于重写。

但是,即使我们计划丢掉一个,也最好编写一堆验收测试以确保第二版在正确的轨道上。然后,我们可以逐段移植到下一个版本,同时确保从用户的角度来看,功能不会改变。听起来有点像重构,我猜只是有点草率。

回答

《神话人月》的中心点之一是软件开发的难点在于弄清楚该说些什么而不是怎么说。

我最近对此的解释是,我们从初稿中获得的最大价值就是我们以测试形式收集并保留的需求。如果我们小心翼翼地不测试不是系统真正要求的内容,则可以通过各种方式重构自己的方式。

只要我们不必将自己编写到必须开始抛出测试的陷阱中,就可以在不损失大量实际工作的情况下抛出所需数量的代码。

回答

在谈论敏捷时,我们可以同时做这两种事情,但是以一般的方式,我们只会做一些尖峰(原型)来尝试特定的问题,了解它们并能够做出更好的估算。当我们执行简单的尖峰操作时,请扔掉;在对应用程序进行真正的编码时,请进行重构。

亲切的问候

回答

我在这里的一般建议是将现有系统从不良设计重构为具有更好设计的系统。这样可以维护系统并允许随时进行部署。如果我们从头开始,则可能要过一段时间才能部署,或者永远不要部署。

如果我们要谈论的是在没有现有系统的情况下编写一些全新的代码,那么经常可以编写一些代码,但这是个好主意,但是我们可以根据需要将其丢弃,因为它从未被部署并重新启动(使用TDD)。

回答

我认为版本控制系统在这里起着很大的作用。如果我们运行具有容易分支的分布式版本控制系统(git,mercurial,现在这些天),那么我们将能够更轻松地进行原型设计和重构,而同时仍然拥有有效的工作副本。其他任何事情都需要更多的纪律性。

回答

作为该组织的开发经理,我"不允许"编写生产代码。

我(ab)使用该规则敲出了解决一个或者另一个关键点的快速,肮脏的概念验证代码,然后将其检入到源代码管理中,并指向该代码的"适当"开发人员,然后说:"完成,现在就正确地进行。"

这和我们在这里"扔掉"就差不多了,我最多可能要花几个小时才能把它们撞在一起。花时间投入诸如错误处理,边界检查以及所有其他能产生良好代码的位的事情,将浪费时间进行此类工作,但这意味着获得报酬来编写生产代码的人可以将他们的时间花在他们身上。编写产品代码的时间,而在代码审查时间方面没有诸如"这只是原型"之类的借口。

建立一个被扔掉的东西常常被当作借口,因为做得不好。这意味着我们在过程中实际上没有遇到足够多的问题来学习足够的知识以充分利用任何人的时间。正确地做它,只是把它扔掉,更浪费了。

正如几个人先前所说,任何软件中最重要的功能是它附带了。考虑到这一点,我会在任何一天建立"一个让人们付钱的人",而我在重构方面的无情是只允许其中的足够多来获得一个可以正常使用并且可以合理维护的产品。