effective-dart について
effective-dartは、DartとFlutterの開発者向けに、慣用的なコード、構成、ドキュメント、テストの指針をまとめたスキルです。ガイドラインに沿ったコードレビュー項目も含みます。
主な機能
- 01識別子の命名規則
- 02型と関数の指針
- 03フォーマットとファイル構成
- 04ドキュメントとテストの指針
- 05コードレビュー項目
活用シーン
- 01Dartプロジェクトのスタイル統一
- 02Flutterコード規約の確認
- 03型注釈とAPIドキュメントのレビュー
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ evanca/ flutter-ai-rules --skill effective-dartインストール後、Claude Code で/effective-dartを入力して読み込まれたか確認します。
詳細
Effective Dart スキル
このスキルでは、Effective Dart のガイドラインに従って、慣用的で高品質な Dart および Flutter コードを書く方法を定めています。
1. 命名規則
| 種類 | 規則 | 例 |
|---|---|---|
| クラス、列挙型、typedef、型パラメーター、拡張 | UpperCamelCase | MyWidget、UserState |
| パッケージ、ディレクトリ、ソースファイル | lowercase_with_underscores | user_profile.dart |
| インポート接頭辞 | lowercase_with_underscores | import '...' as my_prefix; |
| 変数、パラメーター、名前付きパラメーター、関数 | lowerCamelCase | userName、fetchData() |
- 2 文字を超える頭字語や略語は、単語のように大文字と小文字を使います。例:
HTTPRequestではなくHttpRequest。 - 略語のほうが正式名称より一般的な場合を除き、略語は避けます。
- 名前では、最も説明的な名詞を最後に置くようにします。
- コード全体で用語を一貫して使います。
- 型パラメーターには、覚えやすい慣例を使います。
E(要素)、K/V(キー/値)、T/S/U(ジェネリック型)。 - API を設計する際は、コードが文章のように読めるようにすることを検討します。
- ブール値以外のプロパティや変数には、名詞句を使います。
- ブール値のプロパティや変数には、命令形ではない動詞句を使い、肯定形を優先します。
- 名前付きブール値パラメーターでは、動詞を省略することを検討します。
- 関数名やメソッド名を
getで始めるのは避けます。API の概念がプロパティを公開するものであれば、getを省いてゲッターを使います。
2. 型と関数
- クラスを拡張または実装できるかどうかを制御するには、クラス修飾子(
final、sealed、interface、base、mixin)を使います。 - 初期化子のない変数には、型注釈を付けます。
- 型が明らかでない場合は、フィールドとトップレベル変数に型注釈を付けます。
- 関数宣言には戻り値の型を注釈します。
- 関数宣言にはパラメーターの型を注釈します。
- 型が推論されないジェネリック呼び出しには、型引数を記述します。
- 型推論に任せず、
dynamicを注釈します。 - 値を返さない非同期メンバーの戻り値の型には、
Future<void>を使います。 - 概念上プロパティにアクセスする操作には、ゲッターを使います。
- 概念上プロパティを変更する操作には、セッターを使います。
- 関数を名前にバインドするには、関数宣言を使います。
- 範囲を受け取る場合は、開始位置を含み、終了位置を含まないパラメーターを使います。
// Prefer: explicit class modifier
final class AppConfig {
final String apiUrl;
final int timeout;
const AppConfig({required this.apiUrl, required this.timeout});
}
// Prefer: sealed for exhaustive pattern matching
sealed class Result<T> {}
class Success<T> extends Result<T> { final T value; Success(this.value); }
class Failure<T> extends Result<T> { final Exception error; Failure(this.error); }
3. スタイル
dart format .
- コードのフォーマットには
dart formatを使い、手動で整形しないでください。 - すべての制御フロー文で中かっこを使います。
- 変数の値が変わらない場合は、
varよりfinalを優先します。 - コンパイル時定数には
constを使います。 - 読みやすさのため、行の長さは80 文字以下を優先します。
4. インポートとファイル
- 別のパッケージの
srcディレクトリ内にあるライブラリをインポートしないでください。 - インポートパスが
libの内部や外部に入り込まないようにします。 - パッケージ内では相対インポートパスを優先します。
- インポートパスに
/lib/や../を使わないでください。 - ライブラリファイルには、ライブラリレベルのドキュメントコメントを書くことを検討します。
5. 構成
- ファイルは単一の責務に集中させます。
- 読みやすさを保つため、ファイルの長さを抑えます。
- 関連する機能をまとめます。
- フィールドとトップレベル変数は、
finalにすることを優先します。 - クラスが対応している場合は、コンストラクターを
constにすることを検討します。 - 宣言は非公開にすることを優先し、必要なものだけを公開します。
6. 使用パターン
// Adjacent string concatenation (not +)
final greeting = 'Hello, '
'world!';
// Collection literals
final list = [1, 2, 3];
final map = {'key': 'value'};
// Initializing formals
class Point {
final double x, y;
Point(this.x, this.y);
}
// Empty constructor body
class Empty {
Empty(); // not Empty() {}
}
// rethrow to preserve stack trace
try {
doSomething();
} catch (e) {
log(e);
rethrow;
}
- コレクションを型でフィルターするには、
whereType<T>()を使います。 - ローカル変数で
varとfinalを使う際の一貫したルールに従います。 - 可能な場合は、フィールドを宣言時に初期化します。
==をオーバーライドする場合はhashCodeもオーバーライドし、==が数学的な等価性の規則に従うようにします。- 具体的な例外処理を優先します。広範囲な
catch (e)や.catchErrorハンドラーではなく、on SomeException catch (e)を使います。
7. ドキュメント
/// Returns the sum of [a] and [b].
///
/// Throws [ArgumentError] if either value is negative.
int add(int a, int b) { ... }
- コメントは文の形式にします(先頭を大文字にし、ピリオドで終えます)。
- 型とメンバーには、
/* */のブロックコメントではなく、///のドキュメントコメントを使用します。 - 公開 API にはドキュメントコメントを記述することを優先し、非公開 API にも必要に応じて記述します。
- ドキュメントコメントは、1文の要約で始め、その後は別の段落にします。
- 周囲のコンテキストと内容が重複しないようにします。
- 主な目的が副作用である関数やメソッドのコメントは、三人称の動詞で始めます。
- 値を返すことが主な目的である場合は、名詞または命令形ではない動詞句で始めます。
- ブール値の変数やプロパティのコメントは、「Whether」に続けて名詞句または動名詞句を記述します。
- ドキュメントコメントでスコープ内の識別子を参照するには、
[identifier]を使用します。 - パラメーター、戻り値、例外の説明には散文を使用します(例:「The [param]」、「Returns」、「Throws」の各セクション)。
- ドキュメントコメントはメタデータ注釈の前に記述します。
- コードが存在する理由や、その使用方法を説明します。コードの動作だけを説明するのは避けます。
8. テストのパターン
- ビジネスロジックには、
groupと説明的なtest名を使用して単体テストを記述します。
import 'package:test/test.dart';
void main() {
group('CartService', () {
late CartService cart;
setUp(() => cart = CartService());
test('addItem increases item count', () {
cart.addItem(Product(id: '1', name: 'Widget', price: 9.99));
expect(cart.items, hasLength(1));
});
test('removeItem decreases total price', () {
final product = Product(id: '1', name: 'Widget', price: 9.99);
cart.addItem(product);
cart.removeItem(product.id);
expect(cart.totalPrice, equals(0.0));
});
});
}
testWidgetsとWidgetTesterを使用してウィジェットテストを記述します。
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('LoginButton shows loading indicator when tapped',
(WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(home: LoginScreen()));
await tester.tap(find.byType(ElevatedButton));
await tester.pump();
expect(find.byType(CircularProgressIndicator), findsOneWidget);
});
}
9. コードレビューのワークフロー
Effective Dart への準拠を確認するために Dart コードをレビューする際、エージェントは次の項目を確認します。
- 命名 — すべての識別子がセクション 1 の規則に従っていることを確認します。
- 型注釈 — 公開 API のパラメーター、戻り値の型、未初期化の変数に型注釈が付いていることを確認します。
- クラス修飾子 — 適切な箇所で
final、sealed、またはinterfaceが使用されていることを確認します。 - ドキュメント — すべての公開メンバーに、1文の要約を含む
///のドキュメントコメントが付いていることを確認します。 - スタイル —
dart format --output=none --set-exit-if-changed .を実行して、フォーマットを確認します。 - 解析 —
dart analyzeを実行し、問題がゼロであることを確認します。
参考資料
コメント
Markdown 対応