シフト希望をLINEとエクセルで集めるのは、どこで限界が来るか ── 集め方を見直した話
シフト希望をLINEで集めてエクセルに転記する運用は、何人までなら回るのか。転記ミス・出し忘れの催促・変更の反映という3つの手間がどこで効いてくるかを整理して、集め方の見直し方をまとめました。
続きを読む →
日程調整アプリ soroe(iOS / Android / Web の Flutter アプリ)は、真っ白な状態から設計したわけではない。既存の SwiftUI アプリ wari-ios(SwiftUI / MVVM)を**「設計図」として渡し、Claude で Flutter / Riverpod へ移植**して作った。
このシリーズでは、Claude Code と個人開発する仕組みを書いてきた。第1回はドキュメント(spec と ADR)、第2回は CLAUDE.md。今回はその上で、すでにある完成品を下敷きに、AIで別スタックへ作り直すという進め方を紹介する。
言語もフレームワークも違う(Swift → Dart、SwiftUI/MVVM → Flutter/Riverpod)。それでも移植がうまくいったのは、コードを1行ずつ翻訳させたからではなく、レイヤーの構造対応表を先に用意したからだった。
wari-ios には、すでに動いている資産がある。
ynetlabo-api を叩く一連の流れこれを新アプリのためにゼロから設計し直すのは、車輪の再発明だ。しかも soroe は同じバックエンドを使う。だったら、やるべきは「新規設計」ではなく「翻訳」になる。
AIはこの「翻訳」が得意だ。ボイラープレートを一から考えさせると迷いや揺れが出るが、手本があれば、それを別の言語・フレームワークの語彙に置き換えるのは精度が高い。移植は、AI支援開発と特に相性がいい。
言語が違っても、アプリのレイヤーが担う役割は対応づく。SwiftUIのViewModelに相当するものは、Flutterでは何か。Codableに相当するものは何か。これを毎回Claudeに推測させると、同じ役割のコードが画面ごとに微妙に違う書き方になってしまう。
そこで、移植を始める前に CLAUDE.md へ構造対応表を書いた。soroeの場合はこうだ。
| wari-ios(SwiftUI / MVVM) | soroe(Flutter / Riverpod) |
|---|---|
Services/APIClient | lib/core/network/dio_client.dart |
ViewModels/*ViewModel(ObservableObject) | Riverpod の Notifier(*controller.dart) |
Models/*(Codable) | 手書きモデル(fromJson / toJson) |
Views/pages・Views/components | presentation/ と core/widgets/ |
UserDefaults の authToken | flutter_secure_storage(TokenStorage) |
この表があると、Claudeは「このSwiftのViewModelはFlutterで何になるか」を毎回考えない。決まった対応で機械的に置けるので、判断のブレが消え、アプリ全体の書き方が揃う。
対応表は、AIに渡す翻訳辞書だと考えると分かりやすい。辞書を最初に固めておくほど、以降の翻訳が安定する。
移植はファイル単位ではなく、機能単位で縦に進めた。soroeなら auth(認証)→ room(グループ)→ shift(シフト)という順で、1機能ずつ移していく。
各機能でやることは同じだ。
data / domain / presentation の縦割り)flutter analyze と flutter test を通す第1回で書いた spec-driven とも噛み合う。移植先の「今の仕様」は docs/specs/ に書き、対応表で「どう置き換えるか」を固定する。元コードは設計図、specは現在地、対応表は翻訳辞書 ── 3つが揃うと、Claudeは迷いなく1機能を書き切れる。
横方向(全画面のAPIクライアントだけ先に、次に全画面のモデルだけ…)ではなく縦方向にしたのは、1機能ずつ動く状態で積み上げたいからだ。認証が通ってから次に進めば、途中で全体が壊れることがない。
とはいえ、全部を機械的に写経したわけではない。そのまま移植してはいけない部分がある。ここはAIに丸投げせず、こちらで設計を判断した。
wari-ios は iOS 専用だが、soroe は Web でも動く。LINEログインは、モバイルはネイティブSDK、Webは LIFF(LINEミニアプリ)と経路が分かれる。ここは「Swiftのコードを翻訳」では出てこない。条件付き import でプラットフォームごとに実装を隔離する、という移植先固有の設計が要る(→ ADR 0002)。
SwiftUIのObservableObjectとRiverpodのNotifierは「役割」は対応するが、破棄のタイミングが違う。RiverpodのautoDisposeやkeep-aliveは、SwiftUIにはない概念だ。画面から戻ったときにデータを取り直す挙動なども、Flutter側の事情に合わせて設計し直す必要があった(→ ADR 0003)。
対応表は9割の「翻訳」を自動化してくれる。だが残り1割の、移植先のフレームワークでしか発生しない判断は人間が握る。そしてその判断は、第1回で書いたとおり ADR に残す。ここの切り分けが、移植を「劣化コピー」にしないコツだ。
すでに動いているアプリが手元にあるなら、別スタックへの展開は「新規開発」より「移植」として捉えたほうが、AIの力を引き出せる。要点は3つ。
CLAUDE.md に固定し、AIに毎回推測させない。移植の9割は退屈な置き換えだ。そここそAIに任せ、人間は残り1割の判断に集中する。この分担が、既存資産を持っている個人開発者にとっていちばん効く。
soroe は、wari-ios という「動く設計図」があったからこそ、短期間で iOS / Android / Web に載せられた。ゼロから設計する迷いがなく、バックエンドはそのまま流用でき、挙動の互換性も保ちやすい。
その移植を支えたのは、派手な仕組みではなく、CLAUDE.md に書いた一枚の構造対応表だった。AIに「翻訳」させるなら、まず辞書を渡す。既存資産を別スタックへ広げたい人に、参考になれば。
このシリーズ:第1回 spec と ADR/第2回 CLAUDE.md の書き方/第3回(本記事)
シフト希望をLINEで集めてエクセルに転記する運用は、何人までなら回るのか。転記ミス・出し忘れの催促・変更の反映という3つの手間がどこで効いてくるかを整理して、集め方の見直し方をまとめました。
続きを読む →アプリ開発と旅行計画で毎回同じことを Claude に説明していたので、Agent Skills として切り出して GitHub に公開した。何をスキルにして何をしなかったか、SKILL.md を書くときに効いた3つのルール、そして description が一番重要だという話。
続きを読む →Y.NetLabo の使い方ガイドに載っている画面図は、すべて Claude にコードを読ませて描かせたラフ画です。実際にサイトで公開している図をそのまま並べて、何ができて何ができないか、なぜスクリーンショットをやめたのかを書きました。
続きを読む →