Robust SwiftUI State Modeling

2K Views

January 28, 26

スライド概要

YUMEMI grow 26という勉強会で発表した資料です
https://yumemi.connpass.com/event/380643/

ご意見がありましたら #yumemi_grow とか https://x.com/yimajo

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

(ダウンロード不可)

関連スライド

各ページのテキスト
1.

Robust SwiftUI State Modeling AIがコードを書くのが当たり前となった時代は ソフトウェアエンジニアは品質について考える事が超重要 2026.1.28 #yumemi̲grow 26 y.imajo

2.

はじめに この発表はSwiftUIの頑強/しなやか(Robust)なアプリ作りについて、軽くお 話しします。 勉強会自体のテーマがgrowなので、そこから単なる設計パターンやコーディン グスタイルについてではなく、AIがコードを書くのが当たり前のこの時代のソフ トウェアエンジニアの継続的な成長とは何かについて触れたいと思ってます。 ご意見があればどんな方法でもいいので教えてください。

3.

どこにバグがあるかわかりますか? var body: some View { if data == nil { // データがない場合のView // 省略 } else if isLoading { // ロード中のView // 省略 } else { // データを表示するView // 省略 } }

4.

答え: ifの順序に依存して間違えている var body: some View { if data == nil { // データがない場合のView // 省略 } else if isLoading { // ロード中のView // 省略 } else { // データを表示するView // 省略 } } データロード中のViewを出したくてisLoading=trueにしても、その際に もしdataがnilなら「データがない場合のView」を出してしまう。

5.

解決策: 順序に依存しない「網羅性」へのシフト var body: some View { switch viewState { case .empty: // データがない場合のView - switch caseにより順番の依存をなくす - switch caseにするだけではダメでcaseで網羅 - switchの対象の変数を1つにしenumで型を作る - 状態をモデリングする // 省略 case .isLoading: // ロード中のView // 省略 // Viewが取りうる状態をモデリング enum ViewStatus { case empty case .loaded(let users) case isLoading // データを表示するView // 省略 } } case loaded(Users) }

6.

状態の組み立てはどこに書く? struct MyView: View { var body: some View { switch viewState { // 省略: 順序に依存しなくなった } } // プレゼンテーションロジック var viewState: ViewState { // この処理の中はまだ順序依存 if isLoading { return .isLoading } guard let users else { return .empty } return .loaded(users) } } - そのViewStateを計算するプレゼンテーションロジックはどこに書く? - var bodyと同じようにSwiftUI.View内に書く? - コンピューティッドプロパティとしてvar viewState? - var viewStatus: ViewStateの中は依然として実装順序の問題がある - 単体テストがしないと不安 - 単体テストのためにSwiftUIのMyViewをインスタンス化する必要性 - 弱み - プレゼンテーションロジックをViewのプロパティとする作りの弱さ - 単にviewStateをテストしたいだけなのにViewをインスタンスにする面倒さ - Viewというのは複雑に依存が増えるもので、難易度も上昇 - デザイナーが軽くUI修正しようとして触って壊すかも

7.

ViewのModel var body: some View Viewの見た目の状態 Viewの状態を計算 View ViewModel 見た目のための条件をViewStateとして整理したように ViewそのものをモデリングしたViewModelを作ればいいのでは… そこにViewState計算のようなプレゼンテーションロジックを持たせる。

8.

ViewのModel テストコードから実行 検証したいのは指定の入力のときの結果が想定通りか var body: some View Viewの見た目の状態 Viewの状態を計算 View ViewModel 見た目のための条件をViewStateとして整理したように ViewそのものをモデリングしたViewModelを作ればいいのでは… そこにViewState計算のようなプレゼンテーションロジックを持たせる。

9.

UIとプレゼンテーションロジックの分離 MVVM View UIロジック担当 どんなViewStateの時に どういう表示かをきめる ViewModel Viewをモデリングしている プレゼンテーションロジック担当 どんなデータの時にどういう ViewStateかをきめる Model ビジネスロジックをモデリング

10.

UIとプレゼンテーションロジックの分離 MVVM View UIロジック担当 どんなViewStateの時に どういう表示かをきめる ViewModel Viewをモデリングしている プレゼンテーションロジック担当 Model ビジネスロジックをモデリング どんなデータの時にどういう ViewStateかをきめる ViewModelは共通のまま iOSとiPadは共通のSwiftUI.Viewで macOSは別のSwiftUI.Viewを 使うということもまあ可能

11.

話の脱線: SwiftはenumにAssociated Valuesがある var body: Some View { enum ViewStatus { switch viewState { enum AudioState { case player(let status): case playing PlayerView(status) case pause .redacted( case prepare reason: status == .prepare ? .placeholder case player(Player) : [] case contentUnavailable ) case contentUnavailable: Text(“データが存在しませんよ”) } } } } もしAudioデータが存在しない時、 prepareとかそんな状態気にしなくていい。

12.

ViewModelがなかったら? 1.Viewへプレゼンテーションロジックが書かれてる • 表示もしないのにテストのロジック実装箇所のためにViewインスタンスを作る無駄な作業 • Viewを組み立てるテスト難易度はViewModelを組み立てるより高い 2.複数人でアプリを作る際にプレゼンテーションロジックをどのように書くかが不明瞭 • 書くスピードも遅くなる • 読む側の無駄なコストもある 3.ViewModelと同じ役割の別の名前のものがある • 「これってやってることViewModelですよね?え?どこから話せばいいの?」

13.

「MVVMのViewModelは必要か?」 私が考える結論 必要かどうかは誰が何をどういうふうに作るかに依存している たとえば、 1人が優先度を決めてテスト書かずに1時間でアプリ作る時 MVVMのViewModelが 不要か必要かを自分以外が断定できない

14.

https://www.docswell.com/s/usami-k/59MP99-mvvm-yumemigrow ここからは、前回のyumemi.grow 25の 「iOSの設計にMVVMを使わない理由」に対して 事実と異なる/別の見解 があるのでそれを指摘したいという趣旨です

15.

P13. ViewModelのテストが複雑に https://www.docswell.com/s/usami-k/59MP99-mvvm-yumemigrow#p13 感想 • それはテストコードを書きたくない理由だと思える • MVVM.ViewModelを使わない理由とは思えない • テストコードを書いてみると複雑? • 単純にテスト手法知識不足の課題のように思える • 例えばSwiftだとテストダブルはテストに関係ないものが呼ばれた らクラッシュさせるよう統一的な仕組みを1つ作るとか 引用 • ViewModelの単体テストは実際に書いてみると複雑 • ViewModelが肥大化していることも関連 • テスト用のMockがたくさん必要 • テスト対象に関係するものだけその時作るだけ • OSSが充実してるしAIがある • いくらでもシンプルにできると思う • シンプルにすることがソフトウェアエンジニアリング ではないかと思う • (人によってシンプルの解釈の違いもあり経験や危機察知 能力による違いが大きく影響するのでその感度が合う人と 仕事ができるのが良いですよね)

16.

P14. ライフサイクルの扱いが複雑に https://www.docswell.com/s/usami-k/59MP99-mvvm-yumemigrow#p14 感想 • 意味が読み取れないので的を得た回答できないかも • 二重管理になるという意味がわからない • 管理という言葉の内容が具体的に想像できない • 自分は次のように思う • MVVM.ViewModelはViewを抽象化(モデリング)している 引用 • UIKitのライフサイクルは ViewController の役割 • ViewModel ではライフサイクルを意識しないです む想定 • しかし実際に書いてみると、そううまくはいかない • ViewModel でもライフサイクルを意識した実装が 必要になる • ライフサイクルの二重管理状態に • ライフサイクルは入力としてViewModelへ伝えられる • onAppearとか • ライフサイクルは副作用としてViewModelが取得 • Sceneとか • MVVM.ViewModelはその伝えられた処理を行う • 自分のタイミングでも保持もしないので管理してると思えない

17.

P16. SwiftUIの登場 https://www.docswell.com/s/usami-k/59MP99-mvvm-yumemigrow#p16 感想 • 標準的な設計とは何をもって標準というのかが不明 • 「SwiftUIの登場でMVVMの利点は解決」も意味がわからない • むしろ • MSの宣言的UIであるXAMLがMVVMの発明になった経緯 • XAMLとViewModelはUIとプレゼンテーションロジックを分離す 引用 • MVVM は、問題点はありつつも標準的な設計のひとつ • しかし、SwiftUI の登場で話が変わってきた • MVVM の利点が、SwiftUI によって別の形で解決される るためにある • もしSwiftUIの利点がコードを実装できてしまうことだとしたら • それによって責務多重で肥大化しているのでデメリットでもある • 宣言的UIがコードを書けてしまうというのは大昔からあるデメリット •例 • ReactのJSX

18.

P17. データバインディングの仕組みがある https://www.docswell.com/s/usami-k/59MP99-mvvm-yumemigrow#p17 感想 • 「データバインディングがあるからViewModelが不要」? • 書いてることは理解できかねます • MVVM.ViewModelにとってRxなんてどうでもいいと思うため • どういうふうに勘違いをしているのかを想像 • RxがないとMVVM.ViewModelとは名乗ってはいけないと思ってる? 引用 • データバインディングの仕組みが SwiftUI フレームワー クにある • Observation など • データバインディングを RxSwift に頼る必要がない • サードパーティーライブラリへの依存の解消 • ObservationでMVVM.ViewModelを作れないと思ってる? • 知識マウントをすると • ObservationはSwift言語仕様でありSwiftUIは利用例の1つ • Observationは値の変更検知なのでテストコードにも使える

19.

P18. View が肥大化しにくい https://www.docswell.com/s/usami-k/59MP99-mvvm-yumemigrow#p18 感想 • ViewControllerが肥大化していたよくある理由を自分なりに考えると • Appleのサンプルコードをそのままプロダクションで真似された • DelegateパターンによるサンプルをそのままVCに実装したから • イベントをVC自身が自分に移譲し自分に実装してしまった • 責務がイベントハンドリングとデータソース両方兼ねた 引用 • ViewController や ViewModel が肥大化していたのは次 の理由 • 責務があいまいになりやすい • データバインディングが冗長になりやすい • SwiftUI の View は責務がわかりやすい • プレゼンテーションの実装に集中しやすい • ロジックも書けてしまうけど、分離はしやすい • データバインディングもシンプルになった • くり返しだけどSwiftUIのViewは責務がわかりやすくない • ロジックが書けてなんでもできてしまう • 「ロジックをかけてしまうけど、分離はしやすい」? • 結局分離した先がViewModelならそれはViewModel不要と言えない • 最初はViewModelを作らずに必要になったら作ればいい? • じゃあ最初から作ればいい • 大抵AIがコード書くんだし

20.

P19. ViewModel は不要に https://www.docswell.com/s/usami-k/59MP99-mvvm-yumemigrow#p19 感想 • 適切な設計はチームの数だけあると思う • テストコード書かないならぶっちゃけ何でもいい • どんな人たちが何をどのくらいの期間で作るのか • もし私が趣味で1ヶ月以上アプリを作るならTCAを使うと思う • 1ヶ月未満だとViewModelを作るとは思う 引用 • View の肥大化の解決 • データバインディング手法の解決 • これらにより、ViewModel の利点の多くが不要にな り、むしろ冗長 な存在になった。 SwiftUI 時代に MVVM は適切なアーキテクチャとはいえない • 自分の場合SwiftUIに全部書くとわけわからんと思う • ViewModelではなく、Storeみたいな名前つけてプレゼン テーションロジックを分離するということもしないと思う • AIにとってもViewModelと名前がついてる方が個人ル ール押し付ける必要ないから楽なのでは?

21.

さらに念の為に想定Q&A 勝手に想定問答を作ってみます

22.

Q: プレゼンテーションロジックはswitchなの? いいえ。 var body内でロジックをなるべく減らすための例でした。 もちろんプレゼンテーションロジックをifで書く場合もあるし、switch caseを書いた上にif elseを書く場合もあっていいと思います。

23.

Q: 自分が知ってるViewModelと違う はい。 ViewModelはいっぱいあると思います。 たとえばAndroidの(Blueprint時代の)ViewModelはViewをModelingしているのではなく、 ViewがModelを使うためのモノを指していると思います。 あとクリーンアーキテクチャ本でViewModelを検索してみてください。Viewに表示する型をViewModelと呼んでいます。

24.

Q: TCAのReducerはMVVM.ViewModel? いいえ。 ViewをModelingしていませんのでMVVM.ViewModelじゃないと思います。 ViewがModelを使うための仕組みでもありません。 TCAのReducerはどちらかというとViewではなくFeatureをModelingしていると思います。 なぜなら、ActionによってStateがどのように変わるか、Side E ectがどう関係してくるのか、 さらに、Feature同士がどのように連携しているかを構造で表現することができます。 (もちろんそんなのアプリ開発に必要かというと必要ではなく、テストコードを書いていないままTCAを使ってしまうと、 ff ただのstructとenumと関数でしかなく、何だってありの実装になってしまうので感想は違うかもしれません)

25.

Q: WWDCではSwiftDataをSwiftUI.Viewに書ききってる はい。 WWDCのコードは開発用ではなく新規開発者などが参入障壁を下げるための「エントリーレベル」のコードサンプルだと思います。 そのためテストを書くことを考慮していないサンプルとなってるのではないでしょうか。 さらに彼らのプロダクトを私含めて皆さんも毎日使ってるけど、アプリやWebサービスの使いづらさはひどく、 特にQAをしていないXcodeはもっとひどい。 具体的には異常系の処理が甘いと感じます。 なので、サンプルコードのやり方が正しくて絶対と思ってはいけないと思います。

26.

まとめ • ViewModelが必要かどうかは作る人が決めれば良い • ViewModelは役割分担でありその役割をまっとうす るためにテストコードによる自動実行が補助となる • テストコードの作成コストは現代ではほぼ0に近づい てる • 正しいテストコードをAIが作れるとは限らない • ソフトウェアエンジニアは品質低下を起こさないため に、品質に向き合うことになる

27.

おわりのポエム

28.

AIによってプログラマーの時代は終わった感があり AIはもう機能のコードもテストコードもガンガン書ける。 テストコードを書く時間がコストではなくなっている。 ただ意味のあるテストコードなのかを人が見分けるのは難しい。 AIが安定したテストコードを書くのも難しい。 ソフトウェアエンジニア( プログラマー)は 自動で生成されるソフトウェアの品質低下をさせないよう、 より考えていくことが仕事になっていると思う。 そのためには課題に向き合って 手を動かしてテストコードをもっと書いたり、自動化させていって 問題を解決したり、事前にリスクを抑えたりする。 それを繰り返すのがある種の成長となるんじゃないだろうか。 他にはUI/UXとか仕様や事業に関する事とか色々あるでしょう。 ご清聴ありがとうございました。 ご意見あれば #yumemi̲grow とかに流してくれると読ませていただきます