专栏名称: 逸言
文学与软件,诗意地想念。
目录
相关文章推荐
OSC开源社区  ·  2024热门前端UI组件库最全盘点:包含We ... ·  6 天前  
程序员的那些事  ·  阿里云机房火灾,字节等服务瘫痪,网友:吃瓜吃 ... ·  1 周前  
51好读  ›  专栏  ›  逸言

项目札记004:多租户的领域建模设计

逸言  · 公众号  · 程序员  · 2024-09-18 09:47

正文

虽然JasperServer已经能够支持多租户的访问,但是却未曾提供租户订阅管理与功能权限管理的特性,需要由我们自行设计。除此之外,还应提供订阅收费的特性,它牵涉到支付、退费、账务甚至发票等功能。

现在回想起来,之所以当时未考虑这一特性的设计,可以从MVP(最小可用产品)的角度考虑,租户订阅特性的优先级显然要高于订阅收费特性,毕竟,我们一开始主要希望通过提供免费服务来吸引更多的租户,从而达到较高的访问量,不太在乎从一开始就能通过租户对服务的订阅获得现金流收入。

当时,我对Eric Evans提出的领域驱动设计(Domain-Driven Design,DDD)方法已有所了解,属于半通不通的水平,因此在为多租户模块进行设计时,借鉴了DDD的一些战术设计模式,不过,并没有在设计模型中清晰体现聚合、实体与值对象的概念,主要还是运用了领域服务和资源库等模式,同时,采用了面向对象分析与设计的做法,考虑了各个对象的职责,并通过适度抽象降低对象协作之间的依赖强度。

下图是当时设计的领域模型。为了真实表达当时的项目状态,除非特别说明,本专栏给出的设计方案尽可能保持当初的原貌,设计图则直接使用原设计图(原设计图使用Enterprise Architect绘制)。

这是一个领域模型,但并非领域设计模型,因为该模型并未体现实体、值对象、聚合等设计元素。图中的BusinessService是多租户业务的一个领域概念,代表租户(Tenant)订阅的一个服务。FunctionNode指一个具体的功能,由它组成一个BusinessService。之所以在BusinessService之下细分该粒度,一方面,说明面向租户提供的服务以可组合的形式获得,另一方面,FunctionNode还可用于细粒度的功能权限控制。关于权限控制的内容,会在专栏以单独章节给出。

在绘制领域对象之间的关系时,该图存在明显问题。一个租户可以订阅多个服务,一个服务可以被多个租户订阅,二者存在多对多的关系,但实际上,引入TenantSubscription之后,就可以将这个多对多关系拆解为两个一对多关系,即当一个租户订阅多个服务后,就会生成一个TenantSubscription,每个订阅包含多个订阅项,即图中的ServiceSubscription,这一概念又相当于拆解了订阅与服务的一对多关系,转换为订阅与订阅项的一对多关系,以及订阅项与服务的一对一关系。用户对服务的订阅也类似,只是用户订阅的服务范围必须是在所属租户提供的服务范围内。修改后的领域模型如下图所示:

为了避免多个Subscription产生混淆,我将原图中的ServiceSubscription修改为ServiceSubscriptionItem。同样,我为UserSubscription也提供了对应的订阅项。

如果要引入OO和DDD的设计要素,领域模型应表示为:

该模型不仅仅表达了两个类之间存在关系,而且会具体为什么样的关系,空心菱形表示聚合关系(Aggregation),实心菱形表示合成关系(Composition),每个虚线框表示一个DDD聚合,深绿色为聚合根实体,绿色为非聚合根实体,图中并没有表示值对象。