Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >接手了严重过时的软件,到底是该逐步重构还是摧毁重写呢?

接手了严重过时的软件,到底是该逐步重构还是摧毁重写呢?

作者头像
深度学习与Python
发布于 2020-10-23 08:23:26
发布于 2020-10-23 08:23:26
4160
举报

作者 | Ben Northrop

译者 | 刘雅梦

策划 | Tina

有一个应用程序充斥着技术债,严重的过时了,或者只是对用户服务不足,因此,我们需要了解我们的最佳选择是什么——是继续艰难地探索并逐步进行重构更有意义,还是把它全部摧毁并从头开始重写更有意义呢?这就是我们将在本文中探讨的基本难题。所以让我们开始吧…...

但是没有那么快!在我们进一步研究之前,需要解决一个大家“避而不谈”的问题,即:对于任何需要改进的遗留应用程序,下一步要做什么并不是一个这样或那样就可以了的简单决定。 我们通常会将我们的选项框定为重写或重构,但这些术语,正如我们将要看到的那样,实际上只是摆在我们面前的一系列选项的替代品。

通过重构,在现代化遗留应用程序的场景中,通常意味着我们将会保持应用程序基本不变,但会进行一些微小的内部改进以解决特定的问题(如可维护性、可扩展性等)。另一方面,通过重写,则意味着我们打算“从头开始”,或者换句话说,进行重大的变更。

但这只会引出下一个问题!较小变更(Minor)和重大变更(Major)到底是什么意思?如果我们打算将前端框架从 AngularJS 升级为 React,但保留后端服务不变,这是重构还是重写呢?或者,如果我们想要将一个单体应用拆分成三个不同的微服务,但只是复制粘贴业务逻辑到新的版本控制存储库中,那这是重写、重构还是其他什么呢?我们真的在乎吗?给我们的努力贴上标签真的很重要吗?

是的,确实是。虽然我们的工作是构建可运行的软件,而不是对语义进行哲学思考,但我们使用的词汇确实会产生影响。当我们提议走重写或重构的道路时,业务和技术涉众应该能够准确地理解我们的意思,以及需要付出什么样的努力。换句话说,我们措辞的精确性将有助于我们更好地设定预期。此外,当我们穿过一些概念上的迷雾并找到更清晰的定义时,也会让我们对这个决定有一个更细致的看法,并能使我们脱离狭隘的重写或重构框架。

所以,就像任何一次长途旅行一样,在我们跳上车出发之前,让我们花点时间整理行李。我们不想出现在海滩上才发现自己忘了带泳衣。

1 功能改进

一个好的起点是定义重写和重构不是什么,它们是改进应用程序功能的策略。这种类型的工作,无论是修复缺陷,交付新特性,还是清理用户界面,我们都可以称之为增强。它是关于改进应用程序为用户所做的事情的,正如我们稍后将看到的那样,它是正常的开发状态。

但在某些情况下,功能增强的范围可能相当大。例如,企业可能想要确定某应用程序是为正确的用户群提供服务的,但所有的功能都需要彻底检查。这种情况也可能被称为重写,但是在这里我们要做一个区分。因为这种类型的工作需要构建所有新的功能,所以它与新建项目基本上没有区别。当需要定义新的功能需求时,从零开始开发一个独立的系统,并且不能继承原逻辑或代码,我们会将其视为新开发的应用程序,而不是重写。

2 重构是什么

向应用程序添加功能并不是本文的重点。我们的场景是:应用程序通常会执行预期的操作,但缺少如何执行的能力,换句话说,即缺少系统的非功能或 质量属性。例如,用户可能对这些功能感到满意,但应用程序可能过于难以维护,或者可能频繁崩溃,或者在峰值负载下性能很差。当这些非功能属性缺失时,我们才会考虑重写或重构。

关于重构,我们经常使用这个术语来指代不同的工作范围。Martin Fowler 在他的 《重构》 一书中是这样定义重构:

重构是一种用于重组现有代码主体,在不更改其外部行为的情况下更改其内部结构的规范技术。

从这种纯粹的意义上讲,重构主要是为了使代码更易于维护。这可能是分解冗长的或复杂的函数,修复不一致的命名,添加单元测试,或者重组类的层次结构、数据结构或模式。请注意,没有更改任何对用户可见的内容,但是修改了内部的代码结构,使其更容易为开发人员所使用,从而提高了我们的工作效率(和幸福感!)。

然而,在我们做重写或重构决策的场景中,这个定义过于严格。在我们的场景中,当我们谈论重构时,我们通常不会区分内部和外部,而是 会区分功能和非功能。例如,我们可能会说,我们选择重构现有的代码库,以提高应用程序的可靠性或性能。从技术上讲,这些质量属性不是系统的内部属性(用户可以明显感知到它们,因为它们直接影响用户),它们只是非功能性的。这可能是一个过于学术的区别,但本着精确的精神,我认为有必要指出来。在本文中,我们将使用更广泛的重构定义:

重构是一种方法,通过这种方法对现有的代码主体进行增量重组,以提高系统的质量属性。

最后,需要注意的是重构是关于迭代变更的。它会对应用程序进行细微的调整,将其交付,然后冲洗并重复。在功能增强的基础上,重构可以使我们的用户满意,使我们的代码库保持健康,并能最大限度地减少技术债和功能缺陷。然而,如果被忽略,我们可能需要考虑更重的替代方案。

3 重写是什么

与重构一样,重写也有着相同的基本目标:改善应用程序的非功能性。区别在于更改了多少。简单地说,如果重构是管道胶带,那么重写就是一个大锤或一个反铲。它不是要对现有的功能进行渐进式的改进,而是要摧毁它,重新构建。对应于我们讨论过的其他类型的开发工作,我们可以这样可视化地展示重写:

可以说,重写是一项涉及到 对系统进行重大更改的工作,以便对其质量属性进行根本性的改进。但也有灰色区域。重写工作通常会扩散到其他象限。例如,一个应用程序可能会因为技术债而瘫痪,以至于几乎不可能再添加新特性。我们可能会选择重写然后建立一个新的基础来提高可维护性和可扩展性(质量属性),但是在重写的过程中,我们也可能会加入一些新的特性来满足业务需求。它基本上是重写的,但也进行了一些增强。

同样地,在重写和重构的边界上也存在一些模糊性。在一些“平移”(lift-and-shift)的情况下,系统被迁移到一个新的平台上,使得它在本质上成为了一个不同的应用程序,但其中的代码实现基本相同,即没有重构。这感觉像是重写了,但真的是这样吗?需要做多少更改才能被视为是重写呢?

再次,让我们看看是否可以增加一些精度。在本书中,我们使用以下定义:

重写就是重新构建存在于遗留应用程序中的相同功能,但使用不同的语言 / 框架,在新的代码库(不仅仅是分支)中维护,并作为一个全新的构件进行部署(可能部署到不同的平台上,如服务器、硬件、无服务器、客户端等)。

换句话说,我们要画一些明确的界限。例如,如果我们要重写一个重要的函数、类甚至模块,但是我们的工作是在代码库主线的分支上完成的,那么这就不是重写。同样地,如果我们重新实现了应用程序的一部分,但是系统本身仍作为同一构件(二进制文件、WAR 等)部署,这也不是重写。在我们的场景中,重写是很大的(BIG)。它们是涉及需要构建和部署全新应用程序的重大更改。是的,在实现这一目标的过程中可能会有一些渐进的步骤,我们稍后将会看到,但这是一种与重构根本不同的工作。

为了帮助自己梳理具体的情况,你可以把它画出来。即对于可能现代化或改进应用程序的不同途径,究竟要更改些什么?这里有一个例子:

实际上,变更的性质可能与重写或重构的定义不一致,但这没有关系。例如,上图可能表示了这样一种情况:我们提议使用一组更现代化的技术来重新实现某个服务,但同时保持公开的 API 和底层持久层结构不变。这是一个较小变更和重大变更的混合体,所以应该如何确切地标记它可能仍然不清楚。然而,重要的是,我们已经了解了更深层次的细节,这将有助于我们更好地思考和证明这个决定。

现在我们的准备工作已经差不多完成了,但是在我们开始我们的旅程之前,让我们先把它们放在一起,看看这些不同类型的开发工作是如何适应给定应用程序生命周期的。换言之,让我们探究一下起源故事,以便重写。

4 重写的起源故事

这一切都是从新建开发阶段开始的,在这个阶段我们有了一个想法,并开始从中构建一个功能强大的应用程序。经过数周或数月的不懈努力,某些产品最终被投放到“市场”(可能是实际的付费客户,或只是一组内部业务用户,等等)。如果该应用程序很受欢迎,它将会在一段时间内处于增强的平衡阶段,在此阶段会添加新功能并修复缺陷。每个人都很开心。但最终,技术债会累积起来,我们开始看到努力的回报在递减,虽然在过去一周的开发足以添加一个全新的功能,但现在一周却不足以改变一个按钮的颜色。

在这一点上,我们可能会质疑是否值得投入更多的时间和金钱。此外,自从应用程序首次发布以来,可能已经出现了一些令人兴奋的新技术,我们可能会对如何利用这些技术来使我们的应用程序更具弹性、更易于使用、更具性能等抱有一些宏伟的设想,因此我们开始制定重写计划。其想法是在短时间内冻结现有系统的开发,然后将资源转移到替换系统上。我们将首先构建基础(使用更现代化的模式、工具、语言等等),然后将现有的功能迁移到该基础中。用户只需要安然度过“暂停”(即不需要任何新的更新),但当重写系统就位时,工作效率就会是之前的两倍(或更多!)。

虽然这个计划看起来很直接,但它掩盖了一些关键的风险:技术、组织和心理因素,所有这些因素都会导致重写阶段是极不稳定的。随着这一阶段的拖延,我们成功替换的机会会越来越渺茫。在接下来的文章中,我们将探讨一些隐藏在重写工作中的危险,以及为什么我们总是不顾这些危险勇往直前的原因。

原文链接:

http://www.bennorthrop.com/rewrite-or-refactor-book/chapter-1-what-we-mean-by-rewrite-and-refactor.php


本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-10-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 InfoQ 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
重构单体为微服务
单体应用程序转换为微服务的过程是应用程序现代化的一种形式。这是几十年来开发人员一直在做的事情。因此,在将应用程序重构为微服务时,有一些想法是可以重用的。
用户9184480
2024/12/19
730
重构单体为微服务
马斯克“逼疯”DOGE 团队:限时数月内“闪电式”重构6000万行代码,老程序员和IT专家吓傻了!
马斯克领导的 DOGE 团队正酝酿一场豪赌:他们计划在短短几个月内重写一套运行了数十年的核心代码库。该代码库包含数千万行 COBOL 代码,以及部分汇编语言。按理来说,要安全、完整地重写这些代码,至少需要数年时间,而将这一过程压缩到几个月几乎是不可能完成的任务。
深度学习与Python
2025/04/01
850
马斯克“逼疯”DOGE 团队:限时数月内“闪电式”重构6000万行代码,老程序员和IT专家吓傻了!
Chapter 2 :重构的原则
总而言之:重构的门槛远远没有想象中那么高,重构是对既有代码的修改,也许我们在无意识中就已经做了这样的工作,一方面继续保持良好的编程习惯,另一方面学习更加成体系的重构手法。
Noneplus
2020/01/22
6380
AI生成代码缺失了什么?重构
AI代码生成提速,但GitClear报告揭示重构骤降,代码重复激增!开发者需警惕AI Copilot带来的“生产力陷阱”,避免牺牲代码质量。拥抱AI提效同时,别忘了重构等软件工程基础实践,否则将面临软件危机!
云云众生s
2025/03/16
390
AI生成代码缺失了什么?重构
eBay 改造“2.5 亿次访问”页面:工作效率翻倍、变更成功率飙升
eBay 整合了负责提供“查看商品”页面的服务——该页面每天加载超过 2.5 亿次——去除了重复代码,提高了开发人员的工作效率。结果,他们的团队速度翻了一番,现在甚至可以每天将变更部署到该页面,并且变更失败率降低了许多。
深度学习与Python
2023/09/08
1500
eBay 改造“2.5 亿次访问”页面:工作效率翻倍、变更成功率飙升
老旧系统改造要点
遗留系统的迁移是一个相当复杂的工作,以至于重写的成本甚至比迁移的成本更高。但是从技术维度来看,步骤无非就是:
Phodal
2020/07/02
7680
该如何接手别人遗留下的代码?
在我们开始之前,你应该先了解一些事项。首先,请阅读这篇 Joel Spolsky 的著名文章,了解为什么永远不应该重写代码(https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/)。在这篇文章中,Spolsky 强调了为什么要重构代码库而不是重写代码库。所谓重构,即在不改变行为的情况下对代码质量进行一系列逐步改进的过程。当你尝试修复代码时,同时更改其结构和行为是自寻麻烦。
我就是马云飞
2018/10/25
5940
马斯克被Twitter脆弱的代码“逼疯”,要求全部重写!网友:重构是空降领导了解当前系统最快的方式?
作者|褚杏娟、核子可乐 “从始至终,我们一直都笑呵呵的。” 当地时间周一上午,Twitter 网站又出了新故障。 有 Twitter 用户在登录之后发现了一大堆相互关联的问题。首先是单击链接无法跳转,反而弹出了一条神秘的错误消息,称“您当前的 API 计划不包括对此端点的访问权限”。 “我猜这意味着 Twitter 非常需要现金,它开始收取 Twitter API 访问权限费用,但 Twitter 自己无法支付这笔费用。”普林斯顿计算机科学教授 Arvind Narayanan 发布推文略带调侃地评论
深度学习与Python
2023/03/29
8920
马斯克被Twitter脆弱的代码“逼疯”,要求全部重写!网友:重构是空降领导了解当前系统最快的方式?
将单体应用重构为微服务
微服务重构概述 将单体应用程序转换为微服务的过程是应用程序现代化的一种形式。这是几十年来开发人员一直在做的事情。因此,在将应用程序重构为微服务时,有一些方法可以重用。 一个策略是不推荐“大面积”重写。那就是当您将所有的开发工作集中在从头开始构建新的基于微服务器的应用程序时。虽然听起来很吸引人,但它是非常危险的,可能会以失败告终。 您应该逐步重构单体应用程序,而不是大面积重写。您应该逐渐构建一个由微服务组成的新应用程序,并与您的单体应用程序一起运行。随着时间的推移,单体应用程序实现的功能量会缩小,直到它完全消
用户1263954
2018/01/30
1K0
将单体应用重构为微服务
如何接手别人的系统-遗留系统重建的道法术器势志(万字长文)
成熟的公司会有大量的存量系统,程序员难免接手他人开的的系统。万一不小心接手的系统过于腐烂,祖传代码难以破译,一边吃力不讨好艰难维护老系统,一边在上面做新业务,出了问题要背大锅,一头包,难有好成绩,满身疲惫,终成大冤种。本文尝试探讨如何接手遗留系统的方法论,重建遗留系统的道法术器势志,使得遗留系统跟上组织内系统演进和满足业务需求,逐步从泥沼中走脱。
知码行者
2023/04/03
7520
如何接手别人的系统-遗留系统重建的道法术器势志(万字长文)
重写的六大风险
我们在本文将批判这种基于直觉的认识。你会看到,重写绝非易事。尽管我们不受新应用程序部分挑战的影响,但也会碰到前所未有的全新挑战。为成功地完成重写,我们必须应对这些挑战,因此提前了解有什么风险很有必要。
深度学习与Python
2020/09/23
3130
重写的六大风险
「中文翻译」Vue3 的诞生之路
因时间有限,文中翻译不对的地方还请指出,望海涵。想感受原汁原味还请移步上方链接。致敬尤大!
童欧巴
2020/06/04
6950
技术债是什么、怎么还?你想知道的都在这一篇文章里了!
前两周写了关于技术债务的文章,尽管实践中会堆积技术债,但这个概念并不在我们的工作中频繁出现。这篇文章就系统性讲讲技术债,让大家避免知其然,不知其所以然。
陈哥聊测试
2021/03/12
4.9K0
软件架构:问题起源和应对
在职业的某个阶段,许多开发人员都会面对这样一个挑战:软件架构变得非常复杂,缺乏清晰的组织结构,甚至对最有经验的开发者来说也是一项艰巨的任务。尤其是在加入一家新公司时,这种情况更为常见。你可能会被要求接手一个遗留项目,或者加入一个已经在进行的团队。这时候,最初的反应往往是沮丧。抱怨的声音此起彼伏:代码缺乏测试,需要在多个地方进行修改,甚至连最基本的标准都没有。这些都是经常遇到的问题。
FunTester
2025/01/23
910
软件架构:问题起源和应对
7、重构单体为微服务
本书主要介绍如何使用微服务构建应用程序,这是本书的第七章,也是最后一章。第一章介绍了微服务架构模式,讨论了使用微服务的优点与缺点。随后的章节讨论了微服务架构的方方面面:使用 API ​​网关、进程间通信、服务发现、事件驱动数据管理和部署微服务。在本章中,我们将介绍单体应用迁移到微服务的策略。
Java架构师历程
2018/09/26
5550
7、重构单体为微服务
一文读懂微服务架构的重构策略
你很有可能正在处理大型复杂的单体应用程序,每天开发和部署应用程序的经历都很缓慢而且很痛苦。微服务看起来非常适合你的应用程序,但它也更像是一项遥不可及的必杀技。如何才能走上微服务架构的道路?下面将介绍一些策略,帮你摆脱单体地狱,而无须从头开始重写你的应用程序。
猿天地
2019/05/23
7150
如何用Swift重写C++/ObjC代码库,并将其缩减70%
作者 | Ron Avitzur 译者 | 刘雅梦 策划 | Tina 疫情期间,作者花了 18 月的时间,将图形计算器(Graphing Calculator)从 C++/ObjC 移植到了 Swift 上,将代码量缩减为原来的 30%,并且没有明显的功能或性能损失。 图形计算器(Graphing Calculator)始于 1985 年,是为了 128K Macintosh 用 C 语言编写的,当时它仅有 16 位整数、黑白 Quickdraw 以及不带 MMU、FPU 和 GPU 的 8MH
深度学习与Python
2023/03/29
9250
如何用Swift重写C++/ObjC代码库,并将其缩减70%
解决方案架构师修炼之道
推荐序二 在IT领域里,解决方案架构师的培养成本也是极高的,架构的优劣决定着企业IT的建设和运营成本,架构设计上的漏洞可能会给企业带来巨大的损失。一名优秀的解决方案架构师在成长的道路上,要学习各类IT知识,在项目中摸爬滚打,总结经验教训,从实践中提炼方法论 ---- 推荐序四 我们介入后,围绕发布目标,反向梳理了三大模块工作细节及其配合关系,包括功能性开发与测试、非功能性开发与验证、产品运营与推广等,帮助产品相关的几十人的业务与技术团队就目标形成共识,包括帮助团队明确和调整优先级,舍弃一些不太重要的功能,提
yeedomliu
2021/12/01
2.7K0
解决方案架构师修炼之道
我的20年职业生涯:全是技术债
1992 年,Ward Cunningham 在敏捷宣言中首次提出了“技术债”概念,主要指有意或无意地做了错误的或不理想的技术决策所累积的债务。随后,《重构》一书的作者 Martin Fowler 基于 Cunningham 的比喻,创建了一个“技术债务四象限”,包括:
深度学习与Python
2023/09/08
2700
我的20年职业生涯:全是技术债
尤雨溪自述:打造Vue 3.0背后的故事
在过去的一年中,Vue 团队一直都在开发 Vue.js 的下一个主要版本,我们希望能在今年上半年发布它(本文完成时这项工作尚在进行)。Vue 新版本的理念成型于 2018 年末,当时 Vue 2 的代码库已经有两岁半了。比起通用软件的生命周期来这好像也没那么久,但在这段时期,前端世界已经今昔非比了。
苏南
2020/12/25
8940
推荐阅读
相关推荐
重构单体为微服务
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文