イントロダクション
「ほとんどの組織において、誰もが必要な知識を手に入れ、何をすべきかを理解しているのに、まったく行動に表れていない。 業績に対してもマイナスの影響を及ぼしている」
引用:スタンフォード大学のJ・フェファーとR・I・サットンが提唱した概念『Knowing-Doing Gap』より
はじめに
上田 勲氏の著書「プリンシプルオブプログラミング 3年目までに身につけたい 一生役立つ101の原理原則」を読破したので、その要約や感想をqiitaにアウトプットします。
まとめただけで終わってしまうのがいつもの癖なので、「今日からでも実践できそうなもの」を抜粋・要約しました。
(投稿者の独断と偏見により選定されていますので、詳しく知りたい方は本書をお読みください🙇♂️)
ネタバレ注意です。
これから読まれる方で先に内容知りたくない方はブラウザバックを推奨します。
各章まとめ
第1章 前提〜プログラミングの変わらぬ真実
1.1 プログラミングに銀の弾丸はない
プログラミングには、魔法のような解決策がない。これさえあれば、必ずうまくいくという「特効薬」はない。
ソフトウェアは、本質的に「困難性」を持っています。その困難性を示す4つの性質は、「複雑性」「同調性」「可変性」「不可視性」です。
- 複雑性: ソフトウェアは数千万行という規模のコードで成り立っていることも珍しくはない
- 同調性: ソフトウェアは単独で存在しているわけではなく、ハードウェアやネットワーク、人間の行動や習慣など、実世界に接続され使用される
- 可変性:ソフトウェアは変化し続ける。ソフトウェアはユーザーの認識に影響を及ぼし、新たな要求が発生するためだ
- 不可視性: ソフトウェアは概念の集積であり、目に見えない。製品そのものやプロセス、意思決定の経緯なども見れない
1.2 コードは設計書である
ハードウェアは、まず「設計」して、設計図をアウトプットする。そして設計図をインプットとして、物理的に「製造」する。
これをソフトウェアに対比してみると、上流工程の担当者の「設計」によって、基本設計書が作成される。その設計書をインプットに、プログラマがコードを書いて「製造」する、と解釈される。
しかし、この対比は間違っているという。
上流の「基本設計」から「詳細設計」「プログラミング」「テスト」「デバッグ」まで、すべてが「設計」であり、そのアウトプットが、設計書である「コード」となる。
「製造」にあたるのはリリースビルドとなる。つまり、製造はプログラマではなく、コンパイラやビルドシステムが行う。
こう考えると、プログラミングは設計行為であり、ソフトウェア開発で作成される文書の中で、真にエンジニアリングのドキュメントと言えるものは、コードだけだという。
1.3 コードは必ず変更される
最初のリリースだけで、要望を完全網羅したソフトウェアを作ることは不可能です。
さらに、ユーザー自身というより、ユーザーのビジネス環境の変化により、要求が変化していきます。
変更に強いコードを書くことが大切です。そのためには「コードが読みやすい」ことが最も大切です。
第2章 原則 〜プログラミングのガイドライン~
2.1 KISS
KISS(Keep It Short.
: 簡潔かつ単純にしておけ)
コードは自然に任せて修正していくと、無秩序になり複雑化していきます。
複雑なコードは読みにくく、修正しにくくなります。
例えば、以下のようなケースはコードの複雑化につながる可能性が高いです。
①新しく覚えた技術を使いたい
②将来の必要に備えたい
③勝手に要件を加えてしまう
コードは、頭の良さをアピールする場ではない。ユーザーに価値を提供するもの。
シンプルをプログラミングの羅針盤にしましょう。コードから、余計なこと、過剰なことを可能な限り排除します。そのためには、プログラミング、「動作させるために最もシンプルなものは何か」と常に問いかけるようにすることです。
2.2 DRY
DRY(Don't Repeat Yourself.
: 繰り返すな)
同じコードを重複して書いてはいけません。
最も多いのは、ひとまとまりのロジックを、安易に別の部分にコピペすること。
他には、同じ条件を扱う制御文のブロック群が、さまざまな場所に重複して現れること。
func A() {
if(a) {
xxx
} else if(b) {
xxx
} else {
xxx
}
}
func B() {
if(a) {
xxx
} else if(b) {
xxx
} else {
xxx
}
}
コードを抽象化(「関数化」、「モジュール化」)して重複を排除しましょう。
2.7 名前重要
プログラミングにおいて、「命名」は最重要課題として認識して取り組むこと。
コードを読んでいる時、関数名を見ただけで処理内容が分からなければ、それを理解するために関数の内部を解析しなければならない。つまり、「深く」読むことを強いられる。
命名の時は、以下の点に注意します。
- 名前には、より多くの情報を詰め込む。「短いコメント」と考えると、伝えるべき情報が含まれやすくなる
- 名前は、「効果」と「目的」を説明する
- 名前は、発音可能なものにする。現実の会話でも使用しやすく、コードを読むときも発音できた方が脳に負担がかからない
- 名前は、検索可能なものにする。例えば、英数字の1文字の名前は、コード全体で無限にヒットするので、コードの解析に手間がかかる
第3章 思想 〜プログラミングのイデオロギー〜
3.2 コミュニケーション(プログラミングセオリーを支える3つの価値①)
コードはコミュニケーションの場である
コードも、人に見せる「文書(ドキュメント)」です。そして「文書」の本質は「コミュニケーションツール」です。
ソフトウェアの開発コストの大半は、最初に開発された後に発生します。つまり、保守のコストです。
コードは、書く時間よりも、読む時間の方が圧倒的に多くなります。
重要なのは、コードを書いているとき、コードを読む他の人のことを考えるようにすることです。
UNIX思想15 最適化の原則
速いコードより正しいコード
プログラミングにおける最適化とは、パフォーマンス・チューニングを行うこと。動作スピードを上げたり、メモリやディスクスペースなど、マシンリソースの使用を効率化したりします。
ただし、プログラミングにおいては最適化の前に、正しく動作するコードを書くようにします。
正しく動作する前に最適化に走ると、以下のような問題が発生するためです。
- コードが無理なものだったり、内部構造がわかりにくいと、多くの障害を生み、莫大な時間を浪費する
UNIX思想17 拡張性の原則
ソフトウェアにおいて、「唯一の正しい方法」はありません。自分の設計が「唯一の正しい方法」だと考えるのは危険です。
よって、コードには成長の余地を残しておかなければなりません。成長していくことで、多様なニーズに応えていきます。
第4章 視点 〜プログラマの観る角度〜
4.5 コードの臭い
「コードの臭い」とは、コードの中で理解しにくい、修正しにくい、拡張しにくい、と感じられる部分を怪しいサインとして呼んでいるものです。
コードの臭いの兆候
- そっくりなコード(重複するコード)
- 関数が長すぎるコード
- モジュールが大きすぎる
- 名前が実際のコードと合わない
4.6 技術的負債
問題コードは「借金」である
技術的負債とは、コードにおける「修正しにくい」「理解しにくい」といった、問題のある汚いコード部分のこと。「障害そのもの」ではなく、障害の温床、障害の発見の妨げとなる、問題のあるコードを「借金」に喩えています。
実際のビジネスにおいて、「負債」を一時的に抱えても、返済すれば問題はない。
コードでも同様に、一時的に「汚いコード」を許容しても、正しいコード(きれいなコード)に修正すれば問題はない。
しかし、すぐに返済できなかった場合、「利子」が発生する。つまり、汚いコードがソフトウェアに残り続ける。ソフトウェアの動作も不安定になってくる。
負債を抱えすぎてしまった場合、返済不能に陥る。つまり、「機能追加」も「保守」もできないコードになる
(対処方法)
- 問題あるコードを変更前の状態に戻し、本来あるべき「きれいなコード」に修正する
問題コードの誘因
- 経験不足のプログラマー
- 締切のプレッシャー
- 読みにくいコード
- 特殊化されたコード
- 不要に複雑なコード
- 単に悪い設計
以下のようなチーム文化があると、それも誘因になりうるという
- きれいなコードを書こうとしない
- 不明瞭なコードがあっても受け入れてしまう
- リファクタリングに時間を割かない
- リリース直前に回帰テストを実行する
- 膨大な依存性を抱えた古いシステムのリプレースを躊躇する
- 安易にコードをブランチさせる
第5章 習慣 〜プログラマのルーティン〜
5.1 プログラマの3大美徳
怠慢
全体の労力を減らすために、手間を惜しまない気質。みんなが後で楽できるように、今役立つコードを書く
短気
コンピューターがサボっているときに、怒りを感じる気質。コンピューターが効率的に働いてなかったり、意図通りに働いてなかったら、直ちにコードを書き直します。
また、今ある問題にとどまらず、今後起こりうる問題を想定したコードを書いておきます。
傲慢
神罰が下るほどの、過剰な自尊心を持つ気質です。高いプライドを持ち、人様に対して恥ずかしくないコードを書きます。
3大美徳は悪徳??
一見、悪徳のように思えますが、逆の言葉である「勤勉」「寛容」「謙虚」の方が、倫理的には正しいと著者は言う。
しかし、プログラマにとっては「怠慢」「短気」「傲慢」の方が理にかなっていると言う。
その理由を以下のように述べている。
-
怠慢
- 日常には、面倒な仕事、何回も繰り返す仕事がたくさんある。それをコンピューターにやらせることで時間を大幅に節約できる。また、作業の正確性も保証される
-
短気
- 怒ると言っても、コンピューターに怒鳴り散らすわけではない。コンピューターが望むように動かないときに、こちらの思い通りにコードを書き換える。そうすることで、我慢している時間が、快適な時間に変わる。作業品質、作業にかかる時間も改善される
-
傲慢
- 自分のコードを誰に見られても、恥ずかしくないように書く。そしてそのコードに対して責任を持つ。仕事の成果については「傲慢」になり、プロフェッショナルの意識を持って仕事に取り組む
(感想)3大美徳の意味を自分は少し勘違いしてました。人には優しくしたいと思いました。
5.4 エゴレスプログラミング
コードを見る側も、見せる側も、「自分の方が優れている」などといった自尊心を捨て、純粋に「より良いものを作る」と言うことに価値を置くべきということ。
エゴレスプログラミングの十戒(抜粋)
- 自分自身も間違いを犯すということを理解し、受け入れます
- 書いたコードは、自分自身ではありません
- 自分よりもスキルが劣る人にも、尊敬と敬意と忍耐を持って接します
- 世界で唯一変わらないことは、変わるということだけです
- 「人に優しく、コードに厳しく」して、人ではなくコードを批評します
5.5 1歩ずつ少しずつ
小さいけれども、確実な1歩を繰り返して進む方が、結果として品質も時間効率も上がります。
なぜなら、複数の作業を一度に行うと、それらの作業が混線してどれも失敗する可能性が高くなるからです。
古いものを新しいものに変えていく場合、
「動く状態を保ちつつ、新しいコードを追加していき、古いものが全て新しくなったところで、古いものを壊す」という手順を踏むと、失敗する危険は少なくなる。
思考も「1歩ずつ少しずつ」
頭のいい人は、何か特別な手法を使って、手順を飛ばして考えるのが速くなっているわけではない。
コツコツ考えて、やらなければならない論理ステップを構築し、各ステップをそれぞれ速く、確実に行うので、全体として速く正確になっている。
論理的思考のコツ(抜粋)
- 瞬時に答えを得ようとする態度は誤りです。瞬時にわからなくても考え続けること
- すぐに結論に飛びつくのは誤り。条件を満たすものが1つ見つかった時に思考停止せず、思い込みを排除して、他の可能性も検討する
第6章 手法 〜プログラマの道具箱〜
6.6 コンテキスト
コンテキストとは、周りの状況や背景のことです。文脈とも言います。
コードを書くときは、コードを読む人のコンテキストを醸成する必要がある。そのため、コードを書くときは、その内容をトップダウンで伝えるようにする。
具体的には、モジュール名などの大きな括りの名前で、「何」について責任を持っているかを明確にする。その中に含まれる関数についても、モジュール名を文脈として、さらにその中で何について処理しているかを名前にする。
プログラミングは問題解決の作業です。
単独の要素を見ているだけでは、問題解決に至りません。物事は単独で存在せず、周囲と繋がっていたり、背景があったりします。全てが繋がっており、微妙に動いています。
プログラミングの達人と言われる人は、このコンテキストを使用しています。自分の体験と照らし合わせ、持っているパターンの中から、状況にあった解決策を施します。
第7章 法則 〜プログラミングのアンチパターン〜
7.1 ブルックスの法則
プロジェクトの工数は、人月換算されます。
「何人が、何ヶ月従事するか」なので、「人×月」のかけ算になります。
重要なのは、「人」と「月」は交換不能である、という事実です。
つまり、「人×月 = 月×人」という式は成り立たない。
(例)
12人月のプロジェクトで「6ヶ月で開発してくれ」と言われたら、2名の人員を投入すればいい。ここで「急ぐので、2ヶ月で開発してくれ」と言われたら、6人投入する。
しかし、現実的には「6×2」と「2×6」は同じにはならない。2人で作業するときと、6人で作業するときの能率は違う。以下のような理由が挙げられる。
- 依存関係によるオーバーヘッドが発生する
大抵の仕事は、分割すると、それぞれの作業や担当部分間の依存関係が発生する。それにより、タスクの分割や諸々の確認作業、コミュニケーションパス増加によるオーバーヘッド(=間接費)が新たに発生する - 教育に時間を取られる
追加した人が戦力になるには、プロジェクト固有の色々な知識や情報、技術を学習する必要がある。この知識を教えるのは、同じプロジェクト内のメンバーとなる。必然的に、新チーム全体としての生産性は落ちることになる。
感想:これを知ってから、教える立場の目線でも物事を考えるようになりました🙏
スケジュールの遅れは、人員の投入で取り戻せる?
結論から言うと、うまい方法ではない。
今の人員に無理をさせるのも、プロジェクトにダメージが蓄積されるだけなので、選択肢にはならない。
最も良い解決方法は、リスケジュール。その際はユーザーと調整しながら、機能に優先度をつけて、段階的にリリースします。
感想:実際にリスケして対応するかどうかは、プロジェクト状況やクライアントの要望にもよる?
7.7 セカンドシステム症候群
リリースしたソフトウェアの、2番目のバージョンには、機能を盛り込みすぎてしまい、品質が悪くて機能の使い勝手も悪くなる傾向がある。
プログラマーは自制心を働かせ、「多機能主義」にならないように気を付ける。
有効なのは、ユーザーを明確に定義し、イメージすること。
- ユーザーは、誰なのか?
- ユーザーは、何を必要としているのか?
- ユーザーは、何が必要だと考えているか?
フィーチャー・クリープ
ユーザーからの要望を無秩序に導入していくのも、機能が必要以上に膨らむ要因の一つ。
これを避けるポイントは、多くの要望に対して「NO」と言える勇気を持つこと。他のソフトウェアと組み合わせて実現できるものに関しては、明確にNOと言うこと。
ただし、クライアントからの強い要望で、NOと言えない場合もある
7.8 車輪の再発明
既に機能を実現しているコードやライブラリがあるのに、自分で同じ機能をプログラミングしてしまうことなどを喩えている。
工数の浪費になるし、再発明したものよりも、既にあるものの方が、大抵の場合は品質が優れている。
再発明してしまうパターン
-
車輪を知らない
これはプログラマの知識不足・勉強不足によるもの。言語の標準ライブラリと同じ機能のコードを作成したりすることなどが当てはまる。 -
車輪を作りたい
これは、確信犯。
技術的興味や、他の人が作った部品を使いたくないプライドから、自分で何でも作りたがってしまう傾向にあるみたいです。
(対策)
-
「車輪」以外に注力する
同じ機能が標準ライブラリにないか、オープンソースライブラリにないか、標準プロトコルがないかなどを必ずチェックする。また、チーム内で相談して他のプログラマーから情報をもらうなども良い。
「作りたいから作る」はプログラマーのエゴです。
ソフトウェアの目的は、ユーザーの要求を満たすことです。
7.9 ヤクの毛刈り
ある問題を解こうと思ったら別の問題が出てきて、なかなか大元の問題の解決に辿り着かない。問題を解こうと思ったら、さらに別の問題が出てくるということが延々に続く...といった状況のことを喩えています。
- 「Webサーバーをダウンロードしよう」
- 「あれ、ファイルが大きくてダウンロードできない」
- 「ダウンロードツールを入れよう」
- 「ダウンロードツールが動かない」
- 「前提モジュールを導入しよう」
- 「あら、ユーザー登録必要なのか」
- 「あれ、ユーザー登録できない」
- 「ブラウザのバージョンが古いのか」
- 「あれ、そういや何を解決したいんだっけ??」
早々に切り上げる
「目的からずれている」「時間やコストと見合わない」と認識したら、すぐに作業を止めるようにしましょう。別の道を探したほうが良い結果になる場合もあります。
例えばコードを読んでいるときも、入り組んだ呼び出し関係を追っていると、読んでいる目的を見失いことがよくあります。そんなときは、メモをとりながら作業をすることも重要です。
あとがき
読み飛ばしてしまいがちな著者の「あとがき」
ここにも学びになるような話があったので共有します。
ケアリング
現代の哲学者メイヤロフ著の書籍「ケアの本質」より
ケアリングとは、相手をケアすることです。相手をケアすることは、相手の成長や自己実現を助けるだけではなく、自身の自己実現につながります。
プログラマにとって、ケアする相手は、「コード」であり、「コードを読む人」です。
わかりやすいことが、コードの成長を助けます。コードを読む人の仕事を助けます。
そしてそれが自分自身に返ってくることになります。
道徳法則
近代の哲学者カント著の書籍「実践理性批判」より
「汝の意志の格率が、常に同時に普遍的立法の原理として打倒するように行為せよ」
超訳すると、「自分自身の行動を問い、みんなが認めてくれるようなことであれば、それを行え」と言うことです。
ユーザーとプログラマは、互いに利用し合う存在ではなく、貢献し合う存在です。
おわりに
この本を私なりに例えると、プログラミングにおいての「聖書」のように思えました。
今後開発していく上での一つの「指針」にもなりうるように思いました。
今回まとめたこと以外にも大切な原理原則が本書に書かれています。もしこの投稿を見て、少しでも興味を持って頂けたなら幸いです🙇♂️