関心の分離

関心の分離とは、ソフトウェア工学においては、プログラムを関心毎に分離された構成要素で構築することである。

プログラミングパラダイムは開発者が関心の分離を実践することを手助けするものもある。その為には、モジュール性とカプセル化の実装のしやすさが重要となる。

関心の分離は複雑で依存関係が入り乱れたシステムの理解・設計・運用を容易にすることが出来るので他の工学分野でもみられる。

1. 歴史
-----

「関心の分離」を意味する英語「en」は、エドガー・W・ダイクストラが1974年に論文「en」で初めて使用したとされている。1989年にChris Reade が「en」というタイトルの書籍で関心の分離を説明している。

2. 例
----

関心の分離の例として構造と見た目の分離がある。

2.1. React: ライフサイクルメソッド/時間的凝集とhook/機能的凝集
----------------------------------------

以降、ReactというJavaScriptライブラリでの例を挙げる。このライブラリには、ライフサイクルメソッド という考え方を持っている。ライフサイクルメソッドがもたらした機能的凝集度の低さをhookによって克服し、SoCを実現している。

ライフサイクルメソッドは周期のある時点で自動的に呼び出されるメソッドである。例えばコンストラクタはインスタンス作成時のメソッドであり、onMemberChangedメソッドはメンバ更新時に毎回呼び出されるメソッドである。ライフサイクルメソッドとして時間的に適切な処理を実装すれば、ある時点でおこなわれる処理が一か所に集約され時間的凝集度が高いコードになる。

例えばタイマー2つによるカウントダウンUIを考える。ライフサイクルメソッドを利用する場合、開始時でcount変数を用意し、UI作成時にタイマーをセットし、レンダリング時にカウント表示を更新、UI破棄時にタイマーを破棄する。 class Clock extends React.Component { constructor { super; this.state = { countA: 0, countB:0 }; }

componentDidMount { this.timerIDa = setInterval => this.tickA, 1000) this.timerIDb = setInterval => this.tickB, 1000) }

componentWillUnmount { clearInterval; clearInterval; }

tickA { this.setState; } tickB { this.setState; }

render{ return

now count: A/{this.state.countA} - B/{this.state.countB} } }<WtXmlEndTag />ある時点で何が起きるかが一見してわかる一方、機能的に見ると一連の処理を時間ごとに別の関数に切り出していることになる。また1つのサイクルメソッドの中にタイマーAの処理とタイマーBの処理が混在することになる。このようにライフサイクルメソッドを用いたコードは時間的凝集度が高くても機能的凝集度は低いといえる。そこでReactでは機能的凝集度を高めるhookと名付けられた機能を導入した。hookはライフサイクルメソッドのようなclass interface実装ではなく、関数の暗示的状態を利用している。コンポーネントあたり1つしか持てないライフサイクルメソッドと異なり、関数であるhookは何度でも利用ができる。また各hook関数が状態の保持やライフルサイクルの管理といった個別機能を持つため、機能Aに必要なすべてのhookを1箇所に集めることができる。すなわち機能的凝集度が高い状態、機能的なSoCが実現できる。 function Clock { // Timer A ///////////////////////////////////////// const [countA, setCountA] = useState; useEffect=>{ const id = setInterval => setCountA, 1000); return => clearInterval }, []); // Timer A /////////////////////////////////////////

// Timer B ///////////////////////////////////////// const [countB, setCountB] = useState; useEffect=>{ const id = setInterval => setCountB, 1000); return => clearInterval }, []); // Timer B /////////////////////////////////////////

return

now count: A/{countA} - B/{countB} }<WtXmlEndTag />
"It can take input from the user and display information, but it should not manipulate the information other than to format it for display." p.96

3. プレゼンテーションとドメインの分離
--------------------

プレゼンテーションとドメインの分離は「ユーザーインターフェースコードをその他のコードを分離する」という設計原則である"Separating User Interface Code" p.96 }}"separation of presentation and domain" p.97 }}"refer to the user interface code as //presentation code// and the other code as //domain code//." p.96 }}。すなわちソフトウェアをプレゼンテーションとドメインという2つの関心に基づき分離するという原則である"Presentation and domain are two separable concerns I’ve found" p.97}}"The general principle here is that of separating concerns" p.97}}。

関心の分離により様々な利点が得られる。

特定の機能に凝集したコードのみへの集中
分業と専門家の活用
UIモジュールの切り替え
ドメイン部分のテスタビリティ向上明確な分離が必要になるか否かはソフトウェアの複雑性に依る"For a simple set of pages, there is an overhead " p.97 }}。例えばデータがViewと完全に一致するのであればマッパーでSQLとViewを密結合に生成するライブラリが有用であろう"the tools don’t provide any place to extract the domain code. If straight updates to data and view are all you do, then this is not a problem. ... However, once domain logic gets complicated, it becomes hard to see how to separate it." p.97 }}。しかし複雑性が増すにつれプレゼンテーションとドメインを分離する上記の利点が大きくなる"as the set gets more complicated, the value of the separation grows." p.97 }}。

4. 関連項目
-------

凝集度
結合度

5. 参考資料
-------

[1]
[2]
[3]

6. 脚注
-----

de:Cross-Cutting Concern#Separation of Concerns