Day968.如何开启一个遗留系统现代化项目? -遗留系统现代化实战

如何开启一个遗留系统现代化项目?

Hi,我是阿昌,今天学习记录的是关于如何开启一个遗留系统现代化项目?的内容。那如何启动一个遗留系统现代化项目。


一、项目背景

说来有点唏嘘,国内遗留系统的重灾区,恰恰是那些最早拥抱信息化的行业,比如电信、银行、保险、民航等。

它们早年身先士卒,投资金、投人力,建设了信息化系统,没想到多年以后反而成为了限制业务发展的遗留系统。

这些遗留系统都在各方面都存在着许多共性:

  • 代码量巨大且质量不高
  • 前端普遍使用用 ASP、JSP 等服务端渲染技术,在页面中内嵌了大量业务逻辑
  • 数据库中存在大量存储过程和函数
  • 单体“大泥球”架构
  • 系统缺乏文档和知识,新人很难上手
  • 几乎没有 DevOps

虚拟案例是一个车险行业的业务系统,它具备以上所有特点,使用 JSP 技术,数据库是 Oracle,存储过程的代码量占整体代码量的三分之一左右。

那么在开始现代化之前,需要做哪些前期准备呢?


二、业务梳理

作为架构师,可能并不熟悉每一个业务模块的具体内容,但不了解业务是无法设计出合理架构的。

因此,需要先对整体业务进行梳理划分出业务的边界,才能进一步设计组件和服务。还需要沟通好业务方,请他们派出各个业务模块的领域专家跟你一起梳理。也同样需要业务分析师、质量分析师和资深开发人员。

有很多梳理业务的方法和工具,像用户旅程、用户故事地图等,它们可以帮助理解业务流程、梳理业务架构。这其实也是一个降低外在认知负载、提升相关认知负载的过程。

梳理好的投保和理赔业务的用户旅程(这里是一个简化版的用户旅程,忽略了痛点和心情曲线,目标是梳理业务流程,而不是寻找用户痛点)大致如下所示:

在这里插入图片描述

在这里插入图片描述


三、战略建模与架构设计

接下来,需要以用户旅程为蓝本,对整个系统进行战略建模,目的是设计出目标架构。

战略建模同样有很多工具可用,常见的有事件风暴、动名词法,以及刚刚兴起的领域故事会。在这个案例里,使用动名词法。

动名词建模法 是指通过梳理业务需求、识别关键领域名词、识别命令动词,并将名词动词进行关联,从而形成统一语言、提取模型的建模过程。

其中,领域名词是指在业务操作中出现的名词,通常是业务操作的对象,比如“订单”,“商品”等。 而命令动词是指作用于领域名词的动作,使用业务语言描述(区别于 CRUD),比如“下单”,“订购”等。

在实战中,将整个建模过程分为以下七个步骤。

在这里插入图片描述

其中,前四个步骤属于业务梳理,后三个步骤属于架构设计。

步骤一:识别动名词

在这一步中,跟领域专家一起,进一步详细分析用户旅程中的每一个业务阶段。

按照业务时序,讨论业务步骤,以达成一致的理解。

梳理完毕后,将动词和名词按照业务相关性组织到一起。

在这里插入图片描述
在这一过程中,可以和领域专家澄清很多缩略的业务术语。

比如核保,拆分成命令动词和领域名词,应该是审核投保单,承保应该是承接投保单,缴费应该是缴纳保费,报案应该是申报案件申请,结案应该是结束案件……澄清这些术语很重要。

比如核保和承保,字面上理解是审核和承接保单,但实际业务中却是投保单。

通过和领域专家的沟通,才会明白,保单才是保险公司和投保人之间的合同,而投保单只是一个投保申请。

因此,保单和投保单很明显是两个领域名词,建立的模型也肯定是不一样的。

再比如缴费这个术语,在投保上下文里代表的是缴纳保费,但在其他上下文里,可能是缴纳其他费用。

越早澄清这些容易引起歧义的名词,就越容易形成统一语言,避免误解。


步骤二:识别角色

角色 是命令动作的发起者,比如“代理人”、“承保岗”、“查勘岗”,也可以是一个系统,比如微信小程序、支付宝等。

通过识别角色,可以进一步了解命令动作是如何参与到业务中的。

另外,不同角色的需求和变化频率往往不同,这有助于设计边界更加合理的架构。


步骤三:寻找缺失概念

缺失的概念是 指业务人员没有明确提到的概念,但是缺失后很可能影响业务的完整性和可追溯性。

缺失的可能是名词,比如已经识别出来了某个动词,但却没有找到与之对应的名词,需要找到这个名词,并补充到模型中;

缺失的也可能是动词,业务人员没有明确提到,但缺失了某一动词后,名词的生命周期就不完整,这样的动词也需要补充到模型中。

比如在步骤一提到的投保和缴费,就都是行为,没有对应的名词,找到投保单和保费的概念,就弥补了缺失的名词。

再比如赔款这个名词,只有“支付”这一个动词与之对应,显然生命周期是不完整的,应该补充“生成赔款”这一动作。


步骤四:去除噪音

与前一步“寻找缺失的概念”相反,这一步是要去除或忽略无用的信息(噪音)。

通常需求⽂档或者业务人员的描述会涉及到很多细节,但并不是所有的内容都和建模相关。在实施过程中需要有针对性地甄别,避免噪音对模型的干扰,降低后续设计过程的复杂度。在建模时不需要关注的噪音通常包括:

  • 无需记录的线下操作:有些行为并不会影响系统的数据或状态,因此不需要被系统记录。比如投保人提供投保单材料、上级人工核保、打印保单、清分单据等。
  • 查询操作:和数据查询相关的操作,如数据展示、数据导出、数据过滤查询等。
  • 字段说明:业务验证错误时的提示语、出错信息等。

经过这四个步骤,完成了业务梳理,部分的领域名词和命令动词如下所示:

在这里插入图片描述


步骤五:区分基础能力与运营能力

对于一个大型的复杂系统,需要将它分解成更小、更简单的部分。

借鉴 Unix 操作系统“分离策略与机制”的设计原则和 DDD 战略设计方法,将业务能力分为基础能力和运营能力。

基础能力通常提供原子能力,它们不依赖于编排能力,且变化的频率很低;

运营能力是在基础能力之上,企业想要健康运作而需要的能力,它们的变化频率很高。

在这一步中,要区分已经汇总的动名词对儿,并将它们按照基础能力和运营能力分成两层。

在这里插入图片描述


步骤六:识别核心基础能力

对于像保险业务系统这样的大型复杂系统,其基础能力可能仍然过大,需要进一步分解。

按照 Gartner 的 PACE Layered Application Strategy,对于基础能力里稳定性(或变动频率)不同的部分,可以再次划分,识别出核心基础能力。

核心基础能力是指反映业务本质,实现业务价值所必须的最小能力集合。

在识别核心基础能力的时候,可以遵循这样三个原则:

  • 稳定性原则:即找出反映业务本质的部分。业务本质通常是最稳定的,而与用户的交互通常是不稳定的。
  • 最小化原则:即尽可能做减法,非必要不做加法。
  • 完备性原则:即核心基础能力应该是完备的,能够独立实现业务价值。

以保险业务为例,不论其渠道端(柜台、互联网、移动端)怎么变化,不论实现技术怎么变化,其业务本质仍然围绕保单展开的,包括保单的费用和服务(案件、赔款)。

在识别出业务本质后,业务名词就可以分解为这样的三层。

在这里插入图片描述


步骤七:设计分层架构

当把业务名词分层之后,就可以着手设计目标架构了。

在这里,把这些业务名词理解为一个业务模块或组件中的核心模型,并以这些名词作为模块或组件的名称。

对于企业的业务系统,可以粗略地设计为三个层次:接入层、运营作业层和核心能力层。

  • 接入层 一般为 UI 系统、API Gateway 或 BFF 等,比如手机 App、微信小程序等。
  • 运营作业层是指围绕业务价值所展开的运营活动和作业管理。在这里把前面的运营能力层和基础能力层合并,来作为运营作业层。
  • 核心能力层是实现业务价值所必须的最小能力集合,是企业运营的本质。比如保险行业就是保单和保费,而银行则是围绕账户所展开的金额和状态的管理。
  • 除此之外,业务系统还需要对接一些企业已有的公共服务,比如产品中心、银行对接、客户管理、权限管理等,也需要与一些外部系统进行交互。最终的目标架构如下图所示:

在这里插入图片描述

当然,这只是一个假想的保险业务系统,仅仅做了其中部分业务的粗略梳理,并不是什么行业标准。


四、选择试点

有了战略模型和架构设计后,接下来要选择一个试点进行遗留系统现代化。

在做数字化转型时,常常会选择一个**精益切片(Thin Slice)**作为试点,而不是全盘地转型。

遗留系统现代化同样可以借鉴这种方法,对架构进行垂直的切割,将业务的所有元素整合成一个价值交付部分,能够提供完整的价值。

除了业务价值,还需要考虑试点的复杂度。可以使用一些工具,全盘分析整个遗留系统,一方面可以得出一些质量指标,比如缺陷数、坏味道数等,评估代码质量。

另一方面也能得出模块间的依赖关系,了解系统的复杂度。对于代码质量,推荐你使用流行的 SonarQube。

对于架构,推荐公司的开源工具 ArchGuard。

什么样的切片才适合做试点呢?这需要权衡业务价值和复杂度。

业务价值高的,往往很复杂,不好做;而简单的,又可能没有价值。

所以要尽量选择既能提供一定业务价值复杂度又不是很高的切片

因为复杂度太高的话,进展会很慢,容易让团队和各方干系人失去信心和耐心。

相对简单的模块则更容易成功,可以给业务带来实惠,给团队增加信心,同时可以总结出来各种经验和套路,供下一个切片使用。

在综合评估了业务价值和复杂度这两个维度后,选择核保模块作为试点

下图中阴影覆盖的部分,就是一个切片。

在这里插入图片描述


五、以假设驱动为指引选择现代化方向

选择完试点,你还需要选择要对试点所采取的遗留系统现代化方向。

是重构代码,还是添加测试?是拆分模块,还是拆分服务?这些都是可行的方向,需要选择的是最可能实现更大业务价值的那些。

这时候需要以假设驱动为指引,找到价值最大的方向。比如从业务敏捷这个维度,需要缩短需求交付周期、扩大需求吞吐量。

以前 30 人天开发完成的需求,能否缩短到 20 天?以前一个迭代交付 5 个需求,能否再增加 1 个?如果业务方更关注业务响应力,可能需要将这个模块拆分成相对独立的服务

另一方面,如果平时这块业务 Bug 比较多,需求方更希望改善它的质量,那可能需要对代码添加各种级别的测试。

指标的重要性和优先级确立以后,需要与业务方达成一致,并选择可以支撑这些指标的工作。

就本案例而言,业务方更关注业务响应力,因此选择将核保模块拆分为微服务


六、确定目标架构

对于试点的目标架构,其实无需关注太多细节。虽然通过战略建模,梳理出了整个系统的大致架构分层,但这其实还是对于问题域(Problem Space)的分析。

具体解决方案域(Solution Space),这些模块是微服务,还是几个模块合并成基于服务的架构,其实都不需要在现阶段给出答案。

遗留系统是复杂的,架构应该是慢慢演进的。一个负责任的架构师,是不可能仅仅在几天的业务梳理和战略建模之后,就给出最终的确切架构的。

对于核保模块这个试点,目标架构十分简单,就是把它拆分出来,形成一个微服务

在这里插入图片描述


七、制定架构演进计划

虽然目标架构的形态十分直观,但演进计划却并不简单。

这是一个将遗留系统的微服务拆分这个复杂问题,拆解成多个简单问题的过程,最终让任何一个普通的开发人员,都能够胜任其中的一个简单任务。

在制定计划时,需要考虑以下几个方面:

  • 首先,代码如何拆分。在遗留系统中,各个业务模块的边界是否清晰?是否可以使用基于组件的分解?或者是一个结结实实的大泥球,只能使用战术分叉?最终决定采用战术分叉方式

  • 其次,数据如何拆分。是暂时不拆分,和遗留系统共享单体数据库?还是使用单体封装的数据库服务?或者变更数据所有权,并在应用中同步数据?关于这部分,你可以复习第十五节课的内容。本案例最终选择的是拆分数据。

  • 第三,如何增量迭代。按照增量演进原则,不能采取长期改造、一次性上线的交付方式,而应该是每个迭代都交付一部分增量。那么对于服务拆分,应该如何迭代?是按页面交付?还是按 API 交付?在这个案例里,考虑到页面过于复杂,包含很多按钮,而每个按钮都对应一个后端 API,选择按 API 交付,这样粒度更小。

  • 第四,组建拆分小组。你需要和项目负责人沟通好资源,给你一个 5~9 人的开发团队。如果遗留系统的团队结构是业务组件团队,则最好就是从维护核保这个组件的团队中抽调一些人。如果是特性团队,则最好是经常做核保特性的团队。最糟的情况是技术组件团队,你需要选择一些对核保业务比较熟悉的开发人员。另外,一定要配备一到两名专职测试拆分结果的测试人员,不要给他们分配其他测试工作。我们在第十八节课中介绍过,这样会让测试人员在不同上下文之间频繁切换,增加他们的认知负载。

  • 第五,干系人如何管理。需要与业务方、项目负责人、业务分析师、其他架构师、核心开发人员、测试人员建立紧密的联系,获得他们的支持和帮助。做好这几个方面,你就可以开始按迭代增量演进了。


八、按迭代增量演进

迭代 0 是增量演进中最重要的迭代,有很多事情要在这个迭代完成。

  • 第一,创建全新的核保代码库。按照战术分叉的方法,将遗留单体的代码全量复制到核保代码库中,并将与核保无关的代码删除。
  • 第二,创建全新的核保数据库。对于数据,也可以使用战术分叉方法,将全量数据复制过来再删除掉无关的表,或者利用 Oracle 的特性,使用 DB Link,先远程访问单体数据库中的内容。具体方法我们后面的课程再展开。
  • 第三,搭建核保服务的持续集成流水线。如果遗留系统已经有了持续集成流水线,可以复用。如果没有,可以只搭建一个最简单的流水线,只包含构建和打包功能。
  • 第四,将持续集成流水线打出来的包部署到各个环境中。部署完之后,可以通过 API 工具测试部署是否成功。
  • 第五,建立开关机制。将流量引流到新的服务中,以验证真实场景下的连通性。
  • 第六,计划迭代 1 要改造的 API。从迭代 1 开始,增量演进就将进入一个稳定的交付阶段,你需要在每个迭代结束前,计划好下个迭代要完成的工作。
  • 第七,制定开发工序。要将复杂的任务简单化,你需要制定一个普通开发人员可以遵循的开发清单。

比如用活文档工具进行业务梳理、添加 API 的开关并验证、在单体中的老 API 上添加 @Deprecated 注解、Java 代码怎么拆分、存储过程怎么拆分、JSP 中的代码如何处理、如何测试、如何寻求帮助等等。开发工序应该尽可能详细,以降低普通开发人员的认知负载。

由于迭代 0 的工作量巨大,可以相对延长迭代 0 的时间。比如一个迭代是两周,可以把迭代 0 延长到一个月,以确保这些内容顺利完成和交付。

从迭代 1 开始,就可以按增量来演进了。


九、关于估算

在改造时,一个绕不过去的话题就是需要多长时间。对于正常的功能开发,工作量的估算可能还比较准确,但是对于遗留系统现代化,想准确估算出具体的时间节点是难上加难。

因为遗留系统现代化是一个复杂问题,会有很多不确定的东西时不时冒出来,比如人员变动、临时添加的紧急需求、代码和架构本身未知的复杂度等等。不过,这和业务方的诉求是矛盾的,业务方想知道到底需要多少预算,来评估风险、衡量 ROI。

然而,如果迫于业务方的压力而随意拍脑袋给一个人天(比如 10 人天就是 1 个人工作 10 天,或者 2 个人工作 5 天),反而是不专业的。

这时最好的答案就是坦诚地说:我还不知道。

正因为如此,才更应该选取一个小的精益切片,并且将功能开关锁定在一个小的 API 上。因为开发的规模变小了,估算可能还相对容易一些。你应该快速做出一个小的增量,证明这是可行的,给团队、领导和业务方以信心。

然后根据做出的这个增量的工作量去估算其他增量。也可以让业务方来比较一下,希望开发给出一个一年的承诺,最后一次性上线全部承诺,还是不做出具体承诺,但是一年内每个月都能看到一个具体的进展,并且随时可以中止(因为是增量且可回退的)。

如果业务方选择后者,那么他们就不会再纠结于一次性知道全部费用了。


十、总结

讨论了如何开启一个遗留系统现代化项目。

花了不少篇幅去梳理开启项目的步骤,需要先对不熟悉的业务进行梳理,得到初步的用户旅程或用户故事地图;

再通过动名词法等工具,对系统进行战略建模,并设计出目标架构;

然后选择一个端到端的业务进行试点,并以假设驱动的方式寻找合适的现代化方案;

确定目标架构以及制定演进计划,并按照计划逐个迭代地增量演进;

最后,每个迭代都需要得到充分验证。

目标很明确,就是要把核保业务从单体大泥球架构中拆分出来,形成具有独立数据库的微服务。这已经是个非常艰巨的任务了。

因此一定要记住,一次只做一件事。有时候你可能既想拆分微服务,又要进行代码重构,或者既要拆分数据,又想重新设计不合理的数据库,这些都是我不推荐的。

可以把它们排进计划,等一件事彻底做完再做另一件,而不要企图并行完成

因为认知负载太高了,什么都想做,最终什么也做不成。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/20607.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WiFi(Wireless Fidelity)基础(八)

目录 一、基本介绍(Introduction) 二、进化发展(Evolution) 三、PHY帧((PHY Frame ) 四、MAC帧(MAC Frame ) 五、协议(Protocol) 六、安全&#x…

迪赛智慧数——柱状图(象形标识图):在选择另一半时,你更看重的是?

效果图 好看只排第六,第一确实众望所归!当代男女择偶标准出炉,一张图带你看清。 女性挑选另一半时,她们更看重伴侣收入高、职业体面、工作能力强、受教育程度高,还得和自己有共同话题。 男性择偶观和女性恰恰相反&am…

ctfshow周末大挑战2023/5/12

本周周末大挑战用到的函数讲解 parse_url() 作用:解析URL,返回其组成部分 语法: parse_url ( string $url [, int $component -1 ] ) 参数: url:要解析的 URL。无效字符将使用 _ 来替换。 component: …

软件测试月薪2万,需要技术达到什么水平?

最近跟朋友在一起聚会的时候,提了一个问题,说一个软件测试工程师如何能月薪达到二万,技术水平需要达到什么程度?人回答说这只能是大企业或者互联网企业工程师才能拿到。也许是的,小公司或者非互联网企业拿二万的不太可…

Threejs进阶之十四:在uniapp中使用threejs创建三维图形

在uniapp中使用threejs 一、uni-app介绍二、新建uni-app项目三、安装three.js库四、在vue组件中引入three.js库五、创建场景(Scene)和相机(Camera)六、创建渲染器(Renderer)七、创建物体和灯光八、渲染场景(Scene)九、运行测试核心代码 一、uni-app介绍 uni-app是一个基于Vue.…

sqlserver 中的表值函数和标量函数

目录 一、表值函数 1.内联表值函数 1.创建函数 2.调用函数 3.返回结果 2.多语句的表值函数 2.调用函数 3.返回结果 3.内联表值函数和多语句的表值函数的区别 1.语法上 2.结构上 二、标量函数 1.创建函数 2.调用函数 2.返回结果 总结 一、表值函数 表值函数是返回一个Table类型…

如何使用jmeter进行压测

1.概述 一款工具,功能往往是很多的,细枝末节的地方也很多,实际的测试工作中,绝大多数场景会用到的也就是一些核心功能,根本不需要我们事无巨细的去掌握工具的所有功能。所以本文将用带价最小的方式讲解如何快速上手使用…

centos7.5离线安装部署TiDB-6.5.0分布式系统

centos7.5离线安装部署TiDB-6.5.0分布式系统 一、需求,为什么要部署TiDB-6.5.0分布式系统 当前绝大部分企业的业务数据都分散在不同的系统中,没有一个统一的汇总,随着业务的发展,企业的决策层需要了解整个公司的业务状况以便及时…

【Linux Network】应用层协议——HTTP

目录 1. 认识URL 2. urlencode和urldecode urlencode例子: urldecode例子: 3. HTTP协议格式 3.1 HTTP请求: 3.2 HTTP响应: 3.3 HTTP的方法: 3.4 GET方法和POST方法的区别 3.5 HTTP的状态码: 3.6 HTTP常见He…

Buf 教程 - 使用 Protobuf 生成 Golang 代码和 Typescript 类型定义

简介 Buf 是一款更高效、开发者友好的 Protobuf API 管理工具,不仅支持代码生成,还支持插件和 Protobuf 格式化。 我们可以使用 Buf 替代原本基于 Protoc 的代码生成流程,一方面可以统一管理团队 Protoc 插件的版本、代码生成配置&#xff…

QT的qrc文件的创建和编辑

qrc文件,这个是Qt的资源文件,如果在pro文件中不包含的话,在编译的时候会提示找不到相应资源的错误;下面说一下手动修改pro和编写qrc文件的方法: 2.1 添加qrc文件; 2.2 编写qrc文件; 可以用 file…

Linux_证书_Openssl工具详解

文章目录 OpenSSLopenssl实现对称加密openssl生成密钥对、非对称加密、数字签名根据CA颁布证书生成ca私钥和ca证书根据ca生成证书 小结 OpenSSL OpenSSL 是一个开源项目,其组成主要包括一下三个组件: openssl:多用途的命令行工具 libcrypt…

AR VR 到底哪种技术可以改变未来?

随着科技的不断进步,虚拟现实(VR)和增强现实(AR)技术已经成为了当今科技领域的热门话题。VR和AR的出现,为人们带来了前所未有的体验和感受,也为各行各业的发展提供了新的机遇。但是,…

clang-format configurator - 交互式创建 clang-format 格式配置文件

clang-format configurator - 交互式创建 clang-format 格式配置文件 clang-format configurator https://zed0.co.uk/clang-format-configurator/ clang-format-configurator https://github.com/zed0/clang-format-configurator Interactively create a clang-format confi…

ANR基础篇 - Trace.txt文件分析

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 文章目录 系列文章目录前言一、trace.txt文件示例二、日志分析2.1 CPU 负载2.2 内存信息2.3 堆栈信息schedst…

裸辞5个月,面试了37家公司,终于.....

上半年裁员,下半年裸辞,有不少人高呼裸辞后躺平真的好快乐!但也有很多人,裸辞后的生活五味杂陈。 面试37次终于找到心仪工作 因为工作压力大、领导PUA等各种原因,今年2月下旬我从一家互联网小厂裸辞,没想…

学习Se-net和Sk-net 附网络简单代码(pytorch)

(一)Se-net的原理和思路     Se-net严格来说是一个小结构,它可以直接插入已有的网络结构中,帮助原有结构获得更好的效果,如插入Resnet网络中。 Se-net的整个流程如下:     (1&#xf…

Cisco 产品下载链接汇总 2023 持续更新中

Cisco 产品链接汇总 2023 持续更新中 IOS-XE, IOS-XR, NX-OS & FXOS based on linux kernel 请访问原文链接:https://sysin.org/blog/cisco/,查看最新版。原创作品,转载请保留出处。 作者主页:sysin.org 本站 Cisco 产品汇…

Java是如何实现双亲委托机制的

Java 是一种面向对象的编程语言,它有一套独特的类加载机制。其中,双亲委托加载机制是 Java 类加载机制中的一个重要概念。本文将介绍 Java 的双亲委托加载机制是如何实现的,并解释其作用和优点。 Java 类加载机制 在 Java 中,类的…

ADAS/AD笔记之特斯拉Autopilot-HW3.0系统

摘要: 目前国内一般直接将高速NOA成为“L2”;因此,复杂度更高的城区NOA,就自然的映射到了“L2”。 一、概述: 特斯拉Autopilot系统首创了NOA这种淡化脱手/脱眼/脱脑(驾驶自动化程度)逻辑的功能…