改訂新版 良いコード/悪いコードで学ぶ設計入門
―保守しやすい 成長し続けるコードの書き方
―保守しやすい 成長し続けるコードの書き方
2024年12月25日紙版発売
2024年12月25日電子版発売
仙塲大也 著
A5判/408ページ
定価3,520円(本体3,200円+税10%)
ISBN 978-4-297-14622-1
書籍の概要
この本の概要
本書は,より成長させやすいコードの書き方と設計を学ぶ入門書です。筆者の経験をふまえ構成や解説内容を見直し,より実践的な一冊になりました。
システム開発では,ソフトウェアの変更が難しくなる事態が頻発します。 コードの可読性が低く調査に時間がかかる, コードの影響範囲が不明で変更すると動かなくなる, 新機能を追加したいがどこに実装すればいいかわからない……。
変更しづらいコードは,成長できないコードです。 ビジネスの進化への追随や,機能の改善が難しくなります。
成長できないコードの問題を,設計で解決します。
こんな方におすすめ
- コードの設計スキルに興味がある人
- 日々,悪いコードと向き合っていて改善したい人
- より良いコードを書きたい人
本書のサンプル
本書の紙面イメージは次のとおりです。画像をクリックすることで拡大して確認することができます。
目次
- 改訂新版 まえがき
- はじめに
- 謝辞
第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 設計技術書でさらなる高みを目指そう
- 参考文献
- 索引
この本に関連する書籍
-
良いコード/悪いコードで学ぶ設計入門 ―保守しやすい 成長し続けるコードの書き方
「ITエンジニア本大賞2023」技術書部門で大賞受賞! 本書は,より成長させやすいコードの書き方と設計を学ぶ入門書です。 システム開発では,ソフトウェアの変更...