mcpField
D
dependency-hygiene

dependency-hygiene

github.com/zakariaf開発63150 回インストール5 週間前に更新
リポジトリ

dependency-hygiene について

dependency-hygieneは、Flutter/Dartアプリ開発向けの依存関係管理スキルです。ロックファイル、依存監査、更新、ベンダリングの手順を定め、推移的依存関係も確認します。

主な機能

  1. 01依存範囲とロックファイルの規則
  2. 02推移的依存関係の監査
  3. 03SDKとlint includeの確認
  4. 04更新と実機検証の指針
  5. 05インターフェース経由のプラグインベンダリング指針

活用シーン

  1. 01pubspec.yamlの変更レビュー
  2. 02新しいパッケージ導入前の監査
  3. 03SDKやネイティブプラグインの更新
  4. 04依存関係の削除やベンダリング

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/zakariaf/flutter-skills --skill dependency-hygiene

インストール後、Claude Code で/dependency-hygieneを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

examples/
vendored_plugin_behind_interface.dart
references/
dependency-gate-and-audit.md
sdk-pin-and-lint-include.md
vendoring-behind-an-interface.md
scripts/
audit_deps.py
audit-deps.sh

詳細

依存関係の衛生管理

依存関係はどれも、いずれ誰かが保守しなければならない負債です。「最新」ではなく、「何年後も解決してビルドできること」を優先してください。このスキルでは、pubspec と lock の仕組み、新しいパッケージが通過すべきゲート、重要なパッケージが劣化した場合の回避策を扱います。

作業内容に応じて、次のリファレンスを読んでください。

  • references/dependency-gate-and-audit.md — 拒否/受け入れのゲート、推移的依存関係の監査、ライセンスの記録、アップグレードの規律。
  • references/sdk-pin-and-lint-include.md — SDK バージョンの記録と、SDK 更新時に発生する気づきにくい lint 無効化の落とし穴。
  • references/vendoring-behind-an-interface.md — lib/ に手を加えず、バス係数が 1 のネイティブプラグインを third_party/ にベンダーする方法。

pubspec.yaml を変更する PR の前に、scripts/audit-deps.sh を実行してください。

絶対に守るルール

  1. pubspec.yaml ではキャレット範囲を使い、正確な固定は pubspec.lock のみで行います。 drift: ^2.31.0 とし、drift: 2.31.0 とはしません。lock はバージョンを固定し、範囲は解決可能な状態を保つためだけに使います。pubspec で正確なバージョンを固定すると、次回の SDK 更新時に解決不能な競合を生みますが、lock がすでに実現している以上の利点はありません。
  2. pubspec.lock をコミットします。 これはパッケージではなくアプリケーションです。その違いによってルールが逆になります。Dart のデフォルトの .gitignore テンプレートには pubspec.lock が記載されているため、その行を削除してください。コミット済みの lock だけが、実機でテストされた正確なバージョンを、他の開発者が git clone して解決できるようにします。
  3. pubspec.yaml の差分に対応する pubspec.lock の差分がなければ、不完全です。 flutter pub get を実行し、追加、アップグレード、削除のいずれの場合も、同じコミットに lock を含めてください。
  4. SDK のバージョンはツールとは別に記録します。 pub が依存関係を解決できるように、environment: sdk: は実際の範囲指定にします。テスト済みの正確な Flutter バージョンは、CI が参照するコミット済みの記録に固定してください(リファレンスを参照)。他の開発者と CI が読むのはその記録です。バージョン管理ツールとファイルを混同しないでください。
  5. lint の include ファイル名は、解決された SDK と連動しています。 バージョン固定された include: が、解決済みの linter パッケージに存在しないファイルを指定すると、include_file_not_found が出力されます。これはデフォルトの dart analyze/flutter analyze では致命的なエラーとなるため、標準の CI で検出されます。警告を致命的でない扱いにしている場合に限り、何も知らせずに成功します。その場合でも適用されなくなるのは、analyzer の組み込みルールではなく、ルールセットで追加または昇格したルールです。SDK を更新するたびに確認してください(リファレンスを参照)。
  6. パッケージを追加する前に、pubspec ではなく推移的依存関係のツリーを監査します。 禁止対象の SDK が入り込むのは、まさに 2 段目の依存関係です。新しい依存関係をコミットする前に、scripts/audit-deps.sh(または dart pub deps --json と監査スクリプトの組み合わせ)を実行してください。
  7. ネットワークへの接続経路を開く、クラッシュや使用状況を報告する、テレメトリのコアを引き込む、または未リリースの機能のためにデバイス識別子を収集するものは、直接依存でも推移的依存でも、ポリシーにより拒否します。 CI が成功しても、ネイティブ機能が動作する証拠にはなりません。ゲートのリファレンスを参照してください。
  8. 依存関係を削除した後は lib/ を grep します。 パッケージを pubspec.yaml から削除しても、推移的に解決可能なままだと、今日のビルドは通りますが、重要な clone でビルドが壊れます。analyzer が検出するのは解決されない import であり、偶然解決されている import ではありません。
  9. バス係数が 1 のネイティブプラグインは、今すぐインターフェースの背後に置き、ベンダーするのは後にします。 インターフェースは安価な保険です。まだ発生していない破損に備えて先回りしてベンダーするのは、保守の負担になります。ベンダーのリファレンスを参照してください。

pubspec では範囲を指定し、lock では固定する

すること絶対にしないこと
キャレット範囲:drift: ^2.31.0正確な固定:drift: 2.31.0
environment: sdk: ^3.6.0 — 実際の範囲指定sdk: の正確なバージョン指定
pubspec.lock をコミットするpubspec.lock を Gitignore に追加する

lock が最優先の情報源です。範囲指定は SDK アップグレード時にソルバーが更新できる状態を保ち、lock は実際に検証されたバージョンを全員が使えるようにします。

新しい依存関係が必ず通過しなければならない関門

パッケージ自体、または推移的な依存関係ツリー内の何かが次のいずれかを行う場合、そのパッケージは受け入れません。

  • 製品がネットワークを使用しない、またはオフラインファーストを約束しているのに、自分で選んでいないネットワーク経路(http、dio、ソケット、gRPC)を開く。
  • テレメトリーを行わない方針に反して、クラッシュや使用状況を報告する(Crashlytics、Sentry、あらゆる分析またはアトリビューション SDK)。
  • テレメトリー/分析のコアを推移的に取り込む。クラッシュ SDK のコアは、呼び出していなくてもストアのプライバシーラベルに悪影響を及ぼすことがあります。
  • 提供していない機能のためにデバイス識別子を収集する。
  • --enable-experiment フラグが必要である。実験機能が必要な、放置されたリポジトリはビルドできなくなります。

また、次の項目も考慮し、通常は受け入れません。インターフェースで隔離されていない、単一の保守担当者に依存するパッケージ、機能が数百行程度の自社製 Dart コードで実現できるもの、入力の手間を省くだけのものです。ライセンスも記録してください。寛容なライセンス(MIT、BSD、Apache-2.0)はベンダー化という代替手段の前提条件です。コピーレフトの依存関係では、その選択肢が失われます。チェックリストの全容は references/dependency-gate-and-audit.md を参照してください。

推移的な依存関係ツリーの監査

dart pub add --dry-run <package>     # see what would resolve, resolve nothing
dart pub deps --json > /tmp/deps.json
scripts/audit-deps.sh                 # walks the resolved set, flags banned patterns

この監査では、解決済みの依存関係グラフ全体をたどり、各名前をポリシーパターンのリストと照合して、該当項目を direct または TRANSITIVE として記録し、APK に含まれる依存関係と、ビルド/テスト専用の依存関係を分けます(禁止パッケージが dev_dependencies からのみ到達可能な場合、バイナリには含まれないため、出荷上の問題ではありません)。終了コード 1 は、その依存関係を拒否するか、該当パッケージを取り込まないものを探す必要があることを示します。パッケージを導入した依存関係を調べるには、dart pub deps | grep -B4 <name> を実行してください。

BANNED/ALLOW リストは、自分のポリシーに合わせて scripts/audit_deps.py の先頭で編集してください。ALLOW の各項目には、その横に必ず文書化された正当な理由を記載してください。

アップグレード

自分のスケジュールに合わせて dart pub outdated を実行してください。ボットはありません。**Dependabot は pub に対応したことがなく、Renovate は、個人運営のリポジトリには対応するワークフローがないにもかかわらず、PR を作成します。**役立つアイデアだけを手作業で取り入れてください。アプリの中核機能が依存するネイティブプラグインを、内容を確認せずにアップグレードしてはいけません。

**CI が成功しても、ネイティブ機能が動作する証拠にはなりません。**ヘッドレスエミュレーター上の CI ジョブでは、アプリが音声を再生する、センサーを読み取る、プラットフォームチャネルとエンドツーエンドで通信するといった動作を証明できません。integration_test で確認できるのは、チャネル呼び出しが「発行された」ことまでです。それ以上は確認できません。機能上重要なネイティブプラグイン、または SDK を更新した後は、実機で手動テストを行ってください。コード生成パッケージ(drift、freezed、json_serializable)に関わるアップグレードの後は、コードを再生成してコミットしてください。古い生成コードは CI で検出されますが、アナライザーでは検出されません(run-codegen を参照)。

単一の保守担当者に依存するプラグインのベンダー化

単一の保守担当者が管理するネイティブプラグインのうち、動作しなくなるとアプリをビルドできなくなるものは、事前に対策を計画する価値のある唯一の依存関係です。対策として、初日から薄いインターフェースを作成し、ベンダー化の際に lib/ に触れずに済むようにします。

// A port the app depends on; the plugin lives behind it. The `Gateway` suffix
// marks a thin wrapper over a SPECIFIC plugin (here flutter_secure_storage) —
// `naming-conventions` owns that Service-vs-Gateway distinction.
abstract interface class SecureStorageGateway {
  Future<void> write(String key, String value);
  Future<String?> read(String key);
}

プラグインに実際の問題が発生した場合に限り(Flutter のリリースに対してビルドできなくなった、または上流で修正されないリグレッションがリリースされた場合)、最後に正常だったタグで third_party/<plugin>/ にクローンし、pubspec の参照を path: に変更し、SHA と変更したすべての行を VENDORED.md に記録し、ライセンスで再配布が許可されていることを確認して、リファクタリングではなくパッチを適用してください。手順と適用条件の全容は references/vendoring-behind-an-interface.md を参照してください。examples/vendored_plugin_behind_interface.dart も参照してください。

依存関係の削除

pubspec のエントリーを削除し、flutter pub get を実行して、同じコミット内で pubspec.lock の差分をコミットしてください。その後、grep -r "package:<name>" lib/ を実行します。推移的に解決可能なインポートは現在はコンパイルできても、重要なクローンで問題を引き起こします。

マルチパッケージ(ワークスペース)の場合

Dart の pub ワークスペース/モノレポでは、各パッケージが範囲を指定した独自の pubspec.yaml を保持しますが、ワークスペース全体でルートにある共通のロックファイルを解決します。そのルートのロックファイルを監査し、コミットしてください。監査は、単一パッケージではなく、ワークスペース全体の解決済み依存ツリーに対して実行します。単一パッケージの pubspec からは、兄弟パッケージが共通の解決結果に持ち込む依存関係を確認できません。ワークスペースのツールチェーンの仕組みについては codegen-and-toolchain を参照してください。

アンチパターン

  • pubspec.yaml でバージョンを完全固定する。 次の SDK アップグレードが、解決不能な競合のデバッグ作業になってしまいます。バージョンはロックファイルですでに固定されています。
  • アプリで pubspec.lock を Git の追跡対象から外す。 新たにクローンすると、テスト時の依存関係ではなく、その時点で pub が選ぶ依存関係が解決されます。
  • ロックファイルの差分をコミットせずに pubspec を編集する。 次の環境では異なる依存グラフが解決されます。
  • 依存関係が安全かどうかを判断するために pubspec.yaml を読む。 禁止対象の SDK が二段目の依存関係にあれば、そこには現れません。
  • ネイティブ機能について、CI が成功したから問題ないと信頼する。 エミュレーターには音声エンジンや実際のセンサーがありません。CI の成功が証明するのは Dart のコンパイルであり、機能が動作することではありません。
  • 問題のないプラグインを先回りしてベンダー化する。 問題が起きる前から保守の負担を背負うことになります。安価な保険になるのはインターフェースであり、フォークではありません。
  • リファクタリングを伴うベンダー化をする。 third_party/ で変更したすべての行は、永続的に自分たちが保守する行になります。問題を修正したら、そこで止めてください。
  • インターフェースのない、バス係数が 1 のパッケージを追加する。 劣化したときに、その背後へベンダー版を導入するための境界がありません。

完了の定義

  • 新規または変更した依存関係にはキャレット範囲を使用し、どの pubspec.yaml にも完全固定を使っていません。
  • pubspec.yaml の変更と同じコミットに pubspec.lock の差分をステージングしています。
  • scripts/audit-deps.sh が終了コード 0 を返します(または、検出された項目すべてに正当な ALLOW エントリーがあります)。
  • SDK を更新する場合:バージョン記録を更新し、バージョン固定された lint の include: ファイルが解決済みパッケージ内に存在することを確認しています(references/sdk-pin-and-lint-include.md)。
  • 新しい依存関係のライセンスを記録しています。ベンダー化の候補である場合は、許容的なライセンスであることを確認しています。
  • 機能上重要なネイティブプラグインはインターフェースの背後に置き、そのプラグインの更新後に実機での確認を行っています。
  • 削除後に grep -r "package:<name>" lib/ の検索結果が空です。

関連スキル

  • codegen-and-toolchain — ワークスペースのリンク、ツールチェーンレベルでの SDK 固定、生成コードをコミットするか Git の追跡対象から外すか。
  • run-codegen — コード生成パッケージのアップグレード後に実行する、決定論的な build_runner の処理。
  • lint-and-style-config — バージョン固定された include: が読み込む、厳格な analysis_options.yaml。
  • service-boundary-and-native — ベンダー化の境界が依存する、副作用ごとに注入可能なインターフェースを設けるパターン。
  • naming-conventions — Service と Gateway の境界サフィックス規則を定めています。SecureStorageGateway のようなプラグインラッパーには Gateway サフィックスを使用します。
  • ci-pipeline-and-gates — 監査とロックファイルの最新性チェックを CI に組み込みます。

参考資料

コメント