Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AI時代における_iOS設計の守り方と人間の役割

Avatar for TVer Inc. TVer Inc. PRO
September 17, 2026

 AI時代における_iOS設計の守り方と人間の役割

Avatar for TVer Inc.

TVer Inc. PRO

September 17, 2026

More Decks by TVer Inc.

Other Decks in Programming

Transcript

  1. About TVer TVerとは ⺠放テレビ局がひとつになった テレビの新しい プラットフォーム ⾒放題 0 ¥ ドラマ

    バラエティ アニメ/ヒーロー 報道/ ドキュメンタリー スポーツ その他 © 2025 TVer Inc. | Recruiting Deck 5
  2. Data サービス規模 現在、常時約800番組をすべて無料で パソコン‧スマートフォン‧タブレット‧テレビに配信 アプリダウンロード数 MUB (TVer単体‧訪問ベース) 9,000 万 4,460

    万 ※MUB=⽉間ユニークブラウザ数 © 2025 TVer Inc. | Recruiting Deck (2025年11⽉時点) (2025年12月時点) 再⽣数 (TVer単体) 認知率 (15〜69歳/男⼥) 6.5 億回 73.3 % (2025年12⽉時点∕TVer DATA MARKETING調べ) (2024年11⽉時点∕株式会社マクロミル調べ) 6
  3. 去年までのおさらい ⼈が増えAI導⼊が始まり AIに渡す前提を、順番に作ってきた AI関与するコミットPR iOSエンジニア2⼈⼊社 2023/09 が⽉の半分に 2025/07 2025/01 初めてのiOSエンジニア

    ⼊社 2025/12 Claude Code 導⼊ ここから2年かけて⼈を増やし 初のAIコミットが 7/02。 た この⽉はまだ6本 © 2026 TVer INC. 2026/03 4⼈⽬の iOSエンジニア⼊社
  4. AI導⼊から約1年 AIに渡す内容を作ってきました 2025-07 初めてAIが関わったコミット。CLAUDE.md を置く 2025-12 レビュー⽤などサブエージェントの構築 2026-03 rules/ を作る。AIが⾃分でブランチを切ってPRを出し始める

    2026-04 AI⾃⾝に振り返らせて、ルールを改善させるループを⼊れる 2026-05 アーキテクチャガイドを書く 2026-06 仕様を機械可読な契約に落とす。依存⽅向 lint を導⼊ 2026-08 CI上でAIがバグを修正してDraft PRまで作るようになる © 2026 TVer INC. 12
  5. AI導⼊から約1年 AIが関わったコミットの割合 0% → 73% TVer iOSリポジトリ / 2025-06 →

    2026-08 の実測 claude/ ブランチからのPRは累計516本、多い⽇は1⽇25本マージ © 2026 TVer INC.
  6. AI導⼊から約1年 リリースの回数と内容が増加 この1年で 43本リリースした。⽉あたり 3.6本。 リリース回数(⽉あたり) 2.6本 → 3.6本 約1.5倍

    1リリースに⼊るPR 66本 → 126本 約2倍 1リリースに⼊るコミット 249 → 475 約2倍 1回のリリースで動くコードの量が、2倍近くになった。 © 2026 TVer INC.
  7. AI導⼊から約1年 アーキテクチャガイドラインの設定 • 迷わない ◦ • 持続可能 ◦ • 品質を継続的に担保できる構造

    安全に変更できる ◦ © 2026 TVer INC. 負債がたまらない。10年後も健全であり続ける テスタブル ◦ • 誰でも、AI でも統⼀した実装ができる 意図しない副作⽤が⽣まれにくい。テストされている
  8. AI導⼊から約1年 22 → 204 約1年間でモジュール数は約10倍 TVerApp / App TVerLibrary LegacyAppFeature

    109 94 1 Domain ∕ 画⾯Feature 共有インフラ 114,234⾏の 単⼀ターゲット 境界をはっきりさせて、ビルド時にアーキテクチャの違反を静的に検出できる © 2026 TVer INC.
  9. AI導⼊から約1年 Packageの切り⽅と、依存の向き AppFeature 画⾯Feature 画⾯Feature 画⾯Feature Domain DesignSystem 共通UI Client

    - / ClientLive それぞれの画⾯ごとにUIとDomainのパッケージを分ける デザインは共通化されたものを利⽤する © 2026 TVer INC.
  10. AI導⼊から約1年 Packageの切り⽅と、依存の向き AppFeature 画⾯Feature 逆流 禁⽌ × 画⾯Feature 画⾯Feature ×

    Domain DesignSystem Client / ClientLive 依存の⽅向性をlintで制限し、CIで確認する © 2026 TVer INC. × 共通UI
  11. AIは速い。でも、任せきれない AIは全体像ではなく、近くのコードを手本にする /// メニュー「シェア」で共有する URL。 /// /// 同じ組み立てが `EnderListPage` と

    `HomePage.shareURL(for:contentID:)` にもある。 /// 暫定なので、BE 供給が入ったら各所をまとめて応答の値へ差し替える。 func shareURL(contentID: String) -> URL? { ... } 13 モジュール・ 15 箇所に散っていた組み立てを集約した。各画面の実装は互いにコピーで、 同じ FIXME コメントも 15 箇所に重複 していた。空 contentID のガードは従来 3 画面にしか 無かった 。 © 2026 TVer INC.
  12. AIは速い。でも、任せきれない 嘘が、仕様になってしまう // 上限エラーを返すのも series(70003)のみ // (`FavoriteCategory.init(contentType:)` の doc 参照)。

    事実は対象エラーコードは対象種別によらず 4008。70003 は legacy API 由来で、この説明は最初から誤り。 ad863ac684 LiveDetailPage に混入 Claude Fable 5 f0083452e2 SpecialDetailPage へコピー — 参照先を FavoriteLimitModal に差し替えて Claude Sonnet 5 36ec01ec80 RealtimeLivePage へコピー、テストのコメントにも波及 Claude Opus 5 106a4a711f 17 日後、8 ファイルを一括修正 FavoriteLimitModal と FavoriteRepositoryLive が互いを出典として参照し合う循環をやめる。 →本番にリリースする前に気づくことはできた © 2026 TVer INC.
  13. AIは速い。でも、任せきれない UIKit は 34 箇所。それぞれ理由がある SDK‧OS標準がUIKitでしか来ない。選べない 13箇所 SwiftUI にその機能が存在しない 9箇所

    特定のOSバージョンでSwiftUIが動かない 3箇所 ⾒た⽬はSwiftUI、挙動だけUIKitで直す 5箇所 UIの都合ではない 4箇所 © 2026 TVer INC.
  14. AIは速い。でも、任せきれない SDK‧OS標準がUIKitしかない。選べない SDK が UIKit の部品として配っている。包む以外にやることがない private struct Representable: UIViewRepresentable

    { func makeUIView(context _: Context) -> TapReportingCastButton { let button = TapReportingCastButton(frame: .zero) // 純正ボタンは渡したアイコンを tintColor で塗る。 button.tintColor = UIColor(tintColor) // a11y ラベルは SDK が cast state ごとのローカライズ済み文言を // 既定で設定するため、こちらでは触らない。 button.onTap = onTap return button } } © 2026 TVer INC.
  15. AIは速い。でも、任せきれない 特定のOSバージョンでSwiftUIが期待通りに動かない SwiftUI では、特定のOSバージョンで動かない private func attach() { var view:

    UIView? = superview while let c = view, !(c is UIScrollView) { view = c.superview } guard let sv = view as? UIScrollView else { return } // iOS 17 では onScrollPhaseChangeはないので、UIScrollViewで実装 offsetObs = sv.observe(\.contentOffset, options: [.initial, .new]) { [weak self] _, _ in self?.scheduleEmit() } // 慣性中を掴んで離す操作は offset が動かないので pan からも拾う sv.panGestureRecognizer.addTarget(self, action: #selector(panStateChanged)) } © 2026 TVer INC.
  16. AIは速い。でも、任せきれない SwiftUI にその機能が存在しない SwiftUI の Menu には開いているか閉じているかを表す情報を返せない private func deferredRowElement(

    resolve: @escaping @MainActor @Sendable () async -> [MenuAction], onSelect: @escaping @MainActor (MenuAction) -> Void, ) -> UIDeferredMenuElement { UIDeferredMenuElement.uncached { completion in Task { @MainActor in completion(await resolve().map { $0.uiAction(onSelect: onSelect) }) } } } © 2026 TVer INC.
  17. 決めるのは⼈間 AIの失敗は、決定の不在だった 02章で⾒た失敗と、そこで⼈間が決めていなかったこと。 AIがやったこと(02章) ⼈間が決めること 近くのコードを⼿本にする → 嘘の仕様が正しくなる → バグが、バグのまま仕様になる

    → UIKitがいいのか? SwiftUIがいいのか? → © 2026 TVer INC. ① 構造を決める 境界を切り、参照すべき場所を作る ② 正の在り処を決める どこを信じるかを指定する ③ 仕様の中⾝を決めて返す 外から正を持ってくる ④ 実機で動作を⾒てUI を承認する
  18. 決めるのは⼈間 何を失うかを決める // SwiftUI Text には無い指定 let style = NSMutableParagraphStyle()

    style.lineBreakMode = .byCharWrapping // 代償: byCharWrapping を選ぶと // © 2026 TVer INC. UILabel は末尾省略(…)を描かない。
  19. 決めるのは⼈間 決めたら、仕組み化するまでが決定 決めたこと 置き直した先 次からどうなるか アーキテクチャ モジュール + 依存⽅向 lint

    違反すると CI で PR が⽌まる 正しさの根拠 .claude/agents/ rules/ Confluence / Figma 同じ仕様から実装される 実機で動作を⾒てUI を 承認する UI パッケージで共通化する 同じUIパーツを利⽤すれば問題は今 後起こらない © 2026 TVer INC.