第一部分 开始
第 01 章 了解遗留项目中的挑战
1.1 遗留项目的定义
任何已经存在的、难以维护或难以扩展的项目都是遗留项目。
项目包括:
- 构建工具和脚本;
- 对其他系统的依赖;
- 运行软件的基础设施;
- 项目文档;
- 沟通方式
这些都有可能埋有地雷。
1.1.1 遗留项目的特性
老旧
系统的初始设计和前维护人员的意图遗失。
庞大
代码量大,隐藏的bug多
继承而来
最初写这些代码的人现在找不到,联系不上。我们只能通过猜的方式来了解它。
文档不完善
谁能保证文档是最新的呢?反正我是不敢。
1.1.2 规则的例外
Linux内核挺牛的,时间长,维护人多,但是它却是可维护的。
代码评审(code review),保证了这一切。
1.2 遗留代码
1.2.1 没有测试和无法测试的代码
如果在设计时没有考虑单元测试的话,那么写出的代码很有可能就是不可测试的。
我曾经带过一个项目,最初团队成员没有考虑单元测试,在为它们编写单元测试时,我们发现测试覆盖率小于10%,为了把测试覆盖率提升到85%,重写了大量的代码。
1.2.2 不灵活的代码
先看代码,下面这段代码是要删除一个Wibble的业务代码。
public void deleteWibble(Wibble wibble) throw NotAuthorizedException {
if (!loggedInUser.isAdmin()){
throw new NotAuthorizedException("Only Admin are Allowd to delete wibbles");
}
}
没有抽象,以后添加一个用户角色就非常难。
1.2.3 被技术债务拖累的代码
技术债务可能会存在并且长期存在。
1.3 遗留基础设施
软件不光只有源代码,其他东西也会产生影响。
1.3.1 开发环境
困难:
- 下载、安装和学习那些项目中使用的晦涩难懂的构建工具
- 运行那些在项目/bin文件夹里无人维护的神秘脚本
- 执行那些写在总是过期的wiki页面上的大量手工步骤
1.3.2 过时的依赖
第三方的依赖不可控,隐藏性问题。
1.3.3 异构环境
多个环境的一致性也是难题。
错误的行为:
- 从生产环境向回“流”
- 在不同的环境中使用不同的工具
- 特殊的变更
1.4 遗留文化
1.4.1 害怕变化
由于缺少关键信息,许多团队认为保持现状是最安全的选择。视变更为纯粹的风险。
1.4.2 知识仓库
导致一个团队缺少沟通的因素:
第 02 章 找到起点
2.1 克服恐惧和沮丧
2.1.1 恐惧
2.1.2 沮丧
2.2 收集软件的有用数据
2.2.1 bug和编码标准违例
2.2.2 性能
2.2.3 错误计数
2.2.4 对常见的任务计时
2.2.5 常用文件
2.2.6 度量可度量的一切
2.3 用FindBugs、PMD和Checkstyle审查代码库
2.3.1 在IDE中运行FindBugs
2.3.2 处理误报
2.3.3 PMD和Checkstyle
2.4 用Jenkins进行持续审查
2.4.1 持续集成和持续审查
2.4.2 安装和设置Jenkins
2.4.3 用Jenkins构建和审查代码
2.4.4 还能用Jenkins做些什么
2.4.5 SonarQube
第二部分 通过重构改善代码库
第 03 章 准备重构
3.1 达成团队共识
3.1.1 传统主义者
3.1.2 反传统主义者
3.1.3 一切都在于沟通
3.2 获得组织的批准
3.2.1 使它变得正式
3.2.2 备用计划:神秘的 20% 计划
3.3 选择重构目标
3.4 决策时间:重构还是重写
3.4.1 不应该重写的情况
3.4.2 从头重写的好处
3.4.3 重写的必要条件
第 04 章 重构
4.1 有纪律的重构
4.1.1 避免麦克白的悲剧
4.1.2 把重构和其他工作分开
4.1.3 依靠 IDE
4.1.4 依靠版本控制系统
4.1.5 Mikado 方法
4.2 常见的遗留代码特征和重构
4.2.1 陈旧代码
4.2.2 有毒的测试
4.2.3 过多的 null
4.2.4 不必要的可变状态
4.2.5 错综复杂的业务逻辑
4.2.6 视图层中的复杂性
4.3 测试遗留代码
4.3.1 测试不可测试的代码
4.3.2 没有单元测试的回归测试
4.3.3 让用户为你工作
第 05 章 重搭架构
5.1 什么是重搭架构?
5.2 将单体应用程序分解为模块
5.2.1 案例研究——日志管理应用程序
5.2.2 定义模块和接口
5.2.3 构建脚本和依赖管理
5.2.4 分拆模块
5.2.5 引入 Guice
5.2.6 Gradle 来了
5.3 将 Web 应用程序分发到服务
5.3.1 再看一下 Orinoco.com
5.3.2 选择一个架构
5.3.3 继续采用单体架构
5.3.4 前后端分离
5.3.5 面向服务架构
5.3.6 微服务
5.3.7 Orinoco.com 应该做什么?
第 06 章 大规模重写
6.1 决定项目范围
6.1.1 项目目标是什么?
6.1.2 记录项目范围
6.2 从过去学习
6.3 如何处理数据库
6.3.1 共享现有数据库
6.3.2 创建一个新数据库
6.3.3 应用程序间通信
第三部分 重构之外——改善项目工作流程与基础设施
第 07 章 开发环境的自动化
7.1 工作的第一天
7.1.1 搭建用户活动仪表盘开发环境
7.1.2 出了什么问题?
7.2 一个好的 README 文件的价值
7.3 用Vagrant 和 Ansible 对开发环境进行自动化
7.3.1 Vagrant 介绍
7.3.2 为用户活动仪表盘项目搭建 Vagrant
7.3.3 用 Ansible 进行自动化配置
7.3.4 添加更多的角色
7.3.5 移除对外部数据库的依赖
7.3.6 工作的第一天——再来一次
第 08 章 将自动化扩展到测试环境、预生产环境以及生产环境
8.1 自动化基础设施的好处
8.1.1 保证环境一致性
8.1.2 易于更新软件
8.1.3 易于搭建新环境
8.1.4 支持追踪配置更改
8.2 将自动化扩展到其他环境
8.2.1 重构 Ansible 脚本以处理多种环境
8.2.2 为 Ansible 角色和 playbook 搭建库
8.2.3 让 Jenkins 负责
8.2.4 常见问题
8.3 移到云上
8.3.1 不可变基础设施
8.3.2 DevOps
第 09 章 对遗留软件的开发、构建以及部署过程进行现代化
9.1 开发、构建以及部署遗留软件的困难
9.1.1 缺乏自动化
9.1.2 过时的工具
9.2 更新工具链
9.3 用 Jenkins 实现持续集成与自动化
9.4 自动发布和部署
第 10 章 停止编写遗留代码
10.1 源代码并不是项目的全部
10.2 信息不能是自由的
10.2.1 文档
10.2.2 促进沟通
10.3 工作是做不完的
10.3.1 定期进行代码评审
10.3.2 修复一扇窗户
10.4 自动化一切
10.5 小型为佳
网友评论