プリンシプルオブプログラミングをざっくり読んでみた
最初に
プリンシプルオブプログラミングを読んでいる際に、個人的につけていたメモです。
いわゆるまとめ記事ではなく、内容も飛び飛びで読んだときの自分の感想がメインの記事となっています。
とっ散らかった文章ですが、参考になれば。
本の感想ですが、いろんな有名な本からエッセンスを抜いてきてまとめてきた感じの攻勢になっているのでお得感がありました。参考文献もしっかり引いてあるので、深堀したい本を次読む、みたいな使い方もできそうです。
第1章 前提 ~ プログラミングの変わらぬ真実 ~
ソフトウェアの複雑性と変更容易性
ソフトウェアは実世界の問題を解決するためのものである以上、本質的に複雑であり、常に変化し続けている。そのため、変化することを前提として、変更に強い設計、すなわち変更容易性が高い実装であることが重要となる。
そのためには、いわゆる「設計」と呼ばれるところのみ頑張るだけでは不十分であり、設計、実装、テストに至るまであらゆる点において変更容易性を高めるための設計を行うという意識をもって取り組むことが必要となる。
プログラミングは本質的に設計であり、ソフトウェア開発におけるほかの工程も互いに依存していることから、一部分を切り取って取り組む、というのはより高い成果を出すためにベストな方法とはおそらく言えないのだろう。
第2章 原則 ~ プログラミングのガイドライン ~
DRYの原則をあらゆることに適用しよう
DRY(Don't repeat yourself)はプログラミングにおけるとても有名な原則であるが、その適用範囲はプログラミングに限った話ではない。仕事におけるプログラミング以外の各業務の中で重複しているものがないか、重複を取り除くことで効率化できないかと考えを巡らせ、工夫することも重要となる。この話は達人プログラマーの中で会ったアジャイルの話と一緒だな~と思った。
実際、プログラミング以外の部分に対するDRY原則の適用は頭ではわかっていても、つい先送りになってしまったり、なぁなぁになってしまいがちなので、ちょっとでも苦痛を感じたらそれを解消することに時間を投資するというスタンスは持ち続ける必要があると思った。
SLAP原則
SLAP(Single Level of Abstraction Principle)は、関数やモジュールが一つの抽象度レベルに留まるように設計することを推奨する原則である。
以前とある人に聞いた「構造化されていないコードは説明がしにくい、だから人に説明しやすい構造・処理順序でコードを書こう」という話と通じる部分があった。コードは機械に命令をするための文章である一方で、それを読み解いて改修を加えるのはしばらくは人間であるため、人間が理解しやすい構成で書くのが望ましいのはある種当たり前ともいえる。コードの全体構造をデザインする行為は論文執筆やスライド作成とつまるところ同じであり、気を付ける部分も一緒になるのだろう。それをプログラミングチックにいうと抽象度を合わせましょう、的な話になるだけだ。
DevinなどのAI Agentがゴリゴリプログラミングしてくれる中で可読性って優先度的に下がっていくのだろうか、いや結局採取的な品質担保を人間がする以上、しばらくはSLAP原則は適用できる気がする。仮に、コード以外でコードの振る舞いを構造化して正確に把握できる方法が確立されたらその限りではないかもしれないが。
メンタルマッピング
メンタルマッピングとは、コードを読む際に、書かれている情報に自分がこれまで経験し知っている内容や標準的なイメージを連感させて理解するプロセスを指す。ことプログラミングにおいては、変数やメソッドへの命名を適切に行うことで、コードの読み手側でのメンタルマッピングのコストを減らすことができる。
メンタルマッピングという単語は初めて聞いた。いわゆる、仕事ができる人や理解の速い人は、既存の知識と結びつけながら認知のズレを確認し、全体感を素早く把握しているから人の話の理解が速いのだろうなと思った。読み手に不必要なメンタルマッピングを強いらないコーディングを心がけようという話だった。
ちなみに、どんだけプログラミングをする側が気を配っていても読む際には少なからずメンタルマッピングは発生する。デザインパターンや重要となる設計思想を理解しておくとコードリーディングが楽になるのはメンタルマッピングによるコストを低く抑えられるからなのだろうと思った。
いわゆる可読性が高いコードを書こう、というのは重要視される一方で、コードを理解する側のメンタルマッピングのコストを減らすためのテクニック・考え方って意外と体系化されていないかもなと呼んでいて思った。
第3章 思想 ~ プログラミングのイデオロギー ~
コード妥当性レビュー観点
コードをレビューするにあたって持つべき観点として以下の7つがある。
-
単純原理
- シンプルなつくりにこだわろう
- 複雑な部分にこそバグが生まれる、だからこそシンプルに作ろう
-
同型原理
- 形にこだわろう。
- 同じことは同じように扱うことで、異物が入り込むことを防ぐ
- ○○の場合は例外としてこの分岐に行く、みたいな実装は同型原理に即していないとも言えそう
-
対称原理
- 形の対称性にこだわろう
- コードの形に対称性があると、読む側のコストを減らせる。これは先述したメンタルマッピングのコストを下げることと同意
- stat/endのように命名にも対称性を意識すると良い
-
階層原理
- 構造が階層になっていうことにこだわろう
- ドキュメントが抽象⇒具体に行っているほうが分かりやすいのと同じく、コードも階層構造にのっとっていることで格段に読みやすくなる
- ただモジュールの依存関係を階層構造にするだけではなくて、扱うデータの種類や変更する値を同一階層内に閉じ込めることを意識する
- 抽象度が異なる各層で同じ変数を引き回したり、いじくりまわした実装になっていると読みにくいのも原理としては同じ
-
線型原理
- 処理の流れを直線にすることにこだわろう
- コードを上から下に読むことで処理の流れを理解できるようにしようということ。コードの見通しのよさという話から「透明原理」と呼ばれたりもする
- 階層構造がきれいだと自然と線形原理に即した状態になりそう
-
明証原理
- ロジックの明証性にこだわろう
- 明証性とははっきりしているかどうか、みてすぐ正しいか判断できるかという指標を示している
- コードだけで明証性を伝えられないのであれば図やドキュメント、コメントを用いて理解できるように工夫するべきで、並行してコードだけで伝わるように明確な記述を心がけることが重要となる
- コードを実行するのはコンピュータだが、読み、改修するのは人間なので複雑でスマートな書き方は明証性という観点で見ても望ましい記述とは言えない
-
安全原理
- 安全性にこだわろう
- 言葉そのままの意味。とはいえ、実装の際にハッピーパスしか考慮できていなくて、リリース後に障害につながるというのはありがち
- いわゆる仕様は仕様書に書いてあるがそれがすべてではなく、最終的に機能の振る舞いはコードによって定義される以上、プログラミングを進めていく中で仕様が確定していくこととなる
- だからこそ、ただ仕様書にあるものをコードに落としていくのではなくて、○○の場合はどう考慮すべきか?どのような実装にすると堅牢になるか?をプログラマー自身がオーナーシップをもって実装するのが肝要となる
第4章 視点 ~プログラマの見る角度~
冪等性と安全性
冪等性とはある捜査を何度行っても結果が変わらない性質を指す。また、安全性とは操作対象の状態を変化させない性質を表す。HTTPにおけるGETは冪等性と安全性を持つことが要請される。なぜなら、HTTPを用いた通信はネットワークの状態など外的要因によって容易に失敗しうるため、通信を安定して行うために、失敗したときは再度リクエストを送れるなどといった非機能要件が存在するからである。
第5章 習慣 ~ プログラマのルーティン ~
プログラマの三大美徳
「怠慢」「短気」「傲慢」はあまりにも有名だが、周りの優秀な人を見ていると「怠慢」を貫くために今の作業を効率化することに勢いよく時間を投下し粘り強く取り組む人が多いと感じる。
手作業で大変な仕事があっても慣れてしまうと案外そこから抜け出すのは難しく、より良い改善をする行為に投資するというアクションをとるのが億劫になりがちだが、積極的に「怠慢」していかねばと最近思う。
第6章 手法 ~ プログラマの道具箱 ~
コンテキストの話
前提としてソフトウェアは現実の問題を効率よく解決するためのものであるため、そもそもどのような課題を解決したいのか、というコンテキスト(文脈)がとても重要になる。目の前のことだけでなくて背景を理解しましょう。というのはよく言われることだが、それは他人事ではなくて自分事として考えよう、というモラル的な話ではなくて、具体としての問題を解決するための抽象である背景理解をすることで本質的な解法を考えるために必要だからなのだろうと思う。
コードリーディングの際にコードとにらめっこする前に業務知識の理解を深めたほうがトータルでのコードリーディングの速度が速くなる、というのはあるあるなのだろうか。
第7章 法則 ~ プログラミングの安置パターン ~
ジョシュアツリーの法則
ジョシュアツリーという木の存在を知ってから道端に立っている木の存在に気づいたことから、名前って大事だねと学んだ話である。名前を付けるという行為はコンテキストを可視化する行為ともいえるかもしれない。なんとなく文脈で理解していた部分にきちんと名前を付けて言語化することでチーム内で共有できる状態を作り出せる。そしてそれらをコードの中に埋め込むことで、コードのドキュメントとしての品質が上がり、可読性が下がり、改修スピードが上がる良いサイクルが回せそう。
そのためにはチーム内のユビキタス言語に気を配り、定期的にメンテナンスする、というアクティビティも重要になりそう。定期的に勉強会をして互いの認識をそろえたり、言葉の揺らぎを修正するという行為は優先度が低くなりがちだが地味に効いているんだろうなと思った。
ヤクの毛刈り
ヤクという動物の肉を食べるためにはとっても毛深い毛を刈り取り続けることが必要で、毛を刈っていくことに時間を割きすぎて肉が食べられなくなる、という話から、必要以上に時間コストがかかっていそうだったら潔く引き返そうというたとえ話である。
その通りであると思う一方で、時間的な制約が許されるのであればガンガンヤクの毛を刈ってもよい気がする。例えば、機能開発したいけど細かい文法が理解できないからAIにとりあえず書かせて動いたから良しとする、という行動はヤクの話で言うと肉を最速で食べるために別の道を選択していることになる。細かい技術をグリップしないまま進めると肉はとりあえず食べられるけど困ったときに手詰まりしそうだなとも思う。
今毛刈りしまくってな~って思った時にはいったん立ち止まって最悪のケースで取れる解決策を考えて保険を作ってから再度毛刈りに没頭するというのが案外重要だったりして?と思った。
Discussion