simplifying-ruby-code について
構造を簡素化しつつ意味のある振る舞いを保つ、Rubyコードレビューとリファクタリング向けのスキルです。不要なクラスの置き換え、判断とI/Oの分離、削除前の呼び出し元確認を扱います。
主な機能
- 01ステートレスなコマンドオブジェクトを関数に置換
- 02値に応じてHash、Struct、Dataを選択
- 03深い継承よりコンポジションを優先
- 04純粋な判断とI/Oを分離
- 05クラス削除前に呼び出し元を確認
- 06レビューと段階的なリファクタリングを支援
活用シーン
- 01Rubyコードの簡素化候補をレビュー
- 02RailsのサービスオブジェクトやConcernをリファクタリング
- 03クラスを安全に削除する計画
- 04計算とデータベースやファイル操作を分離
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ bostonaholic/ skills --skill simplifying-ruby-codeインストール後、Claude Code で/simplifying-ruby-codeを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlreferences/review-findings.mdscripts/find-callers.sh詳細
Ruby コードをシンプルにする
状態や振る舞いを追加しないクラスよりも、プレーンなデータ(Hash、Array、Struct、Data)と純粋関数を優先してください。判断と副作用を分離します。判断はデータを受け取ってデータを返し、副作用は I/O(データベース、ネットワーク、ファイル、時刻)を扱います。判断をモックなしでテストできるよう、別々のメソッドまたはモジュールに分けてください。
ユーザーがレビューを依頼した場合、指摘事項を報告し、編集は依頼された場合にのみ行ってください。パターンは番号(「Pattern 1」)またはアンチパターン名で示してください。
パターン
-
コマンドオブジェクトをモジュール関数にする。 唯一の公開メソッドが
call、perform、run、executeのいずれかで、コンストラクター引数以外に何も保持しないクラスは、直接呼び出しまたはモジュール関数に置き換えます(UserCreator.new(params).callはUser.create(params)になります)。呼び出しをまたいで状態を保持する場合、名前を付ける価値のある複数ステップのアルゴリズムを実行する場合、またはバックグラウンドジョブのようにシリアライズする必要がある場合は、オブジェクトのままにします。 -
値オブジェクトを Data、Struct、または Hash にする。 手書きの
initialize、アクセサー、または==があり、振る舞いや検証を持たず、属性を保存するだけのクラスは、次のようにします。使用する型 場合 Hash 一時的なデータ、キーが変化するデータ、JSON の入出力 Struct 属性が固定で、変更可能なデータ Data 属性が固定で、イミュータブルなデータ( ruby -v>= 3.2 を確認)Custom class 検証、不変条件、または実際のドメイン動作がある場合 -
クラスメソッドのみのクラスをモジュールにする。 インスタンス化されず、
self.メソッドのみを定義するクラスは、module_functionを使うモジュールに置き換えます。 -
深い継承をコンポジションにする。 プロジェクト独自のクラスのみを数えて 2 階層を超える場合、または抽象基底クラスにサブクラスが 1 つだけある場合が該当します(
ApplicationRecordやStandardErrorなど、フレームワークや標準ライブラリの基底クラスは数えません)。 -
Ruby プロトコルの不足。 呼び出し側がコレクション風または値風のクラスを手作業で展開している場合は、
Enumerableを使ったeach、to_h、Comparableを使った<=>、またはhashとeql?を実装してください。 -
判断と副作用の混在。 テストに多くのモックが必要な場合や、1 つのメソッド本体で計算と書き込みを行う場合が該当します。計算を純粋関数に抽出し、I/O を行うメソッドは薄く保ちます。
Rails のアンチパターン
- サービスオブジェクト: 単一メソッドでステートレスなサービスは、モデルメソッドまたはモジュール関数にします(Pattern 1)。複雑なオーケストレーションはサービスとして維持しますが、判断と副作用を分離してください(Pattern 6)。ジョブはシリアライズされるため、正当なオブジェクトです。
- モデル: ActiveRecord モデルはクラスのままにし、ビジネス計算は純粋関数に移します。
- Concern: Concern は複数のモデル間で振る舞いを共有するためのものです。単一のモデルのための寄せ集めとして使われていたら指摘してください。
- ヘルパー: ビューの整形のみに使います。ビジネスルールはモジュールに置きます。
- Rails の再実装: スコープ、バリデーション、コールバック、列挙型、または
ActiveModelと重複するカスタム DSL や基底クラス。
プレーンな Ruby のアンチパターン
- テンプレートメソッド: ブロックで実現できるのに、フックメソッドを持つ基底クラスを使うこと。
- ビルダー: キーワード引数や
Data.defineで直接構築できるオブジェクトにビルダーを使うこと。 - ラッパー: Array、Hash、Set、またはその他の標準ライブラリ型をラップし、大半の呼び出しを転送するクラス。
- メタプログラミング: プレーンなメソッドで実現できるのに、
method_missing、define_method、またはinstance_evalを使った DSL を使うこと。 - 依存関係: 標準ライブラリのコード数行のために gem を追加すること。
gem では、公開定数はすべて、他のプロジェクトから呼び出される可能性のある API です。
クラスを削除またはインライン化する前に
- 各クラスについて、
bash <skill-dir>/scripts/find-callers.sh <Constant> <project>を実行します。 - 終了コード0:すべての
referenceとrequireのヒットに対処し、各dynamicのヒットについて、組み立てられる名前がそのクラスになり得るかを判断します。その判断にはコードを読む必要があるため、あなた自身で行ってください。 - 終了コード1:呼び出し元は見つかりませんでした。終了コード2:引数を修正してください。終了コード3:指定されたツールをインストールしてください。終了コード4:grepエラーを報告してください。
- コントローラーは、スクリプトが検索しないスネークケースのリソース名を使って
config/routes.rbからも呼び出されます。このファイルを確認してください。 - レビューでは、呼び出し元を確認できない指摘は削除するか、重要度を下げてください。
レビューの指摘
レビューを報告する際は、レビューの指摘を読み、指摘のグループ分け、各指摘のフィールド、締めくくりの順序を確認してください。
リファクタリング
まず、すべてのテストが成功するベースラインを確立してください。パターンを1つずつ適用し、それぞれの後にテストスイートを実行します。失敗した場合は、先に進む前にそのステップを修正するか、元に戻してください。削除したレイヤーをモックしていたテストは、純粋関数または直接のAPIを呼び出すように更新してください。