「Chatwork」アプリにおけるSVVS実装戦略

121 Views

September 20, 25

スライド概要

iOSDC2025の登壇資料です。

ビジネスチャット「Chatwork」を提供する株式会社kubell(旧Chatwork株式会社)では、iOSDC Japan 2023で「SVVS」に関する発表を行いました。
あれから2年、Swiftの進化とともに、私たちの実装も大きく前進しています。

本セッションではその続編として、最新のSwiftを活用した「SVVS実装戦略」をお届けします。進化の過程で、私たちは以下のような課題に向き合ってきました。

・アプリ全体で有効なものと、ログイン中にのみ有効なもののライフサイクル設計
・CombineからObservationへの移行とその影響
・DIを用いたUIロジックの単体テスト手法

これらの課題に対するkubellでのアプローチを、具体的なコードの変遷とともにご紹介します。

シェア

またはPlayer版

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

ダウンロード

関連スライド

各ページのテキスト
1.

「Chatwork」アプリにおける SVVS実装戦略 株式会社kubell iOS開発グループ / 基盤開発チーム 若江 照仁 2025年9月20日 iOSDC Japan 2025

2.

自己紹介 ● 名前:若江 照仁 (terry @terrypy6) ○ ● 2023年に 株式会社kubell (当時 Chatwork株式会社) 中途入社 役職:iOS開発グループ 基盤開発チーム(通称: Blanc) チームリーダー ● 趣味 ○ ギター ○ 燻製 ○ ウィスキー ○ 娘と遊ぶ 2

3.

会社概要 会社名 株式会社kubell 代表取締役CEO 山本 正喜 グループ従業員数 639名(2025年6月時点) 所在地 東京、大阪 設立 2004年11月11日

4.

MISSION 働くをもっと 楽しく、創造的に ⼈⽣の⼤半を過ごすことになる 「働く」という時間において、 ただ⽣活の糧を得るためだけではなく、 1⼈でも多くの⼈がより楽しく、 ⾃由な創造性を存分に発揮できる社会を実現する。

5.

2024年7月1日よりChatwork株式会社は、株式会社kubell(読み:クベル)に社名変更しました。 株式会社kubellは、誰もが使いやすく、社外のユーザーとも簡単につながることができる 日本最大級のビジネスチャット「Chatwork」を運営しています。 また、チャット経由で会計、労務、総務など様々なバックオフィス業務をアウトソースできる 「Chatwork アシスタント」などのBPaaSサービスを幅広く展開。 ビジネスチャットの会社から、BPaaSで「働く」を変えるプラットフォームを提供する会社へ事業領域を拡張します。

6.

01 | SVVSの概要 02 | ライフサイクル設計 03 | DIとViewStateのテスト CONTENTS 目次 04 | CombineからObservationへ

7.

SVVSの概要

8.

SVVSの概要 8

9.

SVVSの概要 Store View ViewState 9

10.

SVVSの概要 Store 10

11.

SVVSの概要 画面に閉じない「状態」の単一の情報源 画面に閉じない範囲で扱う「状態」を管理する SwiftUI化に重要なSingle Source of Truthを実現する 11

12.

SVVSの概要 ViewState 12

13.

SVVSの概要 Viewの状態を管理する StoreのデータをViewの表示に適した形に修正して、自身のプロパティに反映する 画面内の入力状態など、画面に閉じた状態もViewState自身で管理する 13

14.

SVVSの概要 View 14

15.

SVVSの概要 SwiftUIで実装された画面 Viewは必ずViewStateを持つ (View ≠ Component) ObservationやObservableObjectの仕組みでViewStateを保持する 15

16.

ライフサイクル設計

17.

ライフサイクル設計 「Chatwork」アプリ SVVS導入における2つの課題 課題 1 「データ不整合のリスク」 課題 2 「煩雑なアンラップ処理」 17

18.

ライフサイクル設計 データ不整合のリスク アカウント切り替え アカウントA アカウントB アカウントAのデータで 上書き アカウントAのデータを 非同期で取得 18

19.

ライフサイクル設計 煩雑なアンラップ処理 ログイン前提のロジックでも毎回ログイン情報をアンラップ 19

20.

ライフサイクル設計 ライフサイクル を意識した設計 20

21.

ライフサイクル設計 ライフサイクルとは 「オブジェクトや処理が生成されてから 破棄されるまでの一連の流れ 」

22.

ライフサイクル設計 アプリのライフサイクル 「定数」「アプリの設定」など アプリ 起動 アプリ 終了 Global Context 22

23.

ライフサイクル設計 ログインのライフサイクル 「ユーザ情報」 「チャット情報」 ログイン ログアウト ? 23

24.

ライフサイクル設計 LoginContext 24

25.

ライフサイクル設計 LoginContext 補足:非Optionalで保持 ログイン中に必ず存在するもの ログインのライフサイクル上でのみ存在する ● ログイン情報などログイン中に 必ず存在するものはアンラップ不要 全てのインスタンスを単一のインスタンスで保持 ※ 画面内などに閉じた状態(データ)ではない ログイン時に生成され、ログアウト時に破棄される staticに保持せず、グローバルスコープからのアクセスを制限 バケツリレーにより各View, ViewStateへ渡す 25

26.

ライフサイクル設計 アプリのライフサイクルなのでログインしない状態も扱う Global Context RootView ログイン前 ログイン MainView RoomListView ログイン情報 ? アンラップ ログイン情報 ? アンラップ 26

27.

ライフサイクル設計 ログインのライフサイクルなのでログインの状態のみ扱う MainView RoomListView アンラップ不要 アンラップ不要 LoginContext LoginContext RootView ログイン前 ログイン LoginContext 27

28.

ライフサイクル設計 Global Context アクセス不可 MainView RoomListView LoginContext LoginContext RootView ログイン前 ログイン LoginContext

29.

ライフサイクル設計 ログアウト 破棄 MainView RoomListView LoginContext LoginContext RootView ログイン前 29

30.

ライフサイクル設計 「Chatwork」アプリ SVVS導入における2つの課題 課題1 「データ不整合のリスク」 → 解決!! 課題2 「煩雑なアンラップ処理」 → 解決!! 30

31.

DIとViewStateのテスト

32.

DIとViewStateのテスト Storeを通してAPI通信が発生 ↓ テストがFlaky 32

33.

DIとViewStateのテスト Storeを抽象化 33

34.

DIとViewStateのテスト 34

35.

DIとViewStateのテスト 型パラメーターインジェクション 35

36.

DIとViewStateのテスト 36

37.

DIとViewStateのテスト 37

38.

DIとViewStateのテスト 38

39.

DIとViewStateのテスト Dependency: DependencyProtocol 39

40.

DIとViewStateのテスト 40

41.

DIとViewStateのテスト 41

42.

DIとViewStateのテスト 使わない定義も必要? 42

43.

DIとViewStateのテスト ✅ 使う ⛔ 使わない 43

44.

DIとViewStateのテスト protocol の Default実装 による 解決 44

45.

DIとViewStateのテスト 45

46.

DIとViewStateのテスト 46

47.

DIとViewStateのテスト 47

48.

DIとViewStateのテスト ✅ 使うものだけ 48

49.

DIとViewStateのテスト 実際のLoginViewStateのテスト 49

50.

DIとViewStateのテスト ログイン中かどうか ログインボタンタップ 50

51.

DIとViewStateのテスト 開始 ログインボタンタップ ⚠非同期 ログイン処理開始 ✅ ログイン中 ログイン処理完了 終了 51

52.

DIとViewStateのテスト 処理の順番を制御したい 52

53.

DIとViewStateのテスト 開始 ログインボタンタップ ⚠非同期 ログイン処理開始 ログイン処理 開始を待機 ログイン処理完了 ログイン処理 完了を制御 終了 53

54.

DIとViewStateのテスト 54

55.

DIとViewStateのテスト テスト側で待機したいので テスト側で作成した continuationをセット 55

56.

DIとViewStateのテスト Store側で待機したいので Store側で作成した continuationをセット 56

57.

DIとViewStateのテスト 開始 ログインボタンタップ ログイン処理開始 ✅ ログイン中 ログイン処理完了 終了 57

58.

Combine から Observation へ

59.

CombineからObservationへ コードが減り・バグも減る データの同期処理を手続き的に書かなくてよくなる 責務がわかりやすい リアクティブ 本質的ではないコードが減る 各レイヤー間のデータが 同期されている SwiftUI向け Storeを単一の情報源としてSingle Source of Truthを実現 59

60.

CombineからObservationへ Combine Customize handling of asynchronous events by combining event-processing operators. The Combine framework provides a declarative Swift API for processing values over time. These values can represent many kinds of asynchronous events. Combine declares publishers to expose values that can change over time, and subscribers to receive those values from the publishers. Observation Make responsive apps that update the presentation when underlying data changes. Observation provides a robust, type-safe, and performant implementation of the observer design pattern in Swift. This pattern allows an observable object to maintain a list of observers and notify them of specific or general state changes. This has the advantages of not directly coupling objects together and allowing implicit distribution of updates across potential multiple observers. 60

61.

CombineからObservationへ メリット1 Store → ViewState → View データ の 購読が シンプル 61

62.

CombineからObservationへ Combine 購読処理が必要 62

63.

CombineからObservationへ Observation コンピューティッドプロパティで そのまま渡すだけ 63

64.

CombineからObservationへ メリット2 抽象化しやすい 64

65.

CombineからObservationへ Combine 65

66.

CombineからObservationへ Combine 書き込み可能 読み取り専用 66

67.

CombineからObservationへ Observation 67

68.

CombineからObservationへ メリット3 パフォーマンス改善 68

69.

CombineからObservationへ View name 名前だけ表示する画面 ViewState name Store name email Storeには メールアドレスもある 69

70.

CombineからObservationへ Combine View name 再描画 ViewState name 変更を検知 Store name email 70

71.

CombineからObservationへ Observation View name 何も起きない ViewState name 何も起きない Store name email 71

72.

まとめ

73.

まとめ ・LoginContext ・DIとテスト手法 ・Observation あくまでSVVSの実装の一例 複雑な仕様をシンプルに保つための実装戦略 73

74.

まとめ SVVS Sample Repository https://github.com/chatwork/iosdc2025_svvs-sample 74

75.

まとめ 最後に一つ宣伝です 75

76.

まとめ 76

77.

働くをもっと楽しく、創造的に 77