静と動の往還としてのモデリング

DCIを参照しつつ「業務分析」について考える

はじめに

最近「アジャイル」という言葉をなるべく使わないようにしています。なぜなら、この言葉に込められた「桃源郷へのあこがれ」が、色々なものを見えなくしてしまうような気がするから*1。例を挙げましょう。アジャイルの基本は、「タイムボクシングによるインクリメンタルかつイテレーティブな開発」であると言え、それを実現するために流派によって様々なテクニックが提示されます。Scrumを見てみましょう。Scrumを実現するために絶対的に必要なのは、プロダクトオーナーによって適切に優先順位付けされたプロダクトバックログなわけですが、網羅性と整合性を保証したかたちでバックログアイテムを優先度順に並べるって、実はものすごく難しいことを言っていませんか? 確かにタイムボクシングによる軌道修正がある程度できるとは言え、「優先順位の低いところは粒度が粗くてもいいよ」で先々問題が起きないとは、私にはどうしても思えないのです。どんなにプロダクトオーナーが先を読んでいても、どれほどチームが優秀でも、プロダクトオーナーとチームとの間で最終的なアーキテクチャが共有されていない限り、コードが先々の変化に耐えられるかたちになっているとはどうしても思えない。


逆に言えば、網羅性と整合性が保証されたかたちでプロダクトバックログなり機能一覧なりが整備されていて、それを実現するためのアーキテクチャが定まっているのであれば、「それは、もう真っ当にウォーターフォールをやってもうまくいくのでは?」という気もします。しかも、継続的デリバリーのようなテクニックをウォーターフォールでは使えないかというと、それはまた別の話。


こうして見ると、アジャイルウォーターフォールかという区別は「アップフロントでの作業云々」ではなく、「何を固定するか」という話と社内事情とを照らし合わせたときに出てくる解ととらえるとすっきりします(これもよく言われることではありますが)。つまり、自社メンバだけで開発するという前提ならリソース固定(アジャイル)にならざるを得ないし、「どうしてもこの日までにこの機能を」というのがお客様のビジネスにとって必要なら、リソースのスケールアウト戦略(ウォーターフォール)を考える必要が出てくるでしょうし。


前置きが長くなりましたが、こうしたことを踏まえて、いずれにせよ必要になるであろう「アップフロントな分析・設計作業」が本エントリの主題です。

ソフトウェアをデザインする

業務を分析してソフトウェアを設計する作業は、抽象度をコントロールしながらシステムのモデルを作り上げていく作業です。どういうものを書かなければいけないかは、教科書を見ればいくらでも出てきます。業務フロー、機能一覧、ER図、画面遷移図、入力チェック仕様、データアクセス仕様、クラス図、シーケンス図 etcetc・・・。このとき重要なのは、こうした複数のモデルが、1つのシステムの別々の側面を記述しているものであること。つまり、モデル1つ1つが、明確につながっていなければならないということです。このつながりが見えているかどうかが、設計の整合性と網羅性に決定的な影響を与えます。


このつながりを考える上で、大きなヒントを与えてくれるのがDCIアーキテクチャです。

システムが「どのようなものか」/「何をするのか」

DCIの根底にある考え方を簡単におさらいします。DCIでは、人間がシステムをとらえる際には「システムがどのようなものであるか」と「システムが何をするか」の2つから考えているとします。その上で、オブジェクト指向のことを、後者を表現することには長けているが、前者をうまく表現することはできないと批判します。さらに、「人間のメンタルモデルを表現する」というオブジェクト指向の理念に従い、この「システムが何をするか」と「システムがどのようなものであるか」という異なる位相で重なり合う2つの軸を表現するために、ロールという概念が導入され、実装のためにScalaのTraitが提示されます(詳しくはこちら)。


これを実装の話としてだけとらえてしまうと、実務で使うにはちょっと怖い感覚があるのですが、システムを「どのようなものか」と「何をするか」という2つの軸でとらえるという発想は、システムをデザインする上で大きなヒントを与えてくれます。この軸は「構造とふるまい」であり、「静と動」であり、「空間と時間」でもあるのです。

静的なモデルと動的なモデル

業務分析の入り口は、ユーザーの動きです。システム以前に、ユーザーが何をするのかがまず問題になるということですね。これを表現するためのテンプレートとしては、業務フローやユースケース、あるいはユーザーストーリーなど、そのコンテキストに応じて適切なものを選択すればよいですが、表現したいのはユーザーがシステムで何をしたいのか、それを踏まえてシステムは何をしなければならないのか、という動的な側面です。


動的なモデルは時間軸を含むため、単一のモデルで全体を表現することができません。したがって、ソフトウェア全体を俯瞰するためには、つまり「システムがどのようなものか」をとらえるためには、時間軸を無視して全体を一枚に表現する静的なモデルが必要となります(Copeであれば、空間的という表現を使うでしょうか)。それは、ユースケース図かもしれないし、機能構成図かもしれないし、ER図かもしれない。どのかたちに落とすのが適切かは、先行する動的モデルの性質と精度によるでしょう。静的なモデルを引くことにより、先行する動的なモデルの検証も行うことができます(「これがあるということは、こういうこともしないといけないですよね?」)。


こうして出来上がった静的なモデルは、今度は動的なモデルによって検証されることになります。静的なモデルの構成要素が登場するインタラクションを時間軸を導入しつつより具体的なレベルで分析することで、必要な要素が抜けていないか(網羅性)、構成要素に矛盾がないか(整合性)といったことを検討できるのです(「これをやるためには、こういうものも必要ですよね?」)。


このとき重要なのは、「動的」という言葉が時間軸を含んでいるということです。たとえば、「メッセージング」のような概念はそれ自体が動的であるかのように思えますが、単純に2つの構成要素間でメッセージングが行われていることを示しているだけなら、それは静的なモデルです。コンテキストを限定し、時間の流れとともに何が起きるのかを追跡するのが動的なモデルだということです。


こうして、全体像とその動き(静と動)をクロスチェックしながら、抽象的なところから具体的なところに落としていくことで、その作業の結果が設計成果物となっていくわけです。

プログラムをデザインする

こうした静と動の関係は要件定義フェーズだけに限定されるものではなく、成果物の抽象度が詳細レベルまで落ちてきても本質的には変わりません。たとえば、ER図の妥当性は最終的にはSQLを設計する際に検証される、ということです。プログラムの設計の場合にはどうかと考えると、ここにはSteve FreemanとNat Pryceの提唱している「モックを使ったTDD」がうまく当てはまります(「モックを使ったTDD」について詳しくはこちら)。


「この入力に対してはこの出力が返される」という仕様は静的なものです。モックを使ったTDDの場合、実装時にはユニットテストコードを書きながらオブジェクトとコラボレーターとのインタラクション(動的)を規定していきます。テストコードがグリーンになったら、今度はコードを静的な構造としてとらえ直し、コラボレーターとしてのインターフェイスを実装したクラスの配置をリファクタリングします。ここではTDDのサイクルが、静と動との往還と一致しているのです。

まとめ

「システムがやること」と「システムのあり方」あるいは「静/動」という概念を軸に、設計について考えてきました。最後に、ドメイン駆動設計について少し触れておきたいと思います。『エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)』の中で登場するのは、ほとんどがエンティティ同士の関係を示す静的なモデルです。しかし、これらの静的なモデルを作り上げる過程では、シナリオの中でそうしたエンティティがどう動くのかという動的な側面が、顧客との対話の中で考察されていることが読み取れるでしょう。


事実、DDDを行うプロセスとして現在エリックが整備している「モデルを探究するうずまき*2では、動的な要素としてのシナリオと、静的な要素としてのモデルとの往還関係を繰り返しながらモデルが進化していくとされています。


Copeが「アーキテクチャ」という言葉を使うときには、システムをとらえるためのこうした大きな枠組みが含まれています*3。こうしたアーキテクチャに対する思考は、アジャイルであれ、ウォーターフォールであれ、ある程度はアップフロントに行うべきものだと思うのです。

*1:にも似たようなことは書いた気がしますが

*2:以前、こちらのエントリで少し整理しました

*3:Alexanderの思想を受け継いでいる彼の場合、実際にはそれをも超えて、人とシステムとのかかわり全体(バリューストリームと呼ばれるもの)までが視野に入っているのですが