『プリンシプル オブ プログラミング』読書記録 第3章後半


はじめに

今回『プリンシプル オブ プログラミング』という本を読みましたので、自分なりにアウトプットしていく目的でまとめます。
リンク:『プリンシプル オブ プログラミング 3年目までに身につけたい一生役立つ101の原理原則』

UNIX思想

 UNIX思想とは、優れたプログラミングを行うための実践的な「技」の集合のことである。これは公式な方法論では無く、半ば暗黙的な知識として、UNIX文化の中で育まれ、伝承されてきたものである。これは17個の原則にまとめられている。

【一言まとめ】

  • モジュール化の原則
    • 関連度の高い要素のみでモジュール化する。
  • 明確性の原則
    • シンプルで明確なコードを書く。
  • 組み立て部品の原則
    • テキストストリームやコマンドラインで使用できるようにする。
  • 分離の原則
    • ソフトウェアの前提に依存する部分としない部分は分離すべきである。
  • 単純性の原則
    • コードはシンプルである方が、複雑で高度であるよりも良い。
  • 倹約の原則
    • コードは少なく簡単に書く。
  • 透明性の原則
    • デバックのしやすいコードを書く。
  • 驚き最小の原則
    • 想定するユーザーの予想や既知のものに寄せて設計をする。
  • 安定性の原理
    • コードの内部構造について説明できるようにする。
  • 表現性の原理
    • 不可避の複雑さはデータ側に持たせる。
  • 沈黙の原則
    • ソフトウェアの表示は最低限に抑える。
  • 修復の原則
    • 障害発生時にはわかりやすくエラーを出し、処理を停止させる。
  • 経済性の原則
    • 設備や環境には投資をすること。
  • 生成の原則
    • 繰り返しの単純作業はコード化すること。
  • 最適化の原則
    • 最適化は正常な動作を実装できたあとから検討する。
  • 多様性の原則
    • 手法については柔軟に発想し、よく検討する。
  • 拡張性の原則
    • プラガブル(接続可能)な設計を心がける。

 長く使用されてきたこのUNIX思想を設計の指針とすることで、良いコーディングができる。

【補足】

モジュール化の原則

 モジュールを関係度の高い要素のみを集め、シンプルすることで、問題が局所化され、改修がしやすくなる。ソフトウェアはこのようなシンプルなモジュールの修道体として構築するべきである。

明確性の原理

 巧妙で複雑なコードではなくシンプルで明確なコードを書くよう心がける。コードを読んだ時、わかりにくいコードの解読を2度行うことがあれば、その時に適切なコメントをするか、コード自体を修正するなどして、読みやすくする必要がある。

組み立て部品の原則

 相互接続の容易なソフトウェア構築を心がけること。そのためには、そのソフトウェアを独立させることが必要である。テキストストリームを読み書きする、コマンドラインで使用できるソフトウェアの構築を行うなど複数のソフトウェアを組み合わせて利用できるようにする。

分離の原則

 コードの中でビジネスロジックやユーザインタフェースなど、そのソフトウェアの前提に依存する比較的不安定な部分のことをポリシーという。また、そのソフトウェアの前提に依存しない、独立した部分のことをメカニズムという。これら2つは独立させるべきである。
 サービス系アプリケーションを構築する際は、フロントエンド部分は「ポリシー」であり、バックエンド部分は「メカニズム」である。これらのモジュールを分割することで、シンプルなコードとなる。
 エディタアプリケーションを構築する際は、機能を拡張するモジュールを、設定ファイルで駆動できるようにする。拡張可能なユーザーへのインターフェースが「ポリシー」であり、エディタのエンジンが「メカニズム」となる。

単純性の原則

 プログラマの心理として「もっとも入り組んだ美しい」モジュールを書くことを求めてしまうが、チーム内での開発の効率を考えると、「もっとも単純で美しい」コードを求めるべきである。また、過剰な機能の実装も避けるべきである。

倹約の原則

 コードの分量や複雑さはなるべく抑え、小さなコードを書くようにするべきである。コードの継ぎ足しによりコードが大きくなってしまった際には、分割して書くようにする必要がある。

透明性の原則

 ソフトウェアの動作について、ひと目見て分かるようにし、また内部状態が表示されるようにすることで、デバッグのしやすいコードとなる。デバックのための機能を最初の段階から組み込んで設計するべきである。モジュール内変数の内容を書式文字列化するメソッドを組み込む、また、ログを多く組み込むなど、本番コードにデバッグを簡単にする仕組みを組み込むことが必要である。

安定性の原則

 安定性とはコードが「透明性」と「単純性」を持っているということである。コードの内部構造について、簡単に説明出来ない場合は、安定性を保証できないため、コードレビューや、特異な入力や、極端に大きい入力に耐えられるような検証を行うことで、透明性や単純性を保つようにする。

表現性の原則

 コード上、複雑さが避けられない場面では、ロジックではなくデータ側に複雑さをもたせるようにする。データ型のほうが比較的複雑でも理解しやすいからである。

驚き最小の原則

 ユーザーの予想や既知のものに寄せた設計を心がけることで学習コストが下がり、ユーザビリティに繋がる。また、想定ユーザーがどのような層なのかの見極めや、伝統的に慣習となっている決まりなどへの考慮も必要となってくる。他に、既知のものに寄せる際に、一見似ているが微妙に異なるものにしてしまうと、より混乱を招くため注意が必要である。

沈黙の原則

 ソフトウェアの表示は、必要なものだけに抑える必要がある。重要な情報のみ出力し、内部動作の情報を混ぜないようにするべきである。例えば、本当のエラーのみを標準エラー出力に表示し、その他の要求されていないデータは表示しないよう設計する、また、デバックの際に進行状況についてメッセージを表示したい場合は、冗長モードのスイッチを作成しデフォルトでは無効にするなど、表示を選べるようにする。

修復の原則

 ソフトウェアの動作中、エラーの回復に失敗した際には、直ちに処理を停止する必要がある。また、不具合が起こった際にはできる限り簡単に障害を診断できるようなエラーを起こすようにする。
 ソフトウェアの入出力について、入力はできるだけ多様な表現を受け入れられるように、出力については、厳密でクリーンな正確なデータを出力するように設計する必要がある。しかし、入力について、その仕様に対しては一律のものを使用するようにする。

経済性の原則

 ハードウェアなどの設備やインターネット環境の拡充など、プログラマの開発を効率化させるよう、投資をするべきである。投資にかかるコストより、生産性が落ちることによる損失のほうが大きく、また、ルールや制約に関しては、施工した後にバランスを取っていき、すり合わせを行う必要がある。
 

生成の原則

 手動の単純作業、繰り返しの多い定型のコードに関しては、コード生成のためのコード(コードジェネレータ)を作成するべきである。

最適化の原則

 コードの最適化は重要であるが、まずは、遅くてリソースを多く消費するとしても正しく単純なコードを書くことが必要である。正しい動作の前に最適化を行うことは、透明化や単純化、全体の最適化を妨げ、設計を破綻させてしまう。正しく動くコードを完成させた後、最適化ができる箇所を体系的に探すという手順で行うべきである。

多様性の原則

 ソフトウェアに関わるすべての場面において「唯一の正しい方法」は存在せず、思考停止すること無く、よりよりやり方を模索することが大切である。また、一回のリリースでユーザーのすべての要望に完璧に答えられるということは無いため、柔軟性、拡張性のあるソフトウェア作りが肝要となってくる。

拡張性の原則

 多様性の原則にもあったようにソフトウェアに「唯一の正しい方法」は存在しないため、拡張性を持たせることが必要である。そのためには、プラガブル(接続可能)な設計を心がける必要がある。またそれを、コードの中にコメントとして明示するなどの配慮も行うべきである。

UNIX哲学

 UNIX哲学とはUNIXの背後にある設計の哲学のことである。これは9個の定理としてまとめられている。

【一言まとめ】

  • 小は美なり
    • 小さく設計し、ソフトウェアを小さく保つ。
  • 1つ1仕事
    • 1つのソフトウェアには1つの機能だけ持たせる。
  • 即効プロトタイプ
    • 早くプロトタイプを完成させ、ブラッシュアップする方向で開発を進める。
  • 効率性より移植性
    • 開発効率性より、他のハードウェアへの移植性を重視する。
  • データはテキスト
    • データはなるべくテキストファイルに保存する。
  • レバレッジ・ソフトウェア
    • 上手く既存のソフトウェアを利用する。
  • 対話インターフェース回避
    • ユーザーに入力を求めるようなインターフェースを過度に使用しない。
  • フィルタ化
    • 標準入力、標準出力を使用して接続しやすいソフトウェアに設計する。

 これらをその「理由」を把握した上で、設計方針やプログラミングに反映させる必要がある。

小は美なり

 小さなソフトウェアは理解が容易であり、保守が容易である。また、マシンリソースの負担も軽減される。他にも、他のソフトウェアとの組み合わせも簡単に可能である。逆に、大きなソフトウェアでは、複雑でコードの理解が難しく、デバックも困難になる。
 コードを書く際は、小さく設計し、ソフトウェアを小さく保つことが重要である。機能が不足した場合は、他のソフトウェアと連携するようにし、解決する問題をきちんと理解して小さく作成する必要がある。

1つ1仕事

 1つのソフトウェアには1つの機能のみ担当させるよう心がける必要がある。何か大きな問題があった場合は、小さな問題に分割し、その小さな1つの問題にのみ対応するプログラムを組むべきである。問題が拡張した場合は、別途1つの仕事をするソフトウェアを作成し、組み合わせることで解決していくべきである。

即行プロトタイプ

 できるだけ早くプロトタイプの作成を行うべきである。最初から完全なソフトウェアを完成させる事は不可能であり、一度最低限のものを完成させてから、チーム内での合意を取りつつ改善作業を行っていく方法を取るべきである。これにより、前提の誤りや要件の不備があれば早めに発見でき、また開発中に見つかる誤りについて早く対処出来る。

効率性より移植性

 開発効率性が下がったとしても、他のハードウェアに移植可能な移植性を持たせるべきである。そのためには、ハードウェアに依存する部分と、依存しない部分を切り分けて設計し、再利用しやすい単位でモジュール化を行う。
 また、コードの最適化を求めすぎるとハードウェアに依存しがちになるので避けるべきである。

データはテキスト

 データはバイナリ形式のデータファイルではなく、テキストファイルに保存するべきである。テキストファイルは、移植性が高い上に、可読性が高く、ツールやコマンドの扱いが容易であり、多少冗長でもテキストファイルを採用すべきである。また、CSVやXMLなど言語やOSによらない標準的なもの使用することで、他のソフトウェアとの接続性が高まる。

レバレッジ・ソフトウェア

 よい既存のソフトウェアを借りてくることで、少ない労力で自分のコードの有用性を格段に向上できる。コレを梃子の効果という。これを効果的に利用する場面の1つとして、手作業の自動化がある。

シェルスクリプト活用

 シェルスクリプトをグルー言語、すなわち、ソフトウェア同士を結びつける言語として利用するべきである。シェルスクリプトは高い移植性があるため、上記の梃子の効果を増幅させるものとして上手く利用する。

対話インターフェース回避

 対話型インターフェース、すなわち、ユーザーに入力を求めるようなインターフェースを過度に使用しないこと。シェルスクリプトの活用や、待ち時間の発生、入力部分のコードの肥大化などを引き起こすため、コマンドインタプリタに制御を返すようなソフトウェアを作成する。

フィルタ化

 ソフトウェアはフィルタとして設計する。フィルタとは入力ストリームをデータとして受け取り、加工を施して出力ストリームに送り出すことである。データを処理するものとして設計し、標準入力、標準出力を使用して接続しやすいソフトウェアに設計する。
 

参考文献

『プリンシプル オブ プログラミング 3年目までに身につけたい一生役立つ101の原理原則』上田勲 著 株式会社秀和システム 2016年3月29日 p.129-181