対比図:ドメインモデル貧血症をおこしたモデルたちと、DDDな作りのモデルたち
少し前にリファクタリング界隈(?)で話題となったと思われる技術記事『Refactoring from anemic model to DDD』。変化に弱いMVCな作りなコードを、DDDな作りへと作り変えていく実践記事となっている。
前提となるのは、いわゆるドメインモデル貧血症をおこしたモデルたちとDDDな作りのモデルたちを対比した以下の図。
(図が描かれた背景) : Some time ago during one of our internal DDD learning group meeting I was wondering what is the best way to show differences between writing an application with an anemic model and application with applied concepts of DDD. I came up with a drawing which illustrates these two types of application.
出典 Domain-Driven Design vs. anemic model. How do they differ?
これらの一連のブログは、技術ブログにしては相当な評判だったよ、と著者はお茶目に誇っている。
リファクタリングの《羅針盤》に分かりやすい名を記したい。
世にリファクタリングが必要なシステムは数多い。リファクタリングに取り組む人々は、銀の弾丸はないと重々承知の上で、よりべとなる羅針盤を求めている。私は、ドメイン駆動設計(DDD)、マイクロサービス化、クリーンアーキテクチャなどに、羅針盤の役割を果たしてほしいと思っている。
私は、最近、anemic model(貧血モデル)な作りの典型と思われるシステム(web系)のコードをがっつりと見ることとなった。そうしたシステムにありがちな話だが、ユーザー要求を実現するための改修のベロシティを上げづらく、謎の不具合も生じてしまっている。そう、ビジネスロジックがDAO(データアクセス用オブジェクト)などに入り込んでしまっていて、コードを書き換える際の影響範囲がやたらと広く、かなり読みにくいといった類の「闇落ち系」の技術的負債だ。
さぁ、リファクタリングだ、といきたいところだが、どうやらリファクタリングにまとまった時間を取ることは難しいようである。合間合間のリファクタリングで少しずつ技術的負債を返して行くことになるとして、まずは、チームとしての取り組みの方向性を固めておきたい。
どうしたものかと思ううちに、ふと、「バグをドラゴンと呼ぶ」いう記事(『組織で技術的負債に立ち向かうための取り組み』)を目にした。
そう、チームが目的を見失わないよう、ターゲットに分かりやすい名前を与えることは重要だ。私は、冒頭で引用した対比図は簡潔で良いと思っているのだけれど、用語が頭に入りにくい。ドメイン駆動設計界隈では、シンプルな単語(entity, value, object, humbleなど)にはけっこう奥深い意味があり、抽象用語(aggregateなど)や略語(CQRS;Command Query Responsibility Segregation)もそこそこ多い。そのため、ドメイン駆動設計を羅針盤に用いるリファクタリングにあたっては、チームのひとりひとりが特有の用語法を少しずつ噛み砕いていくことが必要となる。
ドメイン固有の"Aggregate"へとリファクタリング
さて、改めてクリーンアーキテクチャの図を引用し、上の図を見比べておこう。
上の図におけるDAOの問題は、クリーンな作りでは、ユースケース層・アダプター層に書かれるべきロジックが特定のフレームワーク(例、Ruby on RailsでのActiveRecord、PlayFrameworkでのslickなど)を扱うDAOのコードと混在していることである。こうした混在は、テストを困難にする。
そのため、リファクタリングにあたっては、DAOなどの外層(城外)のコード書き込まれたロジックを、Repository,Entity, ValueObjectなどのコードへとクリーンに書き換えて、ユースケース層、アダプター層という『城内』に再配置することになる。
これにより、Entity + ValueObjectという作りのAggregateにドメイン固有の作りが集約されていくことになる。
- (参考)ドメイン駆動設計におけるAggregateの実装の羅針盤(チェックシート)の例
Aggregateが大事なのは分かったとして、用語としてちょっと扱いにくい。特に、Aggregateが大事という物言いに、ビジネスインパクトの観点が全く感じられないのは、かなり痛い。
"Aggregated objects"のうち、最重要なものを《ヘビーオブジェクト》と名付けてみる。
ドメイン駆動設計の重要タームの一つAggregateが用語として扱いにくい要因は、ビジネス上のトランザクションの単位としての"Aggregate"、"Aggregate Root"といったモデリング上の概念、さらには、"aggregation"というデザインパターン上の概念など、多義的に用いられるためである。
"Let's aggregate!"といった標語は、チームの目標として壁に貼っておいたとしても、いささか抽象的だ。
貧血モデルで闇落ちしつつあるシステムをドメイン駆動設計の手法を用いてリファクタリングする際に、ユースケース層の"Aggregate"に含まれる、他のサービスとの差別化を行うためのコードの品質はリファクタリングの際の最優先目標となる。言い換えると、集約オブジェクト(Aggregate objects)の中には、開発プロダクトの成否を分ける、ビジネス展開上の最重要オブジェクトが含まれる。最重要の成果物には、もっと戦略目標っぽい名前を与えたいものだ。
そこで、以下のように図にメモを加え、リファクタリングの最重要の戦略目標としての"Aggregate"を《ヘビーオブジェクト》と呼ぶことにしたい。
そう、この用語の下では、チームは、ビジネスモデルを実現するための固有のユースケースを《ヘビーオブジェクト》として着々と作り上げていくことになる。
この《ヘビーオブジェクト》は、抽象化されたロジックのコードからなる。具体的なデータベースへのアクセスコードなどは含まれないため、たとえコード量が増えたとしても、集約オブジェクト(Aggregate objects)と同様に、改修時の他の単体テストは比較的容易である(すなわち、状況の変化に強い)。
こうした概念を現すのには、《ヘビーオブジェクト》方が、"Aggregate"より分かりやすいと、自分は思った。
《ヘビーオブジェクト》をちゃんとメンテし続けるために。
《ヘビーオブジェクト》が戦略目標だとイメージしやすくするためには、とりあえず壁にこれあたりを貼っておくのでしょうか?
ここまででかいとモノリスっぽいけれども。
出典 ヘビーオブジェクト紹介
チームにとっての《ヘビーオブジェクト》は、以下の抽象概念だけれどね。
さて、最後に、こうした《ヘビーオブジェクト》をきちんとメンテし続けるために、設計と実装に携わるメンバーには何を心がけると良いのだろうか、と自問しておく。もちろん、既存のコードの意味を理解し、参考となるコードのチェックを怠らず、そして、ドメイン駆動設計の本も積読し、というのが優等生的な回答である。たけれど、集約オブジェクトが属するユースケース層の実装が特定のアーキテクチャ(webかクラサバか,など)に依存しないことを忘れてはならない。併せて、全然別分野であっても、気合の入った集約オブジェクト、特にサービスの差別化要因となる《ヘビーオブジェクト》の実装に触れ続け、刺激を受けることが大切なことなのだと思う。興味がわく、しっかりとした実装ならば分野は問わない(ということで、今しばらくは、個人的にはGoogleの怪作なクロスプラットフォーム開発プラットフォームFlutterの《ヘビーオブジェクト》Widgetを追いかけてみることにする)。
あと、実務的には《ヘビーオブジェクト》のコーダーとしては、散らばってしまったDAOたちを、システムを下支えするhumble objectへと丁寧に作り変えていく大切だね。頑張れ、整備兵。ドラゴンという名の敵兵(バグ)を倒し続けるのだ。