首页 存档 技术 查看内容

业务系统重构总结

2018-3-30 13:00 |来自: 互联网 285 0

摘要: 架构师(JiaGouX)我们都是架构师! 之前在服务化设计模式实践(http://blog.brucefeng.info/post/service-design-patterns-practices)里面介绍了交易侧系统服务变迁的模式,服务的变迁更好的支持了业务的发展, ...

架构师(JiaGouX)
我们都是架构师!



之前在服务化设计模式实践(http://blog.brucefeng.info/post/service-design-patterns-practices)里面介绍了交易侧系统服务变迁的模式,服务的变迁更好的支持了业务的发展,伴随着业务的发展,对业务系统内部的要求也更好,需要具有更好的扩展性。随着业务的不断发展,每个服务内部的逻辑也变得越来越多,需要有更好的抽象来支持以后更多的业务类型。


1. 项目业务背景

重构的项目有订单服务,预订系统,退款系统;这三个系统都是与用户交易行为息息相关。


其中订单系统参与重构的模块为订单创建,订单状态流转,订单支付;


预订系统的重构主要为了支撑更多的预订方式,如之前已经支持的库存模式、商家接单模式和售中客服模式,伴随着重构还需要支持商家系统直连模式,而且需要能够支持以后业务发展更多的预订模式。


退款服务的复杂度主要来源于多种退款类型,如用户退款,系统退款,商家退款和客服退款等多种类型,而每种类型又有各种不同的退款规则;退款服务需要支持多种业务,如已有的KTV预订和将要扩展出的酒水点单。


在这里我们主要来讲讲预订系统重构,因为这个系统的重构几乎涵盖了订单服务和退款服务重构所使用到的技术


目标

  • 抽象预订流程,并模板化

  • 对可变化的部分支持配置化 

  • 在上线过程中支持新老流程切换 


2. 业务抽象

由图中可以看出,业务流程非常复杂,一个订单的预订过程会根据不同的情况走不同的预订渠道,如果一个预订渠道因为某种原因预订失败了,可能会继续使用另外一个预订渠道继续进行预订,也就是会发生流转。


另外,在预订成功和预订失败时,会需要做一些其他操作,例如发送短信告知用户结果等;


图中还有一点没有体现的是,在开始发起预订时,需要校验数据的正确性,校验是否复核预订规则等等校验。


根据这些条件我们做了以下抽象:

  • 首先订单从预订开始、预订中到预订成功/失败定义为预订的主流程,其中每个接单都是一个重要的业务节点,这种主流程定义为一级业务。

  • 对于不同的预订模式(如库存模式、商家接单模式、客服售中介入模式和商家系统直连等),抽象为预订渠道。预订渠道之前的转化定义为渠道流转。

  • 预订渠道会直接影响预订结果

  • 预订中、预订成功/失败 时渠道需要个性化的操作,如商家接单渠道开始时需要通知商家等,这种流程会影响一级业务,但其业务具有个性化特征,因此定义为二级业务。

  • 同时预订中、预订成功/失败后 需要进行不影响业务流程的操作,如发送短信告知用户预订结果,记录一些属性等等。这部分业务定义为三级业务。

一级业务是系统最重要的业务,业务流程标准化且会直接影响业务结果;二级业务是一级业务一个步骤,但因为预订渠道的不同而有个性化操作;三级业务是根据业务结果来执行的操作,不会再影响系统的主流程。


3. 重构

3.1 核心业务流程


预订中核心业务流程是最重要的部分,也就是图中所标注的一级业务,每一个步骤都是一个重要的业务节点,且每一个节点都会有一些复杂的逻辑。


因此在重构时,将核心业务流程的实现定义为一个模板引擎,在这个模板引擎中的每一个节点都可以是一个接口,可以任意的配置。在代码上的表现就会是这样的。


开始预订:

publicclassKtvReserveService{

publicKtvReserveResultDTOreserve(KtvReserveContextreserveContext)throwsReserveException{
//校验
KtvValidateResultvalidateResult=this.ktvReserveValidateStack.validate(reserveContext);
if(validateResult==null||!validateResult.isValid()){
returnKtvReserveResultDTO.createFailedResult("validateinvalid");
}
//判定预订渠道
KtvReserveChannelreserveChannel=reserveChannelJudgeService.judgeChannelType(reserveContext);
reserveDataService.store()
reserveDataService.transferReserveChannelStatus();
//开始渠道预订
ChannelResultchannelResult=this.reserveChannelService.reserve(reserveContext);
returnKtvReserveResultDTO
.genResult(channelResult.isSuccess(),channelResult.getDesc(),reserveFlow.getReserveId());
}}


渠道反馈预订结果:

publicclassKtvReplyReserveService{

@Override
publicReplyReserveResultreply(KtvReplyReserveInforeplyReserveInfo)throwsReplyReserveException{
//校验
KtvValidateResultvalidateResult=replyReserveValidateStack.validate(replyReserveInfo);
if(validateResult==null||!validateResult.isValid()){
logger.warn(String.format("%svalidatefailed",param));
returnReplyReserveResult.createFailedResult("validatefailed");
}
//更新预订状态
reserveDataService.transferReserveChannelStatus();

ReplyReserveResultresult;
//判定预订结果
KtvReserveStatustoReserveStatus=this.reserveChannelJudgeService.judgeReserveResult(replyReserveInfo);
booleanreserveFailed=
toReserveStatus==null||toReserveStatus==KtvReserveStatus.ReserveFailed||toReserveStatus==KtvReserveStatus.Init;
if(reserveFailed){
//预订失败处理
result=this.reserveFailed(replyReserveInfo);
}elseif(toReserveStatus==KtvReserveStatus.ReserveSuccess){
//预订成功处理
result=this.reserveSuccess(replyReserveInfo);
}else{
//需要转移其他渠道预订
result=ktvReserveTransferService.transferChannel(ktvReserveContext);
}
//渠道处理内部事务
this.replyReserveChannelService.reply(replyReserveInfo);
returnresult;
}}

3.2 校验栈

在业务性很强的服务来说,在业务开始之前需要有复杂的校验,如果在这个服务中支持多种业务类型,还需要根据不同的业务类型来选择不同的校验逻辑,因此在服务中将校验栈独立出来。


校验栈的组装采用责任链模式,这样每个校验service通过组装的方式即可以灵活支持多种校验。但是对于业务主流程来说,把校验service的组装服务并不适合放在主业务流程里,因此在重构的时候将校验栈的组装逻辑放在一个单独的service中采用代理模式进行组装。

publicinterfaceKtvReserveValidateService{
/***校验预订信息*@paramreserveContext*@return*/
KtvValidateResultvalidate(KtvReserveContextreserveContext);}


publicclassKtvReserveValidateStackimplementsKtvReserveValidateService{
privateList
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部