xfyuan
xfyuan A Chinese software engineer living and working in Chengdu. I love creating the future in digital worlds, big and small.

领域驱动,必有勇夫

领域驱动,必有勇夫

本文已获得原作者(Jorge Manrubia)和 37signals 授权许可进行翻译。原文描述了在领域驱动设计中,对于如何选择代码“遣词造句”的思考。

【全文如下】

引言

如何创建一个好的领域模型是许多书籍的主题,但我从 37signals 学到的是:不要保守,加倍大胆。

正文

当我三年前在 37signals 开始工作的时候,最先做的事情里,其中一件是把 Basecamp 的 git 代码库 clone 下来。我探索了一下,最后看到了这个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module Person::Tombstonable
  
  def decease
    case
    when deceasable?
      erect_tombstone
      remove_administratorships
      remove_accesses_later
      self
    when deceased?
      nil
    else
      raise ArgumentError, "an account owner cannot be removed. You must transfer ownership first"
    end
  end
end

这表示在 Basecamp 的一个 person 有一个 delegate type attribute,代表它的特定类型(比如,User 或 Client)。当你从给定 account 移除一个 person,Basecamp 就用一个占位符替换它,这样它所关联的数据就保持不动且功能不受影响。

那时我很熟悉 Domain-Driven Design 和代码重构领域概念的重要性,但还从未见过其理论如此有意地被用于实际。我本来预计的写法是在移除时用一个占位符来替换一个 person 之类的东西,但在一个 person “死亡”时“竖起墓碑”的用词显然要好得多。

从客观的角度,这种用语更传神、清晰和简洁。从主观的角度看:它有了一个大胆的构成,犹如有了个性或者说灵魂。代码也可以有这样的东西吗?它可以,而且,如果做得好的话,这会是一个相当大的提升。对我而言,这是一个顿悟的时刻。

让我来展示另一个例子,HEY screening system。在内部,系统看起来类似于这样:users 检查发送邮件的联系人所请求的 clearance petitions【许可申请】。

img

再一次,我发现了大胆的构成。一个 petition 跟一个 request 是有区别的,因为它暗示了其正式性。HEY 中的 Screening 在设计上是很正式的:没有你的允许,别人不能获取你邮箱中的邮件。petitioner【申请人】的 clearance petition【许可申请】必须得到 examiner【审查员】的批准,这是一种向另一个人解释系统正在做什么的清晰方式,而这正是代码所映射的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Contact < ApplicationRecord
  include Petitioner
   
end

module Contact::Petitioner
  extend ActiveSupport::Concern

  included do
    has_many :clearance_petitions, foreign_key: "petitioner_id", class_name: "Clearance", dependent: :destroy
  end
   
end

class User < ApplicationRecord
  include Examiner
end

module User::Examiner
  extend ActiveSupport::Concern

  included do
    has_many :clearances, foreign_key: "examiner_id", class_name: "Clearance", dependent: :destroy
  end

  def approve(contacts)
    
  end

  
end

这种 concerns 的用法让我想起了 DCI architectural pattern 中的角色。DCI 是那些充满有趣想法的提案之一,这些想法往往不能很好地转化为代码。这种 concerns 的使用是一种非常实用的角色实现。

在构建一个非一般的模型时,我最喜欢的工具是写一个纯文本的描述。当我为 HEY 改进邮件分析系统时,给自己写了写了一篇关于新领域模型看起来怎样的笔记。如下所示,你可以看到这篇笔记(上)和我在系统构建完成的 PR 中所包含的描述(下)。笔记的内容与其准确性并不相关——对我来说,书写是一种思考工具——在思考复杂系统时,纯文本是一个绝好的起点。一本字典是做这种事情的好伴侣。

img

img

从第一个代码提交以来,HEY 和 Basecamp 都在领域驱动设计上下了很大的功夫。当然,这并不意味其每个角落都耀眼和完美,但总的来说,阅读它们的代码是一种乐趣。如何创建一个好的领域模型是许多书籍的主题,而我在这里学到的是:不要保守,加倍大胆。

Rating:

comments powered by Disqus