iOSDC Japan 2022 視聴したトークをまとめてみたよ🍑
https://scrapbox.io/files/631c46de68a9a2001d561cb8.jpeg
今年もオンラインで参加しました🫶
以下、私(orimomoorimomo.icon)が視聴したトークの走り書きメモです。
(気になった部分の抜粋になっている点、聞くことに集中してしまったトークは書けていない点、ご了承ください🙏)
--------------- Day0 ---------------
◆施策基盤としてのディープリンク 〜なめらかにアプリが開く体験のために〜
Web→アプリ誘導、友達招待キャンペーンなどでディープリンクが使われる
ディープリンクは機能ではなく概念および名称
ユニバーサルリンクやカスタムURLスキームなど
Deferred Deep Link
アプリをインストールさせたときまで遷移を遅延させる
iOSに公式機能はないが、クリップ機能などを使って実現可能
Androidには公式機能あり
https://scrapbox.io/files/631c45debb656300225d8969.png
手軽に利用できるサービス
Firebase Dynamic Links
Adjust
Crossroad
一つのルート定義で多用な経路からの外部流入に対応できる
AppStore Custom Product Page
https://scrapbox.io/files/631c462d07feb4002329d867.png
https://scrapbox.io/files/631c463ec23c82001dd7471a.png
◆SwiftUI Navigation のすべて
様々な種類のNavigation
Tab
Alert
Sheet
NavigationView / NavigationLink(非推奨)
OSによる変化が激しい
https://scrapbox.io/files/631c4e8ca7849d00200ed9bc.png
Navigation APIは大きく2つに分類できる
Fire and forget Navigation API
Binding引数を取らない
State driven Navigation API
Binding引数を取る
プログラム的な制御が可能なので、Deep Linkなども可能となる
課題
遷移先の画面にBinding valueを渡す機構を備えていない
状態管理を複雑にさせるAPIが存在している
複数のNavigationを管理しだすと無駄な状態が増える
様々なパターンの状態が発生するが、有効な状態は一部のみ
どう課題に立ち向かうか
https://scrapbox.io/files/631c4eeae5f7ba001dbf6797.png
◆SwiftPMのプラグイン機能をiOSアプリ開発に活用する
https://scrapbox.io/files/631ef064a03575001dfde40b.png
パッケージ:SwiftソースファイルとPackege.swiftで構成される
XcodeプロジェクトとSwiftPM
配布されているパッケージを利用する
アプリのコードをパッケージ化
ローカルのSwiftパッケージをアプリでインポートする
一部だけでなく、ほとんどのコードをパッケージに入れても良い
パッケージ化のメリット
codeprojでのソースコード管理が減る
コンフリクトが起こりにくくなる
アプリ内のモジュール分割が容易になる
パッケージ化で未解決の問題
ビルドスクリプトはXcodeプロジェクトで管理する必要がある
SwiftLintでのコードチェックとか
→ この問題はSwiftPMのプラグイン機能で解決できる
SwiftPMのプラグイン機能(Swift5.6〜)
配布されているプラグインを使う
プラグインを自分で実装する
ビルドツールプラグイン
ビルド前
ビルド中
プラグインであらかじめ定義された処理が実行される
SwiftLintプラグイン
SwiftLint公式から artifact bundleが提供されている
これを利用してプラグインを自作すればよい
◆ChaChaPoly and You, CryptoKit Explained
CryptoKit
簡単に安全な暗号化オペレーションをおこなえるSwift Framework
wwdc 2019で発表された
https://scrapbox.io/files/631c61cdc23c82001dd80fad.png
Hash Functions
一方向(戻せない)
決定的(同じハッシュ値は必ず同じになる)
一意
https://scrapbox.io/files/631c61f7a7849d00200f98a8.png
Symmetric key cryptography(共通鍵)
同じキーで暗号化と復号化する
ChaChaPoly(モバイル端末だとオススメ。より速い)
Public key cryptography(公開鍵)
2つの異なるキーを使う
https://scrapbox.io/files/631c62b78b6998001d48b4c1.png
◆「問題はソースコードではない!?」長生きするアプリの「品質低下」の謎
品質低下は避けられるか?
見積もりに気をつける
見積もった期間のあとの方になると焦りが出てくる
「時間がない」「スプリントが終わりそう」
綺麗じゃないコードを書いたり近道をして、品質が下がってしまう
https://scrapbox.io/files/631d83e8243fe4001dfc0220.png
ゆとりを持つ
ゆとりがない場合
3人でやってて、一人が休むと他の二人に負荷がかかってオーバーワークに
その結果品質が下がる
https://scrapbox.io/files/631d841dadaf7900231f94be.png
ゆとりがある場合
誰か一人が休んでも余裕がある。これなら持続できる
https://scrapbox.io/files/631d843dca151e001d5af944.png
見えない負荷もあるので注意
ビルドにかかる時間
CIの修正
問題調査
日常的なやりとりなど
--------------- Day1 ---------------
◆Swift Concurrency Next Step
基本的な3つの機能のおさらい
Async/await
コールバックを置き換えられる
Structured concurrency
Taskで階層構造を作れる
Actor
データ競合を防ぐ
最近のアップデート
https://scrapbox.io/files/631d4abd922680001f8428ea.png
https://scrapbox.io/files/631d4b0f2d393d001d04dcbe.png
◆Kotlin Multiplatform Mobile でiOSとAndroidの実装差異を無くす
KMM
ネイティブのUXを保ったまま、ロジックをiOSとAndroidで共有する
KMMを採用した経緯
ロジック部分の品質を求められるプロジェクトだった
OS間での実装差異が問題となっている
OS間での実装差異の解消
実装するエンジニアの認識のズレ、言語仕様の違いから、どれだけ念入りにやっても発生する
KMMはiOSとAndroidで同じコードを使うことでOS間の実装差異をなくす
https://scrapbox.io/files/631d9f8df27066001d59ef2a.png
KMMとネイティブでの役割分担
ViewとViewModelはネイティブ
ビジネスロジック、ネットワーク通信、ストレージへのアクセスはKMM
https://scrapbox.io/files/631d9fb306b8ae0023692b35.png
KotlinのコードはどのようにSwift上で動作するのか?
Obj-cのフレームワークに変換される
KMMをiOSプロジェクトに組む込む方法は?
Obj-cのフレームワークに変換して利用する
iOSで普段やっているところをKMMでやるならどうするか?
マルチプラットフォーム対応のKotlinライブラリを使う
iOS独自のコードをKMMから呼び出せる
リポジトリの管理方法は?
こうしておくと担当者によって責務を分けられる
KMM更新時にiOS側にPullする部分は、CI/CDによるフレームワークの自動ビルドに任せる
https://scrapbox.io/files/631d9fe42ca325001d297626.png
実際のチームでの開発
ネイティブメンバーはビジネスロジック・インターフェースの理解が必要
KMMメンバーはKMMの利用箇所の把握が必要
相互理解を密におこなう
◆UIKit ベースの大規模なプロジェクトへの SwiftUI 導入
SwiftUI導入に向けてのプロセス
下準備のおかげでさくさく導入が進んだ
https://scrapbox.io/files/631d637036a22600211b513b.png
https://scrapbox.io/files/631d63acca151e001d59febd.png
実装者の判断でUIKitを使うか、SwiftUIを使うか判断している
◆Swift Concurrency時代のリアクティブプログラミングの基礎理解
https://scrapbox.io/files/631d8705ce004d001dfe6c4c.png
Swift ConcurrencyかRPか
いわゆる非同期プログラミングの部分はSwift Concurrenc
APIコール1個
一連のasync funcをローカルでまとめたい
状態変化があり、状態をつないでデータフローを設計できるところはRP
ローカルスコープを越えてVCやVMのメンバ変数として保持される状態があり、状態間に伝播がある
◆レガシーなプロダクトからドメイン層を再設計する
Viewが肥大化したのでリアーキテクチャした
→Viewが簡素化されてFat Presenterができた
やりたいことと違う...
twadaさん「どのレイヤーがどんな責務を持つべきかという議論の前に、ドメインがどうなっているかを知ることが重要です」
→モデリングしてみた
twadaさん「既存の実装で扱われているデータのモデリングになってしまっていて、UI、API、DBの実装の影響を強く受けてしまっている」
現状の実装に引っ張られて、レイヤリングによる交通整理をしただけだった
必要だったのは、アプリの本質から考えた基本構造のモデリングだった
https://scrapbox.io/files/631d982797bc2d001d7c23ba.png
https://scrapbox.io/files/631d984bccc88c001db2e544.png
--------------- Day2 ---------------
◆Xcode が遅い! とにかく遅い!! 遅い Xcode をなんとかする方法
ワークスペースを開いてビルドすると止まる問題
XCBBuildServiceがXcodeのビルド(インデックス作成の作業)を担っている
Xcodeとは別のプロセス
作業の中にあるバグを踏んで反応しなくなり、Xcodeを強制終了するしかなくなる
回避策
Xcode14で直っている!!
たまに普段よりビルドが遅くなる問題
アクティビティモニターで見ると、ビルドが進んでないように見え、CPUも暇してそう
clang(C言語向けコンパイラ)のロック機構の問題
ロック解除を待ち、一つのclangしか仕事ができない状況が発生する
回避策
ロックしないように設定したり
挙動を解決したツールチェーンに置き換えたり(ツールチェーンのビルドはかなり大変)
FIXMEって書いてあるから直してほしい
Xcodeやめる?
問題点
Appleしか手出しできないうえに更新が遅い
大きなアプリをビルドする顧客がターゲットでないように思える
利点
プラットフォームの新しい機能に即座に追従できる
ほとんどの開発者が使うデファクト
外部のビルドツールだと有名なのはBazel
LINEも使ってる
https://scrapbox.io/files/631e958a07512800201b2015.png
https://scrapbox.io/files/631e95b6bd0d0d001d0d61af.png
◆Feature Flagを使った開発で高速でストレスフリーなデリバリーを実現する
チーム開発でのブランチ運用
複数ブランチで並行開発するのが特徴
メインブランチ(リリースコード)を壊してはならないがルール
専用の開発ブランチを作りがち(親ブランチから小ブランチを作る)
影響範囲の分離には成功したが、課題も多い
https://scrapbox.io/files/631e9677a03575001df6a36a.png
トランクベース開発
常にメインブランチから開発・マージする開発手法
Rettyも全社的に親ブランチからトランクベースに移行した
かつてはビックバンリリースが主流だった
小さく開発・小さくリリースするため
リリース版に影響与えないようにするためのFeatureFlag
https://scrapbox.io/files/631e976921ae46001d8e6b20.png
自前実装もできるし、外部サービスだとFirebase Remote Configなどがある
Rettyだと基本は自前実装、足りなければ外部サービスという使い分け
https://scrapbox.io/files/631e97fcb816ae001d9a7e2e.png
FeatureFlagの注意点
Feature Flagは最終手段と考え、動作に影響しない部分は早くリリース
分岐は極力ブロックにまとめる
三項演算子は間違えやすいので注意
QAやUIテストなどでフラグが反転してないかを常に確認
不要フラグの削除は早めに
フラグ削除までがリリース
◆サーバーと同期してリアルタイムに更新する画面を実装する
更新の種類
ユーザーの明示的なアクション
PullToRefleshや更新ボタン
自動的な更新(今回はこっちの話)
サーバーの更新を検知してリアルタイム更新
soft-real-time: 多少のオーバーヘッドは許容する
Polling
クライアントで指定の間隔でAPIを呼ぶ
タイマーでぐるぐる回すだけ
実装がシンプルでAPIも使い回せる
無駄なAPI通信が発生するのでパフォーマンスが悪い
ユーザー数が増えるとその分増える
サイレントPush通知
payloadにcontent-available:1で送る
既存のPushの仕組みを使い回せる
他のプラットフォームへの流用が難しい(デスクトップなど)
ユーザー設定でOFFにできてしまう
Push通知対応してない場合新規実装が必要
Firebase Realtime Database
Client実装がシンプル
インフラのメンテナンスコスト低い
FirebaseにDBが依存してしまう
https://scrapbox.io/files/631e9f571d9fbb001d3f9e7a.png
WebSocket
クライアント-サーバー間双方向通信を可能にする
拡張性・自由度が高い
他プラットフォームでも同様の仕組みが使い回せる
クライアント-サーバー実装が大変になりがち
https://scrapbox.io/files/631e9f8a0c1efd001d10f554.png
https://scrapbox.io/files/631e9f94bae7130021924a7b.png
clusterでの実例
メッセージやフレンドリクエストに利用
WebSocketを採用
多くのプラットフォームをカバーできる
Unity内の通知にもWebSocketを利用
FirebaseのDBを利用していない
UIをリアルタイムに更新するときに大事なこと
ユーザーの邪魔をしない
突然インジケーターやエラーを出たり
スクロールしてた画面が勝手に戻ったりはだめ
DiffableDataSourcesで差分更新を実現できる
◆モバイルアプリの行動ログの「仕込み」を快適にする
ドキュメントベースの型安全なログ実装コード自動生成
マークダウン記法でドキュメントを書く
makeコマンドでスクリプトを実行
Xcodeプロジェクト内にコード(ログ定義のenum)が自動生成される
生成された列挙型でログ送信箇所に実装する
2年間混乱なく活用できている
良い点
ドキュメントが常に完備される
アプリと同じリポジトリでGitバージョン管理
型安全
ドキュメントと実装のズレを静的解析で自動検出(CIで定期確認)
https://scrapbox.io/files/631eec25b816ae001da064af.png
リリース後にログの実装漏れに気づくケースを回避したい
チェックリストが自動で埋まるアプリ内ログ確認ツール
開発ビルドだけで見れるアプリ内ログビューアー
ログの確認は地味に面倒で、その面倒さが実装漏れにつながっている
実装者以外でも確認できるのも良い点
https://scrapbox.io/files/631eebf997edea001d1bc0bb.png
https://scrapbox.io/files/631eec02e69ce30020aa4d73.png
どれも勉強になるトークでした👏 あとで見返します。
スピーカー・寄稿者のみなさま、運営の方々、今年もありがとうございました!!!!
https://scrapbox.io/files/631ef90921ae46001d9572f7.png