7年開発/運用が続くkencom iOSアプリの全面的リファクタリング【DeNA TechCon 2023】
by
DeNA_Tech
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
7年開発・運用が続いている kencomのiOSアプリの全面的リ ファクタリング 野瀬田 裕樹
Slide 2
Slide 2 text
野瀬田 裕樹 所属 ヘルスケア事業本部 製品開発部モバイルソリューションG 担当 iOS/Androidエンジニア 出身地 京都府 家族構成 妻と4歳の長男の3人家族 2 @ynoseda
Slide 3
Slide 3 text
kencomとは ● https://kencom.jp/ ● 2015年10月にv1.0.0をリリース ● 楽しみながら健康になれることを促す ● 健康保険組合・自治体などの団体に対 して販売を行っている ○ 団体に所属している人だけが使える ● 健康診断の結果の閲覧、健康状態に応 じた記事のレコメンド、歩数データの 管理などができる 3
Slide 4
Slide 4 text
● 1st commit:2015年6月5日 kencom iOSアプリの開発の履歴 4
Slide 5
Slide 5 text
● 1st commit:2015年6月5日 ● 1st release:2015年10月8日 =開発期間4ヶ月 kencom iOSアプリの開発の履歴 5
Slide 6
Slide 6 text
● 1st commit:2015年6月5日 ● 1st release:2015年10月8日 ● 基本的には100% swift kencom iOSアプリの開発の履歴 6
Slide 7
Slide 7 text
● 1st commit:2015年6月5日 ● 1st release:2015年10月8日 ● 基本的には100% swift ● 短期間での開発のためか初期から負債が蓄積された状態 ○ Realmを使っているが不安定で壊れたりしていた(その後に削除) ○ FatViewController、FatStoryboard ○ ViewController内でviewの位置調整などを多数やっている kencom iOSアプリの開発の履歴 7
Slide 8
Slide 8 text
● 現時点で24 Contributors ● gitのログから大規模なアプリの機能改修は今まであまりなく、 リファクタを推進するきっかけに乏しかった様子が伺える kencom iOSアプリの開発の履歴 8
Slide 9
Slide 9 text
● 現時点で24 Contributors ● 大規模なアプリの機能改修は今まであまりなかった ● その結果、秘伝のタレコードが多数発生 ● 以下のような課題が発生 ○ 提供する機能要件に対して不必要に多いコード量 ○ 現在では不要になった多数のOSSのライブラリ ○ 結果としてビルド時間が長くなってきた kencom iOSアプリの開発の履歴 9
Slide 10
Slide 10 text
● 色々な負債が存在していたため、全てをリファクタは困難 リファクタリングの方針 10 秘伝のタレ 重いビルド 古い設計 不要な実装 古い書き方
Slide 11
Slide 11 text
● 色々な負債が存在していたため、全てをリファクタは困難 ● そこでまずは今後の開発を楽にするためのリファクタを実施 ● リファクタリングの方針 ○ 通信部分の刷新 → 今後の機能開発で簡潔に書けるようになる ○ プロジェクト全体のスリム化 → 断捨離でビルド時間短縮を期待 リファクタリングの方針 11
Slide 12
Slide 12 text
● 通信ライブラリの選定 ● インターフェース設計 ● 通信呼び出し部分の差し替え作業 通信部分の刷新 12
Slide 13
Slide 13 text
● 旧実装ではライブラリとしてMoyaを採用 ● MoyaとはAlamofireをラップしたライブラリ 通信部分の刷新:通信ライブラリの選定 13
Slide 14
Slide 14 text
● 旧実装ではライブラリとしてMoyaを採用 ● MoyaとはAlamofireをラップした通信用のライブラリ ● しかし、旧実装ではMoyaのメリットが活かせていない状態 ○ 通信部分の単体テストは行ってない ○ Moyaを更にラップした通信クラスがある 通信部分の刷新:通信ライブラリの選定 14
Slide 15
Slide 15 text
● 考えられる方針 ○ ライブラリは今のまま:Moyaのメリットを最大限に生かす ○ ライブラリを使わない:URLSessionを直接使用する ○ 使うライブラリを変更する:Alamofireに切り替える 通信部分の刷新:通信ライブラリの選定 15
Slide 16
Slide 16 text
● 考えられる方針 ○ ライブラリは今のまま:Moyaのメリットを最大限に生かす ○ ライブラリを使わない:URLSessionを直接使用する ○ 使うライブラリを変更する:Alamofireに切り替える 通信部分の刷新:通信ライブラリの選定 16
Slide 17
Slide 17 text
● 旧実装のインターフェースはRxSwiftのObservable ● 具体的には、request関数の返り値がObservable 通信部分の刷新:通信のインターフェース 17
Slide 18
Slide 18 text
● 昔はRxSwiftを利用したReactiveプログラミングが多かった ● Swift 5.5からasync/awaitを使った非同期処理が可能になった ● 同期処理のコードにasync/awaitのキーワードを追加するだけで 非同期処理になるので非常にシンプルに書ける 補足)Swiftの非同期処理について 18
Slide 19
Slide 19 text
通信部分の刷新:実装イメージ 19 ● 通信を行うstaticな関数を準備 ● 新しい実装ではasyncな関数として通信のI/Fを用意
Slide 20
Slide 20 text
通信部分の刷新:実装イメージ 20 ● APIのリクエストに必要なものを実装するためのprotocolを準備
Slide 21
Slide 21 text
● 作業手順 ○ 全てのAPIを一覧にしてチェックリストを準備 ○ API一つにつきAPIRequestに適合したstructを準備 ○ 一つずつ新しいrequest関数に置き換え ○ 全て置き換えが完了したら古いコードを削除 通信部分の刷新 21
Slide 22
Slide 22 text
● 作業手順 ○ 全てのAPIを一覧にしてチェックリストを準備 ○ API一つにつきAPIRequestに適合したstructを準備 ○ 一つずつ新しいrequest関数に置き換え ○ 全て置き換えが完了したら古いコードを削除 通信部分の刷新 22
Slide 23
Slide 23 text
● 利用しているライブラリの見直しを実施 ○ 元々使用していたライブラリの数:25個 ○ 断捨離できるライブラリの数:半分以上 ● 元々使っていたライブラリの例 ○ Rx系(RxSwift, RxCocoa) ○ ObjectMapper ○ CryptoSwift プロジェクト全体のスリム化 23
Slide 24
Slide 24 text
● Rx系の断捨離の方針案 a. 対応するCombineのコードで置き換え b. 個別に最適な実装にリファクタ プロジェクト全体のスリム化:Rx系の断捨離 24
Slide 25
Slide 25 text
● Rx系の断捨離の方針案 a. 対応するCombineのコードで置き換え b. 個別に最適な実装にリファクタ c. 一部はリファクタするが、大半は機械的にCombineに置き換え プロジェクト全体のスリム化:Rx系の断捨離 25
Slide 26
Slide 26 text
● Rx系の断捨離の対応内容 ○ ほぼ機械的にCombineのコードに置換できたため、ひたすら置換 ○ 通信部分やRepositoryへのアクセスはasync/awaitで書き換え ○ RxCocoaなど機械的な置換ができない箇所だけ後から手動書き換え ○ 基本的に地道な作業なので気合いで修正を完了 プロジェクト全体のスリム化:Rx系の断捨離 26
Slide 27
Slide 27 text
● ObjectMapperについて ○ Jsonと任意のモデルオブジェクトとを相互に変換できる ○ 今ではCodableがある ○ 通信部分の刷新に合わせて全てCodableに置き換え ○ これもほとんど機械的な修正で済むため、気合いで修正 プロジェクト全体のスリム化:ObjectMapperの断捨離 27
Slide 28
Slide 28 text
● CryptoSwiftについて ○ 暗号化/復号化のためのライブラリ ○ 標準のCryptoKitに置き換えできる ○ 通信のJWTを生成するためだけに使用していたので、すぐに修正完了 プロジェクト全体のスリム化:CryptoSwiftの断捨離 28
Slide 29
Slide 29 text
● その他の断捨離について(一部) ○ SwiftDate → あまり使ってなかったので標準のDateの実装に書き換え ○ Appirater → レビューのタイミング調整にだけ使ってたので削除 ○ XCGLogger → ほぼ使ってなかったので削除 ○ PKHUD → 自前のローディング画面に置き換え ○ Device → 更新されてなかったので削除 ○ SwiftyDrop → 自前のViewに書き換え プロジェクト全体のスリム化 29
Slide 30
Slide 30 text
● 10個以上のライブラリを断捨離 ● 該当バージョンで3万行以上コードを削減 リファクタリングの結果 30
Slide 31
Slide 31 text
● ビルド時間は5分以上かかっていたのが1分強に リファクタリングの結果 31
Slide 32
Slide 32 text
● QA検知の不具合は計7件 ● リリース後も大きな問題なく通常運用へ ● 要因 ○ 開発者側での手厚いレビューと開発者検証 ○ 短期間で集中的にリファクタを進めた ○ 機能開発とほぼ並行しないようにした ○ 十分に影響範囲をQAに伝えた リファクタリングの結果 32
Slide 33
Slide 33 text
● 継続して画面単位での改善も実施中 ○ 古い設計を新しい設計へ移行 ○ UIKitからSwiftUIへ移行 ● 同バージョンでホーム画面の作り直しも実施 その他のリファクタリング 33
Slide 34
Slide 34 text
● 数字ありバッジがついた丸型アイコンの実装 ● 単純にoverlayで重ねても、それっぽく見える 余談)SwiftUIで作ったViewを一部紹介 34
Slide 35
Slide 35 text
● 数字ありバッジがついた丸型アイコンの実装 ● 単純にoverlayで重ねても、それっぽく見える ● しかし、文字サイズを大きくすると位置がずれる ○ バッジの位置調整 or アイコンの可変化が必要 余談)SwiftUIで作ったViewを一部紹介 35
Slide 36
Slide 36 text
● 数字ありバッジがついた丸型アイコンの実装 ● overlayで重ねたバッジにoffsetを追加して調整 ● 指定するオフセットはバッジのサイズに応じて可変 ● 計算式:中学生ぐらいの気分になって考えてみよう 余談)SwiftUIで作ったViewを一部紹介 36
Slide 37
Slide 37 text
● 数字ありバッジがついた丸型アイコンの実装 ● overlayで重ねたバッジにoffsetを追加して調整 ● 指定するオフセットはバッジのサイズに応じて可変 ● 計算式:バッジの円の半径 - (1-1/√2) × アイコンの円の半径 余談)SwiftUIで作ったViewを一部紹介 37
Slide 38
Slide 38 text
● リファクタリングは地道な作業なので気合いは必要 ● 目的と手段を整理し、しっかり下準備すれば成功する ● リファクタリングの際には開発者確認とQAをきちんとしよう ● ちゃんとテストすれば、案外根幹部分に手を入れても大丈夫 まとめ 38
Slide 39
Slide 39 text
ご清聴ありがとうございました 良いリファクタリングライフを! 39