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


重构是一种用于重组现有代码主体 , 在不更改其外部行为的情况下更改其内部结构的规范技术 。从这种纯粹的意义上讲 , 重构主要是为了使代码更易于维护 。 这可能是分解冗长的或复杂的函数 , 修复不一致的命名 , 添加单元测试 , 或者重组类的层次结构、数据结构或模式 。 请注意 , 没有更改任何对用户可见的内容 , 但是修改了内部的代码结构 , 使其更容易为开发人员所使用 , 从而提高了我们的工作效率(和幸福感!) 。
然而 , 在我们做重写或重构决策的场景中 , 这个定义过于严格 。 在我们的场景中 , 当我们谈论重构时 , 我们通常不会区分内部和外部 , 而是会区分功能和非功能 。 例如 , 我们可能会说 , 我们选择重构现有的代码库 , 以提高应用程序的可靠性或性能 。 从技术上讲 , 这些质量属性不是系统的内部属性(用户可以明显感知到它们 , 因为它们直接影响用户) , 它们只是非功能性的 。 这可能是一个过于学术的区别 , 但本着精确的精神 , 我认为有必要指出来 。 在本文中 , 我们将使用更广泛的重构定义:
重构是一种方法 , 通过这种方法对现有的代码主体进行增量重组 , 以提高系统的质量属性 。最后 , 需要注意的是重构是关于迭代变更的 。 它会对应用程序进行细微的调整 , 将其交付 , 然后冲洗并重复 。 在功能增强的基础上 , 重构可以使我们的用户满意 , 使我们的代码库保持健康 , 并能最大限度地减少技术债和功能缺陷 。 然而 , 如果被忽略 , 我们可能需要考虑更重的替代方案 。
3重写是什么 与重构一样 , 重写也有着相同的基本目标:改善应用程序的非功能性 。 区别在于更改了多少 。 简单地说 , 如果重构是管道胶带 , 那么重写就是一个大锤或一个反铲 。 它不是要对现有的功能进行渐进式的改进 , 而是要摧毁它 , 重新构建 。 对应于我们讨论过的其他类型的开发工作 , 我们可以这样可视化地展示重写:
InfoQ|接手了严重过时的软件,到底是该逐步重构还是摧毁重写呢?
本文插图
可以说 , 重写是一项涉及到对系统进行重大更改的工作 , 以便对其质量属性进行根本性的改进 。 但也有灰色区域 。 重写工作通常会扩散到其他象限 。 例如 , 一个应用程序可能会因为技术债而瘫痪 , 以至于几乎不可能再添加新特性 。 我们可能会选择重写然后建立一个新的基础来提高可维护性和可扩展性(质量属性) , 但是在重写的过程中 , 我们也可能会加入一些新的特性来满足业务需求 。 它基本上是重写的 , 但也进行了一些增强 。
同样地 , 在重写和重构的边界上也存在一些模糊性 。 在一些“平移”(lift-and-shift)的情况下 , 系统被迁移到一个新的平台上 , 使得它在本质上成为了一个不同的应用程序 , 但其中的代码实现基本相同 , 即没有重构 。 这感觉像是重写了 , 但真的是这样吗?需要做多少更改才能被视为是重写呢?
再次 , 让我们看看是否可以增加一些精度 。 在本书中 , 我们使用以下定义:
重写就是重新构建存在于遗留应用程序中的相同功能 , 但使用不同的语言 / 框架 , 在新的代码库(不仅仅是分支)中维护 , 并作为一个全新的构件进行部署(可能部署到不同的平台上 , 如服务器、硬件、无服务器、客户端等) 。换句话说 , 我们要画一些明确的界限 。 例如 , 如果我们要重写一个重要的函数、类甚至模块 , 但是我们的工作是在代码库主线的分支上完成的 , 那么这就不是重写 。 同样地 , 如果我们重新实现了应用程序的一部分 , 但是系统本身仍作为同一构件(二进制文件、WAR 等)部署 , 这也不是重写 。 在我们的场景中 , 重写是很大的(BIG) 。 它们是涉及需要构建和部署全新应用程序的重大更改 。 是的 , 在实现这一目标的过程中可能会有一些渐进的步骤 , 我们稍后将会看到 , 但这是一种与重构根本不同的工作 。


推荐阅读