废墟的召唤

thinker
2020-01-27 看过

废墟的召唤

代代层累并不是历史。废墟是毁灭,是葬送,是诀别,是选择。时间的力量,理应在大地上留下痕迹,岁月的巨轮,理应在车道间辗碎凹凸。没有废墟就无所谓昨天,没有昨天就无所谓今天和明天。废墟是课本,让我们把一门地理读成历史;废墟是过程,人生就是从旧的废墟出发,走向新的废墟。营造之初就想到它今后的凋零,因此废墟是归宿,更新的营造以废墟为基地,因此废墟是起点。废墟是进化的长链。

除了代码,还有环境。有一个项目直到我离开都不知道如何在本地开发环境搭建好完整的系统,而隔壁的团队戏称他们的系统环境搭建需要至少3年工作经验

从建立度量代码的基础设施入手探索了重新改造遗留软件的切入点。围绕重构从代码级别、模块级别到架构,给出了逐步改善遗留软件的方法。改善项目的基础实施及工作流程

代码变成遗留资产的原因

1、大多数原因与人有关而非技术。

2、如果人们彼此之间没有足够的沟通,当他们离开组织时,有关代码的信息就可能会丢失。

3、如果开发人员、管理者和组织作为一个整体,并没有正确地划分他们工作的优先级,那么技术债务会累积到不可持续的水平,开发的速度几乎会下降为零。

重点关注信息随时间流失的问题

技术和工具:

Jenkins、FindBugs、PMD、Kibana、Gradle、Vagrant、Ansible、Fabric

第一部分 开始

第1章 了解遗留项目中的挑战

项目:

1、构建工具和脚本

2、对其他系统的依赖

3、运行软件的基础设施

4、项目文档

5、沟通方式

遗留项目的特征

1、老旧

2、庞大

3、继承而来

4、文档不完善

在2012年,Covertiy公司在Linux内核上运行了静态分析扫描,发现它的缺陷率是0.66缺陷/千行代码,低于许多同等规模的商业项目。

Linux公开和坦诚沟通的文化。任何对Linux的修改都会被全面地评审,这增进了开发人员彼此之间的信息共享,而Linus Torvalds特有的独裁式沟通方式,让所有参加这个项目的人都能明确了解他的意图

遗留代码

1、没有测试和无法测试的代码

由于软件项目的技术文档通常是不存在的或者不可靠的,所以测试往往就成了我们寻找关于系统行为和设计假设的线索的最好地方。一组好的测试套件可以作为项目事实上的文档

测试甚至比文档还有用,因为它们更有可能和系统实际的行为保持同步。

2、不灵活的代码

遗留代码的另一个常见问题是,实现新功能或者修改现有的行为会非常困难。

3、被技术债务拖累的代码

每个临时的或者取巧的解决方案都会降低项目的整体质量,让将来的工作变得更加困难。如果这样的代码累积得过多,最终项目的进度也会陷入停滞。

遗留基础设施

1、开发环境

从最初从版本控制系统中检出代码,到达到下面列出的状态,你大概花了多长时间?

可以在IDE中查看和编辑代码

可以运行单元测试和集成测试

可以在本地机器上运行应用程序

搭建遗留项目经常涉及如下事项:

下载、安装和学习那些项目中使用的晦涩难懂的构建工具

运行那些在项目/bin文件夹里无人维护的神秘脚本

执行那些写在总是过期的wiki页面上的大量手工步骤

2、过时的依赖

外部依赖改变的速度是我们无法控制的。跟上所有依赖的最新版本需要不断的努力。升级常常会提供性能改善和bug修复,有时还包含一些关键的安全补丁

3、异构环境

升级从生产环境向回流

在不同的环境中使用不同的工具

特殊的变更

遗留文化

害怕变化

知识仓库

在编写和维护软件时,开发人员遇到的最大问题往往是知识的缺乏,这可能包括:

用户需求和软件功能规范相关的领域信息

关于软件的设计、架构和内部的项目特定的技术信息

通用的技术知识、如高效算法、高级语言特性、方便的编码技巧和有用的类库

缺乏面对面沟通

代码是我的

忙碌的面孔

第2章 找到起点

对代码的恐惧往往是因为对未知的恐惧

该应用程序有多个组件,具体如下:

1、核心组件实现了复杂的业务逻辑,并包含多个工具类。

2、用户界面组件为员工提供了一个记录他们工作时间的Web界面。它还为管理者提供了构建和下载员工时间花费报告的功能。在技术上,它是一个基于Struts的遗留本地化Web框架构建的。

3、批处理组件包含了多个夜间批处理任务,用来将数据插入到工资单系统的数据库。

4、审计组件收集和处理夜间批处理任务输出的日志,以便生成符合年度税务审计的合规报告。

克服对未知恐惧的最好方法很简单,即需要深入到代码中并开始使用它

尝试重命名方法,在两个类之间移动方法,引入新的接口,添加注释——基本上可以尝试任何你想到的让代码更整洁可读的工作。这个过程成为探索性重构

1、探索性重构的好处

探索性重构增加了你对代码的理解。你探索得越多,就越了解代码

增加对代码库的理解是探索性重构的主要目的,如果你让更多的开发人员参与其中,效果会更好。

探索性重构提高了代码的可读性。

注意:探索性重构的目的不是在架构层面实现深层革命性的更改。但它至少应该在单个类和方法的层次上,对提高代码的可读性有显著的改进

2、帮助唾手可得

版本控制系统

IDE

编译器

其他开人员

3、特征测试

作为探索性重构的补充,你还可以尝试增加特征测试。

收集软件的有用数据

1、开始时代码是什么状态?它是否真的如你想象的那么糟糕?

2、在任何给定的时间,你的下一个重构目标是什么?

3、你的重构有多少进展?你对代码质量的改善速度足以跟上新更改引入的熵吗?

bug和编码标准违例

对于Java代码,该领域的3个大型工具是FindBugs、PMD和Checkstyle

对常见的任务计时

1、从头开始搭建开发环境的时间

2、发布或部署项目所花的时间

3、修复一个bug的平均时间

用Jenkins进行持续审查

持续集成和持续审查

用Jenkins自动化的事情

1、运行单元测试

2、使用Selenium执行端到端UI测试

3、生成文档

4、将软件部署到预生产环境

5、将包发布到Maven仓库

6、运行复杂的多级性能测试

7、构建和发布自动生成的API客户端

第二部分 通过重构改善代码库

第3章 重构准备

只有你能证明它能为企业提供长期的价值时,才应对它进行重构。

应该重构还是应该重写?如果只是重构,能真正地将软件的质量提高到一个可接受的水平吗?或者这个代码到目前为止,全新重写是更明智的选择?这是你和你的团队最终必须自己回答的一个问题。我会尽力提供指导,帮你做出决定

达成团队共识

传统主义者

1、结对编程

2、解释技术债务

反对传统主义者

1、代码评审

2、自动化测试

3、结对编程

4、划定代码区域

选择重构的目标

价值、难度和风险

价值是用来衡量重构对团队多有用以及间接地对整个组织多有用的度量。

难度是用来衡量进行一个指定重构任务的难易程度的度量。

风险通常取决于依赖这段要重构代码的其他代码的数量

决策时间:重构还是重写

在你承诺用自己的解决方案解决一个问题之前,请记住,你编写的每行代码都需要被维护很多年。请确保你彻底研究了用第三方的解决方案(商业的或开源的)来替换内部软件的可行性

重写会有很多缺点:(我相信完全重写几乎一定是个坏主意)

1、风险

重写遗留系统是一个重大的软件开发项目。根据原始系统的大小,这可能需要几个月甚至几年才能完成。所有这么大规模的开发项目都有一定风险的。任何事情都可能出错。

bug的数量可能会多到让人无法接受的程度。

即使软件稳定并且没有bug,它的功能可能也跟用户想要的不一致。

项目可能需要比原计划更长的时间来完成,导致其超出预算。

有可能项目进行到一半,你才发现这个架构基本上是不可行的,并最终放弃你到目前为止写的所有代码。

更糟糕的情况是,可能直到向用户发布软件,你都没意识到这些架构上的问题,并最终发现它在负载下是完全不稳定的。

2、开销

构建文件、日志工具、数据库访问代码、帮助读取配置文件的实用程序,以及许多其他的细节,当你在一个已经成熟的项目上工作时,是从来不会真正注意到这些事情的。

一个新的服务的运营成本是持续的,而不仅仅是项目开始时的一次性投入。从长远来看,至少在你完全关闭旧系统之前,你都会有一个额外的系统要维护、监控并保持它顺利运行。

3、任务总是超出预期时间

估计软件项目的规模是非常困难的,而且项目越大越困难。

4、绿地不会常青

从头重写的好处

1、自由

2、可测试性

重写的必要条件

鉴于前面的利弊,并基于个人经验,我强烈建议把重构当作默认的方式。开始一个新项目带来的大量的风险和开销往往超过它能带来的潜在的好处。但是总有某个时候——单独使用重构无法拯救代码库,这时重写就成了唯一的选择。我认为在考虑重写时,必须同时满足两个必要的条件。

1、尝试过重构并且失败了

2、编程范型的转变

第三种方式:增量重写

第4章 重构

有纪律的重构

1、避免麦克白的悲剧

2、把重构和其他的工作分开

3、依靠IDE

4、依靠版本控制系统

5、Mikado方法

The Mikado Method

重构与模式》《Principle-Based Refactoring

第5章 重搭架构

不要太在意重构和重搭架构之间的区别。它们就像一枚硬币的两面。重构和重搭架构的重点都是更好地改变软件的内部结构,而不影响其外部可见的功能

重搭架构是比方法和类更高级别的重构

1、通过模块化内建质量

2、良好的设计保障可维护性

3、通过独立达到自治

单体应用程序分解为模块

1、定义模块和接口

2、构建脚本和依赖管理

需要一个依赖管理工具,以便明确每个模块对其他模块和第三方库的依赖关系。

apache ivy

第6章 大规模重写

项目的目标是什么

1、黑盒式重写

2、温习式重写

3、补偿式重写

第7章 开发环境的自动化

几乎所有的软件对周围的环境都有一些依赖

0 有用
0 没用

查看更多豆瓣高分好书

评论 0条

添加回应

推荐遗留系统重建实战的豆列

了解更多图书信息

豆瓣
免费下载 iOS / Android 版客户端