pragmatic-programmer について
開発者やエンジニアリングチーム向けのソフトウェア設計スキルです。The Pragmatic Programmer の考え方をもとに、アーキテクチャ、コードレビュー、開発習慣を導き、理解しやすく変更しやすいシステムを目指します。原則の診断と改善策も扱います。
主な機能
- 01DRY による知識の重複特定
- 02直交性のあるコンポーネント設計
- 03トレーサーバレットとプロトタイプの活用
- 04契約とアサーションの定義
- 05割れ窓と技術的負債への対処
- 06可逆的な判断と幅のある見積もり
活用シーン
- 01結合度と変更影響を意識した設計レビュー
- 02薄いエンドツーエンド実装の計画
- 03モジュールの事前条件と不変条件の設定
- 04ベンダー選定と見積もりの評価
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ wondelai/ skills --skill pragmatic-programmerインストール後、Claude Code で/pragmatic-programmerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/broken-windows.mdcontracts-assertions.mddry-orthogonality.mdestimation-portfolio.mdreversibility.mdtracer-bullets.md詳細
The Pragmatic Programmer フレームワーク
Hunt & Thomas の「The Pragmatic Programmer」(20 周年記念版)が示す、ソフトウェアのクラフトマンシップへのシステムレベルのアプローチです。システムの設計、アーキテクチャのレビュー、コードの記述、エンジニアリング文化への助言を行うときに、こうしたメタ原則を適用してください。ソフトウェアをどう書くかだけでなく、どう考えるかを示します。
基本原則
自分の仕事に誇りを持ちましょう。 ソフトウェア開発には、継続的な学習、規律ある実践、そして個人としての責任が求められます。プラグマティックなプログラマーは、目の前の問題だけでなく、その文脈、トレードオフ、長期的な影響まで考えます。優れたソフトウェアは優れた習慣から生まれます。重複を徹底的に排除し、コンポーネントを直交させ、すべてのコード行を価値を示すべき生きた資産として扱いましょう。目標は完璧さではありません。変更しやすく、理解しやすく、信頼しやすいシステムを作ることです。
スコアリング
目標:10/10。 7 つのクイック診断項目に基づいて採点します。「はい」と答えた項目ごとに約 1.4 点を加算します(7 項目すべてが「はい」なら 10 点)。次に、結果を次の基準に当てはめます。
- 9-10:すべての原則が守られています。DRY に基づいた知識、直交するレイヤー、動作するトレーサースライス、境界での契約、壊れた窓がないこと、元に戻せるベンダー/DB の選択、幅を持たせた見積もりができています。
- 5-6:実際の変更工数を増やす違反が 1~2 件あります(例:ビジネスロジックが DB と密結合している、単一のポイント見積もりを使っている)。
- <=3:重複、グローバル状態、または壊れた窓の蓄積が広範囲にわたり、エントロピーが勝っています。
必ずスコアを示し、診断で不合格となった項目を挙げ、10/10 に到達するために「アクション」列に記載された具体的な修正方法を示してください。
7 つのメタ原則
長く使えるソフトウェアを構築するための 7 つの原則です。
1. DRY(Don't Repeat Yourself)
基本概念: すべての知識は、システム内で単一の、曖昧さのない、信頼できる表現を持つ必要があります。DRY が対象とするのはコードではなく知識です。ロジック、ビジネスルール、設定の重複は、構文の重複よりもはるかに危険です。
有効な理由: 重複した知識を変更するには、複数の場所を更新する必要があります。やがて更新漏れが発生し、不整合を招きます。DRY はバグが入り込む余地を減らし、システムを変更しやすくします。
重要なポイント:
- DRY が対象とするのは知識と意図であり、テキスト上の類似性ではありません。異なるビジネスルールに使われる同一のコードブロック 2 つは、重複ではありません
- 重複には 4 種類あります。強制的な重複(環境によって避けられない)、不注意による重複(開発者が気づいていない)、性急な重複(抽象化するのが面倒)、開発者間の重複(複数の人が重複して実装する)
- コードの内容を言い換えるコメントは DRY に反します。「何を」ではなく「なぜ」を説明しましょう
- データベーススキーマ、API 仕様、ドキュメントは、単一のソースから生成されない限り、知識を重複させます
- DRY の対義語は WET です。「Write Everything Twice(すべてを 2 回書く)」または「We Enjoy Typing(入力を楽しもう)」
コードへの適用:
| コンテキスト | パターン | 例 |
|---|---|---|
| 設定値 | 信頼できる唯一の情報源 | DB 接続設定を 1 つの環境ファイルに置き、すべての場所から参照する |
| バリデーションルール | 共有スキーマ | クライアントとサーバーで 1 つの JSON Schema または Zod スキーマを使う |
| API 契約 | 仕様から生成する | OpenAPI 仕様から型、ドキュメント、クライアントコードを生成する |
特定の重複を分類するときや、2 つのコードブロックが本当に同じ知識を表しているか判断するときは、references/dry-orthogonality.md を参照してください。4 種類の重複それぞれについて、例と軽減策が記載されています。
2. 直交性
核となる概念: あるコンポーネントに加えた変更が別のコンポーネントに影響しない場合、その2つは直交しているといえます。コンポーネントが自己完結していて、独立し、明確に定義された単一の目的を持つシステムを設計します。
効果がある理由: 疎結合にすると変更の影響を局所化できます。あるモジュールの修正が無関係なモジュールに波及しないため、影響範囲を限定できます。データベース層を変更してもUIは壊れず、認証プロバイダーを変更してもビジネスロジックには影響しないはずです。
重要なポイント:
- 「ある関数の背後にある要件を大幅に変更したら、影響を受けるモジュールはいくつあるか」と考えてみましょう。答えは1つであるべきです
- 無関係な要素間の影響をなくします。ログの変更で請求処理が壊れるようなことがあってはなりません
- 階層型アーキテクチャは直交性を高めます。プレゼンテーション、ドメインロジック、データアクセスに分けます
- グローバルデータは避けましょう。グローバル状態を利用するすべてのコンシューマーは、その状態に結合してしまいます
- クラスの継承を強制するフレームワークは、直交性を損ないます
コードへの適用例:
| コンテキスト | パターン | 例 |
|---|---|---|
| アーキテクチャ | 階層の分離 | Controller -> Service -> Repository。それぞれを置き換え可能にする |
| 依存関係 | 依存性注入 | 具象クラスの SlackClient ではなく、Notifier インターフェースを渡す |
| テスト | 分離されたユニットテスト | データベース、ネットワーク、ファイルシステムを使わずにビジネスロジックをテストする |
結合度の測定や、疎結合な階層へのリファクタリングを行う際は、references/dry-orthogonality.mdを参照してください。変更の影響テストと見知らぬ人テスト、階層型アーキテクチャの図、ヘリコプターのたとえを紹介しています。
3. トレーサー・バレットとプロトタイプ
核となる概念: トレーサー・バレットは、最小限の機能でシステムのすべての層をつなぐ、エンドツーエンドの実装です。使い捨てのプロトタイプとは異なり、トレーサー・バレットのコードは本番コードです。薄くても、実際に動くものです。
効果がある理由: トレーサー・バレットを使うと、すべての機能を作り込む前に、エンドツーエンドのフィードバックをすぐに得られます。ユーザーは実際に動くものを見られ、開発者はその上に構築するためのフレームワークを得られ、統合上の問題も早期に表面化します。
重要なポイント:
- トレーサー・バレット:システムを通る、薄くても完結した経路(UI -> API -> DB)。これは残します
- プロトタイプ:リスクの高い要素を1つに絞って検証します。これは使い捨てです
- 要件が曖昧で、アーキテクチャが未検証など、「暗闇で撃つ」ような状況ではトレーサー・バレットを使います
- トレーサーが的を外したら、調整してもう一度撃ちます。反復のコストは低く抑えられます
- プロトタイプには使い捨てであることを明記します。本番コードにしてはいけません
コードへの適用例:
| コンテキスト | パターン | 例 |
|---|---|---|
| 新規プロジェクト | 垂直スライス | 1つの機能をエンドツーエンドで実装する:ボタン -> API -> DB -> 応答 |
| 不確実な技術 | スパイクプロトタイプ | WebSocketの性能を検証してから採用を決める |
| マイクロサービス | ウォーキングスケルトン | CI/CDパイプライン全体を通るHello Worldサービス |
新規プロジェクトでトレーサーとプロトタイプのどちらを使うか決める際や、ウォーキングスケルトンを構築する際は、references/tracer-bullets.mdを参照してください。暗闇で撃つ状況の判断、反復のループ、よくある落とし穴を紹介しています。
4. 契約による設計とアサーティブプログラミング
中核となる概念: 事前条件(実行前に満たされている必要がある条件)、事後条件(実行後に保証される条件)、不変条件(常に真である条件)を通じて、ソフトウェアモジュールの権利と責任を定義し、適用します。契約に違反した場合は、ただちに明確なエラーで失敗させます。
効果がある理由: 契約によって前提が明示されます。データをひそかに破損させたり、無効な状態で何とか動き続けたりするのではなく、問題が発生した時点でシステムがクラッシュします――停止したプログラムはうそをつきません。
主なポイント:
- 事前条件:呼び出し側の責任――「正の整数のみを受け付けます」
- 事後条件:ルーチンの保証――「ソート済みのリストを返します」
- 不変条件:常に真である条件――「口座残高は決してマイナスになりません」
- 早期にクラッシュさせる:機能不全に陥ったプログラムより、停止したプログラムのほうが被害ははるかに少なくなります
- 決して起きてはならないことにはアサーションを使い、起きる可能性があることにはエラー処理を使います
- 動的言語では、実行時チェックとガード節を使って契約を実装します
コードでの適用例:
| コンテキスト | パターン | 例 |
|---|---|---|
| 関数の開始時 | 事前条件のガード | 関数の冒頭で assert age >= 0, "Age cannot be negative" を実行 |
| クラスの状態 | 不変条件の検証 | 状態が変更されるたびに validate! を呼び出す |
| API 境界 | スキーマ検証 | 処理の前に、リクエストボディをスキーマに照らして検証 |
参照:references/contracts-assertions.md。ルーチンに契約を追加するときや、アサーションとエラー処理のどちらを使うか判断するときにご覧ください。事前条件・事後条件・不変条件の具体例、動的言語でのガード節、アサーションとエラー処理の境界を解説しています。
5. 割れ窓理論
中核となる概念: 割れた窓が一つ――設計の悪いコード、まずい管理上の決定、「あとで直す」つもりのハック――あるだけで、腐敗が始まります。システムに放置の兆候が現れると、エントロピーが加速し、規律が崩れていきます。
効果がある理由: 心理的な要因です。コードがきれいであれば、開発者はその状態を保とうとする社会的な圧力を感じます。一方、コードがすでに乱雑であれば、さらに乱雑にすることへの抵抗はなくなります。品質はチームの習慣であり、個人の英雄的な努力によって実現するものではありません。
主なポイント:
- 割れた窓(悪い設計、誤った決定、質の低いコード)を放置しないでください
- すぐに直せない場合は、板で塞いでください。チケットに紐づけた TODO、無効化した機能、スタブなどが使えます
- 変化のきっかけを作り、未来の姿を実際に動く形で見せてください(ストーンスープ)
- ゆっくりとした劣化(ゆでガエル)に注意し、技術的負債の指標を継続的に監視してください
- 最初のハックは、その後のすべてのハックを許すことになるため、最も高くつきます
コードでの適用例:
| コンテキスト | パターン | 例 |
|---|---|---|
| レガシーコード | 窓を板で塞ぐ | 機能を追加する前に、問題のあるコードをクリーンなインターフェースでラップする |
| コードレビュー | 新たな負債を一切許さない | チケットなしで // TODO: fix later を追加する PR を却下する |
| 技術的負債 | 負債予算 | 各スプリントの 20% を割れた窓の修復に充てる |
参照:references/broken-windows.md。チームが放置を当たり前のものとしている場合や、立て直しを進める必要がある場合にご覧ください。修復戦略、ストーンスープによる変化のきっかけづくり、品質を重視する文化の築き方を解説しています。
6. 可逆性と柔軟性
中核となる考え方: 最終的な決定というものはありません。データベース、フレームワーク、ベンダー、アーキテクチャ、デプロイ先について、考えを変えやすいシステムを構築しましょう。変更コストは、変更範囲に比例するべきです。
有効な理由: 要件は変わり、ベンダーは買収され、テクノロジーは時代遅れになります。アーキテクチャにこれらの前提がハードコードされていると、変更のたびに書き直しが必要になります。柔軟なアーキテクチャでは、決定を構造ではなく設定として扱います。
重要なポイント:
- サードパーティ依存関係は独自のインターフェースの背後に抽象化し、ベンダー API をビジネスロジックに決して漏らさないようにします
- 「分岐点」テスト:Postgres から DynamoDB に1週間で切り替えられますか? できないなら、密結合しています
- メタデータ駆動型システム(設定ファイル、機能フラグ)は、ハードコードされたロジックより柔軟です
- YAGNI は時期尚早な抽象化にも当てはまります。まだ必要のない柔軟性を作り込まないでください
- 可逆性とは未来を予測することではありません。行き詰まるような状況を作らないことです
コードでの適用例:
| コンテキスト | パターン | 例 |
|---|---|---|
| データベース | リポジトリパターン | ビジネスロジックでは pg.query(...) ではなく repo.save(user) を呼び出します |
| 外部 API | アダプター/ラッパー | PaymentGateway インターフェースで Stripe をラップし、後から Braintree に切り替えられます |
| 機能フラグ | 実行時の切り替え | 新しいチェックアウトフローをフラグで制御し、数秒でロールバックできます |
ベンダーやフレームワークを選定するとき、または決定にどの程度の可逆性が必要かを検討するときは、references/reversibility.md を参照してください。レイヤーごとの可逆性パターン、「分岐点」テスト、可逆性を最適化すべきでない状況について説明しています。
7. 見積もりと知識ポートフォリオ
中核となる考え方: スコープを理解し、モデルを作り、コンポーネントに分解して幅を持たせた見積もりを提示することで、信頼性の高い見積もりを学びます。学習は金融ポートフォリオのように管理しましょう。定期的に投資し、分散させ、リバランスします。
有効な理由: 誠実な見積もりはステークホルダーとの信頼を築きます(自信満々に間違った「2週間」と言うより、「1~3週間」のほうが適切です)。知識ポートフォリオがあれば、テクノロジーの変化に合わせて価値を保てます。学ぶことをやめたプログラマーは、効果的に働けなくなります。
重要なポイント:
- 「この見積もりは何のためですか?」と尋ねます。状況によって必要な精度は異なります(予算計画とスプリント計画など)
- PERT を使用します:(楽観値 + 最頻値 × 4 + 悲観値)/ 6
- コンポーネントに分解して個別に見積もります。その合計は、単一の推測よりも正確です
- 見積もりログを記録します。見積もりと実績を比較して、精度を調整します
- ポートフォリオのルール:定期的に投資する(毎週学ぶ)、現在の技術スタック以外にも分散する、安全な選択肢と投機的な選択肢を組み合わせる、新興技術を早い段階で学ぶ(安いうちに買う)
コードでの適用例:
| コンテキスト | パターン | 例 |
|---|---|---|
| スプリント計画 | 幅を持たせた見積もり | 単一の数値ではなく、確信度を添えて「3~5日」とします |
| 新しいテクノロジー | 期間を限定した調査 | 「評価に2日かけます。その後、適切に見積もれます」 |
| 学習 | 毎週の投資 | 新しい言語、ツール、または分野に週1時間を費やします |
守る必要のある見積もりを作成するときや、過去の見積もりの誤差を調整するときは、references/estimation-portfolio.md を参照してください。PERT と分解の手順、見積もりログによる精度調整のループ、ポートフォリオのリバランスについて説明しています。
よくある間違い
| 間違い | 失敗する理由 | 修正方法 |
|---|---|---|
| 目的が異なるのに、似て見えるコードを DRY にする | 無関係な概念が結び付けられ、一方を変更するともう一方も壊れます | 偶然コードが似ているだけの箇所ではなく、知識だけを DRY にします |
| トレーサーバレットを省き、レイヤーごとに構築する | 統合上の問題が後になって発覚し、エンドツーエンドのフィードバックが得られません | まず、薄い垂直スライスを 1 つ構築します |
| 「後でリファクタリングするから」と、割れ窓を放置する | エントロピーが加速し、後回しはそのままになり、士気も下がります | すぐに修正するか、チケットを作成して追跡しながら一時的にふさぎます |
| 単一の数値で見積もりを約束する | 予測が外れると、見せかけの精度によって信頼が損なわれます | 常に信頼度を添えて範囲で提示します |
| 最初からすべてを「柔軟」にする | 過剰設計となり、必要性の証拠がないまま抽象化することになります | 必要になる具体的な証拠が得られてから、柔軟性を追加します |
| 「パフォーマンスのため」に本番環境のアサーションを削除する | アサーションが検出するはずのバグが、気付かれないままデータを破損させます | 重要なアサーションは残し、削除する前にベンチマークを実施します |
| 「便利だから」とグローバル状態を使う | 直交性が失われ、あらゆるものが互いに結合します | 依存性注入と明示的なパラメーターを使用します |
クイック診断
| 質問 | いいえの場合 | 対応 |
|---|---|---|
| ビジネスロジックに触れずにデータベースを変更できますか? | 直交性の違反 | リポジトリ/アダプターパターンを導入します |
| エンドツーエンドで動作するスライスがありますか? | トレーサーバレットが不足しています | 拡張する前に、垂直スライスを 1 つ構築します |
| すべてのビジネスルールが、ちょうど 1 か所で定義されていますか? | DRY 違反 | 正式な情報源を特定し、重複を取り除きます |
| 新しい開発者は、このコードベースを「クリーン」と呼ぶでしょうか? | 割れ窓が残っています | 専用のクリーンアップスプリントを予定します |
| 見積もりに範囲と信頼度を含めていますか? | 見積もりに問題があります | PERT または範囲に基づく見積もりに切り替えます |
| 5 分以内にこのデプロイをロールバックできますか? | 可逆性に課題があります | フィーチャーフラグとブルーグリーンデプロイを追加します |
| 毎週、新しいことを学んでいますか? | 知識の蓄積が停滞しています | 毎週の学習時間を確保し、記録します |
さらに読む
- Andrew Hunt と David Thomas 著、The Pragmatic Programmer: Your Journey to Mastery, 20th Anniversary Edition
著者について
Andrew Hunt と David Thomas は Pragmatic Bookshelf を共同創業し、アジャイルマニフェストの当初の著者 17 名の一員でした。Thomas は「DRY」と「Code Kata」という言葉を生み出し、『Programming Ruby』(通称「Pickaxe book」)を共著しました。Hunt は、チームの学習、コミュニケーション、品質維持に注力しています。2 人は共に、これまでに出版されたソフトウェア書籍の中でも特に大きな影響を与えた 1 冊である『The Pragmatic Programmer』を執筆しました。