【11】ドメインの言葉を使ったコード

ダン・ノース(Dan North)

 たとえば、コードベースの中に、次のようなコードが見つかったとします。

if (portfolioIdsByTraderId.get(trader.getId())
    .containsKey(portfolio.getId())) {...}

 このコードを見ても、何をやりたいコードなのかをすぐには理解できずに思わず頭をかきむしる……。そういう人が多いのではないでしょうか。どうも trader オブジェクトから ID を取得して、その ID を使って「Map の Map」から Map を取得しているようではあります。その「内側」の Map に portfolio オブジェクトの ID が存在しているかを確認しているようです。portfolioIdsByTraderId の宣言部分が次のようになっているのを見れば、もっと頭をかきむしりたくなるでしょう。

Map<int, Map<int, int>> portfolioIdsByTraderId;

 だんだんわかってきました。どうやら、あるトレーダーが、あるポートフォリオにアクセスできるか否かを確認するためのコードのようです。そして、これから同じコードを(もっと言えば、ほとんど同じで実は細部が微妙に違っているようなコードを)あちこちで見ることになるのでしょう。たとえば特定のポートフォリオにアクセスできるかだけを確認するなどです。

 では、次のような書き方ではどうでしょうか。

if (trader.canView(portfolio)) {...}

 これなら頭をかきむしることはありません。「あるトレーダーがあるポートフォリオにアクセスできるか否かを確かめる」というコードだろう、ということはすぐにわかるし、その確認を具体的にどのようにするのかを知る必要はないからです。おそらく中では同じように「Map の Map」を扱うなどの面倒な処理が行われるのでしょう。そんなことは、こちらで考えなくても、trader オブジェクト任せにしておけば済むわけです。

 ここで問題なのは、読者が実際に扱うコードが、上の 2 つのうちのどちらに近いかということです。

 かつてプログラミングに使えるデータ構造は、非常に基本的なものに限られていました。ビットかバイトかキャラクタです(正確にはすべてがバイトだったのですが、表面上、文字や記号として扱うこともできました)。数値の扱いはやや面倒でした。コンピュータでは 2 進数が基礎となり、10 進数をそのまま扱うことができないからです。このため、何種類かの浮動小数点型を使い分けるということをしてきました。その後、配列や文字列(文字列も正確には配列の一種)、さらにスタックやキュー、ハッシュ、リンクリスト、スキップリスト、その他にも現実世界には存在しないような面白いデータ構造が加わりました。コンピュータサイエンスの世界は、現実世界を制限のあるデータ構造にどう対応づけ表現するのかという問題にずっと取り組んできました。真のベテラン技術者なら、取り組みの歴史がどのようなものだったのかを語れるでしょう。

 そして現在、私たちは「ユーザ定義型」というものを使うことができます。「そんなの知っているよ」と思うでしょうが、これが非常に大事なのです。ユーザ定義型が使えるか使えないかで状況はかなり変わるからです。ある分野(ドメイン)に「トレーダー」や「ポートフォリオ」といった概念が存在しているとすれば、それをたとえば TraderPortfolio という名前の型を定義してモデリングすることができます。さらに重要なのは、こうした概念間の「関係」も、ドメインの言葉を使ってモデリングできるということです。

 仮にドメインの言葉を使わずにコードが書かれたとすると、読む側には「一見してもわからないが、この int 型データは、トレーダーの ID を表し、でもあの int 型データは実はポートフォリオの ID を表す」というような「暗黙の了解」が必要になります。混ぜるな危険!、両者を混同してしまわないように細心の注意が必要ということです。また、何らかのビジネス上の決まり(同じポートフォリオでも参照可能なトレーダーと、法的に参照を許されないトレーダーがいる、など)を、ユーザ定義型を使わずにアルゴリズムで、たとえばキーの Map に関連が存在するのかどうかで表現した場合には、監査やコンプライアンスの担当者には分かりにくいプログラムができあがるでしょう。

 プログラムに暗黙の了解の部分があると、他の人が見た時、それがわからずに苦労することになります。暗黙の了解の部分などは作らず、できるだけ明確にしておくべきでしょう。あるキーを手がかりに取得した別のキーを使って存在チェックをするというのは、明解だとはとても言えません。そんなコードを見て、すぐに「なるほど、このコードは利害衝突を阻止するためのビジネスルールの実装だな」などと直感する人はそういないでしょう。

 コードがどのような概念を表現しているのかは、できる限り一目でわかるようにしておくべきです。そうすれば、他のプログラマがコードを見る時に、いちいち「まず、必要な概念を理解してから、それに当てはまるコードを探す」などということをしなくても、何が書いてあるのかすぐに理解できます。また、ドメインモデルが成長した時に——あなたのドメイン理解が深まる度に——コードをそれに合わせて進化させることが可能になります。さらにカプセル化も十分ならば、特定のビジネスルールに対応するコードを 1 箇所に集中させることができます。コードを修正する際も、他のコードへの影響を心配する必要がないので、誰にも迷惑をかけずに修正ができるのです。

 何ヶ月か時間が経ってからコードを見たプログラマは、きっと最初にコードを書いた人に感謝するでしょう。そしてそのプログラマは、最初にコードを書いた本人かもしれないのです。