跳到主要内容

业务建模小技巧

1.用一句话描述业务场景

需要一个完整的句子,包括主谓宾壮,可能还有定语

主语和宾语往往是我们要找的实体/值对象,谓语是主语对应的实体/值对象的行为方法,状语是这个case下的业务规则,往往需要归类到前面的实体行为方法中,定语也会是一些业务规则,同样要内聚到主语对应的实体中

举个例子:帖子作者只能在其已经加入了的某个圈子下才能发布帖子

主语:帖子作者

宾语:帖子

谓词:发布

状语:只能在其已经加入了的圈子

我们可以得到帖子作者、帖子两个实体,得到帖子作者有一个发布帖子的行为方法,得到一个业务规则:帖子作者发布帖子的前提是加入对应的圈子

2.写下思考过程

业务建模是一个不断思考的过程,画在白板上或者写wiki都可以,写的过程会让你梳理审视不足或者优劣

  • 业务建模 一句话描述

  • 关注当前模块 保持和关联模块的良好沟通就好,如果沟通过多,可能模块划分不合理

  • 代码示例 模型demo,用单元测试或者应用服务模拟模型的客户端调用,能发现很多模型不足,不要陷入代码细节

3.先从复杂的业务case开始建模

在一个聚合中,先从根实体入手,逐步涉及与其关联的其他实体/值对象

业务模型中涉及case的复杂度从高到低依次为:增-改-删-查,所以先将增这个业务case完成,基本上就完成了一大半

4.应用层

用DDD实现业务服务时,校验业务模型的质量的一个标准是:

应用层的servcie方法中不要有if/else,如果存在,要么是系统用例存在耦合,要么就是业务模型不够友好导致部分业务逻辑泄露到service了

通常,一个业务case在service层便会对应到一个service方法,确保case实现的独立性。用社区服务中的帖子模块来说,发帖、删帖、查询帖子详情这些case在service层都有对应的独立业务方法

对于较复杂的case,查询帖子列表,可能需要根据不同tag过滤帖子、查询不同类型的帖子、或者查询热门帖子,这时候使用一个service方法实现还是多个方法?

考虑这个问题主要从domain的一致性和数据存储一致性两方面入手,如果两个都一致,可以在一个方法中实现,否则就用不同的方法完成

例如:根据tag查询帖子和查询全部帖子列表,domain一致,数据都存在db中,只用在sql层面就可以处理,放在一个方法中。而查询热门帖子,其数据源并不在db中,获取的逻辑差异较大,就单独写一个方法来查询

5.有用的模式

  • 具有关联关系的实体,可以为这种关联关系引入一个值对象,从而降低实体间的耦合

    比如Post和Topic之间,引入了TopicPost值对象

  • 当实体依赖于领域服务时,将领域服务作为实体业务方法的参数传入,因为实体不会被spring管理,无法注入领域服务

  • CQRS,查询和命令式的接口走不通实现。查询式接口,入参校验-鉴权-从repository获取数据-拼接数据-数据转换-返回数据,理论上不应该存在过多的的业务逻辑,可以淡化domain层。

    命令式接口则必须走domain层,走相应的业务逻辑

系列文章:【DDD】使用领域驱动设计思想实现业务系统

6.如何识别应该有哪些对象

  • 有些书说类是现实世界里的事务的一个建模,但是对于一些抽象概念,无法有现实世界的事物来映射(现实世界映射法)

  • 有些书里说从需求里提取名词,作为可能的候选项,然后再进行筛选(名词法)

  • 还可以根据需求描述,把其中涉及的功能点罗列出来,再去看哪些功能点职责相近、操作同样的属性,可否归为同一个类(功能分析聚合法)