Table of Contents
在维护和改进工程系统时,各组织往往面临一个关键的决定:它们应该重新构建或完全改写现有组成部分? 了解每一种方法的不同、优缺点对于做出与项目目标和资源限制相一致的知情选择至关重要。 本条为权衡提供了全面的框架,利用现实世界的例子和专家的见解指导你的决定。
理解重构
重构涉及在不改变现有系统核心功能的情况下,对其进行渐进改进。它旨在在保持系统行为的同时,提高代码质量、可读性和维护性。 这种方法往往被用于减少技术债务,为未来发展系统做准备。重构不是要增加功能;而是要改善代码的内部结构,以便未来的修改变得更加容易、更安全和更快。
递增改进和代码
重构通常针对“代码嗅觉”目标 — — 表面指标通常与系统中更深层的问题相对应。例如,重复代码、长的方法、大类和过度的耦合。通过系统地消除这些嗅觉,团队可以使代码库更加模块化和可测试性。静态分析器和IDE重构功能(如重构、提取方法、拉动)等工具可以帮助实现许多这些变换的自动化。
何时重构
重构效果最好,当现有系统结构上仍然健全,但积累了中等技术债务时,重构效果也合适,当业务逻辑复杂且被很好地理解时,因为重构有可能失去来之不易的域知识. 练习连续重构的团队会发现代码库仍然健康,对大重写的需求减少. 重构风险较小,因为您可以通过测试和小部署来渐进验证正确性.
理解重写
另一方面,重写涉及从头开始开发新系统或对现有系统进行实质性的检修。这种方法通常是在当前系统过时、过于复杂或不再满足业务需求时选择的。重写可以提供一个新的开端,从而可以实施现代建筑和技术。然而,它也意味着放弃旧代码中埋藏的多年的bug修正、优化和机构知识。
绿地对布朗菲尔德重写
绿地重写开始于空白板块,在全新的环境中构建系统。这经常发生在原始平台过时(例如从Cobol迁移到Java)或系统必须完全重装可扩展性时。棕地重写将部分现有系统逐步替换,同时让其他系统运行起来——有时被称为“硬体无花样模式 ” 。 这种混合方式允许分阶段迁移,从而减少风险。
何时重写
当当前系统已经达到重构成本高于重建的地步时,重写是正当的. 指标包括:代码库是无法测试的,架构阻止了必要的改变(例如无法水平缩放),或者技术堆栈不再被支持. 另一种情况是,商业模式发生了如此巨大的变化,以至于遗留系统无法在不完全重建的情况下进行改造. 重写也可以是策略性动作,通过采用微服务或无服务器等新模式来获得竞争优势.
风险和费用比较
这两种方法都具有不同的风险概况和费用结构,了解这些帮助各小组根据组织风险承受能力和预算周期调整其选择。
风险因素
重构风险:[] 最大的风险是重构永远不会完成——它成为系统根本问题持续存在的同时小改进的无尽循环,另一个风险是"重构疲劳",即团队因为进度缓慢且对利害关系方来说是看不见而失去动力,然而重构通常具有较低的平移风险,因为每次修改都是小而可逆的.
重写风险: 最著名的警告来自Joel Spolsky的文章"Thes You Should Never Do, Part I",他在那里辩称重写往往导致一个故障,特征差的替换年限晚些年. 重写引入了调度风险(新系统可能比预期的要长),知识风险(翻译中丢失的商业规则),以及集成风险(数据迁移和与其他系统的互操作性).
成本分析
重构成本随时间推移而分散。 软件工程研究所的一项研究发现,在发布后修复缺陷比设计期间修复成本高出10-100x,但重构成本通过提高代码清晰度而及早发现许多缺陷。 重构需要大量的前期投资:你需要重新分析、重新设计、重编码和重新测试所有东西。 重构成本通常超过重构3-5年的全程成本,除非遗留系统真的无法维护。 然而,重构成本一旦部署,就可以降低运行成本(比如云基础设施、许可证)。
工程领导人决定框架
重构和重写之间的选择取决于各种因素,如系统复杂度、业务重点、可用资源和长期目标。 以下决定框架可以帮助评估您的具体情况。
系统健康评估
使用诸如环形复杂度、代码覆盖度、耦合度和缺陷密度等度量对代码库进行系统分析。 SonarQube 或 CodeClimate 等工具可以提供客观数据。 如果系统在可维护性上得分差,但业务逻辑稳定,则重构可能就足够了。 如果架构存在根本缺陷(例如,无法模块化的单立面),则可能需要重写。
业务目标对齐
将技术决定映射到商业成果中。 如果目标是在下一季度内加快特性的交付,那么重构通常会更安全。 如果目标是进入一个需要完全不同性能或缩放特性的新市场,那么重构就是合理的。 让产品所有人和利益攸关方参与澄清“原因 ” 。 例如,启动者可能选择重构为快速地支点,而拥有关键遗留系统的企业可能倾向于递增重构以避免故障时间。
团队能力和机构知识
重构很大程度上依赖于对现有系统的理解。 如果原始作者还在团队中, 重构效率更高。 如果代码库是一个黑匣子, 文件很少, 重写可能会显得诱人 。 但是它有重写过去错误的风险 。 在这种情况下, 考虑“ 重写并保存 ” : 平行构建新系统, 但通过仔细阅读和自动测试从旧代码中提取商业规则, 然后再丢弃旧系统 。
现实世界实例
审查其他组织如何选择这一选择,可以提供实际的见解。
示例: Basecamp 重构“嘿”
在开发电子邮件服务Hey时, Basecamp 的团队选择了重构现有的 Rails 代码库而不是从零重写。 他们系统地将域逻辑提取到服务对象, 提高测试覆盖范围, 并消除死代码。 这样他们就可以按时运送产品, 同时保持代码库的维护。 [[FLT: 0] 团队记录了他们的方法[[FLT: 1], 强调了渐进改进是保持他们对电子邮件处理的深刻理解的关键 。
示例: 新鲜书本重写
FreshBooks,一家会计软件公司,著名的是将整个平台从单体PHP应用重置为现代的可扩展系统. 这一决定是在经过多年的磨难后做出的,而再造也无法解决的性能和建筑限制. 重写花了两年多时间,花费了数千万美元,但能够让他们为更大的客户服务,降低支助费用. 首席执行官指出重写是"我们做过的最难的事",但企业必须生存下来. ir 死后强调商业视野和技术架构的一致的重要性.
实例:马丁·福勒的重建社区
开创性书的作者马丁·福勒(Martin Fowler) 重构:改进现有代码的设计[,长期以来一直主张重构重构,而不是重写,他主张如果团队投资自动测试和连续集成,大多数系统都可以逐步改进. His 重构目录[提供了任何团队都可以应用的证明模式. 福勒的观点是重构应该是最后的手段,而不是第一本能.
结论:作出正确的选择
重构和重写在工程系统管理中都有其位置。 对具体情况的仔细评估将指导各组织实现最有效的战略,平衡风险、成本和未来准备状态。 正确的路径往往涉及一个组合:重构可修复部分,并只重写那些无法修复的部分。 使用这里概述的框架来评估您的代码库的健康,与业务目标保持一致,以及利用团队知识。 通过做出明智的选择,你能够引导你的组织走向更强健、高效和适应性强的系统,支持增长,而不会落入过早重构或无休止的重构的陷阱。