時間的な結合度とふるまいにおける結合度 - Ian Robinson
この記事はIan Robinson氏の記事「http://iansrobinson.com/2009/04/27/temporal-and-behavioural-coupling/」の全文を、氏の許可を得て翻訳したものです。
私はこれまでに幾度となく開発者やアーキテクトの人たちと仕事をし、分散システム設計時の選択に関する性質やその帰結について理解する手助けをしてきました。そこで有効な議論を形作るために見いだした方法の一つが、結合度(“coupling”)の問題、特に時間的な結合度("Temporal coupling")とふるまいにおける結合度("Behavioral coupling")の結果として生じる問題に目を向けることでした。
ホワイトボードに見当外れなことを書いてしまう傾向に抗う技術者なら誰でも、少なくとも1つは「魔法の象限」図をつくらなければいけないものですが、私にとってはこれがそうでした。下に示す結合度マトリクスです。残念ながら、キャリア形成に役立つほどの、アーキテクチャにおける銀の弾丸ではないのですが、この図は既存のソリューションが持つある部分を特徴づけ、将来なされる決断のための方向性を思い描く際の助けになるでしょう。またそれだけでなく、諸々の制約(妥当なものであれ、不注意から生じるものであれ)について理解する助けにもなると思います。そういった制約は、設計においてどのような選択肢があるのかということをある程度決定づけるものなのです。
まずはこれら2種類の結合について簡単に概観します:
時間的な結合度
時間的な結合度とは、メッセージの送信と処理とが時間的に結びついている度合いを指しています。もしメッセージの送信側が、メッセージが送られた時間に受信側を利用できるかどうかということに依存するのであれば、時間的な結合度が強いことになります。サービスのプロバイダを利用できなければ、やりとりは失敗します。プロセスの中で、アクティビティが厳格に順序付けされているものや、先行するリクエストに対するレスポンスが受信されるまで、後続のアクティビティが開始できないようにして結果を繰り越すようなものは同じように時間的に密結合しています。時間的に密結合な状況においては、メッセージの処理を行い、レスポンスを返すのにかかる時間は、送り手側の処理時間に影響を与えます。
ふるまいにおける結合度
ふるまいにおける結合度とは、送信側と受信側が、どうふるまうかという点に関する前提をどの程度共有しているかということです。ふるまいとは、より明確に言うならば、どのアクションが実行され、そしてそれがどのように実行されるのかを決定するという2重の責任を、分散された相互作用の参加者に対して割り当てた結果のことを指しています。ふるまいにおける結合が極端に密であるシステムでは、メッセージの送信側が何をすべきかを決定し、同時に受信側がどのようにその要求を満たさなければならないのかについても、何かしら知っています。こうした結合が典型的に示されるのは、例えばデータベースの外部キーであったり、コレクション型のようなプラットフォームに依存するものがメッセージや操作に影響しているような場合においてです。メッセージの送信側が何をするのかを決定し、受信側が送信側の要求をどのように満たすのかを決定する場合でも、両者は同じようにふるまいにおける密結合を示しています。受信側だけがメッセージに対して何をどのようにするのか決定するのであれば、送信側と受信側はふるまいにおいて疎結合であると言えます。ふるまいにおいて密結合である場合、サービスのプロバイダはコンシューマの要件が変更するのに合わせてサービスの提供内容を進化させなければなりません。
では、各象限の特徴について簡単に概観します:
分散3階層
伝統的な3階層アプリケーションアーキテクチャは分散した各部分にまで至り、コールスタックのような、命令的なふるまい(時間的にもふるまいにおいても密結合なもの)と、同期したリクエスト−レスポンスのやりとりによって特徴付けられます。これには、非同期メッセージ通信の最上層において階層間の同期通信を行っているシステムも含まれます。送信側が受信側に何をすべきかを伝え、受信側は送信側の命令を実行します。送信側とすべての中継地点はコールスタックが解放されるまでブロックされますが、その際には効果的にロックが行われ、同時に(あるいは)コールチェインの先端に至るまでのシステムリソースを消費します。このようにブロックを行うふるまいは上層のコンポーネントの自律性を掘り崩し、同時に下層のコンポーネントの可用性に対する要求を増大させます。Michael Nygards氏の「Release it!」が思い出させてくれるように、このような状況下ではシステム全体の可用性は、その中で最も低い部分を越えることが無く、障害が発生する可能性は、すべてのコンポーネントないしサービスが障害を起こす可能性を合計したものとなります。
コマンド指向
「優れた」「正統派」のSOAがこれにあたります。時間的な結合度の弱さは、非同期の連携、延期された状態とレジュームが可能なプログラミングモデルによって特徴付けられます(リソースを無駄にしないため、プロセスやアクティビティのインスタンスはリモート呼び出しの間には退避(“dehydrated”)され、レスポンスに応じて復元(“rehydrated”)されます)。典型的には、送信側は何がなされる必要があるかを決定しますが、その指示をどのように実行するかを決定するのは受信側に委ねます。このふるまいにおける結合度のせいで、サービスのプロバイダは、コンシューマの要求が変更されるのと歩調を合わせて進化(メッセージのフォーマットやサポートする操作など)しなければならないかもしれません。
イベント指向
時間的にもふるまいにおいても疎結合なものです。受信側がメッセージの内容に応じて何がなされる必要があり、どうやってそれを行うのかを決定します。これはレジュームが可能なプログラミングモデルです。つまり、プロセスはイベントを待つ間、一時停止するか退避されます。トランザクションやアクティビティが実行された経過を最初から最後までトレースするのは難しいかもしれません。イベント終了(“ExtinguishFire”)の操作を提供するのは、ビジネスプロセスを実行する上でのコマンド指向的なやり方です。イベント開始(“FireStarted”)通知に対して動作するのがイベント指向のアプローチです。
エマージェンシー・サービス
このように呼ばれるのは、あなたが相手に何が起こったのかを伝え、相手が何をするのかを決めるからです。しかし、電話を受ける相手がいなければ、あなたは待たされてしまいます。ふるまいにおける疎結合によって、システムのコンポーネントはそれぞれ独自に進化することができますが、時間的な結合の度合いは各コンポーネントの可用性に対する要求に影響を与えます。多くのRESTfulなソリューションがここに該当します。URI形式のソリューションはハイパーメディア駆動のソリューション(これはクライアントは次に何ができるかということをサーバが制限し、ガイドするやり方であり、同時に、どうすればリクエストを最も良い方法で満たせるのかということもサーバが決定するものです)よりも、ふるまいにおける結合度が強くなります。ただし、クライアントにおけるポーリングやキャッシングによって、時間的な結合度の問題を緩和できるかもしれません。
後注
こういった結合度の問題は、多くの開発者やアーキテクトが理解しているものではありますが、それは特定の権威や出自を持たない一般的な知識によって成り立っています。それに対して私がやりたかったのは、Bill Pooleが書いた素晴らしいエントリの一つである「Avoid Command Messages」に読者の目を向けることでした。少し前のことですが、私自身、このエントリのおかげで、ふるまいにおける結合度に注目することができたのでした。