Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
今時のフルスタック主導の iOSアプリ開発
Search
nakajijapan
September 18, 2026
11
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
今時のフルスタック主導の iOSアプリ開発
extension DC 2026 Day1
nakajijapan
September 18, 2026
More Decks by nakajijapan
See All by nakajijapan
サービスにおけるDesign Systemの構築
nakajijapan
11
4.2k
Markdownをリアルタイムに解析する
nakajijapan
5
4.8k
Firebase Authorization
nakajijapan
0
350
Intoducing Izumo
nakajijapan
1
2.1k
Practical CloudKit
nakajijapan
1
1.9k
Introducing to Ajimi - プロダクトを味見していこう
nakajijapan
0
2.4k
Shari
nakajijapan
1
3.1k
Japan Apple Pay Development
nakajijapan
0
350
業務で絶対必要にならない技術
nakajijapan
0
910
Featured
See All Featured
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
740
Docker and Python
trallard
47
4.2k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.3k
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
460
Scaling GitHub
holman
464
140k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.3k
VelocityConf: Rendering Performance Case Studies
addyosmani
331
25k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.7k
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
320
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
280
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.4k
How to Talk to Developers About Accessibility
jct
2
550
Transcript
extension DC 2026 Day1 今時のフルスタック主導の iOSアプリ開発 AI に任せて、一人で回す。 2026 /
09 / 18 @nakajijapan © BaseMe Inc.
@nakajijapan Daichi Nakajima CTO / Software Engineer 🏢 Pepabo ->
Cookpad -> Campfire -> DeNA -> Startup企業s -> KNOWLEDGEWORK -> BaseMe Shari ★113 PhotoSlider ★248
None
None
None
今日の話の流れ 1.一人のエンジニアが見ている範囲 2.AIを仮想チームとして置く 3.現状やれていること 4.まだ課題に上がっていること 5.まとめ © BaseMe Inc. 6
一人のエンジニアが見ている範囲 © BaseMe Inc. 7
モバイルエンジニアを起点に見る範囲 プロダクト開発から技術基盤まで、担当を分けて待てない スタートアップ 少人数 久々の開発 © BaseMe Inc. 8
モバイルエンジニアを起点に見る範囲 プロダクト開発から技術基盤まで、担当を分けて待てない Front-End Design Server Side Security Infrastructure Mobile ©
BaseMe Inc. 9
モバイルエンジニアを起点に見る範囲 幅広く対応 Front-End Design Server Side Security PdM Infrastructure Mission
Mobile Web版をベースにして、iOSは 別軸でモバイルらしい体験を作る © BaseMe Inc. 10
プロダクトを支えるメンバー それぞれ軸を持ちつつも、職域を越境して開発 © BaseMe Inc. 11
1 つの機能が、全部の層をまたぐ 二段階認証。iOS・Web・サーバー・インフラを、一人で対応 1 4 iOS パスワードや Apple で アプリ
ログインする Web パスワードや Apple で ブラウザ ログインする 6 ログイン完了。 6 桁を入力する 信頼した端末は次回省略 ログイン完了。 6 桁を入力する 2 信頼した端末は次回省略 5 二段階が有効なら、 サーバー 確かめて、 本物の鍵は渡さず API 本物の鍵を渡す 短い合言葉だけ返す 3 インフラ SMS で 6 桁を送る SMS を送る土台と鍵の置き場 守りと計測 同じ機能の中で 入力と電話登録の 機能フラグで段階的に出す。 電話を失っても 有効にした数と失敗を 回数を絞る 古いアプリを締め出さない 控えの番号で戻れる 数える どの層が欠けても成り立たない機能は、全部の層を一人で触って通す。 © BaseMe Inc. 12
開発スケジュール 239 ios/ のコミット数 240 188 180 120 60 22
0 4月 5月 6月 足場を置いた月 8.5倍 App Store 設計に時間を消費し、開発を加速度的に上げていく © BaseMe Inc.
AIを、仮想チームとして置く © BaseMe Inc. 14
⚫︎ ⚫︎ ⚫︎ ⚫︎ ⚫︎ AIを、仮想チームとして置く 一人で全部を抱えず、AIに役割を持たせる。 ただし、AIを曖昧に「任せる」のではない。 各役割に次の4点を持たせる。 入力、完了条件、検証、引き継ぎ
仕様判断や体験の良し悪しは人が決める © BaseMe Inc. 15
役割ごとに、4 点を決める 曖昧に「任せる」のではなく、役ごとに決めておく 何を iOS の実装パイプラインでは 入力は何か planner には 1〜4
行の依頼。builder には仕様書と設計 何を出力させるか planner は仕様書と受け入れ基準。builder は実装と自己評価 何で正しさを確かめるか evaluator が、ビルド・テスト・シミュレータで受け入れ基準ごとに pass / fail どこで人に戻すか 同じスプリントで 3 回 fail したら、人に上げる この 4 点が決まったとき、AI は仮想チームとして機能する © BaseMe Inc. 16
AIに渡す仕事を、4層に分ける 4 つの層。上ほど毎回、下ほど動かして確かめる 毎回読む CLAUDE.md rules セッションのたびに 10 節 23
本 / 由来 17 必要なとき読む 自前スキル 借りたスキル 12 52 / ハッシュ固定 作業に合わせて 役割として動く orchestrator が回す 動かして確かめる シミュレータ・テスト planner architect builder evaluator fixer DebugHarness テスト E2E 21 ケース 2,266 本 夜間 ここまでは、たぶん皆さんもやっています。 © BaseMe Inc. 17
AIに渡す仕事を、4層に分ける 4 つの層。上ほど毎回、下ほど動かして確かめる 毎回読む CLAUDE.md rules セッションのたびに 10 節 23
本 / 由来 17 必要なとき読む 自前スキル 借りたスキル 12 52 / ハッシュ固定 作業に合わせて 役割として動く orchestrator が回す 動かして確かめる シミュレータ・テスト planner architect builder evaluator fixer DebugHarness テスト E2E 21 ケース 2,266 本 夜間 ここまでは、たぶん皆さんもやっています。 © BaseMe Inc. 18
自前スキル 12 本は、開発の流れに沿って置いてある どの段で、何を AI に読ませるか。借り物の 52 本は、この外側 作る ビルドする
動かして見る 遅い・固まる・落ちる PR を出す App Store へ generate-feature xcodebuild-baseme ios-simulator-skill swiftui-perf-investigate pr-create-draft appstore-release 画面を MVVM の型で一括生成 正しいビルドの打ち方。罠の対処つき シミュレータを触る・撮る・読む Instruments で追う手順 PR は必ず draft で。テンプレを埋める 提出から公開まで design-to-swiftui review-ios Figma やスクショから SwiftUI へ iOS の PR を見る観点 api-client pr-review-triage サーバー API の通信コード bot の指摘を鵜呑みにしない markdown-render-parity markdown の描画 3 経路を揃える web-parity-audit Web の機能を移すときの調査表 上の段が、開発の流れ。下が、その段で AI に読ませる自前のスキル。数は 12 本。 どれも、一度踏んだ手順を、次に AI が同じ手順で踏めるように書いたもの。 © BaseMe Inc. 19
誰が、いつ読むか 4 つの層。上ほど毎回、下ほど動かして確かめる 毎回読む CLAUDE.md rules セッションのたびに 10 節 23
本 / 由来 17 必要なとき読む 自前スキル 借りたスキル 12 52 / ハッシュ固定 作業に合わせて 役割として動く orchestrator が回す 動かして確かめる シミュレータ・テスト planner architect builder evaluator fixer DebugHarness テスト E2E 21 ケース 2,266 本 夜間 ここまでは、たぶん皆さんもやっています。 © BaseMe Inc. 20
iOS の実装は、役割を分けて回す © BaseMe Inc. 21
iOS の実装は、役割を分けて回す planner から fixer まで。渡すものと、fail のときに戻る場所を決めてある orchestrator(司令塔) 順番に回し、pass か
fail を見て次を決める スプリント。1 機能ずつ、この中を回る 自分 1〜4 行の依頼 planner architect 依頼を仕様書に広げる。 受け入れ基準まで書く 仕様書 builder 仕様書から設計。 iOS とサーバーの API。 コードは書かない evaluator 1 機能を実装。 シミュレータで動かして 自己評価を出す ビルドとテスト。 受け入れ基準ごとに pass か fail 次の機能へ pass 全部 pass したら PR。 merge するのは自分 設計書 fail fixer 3 回 fail 3回 evaluator に戻る 最小の変更で直して、 evaluator に戻す 役では直せない。 人間(自分)に戻す Claude Code のサブエージェント。ios/.claude/agents に置いてある。ここまでは役に任せられる。 © BaseMe Inc. 22
iOS Orchestrator © BaseMe Inc.
© BaseMe Inc. 仮想プロダクトチーム
事前に設計を作る © BaseMe Inc. 25
アーキテクチャ 5 つの層。数字は 現在の実数 MVVM View 画面。表示だけ Design System SwiftUI
の画面。状態も処理も持たない。 共通部品は右の Design System から取る ViewModel 状態と処理 Analytics ViewModel 48 本。状態は @Observable(49 ファイル)。 画面が何を出すかは、ここで決まる 通信 サーバーとのやりとり Test 確かめる側 BM* の共通部品 15 種。 色・余白・字はトークンから。画面をまたいで揃える PostHog にイベント(定義 34 種)とセッション録画。 Crashlytics に落ちた記録。dSYM は CI から Realtime API の型は swagger から自動生成。手で書かない。 チャットの本文は SSE、カードの進捗は ActionCable(右) SSE でチャットの本文を流す。 WebSocket でカードの進捗を押す Unit と UI で 282 ファイル・2,266 本。#Preview 334 のうち共通部品はスナップショットへ。 VRT は S3 に基準画像、E2E は夜間。AI が書いた差分は、ここを通って初めて信じる © BaseMe Inc. 26
モバイル側(iOS) ここは自分で設計しました。既製のライブラリは入れていません。 受け口 URLSessionDataDelegate .lines は使わない チャンクをそのまま受ける 行ごとに溜まると流れて見えない SSEParser テストできる形にする
仕様どおりに組む protocol で切り出す テスト 10 ファイル・1,447 行 つなぎっぱなし ActionCableClient WebSocketを閉じ込める 状態を1列に並べる unchecked Sendable なし 生のバイトで受ける 解析 actor 1本 切れたとき 自動で戻す 指数バックオフ ping を見張る 購読の一覧は捨てない 最大 30 秒 6秒来なかったら切れたとみなす 戻ってきたらつなぎ直す © BaseMe Inc. 27
登録した当日の体験を直した、1 か月 登録した当日に、どこまで使ってもらえるか。赤い帯は、つまずいたところ 8月上旬 分析 登録した日に何をした人が、7 日後にまた開いているかを調べた 8月上旬 疑う役が差し戻し 直すべき点を
7 つ挙げて、分析を突き返した 8月上旬 判断 条件つきで採用。登録より先に、Ken と話してもらう案 8月中旬 実装 入力なしで始まる新しい入口を作った。68 コミット 8月末 実験に移す A/B の振り分けが、アプリの画面に届いていなかった。直した 8月末 指標を入れる 効果を測る指標が 1 つも無かった。3 つ足した 9月頭 読み直し 指摘どおりに集計し直しても、差は残った 分析から指標まで、こういうのも自分でやっています。間違えても、ここまでは回ります。 © BaseMe Inc. 28
ミスを0にするのではなく、直すまでの俊敏さ 設計を先に行っても、ビルドもテストも通る場所でミスは残る。狙うのはゼロではなく、一人で見つけて直せる俊敏さ 1. 振り分けが、画面に届いていなかった 前 サーバー A / B を決める
× 2. 効果を測る指標が、1 つも無かった アプリの画面 結果を見ていない 前 だから、A と B の出し分けが起きない 後 実験 2 指標: 0 個 動かしても、効いたかどうかが読めない PostHog の実験 アプリの画面 振り分けを決める A と B を出し分け 振り分けを PostHog の実験に載せ替えた 実験 1 後 イベントを 指標を組む 3 つ足す 効果が読める 測るためのイベントを 3 つ足して、指標を組んだ 見つけて直すところまで一人で回る。 © BaseMe Inc. 29
現状やれていること AIがやりそうなことに遭遇し対策する © BaseMe Inc. 30
現状やれていること、4 本 この章が発表の中心 何を 一言で 4-1 体験をつくる 動かして、計測して、初めて分かる 4-2 正しく確かめる
古いアプリを見ない。推測で直す前に測る。どちらも失敗から rule にした 4-3 境界をつなぐ API の型は生成する。約束がなければ、AI の型でも壊れる 4-4 経験を次の AI 入力へ戻す 失敗を rule・skill・CI の関門に戻す AI が速く書くほど、確認・約束・学習の仕組みが重要になる © BaseMe Inc. 31
4-1 体験をつくる 何を 一言で 4-1 体験をつくる 動かして、計測して、初めて分かる 4-2 正しく確かめる 古いアプリを見ない。推測で直す前に測る。どちらも失敗から
rule にした 4-3 境界をつなぐ API の型は生成する。約束がなければ、AI の型でも壊れる 4-4 経験を次の AI 入力へ戻す 失敗を rule・skill・CI の関門に戻す AI が速く書くほど、確認・約束・学習の仕組みが重要になる © BaseMe Inc. 32
AI チャットが、16 秒固まった ユーザーがやったことと、起きたこと 1 2 3 4 Ken と、長くやりとりする
答えの最後に、選択肢のチップが 出る 画面が止まる。16.23 秒 もう 1 往復すると 答えは文字が流れて届く。 1 文字ずつ画面が更新される どれかをタップする 何も押せない。 Instruments では Severe Hang CPU が 100% に張り付く。 そのまま落ちることもある 止まっていた時間 0秒 16.23 秒 この間、指が効かない 起きた構成 SwiftUI AI と一緒に作った画面。 コードを読んでも分からない。動かして、初めて分かった。 @Observable SSE ストリーミング どれも普通。特別なことはしていない コードを読んでも分からなかった。動かして、初めて分かった。 © BaseMe Inc. 33
Time Profiler の答え。自分のコードは 0.5% Time Profiler は、時間を細かく刻んで「そのとき動いていた関数」を数える道具。誰が呼んだかは数えない 固まっていた 16 秒の間、メインスレッドは誰の関数を動かしていたか
0.5% 自分が書いた関数 99.5% 自分の関数が直接使った時間の合計。どれも軽い SwiftUI の中の関数 レイアウトの計算に、ほとんどの時間が消えている Time Profiler で分かること Time Profiler で分からないこと 誰が時間を使ったか。 答えは「自分の関数ではなく、SwiftUI のレイアウト計算」。 誰がそれを何度も呼んだか。 自分のどの書き方が引き金なのかは、ここからは読めない。 行き止まり 次の道具 自分のコードを削っても直らない。削る場所が無い 「誰が呼んだか」の積み重ねが見える Hangs へ。次のスライド 自分のコードを削っても、直らない。ここで一度、行き止まりになった。 © BaseMe Inc. 34
出てきた名前は、誰の処理か Hangs が出した呼び出しの積み重ね。上が画面を出す土台、下へ行くほど自分の選んだ部品に近づく 呼ばれた順 画面を出す土台 1 回ぶんの画面の変更を、まとめて確定させる CA::Transaction::commit UIKit と
SwiftUI の橋 UIHostingView.layoutSubviews SwiftUI の中心 AG::Graph::UpdateStack::update LazyVStack の位置計算 LazySubviewPlacements.placeSubviews 高さのキャッシュを捨てる LazyLayoutViewCache.invalidateSize Apple の中。 自分では触れない 並べ直しの指示が来るたび、SwiftUI 全体のレイアウトが走 る View・状態・レイアウトの依存の網。1 つ変わると、つなが る節点を全部更新 子の位置と高さを決める。Lazy でも、位置は全部の子で計算 する 1 つ変わると、全部捨てる。これが何度も呼ばれていた 自分が選んだ入れ物。 LazyVStack の中 犯人 犯人は自分の関数ではなく、自分が選んだ入れ物だった。 © BaseMe Inc. 35
1 文字届くたびに、全部測り直していた 「1 つ変わる」とは、最後の吹き出しが 1 文字ぶん伸びること。入れ物によって、そのあとの反応が違う LazyVStack(前) 起きること(どちらも同じ) チャットの画面。答えは 1
文字ずつ届く 測り直し 1 つ変わると 測り直し 測り直し 測り直し 高さのメモを全部捨てて、 全部測り直す 16 秒 止まる 測り直し 測り直し +1 測り直し 答えの途中の吹き出し… 1 文字ごとに、全部。 長い答えほど回数が増えて、止まる 測り直し ↑ 1 文字ぶん、高さが伸びる VStack(後) これが「1 つ変わる」。 1 つ変わると 最後の吹き出しの高さが、 変わった 1 つだけ測り直す。 ほかはそのまま 1 文字届くたびに変わる。 長い答えなら、何百回も起きる 止まらない 1 文字ごとに、1 個ぶん。 回数が増えても軽い 測り直し 16 秒を消したのは、入れ物を変えた 1 語。 LazyVStack { VStack { Lazy の利点は「見える分だけ作る」こと。数十件のチャットでは効かない。数百を超えるなら List を使う 大量で固定のViewを扱うならLazyVStack 可変高Markdownが更新されるため、実測では VStack の方が滑らか © BaseMe Inc. これが宗派y区数千になってくるとまた別問題 36
体験品質の確認方法 UI とアニメーションで、決めていること 3 つ 01 02 03 静止画で判定しない Profiler
を取る 計測の道具を疑う 固まった 16 秒、メインスレッドは誰の関数を動かしていたか 指のスワイプ(0.4 秒) × アプリの録画 idb の合成スワイプ 正解(デザイナーの動画) 0.5% 自分の関数 99.5% SwiftUI の中 6ms に固まって届く 止まった後の 1枚 コマごとに要素の位置を追い、2 本を並べる Time Profiler Hangs 誰が時間を使ったか 誰が何度も呼んだか 画面: ほぼ動かない メインスレッド: 暇 6.8 秒で 3 コマ ほぼ待ち状態 矛盾。凍ったのはアプリではなく、道具の嘘 止まった後の 1 枚は、何も証明しない。 録画をコマに分解して、要素の位置を毎コマ追う。 正解の動画も同じ方法で測る。仕様の数字はそこから出る simctl recordVideo → ffmpeg / ffprobe でコマに分解 読んでも分からなかった。疑う前に、測る。 時間の 99.5% は、自分の関数の外だった。 道具を 2 つ重ねて、初めて犯人に届いた Instruments: Time Profiler → Hangs 計測が矛盾したら、まず道具を疑う。 合成スワイプはタッチを 6ms に固めて届ける。 実時間で動くドラッグに替えて、測り直した idb → ホストから実時間のドラッグ / 実機で触る ここは今も、自分で確かめています。 © BaseMe Inc. 37
4-2 正しく確かめる 2 本目。例は 2 つ。見ていたアプリが古かった話と、見ていた値が古かった話 何を 一言で 4-1 体験をつくる
動かして、計測して、初めて分かる 4-2 正しく確かめる 古いアプリを見ない。推測で直す前に測る。どちらも失敗から rule にした 4-3 境界をつなぐ API の型は生成する。約束がなければ、AI の型でも壊れる 4-4 経験を次の AI 入力へ戻す 失敗を rule・skill・CI の関門に戻す AI が速く書くほど、確認・約束・学習の仕組みが重要になる © BaseMe Inc. 38
古いアプリを見て、実在しない不具合を追った ノートの背景色を直したのに、「まだ白い」と言われ続けた コード 新 シミュレータ ビルド #F9F9FC ✓ 新しい色を書いた BUILD
SUCCEEDED × エラーは出ない 旧 #FAFAFA 古い app のまま 入れ直していない 「直した」 「直っていない」 見ていたのは、コードとビルド 見ていたのは、シミュレータの画面 AI 確かめる側 AI は「直した」と言い、確かめる側は「直っていない」と言う。どちらも嘘はついていない。 見ていたものが違った! © BaseMe Inc. 39
直したのは、アプリではなく AI が読む手順 アプリのコードは 1 行も変えていない。変えたのは、AI が読む 4 ファイル AI
が読む手順 アプリのコード + 消す 変えた のは 0行 変えていない ビルド 入れ直す 測る ここが抜けていた 目ではなくピクセルで + rule + skill 消して、ビルドして、入れ直してから測る。鮮度は 1 点で確か める 色は目で見ない。ピクセルで測る + evaluator + fixer 検証の前に、必ず鮮度の関門を通す 直した後の再検証も、同じ関門を通す 検証 BUILD SUCCEEDED でも、1 ファイルもコンパイルしていないことがある。それも rule に書いた。 © BaseMe Inc. 40
もう 1 つ。アイコンを変えたのに、drawer だけ古い 設定でアイコンを変えると、横から出るメニュー(drawer)にも同じアイコンが出る。6 月、「登録できない」と報告が来た 1 設定でアイコンを変える 新 保存
✓ 2 設定画面は、新しいアイコンに なる 状態更新 ? drawer を開く 旧 表示 × 3 古いアイコンのまま 閉じて、もう一度開く 新 その時だけ、新しいアイコンに なる この時点の仮説 保存ではなく、状態更新から表示までのどこかで止まっている 止まっているのは、この間のどこか 見えていたのは「保存失敗」ではなく、「保存後に表示だけが追いつかない」だった。 © BaseMe Inc. 41
3 回推測で外して、1 回の計測で当てた 推測を試すたびに、実機の確認で 6〜22 分。だから、ログを 3 か所に置いて 1 回で測った
推測で直す 1 閉じる処理を消してみた 測ってから直す × 外れ 1 実機で確かめるのに 6〜22 分 2 状態を直接読んでみた 画面の一番上で読んでみた 届いた ログを 1 行入れて、1 回動かす × 外れ 2 実機で確かめるのに 6〜22 分 3 更新は届いているか 再描画は走っているか 走っていない ログを 1 行入れて、1 回動かす × 外れ 実機で確かめるのに 6〜22 分 3 なぜ走らないか 「変化なし」と判定 ログを 1 行入れて、1 回動かす 3 回やって、何も分からなかった 1 回で、原因に届いた 推測 1 回ごとに、実機の確認で時間だけが減っていく id が同じで URL だけ違うと、「変化なし」と判定されていた 推測で直す前に、1 回測る。これがそのまま rule になった。 © BaseMe Inc. 42
直したのは、比べ方 同じ人なら変化なし、ではなく、同じ中身なら変化なし、にした 前 id だけ比べる 後 いま表示している 保存された 全部を比べる いま表示している
保存された id 42 id 42 id 42 id 42 name Nakajima name Nakajima name Nakajima name Nakajima url /old.png url /new.png url /old.png url /new.png id だけ見る 42 = 42 → 変化なし id・name・url を全部見る url が違う → 変化あり URL の違いは見ていない id が同じでも、中身が違えば描き直す → drawer は描き直さない → drawer が新しくなる 直したのは 1 行。見つけるのに 3 回外して、測ったら 1 回だった。 © BaseMe Inc. 43
4-3 境界をつなぐ 何を 一言で 4-1 体験をつくる 動かして、計測して、初めて分かる 4-2 正しく確かめる 古いアプリを見ない。推測で直す前に測る。どちらも失敗から
rule にした 4-3 境界をつなぐ API の型は生成する。約束がなければ、AI の型でも壊れる 4-4 経験を次の AI 入力へ戻す 失敗を rule・skill・CI の関門に戻す AI が速く書くほど、確認・約束・学習の仕組みが重要になる © BaseMe Inc. 44
実装のずれは、2 通りで起きた どちらも、手元ではビルドもテストも通る。見た目では分からない ケース 1 サーバーだけが進む サーバー側 iOS の生成物 size
を 数字 に直した size は 文字列 のまま 前は文字列だった。仕様を正した ケース 2 生成し直していない。古い 本番に出ていたら ビルド ✓ テスト ✓ 数字を文字列に 入れられず、落ちる AI が、生成したファイルに手で足す 生成したファイル(手で編集しない、と書いてある) 次に生成し直した瞬間 struct Suggestion: Codable + Equatable + var title + = nil 動く 見た目は何も問題ない AI が「便利だから」と足した 手で足した分が消える。 消えたところを使っていると壊れる どちらも、型としては正しい Swift。 コンパイラは文句を言わない。 テストも通る。 だから、人は気づかない。 人が動かした差分も、AI が足した差分も、コンパイラは文句を言わない。 © BaseMe Inc. 45
手で書ける場所を、無くした 型の正はサーバーに 1 か所。iOS 側は生成するだけ。手で触ったら CI が止める 型の流れ サーバーのテスト swagger.yaml
生成スクリプト Generated/*.swift 型の正はここ。 レスポンスの形を書く テストから生成。 手で編集しない swagger を読んで Swift を書き出す 先頭に 「手で編集しない」 止める場所 CI(iOS に変更があるたびに走る) 差分なし → 通る もう一度、生成する 手元の生成物とは無関係に、 CI が自分で作り直す 手元の生成物と比べる git diff を取るだけ 人が手で直した 1 文字も、 AI が足した 1 行も、 生成し忘れた 1 ファイルも、 ここで赤になる。 差分あり → 赤にする 人も AI も、生成物を直接編集しない。編集しても CI で赤になる。 © BaseMe Inc. 46
4-4 経験を次の AI 入力へ戻す 何を 一言で 4-1 体験をつくる 動かして、計測して、初めて分かる 4-2
正しく確かめる 古いアプリを見ない。推測で直す前に測る。どちらも失敗から rule にした 4-3 境界をつなぐ API の型は生成する。約束がなければ、AI の型でも壊れる 4-4 経験を次の AI 入力へ戻す 失敗を rule・skill・CI の関門に戻す AI が速く書くほど、確認・約束・学習の仕組みが重要になる © BaseMe Inc. 47
失敗を直して終わると、次のAIも同じ誤った道を踏む 足場は先に組めない。転んだ場所にしか置けない。そして置いた rule にも穴があった 戻す係がいなかった rule を書いても、3 つの穴があった AI が書く
1 失敗する 先に書けない 4 月に想像で書いた 3 本は、6 月の失敗を 1 つも止めなかった。 足場は、転んだ場所にしか置けない 同じ穴を踏む 2 次のセッションの AI 4〜5 月の 5 本には由来が無い。AI が似た状況で応用できず、 人もあとで消していいか判断できない 人が直す 直して終わり × 3 rule に戻す 「なぜ」が無い 全部読ませると、読まれない CLAUDE.md に書いていた頃、長くなると人間が更新しなくなった。 更新されない記憶は、無いより悪い 戻す係がいない 失敗は直る。でも rule には戻らない。だから次のセッションの AI が、同じ失敗を繰り返す だから決めた 戻す係 書き方 戻す先 ふりかえりの役。提案だけ出し、入れるのは人 由来を書く。触るときだけ読ませる rule・skill・agent・DebugHarness を分ける © BaseMe Inc. 48
ruleは、失敗から育てる ふりかえりの役を置いた 6 月から、rule に由来が付くようになった。月ごとの本数 追加された rule の本数 由来なし 6月
失敗の由来つき ふりかえりの役を置いた 16 本 3本 4月 2本 5月 6月 1本 1本 0本 7月 8月 9月 4〜5 月の 5 本は由来なし。想像で書いた 最初の由来つき rule は、古いアプリを見ていた失敗から生まれた 7 月以降は 2 本だけ。録画に入力欄を残さない/段を進める演出の時間を上書きしない © BaseMe Inc. 49
ローカルとCIの判定を揃える 戻す先は rule だけではない。CI でしか見つからなかった違反を、ローカルの手順に戻した例 前 ローカル 戻した先。rule ではなく、手順に戻した CI
push lint はゆるい設定。 違反があっても通る swiftlint --strict。 ここで初めて落ちる ios/Makefile +5 行 lint-strict のターゲットを新設。既存の lint はそのまま ios/.claude/skills/review-ios/SKILL.md 直して、また push。往復が増える +20 行 build gate の隣に Lint gate。make lint-strict を回し、違反があれば GATE: FAIL 後 ローカル CI push make lint-strict。 CI と同じ判定を手元で。 ここで落ちて、ここで直す 変更なし。 同じ判定なので、通る .github/workflows/ci-ios.yml 変更なし 元から swiftlint lint --strict。SwiftLint 0.57.0 にピン留め 副産物: HomeSpeechBubble.swift が 514 行 → 229 行。HomeBubbleShape と HomeGreetingContent に分割 CI を変えたのではない。ローカルの手順に、CI と同じ 1 行を足した。経験を戻す先は、rule だけではない。 そもそもちゃんとしろ案件 © BaseMe Inc. 50
4 本に共通すること 4 本とも、AI が速く書いたものを、あとから何で止めたか AI が 実装 確認 約束
動かして測ってから、信じる サーバーと iOS の約束。型は生成して、手で は書かない 1 体験をつくる 3 境界をつなぐ 動かして計測する。 静止画で判定しない 型は生成する。 手で書ける場所を無くして、 CI で止める 学習 次の AI に、由来ごと渡す 4 経験を次の AI に戻す 失敗の由来を rule に書いて、 次の AI に読ませる 2 正しく確かめる 直す前に測る。 古いアプリを見ない 速く書けるほど、速く壊せる。だから、確認・約束・学習を仕組みにしておく。 © BaseMe Inc. 51
まだ、課題に上がっていること ここで初めて、人が持つ課題を置く © BaseMe Inc. 52
まだ、課題に上がっていること 4 つ。どれも、AI が回す流れの中で、人が抜けられない場所 01 02 仕様に書いた 0.8 秒 実際に動いた
0.2 秒 動きの仕様を、どこまで言葉にでき るか 体験の良し悪しを、どう測れる形に するか 書いた数字が、そのまま動くとは限らない。 録画で測るまで分からない 静止画は CI が比べる。動きは、まだ人が録 画を見て決めている ✓ 静止画 CI が比べる 人が見る 全体の設定に上書きされた 03 AI 人 動き 04 合否 差し戻し rule を入れる merge AI に渡す判断と、人が持つ判断 を、どう分けるか 合否と差し戻しは AI。rule を入れる、 merge する、は人。全体の決まりは、まだ無 い 仮想チームの成果を、誰が引き受け るか planner architect builder evaluator fixer merge 最後に merge するのは自分。一人だから成 り立っている 自分ひとり 線は、場所ごとに引いている 一度解決して終わりにせず、観測できるようにして、次の判断を少し速くする。ここまでしかできていない。 © BaseMe Inc. 53
まだ、課題に上がっていること 4 つ。どれも、AI が回す流れの中で、人が抜けられない場所 01 02 仕様に書いた 0.8 秒 実際に動いた
0.2 秒 動きの仕様を、どこまで言葉にでき るか 体験の良し悪しを、どう測れる形に するか 書いた数字が、そのまま動くとは限らない。 録画で測るまで分からない 静止画は CI が比べる。動きは、まだ人が録 画を見て決めている ✓ 静止画 CI が比べる 人が見る 全体の設定に上書きされた 03 AI 人 動き 04 合否 差し戻し rule を入れる merge AI に渡す判断と、人が持つ判断 を、どう分けるか 合否と差し戻しは AI。rule を入れる、 merge する、は人。全体の決まりは、まだ無 い 仮想チームの成果を、誰が引き受け るか planner architect builder evaluator fixer merge 最後に merge するのは自分。一人だから成 り立っている 自分ひとり 線は、場所ごとに引いている 一度解決して終わりにせず、観測できるようにして、次の判断を少し速くする。ここまでしかできていない。 © BaseMe Inc. 54
⚫︎ ⚫︎ ⚫︎ ⚫︎ ⚫︎ ⚫︎ アニメーション: 動きは、仕様を細かく決める必要がある アイテムのアニメーション Lottie
Kenのアニメーション モバイル用に最適化した動画を生成 複雑なアニメーション、インタラクション SwiftUI (keyframe / transition) 人間との同時並行が必要 © BaseMe Inc.
None
None
まとめ © BaseMe Inc. 58
⚫︎ ⚫︎ ⚫︎ ⚫︎ まとめ iOS エンジニアの守備範囲は、事業側まで広がる AI は補完ではなく、役割と検証条件を持つ仮想チームとして育てる 最近はAIのマネージメント方が比重が高い
人は、体験の意図、品質基準、最終判断へ AIを仮想チームとして育て、人は体験と判断に集中 © BaseMe Inc.
Thanks アニメーションの制御 @nakajijapan © BaseMe Inc.