大型系统是如何"变老"的
面临的问题
当一个项目使用过长,他的运行效率低、代码乱,需要重构的时候,需要面临一些问题
- 沟通难
- 产品提出一个问题,开发却要很久
- 开发难
- 代码膨胀,对于大型软件,一个旧的类可能有上千行,无法确定更改后的影响有多大
- 测试难
- 改了个需求,测试需要组织庞大的测试计划
- 创新难
- 系统背负的业务越来越重,已经基本丧失了对新技术的灵活敏感
- 比如从
orm
从hebernate
换到mybatis
,因为业务代码是耦合的,无法轻易的更换
微服务架构更在防止系统"老化’'吗
虽然在一开始将一个电商项目根据功能分成了若干个微服务,但是随着系统体量的不断增大,某一个或某几个微服务的功能可能也会变得无比庞大,导致系统"老化"。所以微服务对于防止系统老化只是一个治标不治本的方式。
DDD被认为是目前最理想的方式
在业务上分成一个个的domain
领域,每个领域只针对自己业务上的属性,系统上不在以mvc
构建,而是以带有自己功能的领域来构成。这样在微服务进行拆分时,最理想的方式是可以随意按照领域拆分,这样子的话,项目就可以自由组合,结合微服务的体系,更好的体现微服务的能力,使得系统茁壮的成长。
DDD的保证措施
DDD
使得一些工作经验不多的人可以对相关功能进行负责,但是需要一些保证措施。
mvc
架构的隐患
- 数据库
- 用户的模块发生变化,比如新增了一个字段等等,那么在代码层面可能都需要做一个修改
- 其他的微服务调用或者第三方api
- 调用方式发生改变
- 其他微服务或第三方api业务发生变化,比如校验码发生变化,那么在业务代码对获取到的校验码的判断也需要做出相应的修改
- 消息队列
- 当中间介更换的时候,调用的方式也需要进行变化
mvc
到ddd
的改造
将周边的所有的变化隔离开,留下自己的核心
-
数据库
- 对于数据库的操作不再是引入操作数据库的
dao
,而是通过一个Repository
接口,这样子当数据源发生变化时,通过这样的一个接口隔离,这样子orm
的具体实现不会影响到业务,切换的时候只需要更换Repostory
的具体的实现类,整体的业务不需要变化 - 使得业务只需要拿到数据即可,至于数据是从哪里来的,这个不用管
- 对于数据库的操作不再是引入操作数据库的
-
实体
-
以往的实体
pojo
只需要有一些属性,一些setter
、getter
,在ddd
中把实体和他的业务方法封装到一起,构成一个充血模型,以前的pojo
是一个贫血模型 -
以前的
pojo
实体会把所有属性放在一个大的实体类里,然后通过上层的service
来对这些属性做不同的操作,实现不同的业务,这样会造成贫血失忆症的后果,即从这个实体上看不出他是要做什么事情的 -
所以在充血模型,把业务方法上进来的好处就是,这个实体要做什么事情就会一目了然的
-
-
值对象
- 访问值对象必须通过实体来访问
- 但也不是所有场景都必须通过实体类获取值对象,根据是否是业务来判断
-
业务
DDD
业务指造成实体状态变化的过程,即使得实体的属性发生变化的方法
-
防腐层
- 隔离外部服务
- 封装一个
SafeService
接口,将其他微服务或第三方api的调用放到这个接口里,在这个接口里进行调用和返回结果的判断
- 封装一个
- 隔离第三方组件
- 封装
MessageProducer
和MessageConsumer
接口,在这个接口里指定对应的组件,并实现对应使用该组件的方法
- 封装
- 隔离外部服务
-
领域服务 隔离实体
- 将修改实体状态而业务代码,也封装成一个接口,在接口的方法中调用实体的业务方法,这样子的好处是,以后再新增一些新的业务的时候,也不会说使得业务层类的代码过于庞大,并且因为使用接口组合的方式,业务的可扩展性也更好,耦合度更低
重新编排后的好处
- 业务逻辑清晰,数据流转与业务逻辑完全分离
- 各个模块的功能都是相对独立的,没有外部依赖,可以单独测试
- 原有的
service
不再包含任何具体业务的逻辑,仅仅作为组件编排