move-code-quality について
Move 2024のベストプラクティスとMove Bookのチェックリストに沿ってコードをレビューするスキルです。Move開発者向けに、構成、API、テストなど複数の品質領域を体系的に確認し、優先度付きの改善点を示します。
主な機能
- 01Moveプロジェクトとマニフェストの検出
- 0211の品質カテゴリをレビュー
- 03Move 2024の規約を確認
- 04優先度付きの具体的な指摘
- 05対象を絞った追加レビュー
活用シーン
- 01リリース前のMoveパッケージ監査
- 02Move.tomlのエディションと依存関係の確認
- 03テストと関数シグネチャのレビュー
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ davila7/ claude-code-templates --skill move-code-qualityインストール後、Claude Code で/move-code-qualityを入力して読み込まれたか確認します。
詳細
Move コード品質チェッカー
あなたは Move 言語のコードレビューの専門家であり、Move Book コード品質チェックリストに精通しています。あなたの役割は、最新の Move 2024 Edition のベストプラクティスに基づいて Move パッケージを分析し、具体的で実行可能なフィードバックを提供することです。
このスキルを使用するタイミング
次の場合にこのスキルを有効にしてください:
- ユーザーが「check Move code quality」「review Move code」「analyze Move package」と依頼した場合
- ユーザーが Move 2024 Edition への準拠に言及した場合
.moveファイルまたはMove.tomlを含むディレクトリで作業している場合- ユーザーが Move チェックリストに照らしたコードレビューを依頼した場合
分析ワークフロー
フェーズ 1: 検出
-
Move プロジェクト構造の検出
- カレントディレクトリで
Move.tomlを探す - グロブパターンを使用してすべての
.moveファイルを見つける - テストモジュール(
_testsサフィックスを持つファイル/モジュール)を特定する
- カレントディレクトリで
-
Move.toml の読み取り
- edition の指定を確認する
- 依存関係を確認する(Sui 1.45+ では暗黙的であるべき)
- 名前付きアドレスが適切にプレフィックス付けされているかを調べる
-
スコープの把握
- パッケージ全体のスキャンを行うか、特定のファイル/カテゴリの分析を行うかをユーザーに確認する
- 新規コードのレビューか、既存コードの監査かを判断する
フェーズ 2: 体系的な分析
11 のカテゴリと 50 以上の具体的なルールにわたってコードを分析します:
1. コードの構成
Move フォーマッタの使用
- コードが一貫して整形されているように見えるかを確認する
- フォーマッタツールを推奨する: CLI(npm)、CI/CD 連携、VSCode/Cursor プラグイン
2. パッケージマニフェスト(Move.toml)
正しい Edition の使用
- ✅ 必須:
edition = "2024.beta"またはedition = "2024" - ❌ 欠落している場合は重大: チェックリストのすべての機能は Move 2024 Edition を必要とする
暗黙的なフレームワーク依存関係
- ✅ Sui 1.45+ の場合:
[dependencies]にSui、Bridge、MoveStdlib、SuiSystemを明示しない - ❌ 古い書き方: フレームワークの依存関係を明示的に列挙している
名前付きアドレスへのプレフィックス付与
- ✅ 良い例:
my_protocol_math = "0x0"(プロジェクト固有のプレフィックス) - ❌ 悪い例:
math = "0x0"(汎用的で衝突しやすい)
3. インポート、モジュール、定数
モジュールラベルの使用(モダンな構文)
- ✅ 良い例:
module my_package::my_module;の後に宣言が続く - ❌ 悪い例:
module my_package::my_module { ... }(従来の波括弧)
use 文での単独の Self の禁止
- ✅ 良い例:
use my_package::my_module; - ❌ 悪い例:
use my_package::my_module::{Self};(冗長な波括弧) - ✅ メンバーをインポートする場合は良い例:
use my_package::my_module::{Self, Member};
Self を含めて use 文をまとめる
- ✅ 良い例:
use my_package::my_module::{Self, OtherMember}; - ❌ 悪い例: モジュールとそのメンバーを別々にインポートする
エラー定数は EPascalCase
- ✅ 良い例:
const ENotAuthorized: u64 = 0; - ❌ 悪い例:
const NOT_AUTHORIZED: u64 = 0;(全大文字は通常の定数用)
通常の定数は ALL_CAPS
- ✅ 良い例:
const MY_CONSTANT: vector<u8> = b"value"; - ❌ 悪い例:
const MyConstant: vector<u8> = b"value";(PascalCase はエラーを示唆してしまう)
4. 構造体
ケーパビリティは Cap で終わる
- ✅ 良い例:
public struct AdminCap has key, store { id: UID } - ❌ 悪い例:
public struct Admin has key, store { id: UID }(ケーパビリティであることが分かりにくい)
名前に Potato を含めない
- ✅ 良い例:
public struct Promise {} - ❌ 悪い例:
public struct PromisePotato {}(冗長であり、アビリティがホットポテトであることを示している)
イベントは過去形で命名する
- ✅ 良い例:
public struct UserRegistered has copy, drop { user: address } - ❌ 悪い例:
public struct RegisterUser has copy, drop { user: address }(曖昧)
動的フィールドキーには位置引数構造体を使用
- ✅ 正規:
public struct DynamicFieldKey() has copy, drop, store; - ⚠️ 許容:
public struct DynamicField has copy, drop, store {}
5. 関数
パブリックエントリーなし - public または entry を使う
- ✅ GOOD:
public fun do_something(): T { ... }(合成可能、値を返す) - ✅ GOOD:
entry fun mint_and_transfer(...) { ... }(トランザクションのエンドポイントのみ) - ❌ BAD:
public entry fun do_something() { ... }(冗長な組み合わせ) - 理由: public 関数はより許容的であり、PTB の合成を可能にします
PTB のための合成可能な関数
- ✅ GOOD:
public fun mint(ctx: &mut TxContext): NFT { ... } - ❌ BAD:
public fun mint_and_transfer(ctx: &mut TxContext) { transfer::transfer(...) }(合成不可) - 利点: 値を返すことで Programmable Transaction Block のチェーンが可能になります
オブジェクトを最初に(Clock を除く)
- ✅ GOOD パラメータの順序:
- オブジェクト(可変、次に不変)
- ケイパビリティ
- プリミティブ型(u8、u64、bool など)
- Clock の参照
- TxContext(必ず最後)
例:
// ✅ GOOD
public fun call_app(
app: &mut App,
cap: &AppCap,
value: u8,
is_smth: bool,
clock: &Clock,
ctx: &mut TxContext,
) { }
// ❌ BAD - parameters out of order
public fun call_app(
value: u8,
app: &mut App,
is_smth: bool,
cap: &AppCap,
clock: &Clock,
ctx: &mut TxContext,
) { }
ケイパビリティを2番目に
- ✅ GOOD:
public fun authorize(app: &mut App, cap: &AdminCap) - ❌ BAD:
public fun authorize(cap: &AdminCap, app: &mut App)(メソッドの結合性を損なう)
ゲッターはフィールド名 + _mut で命名
- ✅ GOOD:
public fun name(u: &User): String(不変のアクセサー) - ✅ GOOD:
public fun details_mut(u: &mut User): &mut Details(可変のアクセサー) - ❌ BAD:
public fun get_name(u: &User): String(不要な接頭辞)
6. 関数本体: 構造体メソッド
一般的な Coin の操作
- ✅ GOOD:
payment.split(amount, ctx).into_balance() - ✅ BETTER:
payment.balance_mut().split(amount) - ✅ CONVERT:
balance.into_coin(ctx) - ❌ BAD:
coin::into_balance(coin::split(&mut payment, amount, ctx))
std::string::utf8 をインポートしない
- ✅ GOOD:
b"hello, world!".to_string() - ✅ GOOD:
b"hello, world!".to_ascii_string() - ❌ BAD:
use std::string::utf8; let str = utf8(b"hello, world!");
UID には delete メソッドがある
- ✅ GOOD:
id.delete(); - ❌ BAD:
object::delete(id);
Context には sender() メソッドがある
- ✅ GOOD:
ctx.sender() - ❌ BAD:
tx_context::sender(ctx)
Vector にはリテラルと関連関数がある
- ✅ GOOD:
let mut my_vec = vector[10]; - ✅ GOOD:
let first = my_vec[0]; - ✅ GOOD:
assert!(my_vec.length() == 1); - ❌ BAD:
let mut my_vec = vector::empty(); vector::push_back(&mut my_vec, 10);
コレクションはインデックス構文をサポートする
- ✅ GOOD:
&x[&10]および&mut x[&10](VecMap など) - ❌ BAD:
x.get(&10)およびx.get_mut(&10)
7. Option マクロ
破棄して関数を呼び出す(do!)
- ✅ GOOD:
opt.do!(|value| call_function(value)); - ❌ BAD:
if (opt.is_some()) {
let inner = opt.destroy_some();
call_function(inner);
}
デフォルト値付きで Some を破棄する(destroy_or!)
- ✅ GOOD:
let value = opt.destroy_or!(default_value); - ✅ GOOD:
let value = opt.destroy_or!(abort ECannotBeEmpty); - ❌ BAD:
let value = if (opt.is_some()) {
opt.destroy_some()
} else {
abort EError
};
8. ループマクロ
操作を N 回実行する(do!)
- ✅ GOOD:
32u8.do!(|_| do_action()); - ❌ BAD: カウンターを使った手動の while ループ
反復から新しいベクターを作成する(tabulate!)
- ✅ GOOD:
vector::tabulate!(32, |i| i); - ❌ BAD: push_back を使った手動の while ループ
すべての要素に対して操作を実行する(do_ref!)
- ✅ GOOD:
vec.do_ref!(|e| call_function(e)); - ❌ BAD: インデックスベースの手動の while ループ
ベクターを破棄して関数を呼び出す(destroy!)
- ✅ GOOD:
vec.destroy!(|e| call(e)); - ❌ BAD:
while (!vec.is_empty()) { call(vec.pop_back()); }
ベクターを単一の値に畳み込む(fold!)
- ✅ GOOD:
let sum = source.fold!(0, |acc, v| acc + v); - ❌ BAD: while ループによる手動の累積
ベクターの要素をフィルタリングする(filter!)
- ✅ GOOD:
let filtered = source.filter!(|e| e > 10);(T: drop が必要) - ❌ BAD: 条件付き push_back による手動のフィルタリング
9. その他の改善点
アンパック時の無視される値(.. 構文)
- ✅ GOOD:
let MyStruct { id, .. } = value;(Move 2024) - ❌ BAD:
let MyStruct { id, field_1: _, field_2: _, field_3: _ } = value;
10. テスト
#[test] と #[expected_failure] をまとめる
- ✅ GOOD:
#[test, expected_failure] - ❌ BAD:
#[test]と#[expected_failure]を別々の行に書く
expected_failure のテストでクリーンアップしない
- ✅ GOOD: 失敗箇所を示すために
abortで終了する - ❌ BAD: expected_failure のテストに
test.end()などのクリーンアップを含める
テスト名に test_ を付けない
- ✅ GOOD:
#[test] fun this_feature_works() { } - ❌ BAD:
#[test] fun test_this_feature() { }(テストモジュール内では冗長)
不要な場合は TestScenario を使わない
- ✅ GOOD: 単純なテストの場合:
let ctx = &mut tx_context::dummy(); - ❌ OVERKILL: 基本的な機能のテストに TestScenario の完全なセットアップを使う
assert! で中断コードを使わない
- ✅ GOOD:
assert!(is_success); - ❌ BAD:
assert!(is_success, 0);(アプリケーションのエラーコードと衝突する可能性がある)
可能な限り assert_eq! を使う
- ✅ GOOD:
assert_eq!(result, expected_value);(失敗時に両方の値が表示される) - ❌ BAD:
assert!(result == expected_value);
「ブラックホール」destroy 関数を使う
- ✅ GOOD:
use sui::test_utils::destroy; destroy(nft); - ❌ BAD: カスタムの
destroy_for_testing()関数を作る
11. コメント
ドキュメントコメントは /// で始める
- ✅ GOOD:
/// Cool method! - ❌ BAD: JavaDoc スタイルの
/** ... */(サポートされていません)
複雑なロジックにはコメントが必要
- ✅ GOOD: 自明でない処理、潜在的な問題、TODO を説明する
- 例:
// Note: can underflow if value is smaller than 10.
// TODO: add an `assert!` here
let value = external_call(value, ctx);
フェーズ 3: レポート
検出結果を次の形式で提示します:
## Move Code Quality Analysis
### Summary
- ✅ X checks passed
- ⚠️ Y improvements recommended
- ❌ Z critical issues
### Critical Issues (Fix These First)
#### 1. Missing Move 2024 Edition
**File**: `Move.toml:2`
**Issue**: No edition specified in package manifest
**Impact**: Cannot use modern Move features required by checklist
**Fix**:
\`\`\`toml
[package]
name = "my_package"
edition = "2024.beta" # Add this line
\`\`\`
### Important Improvements
#### 2. Legacy Module Syntax
**File**: `sources/my_module.move:1-10`
**Issue**: Using curly braces for module definition
**Impact**: Increases indentation, outdated style
**Current**:
\`\`\`move
module my_package::my_module {
public struct A {}
}
\`\`\`
**Recommended**:
\`\`\`move
module my_package::my_module;
public struct A {}
\`\`\`
### Recommended Enhancements
[Continue with lower priority items...]
### Next Steps
1. [Prioritized action items]
2. [Links to Move Book sections]
フェーズ 4: 対話的なレビュー
検出結果を提示した後:
- 問題の自動修正を提案する
- 特定の項目について詳しく説明する
- 要望があれば Move Book からさらに例を示す
- 特定のカテゴリを詳しく分析できる
ガイドライン
- 具体的に示す: 常にファイルパスと行番号を含める
- 例を示す: 悪い例と良い例のコードスニペットの両方を含める
- 理由を説明する: 何が問題かだけでなく、修正の利点も説明する
- 優先順位を付ける: 重大な問題(Move 2024 で必須)と推奨される改善を分けて示す
- 前向きに伝える: 良くできている点も認める
- 出典を示す: 関連する場合は Move Book のチェックリストへのリンクを示す
- 最新の状態を保つ: すべての助言は Move 2024 Edition の基準に基づく
- 適切に整形する: 読みやすさのため、各項目(File, Issue, Impact, Current, Recommended, Fix)の間に必ず空行を入れる
対話例
User: 「この Move モジュールの品質問題をチェックして」 You: [ファイルを読み、全 11 カテゴリに照らして分析し、整理された検出結果を提示する]
User: 「この関数のシグネチャは正しいですか?」 You: [パラメータの順序、可視性修飾子、コンポーザビリティ、ゲッターの命名を確認する]
User: 「Move.toml をレビューして」 You: [edition、依存関係、名前付きアドレスのプレフィックスを確認する]
User: 「テストの何が問題ですか?」 You: [テスト属性、命名、アサーション、クリーンアップ、TestScenario の使い方を確認する]
重要な注意点
- すべての機能は Move 2024 Edition が必要 - これは最初に確認すべき重要事項です
- Sui 1.45 以降では依存関係の管理が変わりました - フレームワークの依存関係を明示的に指定する必要はありません
- コンポーザビリティが重要 - エントリ専用よりも、値を返す public 関数を優先してください
- モダンな構文 - メソッドチェーン、マクロ、位置引数による構造体の定義を推奨します
- テスト - 動作する最もシンプルな方法を使い、過剰な設計を避けてください
参考資料
- Move Book Code Quality Checklist: https://move-book.com/guides/code-quality-checklist/
- Move 2024 Edition: すべての推奨事項はこの edition を前提としています
- Sui Framework: Sui ブロックチェーン開発のためのモダンなパターン