从活动记录移动到域对象模式方法
本文关键字:对象 模式 方法 活动 记录 移动 | 更新日期: 2023-09-27 18:30:53
下面是场景:
我加入了一个团队,他们开始开发一个相当大的金融系统,据说目标是DDD,有一个丰富的行为领域模型。 但是,我可以在项目的当前区域看到许多气味,这些气味指向活动记录:应用程序服务中的单个"保存"方法;一组相当贫乏的域对象,它们具有很大的"验证"方法等。 所有这些都非常像 CRUD,并且变得越来越难以管理。
我正在开发的用户故事大致翻译为"当直接借记从特定状态过渡到另一个状态(未预算到预算)时,请为顾问创建一个任务项"。有各种规则来确定"未预算"和"预算"的含义。
目前,DirectDebit 类根本没有"状态"的概念,它是一个相当大的 DTO(有几个子对象 - 再次,所有 DTO),具有大约 1000 行验证逻辑来尝试确定它应该是什么形状。 企业对直接借记可能处于的不同状态有"清晰"的概念,我相信该域名足够丰富,可以保证域名模型。
直接借记应用程序服务有一个"保存"方法,该方法传入更新的直接借记(从 UI)。该方法从存储库中获取现有的直接借记,完全忽略它,对更新的直接借记对象运行"验证",并将其保存到存储库中。然后,该方法审核旧直接借记对象和新直接借记对象之间的更改。
我试图摆脱这里开始发展的类似CRUD的怪物,并向团队展示他们如何开始重构它。
理想情况下,我想开始重构域对象以使用 State 模式,使用良好的封装,也许使用 Domain Events 来冒泡状态已更改的事实。 应用程序层将具有一个名为"CreateTaskWhenBudgeted"或类似内容的域事件处理程序来解耦逻辑。
我的问题是源自UI的大型"保存"直接借记方法。
是否有任何策略可以分解/重构这种方法?没有简单的方法来判断"更改"了什么,因为没有一个明确的命令正在发生。 或者,我应该继续增加混乱并忽略我认为是一个问题......?
以下是应用程序服务的精简版本:
public void SaveDirectDebit(DirectDebit directDebit)
{
directDebit.Validate(false);
var beforeDirectDebit = _directDebitRepository.FetchDirectDebit(directDebit.ExpenditureId.Id);
_directDebitRepository.SaveDirectDebit(directDebit);
var afterDirectDebit = _directDebitRepository.FetchDirectDebit(directDebit.ExpenditureId.Id);
var accountAuditLog = CreateDirectDebitAudit(beforeDirectDebit, afterDirectDebit);
_auditLogRepository.CreateAudit(accountAuditLog);
}
一种方法可以做到这一点(好方法与其他方法相比),您有多个参数(时间,复杂性......
由内而外的方式
免责声明:遗留代码越庞大,这种方法似乎就越难以实现(对我来说成功的条件:你不应该是唯一关心这种重构的人)。
-> 保存到数据库是一个技术问题。你必须首先引入一些无处不在的语言,使隐含的明确,并能够引入概念和进行设计(创建边界和单独的上下文)。
另一种方式
另一种方式是我在评论中开始描述的,对我来说,它与 Eric Evans 所说的"气泡上下文"有关,当你被遗留系统包围时,从一个干净的小有界上下文开始更容易。这种隔离将帮助您应用比现有系统更好(不同)的设计。