陈武,汪骥宇,程植
(1.核动力运行研究所,湖北 武汉 430223;2.中核武汉核电运行技术股份有限公司,湖北 武汉 430223)
数字经济时代的到来,软件产业蓬勃发展,行业产值发展迅速,对软件工程师的需求日益增加。软件工程技术、软件框架理论实践不断发展,各种开发框架理论和组件的出现,在软件研发的各个领域,产生了巨大的作用,极大促进了软件研发效率。这些框架的应用,能够降低对软件研发人员的知识储备要求,降低了软件研发工作的进入门槛。
微服务架构随着云计算的兴起,已经成为企业应用中的主流技术。在微服务架构应用中,广泛地应用了各种开发框架、组件,其主要应用于SaaS 层应用的开发。Spring Cloud、MyBatis 框架组件是在微服务应用开发中,使用最为广泛的框架。
这些开发框架带来极大便利,同时也产生了许多新的问题。特别是在大型软件项目中,对软件质量管理的能力要求高,特别是在工期、资源紧张的情况下,代码规范性执行力下降,导致软件代码的价值继承性、可维护性降低。另外,在后期软件新功能开发、系统功能维护过程中,也会进一步加剧这些问题。
研究这些问题解决方法具有很高的工程实践意义,通过对软件代码的重构[1],解决或有效缓解这些问题,能够极大提高软件质量。软件重构[2]理论有许多的模式,判断如何使用、何时使用的问题,需要设计人员和开发人员的有很高的要求,在工程实践中希望有一个有效的、易操作的方法指导软件重构工作。
本文通过对某核电软件研制工程项目中近百个采用了这两个架构的微服务项目研究、分析,总结出在软件研发过程经常发生几个典型问题,提出微服务项目5分离法迭代重构模式,指导微服务项目进行重构,提高软件的质量。
在某核电软件研制工程项目中的微服务工程,在微服务设计中采用了领域驱动设计,以及典型的4层微服务架构如图 1所示。架构模型中包括接口层、应用层、领域层、持久层,另外还有一个贯穿四层的基础设施层。
1) 接口层:提供前端适配,实现针对不同的前端应用请求提供服务,实现对象转换,以及数据组装等场景。防止核心业务逻辑暴露、数据外泄,同时保证下层的稳定。
2) 应用层:提供应用服务,链接接口层和领域层,主要实现服务协同聚合、服务编排、服务组合,以及安全校验等逻辑处理。
3) 领域层:提供核心业务服务,通过各种领域对象构建领域模型,各种对象的方法调用实现业务逻辑,对应用层提供服务。另外调用持久层服务,实现业务对象持久化。
4) 持久层:提供数据持久化服务,将数据存储到数据库中。
5) 基础设施层:提供基础公共服务,主要包括配置类、工具类、基础公共模块、其他公共模块。
这种分层架构是一个弱耦合架构,层与层之间向下依赖,下层对上层无依赖,基础设施其他层无依赖。这样的分层架构带来很多好处,如开发人员可以只关注整个结构中的其中某一层;可以很容易地用新的实现来替换原有层次的实现;可以降低层与层之间的依赖;有利于标准化;利于各层逻辑的复用[3]。
图1 4层架构
在软件研发项目中,依据范围、进度、成本等方面要求,需要先选择微服务工程进行重构任务的驱动。另外,软件重构管理是一个持续的工作,作为以下重要的任务进行跟踪。每个迭代中会进行重构任务分析,确定是否进行重构,对哪一个项目进行重构,重构的目标是什么。本节介绍一个在工程实践中使用的简易工程选择模型,可以初步确定本迭代需要的微服务工程。在该模型中,涉及7 个元素,包括工程规模(代码量)、人员更替次数、迭代次数、测试Bug 数、工程重要程度、重构次数。
如表1 所示,列出在本项目过程中某个迭代的分析结果。
表1 项目代码分析表
根据情况选择重构紧迫度排名以及项目组开发进度,选择紧迫度高的项进行重构分析。在分析过程中,一般关注重要、核心业务相关实现代码。
通过对微服务项目中重构实施的总结,得到5 个典型问题:超大类、规则划分混乱、参数传递对象未区分、逻辑分层不清晰、业务规则重复。
随着功能、业务规则不断增加,业务类包括的功能越来越大,主业务类的逻辑非常复杂、庞大,导致超大类的出现。类太大会引发的问题一系列问题,如维护困难、规则修改困难,影响虚拟机运行,会导致内存频繁地被占用和回收,类加载会消耗更多时间,占用更大内存,容易引起内存回收。
在开发过程中,随着功能的迭代、逻辑的增加,会增加新的实体对象、事件对象、服务对象,来实现新的业务规则,也可能在原来的类中增加方法来实现新的规则。在这个过程没有对模型进行重构,导致规则的归属出现混乱。
在4层模型中,前端展示层和接口层通过视图对象(VO) 对象传递数据,接口层将对象转换为数据传输对象(DTO) 传递给应用层,再转换为领域对象(DO) 传递给领域层,最后通过持久化对象(PO) 传递给持久层进行持久化。
最常见的问题是一个对象穿透4层,容易导致业务逻辑的失控、信息安全失控、灵活性丢失等问题。
逻辑分层不清晰,在开发过程,未遵照分层的模型,将相应的业务逻辑在对应的层中实现。最常见的是在应用层的类方法中,实现领域模型的业务规则,这样导致在其他应用服务需要相同的领域服务时,需要重写一遍相关的规则代码,导致模型的失控。为后续维护、新功能开发埋下隐患。
业务规则重复,在开发、运维过程中,采用敏捷开发的过程中,每一个开发人员会去写自己的业务逻辑,往往一个业务规则会在不同的方法、不同的类中实现。另外在运维过程中,一个功能在开发过程、运维过程中的人员变化,导致问题修复功能优化时,往往采用复制的方法开发新的方法。
本重构模式包括重构流程和设计模式两个方面的内容。重构流程定义了重构工作的工作流程,设计模式定义的重构的设计方法。
一项工作完美执行需要有一个有效的工作组织管理过程,在重构中按照图 2 所示的流程组织,有效地进行服务项目的重构工作。包括模型回顾、关键方法分析、调用链分析、重构、测试5个环节。
图2 重构流程
1) 模型回顾,重构开始时,需要对服务的模型进行完整的梳理,出现需要重构的情形往往伴随着模型的滞后。这需要重新梳理,完善模型,做好重构准备。同时还需要做好确定本重构的目标,确定迭代的计划。
2) 关键方法分析,在本步骤中对需要重构的内容进行分析,确定服务、对象的关键方法,需要重构的方法。
3) 调用链分析,确定需要重构的方法后,需要分析重构方法的调用链,识别使用情况,从而进步与确定该方法涉及的相关功能以及相关测试用例。
4) 重构,依照本文提到的重构设计模式,完成模型重构设计。然后进行代码的开发,最终实现代码的重构。
5) 测试,本步骤是需要依据前面步骤分析出的相关测试用例进行测试,从而验证重构工作是否成功。
为解决本文中提到的问题,设计如图3 所示的微服务5分离迭代重构模式,在该模式中采用多次迭代,5方法循环应用。在重构过程中,根据实际情况,通过分步迭代的方式,达到最终的重构目标。5 方法包括类分离、方法分离、数据分离、规则分离、代码分离5种方法,这五种方法互为补充,灵活应用。
图3 微服务5分离迭代重构模式
1) 类分离
《公务员法》规定公务员的薪酬由基本工资、补贴、津贴和奖金组成,并不包含福利和保险,但是,随着社会的发展,福利在总薪酬中占比例越来越大,现代薪酬理论普遍接受全面薪酬或者总薪酬的概念,认为薪酬应该是包括基本薪酬、可变薪酬、福利和服务以及一次性奖金、股票期权等多种经济型报酬。
对超大类首先采用类分解的方法,进行拆分,可以参考所示的模式进行分解。可以按照对象基础类、查询类、高级查询类、添加类、修改类、校验类、审批类,以及其他类等模式进行分解。最终形成一个对象类族。一般实施步骤如下:
①进行分类,将方法进行分类,然后根据分类创建类。
②然后将各种方法迁移到各自的类中。调整模型内部的代码结构,修复方法迁移导致的相互引用的失败错误。
③再修复上层调用中因为方法迁移导致的错误。
④最后进行服务测试。
2) 方法分离
如果业务方法实现过程中,出现规则划分混乱的问题时,需要通过方法转移的方式来纠正该问题,从而理顺模型的规范性。一般做法如下:
②测试修改后的功能。
3) 数据分离
当发生传递参数对象未区分问题时,需要通过数据类型分解的方式,来处理该问题。一般做法如下:
①确定需要修改的相关业务服务,分析VO 和DO,确定双方的差异。
②重新构造VO,构造数据类型转换类方法。
③修改接口层、服务层接入数据对象,增加数据转换方法调用。
④进行功能测试。
4) 规则分离
当发生逻辑分层不清晰问题时,需要进行重构,厘清规则的分层。一般做法如下:
①理清应用层逻辑中属于领域部分的规则代码。
②将该部分代码抽取出,封装到独立的方法中。
③将该方法转移到领域模型对应的类中。
④测试修改后的功能。
5) 代码分离
如果存在较多的重复代码块,引发了业务规则重复的问题,如两次以上超过10行的重复代码,可以通过采用重复代码抽取的方式。将重复的代码抽取到公共的方法中,减少重复率,提供代码的可读性、可维护性。一般做法如下:
①同一个类型中的重复代码抽象到公共的私有方法,将业务规则抽象封装。
②如果该方法在同一个对象族中的其他类中也用到相同的规则,那么将这几个类中的共同方法,根据方法的作用,转移到相关的类型中。如公共校验方法转移到校验类中,公共赋值方法转移到基础类或赋值类中。
③如果业务对象的类中使用到相同的规则,那么将这个共同规则方法,转移到领域基础类中。
④修改相关调用规则的代码为调用公共方法。
⑤最后进行服务测试。
在面向对象、领域驱动设计[4]的理论中,以及典型设计模式理论[5]中,各种对象有明确的逻辑职责划分,各层也有相应的划分,数据的传递也有理论要求。软件重构意味着需要更多的投入,在工程实践中,往往并不能按照这些要求来判定是否需要重构。设计人员、开发人员还需要依据项目的实际情况,考虑业务的复杂度、重要度、使用情况等因素,确定是否重构。
本文中总结的问题,在很多工程中都存在,一般是随着项目推进,工程规模不断增大,这些问题才会显现出来。对于一个规模小的项目,即使出现这些问题,对业务实现并没有影响,对软件质量也影响较小,不需要启动重构的。
开发框架的使用,能够极大地提高开发效率、降低开发人员要求,快速交付,从而能够以较小的成本较短的周期完成项目。设计人员、开发人员在研发过程中需要不断对代码进行检查,适时启动代码重构优化,从而提高软件质量。本文的模式可以对这个过程提供一定的指导。