読書要点「プリンシプルオブプログラミング」第3章 アーキテクチャ根底技法


アーキテクチャ根底技法

アーキテクチャ根底技法とは、ソフトウェア・アーキテクチャ構築のための基礎原理で、モジュールの設計指針として示される。
多くの経験によって蓄積されてきた型のようなもので、10の技法がある。

抽象

抽象とは、概念的な線引きを行うことで、「捨象」「一般化」の2つの作業からなる。
複雑な対象から抽象した概念は、単純で無駄のない、扱いやすい概念となる。
そのため抽象は、複雑なプログラムに挑むときの効果的な道具となる。

捨象では、複雑な対象の持つ要素を捨て去る。
このことで本質的でない問題を視界からそらすことができる。
一般化では、複数の対象が持つ性質から共通項を抽出し、単純な概念へと昇華させることである。
捨象により本質的な情報を露見させ、一般化によって扱いやすい概念へと昇華させることで概念を抽象することができる。

カプセル化

関連性の強いデータとロジックをひとまとめにし、モジュール化することをカプセル化と呼ぶ。
結びつきの強い概念がまとまり細分化されることで、コードの可読性の向上、結果の局所化、再利用のしやすさの向上といった利点がある。
関係のない要素が混ざらないようにカプセル化すれば、質の高いモジュールを作成することが可能である。

情報隠蔽

モジュールでどのような実装をしているのかを、モジュールを呼び出すクライアントから見えなくすることである。
モジュールが受け取ったり引き渡す情報はシンプルになり、クライアントも余計な情報が見えないため使い勝手が良くなる。

パッケージ化

モジュールを意味のある単位でグループ化することをパッケージ化と呼ぶ。
論理構造でつながるモジュール群を物理構造に格納していく。
モジュールの数が増えて複雑になったソフトウェアに対する解決策となる。
パッケージ化により複雑性が減るだけでなく、結果の局所化やモジュール群の再利用性の向上も見込める。

ソフトウェアの作成時は、モジュールが増えて意味のあるまとまりを持つようになったらパッケージ化するようにする。
パッケージとは機能分解の単位ではなく、ソフトウェアのビルド方法を示すマップで、トップダウン的に作られるものではない。

関心の分離

カプセル化やパッケージ化で似たような機能を持つ部分を分離するが、機能だけではなく関心にもとづいて分離することも考えたい。
MVCモデルやアスペクト指向プログラミングは関心の分離を目的とした概念である。
MVCモデルではバックエンドを担当するmodel、フロントエンドを担当するcontroller、GUIに関わるviewという3つの関心事から分離を行う。
プログラミング言語単体では機能の分離に目が行きがちな部分にメスを入れる技術だと言える。
関心の分離により、変更頻度や結果の局所化からソフトウェアの安定性につながるだけでなく、関心で分離されるため開発をそれぞれの関心事に並行して進めやすい。

モジュール化を行うときも関心をできるだけ意識しておきたい。
モジュールの機能に限らず、モジュールの持つべき役割・目的にも着目したモジュール化を行うのが良い。

充足性、完全性、プリミティブ性

モジュールが果たすべき抽象の表現の評価についてである。
充足性、完全性、プリミティブ性から評価する。
要は、モジュールは表現したい抽象に対して必要十分であり、モジュール内のそれぞれの要素が独立であるべきだということである。

そのモジュールを呼び出すクライアント目線で使いやすいものを作るべきであり、そのためには必要十分で独立なものを作るようにする必要がある。

ポリシーと実装の分離

モジュールはポリシーと実装を扱う。
ただし、一つのモジュールの中で、その両方を同時に扱ってはいけない。
ポリシーモジュールはソフトウェアの前提に依存し、利用するロジックや引数の選択を行う。
実装モジュールはソフトウェアの前提に依存しないロジック部で、ポリシーモジュールによって利用される。
実装は安定しており、ソフトウェアの前提の変更によって引きずられることはないが、ポリシーは変化しうる。

結果の局所化、変更頻度の観点からもモジュール化の際にはポリシーと実装の分離に努めたい。

インターフェースと実装の分離

モジュールを作るときは、インターフェースと実装から構成するようにする。
インターフェースではモジュールが持つ機能を定義しており、クライアントがアクセスするのに必要な引数の名前などを構成するのに留まる。
実装では、機能を実現するのに必要なデータとロジックを持っており、ここにはクライアントからアクセスすることはできない。
この分離を行うことにより、クライアントは使い方が示されているインターフェースのみを把握していればよく、使い勝手が良くなる。
また、保守の観点でもインターフェースを維持したまま実装の修正を行うことができるので結果の局所化につながる。

モジュール同士の呼び出しにおいて、互いにインターフェースのみが使用されるように設計すると良い。

参照の一転性

モジュールの要素の定義を一度切りにし、再定義を行わないようにすることである。
再定義を頻繁に行うと、要素の変化に応じた影響が発生しやすい上、コードを追いかけるのが困難になる。

要素に対して単一代入を心がけ、できるだけ要素の再定義を行わないようにするのが良い。
プログラミング言語の機能的には再定義が認められることが多いが、極力その回数を減らして見通しの良いコードを書きたい。

分割統治

大きな問題は小さな問題に分割して個別で解決していく。
制御できない大きな問題は制御できるレベルまで分割して考えるのがよい。

設計のときから表現すべき要素を逐一分割していくことで、スムーズな作業につながっていく。