『脳に収まるコードの書き方』
https://gyazo.com/e0c8b85716f39f347458767a78efbe30
2024/6/18
https://www.youtube.com/watch?v=sVlfHMPYrTE
見てない
買う前には見たほうがいいかも?
.@ryuzee さん、オライリー・ジャパン様に『脳に収まるコードの書き方―複雑さを避け持続可能にするための経験則とテクニック』をご恵投いただきました!感謝!
早速読んで、特に印象に残ったところをメモしておきます。(→は自分のコメント)
・ソフトウェア開発においては、言われるような建築フェーズというものは存在しません。このことは、計画が役に立たないことを意味するわけではなく、家を建てるメタファーがどうにも役に立たないことを示しています。(P.5)
(→よく建築のメタファーが使われる業界なので、とてもわかる)
・ウォーキングスケルトンとは、実際の機能として成立するいちばん薄い実装のことで、ビルド、デプロイして、エンドツーエンドのテストが行えます。後でもできますが、最初にデプロイパイプラインを確立することに価値があります。(P.16)
(→最初にデプロイパイプラリンの有用性は体感していたが、名前付けも覚えた)
・そのため、警告にはゼロトレランスで望むべきです。警告が1つもない状態を保つのです。実際、警告はエラーとして扱うべきです。(P.20)
(→共感しかない、自戒から)
・たくさんのコードをすばやくと言うのは、あなたが読むことになるコードが増えることを意味します。たくさん作れば作るほど、たくさん読まなければいけなくなります。自動でのコード生成は事態を悪化させるだけです。(P.32)
(→生成AIパワーで変わるかもしれないが、結局ソフトウェアエンジニアの判断がしばらく残るので、可読性は大事)
・どんな馬鹿でもコンピューターが理解できるコードをかける。良いプログラマーは人間が理解できるコードを書く。(P.36)
(→マーチン・ファウラー氏らしいコメント)
・ドキュメントには、判断の結果よりも、なぜそう判断したかを記述すべきである。(P.47)
(→これもとても同意するところ。Whyが消えると、将来の変更可否が判断しにくい)
・メソッド名を隠してみるのは役に立つエクササイズです。あなたのコードを将来読む人と共感しやすくなるからです。思いついたメソッド名が十分にわかりやすいと思っても、違うコンテキストにいる人にとってはわかりにくいかもしれません。(P.127)
(→全く考えたことがなかった視点。授業でも使おうと思った一節)
・メソッド名で伝えられる事はコメントに書くな。型で伝えられることをメソッド名に書くな。(P.130)
(→わかりやすい指針)
・ペアプログラミングだけではコードの共同所有を達成できる保証は無い。ペアをローテーションして入れ替え、触るコードの場所を変えて、知識のサイロ化を確実に防がなければいけない。(P.149)
(→ペアプロ経験から本当にこれもわかる)
・コードレビューが答えるべきいちばん根本的な質問は、「自分はこれのメンテナンスを問題なく行えるか?」です。(P.153)
(→これも本当にそう。読む回数の多いし、どれだけ簡単に修正できるかが大事)
・私がラバーダックの代わりに使っているのは、Stack Overflow という Q&A サイトです。質問を準備していると、質問が完成する前に問題が何なのかに気づくことがよくあります。(P.186)
(→ SO以外でも投稿中に気付く、というのはあるあるだ)
・デンマーク語のソート順の問題には既に遭遇したことがあったので、問題を特定するのに1分もかかりませんでした。ソフトウェアエンジニアリングの技には、個人の経験にもとづく移ろいやすいものが残っているのです。(P.198)
(→ ニッチなところでアートな技芸が残る)
・コードを純粋関数で組み立てると、ログを出力すべきところは減ります。これは参照透明性が望ましい多くの理由のうちの1つであり、関数型コア・命令型シェルのアーキテクチャを支持すべき理由です。
純粋でない操作を記録し、それ以上は記録しない。
再現できないものは全てログに出力してください。 現在の日時の取得、乱数の生成、ファイルやデータベースからの読み込みなど、決定論的でない高度は全てこれに含まれます。また副作用があるものもすべて含みます。それ以外はログに出力する必要はありません。(P.212)
(→ このログの指針、めちゃくちゃ役立つのでは……この前後を読むだけも一冊の価値がありそう)
ということで、素晴らしい本だったのでめちゃくちゃオススメ!
目次
推薦の言葉
シリーズエディターによるまえがき
はじめに
第I部 加速
1章 アートかサイエンスか
1.1 家を建てる
1.1.1 プロジェクトの問題
1.1.2 フェーズの問題
1.1.3 依存関係
1.2 庭を育てる
1.2.1 何が庭を育てるのか?
1.3 エンジニアリングに向けて
1.3.1 工芸品としてのソフトウェア
1.3.2 経験則
1.3.3 ソフトウェアエンジニアリングの初期の概念
1.3.4 ソフトウェアエンジニアリングの前進
1.4 まとめ
2章 チェックリスト
2.1 記憶の補助
2.2 新規コードベースのためのチェックリスト
2.2.1 Gitを使え
2.2.2 ビルドを自動化せよ
2.2.3 エラーメッセージをすべて有効にせよ
2.3 既存のコードベースにチェックを追加する
2.3.1 漸進的改善
2.3.2 組織をハックする
2.4 まとめ
3章 複雑さに対処する
3.1 目的
3.1.1 持続可能性
3.1.2 価値
3.2 なぜプログラミングは難しいのか
3.2.1 脳のメタファー
3.2.2 コードは書く回数より読む回数のほうが多い
3.2.3 可読性
3.2.4 知的労働
3.3 ソフトウェアエンジニアリングに向けて
3.3.1 コンピューターサイエンスとの関係性
3.3.2 ヒューマンフレンドリーなコード
3.4 まとめ
4章 バーティカルスライス
4.1 動くソフトウェアから始める
4.1.1 データ入力からデータ永続化まで
4.1.2 最小のバーティカルスライス
4.2 ウォーキングスケルトン
4.2.1 特性評価テスト
4.2.2 Arrange-Act-Assert
4.2.3 静的解析の節度
4.3 外側から内側へ(アウトサイドイン)
4.3.1 JSON を受け取る
4.3.2 予約をポストする
4.3.3 ユニットテスト
4.3.4 DTOとドメインモデル
4.3.5 フェイクオブジェクト
4.3.6 リポジトリインターフェイス
4.3.7 リポジトリ内での作成
4.3.8 依存を構成する
4.4 バーティカルスライスを完成させる
4.4.1 スキーマ
4.4.2 SQLリポジトリ
4.4.3 データベースの構成
4.4.4 スモークテストの実施
4.4.5 フェイクデータベースによる境界テスト
4.5 まとめ
5.1 データの保存
5.1.1 変換の優先順位
5.1.2 パラメーター化テスト
5.1.3 DTOをドメインモデルにコピーする
5.2 バリデーション
5.2.1 不正な日付
5.2.2 レッド/グリーン/リファクタリング
5.2.3 自然数
5.2.4 ポステルの法則
5.3 不変条件の保護
5.3.1 常に有効
5.4 まとめ
6章 三角測量
6.1 短期記憶と長期記憶
6.1.1 レガシーコードと記憶
6.2 定員
6.2.1 オーバーブッキング
6.2.2 悪魔の代弁者
6.2.3 既存の予約
6.2.4 悪魔の代弁者vsレッド/グリーン/リファクタリング
6.2.5 どれだけテストを書けば十分か?
6.3 まとめ
7章 分解
7.1 コードの腐敗
7.1.1 しきい値
7.1.2 サイクロマティック複雑度
7.1.3 80/24ルール
7.2 脳に収まるコード
7.2.1 ヘックスフラワー
7.2.2 凝集
7.2.3 特性の横恋慕
7.2.4 ロスト・イン・トランスレーション
7.2.5 検証せずにパースする
7.2.6 フラクタルアーキテクチャー
7.2.7 変数を数える
7.3 まとめ
8章 API設計
8.1 API設計の原則
8.1.1 アフォーダンス
8.1.2 ポカヨケ
8.1.3 読む人のために書く
8.1.4 コメントよりもわかりやすい名前のコードを
8.1.5 名前をXで置き換える
8.1.6 コマンドクエリ分離
8.1.7 コミュニケーション階層
8.2 API設計の例
8.2.1 メートル・ドテル
8.2.2 カプセル化されたオブジェクトとやりとりする
8.2.3 実装の詳細
8.3 まとめ
9章 チームワーク
9.1 Git
9.1.1 コミットメッセージ
9.1.2 継続的インテグレーション
9.1.3 小さなコミット
9.2 コードの共同所有
9.2.1 ペアプログラミング
9.2.2 モブプログラミング
9.2.3 コードレビューの遅延
9.2.4 チェンジセットを拒否する
9.2.5 コードレビュー
9.2.6 プルリクエスト
9.3 まとめ
第II部 持続可能性
10章 コードの増大
10.1 フィーチャーフラグ
10.1.1 カレンダーフラグ
10.2 ストラングラーパターン
10.2.1 メソッドレベルストラングラー
10.2.2 クラスレベルストラングラー
10.3 バージョニング
10.3.1 事前警告
10.4 まとめ
11章 ユニットテストを編集する
11.1 ユニットテストのリファクタリング
11.1.1 セーフティネットの変更
11.1.2 新しいテストコードの追加
11.1.3 テストとプロダクションコードを別々にリファクタリングする
11.2 テストの失敗を確認する
11.3 まとめ
12章 トラブルシューティング
12.1 理解
12.1.1 科学的手法
12.1.2 シンプルさ
12.1.3 ラバーダッキング
12.2 欠陥
12.2.1 欠陥をテストとして再現する
12.2.2 スローテスト
12.2.3 非決定論的欠陥
12.3 二分法
12.3.1 Git による二分法
12.4 まとめ
13章 関心事の分離
13.1 合成
13.1.1 ネストした合成
13.1.2 逐次合成
13.1.3 参照透明性
13.2 横断的関心事
13.2.1 ロギング
13.2.2 デコレーター
13.2.3 何をログに出力するか
13.3 まとめ
14章 リズム
14.1 個人のリズム
14.1.1 タイムボックス
14.1.2 休憩を取る
14.1.3 意識して時間を使う
14.1.4 タッチタイプ
14.2 チームのリズム
14.2.1 定期的に依存を更新する
14.2.2 他のことも予定を入れる
14.2.3 コンウェイの法則
14.3 まとめ
15章 いつもの顔ぶれ
15.1 パフォーマンス
15.1.1 過去の遺物
15.1.2 視認性
15.2 セキュリティ
15.2.1 STRIDE
15.2.2 なりすまし
15.2.3 改ざん
15.2.4 否認
15.2.5 情報漏えい
15.2.6 サービス妨害
15.2.7 権限昇格
15.3 その他のテクニック
15.3.1 プロパティベーステスト
15.3.2 行動コード解析
15.4 まとめ
16章 ツアー
16.1 ナビゲーション
16.1.1 全体像を見る
16.1.2 ファイル構成
16.1.3 詳細を見つける
16.2 アーキテクチャー
16.2.1 モノリス
16.2.2 循環参照
16.3 使ってみる
16.3.1 テストから学ぶ
16.3.2 テストの声を聞く
16.4 まとめ
付録A プラクティス一覧
A.1 50/72ルール
A.2 80/24ルール
A.3 Arrange-Act-Assert
A.4 二分法
A.5 新しいコードベースのためのチェックリスト
A.6 コマンドクエリ分離
A.7 変数を数える
A.8 サイクロマティック複雑度
A.9 横断的関心事のためのデコレーター
A.10 悪魔の代弁者
A.11 フィーチャーフラグ
A.12 関数型コア・命令型シェル
A.13 コミュニケーション階層
A.14 ルールの例外を正当化する
A.15 検証せずにパースする
A.16 ポステルの法則
A.17 レッド/グリーン/リファクタリング
A.18 依存関係を定期的に更新する
A.19 欠陥をテストとして再現する
A.20 コードをレビューする
A.21 セマンティックバージョニング
A.22 テストとプロダクションコードを別々にリファクタリングする
A.23 スライス
A.24 ストラングラー
A.25 脅威モデル
A.26 変換の優先順位
A.27 X駆動開発
A.28 名前をXで置き換える
付録B 参考文献
訳者あとがき
索引
コラム目次
デプロイパイプラインを確立するときによくある課題
null許容参照型
ArgumentNullExceptionがNullReferenceExceptionよりも優れている理由は?
テスト駆動開発のサイエンス
契約による設計
ポステルの法則
昇順に数値表現を書く
Maybe
適切な文章
機動性
バス係数