7年開発/運用が続くkencom iOSアプリの全面的リファクタリング【DeNA TechCon 2023】
by
DeNA_Tech
×
Copy
Open
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
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