Stack Overflow创始人乔尔·斯波尔斯基发表了一篇著名的文章。他的观点是永远不要从头重写一段代码。他举网景为例。他们花了很多年重写软件,公司在重写过程中倒闭了。然而,作者选择从头重写应用程序。原因是什么?

作者|尼古拉斯·蒂茨-索科尔斯基

翻译|月亮,编辑|闫妍

标题| CSDN从VCG下载

由| csdn制作

以下是翻译:

大约一年前,我重读了这篇文章,但我还是选择从头重写我们的应用程序。在本文中,我将简要介绍事件的过程、成功重写代码的过程以及从中吸取的教训。

事情发生在2019年1月,当时Remash还是个小公司。我们雇佣了几个工程师,其中5个负责产品,还有一些工程师负责机器学习或者开发运维。虽然雇佣了很多工程师,但我们的开发速度仍然很慢。即使是简单的函数,添加起来也需要很长时间。我们的产品有很多bug,我们只能标为“已知”,无法修复。而且整个产品好像很久没有新的改进了。

理解为什么会出现这些问题很重要。我们假设这些问题都不是人事问题,我们雇佣的是厉害的工程师。问题主要在于代码和流程。老代码很差,因为我们以前的技术实力不高,解决问题的方式也不好;而我们的过程会鼓励和依赖孤岛的知识,因为我们没有真正的“满栈”。

2019年1月的代码状态

旧应用程序的设计目的与现在的有很大不同。最初,Remesh的目的是在两个群体或个人和群体之间建立双向对话。比如你可以让民主党人和共和党人互相交谈,了解对方的观点,求同存异。或者,市场可以与公众交谈,了解公众的需求和意见。然而,在调查了产品和市场之间的契合度之后,我们改变了用例。我们开始专注于一个人和一群人的对话。

由于这种变化,一些旧的设计决策不再适用,数据库结构需要进行很大的改变。除了数据库的问题,代码本身也很难理解,因为增加了新的功能,但是没有进行重大的重构。在最需要重构的地方,测试覆盖率非常低,因为那些是最老的代码,是在我们建立好的测试实践之前编写的。

除了这些,语言和框架都不适合团队。后台代码用的是仙丹,只有少数工程师懂。其中一个前端代码完全是用旧版Angular写的,我们还有另外两个前端,用的是React。我们几乎没有能掌握一门技术的工程师,更不用说三门了。语言和框架不适合我们的团队和要解决的问题,很大程度上影响了我们的开发速度。

有哪些选择?

当时我们就知道代码需要大改。当面对大量棘手的代码时,您只有三个选择:

重构,直到问题解决

一次性重写

一点改写

重构对于前端是不可行的。Angular的版本太老了,连升级到现代Angular的合理方法都找不到。由于我们的UI和API发生了重大变化,重构不可行。所以对于前端来说,我们的选择只能是一次性重写,或者稍微重写。

后端有几个问题是我们想要解决的:数据库结构、语言、不再能解决问题的代码。我们之所以使用酏是因为它强大的并发支持,但是我们根本不使用并发,所以它只会带来痛苦——因为它在Erlang VM中处理并发的方式,性能测试非常困难,你只能看到你做了什么,而不能看到你在哪里调用它。所以性能优化只能是一个机会。酏的代码也限制了机器学习工程师对后台代码的贡献,因为他们日常使用Python,没有时间深入研究酏。长话短说,我们希望抛弃酏,完全迁移到Python,这样整个团队都可以出力,语言可以支持所有问题,性能测试更容易。

我们还有一些“产品债”,来源于一些用户接受但不理想的概念。这些是有限范围内的最佳解决方案。如果我们能打破这个限制,选择最好的方法,我们可能一步到位。摆脱这些不良观念,需要一次性做很多事情。

最后,我们选择重写是因为以下因素:

我们希望团队的每一个成员都能为后端贡献代码,所以最适合的语言是Python,它易学易用,在团队内部有广泛的接受度。

旧代码太不稳定,测试不全面,重构风险很大。

采用一个观点很强的框架可以获得效率,节省很多时间。

我们有机会根据从客户那里收集的信息制作一个全新的版本,而不必让每个客户都经历许多小的变化。这样客户培训就容易了,销售团队只需要努力一次,而不是一直给客户灌输新观念。

为了做出这个决定,我们制定了一个非常详细的计划。虽然现在人们都在谈论敏捷开发,但是我们在这个问题上采用了瀑布法,不仅仅是因为我们想用瀑布法来实现,更是因为我们想搞清楚每个方案的成本是多少。显然,一次重写整个应用程序需要很多时间,但是重构或重写一点点需要更多的时间,并且具有更大的不确定性。选择重构的风险要大得多。

最后,我们对这个决定非常有信心,并说服了公司的每个人。我们决定重写它,因为这样做可以纠正多年的错误,同时使产品向前迈出一大步。

所以,让我们开始重写。

进展情况

在确定需要包含哪些功能后,我们将从2019年2月开始重写。所以我们的计划非常周密,尤其是在需要做什么方面。这个计划并不敏捷,但是制定一个好的计划可以帮助我们继续朝着正确的方向前进。因为我们在用户测试阶段就偏离了方向,而且从那以后越来越偏离。

经过一个粗略的起步,新版本的实际建设过程非常顺利。换成新技术栈,大家都很痛苦。虽然我们选择了Python供整个团队使用,但还是有一部分人需要学习。而我们的后端或者全栈工程师并不了解Django。前端也差不多。很多人知道React,但是很少有人有Type的经验。尽管如此,经过初期的学习,大家的效率都得到了快速的提高,可以更快的一起学习。这是第一次验证:即使我们对新技术堆栈没有什么经验,我们也可以以比以前快得多的速度构建功能。我们花了很长时间才确定这些效率来自新技术堆栈和新代码,而不仅仅是因为一个新项目。

我们做的第一件事就是让大家熟悉数据库。因为目标之一是减少技术孤岛,让工程师在整个技术栈中感到舒服,所以我们带领不熟悉数据库的前端工程师思考数据库,设计数据库的结构,然后和整个团队迭代。所以整个团队都会考虑数据库。即使他们在一段时间内不处理数据库问题,他们也有能力处理数据库,可以提出有价值的问题。

之后的几个月,我们以飞快的速度工作,在旧版本中重写自己喜欢的特性,并进行改进。我们在合理的时间内建立了一个非常好的项目。一开始我们很看好时间计划,可以一步一步的完成工作,直到六月份。这时候我们不断的添加和修改函数,因为我们知道没有这些修改,新版本是不会成功的。这让我们慢了下来,但根据我们的研究人员、客户团队和一些值得信赖的客户提供的信息,这样做是值得的。

完成这一切后,我们取得了一些非常值得骄傲的成就,这些成就不完全是技术成就:

我们大大扩展了我们的团队。起初,产品团队只有四名工程师,但现在有九名,这不包括一个全职的QA/SDET团队、一个机器学习工程师团队和几名开发和操作人员。在这种增长中,我们不仅避免了通常项目中人力增加造成的延误,甚至提高了速度。我觉得主要是因为是新项目。)

我们改变了工程在整个公司中的地位。虽然最初发布一些新功能的速度慢了下来,但是人们看到我们可以很快重写现有的功能,看到新功能仍然可以很快添加。有一次我们实时演示了Django Admin添加的一个功能,告诉大家我们的速度比以前快了。虽然是小示范,但是很有效。

我们已经从一个有几个服务的面向服务的体系结构转变为只有一个服务的单一服务体系结构,我们可以开始设计容错和横向扩展。这曾经是一件很痛苦的事情。

我们大大提高了迭代的速度,很大程度上是因为新的架构可以很好地适应我们的问题,现在每个人都可以轻松地做出贡献。最棒的是,机器学习团队可以偶尔向真实的产品背景贡献代码。

经验教训

我们认为成功有几个原因。此外,我们从几个非常重要的错误中吸取了一些教训。

我们成功的原因之一是我们对要构建什么有清晰的愿景,我们根据需要缩小了范围,以确保愿景的清晰。虽然我们没有按时发货,事实上也没有人守时,但是我们并没有像网景那样拖延那么久。整个项目用不到原来两倍的时间搭建一个功能和老产品一样的产品,但是我们得到了更好的东西和很多期待已久的功能,比如上传发送视频,下载自动生成PowerPoint报表等。

成功的另一个原因是尽可能早、尽可能频繁地获得反馈。在重写过程中,我们经常在内部使用产品来发现主要错误和性能问题。我们经常给全公司做演示,从客户团队、销售、研究、前期试用客户那里得到反馈。

那么,我们犯了哪些错误呢?我们决定采用两种以前没有用过的技术。我们以前在原型中使用过Type,但是没有太多经验。当时用的还不错,但是没有完全掌握它可以提高生产力,降低出错概率。时间会证明的,我觉得静态类型还是对的。另一个错误是使用GraphQL。我们在REST和Redux上有很多经验,但是在原型上只用过GraphQL。现在回过头来看,用GraphQL,初期的原型阶段非常快,但是需要付出长期的代价,因为我们无法与阿波罗中的一些关键决策进行沟通,也没有任何在后端调方敏的经验。我只能说一两个月很有挑战性,我再也不想尝试了。我们正在逐步摆脱GraphQL,一方面是为了提高性能,另一方面是为了让代码更好地承受慢速请求。

重写最后要提到的是,团队的士气会受到很大的影响,所以你需要主动去处理。每个人在开始一个新项目的时候兴趣都很高,但是在构建了一些现有的功能,修复了一些bug之后,士气就会逐渐下降。从构建现有功能到探索新功能,大家都很积极,但是重建现有功能会很让人沮丧。虽然我们已经完成了重建,但部分原因是我们必须在重建的同时探索新的功能,而不是仅仅将旧代码迁移到新的平台上。不过,我们应该可以在这方面取得更好的平衡。如果还有时间,我会重点保证一些值得信赖的客户参与早期的内部测试,得到反馈和鼓励,让大家都有动力去重建。我也会确保我们可以在前期开发一些新的功能,而不是让旧的功能拖累大家。有些无聊是不可避免的,但我们可以尽力减轻它。

应该重写吗?

根据我的经验,如果你认为重写是错误的,那么我认为你不应该重写。无论如何,你都应该默认选择“否”,然后尽力判断重写是否真的有必要。

如果出现以下情况,可能需要重写:

如果您的体系结构或数据库结构严重不符合您的需求,并且因为体系结构不断更新或修改数据库结构非常困难,就没有明确的迁移路线

如果这些问题严重降低了团队的速度

如果现在的技术栈在团队的贡献上非常有限,很难训练团队学习技术栈,

即使满足以上所有条件,也要考虑目前的业务情况,重写是否适合自己的团队和公司。

除了以上几点,可能还有其他因素需要考虑。这很难判断,但我们需要三思而后行。

原始链接:

https://remesh.blog/refactor-vs-rewrite-7b260e80277a

本文是CSDN翻译的文章,转载请注明出处。

1.《网景软件站 Netscape 重构软件倒闭了,但我仍坚定地站重写!》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。

2.《网景软件站 Netscape 重构软件倒闭了,但我仍坚定地站重写!》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/fangchan/1765345.html