プログラマが知るべき97のこと/ドメインの言葉を使ったコード


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

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進数をそのまま扱うことが出来ないからです。このため、何種類かの浮動小数点型を使い分けるということをしてきました。その後、配列や文字列(文字列も正確には配列の一種)、さらにスタックやキュー、ハッシュ、リンクリスト、スキップリスト、その他にも現実世界には存在しないような面白いデータ構造が加わりました。コンピュータサイエンスの世界は、現実世界を制限のあるデータ構造にどう対応付け表現するのかという問題にずっと取り組んできました。真のベテラン技術者なら、取り組み歴史がどのようなものだったのかを語れるでしょう。

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

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

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

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

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