乐趣区

项目重构记录

前沿

本重构文档仅是本人在项目重构时的汇报文档,如有不当之处欢迎指正。后期还有个重构后性能对比有机会我也会贴出来。在此记录也是为了方便自己以后查证,温故,希望对有需要的朋友有帮助。

1、背景

A 项目现有系统架构继承于外包公司、导致整个系统架构比较落后、臃肿引入很多没必要模块、模块之间耦合度太大无法进行拆分和搽出无关的模块。导致开发、升级、发布比较痛苦。

项目管理后、APP 医生端、APP 患者端整个代码交织在一起,无法做到单独功能、模块的升级、部署。往往会出现解决一个 Bug 又引入更对的 Bug。

2、原有架构

从系统架构图上看、此系统是一个类 SOA 服务的简化本、大家看着也比较熟悉

整理架构让看着也不是太落后但是代码实现让人看着非常怀旧、里面使用大量的使用落后技术分装的比较臃肿的类库。整个系统架构使用 N 年以前封装的一些臃肿的类库硬堆成 SOA 服务架构,里面还是 MVC 架构。

2.1、原架构的存在问题

2.1.1 DAO

DAO 使用自己分装一个大而全的数据库访问操作。优势(对于外包)一个 Jar 解决所有的第三方 ORM 框架。缺点是项目变得臃肿、垃圾代码耦合度太大无法升级。

2.1.2 Service

业务逻辑为 Controller 层提供具体业务的实现。但在实现上、问题很多。如果是严格按照分层架构来实现、对业务逻辑层进行拆分、将本地调用变成远程调用、即可比较容易拆分、但实际中遇到如下问题。

业务层往往未实现单向依赖、部分业务逻辑层实现被注入了接口层的参数(request、response)或者直接在接口层来实现、使其和接口层的耦合的增加。

为了应为不但变更的需求、不少接口使用 map 作为输入输入参数、此类接口在维护时无法约束其参数。

Service 层绝大部分操作使用 PO 对象来作为数据处理对象,未对业务实体建模。这个层的实现是不完整。这使的对业务实体的操作需要推迟到 Controller 层来实现、导致 Controller 臃肿。

当服务之间存在大量依赖关系时,开发人员往往会直接将 Spring BeanFactory 注入到各个服务中,或者简单封装一个 FacadeService,通过这个 Service 可以访问到所有的业务逻辑对象。这个类的使用导致无法评估 Controller 层对 Service 业务对象的具体依赖。

2.1.3 Controller

Controller 层承担了大量的业务逻辑使其臃肿、难以测试。

2.2 功能问题

从整个系统上看、系统并没有区分、APP 患者端、医生端、系统管理、使其代码完全耦合在一起、只是实现了功能、完全没有考虑可用性和扩张性。

3、实施问题

3.1 可扩展性和性能提升困难

应用性能瓶颈基本都在数据库上。这个系统使用 mysql 作为数据库。三个应用对应一个数据库。读写都在一个库上操作。

3.2 系统臃肿、学习周期长

500 多个接口,全在一个项目中。项目最多有 1000 多个类,可用类大概在 300 左右、存在大量的僵尸类。Nginx 前置路由。路由这个让人欣慰,它是整个重构工作的有力支撑。纯后端的项目,为移动端 app,PC,WEB 应用提供接口。
三个应用的的所有代码全部交杂在一个臃肿的系统中、业务逻辑混难导致开发人员不敢去碰现有的代码、修改一个小功能可能会导致整个系统的崩溃。

3.3 合作成本

随着项目组人员增加,每次新版本开发都需要多人一起合作,修改同一个项目代码。虽然使用版本控制工具来对分支进行管理,但是不可避免的,大量的时间花费在代码冲突处理上。新增功能,增强功能,bug 修复,支持各种客户端,都在一个项目上进行,需要建立不同的分支,高峰期五六个分支同时进行都是常见的。这种情况下,代码冲突的频率非常高。一个周的小版本开发,1 天时间在解决冲突都是很正常的。

3.4 测试难度

测试工作也逐步的恶化了。测试环境构建难度高。随着分支的增加,每个进入测试的分支,都需要准备独立的测试环境。环境构建成本高。刚测试完的功能,由于分支合并冲突处理,又得重新跑一遍。严重影响项目进度

3.5 上线风险高

随着系统复杂度的增加,上线风险也越来也大。一个小功能的修改,打印一个日志,修复一个 bug,都需要整体上线。一旦有一个地方修改错了,这个系统就崩溃了。上线时间长,一次上线,半个小时是必须的。

3.6 引入新技术难度大

公司对新技术的追求和使用显得特别饥渴、这种生搬硬套的架构伪 SOA 架构降低了开发成本,但是对屏蔽了其它技术的导入。

很长一段时间这个系统都是由一位同事在维护和开发、对外接口全部混杂在一起,访问量也不大、开发人员完全是在本地开发、出现问题首先想到的是打补丁、而不会考虑是否结束这种混乱的架构而去从新构建系统。而当公司做业务调整,人员迅速增加后,原有的方式,就需要变更了。这就应了所谓的康威定律。

4、重构思路

根据现有系统的遇到问题,我们现在使用微服务架构来从新重构整个项目的架构。根据微服务的特性其可以解决上诉所有问题。

性能问题:对性能要求高的接口可以建立缓存来优化接口。

学习周期:一个项目仅包含少数紧耦合的接口、接口业务单一、开发人员 1 - 2 小时就可以同读代码、即可上手。

合作成本:每个项目相对独立,项目之间仅通过接口来交互。确定完接口后,开发、测试、上线,都是独立进行的,从而降低了沟通成本。

版本控制:由于项目之间是接口依赖而不是代码依赖,每个项目都可以建立独立的代码库。同时项目切分的比较细,每个项目开发时,仅会有一个开发人员对其做修改。这基本就不存在代码合并工作,也避免了代码合并过程中的各种问题。实际上,基于微服务架构的开发,我们并没有采用分支策略,而是直接用主干开发。

测试难度:每个项目独立部署、独立测试。由于消除了代码分支,没有代码合并的隐患,重复测试的工作量减少了。

上线风险:每个项目独立上线,就算出现问题了,也仅影响到少数接口。

新技术:在微服务改造进行中,各种新技术将被引入到系统中,开发不再局限于简单架构。集群、分布式、限流、降级、容错、Redis 等缓存系统,都开始在项目中使用,并有效地解决的业务上存在的问题。

4.1 现有业务拆分

根据现有业务进行梳理后、将整个系统进行拆分为:

API 网关(gateway-server)

统一权限服务(auth-server)

医生聚合服务(doctor-consumer-server)

患者聚合服务(patient-consumer-server)

管理系统聚合服务(system-consumer-server)

用户基础服务(user-provider-server)、

医生基础服务(doctor-provider-server)、

资源基础服务(resource-provider-server)

患者基础服务(patient-provider-server)

消息基础服务(msg-provider-server)

注册中心(eureka-server)

4.2 基础架构

4.3 逻辑架构

4.4 排期

……

退出移动版