标题、标签和其他 UI-related 东西应该包含在领域模型中吗?
Are titles, labels and other UI-related things should be included in domain model?
我对如何严格对待 UI-related 领域模型的业务逻辑中不会使用的事物感到困惑:如何将它们正确地存储在数据库中?
例如,如果我有一个聚合,它是一个实体,而这个模型的主要目的是处理重要的事情,我是否应该在模型中包含一个标题,即使它对业务逻辑没有贡献以任何方式?如果我想将标题存储在与存储我的实体的其他数据(例如重要的东西)相同的 table 中,这有关系吗?
@Entity
MyAggregate:
id: ID
title: str
importantThing: ImportantThing
def doSomethingWithImportantThing():
...
如果我不在模型中包含标题,那么如何使用 Repository
模式正确存储它?如果我将标题保留在我的模型中,我的存储库可能如下所示:
@Repository
MyAggregateRepository:
def create(myAggregate: MyAggregate):
...
如果我从模型中删除标题,存储库会发生什么情况?是不是应该这样变形:
@Repository
MyAggregateRepository:
def create(myAggregate: MyAggregate, title: str):
...
经验法则是只保留做出决策和保护聚合状态中的不变量所必需的东西。否则,聚合会被外来问题污染,并转换为过度增长的数据库 table 或文档的混乱的一对一表示。
任何规则都有例外。我不认为从一开始就过火并过早地拆分实体是个好主意。
但是,如果您觉得事情变得一团糟,并且您可以看到一组字段用于一组函数,而另一组字段仅用于另一组函数的模式,您可能会得到您的聚合值得拆分的想法。
存储库模式在很大程度上与执行命令相关。它的主要目的是处理聚合持久化。在实现查询时,考虑使用 CQRS 并编写您需要编写的查询,它不一定是处理查询的存储库。查询也是幂等的并且没有副作用(性能除外),因此在编写查询时不考虑域模型本身是相当安全的。不过,最好使用通用语言来命名您的查询。
将 title
保持在您的模型范围内。这有几个原因。
title
的效用保留在模型本身的范围内,因为它在领域层中没有任何其他用途。它作为 "identity" 仅对模型本身而言是局部的,然后在 UI. 中浮出水面
title
不是创建聚合所必需的,因为它没有业务逻辑意图。如果是这样,则表示模型与聚合创建之间的耦合更紧密,这通常是不可取的。
title
似乎是一个聚合不变量,您只希望关注聚合根,而不是从外部访问或创建的角度来看。
最终,这会让您的设计更加简洁。
纯粹 UI 相关的事物通常不属于该域,除非该域与管理 UI 相关的项目有关,例如本地化域。
属于域的数据将保留在域中。例如,如果对 AccountTransaction
或类似内容有评论,那么该评论将使用系统用户使用的语言,而不是可以本地化的语言。但是,如果该交易有一个 Type
指标,它是 Debit
或 Credit
那么您不一定要使用字符串表示,而是将其编码;即使 "code" 是 Debit
和 Credit
或 Dr
/Cr
。但是,前端会使用一些 l10n 或 i18n 机制以相关语言显示 Type
的文本。
希望我正确理解了你的问题。
我对如何严格对待 UI-related 领域模型的业务逻辑中不会使用的事物感到困惑:如何将它们正确地存储在数据库中?
例如,如果我有一个聚合,它是一个实体,而这个模型的主要目的是处理重要的事情,我是否应该在模型中包含一个标题,即使它对业务逻辑没有贡献以任何方式?如果我想将标题存储在与存储我的实体的其他数据(例如重要的东西)相同的 table 中,这有关系吗?
@Entity
MyAggregate:
id: ID
title: str
importantThing: ImportantThing
def doSomethingWithImportantThing():
...
如果我不在模型中包含标题,那么如何使用 Repository
模式正确存储它?如果我将标题保留在我的模型中,我的存储库可能如下所示:
@Repository
MyAggregateRepository:
def create(myAggregate: MyAggregate):
...
如果我从模型中删除标题,存储库会发生什么情况?是不是应该这样变形:
@Repository
MyAggregateRepository:
def create(myAggregate: MyAggregate, title: str):
...
经验法则是只保留做出决策和保护聚合状态中的不变量所必需的东西。否则,聚合会被外来问题污染,并转换为过度增长的数据库 table 或文档的混乱的一对一表示。
任何规则都有例外。我不认为从一开始就过火并过早地拆分实体是个好主意。
但是,如果您觉得事情变得一团糟,并且您可以看到一组字段用于一组函数,而另一组字段仅用于另一组函数的模式,您可能会得到您的聚合值得拆分的想法。
存储库模式在很大程度上与执行命令相关。它的主要目的是处理聚合持久化。在实现查询时,考虑使用 CQRS 并编写您需要编写的查询,它不一定是处理查询的存储库。查询也是幂等的并且没有副作用(性能除外),因此在编写查询时不考虑域模型本身是相当安全的。不过,最好使用通用语言来命名您的查询。
将 title
保持在您的模型范围内。这有几个原因。
title
的效用保留在模型本身的范围内,因为它在领域层中没有任何其他用途。它作为 "identity" 仅对模型本身而言是局部的,然后在 UI. 中浮出水面
title
不是创建聚合所必需的,因为它没有业务逻辑意图。如果是这样,则表示模型与聚合创建之间的耦合更紧密,这通常是不可取的。title
似乎是一个聚合不变量,您只希望关注聚合根,而不是从外部访问或创建的角度来看。
最终,这会让您的设计更加简洁。
纯粹 UI 相关的事物通常不属于该域,除非该域与管理 UI 相关的项目有关,例如本地化域。
属于域的数据将保留在域中。例如,如果对 AccountTransaction
或类似内容有评论,那么该评论将使用系统用户使用的语言,而不是可以本地化的语言。但是,如果该交易有一个 Type
指标,它是 Debit
或 Credit
那么您不一定要使用字符串表示,而是将其编码;即使 "code" 是 Debit
和 Credit
或 Dr
/Cr
。但是,前端会使用一些 l10n 或 i18n 机制以相关语言显示 Type
的文本。
希望我正确理解了你的问题。