层层叠叠!注意事项。

作者:Harry,2020-08-13

在书中,我们不厌其烦地指出,每种模式都是一种权衡,并且都伴随着成本。但以防万一还有人没理解我们的意思,仍然认为我们是在说所有应用都应该这样构建,我想我应该写一篇小博客文章,再次强调关于成本的信息。如果你一直有冲动将每一种模式都像“货物崇拜”一样盲目地应用到每一个应用中,那么这篇文章应该能让你打消这个念头。

每次你增加一个层,你都会获得一些解耦,但这会以增加一个额外的活动部件为代价。简单来说,就是你必须维护一个额外的文件。

a recap of all the layers + parts of our architecture
以下是我们架构中所有层和部件的概括

是这样的。很久以前,在我刚加入 MADE 的时候,我记得需要对购买团队使用的一个应用做一个简单的更改。我们需要为每批货物记录一个额外的信息,一个可选的“延迟”字段,用于某些 ETA 计算。这是一个很好的例子,说明了贯穿整个技术栈的旅程,因为从前端/UI 一直到数据库,所有层级都需要进行更改。

如果你使用像 Django 这样的框架,你可能已经习惯于将这样的更改视为在理想情况下只需更改一个文件。你只需更改 models.py,然后你的 ModelForm 将会自动更新,甚至前端也可能“直接工作”,如果你使用表单的自动生成的 HTML。这就是 Django 作为快速应用开发框架如此出色的原因之一:通过紧密耦合其各个部分,它可以为你节省大量处理数据库表、html 表单、验证等等的时间。如果这些是你花费时间的主要事情,那么 Django 将为你节省大量时间。

但是在我们的世界里(至少在理论上 *),数据库表和 html 表单不是我们花费时间的地方。相反,我们希望优化的是捕获和理解业务逻辑,因此我们希望解耦事物。

这会带来什么成本?好吧,让我们回顾一下我在对我们应用的数据模型进行非常小的更改时必须修改的每个文件。

  1. 我首先编辑了一个前端的 selenium 测试,加上一个 javascript 前端测试,加上前端 javascript 本身,以及一个 html 模板。这已经是四个文件了,但它们与我想说明成本的模式和层严格来说并不相关,所以我要说它们不算数。如果你认为我在作弊,别担心;后面还有很多。

所以

  1. 针对相关对象的创建和编辑用例的端到端 / API 测试
  2. 捕获用户可以对该模型进行的写入交互命令类
  3. 我们用来验证传入请求命令模式
  4. 实例化这些命令以测试其处理程序的服务层测试
  5. 服务层编排这些用例的处理程序
  6. 受影响的领域模型测试。尽管并非每个领域模型都需要低级别的单元测试以及服务层测试,所以如果我放纵一点,我可能不会算上这个。但碰巧的是,在这种情况下,我们确实有一些低级别的测试。
  7. 领域模型本身
  8. 仓库集成测试(仓库和数据库相关内容在第 3 章中)
  9. 仓库和 ORM 配置
  10. 数据库模式
  11. 一个迁移文件(诚然是由 Alembic 自动生成的,但我们喜欢在提交之前稍微整理一下)。
  12. 捕获各种受影响用例的持续内部 / 外部后果的事件类
  13. 我们用于(出站)验证事件模式文件。
  14. 但这还不是全部!因为这个应用使用了CQRS,读端与写端是分离的,所以我还必须更改一些 API JSON 视图测试
  15. 以及 CQRS JSON 视图代码

所以总共是十五个文件。十五个!就为了添加一个字段!

现在我应该补充一点,每次更改都非常简单。大多数更改都是复制粘贴一行和一些查找+替换。整个工作可能花费了一个小时左右。但是,如果你习惯于这种事情只需要五分钟,并且在一个或最多几个文件中完成,那么当第一次面对所有这些层时,你肯定会开始质疑整个工作的合理性。我知道我肯定质疑过。

我们认为我们在这里强加给自己的成本是值得的,因为我们相信,我们希望使其变得容易的主要事情不是添加数据库字段和 html 表单。我们希望使其更容易在领域模型中捕获复杂且不断发展的业务需求。但是,正如我们试图在每一章中说的那样,你的情况可能会有所不同!

好的,理论上是这样。在实践中,我认为这个特定的应用有点过度设计了。它是团队首次完全自由尝试新模式的应用之一,他们可能有点用力过猛... 但另一方面,现在有讨论将该应用转换为事件溯源,并且由于所有这些层,这将相对容易。相对容易。