dry について
dryは、DRY原則をコーディングエージェントに適用させるスキルです。似たコードではなく重複した知識に注目し、KISSやYAGNIとの境界も扱うため、実装やコードレビューに使えます。
主な機能
- 01知識の重複とコードの類似を区別
- 02設定・ルール・データソースの集約
- 03パターン安定後の抽象化
- 04生成による表現の同期
- 05コードレビュー用チェックリスト
活用シーン
- 01重複したビジネスルールの統合
- 02設定や定数の重複確認
- 03抽象化の早すぎや過剰さの評価
- 04ルール変更の影響ファイル数の削減
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ jordancoin/ codingskills --skill dryインストール後、Claude Code で/dryを入力して読み込まれたか確認します。
詳細
DRY — 繰り返しを避ける
適用する前に
.agents/stack-context.md が存在する場合は、まずそれを読んでください。検出されたスタックに適した慣用的なパターンを使って、この原則を適用してください。フレームワーク固有の詳細については、context7 MCP またはウェブ検索を利用し、推測しないでください。
原則
システム内の知識はすべて、単一の信頼できる表現で保持するべきです。その知識が変わったとき、変更が必要なのは1か所だけであるべきです。
本番環境で重要な理由
重複したロジックは時限爆弾です。ビジネスルールが変わったとき、ある場所は更新しても別の場所のコピーを見落とすと、一貫性のない動作が生じます。これは検出が難しく、デバッグはさらに困難です。コピーが増えるほど、そのうちの1つが気づかないうちにずれていく可能性も高くなります。
DRY は、見た目が似ているコードをなくすことではありません。重複した知識、つまり複数の場所に表現された同じビジネスルール、同じ判断、同じ信頼できる情報源をなくすことです。
ルール
- 知識の重複とコードの重複を区別する。 見た目は同じでも、異なるビジネス概念を表す2つの関数は分けたままにします。同じビジネスルールを表す2つの関数は統合します。
- データの信頼できる情報源を1つにする。 設定、定数、スキーマ定義、検証ルールは、それぞれ1か所だけに置きます。それ以外のものはすべて、その情報源から導出します。
- パターンが安定してから抽出する。 最初に現れた時点では抽出しません。適切な抽象化の形がまだわからないためです。同じ意味でパターンが少なくとも2回繰り返されるのを確認してから抽出します。
- ビジネスルールを一元化する。 税額計算、権限チェック、価格設定のロジックは、ハンドラー、フロントエンド、スクリプトに散在させず、1つのモジュールに置く必要があります。
- 手作業での同期よりコード生成を使う。 2つの表現を同期させる必要がある場合(例:API の型とクライアントの型、スキーマとドキュメント)は、両方を手作業で保守するのではなく、一方からもう一方を生成します。
アンチパターン
- ショットガン手術: 1つのビジネスルールを変更するために、そのルールがあちこちに重複しているため、5つ以上のファイルを編集する必要がある
- コピー&ペーストして変更: 元の関数をパラメーター化する代わりに、関数を複製して調整する
- 並行する階層構造: 複数のレイヤーに対応する構造を保守する(例:共有スキーマから生成されていない、バックエンドとフロントエンドの同一の型定義)
- ファイル間で繰り返されるマジック文字列: 同じステータスコード、エラーメッセージ、設定キーを複数の場所にハードコードする
- コードを言い換えるドキュメント: コードの内容を繰り返すコメントやドキュメント(そして必然的にコードとの不整合が生じる)
間違った DRY
-- Code looks similar but represents different concepts — DO NOT unify
def calculate_shipping_cost(weight, distance):
return weight * 0.5 + distance * 0.1
def calculate_insurance_premium(value, risk_factor):
return value * 0.5 + risk_factor * 0.1
-- These are different business rules that happen to share a formula today.
-- They will diverge. Keep them separate.
正しい DRY
-- Same validation rule duplicated — UNIFY
// in signup handler
if len(password) < 8 or not has_uppercase(password):
return error("Password too weak")
// in password-reset handler
if len(new_password) < 8 or not has_uppercase(new_password):
return error("Password too weak")
-- Fix: single source of truth
def validate_password(password):
if len(password) < 8:
return error("Password must be at least 8 characters")
if not has_uppercase(password):
return error("Password must contain an uppercase letter")
return ok()
境界
- DRY が扱うのは知識であり、構文ではありません。 見た目が同じコードブロックでも、異なるものを表していることがあります。見た目が同じというだけで統合しないでください。
- 時期尚早な DRY は誤った抽象化を生みます。 誤った抽象化は元に戻すのが難しいため、重複よりも厄介です。パターンを理解してから抽出してください。
- KISS との緊張関係: DRY を過度に推し進めたリファクタリングは、元の重複よりも理解しにくい間接層を生み出すことがあります。共通関数があらゆるケースに対応するために5つのパラメーターと3つのブール値フラグを必要とするなら、重複させたほうが単純だったということです。
- YAGNI との緊張関係: 「ほかでも必要になるかもしれない」という理由で汎用ユーティリティを作らないでください。具体的な重複が実際に存在する場合に抽出します。
- 境界を越える DRY はコストが高い。 サービス、リポジトリ、チーム間でコードを共有すると、結合が生じます。独立したデプロイを妨げる共有ライブラリを使うより、境界を越えて重複させたほうが健全な場合もあります。
コードレビューのチェックリスト
- この変更により、ほかの場所にすでに存在するビジネスロジックが重複していませんか?
- 定数にすべきマジック文字列やマジックナンバーはありませんか?
- このビジネスルールが変更された場合、更新が必要なファイルはいくつありますか?
- 共有の抽象化が、あまりに多くの用途に無理に対応させられていませんか?(誤った DRY)
- 手動で同期されている並行表現のうち、生成可能なものはありませんか?
関連スキル
- yagni:抽出するかどうかを判断する際に使用します(3 回目の出現まで待ちます)
- kiss:DRY の抽象化が重複よりも理解しにくくなった場合に使用します
- convention-over-configuration:繰り返される設定パターンをなくすために使用します
コメント
Markdown 対応