写点什么

开发复杂业务系统,有哪些设计思路

用户头像
邴越
关注
发布于: 2021 年 01 月 13 日
开发复杂业务系统,有哪些设计思路

最近参与了一些电商营销中台等复杂业务系统的设计和开发,结合 DDD 和中台等,有一些架构方面的思考和体会,在这里记录一下。

  

做技术方案,核心是下面几个问题:

  • 业务上怎么做?- 业务文档

  • 技术上怎么做?- 技术方案

  • 代码怎么实现?- 落地实现


明确了这几个问题,可以处理大部分日常需求开发,如果是比较复杂的业务系统,就需要拆解的更精细。

比如电商的商品管理、订单交易、促销活动营销中心等系统的开发和重构,业务相对复杂,开发人天在几个月以上,直接开发可能会老虎啃天,无从下手。

 

这时候可以通过一个流程化的模板来指导,如果抽象一个通用的流程,可以参考下面的套路:

  • 业务拆解 > 复杂度来源 > 核心挑战点 

  • 领域驱动设计 > 业务过程分析 > 领域模型抽象 > 模型分解

  • 分层组织 > 工程架构 > 模块化 > 组件化

  • 考虑功能复用 > 可选路径 —( 业务身份,能力,扩展点,工作流程,编排)

  • 方案产出 >  整体-模块-流程-细节 > 方案评审 > 最终方案

 

其中的功能复用环节,也是包括阿里在内的大部分业务中台的解决思路,供参考。

 

一、业务拆解

1.1 复杂度来源


为什么要关注复杂度?


我比较认同系统设计中「软件复杂度」的观点,架构设计的目的是为了解决软件系统的复杂度带来的问题,所以在设计架构时,首先就要分析系统的复杂度。

 

只有正确分析出了系统的复杂性,后续的架构设计方案才不会偏离方向;

否则,如果对系统的复杂性判断错误,即使后续的架构设计方案再完美再先进,都是南辕北辙,做的越好,错的越多、越离谱。

 

举个例子,医院管理应用的医疗管理系统(HIS),复杂度在于业务逻辑复杂,系统之间调用不清晰,

如果你设计一个 QPS 几万的高性能架构,就是没有解决系统的核心问题。

 

正确的做法是将主要的复杂度问题列出来,然后根据业务、技术、团队等综合情况进行排序,优先解决当前面临的最主要的复杂度问题。

 

1.2 核心挑战点

 

射人先射马,擒贼先擒王。


确定了复杂度,也就确定了系统设计的难点,在进行系统设计时,可以把难点列出来,各个击破。 


以电商促销活动和优惠券为例,促销活动最大的复杂度来自营销形态的变化,营销最大的不变就是变,乱花渐欲迷人眼,各类促销方式千变万化。


每次促销活动都有不同的玩法和定义,促销系统的设计必须对促销模式有所抽象,任何活动或优惠手段都是基于最基本的促销模式而建立的。

 

电商促销系统建设难点包括:

  • 底层模型抽象:底层模型抽象可以通过 DDD 的方式,对领域模型和进行抽象。

  • 促销引擎性能:性能问题如何解决?已经是老生常谈,工程领域有很多经典的解决方案,比如缓存,异步,最终一致性。

  • 关联系统交互:理清和关联系统的交互

 

二、领域驱动设计


软件系统的目的反映在业务上,都是来解决一系列问题,例如考试系统完成考试,电商就是卖货,

同一个领域的系统都具有相同的核心业务,因为他们要解决的问题的本质是类似的,一个领域本质上可以理解为一个问题域 。

 

只要确定了系统所属的领域,那么这个系统的核心业务,即要解决的关键问题就基本确定了。 

任何一个系统都会属于某个特定的领域,例如论坛系统,核心功能是确定的,比如用户发帖,回帖等基本功能。

广义的电商系统也是一个领域,做电商业务,必须要支持的商品,订单,交易,物流等功能。

 

多说一句,领域驱动设计不是银弹,也没必要妖魔化,领域驱动设计本身有很多概念,我觉得不要把简单的问题复杂化了,作为指导思想,在实际操作中要具体问题具体分析,综合采用其它各种设计方法。

  

2.1 领域模型设计

 

DDD 里有领域专家的概念,领域专家要在这个领域深入研究,只有这样才会遇到非常多的该领域的问题,积累比较更加丰富的经验。

通常来说,一个领域有且只有一个核心问题,也就是核心子域。在核心子域、通用子域、支撑子域梳理的同时,会定义出子域中的限界上下文及其关系,用它来阐述子域之间的关系 。

 

以电商营销为例,优惠券、抽奖、套餐等,都是围绕这个促销这个业务范围来进行的,在促销域之外,还有相关的用户、商品、订单、风控、商家等。



三、架构分层

3.1 架构分层

下图是领域驱动设计中经典的分层架构:

 


用户界面/展示层:

  • 请求应用层获取用户所需的展示数据;

  • 发送命令给应用层执行用户的命令

应用层:

薄薄的一层,定义软件要完成的任务。

对外为展示层提供各种应用功能,对内调用领域层(领域对象或领域服务)完成各种业务逻辑。应用层不包含业务逻辑

 

领域层:

表达业务概念、业务状态信息及业务规则,是业务软件的核心

 

基础设施层:

为其他层提供通用的技术能力,提供了层间通信;为领域层提供持久化机制。

 

这是一个相对简单的分层架构,其实已经老生常谈,那么问题来了,我们在上面拆解的领域模型,如何映射到更加复杂的工程架构中?

  

3.2 工程架构

DDD 的核心诉求就是将业务架构映射到系统架构上,在响应业务变化调整业务架构时,也随之变化系统架构。 

微服务追求业务层面的复用,设计出来的系统架构和业务一致,不过领域模型并不直接反映数据结构,需要明确这一点。

领域驱动设计最后落地到数据存储上,不需要直接参考领域模型,在最后的技术架构上可以自由选择合适的技术架构。

  


3.3 模块组织

Java 项目一般是典型的 Maven 多模块项目,可以使用不同的 Module,区分各个层次,进一步,通过 Package 来控制 DDD 中的限界上下文。

 


3.4 领域对象

对具体的领域对象封装时,典型的有充血和贫血模型,由于大部分程序员习惯在 Service 里封装业务逻辑的贫血模型,完全的充血模型开发效率相对较低

我自己的体会是,技术服务业务第一,在开发时可以灵活的选择实现策略,模型对象封装一些简单的静态方法,大部分业务逻辑还是放在领域服务中实现。

 

3.5 代码模型

DDD 是一个指导思想,没有一个标准的代码模型。而且我觉得,团队成员水平不同,编码习惯也有区别,如果打着 DDD 的旗号,来给编码过程添加很多约束,那就有点舍本逐末了。


一般来说,可以通过一些脚手架工具,定制一个相对通用的代码模板,比如阿里巴巴的 https://start.aliyun.com/bootstrap.html 脚手架生成。


下面是一个简单的代码模型,可以作为参考:



四、考虑功能复用

4.1 编程 DRY 原则

大家都知道,编写整洁代码,有一个非常重要的原则就是 DRY,

Don't Repeat Yourself,避免产生重复代码,有经验的程序员都能够意识到这一条约束。

 

如果你使用 Idea 开发,Idea 也会识别并且提示你重复的代码,建议你进行抽象。

DRY 的好处更少的代码是好的,它节省了时间和精力,易于维护,并且减少了 bug 的几率。

除了在软件开发领域,在业务系统层面,也存在如何避免重复能力建设,考虑业务复用的问题。

 


4.2 业务层面的 DRY

业务系统层面的 DRY 原则,其实可以总结为一个问题,就是复杂业务系统,如何实现具有共性的业务能力的复用,这个也是很多业务中台关注的问题。


一般的,大部分业务中台(特指业务中台,不包括数据中台等其他形态)对业务复用的方式,

都可以通过定义业务身份 ——>  梳理扩展点 ——> 枚举业务能力 ——> 根据不同业务身份编排工作流 ——> 实现业务能力复用,这样的流程来实现。

 

可以对比编程中的 Pipeline 模式,或者责任链模式,只不过每个链条上负责处理输入和输出的,是不同的业务功能。

 

业务中台是另一个话题,这部分是发散思考,具体可以参考阿里巴巴 TMF (Trade Mudule Framework)框架的介绍:

如何实现32.5万笔/秒的交易峰值?阿里交易系统TMF2.0技术揭秘

 

五、可扩展性和过度设计如何平衡

好的架构设计一定是扩展简单的。

在设计时,要尽量封装可能的变化,在业务流程发生一些调整时,能够比较方便地修改系统程序模块或组件间的调用关系而实现新的需求,也就是我们常说的可扩展性。

但是可扩展性本身也是系统设计的复杂度来源之一,这就涉及到一个问题,如何平衡可扩展和过度设计。

 

5.1 区分确定性和变化

好的架构一定是扩展简单,运行平稳的。

系统架构最开始可以从一个通用的流程开始,case-by-case,

然后将「变化少」的部分沉淀下来为架构,将「变化多」的沉淀为扩展或者配置,梳理清楚,将这两者结合起来,最后完成系统架构设计。

 

5.2 用容量规划的方式来扩展

可以使用容量规划的思想,来处理可扩展性设计。

在做技术方案时,容量规划是一个特别重要的环节,要预估未来几年的增长量,进行数据库和缓存的容量规划。

我觉得这个方式也可以应用在扩展性设计上,对业务变化进行预期,考虑技术方案能够支持的业务发展时间。

 

六、方案评审

好的技术方案很难一蹴而就,大部分时候要经过反复的调整,就是需要关联的各方参与方案的评审和修改,最终确定最终技术方案。

我的建议是,团队最好输出一份技术方案的规范,可以供每个成员参考,从设计阶段,就统一团队成员的认识。

  

七、总结

最后再总结一下,关于复杂业务系统开发的一些体会:

  1. 熟悉业务,抽象产品需求,分析相关测试用例,了解各种用户角色和其使用的场景

  2. 自顶向下进行方案设计,对于比较复杂的业务系统,比较好的方式是先关注顶层模型,避免在一开始就陷入技术和业务细节中去

  3. 从整体设计,到模块局部规划,设计好部署架构、分层和分模块、API 设计、数据库设计等

  4. 可以参考成熟的解决方案,比如将开源软件,改造,变成适合自己业务需求的架构

  5. 验证和优化架构设计方案,完整的架构设计方案,需要有多次的评审,充分收集各方面的反馈,反复修改后确定

  6. 合理进行扩展,考虑架构预期能满足多长时间的业务增长,比如未来一年的业务变化


发布于: 2021 年 01 月 13 日阅读数: 4359
用户头像

邴越

关注

关注产品和技术 2018.08.13 加入

阿里云MVP,多年一线互联网研发经验,公众号「越哥聊IT」

评论 (8 条评论)

发布
用户头像
3.3 模块组织 按这种方式划分模块的话,那仓储接口和仓储实现分别放在哪个模块?
2021 年 02 月 03 日 10:15
回复
用户头像
解决一个复杂的业务分三步
1. 道 - 遵循什么的原则?(比如正交,隔离)
2. 术 - 围绕道,遵守什么样的模式?(观察者?Reactive)
3. 器 - 采用什么样的语言?
2021 年 01 月 23 日 21:56
回复
用户头像
这篇文章记录日常思考,并没有很系统化的梳理,外部的成熟模型,可以参考TOGAF(企业架构)、CMMI(软件过程)、DDD(业务软件复杂性解决之道)、ALPD(10倍速交付,阿里提出来的);关于业务部分,有专门的书介绍业务架构、解决方法架构方法论
2021 年 01 月 23 日 11:20
回复
业务部分啥书,求推荐
2021 年 03 月 17 日 19:37
回复
用户头像
您还是深受Spring影响,跳不出这个思维圈子
2021 年 01 月 22 日 09:30
回复
用户头像
这篇文章是来凑数的吧
2021 年 01 月 15 日 16:24
回复
打人不打脸嗷
2021 年 01 月 15 日 18:28
回复
学习学习
2021 年 01 月 19 日 17:38
回复
没有更多了
开发复杂业务系统,有哪些设计思路