書籍 プリンシプルオブプログラミング 第3章 上 まとめ

3章 プログラミングセオリー 〜 アーキテクチャ根底技法

思想 ~プログラミングのイデオロギー~

プログラミングセオリー

最高のコード:拡張しやすい、余分な要素が存在しない、読みやすい、理解しやすい

価値観を技術の選択基準に

プログラミングにおける問題解決は、その状況に応じて適切な技術を選択する必要がある。 下記の価値観は、個別技術を適用する際の理由になる。

  • コミュニケーション
  • シンプル
  • 柔軟性
フォース

フォース:技術を適用する際に考慮する観点

  • 要件:解決策が満たす必要のある
  • 制約:課題に含まれている
  • 特性:解決策に望まれる

これらを考慮した上で、解決策を選択していく。

意識すること

言語・ツール・技術・問題領域などといった、利用するモノを理解した上で作業に取り掛かるべき

-「何のために?」という本質を理解しておくことで、初歩的なミスや品質的な問題を減らすことが出来る

価値をプログラミングに繋げる原則

3.2 コミュニケーション

コードは記述している時間よりも読んでいる時間の方が圧倒的に多い。 読みやすいコードを記述することで、コードを読む時間を減らせるため、プログラマ同士のコミュニケーションをより円滑にできる。

意識すること

コードを書く際に「このコードを誰かが見たらどう感じるだろう?」と考えながら記述する

3.4 シンプル

コードの複雑性を排除する

コード内の「余分な複雑性」には一切の価値はなく、ただの禍根でしかないため、極力排除すべきである

コードの本質性は独立させる

コードの本質的なところと余分なところを混ぜ込まないようにする

コミュニケーションとシンプルはどっちが優先?

シンプルとコミュニケーションの両立が難しくなった際は、多少冗長でも「コミュニケーション」を優先させる

3.4 柔軟性

コードの変更は必ず行われるので、変更を考慮した「適切に柔軟な設計」を心掛ける

  • 余計な柔軟は複雑化を招くので注意

3.5 結果の局所化

変更の影響を抑える

コードを変更した際の影響を最小限に抑える - 関係ないところに飛び火しない設計

発見、修正が容易になる

結果を局所化することで一部分の検証のみで済ませることができ、余計なコストを減らせる。

3.6 繰り返しの最小化

コードを分割して管理

重複を防ぐためには、コードを小さく分割することが重要。

  • 共通の部分を探し出して関数化

3.7 ロジックとデータの一体化

データと操作は近くに

「ロジック(操作)」と「ロジックで扱うデータ」はなるべく近くに置くこと。

  • コードを読む量を減らせる

3.8 対称性

コードに一貫性を持たせる

同質なコードは、どこで実行されても同じように表現されるよう設計する。

  • 追加メソッドがあれば削除メソッドもある
  • モジュール内のデータの生存期間を統一
  • 抽象化レベルの統一

3.9 宣言型の表現

宣言型を取り入れる

宣言型で無い言語でも、アノテーションDSLなどの宣言型の表現手法を取り入れること。

  • 命令形特有のフローが無くなり、読みやすくなる

3.10 変更頻度

変更理由でグループ化

同じタイミングや同じ理由で変更されるコード同士をグループ化する。

  • 変更によって起こりゆる影響範囲を狭められる

アーキテクチャ根底技法

3.12 抽象

抽象化を行うことで、対象物を以下のように取り扱うことが出来る。

  • 無駄な要素を排除し、本質を捉える
  • 必要な要素のみを残すので、理解しやすくなる
  • 汎用化することで他の場所でも取扱やすくできる

3.13 カプセル化

関連の深いデータや機能を集約してモジュール化することで、関係性を強め無駄な要素が混じるのを防ぐ。 また、以下のようなメリットを得られる。

  • 必要な要素だけになるため、コードが見やすくなる
  • コードの変更が容易になる
  • 変更時の影響をモジュール内で抑える
  • 関数化と同様、機能が独立するため再利用しやすくなる
  • 小さい単位に分割されるため、複雑な問題への対処ができる(小回りが効く)

3.14 情報隠蔽

必要ないものは見せない

モジュール内のデータや機能を外部からアクセスできないようにする。

  • 無駄な関係を作らないことで、モジュールをシンプルにでき、変更などによる影響を最小限に留めることができる。

3.15 パッケージ化

モジュール同士をグループ化

モジュール自体をまとめる(パッケージ化)ことで、機能をモジュール化したときのようなメリットを得られる。

ボトムアップで設計

トップダウンだと正確に決めることが困難なため、ボトムで必要なパッケージ化を行う (上だと詳細なことを把握できない)

3.16 関心の分離

関心ごとにコードを分離

大きな機能や目的(関心)ごとに機能を他の機能から分離することで、関心ごとに独立して操作を行える。

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

モジュールが担っている抽象の表現において、下記の要素全てが成立していなければならない。

充足性

  • 機能が十分存在しているか
  • 一貫性を持っているか

完全性

  • 全ての特徴を完全に備えているか
  • 必要なものを表現できない状況であってはならない

プリミティブ性

  • 必要なものだけで純粋であるか
  • 無駄なものが無い状況

3.18 ポリシーと実装の分離

「ポリシー」と「実装」は混ぜない

ポリシーモジュール

  • ソフトウェアの前提に依存する、ビジネスロジックやその他のモジュールに対する引数の選択を行う部分
  • 特定のソフトウェアに特化している
    • ソフトウェア側で変更が生じると、モジュール側でも変更を強いられる

実装モジュール

  • ソフトウェアの前提に依存しない、独立したロジック
  • 特定のソフトウェアに依存しない「純粋」なモジュール
    • 他のソフトウェアでも再利用可能

それぞれを把握、意識して設計し、別モジュールに分けてコーディングをする。 モジュールの分離が不可能な場合は、モジュール内に明記しておく。

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

構成はインタフェースと実装から

インタフェースパート

  • モジュールが持つ機能を定義し、使用方法を定める部分

実装パート

  • モジュールが持つ機能を実現しているコードの部分
  • 内部で使用するロジックとデータが含まれる

インタフェースと実装を分離させること

  • 使用者が実装部を理解していなくても、インタフェースを利用できる (シンプル)
インタフェースを用いて設計
  • 実装ではなく、インターフェースを意識して設計する
  • モジュール間での呼び出しも、実装を直接叩くのではなくインタフェースを経由して呼び出す
    • 実装側も、インタフェースからの呼び出しのみに対応する

3.20 参照の一点性

定義は一回だけ

モジュールの要素の定義は、最初の一回のみにする(後から変更しない)

  • モジュールから得られる結果が、いつどこで取っても変わらないようにする
  • コロコロ変わる変数を広域で利用しない
単一代入

基本的に変数への再代入を行わない。 なるべく定数を利用したり、Javaでいう「final」を定義して再代入を制限すること。

3.21 分割統治

大きな問題を小さく割る

解決が難しい大きな問題は、小さな問題に分割して各個撃破していく

  • 問題を小さくすると、一つ一つの問題が解決が容易になるため

問題が発生してから分割するのではなく、あらかじめ制御が容易になるくらいの規模に分割しておく。