m15-anti-pattern について
設計上のアンチパターンに焦点を当てた Rust コードレビュー用スキルです。過剰なクローンや本番コードでの unwrap などを代替案や関連スキルに結び付けます。
主な機能
- 01アンチパターンと代替案の対応
- 02所有権とエラー処理の確認
- 03コードの臭いと関連スキルの接続
- 04Rust レビュー用チェックリスト
活用シーン
- 01Rust コードの過剰なクローンの確認
- 02本番コードの unwrap の検出
- 03借用チェッカーの問題から設計を追跡
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ actionbook/ rust-skills --skill m15-anti-patternインストール後、Claude Code で/m15-anti-patternを入力して読み込まれたか確認します。
同梱ファイルpatterns/common-mistakes.md
詳細
アンチパターン
レイヤー 2:設計上の選択
中心となる問い
このパターンは設計上の問題を隠していませんか?
コードをレビューするときは、次の点を確認します。
- 症状と原因のどちらを解決していますか?
- より慣用的なアプローチはありませんか?
- Rust に逆らっていますか、それとも Rust の流れに沿っていますか?
アンチパターン → より良いパターン
| アンチパターン | 問題点 | より良い方法 |
|---|---|---|
あらゆる場所で .clone() | 所有権の問題を隠します | 適切な参照または所有権 |
本番環境での .unwrap() | 実行時にパニックします | ?、expect、またはエラー処理 |
単独の所有者なのに Rc | 不要なオーバーヘッド | シンプルな所有権 |
手軽さのための unsafe | 未定義動作のリスク | 安全なパターンを探す |
Deref による OOP | 誤解を招く API | コンポジション、トレイト |
| 巨大な match アーム | 保守が困難 | メソッドに切り出す |
あらゆる場所で String | 不要なアロケーション | &str、Cow<str> |
#[must_use] の無視 | エラーの見落とし | 処理するか let _ = を使う |
考えるための問い
疑わしいコードを見つけたとき:
-
これは症状ですか、それとも原因ですか?
- 借用を避けるために Clone していますか? → 所有権設計の問題
- 「失敗しないから」と Unwrap していますか? → 未処理のケース
-
慣用的なコードはどのようなものでしょうか?
- Clone ではなく参照を使う
- インデックスループではなくイテレーターを使う
- フラグではなくパターンマッチングを使う
-
Rust に逆らっていませんか?
- 借用チェッカーと格闘している → 構造を見直す
unsafeを過剰に使っている → 安全なパターンを探す
上位をたどる ↑
設計の理解のために:
"Why does my code have so many clones?"
↑ Ask: Is the ownership model correct?
↑ Check: m09-domain (data flow design)
↑ Check: m01-ownership (reference patterns)
| アンチパターン | たどり先 | 問い |
|---|---|---|
| あらゆる場所で Clone | m01-ownership | このデータを所有すべきなのは誰ですか? |
| あらゆる場所で Unwrap | m06-error-handling | エラー処理の方針は何ですか? |
| あらゆる場所で Rc | m09-domain | 所有権は明確ですか? |
| ライフタイムとの格闘 | m09-domain | データ構造を変えるべきですか? |
下位をたどる ↓
実装(レイヤー 1)へ:
"Replace clone with proper ownership"
↓ m01-ownership: Reference patterns
↓ m02-resource: Smart pointer if needed
"Replace unwrap with proper handling"
↓ m06-error-handling: ? operator
↓ m06-error-handling: expect with message
初心者によくある間違いトップ 5
| 順位 | 間違い | 修正方法 |
|---|---|---|
| 1 | 借用チェッカーを回避するために Clone する | 参照を使う |
| 2 | 本番環境で Unwrap する | ? で伝播させる |
| 3 | 何にでも String を使う | &str を使う |
| 4 | インデックスループを使う | イテレーターを使う |
| 5 | ライフタイムと格闘する | データを所有するように構造を見直す |
コードの臭い → リファクタリング
| 臭い | 示唆する問題 | リファクタリング |
|---|---|---|
.clone() が多い | 所有権が不明確 | データフローを明確にする |
.unwrap() が多い | エラー処理が不足している | 適切なエラー処理を追加する |
pub フィールドが多い | カプセル化が崩れている | 非公開にしてアクセサーを追加する |
| ネストが深い | ロジックが複雑 | メソッドに切り出す |
| 関数が長い | 複数の責務を持っている | 分割する |
| 列挙型が巨大 | 抽象化が不足している | トレイトと型を使う |
よくあるエラーパターン
| エラー | アンチパターンの原因 | 修正方法 |
|---|---|---|
| E0382 move 後の使用 | 所有権ではなく Clone を使っている | 適切な参照 |
| 本番環境でのパニック | あらゆる場所で Unwrap | ?、マッチング |
| パフォーマンスの低下 | すべてのテキストに String を使う | &str、Cow |
| 借用チェッカーとの格闘 | 不適切な構造 | 構造を見直す |
| メモリの肥大化 | あらゆる場所で Rc/Arc | シンプルな所有権 |
非推奨 → より良い方法
| 非推奨 | より良い方法 |
|---|---|
| インデックスベースのループ | .iter()、.enumerate() |
collect::<Vec<_>>() してから反復 | イテレーターを連結する |
| 手動の unsafe cell | Cell、RefCell |
キャストのための mem::transmute | as または TryFrom |
| 独自の連結リスト | Vec、VecDeque |
lazy_static! | std::sync::OnceLock |
すばやく確認するためのチェックリスト
- 正当な理由のない
.clone()がない - ライブラリーコードで
.unwrap()を使っていない - 不変条件を持つフィールドを
pubにしていない - イテレーターを使える場面でインデックスループを使っていない
-
&strで十分な場面でStringを使っていない -
#[must_use]の警告を無視していない - SAFETY コメントのない
unsafeがない - 巨大な関数(50 行超)がない
関連スキル
| 場面 | 参照先 |
|---|---|
| 所有権のパターン | m01-ownership |
| エラー処理 | m06-error-handling |
| メンタルモデル | m14-mental-model |
| パフォーマンス | m10-performance |
コメント
Markdown 対応