yagni について
ソフトウェア開発者向けに YAGNI 原則を扱うスキルです。現在の要件を実装し、実際の必要性が生じてから抽象化する考え方を、判断ルール、アンチパターン、適用範囲、コードレビュー項目で示します。
主な機能
- 01現在の要件に集中
- 023回目の重複で抽象化
- 03推測によるコードの削除
- 04早すぎる拡張機構の回避
- 05コードレビュー用チェックリスト
活用シーン
- 01抽象化が必要かどうかの判断
- 02設定項目や未使用コード経路の確認
- 03重複の統合時期の判断
MCP 対応
フレームワーク固有の詳細には context7 MCP またはウェブ検索を使うよう勧めています。`.agents/stack-context.md` があれば、先に読むよう記載されています。
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ jordancoin/ codingskills --skill yagniインストール後、Claude Code で/yagniを入力して読み込まれたか確認します。
詳細
YAGNI — 必要になるまで作らない
適用前
.agents/stack-context.md が存在する場合は、まず読みます。この原則は、検出されたスタックに適した慣用的なパターンを使って適用してください。フレームワーク固有の詳細については、context7 MCP またはウェブ検索を利用し、推測しないでください。
原則
将来必要になるかもしれないという仮定に基づいて作らないでください。今必要なものを作り、実際の要件が出てきたらリファクタリングします。
本番環境で重要な理由
推測に基づくコードは、意図しない複雑さを生む最大の原因です。「念のため」に追加する抽象化、設定オプション、拡張ポイントには、すべて実質的なコストがかかります。理解し、テストし、保守し、デバッグしなければなりません。使われていないコードパスは最も危険です。ひそかに劣化し、テストカバレッジに対する誤った安心感を与え、バグの入り込む範囲を広げます。
早すぎる汎化は、重複よりも悪いものです。重複は見つけやすく、後から簡単に修正できます。一方、誤った抽象化は、ほかのコードがそれに依存するようになるため、取り消すのが困難です。
ルール
- 目の前の問題を解決します。 ユースケースが1つなら、その1つのためのコードを書きます。2つではありません。「後で必要になったら」という想定も不要です。
- 3回目で抽象化します。 初めて書くときは、そのまま書きます。2回目には重複を認識します。3回目にパターンを抽出します。これで、適切な抽象化を設計するのに十分な情報が得られます。
- 推測に基づくコードパスを削除します。 一度も切り替えられていない機能フラグ、一度も変更されていない設定オプション、デフォルト以外の値が一度も渡されていないパラメーターがあれば、削除します。
- プラグインが1つしかないのに、プラグインシステムを作らないでください。 インターフェース、レジストリー、拡張ポイントが正当化されるのは、複数の具体的な実装がすでにある場合だけです。
- 不確かなときはプロトタイプを作ります。 何かが必要になるか確信が持てない場合は、ブランチで試作します。推測に基づく基盤を main にマージしないでください。
アンチパターン
- 「柔軟性のため」に、常に1つの値しか渡されないパラメーターを追加する
- 互いに直接呼び出せばよい2つのコンポーネントのために、イベントシステムを作る
- 具体的な実装が1つしかない抽象基底クラスを作る
- 変わることのない値の設定ファイルを書く
- 「後で必要になるかもしれない」という理由でデータベースの列を追加する
- パフォーマンスの問題を測定する前にキャッシュを実装する
- 関数呼び出しで十分なのに、マイクロサービスを作る
例
-- YAGNI violation: generic "processor" for one operation
class DataProcessor:
def __init__(self, strategy, validator, transformer, output_format):
self.strategy = strategy
...
-- Actually needed: one function
def process_csv_upload(file):
rows = parse_csv(file)
validate_rows(rows)
save_to_db(rows)
-- YAGNI violation: premature abstraction
interface INotificationService
class EmailNotificationService implements INotificationService
class SMSNotificationService implements INotificationService // "we might need this"
class PushNotificationService implements INotificationService // "just in case"
-- Actually needed: you only send emails today
def send_welcome_email(user):
mailer.send(to=user.email, template="welcome")
適用範囲
- YAGNI はアーキテクチャを無視するという意味ではありません。 関心の分離や明確なモジュール境界といった優れた構造は、推測に基づくものではありません。将来の変更を容易にします。YAGNI の対象は、使われていない機能であり、優れた設計ではありません。
- YAGNI はエラー処理を省略するという意味ではありません。 ネットワークエラー、無効な入力、ディスク容量不足など、既知の障害モードへの対処は推測に基づくものではありません。本番環境で実際に発生します。
- YAGNI は、コストがまったくかからない拡張性まで避けるという意味ではありません。 コードを拡張可能にするコストがかからない場合(たとえば、switch 文ではなく map を使う場合)は、そうしてください。YAGNI が対象とするのは、コストのかかる抽象化です。
- DRY との緊張関係: YAGNI を優先すべき場合もあります。誤った抽象化の背後に早まって統合するより、よく似ていても同一ではない関数を2つ用意するほうが適切です。
コードレビューのチェックリスト
- この変更に、現在の要件では実行されないコードパスが含まれていませんか?
- パラメーター、設定、オプションのうち、現時点で可能な値が1つしかないものはありませんか?
- 機能を損なわずに、直接的な実装でこの抽象化を置き換えられませんか?
- このインターフェース/トレイト/プロトコルは、複数の具体的な実装によって正当化されていますか?
- 現在のスコープに対して、もっとシンプルな方法で対応できませんか?
関連スキル
- kiss:推測ではなく、複雑さが問題の場合
- solid:正当化された抽象化を設計する場合
- dry:パターンを抽出するか判断する場合(YAGNI では、3回出現するまで待ちます)
コメント
Markdown 対応