领域驱动设计

领域驱动设计

Administrator 524 2023-06-05

大型系统是如何"变老"的

面临的问题

当一个项目使用过长,他的运行效率低、代码乱,需要重构的时候,需要面临一些问题

  • 沟通难
    • 产品提出一个问题,开发却要很久
  • 开发难
    • 代码膨胀,对于大型软件,一个旧的类可能有上千行,无法确定更改后的影响有多大
  • 测试难
    • 改了个需求,测试需要组织庞大的测试计划
  • 创新难
    • 系统背负的业务越来越重,已经基本丧失了对新技术的灵活敏感
    • 比如从ormhebernate换到mybatis,因为业务代码是耦合的,无法轻易的更换

微服务架构更在防止系统"老化’'吗

image-20221105160246592

虽然在一开始将一个电商项目根据功能分成了若干个微服务,但是随着系统体量的不断增大,某一个或某几个微服务的功能可能也会变得无比庞大,导致系统"老化"。所以微服务对于防止系统老化只是一个治标不治本的方式。

DDD被认为是目前最理想的方式

image-20221105161428086

在业务上分成一个个的domain领域,每个领域只针对自己业务上的属性,系统上不在以mvc构建,而是以带有自己功能的领域来构成。这样在微服务进行拆分时,最理想的方式是可以随意按照领域拆分,这样子的话,项目就可以自由组合,结合微服务的体系,更好的体现微服务的能力,使得系统茁壮的成长。

DDD的保证措施

DDD使得一些工作经验不多的人可以对相关功能进行负责,但是需要一些保证措施。

mvc架构的隐患

  • 数据库
    • 用户的模块发生变化,比如新增了一个字段等等,那么在代码层面可能都需要做一个修改
  • 其他的微服务调用或者第三方api
    • 调用方式发生改变
    • 其他微服务或第三方api业务发生变化,比如校验码发生变化,那么在业务代码对获取到的校验码的判断也需要做出相应的修改
  • 消息队列
    • 当中间介更换的时候,调用的方式也需要进行变化

mvcddd的改造

image-20221105201437426

将周边的所有的变化隔离开,留下自己的核心

  • 数据库

    • 对于数据库的操作不再是引入操作数据库的dao,而是通过一个Repository接口,这样子当数据源发生变化时,通过这样的一个接口隔离,这样子orm的具体实现不会影响到业务,切换的时候只需要更换Repostory的具体的实现类,整体的业务不需要变化
    • 使得业务只需要拿到数据即可,至于数据是从哪里来的,这个不用管
  • 实体

    • 以往的实体pojo只需要有一些属性,一些settergetter,在ddd中把实体和他的业务方法封装到一起,构成一个充血模型,以前的pojo是一个贫血模型

    • 以前的pojo实体会把所有属性放在一个大的实体类里,然后通过上层的service来对这些属性做不同的操作,实现不同的业务,这样会造成贫血失忆症的后果,即从这个实体上看不出他是要做什么事情的

    • 所以在充血模型,把业务方法上进来的好处就是,这个实体要做什么事情就会一目了然的

  • 值对象

    • 访问值对象必须通过实体来访问
    • 但也不是所有场景都必须通过实体类获取值对象,根据是否是业务来判断
  • 业务

    • DDD业务指造成实体状态变化的过程,即使得实体的属性发生变化的方法
  • 防腐层

    • 隔离外部服务
      • 封装一个SafeService接口,将其他微服务或第三方api的调用放到这个接口里,在这个接口里进行调用和返回结果的判断
    • 隔离第三方组件
      • 封装MessageProducerMessageConsumer接口,在这个接口里指定对应的组件,并实现对应使用该组件的方法
  • 领域服务 隔离实体

    • 将修改实体状态而业务代码,也封装成一个接口,在接口的方法中调用实体的业务方法,这样子的好处是,以后再新增一些新的业务的时候,也不会说使得业务层类的代码过于庞大,并且因为使用接口组合的方式,业务的可扩展性也更好,耦合度更低

重新编排后的好处

  • 业务逻辑清晰,数据流转与业务逻辑完全分离
  • 各个模块的功能都是相对独立的,没有外部依赖,可以单独测试
  • 原有的service不再包含任何具体业务的逻辑,仅仅作为组件编排

DDD四层架构

image-20221105202154385