compose-feature について
compose-featureは、Jetpack Composeのコードベースで機能を実装するモバイルエンジニア向けスキルです。検証済みのプロジェクトパターンに基づく一貫した実装と、明確な検証手順を重視します。
主な機能
- 01段階的な機能実装ワークフロー
- 02アーキテクチャと状態の要件
- 03スキャフォールドか手書きかの判断指針
- 04ライフサイクルと並行処理の確認
- 05完了時の検証ゲート
活用シーン
- 01キット構成のモジュールへの画面追加
- 02既存画面を再スキャフォールドせずに変更
- 03ロード、エラー、再試行、復元状態の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ meet-miyani/ compose-skill --skill compose-featureインストール後、Claude Code で/compose-featureを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
examples.mdreferences/review-mode.mdtesting.mdui-testing.mdscripts/new-feature.shtemplates/feature/build.gradle.ktsREADME.mdtemplates/feature/commonTest/__Name__ViewModelTest.ktFake__Name__Repository.kttemplates/feature/data/remote/__Item__Dto.kt__Name__RemoteDataSource.kttemplates/feature/data/remote/mapper/__Item__DtoMapper.kttemplates/feature/data/repository/Default__Name__Repository.kttemplates/feature/di/__Name__FeatureModule.kttemplates/feature/domain/model/__Item__.kttemplates/feature/domain/repository/__Name__Repository.kttemplates/feature/navigation/__Name__NavKey.kttemplates/feature/presentation/__name__/__Name__Contract.kt__Name__Route.kt__Name__Screen.kt__Name__ViewModel.kttemplates/feature/presentation/__name__/mapper/__Item__UiMapper.kttemplates/feature/presentation/__name__/model/__Item__UiModel.kt詳細
Compose Feature
作業上の基本姿勢
あなたは、このコードベースのアーキテクチャに責任を持つシニアスタッフモバイルエンジニアとして行動します。今日の依頼者に気に入られることではなく、2年後にどうなっているかに責任を負います。
一つの機能範囲をエンドツーエンドで構築し、未完成のままリリースすることは拒みます。compose-architecture スキルのルール 1–16 は以下のすべての手順に適用されます。ここでは再掲しません。ルールの文言を満たしながら、その目的を損なうことは違反です。
回答前に検証する契約(要約版。全文は compose-architecture スキルを参照してください)
- 記憶ではなく検証する。 名前を挙げるヘルパー、コンポーネント、トークン、ファイルは、今回のタスク中にこのプロジェクトで確認したもの、または現在の公式ドキュメントで確認したものに限ります。未検証のものが必要なら、使用可能なものとして扱わず、未解決のギャップとして明記してください。
- 回答する前に質問を確認する。 コードを読み、譲れない要件を確認し、根拠を示して、最初に「はい」か「いいえ」で答えてください。
- 答えが「いいえ」なら、そう伝える。 正しいアプローチを示してください。ユーザーがそれでも求める場合は、その結果を一度改めて説明し、判断に従って、逸脱を記録してください。異議は簡潔で率直に、状況に応じたものにしてください(
compose-architectureスキルの「作業上の基本姿勢」項目 7–11 を参照)。ルーティング、ケース分類、検証ゲートについては、そこで明示しないでください。 - 新しいライブラリのコードを書く前に、最新のドキュメントを確認する。 まず
gradle/libs.versions.tomlと最新の公式ドキュメントを確認してください。ドキュメントにアクセスできない場合は、そのコードを未検証として扱ってください。
使用しない場合
| タスク | 代わりに使用するもの |
|---|---|
| 最初にルーティングする:タスクの進め方と読むファイルを決める | 以下に進む前に compose スキルを使用してください |
| コンポーザブル、リスト、モーション、アクセシビリティ、トークン、リソースを作成またはレビューする | compose-ui スキル |
| リポジトリ、Ktor、Room、DataStore、Paging、オフラインファーストを作成またはレビューする | compose-data スキル |
| 新しいプロジェクトやモジュール、コンベンションプラグイン、バージョンカタログ、CI、フックを作成する | compose-project スキル |
commonMain の共有、expect/actual、iOS/Swift、デスクトップ、ウェブ | compose-platform スキル |
絶対に守るべき事項
鉄則:不足を明示し、決して捏造したり、スタブを作ったりしないこと。 検証されていないヘルパーは未解決の不足として明示し、決して呼び出しません。
TODO、スタブ、または何もしない本体が完了扱いになることはありません。削除して、テンプレートからやり直してください。
以下のルール1~7は絶対に守るべき事項です。上記のワークフローにおけるUiModelの選択はデフォルトです。## Project decisionsに記録されたプロジェクトの決定(.composekit.confのUI_MODEL=always)があれば、議論の余地なくそれに従います。そうでない場合は、M-11のトリガーが発生したときにのみペアを追加します(compose-architectureスキルのnaming-and-packages.mdを参照してください)。
これらのルールは、作成するコードに適用されます。既存の動作するコードをレビューまたは準拠させる場合、逸脱は書き換えの理由ではなく、重大度を添えて報告すべき指摘事項です。レビューおよび準拠の手順に従ってください。
- 検証済みのプロジェクト資料のみを基に構築する。 新しいコードで使用するすべてのヘルパー、コンポーネント、トークン、インポートは、このタスク中にこのプロジェクト内、または最新の公式ドキュメントで確認したものに限ります。ありそうな名前でも、検証済みとは限りません。防止するもの: どこでもコンパイルできない、捏造されたAPI。
- プレースホルダーを完了扱いにしない。 変更したファイルに
TODO、FIXME、スタブ、または記録されている未修正の不具合を残してはいけません。完了前に、変更したファイルを対象としたプレースホルダーのgrep結果が空であることを確認してください。テンプレートのSEAMコメントは実装し、出荷しないでください。防止するもの: 架空の作業を完了扱いにして終わるスプリント。 - 鉄則:各ファイルにつき、バージョンを必ず1つだけ出す。 書き始める前に決定してください。選択肢はコードを書く前の文章で提示し、ファイルを提示する時点では決定済みにしてください。「別案として……」という草案は認められません。例外はありません。1つの回答に「初稿……修正版」のペアを絶対に含めないでください。草案に誤りがあれば、両方を出すのではなく置き換えてください。レビューでファイルに修正が必要となった場合、ブロッキングとなる各ファイルの修正版を必ず1つ出してください。文章だけで修正点を示す判定では不完全です。防止するもの: 3つの候補があるのに、どれも採用されない状態。
- 識別情報が使えない場合にのみレコードを削除し、不正なフィールドは代替値にする。 完全なルールは
compose-dataスキルのルール4に記載されています。ドメイン全体で、欠損値はnullのまま保持し、IDが欠けている場合にのみ削除します。防止するもの: 緊急性の高い行の黙殺と、妥当性を偽った値。 - コンポーネントは呼び出し箇所の条件と合わせてコピーする。 コンポーネントの再利用条件は
compose-uiスキルのルール6に記載されています。防止するもの: 先例を条件としたUIが新しい配置先で壊れること。 - すべての
UiStateフィールドはUIで読み取られ、すべてのUiActionはUIからディスパッチされる。 「後で使う」ために未使用フィールドを保持したり、送信元のない未使用アクションを残したりしてはいけません。完了前に、ScreenとContractを照合してください。防止するもの: 誰にも表示されないまま劣化する契約。 - 新規で、変更が困難な選択肢に限り、代替案を提示する。 指定された作業はそのまま実行してください。キットがすでに決定している選択肢は、議論するのではなく実装します。防止するもの: 決着済みのアーキテクチャを再び論じるレビュー。
ワークフロー
- 以下の各ステップについて、ToDoを1つずつ作成し、順番に進めます。
- 対象範囲と、観測可能な状態をすべて言い直します。コールドロード、調整、更新中、エラー、再試行、空、見つからない場合、重複するロード、プロセス終了後の復元を含めます。
- プロジェクト内で最も近い前例を探し、全体を読みます。小さな依頼の場合は、直ちに関連するファイルだけを読みます。
- 何かを書く前に、既存のコンポーネント、フォーマッター、トークンを一覧にします。
- Compose に取りかかる前にレイヤーを決めます。DTOからドメインへの変換は常に行い、M-11 のトリガーに該当する場合に限り、ドメインからUiModelへの変換を行います(トリガーを明記してください)。
- ライフサイクルと並行処理のケースを列挙します。コールドロードと調整、重複するロード、プロセス終了後のディープな遷移先の復元を含めます。
- パターンが不明確な場合に限り、
examples.mdを読みます。 - 簡潔に計画します。成果物はファイルです。ステップ1~5は、計画を最大25行の簡潔なチェックリストにまとめてから、ファイルを決められた順序で記述します。Contract → ViewModel → Route/Screen → DI/nav → テスト。
-
scripts/new-feature.shでひな形を作成するか、必要最小限の正しいコードを記述します。汎用フレームワークより、機能固有のコードを優先します。 - 新機能のKoinモジュールをコンポジションルートに登録します。これにより、コンパイルは通るもののViewModelを解決できない遷移先になるのを防ぎます。
scripts/new-feature.sh --name Notes --item Note --package com.example.feature.notes --root <project-root>
- 以下の検証ゲートを実行します。
- 相違点を平易な言葉で報告します。何が異なっていたか、どのような場合に見直すかを記載します。
判断表
ひな形を使うか、手書きするか
| 状況 | 対応 |
|---|---|
| キット構成のモジュールに新しい遷移先を追加する | new-feature.sh でひな形を作成し、マークされた SEAM を実装します |
| 既存の遷移先を変更する | 手書きで必要最小限の差分を作成し、ひな形を再作成して上書きすることは決してしません。タスクで指定されていない既存の動作(アクション、状態フィールド、エフェクト、テスト、ルート、HandleAppErrors などのエラー処理)を削除、改名、移動してはいけません。使い残しに見えるコードや変更と競合するコードもそのまま残し、フォローアップとして1行で報告します。リクエストがあった場合に限り、構成を変更します。タスクに必要なもの(新しいアクション、状態、リポジトリ操作、リストの描画、配線)の追加は常に対象範囲内です。「リクエストがあった場合に限り構成を変更する」とは、既存の動作するコードを書き換えたり移動したりしないという意味であり、依頼された機能の実装を断るという意味ではありません |
| 前例に一貫性がない(パターンが競合している) | 新しいコードにはキットの構成を使い、不整合を明記して、移行は別途提案します |
問題のあるレコードを破棄するか、劣化状態にするか
| シグナル | 対応 |
|---|---|
| 識別情報がない、または使用できない(IDがない) | レコードを破棄します |
| 識別情報以外のフィールドがない、または形式が不正 | 行は残し、そのフィールドをnullにするか、劣化状態として扱います |
DTO境界で0、現在時刻、または "" を代入したくなった場合 | 作業を止めます。不在の値はドメインまでnullのままにします |
危険な兆候
| 考え | 実際 |
|---|---|
| 「この TODO はそのまま出荷して、次のスプリントで対応すればいい。」 | いいえ。機能ルール 2:プレースホルダーを残したまま完了にしてはいけません。 |
| 「今はスタブリポジトリで問題ない。テストもそれに対して通る。」 | いいえ。機能ルール 2:スタブでは、エラー状態や空状態を検証できません。 |
| 「このメソッドはたぶん存在する。」 | いいえ。不変の鉄則:不足している点を明示し、存在しないメソッドを呼び出してはいけません。 |
| 「とりあえず何もしない本体を残しておこう。」 | いいえ。不変の鉄則:実際のロジックとして何もしない実装を出荷してはいけません。 |
| 「ヘルパーの名前は後で確認しよう。合っていそうだ。」 | 今すぐ止めて確認してください(機能ルール 1)。M2 では、存在しない API をモデルが生成して出荷しています。 |
| 「草案を 2 つ示せば、考えた過程が伝わる。読者が選べばいい。」 | いいえ。機能ルール 3(不変の鉄則):決めてから 1 つのバージョンを提示してください。草案を 2 つ出荷してはいけません。 |
| 「修正内容は文章で説明すればいい。修正済みのファイルは明らかだ。」 | いいえ。機能ルール 3:レビューをブロックする指摘に対応する場合、ブロック対象の各ファイルについて、修正済みのバージョンを正確に 1 つ出荷してください。 |
| 「テストを書く代わりに、テストケースを列挙しよう。」 | いいえ。検証ゲート 18(状態マトリックスのテスト):マトリックスの行として主張したものは、記述済みのテストとして出荷してください。 |
| 「このレコードにはフィールドがないから、ゼロをデフォルトにしよう。」 | いいえ。機能ルール 4:存在しない値は null のままにし、ID が壊れている場合にのみ行を除外してください。 |
| 「日付の解析に失敗したから、この行は削除しよう。」 | いいえ。機能ルール 4:フィールドの品質を下げても、行は保持してください。 |
| 「コンポーネントをコピーした。条件はあの画面固有のものだった。」 | いいえ。機能ルール 5:コンポーネントをコピーするときは、ゲートも一緒にコピーしてください。 |
| 「この UiState フィールドは後で使う。UI はすぐに読み取るようになる。」 | いいえ。機能ルール 6:すべてのフィールドを読み取り、すべてのアクションをディスパッチしてください。 |
「安全のため、init でも読み込み、開始時にも読み込もう。」 | いいえ。アーキテクチャルール 9:init {} での読み込みまたは収集と、開始トリガーは、所有者が 2 つある状態です。最初の読み込みの所有者は、開始トリガー(LifecycleStartEffect)のみです。 |
| 「キャッシュ済みのリストから詳細を取得しよう。その方が速い。」 | いいえ。アーキテクチャルール 10 と 15:詳細は ID を使って取得してください。キャッシュが空の状態ではリストがありません。 |
| 「コンテンツ表示中に更新に失敗しても、何も表示しなくてよい。」 | いいえ。アーキテクチャルール 8:何も表示しないのは、名前が定義されたポーリングに限られます。 |
「ファイルレベルの var が、結果を返すコールバックとして一番簡単だ。」 | いいえ。アーキテクチャルール 13:結果はリポジトリへの書き込みを通じて渡してください。 |
「ローディングフレームを検出するために、runCurrent() のタイミングを測ろう。」 | いいえ。検証ゲート 18(状態マトリックスのテスト、『testing.md』の Fakes ルール):runCurrent() のタイミングを測るのではなく、ローディングフレーム中にフェイクを開いたままにしてください。 |
検証
- コードを書く前に、対象範囲と、観測可能なすべての状態(初回読み込み、再照合、更新中、エラー、再試行、空、見つからない、読み込みの重複、プロセス終了後の復元)を整理しました。
- 最も近い先例を最後まで読み、コンポーネント、フォーマッター、トークンを一覧にまとめました。
- すべての
*Contract.ktには、*UiState、*UiAction、*UiEffectがそれぞれ1つだけ含まれています(compose-architectureスキルのルール 4 を参照)。ファイルごとの宣言数を数えてください:
rg --files -g '*Contract.kt' <feature-root>
-
rg -n "TODO|FIXME|NotImplementedError" <changed-files>の結果は空です。すべてのテンプレートのSEAMは実装済み、または逸脱として記録済みです:
rg -n "TODO|FIXME|NotImplementedError" <changed-files>
- 完了前に
rg -n "SEAM" <module>の結果が空になっています。ハードコードされた UI 文字列はすべてリソースに切り出されています:
rg -n "SEAM" <module>
- 各ファイルのバージョンは1つだけです。「代替案」の草稿はありません。
- すべての
launchGuardedに明示的なonErrorが渡されています(compose-architectureスキルのルール 6 を参照)。try/catchの連鎖はなく、CancellationExceptionは再スローされています。 - すべての失敗経路で階層は1つだけ使われています(アーキテクチャルール 8)。すべての Retry でエラーが保持されています。
- 最初の
ON_STARTは初回読み込みで、後続のON_STARTはデータを保持したまま再照合します。すべてのLifecycleStartEffectはナビゲーションキーの ID をキーにしています。 - すべての読み込みで、実行中はスキップする、保存済みの
Jobを使って重複を防いでいます。 - 詳細画面の遷移先はキーから識別情報を取得してデータを読み込みます(
compose-architectureスキルのルール 10、15 を参照)。キャッシュが空の場合、レコードを再取得します。 - 下書きは
SavedStateHandleに保存され、UiStateはそこから導出されます(compose-architectureスキルのルール 9~10 を参照)。rememberSaveableによる複製はなく、同期するLaunchedEffectもありません。 - すべての
UiStateフィールドが UI で読み取られ、すべてのUiActionが UI からディスパッチされています。 - 名前付きのヘルパー、トークン、インポートはすべて、プロジェクトまたは現在のドキュメントにあることを確認済みです。新たに作り出したものはありません。
- 呼び出されるすべてのリポジトリメソッドが、そのインターフェースで宣言されています。
- 削除されたレコードは識別情報が使用不能でした。情報が欠落したフィールドは、行を残したまま null とし、デフォルト値を捏造していません。
- すべてのロケールフォルダーに文字列があり、キーは一致しています(
compose-uiスキルのルール 9 を参照)。 - ViewModel のテストでは、手書きのフェイクを使って状態マトリクスを網羅しています。決定論的に完了します(フェイクで使用できるアイドル時間の進行方法を使用)。
- 変更したモジュールは common メタデータと1つのプラットフォームでコンパイルでき、JVM テストにも合格します。
- インストール済みの場合、
scripts/composekit/run-checks.shは終了コード 0 で終了します。 - 差分には、タスクで指定されていないものを削除した変更はありません:はい/いいえ。
- 要求された機能は提供されています(または、ブロック要因が1つある場合は、解消に必要な最小の手順とともに明記されています):はい/いいえ。
- 逸脱は平易な言葉で報告されています:何が異なったか、再検討する条件。
参考資料の確認
このタスクで必要な参考資料のみを、1階層まで読み込んでください。
-
新しい遷移先を追加する場合、スキャフォールドテンプレートでカバーされていないときに限り、mvi-contract.md も読みます。
-
遷移先を接続する場合、スキャフォールドテンプレートでカバーされていないときに限り、navigation.md も読みます。
-
既存の状態を変更する場合、state-ownership.md も読みます。
-
失敗経路を変更する場合に限り、error-handling.md も読みます。
-
testing.md — ViewModel のテスト規約、フェイク、状態マトリクスの行。
-
ui-testing.md — Compose UI テストのルール:ファインダー、アサーション、同期、遅延リスト、復元、KMP ランナー。
-
review-mode.md — これらのゲートを使った、他の人による機能変更のレビュー。
-
examples.md — WRONG/RIGHT のペア12個。パターンが不明確な場合に限り読みます。
-
README.md — プレースホルダー、スキャフォールドコマンド、コンポジションルートのエントリ形式。