イベント - 要求分析駆動設計
参考書籍一覧(Amazon アソシエイトリンク)
Entityの操作の中で条件が満たされ、メールを送信したかったり、他のサービスにメッセージを送りたい場合がある。 こういう場合はEntityの操作の後に、条件が満たされたかをUseCase内でチェックすれば要件は満たせる。
entity.command
if entity.notify_to_user?
# ユーザーに通知する処理
end
しかし、この場合、ユーザーに通知する内容をUseCaseで組み立てるか、entityに取得するメソッドを定義しなければならない。 また、条件が満たされた瞬間に存在する情報を通知内容に含めたい場合、entityに保持し続けるようにインスタンス変数を追加しなければならなくなる。
こういった問題を避けるために、イベントという方法がある。 Entityのレイヤスーパータイプを以下のように定義し、Eventクラスを用意していく。
class EntitySuperType
def add_event(event)
return if event.blank?
events << event
end
def events
@events ||= []
end
end
class NotifyToUserEvent
attr_acessor :message
def initialize(message)
self.message = message
end
end
# アクションイネーブラのビジネスルール
class SameRule
def notify_to_user_event(message)
return if condition # 条件が満たされていなければイベントを返さない
NotifyToUserEvent.new(message)
end
end
class SomeEntity < EntitySuperType
def command
# ...
# ユーザー通知の条件が満たされていたら、eventを追加する
add_event(SameRule.new(...).notify_to_user_event('メッセージ'))
end
end
class SomeUseCase
def method
# ...
some_entity.command
some_entity.events.each do |event|
if event.is_a?(NotifyToUserEvent)
# ユーザーに通知する処理
end
end
end
end
この実装例は、EventをためてUseCaseに戻ってきたタイミングでEventを処理する方法をとっている。 普通のイベント処理ではイベントが発生したタイミングでハンドラが呼ばれるが、大半のシステムではそのような仕組みを構築するのはオーバーエンジニアリングだろうし、単純でわかりやすい形をとった。 イベント発生から処理されるまで遅延が発生することで問題がおきるなら、Observerパターンなどでイベントの発生したらすぐに処理する仕組みを構築すれば良い。
正直なところ、あまりドメインイベントを理解できているとは言い難いので、必要なら実践ドメイン駆動設計の「第8章ドメインイベント」を参照して欲しい。