改訂新版 良いコード/悪いコードで学ぶ設計入門 
                    ―保守しやすい 成長し続けるコードの書き方
                  
                  
                  - 仙塲大也 著
 - 定価
 - 3,520円(本体3,200円+税10%)
 - 発売日
 - 2024.12.25
 - 判型
 - A5
 - 頁数
 - 408ページ
 - ISBN
 - 978-4-297-14622-1 978-4-297-14623-8
 
概要
本書は、より成長させやすいコードの書き方と設計を学ぶ入門書です。筆者の経験をふまえ構成や解説内容を見直し、より実践的な一冊になりました。
システム開発では、ソフトウェアの変更が難しくなる事態が頻発します。 コードの可読性が低く調査に時間がかかる、 コードの影響範囲が不明で変更すると動かなくなる、 新機能を追加したいがどこに実装すればいいかわからない……。
変更しづらいコードは、成長できないコードです。 ビジネスの進化への追随や、機能の改善が難しくなります。
成長できないコードの問題を、設計で解決します。
こんな方にオススメ
- コードの設計スキルに興味がある人
 - 日々、悪いコードと向き合っていて改善したい人
 - より良いコードを書きたい人
 
目次
- 改訂新版 まえがき
 - はじめに
 - 謝辞
 
第1章 悪しき構造の弊害を知覚する
- 1.1 意味不明な命名
 - 1.2 理解を困難にする条件分岐のネスト
 - 1.3 さまざまな悪魔を招きやすいデータクラス
- 1.3.1 仕様変更時に牙をむく悪魔
 - 1.3.2 重複コード
 - 1.3.3 修正漏れ
 - 1.3.4 可読性低下
 - 1.3.5 未初期化状態(生焼けオブジェクト)
 - 1.3.6 不正値の混入
 
 - 1.4 悪魔退治の基本
 
第2章 設計の初歩
- 2.1 省略せずに意図が伝わる名前を設計する
 - 2.2 変数を使い回さない、目的ごとの変数を用意する
 - 2.3 ベタ書きせず、目的ごとのまとまりでメソッド化
 - 2.4 関係し合うデータとロジックをクラスにまとめる
 
第3章 カプセル化の基礎―ひとつにまとめる―
- 3.1 クラス単体で正常に動作するよう設計する
- 3.1.1 データクラスは単体での正常動作が困難
 - 3.1.2 クラスが自分自身でドメインモデルの完全性を保証する
 - 3.1.3 悪魔に負けない、頑強なクラスの構成要素
 
 - 3.2 成熟したクラスへ成長させる設計術
- 3.2.1 コンストラクタで確実に正常値を設定する
 - 3.2.2 計算ロジックをデータ保持側に寄せる
 - 3.2.3 不変で思わぬ動作を防ぐ
 - 3.2.4 変更したい場合は新しいインスタンスを作成する
 - 3.2.5 メソッド引数やローカル変数にもfinalを付け不変にする
 - 3.2.6 「値の渡し間違い」を型で防止する
 - 3.2.7 現実の営みにはないメソッドを追加しないこと
 
 - 3.3 悪魔退治の効果を検証する
 - 3.4 プログラム構造の問題解決に役立つ設計パターン
- 3.4.1 完全コンストラクタ
 - 3.4.2 値オブジェクト
 - Column 種類の異なる言語と本書のノウハウ
 
 
第4章 不変の活用―安定動作を構築する―
- 4.1 再代入
- 4.1.1 不変にして再代入を防ぐ
 - 4.1.2 引数も不変にする
 
 - 4.2 可変がもたらす意図せぬ影響
- 4.2.1 ケース1 可変インスタンスの使い回し
 - 4.2.2 ケース2 関数による可変インスタンスの操作
 - 4.2.3 副作用のデメリット
 - 4.2.4 関数の影響範囲を限定する
 - 4.2.5 不変にして予期せぬ動作を防ぐ
 
 - 4.3 不変と可変の取り扱い方針
- 4.3.1 デフォルトは不変に
 - 4.3.2 どんなとき可変にしてよいか
 - 4.3.3 正しく状態変更するメソッドを設計する
 - 4.3.4 コード外とのやりとりは局所化する
 
 
第5章 バラバラなデータとロジックをカプセル化する実践技法
- 5.1 プリミティブ型執着
 - 5.2 staticメソッドの誤用
- 5.2.1 staticメソッドはインスタンス変数を使えない
 - 5.2.2 インスタンス変数を使う構造につくり変える
 - 5.2.3 インスタンスメソッドのフリしたstaticメソッドに注意
 - 5.2.4 どうしてstaticメソッドが使われてしまうのか
 - 5.2.5 どういうときにstaticメソッドを使えばいいのか
 
 - 5.3 初期化ロジックの分散
- 5.3.1 privateコンストラクタ+ファクトリメソッドで目的別初期化
 - 5.3.2 生成ロジックが増えすぎたらファクトリクラスを検討すること
 
 - 5.4 共通処理クラス(Common・Util)
- 5.4.1 さまざまなロジックが雑多に置かれがち
 - 5.4.2 オブジェクト指向設計の基本に立ち返ろう
 - 5.4.3 横断的関心事
 
 - 5.5 結果を返すために引数を使わないこと
- Column C#のoutキーワード
 
 - 5.6 多すぎる引数
- 5.6.1 意味のある単位ごとにクラス化する
 
 - 5.7 アクセス連鎖
- 5.7.1 尋ねるな、命じろ
 
 
第6章 関心の分離という考え方―分けて整理する―
- 6.1 関心の分離の基本
- 6.1.1 インスタンス変数ごとにクラスを分割する
 - 6.1.2 依存関係を図式化しよう
 
 - 6.2 目的の違いを見破り、分離しカプセル化する
 - 6.3 インターフェイスと実装の分離
- 6.3.1 関心の分離がうまくいかない原因
 
 
第7章 関心が混ざったコードを分けて整理する実践技法
- 7.1 ロジックの流用
- 7.1.1 単一責任の原則
 - 7.1.2 責任が単一になるようクラスを設計する
 - 7.1.3 DRY原則の誤用
 - Column クソコード動画「共通化の罠」
 
 - 7.2 継承による関心の混在
- 7.2.1 スーパークラス依存
 - 7.2.2 継承より委譲
 - 7.2.3 継承による悪しき共通化
 - Column クソコード動画「継承」
 
 - 7.3 関心が混在する各種事例と対処方法
- 7.3.1 なんでもpublic
 - 7.3.2 privateメソッドだらけ
 - 7.3.3 スマートUI
 - 7.3.4 巨大データクラス
 - 7.3.5 トランザクションスクリプトパターン
 - 7.3.6 神クラス
 - 7.3.7 巨大なクラスの対処法
 
 
第8章 条件分岐―迷宮化した分岐処理を解きほぐす技法―
- 8.1 条件分岐のネストによる可読性低下
- 8.1.1 早期returnでネスト解消
 - 8.1.2 コードの見通しを悪くするelse句も早期returnで解決
 
 - 8.2 switch文の重複
- 8.2.1 即座にswitch文を書いてしまう
 - 8.2.2 同じ条件式のswitch文が複数書かれていく
 - 8.2.3 仕様変更時の修正漏れ(case文追加漏れ)
 - 8.2.4 爆発的に増殖するswitch文の重複
 - 8.2.5 条件分岐を一箇所にまとめる
 - 8.2.6 よりスマートにswitch文重複を解消するinterface
 - 8.2.7 interfaceをswitch文重複に応用(ストラテジパターン)
 - Column クソコード動画「switch文」
 
 - 8.3 interface設計の考え方を身につけよう
- 8.3.1 機能を取り換える単位を見つける
 - 8.3.2 結果と入力が同じかどうかを確認する
 - 8.3.3 interfaceを定義する
 - 8.3.4 interfaceを実装したクラスをつくる
 - 8.3.5 機能を取り換えるしくみをつくる
 
 - 8.4 条件分岐の重複とネスト
- 8.4.1 ポリシーパターンで条件を集約する
 
 - 8.5 型の判定で分岐しないこと
 - 8.6 フラグ引数
- 8.6.1 メソッドを分離する
 - 8.6.2 ストラテジパターンで機能を取り換えられるようにする
 
 - 8.7 interfaceの使いこなしが中級者への第一歩
 
第9章 コレクション―ネストを解消する構造化技法―
- 9.1 自前でコレクション処理を実装してしまう
- Column 車輪の再発明
 
 - 9.2 ループ処理中の条件分岐ネスト
- 9.2.1 continueで条件分岐のネストを解消する
 - 9.2.2 breakもネスト解消に役立つ
 
 - 9.3 バラバラなコレクション処理
- 9.3.1 コレクション処理をカプセル化する
 - 9.3.2 外部へ渡す場合はコレクションを変更できなくする
 
 
第10章 設計の健全性をそこなうさまざまな悪魔たち
- 10.1 デッドコード
 - 10.2 YAGNI原則
 - 10.3 マジックナンバー
 - 10.4 文字列型執着
 - 10.5 グローバル変数
- 10.5.1 カプセル化とパッケージ依存の設計で影響範囲を小さくする
 
 - 10.6 null問題
- 10.6.1 nullを返さない、渡さない、代入しない
 - 10.6.2 null安全
 
 - 10.7 例外の握り潰し
- 10.7.1 原因分析困難に陥り開発者を疲弊させる
 - 10.7.2 問題検出時にけたたましく叫ばせる
 
 - 10.8 設計秩序を破壊するメタプログラミング
- 10.8.1 リフレクションによるクラス構造および値の変更
 - 10.8.2 型の強みを活かせなくなる、クラス名やメソッド名のハードコード
 - 10.8.3 デメリットを理解し用途を限定すること
 
 - 10.9 技術駆動パッケージング
 - 10.10 サンプルコードのコピペ
 - 10.11 銀の弾丸
 
第11章 名前設計―あるべき構造を見破る名前―
- 11.1 悪魔を呼び寄せる名前
- 11.1.1 関心事ごとに分割する
 - 11.1.2 関心事にふさわしい命名
 - 11.1.3 大雑把で意味が不明瞭な名前
 
 - 11.2 名前を設計する―目的駆動名前設計
- 11.2.1 可能な限り具体的で、意味が狭い、目的に特化した名前を選ぶ
 - 11.2.2 存在駆動ではなく目的駆動で名前を考える
 - 11.2.3 どんな業務目的があるか分析する
 - 11.2.4 声に出して話してみる
 - 11.2.5 利用規約を読んでみる
 - 11.2.6 違う名前に置き換えられないか検討する
 - 11.2.7 関心が分離されているか点検する
 
 - 11.3 設計時の注意すべきリスク
- 11.3.1 名前無頓着になるな
 - 11.3.2 仕様変更時の「意味の変化」に警戒
 - 11.3.3 構造改善を妨げるアンカリング効果
 - 11.3.4 会話には登場するがコード上に登場しない名前に注意
 - 11.3.5 名前を知らないものは知覚できない
 - 11.3.6 形容詞で区別しているときはクラス化のチャンス
 
 - 11.4 意図がわからない名前
- 11.4.1 技術駆動命名
 - Column 技術駆動命名を用いる分野もある
 - 11.4.2 ロジック構造をなぞった名前
 - 11.4.3 驚き最小の原則
 
 - 11.5 構造を歪ませてしまう名前
- 11.5.1 データクラスになりがちな名前
 - 11.5.2 DTO(Data Transfer Object)
 - 11.5.3 クラスが巨大化する名前
 - Column クソコード動画「Managerクラス」
 - 11.5.4 文脈よって意味や扱いが異なる名前
 - 11.5.5 連番命名
 
 - 11.6 名前的に居場所が不自然なメソッド
- 11.6.1 「動詞+目的語」のメソッド名に注意
 - 11.6.2 可能な限り動詞1語で済む名前にする
 - 11.6.3 不適切な居場所のbooleanメソッド
 
 - 11.7 名前の省略
- 11.7.1 意図がわからなくなる省略
 - 11.7.2 基本的に名前は省略しないこと
 - 11.7.3 そのほか省略をどう判断するか
 
 
第12章 コメント―保守と変更の正確性を高める書き方―
- 12.1 退化コメント
- 12.1.1 コメントは劣化コピーにすぎないことを理解すること
 - 12.1.2 ロジックの挙動をなぞるだけのコメントは退化しやすい
 
 - 12.2 コメントで命名をごまかす
 - 12.3 目的や仕様変更時の注意点を読み手に伝えること
 - 12.4 コメントのルール まとめ
 - 12.5 ドキュメントコメント
 
第13章 メソッド(関数) ―良きクラスには良きメソッドあり―
- 13.1 必ず自身のクラスのインスタンス変数を使うこと
 - 13.2 不変をベースに予期せぬ動作を防ぐ関数にすること
 - 13.3 尋ねるな、命じろ
- Column クソコード動画「カプセル化」
 
 - 13.4 コマンド・クエリ分離
 - 13.5 引数
- 13.5.1 引数は不変にすること
 - 13.5.2 フラグ引数は使わない
 - 13.5.3 nullを渡さない
 - 13.5.4 出力引数は使わない
 - 13.5.5 引数は可能な限り少なく
 
 - 13.6 戻り値
- 13.6.1 「型」を使って戻り値の意図を表明すること
 - 13.6.2 nullを返さない
 - 13.6.3 エラーは戻り値で返さない、例外をスローすること
 - Column メソッドの名前設計
 - Column staticメソッドの扱いに注意
 
 
第14章 モデリング―クラス設計の土台―
- 14.1 邪悪な構造に陥りがちなUserクラス
 - 14.2 モデリングの考え方とあるべき構造
- 14.2.1 システムとは何か
 - 14.2.2 システム構造とモデリング
 - 14.2.3 ソフトウェア設計におけるモデリング
 
 - 14.3 良くないモデルの問題点と解決方法
- 14.3.1 Userとシステムの関係
 - 14.3.2 仮想世界を表現する情報システム
 - 14.3.3 目的別にモデリングする
 - 14.3.4 モデルはモノではなく目的達成手段
 - 14.3.5 単一責任とは単一目的
 - 14.3.6 モデルの見直し方
 - 14.3.7 モデルと実装は必ず相互にフィードバックする
 - Column クソコード動画「Userクラス」
 
 - 14.4 機能性を左右するモデリング
- 14.4.1 裏に隠れた真の目的を見破る
 - 14.4.2 機能性をイノベートする「深いモデル」
 
 
第15章 リファクタリング―既存コードを成長に導く技―
- 15.1 リファクタリングの流れ
- 15.1.1 ネストを解消し、コードの見通しを良くする
 - 15.1.2 意味のある単位にロジックをまとめる
 - 15.1.3 条件を読みやすくする
 - 15.1.4 ベタ書きロジックを目的を表すメソッドに置き換える
 
 - 15.2 安全にリファクタリングする方法
- 15.2.1 コードの課題を整理する
 - 15.2.2 テストコードを用いたリファクタリングの流れ
 
 - 15.3 あやふやな仕様を理解するための分析方法
- 15.3.1 仕様分析方法1:仕様化テスト
 - 15.3.2 仕様分析方法2:試行リファクタリング
 
 - 15.4 IDE のリファクタリング機能
- 15.4.1 リネーム(名前の変更)
 - 15.4.2 メソッド抽出
 
 - 15.5 リファクタリングで注意すべきこと
- 15.5.1 機能追加とリファクタリングを同時にやらない
 - 15.5.2 スモールステップで実施する
 - 15.5.3 無駄な仕様は削除することも視野に
 - Column Railsアプリケーションのリファクタリング
 
 
第16章 設計の意義と設計への向き合い方
- 16.1 本書はなんの設計について書いたものなのか
 - 16.2 設計しないと開発生産性が低下する
- 16.2.1 要因1:バグを埋め込みやすくなる
 - 16.2.2 要因2:可読性が低下する
 - 16.2.3 木こりのジレンマ
 - 16.2.4 一生懸命仕事した感覚だけが残って生産性は悪いまま
 - 16.2.5 国家規模の経済損失
 
 - 16.3 ソフトウェアとエンジニアの成長性
- 16.3.1 エンジニアにとっての資産とは何か
 - 16.3.2 レガシーコードに人は引きずられやすい
 - 16.3.3 レガシーコードは高品質設計を妨げる
 - 16.3.4 レガシーコードは本来やるべき開発の工数を減少させる
 
 - 16.4 課題を解決する
- 16.4.1 課題が見えないとそもそも設計する意識が生まれない
 - 16.4.2 知覚容易な課題と知覚困難な課題がある
 - 16.4.3 理想形を知ってはじめて課題を知覚できる
 - 16.4.4 変更容易性を比較できないジレンマ
 
 - 16.5 コードの良し悪しを判断する指標
- 16.5.1 実行可能コードの行数
 - Column クラスを分割すると読みにくくなる?
 - 16.5.2 循環的複雑度
 - 16.5.3 チャンク
 
 - 16.6 コード分析をサポートする各種ツール
- 16.6.1 Code Climate Quality
 - 16.6.2 Understand
 - 16.6.3 Visual Studio
 - Column シンタックスハイライトを品質可視化に利用する
 
 - 16.7 設計対象と費用対効果
- 16.7.1 パレートの法則(80:20の法則)
 - 16.7.2 サービスの中心的領域、コアドメイン
 - 16.7.3 重点設計対象の選定には業務知識が必要
 
 - 16.8 時間を操る超能力者になろう
 
第17章 設計を妨げる開発の進め方との戦い
- 17.1 コミュニケーション
- 17.1.1 コミュニケーションが希薄だと設計品質に問題が生じる
 - 17.1.2 コンウェイの法則
 - 17.1.3 心理的安全性
 
 - 17.2 設計
- 17.2.1 「早く終わらせたい」心理が品質低下の罠
 - 17.2.2 粗悪なコードはきれいなコードを書くより常に遅い
 - 17.2.3 設計と実装のフィードバックサイクルを回す
 - 17.2.4 厳密に設計しすぎず、サイクルを回し続けるのがコツ
 - 17.2.5 「パフォーマンスが落ちるからクラスを追加しない」は正しい?
 - 17.2.6 設計ルールを多数決で決めるとコード品質は最低になる
 - 17.2.7 設計ルールづくりのポイント
 
 - 17.3 実装
- 17.3.1 割れ窓理論とボーイスカウトの規則
 - 17.3.2 既存コードを信用せず、冷静に正体を見破る
 - 17.3.3 コーディング規約を利用しよう
 - 17.3.4 命名規約
 
 - 17.4 レビュー
- 17.4.1 コードレビューをしくみ化しよう
 - 17.4.2 コードを設計視点でレビューしよう
 - 17.4.3 敬意と礼儀
 - 17.4.4 定期的に改善タスクを棚卸しすること
 
 - 17.5 チームの設計力を高める
- 17.5.1 影響力を持つレベルにまで仲間を集める
 - 17.5.2 基本はスモールステップ
 - 17.5.3 実感が大事、手を動かしてみよう
 - 17.5.4 フォローアップ勉強会を開いてみよう
 - 17.5.5 勉強会のバッドノウハウ
 - 17.5.6 リーダーやマネージャーに設計と費用対効果の話をする
 - 17.5.7 設計責任者を立てる
 
 
第18章 設計技術の理解の深め方
- 18.1 さらにステップアップするための設計技術書紹介
- 18.1.1 現場で役立つシステム設計の原則〜変更を楽で安全にするオブジェクト指向の実践技法
 - 18.1.2 リーダブルコード―より良いコードを書くためのシンプルで実践的なテクニック
 - 18.1.3 リファクタリング 既存のコードを安全に改善する(第2版)
 - 18.1.4 Clean Code アジャイルソフトウェア達人の技
 - 18.1.5 レガシーコード改善ガイド
 - 18.1.6 レガシーソフトウェア改善ガイド
 - 18.1.7 レガシーコードからの脱却―ソフトウェアの寿命を延ばし価値を高める9つのプラクティス
 - 18.1.8 エンジニアリング組織論への招待〜不確実性に向き合う思考と組織のリファクタリング
 - 18.1.9 プリンシプルオブプログラミング 3年目までに身につけたい一生役立つ101の原理原則
 - 18.1.10 Clean Architecture 達人に学ぶソフトウェアの構造と設計
 - 18.1.11 エリック・エヴァンスのドメイン駆動設計
 - 18.1.12 ドメイン駆動設計をはじめよう―ソフトウェアの実装と事業戦略を結びつける実践技法
 - 18.1.13 セキュア・バイ・デザイン 安全なソフトウェア設計
 - 18.1.14 ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本
 - 18.1.15 ドメイン駆動設計 モデリング/実装ガイド
 - 18.1.16 ドメイン駆動設計 サンプルコード& FAQ
 - 18.1.17 テスト駆動開発
 - Column バグ退治RPG『バグハンター2 REBOOT』
 
 - 18.2 設計スキルを高める学び方
- 18.2.1 インプットは2/アウトプットは8
 - 18.2.2 設計効果を意識する
 - 18.2.3 悪魔の構造を見破る練習
 - 18.2.4 リファクタリングで大幅スキルアップ
 - 18.2.5 設計の良し悪しを説明できることがスキルアップにつながる
 - Column C#と長き旅、そして設計への道
 - 18.2.6 動くコードを書いたら、設計し直してからコミット
 - 18.2.7 設計技術書でさらなる高みを目指そう
 
 
- 参考文献
 - 索引
 
プロフィール
仙塲大也
X(旧Twitter) : ミノ駆動(@MinoDriven)
青森県出身。大手電機メーカーからWeb業界へ転身。アプリケーションアーキテクトとして、リファクタリングやアーキテクチャ改善、若手の設計スキル育成といった、設計全般を推進する業務に従事。悪しきコードとの戦いの中で設計の魅力に気付く。暇さえあれば脳内でリファクタリングしている。X(旧Twitter)ではプログラミングの風刺動画を不定期で投稿。
登壇実績多数。Developers Summitではベストスピーカー賞など受賞多数。