はじめに
上田勲さんの「プリンシプル オブ プログラミング」を読んだので、自分用のメモ程度に記録していきます。
https://www.shuwasystem.co.jp/book/9784798046143.html
また、本書における「プリンシプル」とは「より良いプログラミングのためのエッセンス」とのことです。
具体的には、前提・原則・思想・習慣・視点・手法・法則などのことです。
1章:前提 〜プログラミングの変わらぬ真実〜
プログラミングの「普遍的な事実」に関するプリンシプルが紹介されています。
1章で私が印象に残った話は、「コードは設計書である」です。
ハードウェアは、まず「設計」して設計図をアウトプットします。そして、設計図をインプットして物理的に「製造」します。
上記をソフトウェアに当てはめると、上流の基本設計からテストやデバッグまでが「設計」であり、それをビルドしてリリースすることが「製造」になります。
この意味で、「設計」という行為の成果物は「コード」となります。
そのため、基本設計からテストやデバッグまでを分担するというのは、そんなに良いやり方ではないようです。
理想としては、プログラマ全員が仕様を作成し、コードを書くことです。
さらに、実際にコードを書いてみないと不明瞭な点が多く、いつまで経っても設計が終わらないという事実もあります。
これまでの開発現場を振り返ると、基本的に基本設計などをやる人とコードを書く人は別であり、基本設計が終わった段階で「設計は一旦完了」のような空気感があったので、コードを書くまで設計が終わらないというのは良い意識改革になりそうだと思いました。
2章:原則 〜プログラミングのガイドライン〜
プログラミングの「原則」、つまり多くの場合共通に適用されるべき基本的な「決まりごと」に関するプリンシプルが紹介されています。
2章で私が印象に残った話は、「意図を表現してプログラミングせよ(Program Intently and Expressively)」です。
コードとは「コンパイラ」ではなく「人」が読むためのものなので、コードの読み手に意図が正しく伝わるように書くことが大切ということです。
コードだけがソフトウェアの動作を「正確に」「完全に」知るための手掛かりです。ソフトウェアの動作を把握するためには、ドキュメントではなくコードを読むしかないのです。
そのため、コードは「書きやすさ」より「読みやすさ」を重視するべきです。コードが読みやすければコメントを書く必要もありません。
しかし、どんなに「What」や「How」が伝わるコードでも、「Why」までは伝えきれません。「なぜそれをしているのか」に関してはコメントを適切に使うことが良いようです。
私はまだ未熟なこともあり、コードリーディングを素早くできていない自覚があります。
そのため、自分が実装した場合にも「ちょっとわかりづらそうだなぁ」という場合には「What」などをコメントで残してしまっていました。
実際問題、納期があるので未熟な私が「読みやすいコード」のためにどこまで時間を割けるのかという問題はありますが、可能な限りコードだけで「What」や「How」が伝わるようにしようと思いました。
3章:思想 〜プログラミングのイデオロギー〜
プログラミングの「思想」が紹介されています。具体的には、これまで培われてきた「文化」「哲学」「価値観」などの思想が紹介されており、これらを学ぶことでプログラミングの設計方針などに活かすことができます。
3章で私が印象に残った話は、7つの設計原理のお話です。
これは、障害を作り込まないために意識するべき7つのお話であり、具体的には以下になります。
- 単純原理
- シンプルなコードにこだわる
- 同型原理
- 同じことは同じような形にする(モジュール内で扱う数値の単位や、公開関数の引数の数の統一など)
- 対称原理
- 条件があれば反条件など、対称性を意識する
- 階層原理
- 同じ種類の処理は、同じ階層構造で記述する(リソースの獲得とリソースの解放など)
- 線形原理
- 処理の流れは上から下の一直線にこだわる
- 明証原理
- 一見して明らかに正しいといえるコードを書く(不明瞭なところは、コメントや図を書くなどして明証する)
- 安全原理
- 例外などを意識する(else文やnullチェックなど)
これらは実際のソフトウェア開発現場の分析から導き出された、品質の良いコードを書くための「経験則」であり、コードレビューをする際の視点として持つと良いそうです。
もっと言うと、上記コードレビューの視点を持って開発ができると良いとのことです。確かにですね。
また、このお話ではないところだったと思いますが、「3回読まなきゃ分からないコードは改修するべき」と言うのも印象的でした。
私のように未熟なエンジニアだと判断が難しくもありますが、2回目で理解できるコードが理想のようです。
4章: 〜プログラマの観る角度〜
プログラミングの「視点」「味方」が紹介されています。プログラミングをする際に行う選択の助けとなります。
4章は「凝集度」と「結合度」の話がメインなように感じました。
凝集度とは、モジュール内に含まれている機能の純粋さを表す尺度のことです。レベルが低いものから高いものまで、7段階に分けられます。
この手の話は昔に読んだ「良いコード 悪いコード」にもあったと思うのですが、私にはピンと来なかったので、ChatGPTにわかりやすい例えを聞いてみました。
想像してみてください。あなたが料理をするために台所用品を揃えるとします。ここで、高い凝集度を持つ台所用品セットと、低い凝集度を持つセットの違いを考えてみましょう。
高い凝集度の台所用品セット: 包丁、まな板、ピーラー、果物ナイフなど、すべての道具が「野菜や果物を切る・剥く」という共通の目的に関連しています。これらの道具が一緒にセットになっているのはとても意味がありますね。
低い凝集度の台所用品セット: 包丁、フォーク、コーヒーメーカー、鍋敷き、冷蔵庫のマグネット。このセットには共通の目的がほとんどなく、どの道具が他の道具と関係しているのかが分かりにくいです。
なるほどです。
しかし、この手の話は実際の現場で意識して見ていかないと身につきづらいとも感じました。
また、結合度とは、モジュール同士の密接さを表す尺度です。「疎結合に〜」というワードは耳にしたこともあったので、なんとなくは理解していたつもりですが、これもレベル別に6段階あるようです。
1行1行のコードに意識を向けることはもちろん、「コードの塊であるモジュールにどんなコードを含めるべきなのか」、「モジュール同士どのような関係性を持たせるのか」まで意識しないといけないのだなと感じました。
5章: 〜プログラマのルーティン〜
プログラミングの「習慣」が紹介されています。良いコードを書くプログラマが日々行なっていること・心掛けていることを知り模倣することで、良いプログラマに近づくことができます。
私が5章で印象に残ったのは、「速いコードより良いコード」です。
これはパフォーマンスチューニングのお話なのですが、絶対的に最優先は「良いコード(シンプルで可読性が高いなど)」だということです。
コードの最適化を行う際には、コードの「大切な何か」を失うそうです。具体的に引き起こされるネガティブな現象は以下です。
- 可読性の低下
- 品質の低下
- 複雑性の増大
- 保守の阻害
- 環境間の競合
- 作業量の増大
また、基本的に「良いコード」というのは「よいパフォーマンス」もある程度兼ねています。
さらに、ソフトウェアのパフォーマンスはコード以外にも、アーキテクチャ・実行環境・使用しているライブラリなどによっても影響されます。
そのため、まずは「良いコード」を書くことに専念し、コードの最適化を行う際には以下の手順で慎重に進めると良いそうです。
- 最適化の必要性を証明する
- パフォーマンスを計測し、ボトルネックを特定する
- ボトルネックのコードを最適化する
- パフォーマンスを計測し、最適化の効果を確認する
- 最適化したコードの動作に問題がないことを検証する
「コードの最適化」や「パフォーマンスチューニング」などと聞くと難しそうに感じていましたが、基本的には「良いコード」を書いていれば良いのだと理解することができました。
6章: 〜プログラマの道具箱〜
プログラミングの「手法」が紹介されています。何も気にせずコードを書くと、頭がパンクして品質が悪くなります。そのため、「思考フレームワーク」や「設計手法」「問題解決手法」などの、「よい道具」を知り使うことが大切です。
私が6章で印象に残ったのは「契約による設計(Design by Contract)」です。
これは、「関数を呼び出す側」と「呼び出される関数側」で守るべき契約を結びましょうということだと思います。
具体的に、「関数を呼び出す側」は関数に処理を渡す前に、ユーザーからの入力値の妥当性を検証します。また、「呼び出される関数側」は処理前に契約通りの値が渡ってきたか検証し、処理後の値を返す前には契約通りの値を返せるかの検証をするなどです。
このとき、「呼び出される関数側」で引数を加工したりしてはいけません。「関数を呼び出す側」の責任なためです。
これまで例外処理などは色々と書きましたが、上記の考えを意識して検証などをしっかり行えていたかというと、怪しい部分が多くあったなと反省しました。
7章: 〜プログラミングのアンチパターン〜
ソフトウェア開発において陥りやすい「罠(アンチパターン)」が紹介されています。典型的な失敗パターンを知ることで、失敗を未然に防ぐことができます。
私が7章で印象に残ったのは「エントロピーの法則」です。
これは、自然に任せているとコードはどんどん汚れていく(腐ったコードになる)ということです。
どの開発も最初は良いスタートを切ったと感じるかと思いますが、気がつくとコードはどんどん腐っていき保守しづらくなります。
そんなコードの腐敗には以下の予兆があります。
- 硬さ
- 1つ変更するとそれと依存関係にあるモジュールも次々に変更しなくてはならないような、「変更の難しさ」を指します
- 脆さ
- 変更した箇所とは全く関連のない箇所が壊れてしまうなどのことを指します
- 移植性のなさ
- 環境依存のコードがあり、他の環境への移植がしにくいことを指します
- 扱いにくさ
- 設計構造に柔軟性がなく修正が難しくなる「コードの扱いにくさ」と、開発環境の動作が遅いなどの「開発環境の扱いにくさ」のことを指します
- 複雑さ
- 「将来必要になるかも」と記載したコードなど、現在不必要なコードが散乱していることを指します
- 繰り返し
- 同じようなコードが何回も繰り返し現れていることを指します
- 不透明さ
- コードの意図が読み取りづらい、わかりにくいコードを指します
そして、最も大切なことは「チーム文化で腐敗を許さない」ということです。
レビューや振り返りのタイミングなど、腐敗の予兆に気がついたらチームとして対応する意識を、チーム全員で持つことが大切です。
一時的にはコストや時間がかかりますが、コードが腐った際のリスクと比べたら十分に見返りのある投資だと述べられています。
さいごに
他の書籍にも書いてあることや、先輩エンジニアから聞いた話なども記載されていましたが、ここに書いてあることをちゃんと意識して行動できているエンジニアが「できるエンジニア」なんだろうなと感じました。
とても難しい技術的な話ではありませんが、強く意識づけないとすぐ忘れてしまいそうだなと感じました、、