2023/06/15開催、NIKKEI Tech Talk #8登壇資料です #nikkei_tech_talk タイトルは「Androidチームにおけるレガシーコードとの向き合い方 」です https://nikkei.connpass.com/event/284090/
2023/6/15日本経済新聞社 サブスクリプション事業デジタル編成ユニット夏坂 友輔Androidチームにおけるレガシーコードとの向き合い方NIKKEI TECH TALK #8
View Slide
自己紹介2● デジタル編成ユニット アプリチーム● 夏坂 友輔(なつさか ゆうすけ)● 2020年10月 中途入社● @ntsk● Androidアプリのレガシーコードの改善に取り組んでいます
本日話すこと3日経電子版、日経紙面ビューアーのAndroidアプリはリニューアルのあった、2015年から8年ほど運用しているコード。HandlerやAsyncTaskLoaderを駆使した昔ながらの実装から、CoroutinesFlowやComposeを利用した最新の実装まで様々。僕たちのチームのレガシーコードにまつわる課題を紹介しつつ、解決のためのアプローチについて紹介します。
レガシーコードとは4
レガシーコードとは5t● テストのないコード、テストができないコード● 修正や拡張、作業が難しいコード参考・Michael C Feathers.「レガシーコード改善ガイド」. 2009/7/14. 翔泳社・David Scott Bernstein. 「レガシーコードからの脱却」. 2019/9/19. O’Reilly Japan
僕たちのアプリにおけるレガシーコード6● 実装当初からテストがない、もしくはテストしづらい実装のもの○ 実装初期などテストを書く文化形成以前に実装された○ AsyncTaskLoaderを利用した非同期処理が残っていたり、UIとロジックが密結合しておりテストが書きづらい○ 更新頻度が低いアプリ・画面だと長い間そのままになっている
僕たちのアプリにおけるレガシーコード7● Androidアプリ開発のスタンダードが変化することによってレガシーになったもの○ アプリアーキテクチャガイド登場以前の複数世代のアーキテクチャが混在○ 当時はメジャーだった古いサードパーティライブラリと設計が密結合している○ BaseActivity, BaseFragment, BasePresenter, BaseFragmentViewなど継承を利用した画面が多く、ライフサイクルのタイミングが異なるケースなど都度継承元の実装に対する考慮が必要○ その他、OSやSDKのバージョンアップに伴って修正が必要なもの
僕たちのアプリにおけるレガシーコード8● サービス要件の変化が積み重なってレガシーとなったもの○ ローカルDBのテーブル設計がドメインモデルの変化とマイグレーションを繰り返す中で扱いづらくなってきているが、全体を再設計してマイグレーションするコストも高い。OrmLiteやRealmが採用されているが再設計に合わせてRoomに移行もしたい。
僕たちのアプリにおけるレガシーコード9● 短期的な不具合修正が積み重なってレガシーとなったもの○ 障害発生時に暫定対応を行なったコードを追加してリリースし、恒久対応についても方針だけは決まっているが実装されていない
レガシーコードによる影響10
不確実性の増加11レガシーコード比率が高い画面に対して、機能追加に時間がかかる。● 主要な画面ほど機能が多く複雑性も高い。歴史も長いのでレガシーコードの比率も高く単純な機能追加でも時間がかかる● テストをかける状態にするまでのステップが多い● 不確実性が高いので単純な機能追加でも見積もりのバッファが大きくなる
予期しない不具合の発生12レガシーコード起因の不具合がたびたび発生● Baseクラスのライフサイクルに起因したクラッシュの発生● Chromeのアップデートに伴いWebViewの表示が崩れる● DBパフォーマンスの劣化● ANRの発生
レガシーコード改善が永遠に終わらない問題13
レガシーコード改善が永遠に終わらない問題14中長期的な開発速度や開発者体験が低下することによるリスクについてはチームは理解している。だからこそ新機能開発時の事前リファクタリングや、細かなコード改善を日々行なっているが、それでもレガシーコードによる負荷がいつまで経っても減らない。
レガシーコード改善が永遠に終わらない理由151. レガシーコードを要因とした中間的実装の増加 Aで実装したいがB(レガシーコード)が要因でCの実装を行う● Bがアプリケーション全体に影響するなど即時解決困難な課題の場合、機能開発を優先するためCの実装が増え続け、Aの実装が増えない● 問題発生時に暫定対応を行い、恒久対応のためのIssueが作られるが、恒久対応の優先度が上がらない● 将来はAにしたいけどCになってるという経緯を理解する負荷が増える
レガシーコード改善が永遠に終わらない理由162. レガシーコードの解決に必要なタスクが時間と共に肥大化● Aの実装にはBの実装にはCの実装にはDの実装には(以下ループ)● 時が経つにつれ解決に必要な作業が増えていく● 巨大に膨れ上がり、触ることのできない課題になってしまう● 触ることができないのでさらに巨大化していく
レガシーコード改善が永遠に終わらない理由173. チームメンバーがみんな機能開発をしている● 機能開発と一緒にリファクタリングする場合、その機能に関わる画面にしか着手できないので根本解決ができない● スプリントの範囲内で終わるような課題にしか取り組めない● 並行して様々な機能開発が進むため認知負荷が高まる
レガシーコード改善が永遠に終わらない理由184. 開発案件とコード改善のバランス・優先度設定の負荷が高い● 機能開発とコード改善は目的とする指標が異なるため、適切な優先度設定が難しい。チーム外から依頼されたり規模の大きいプロジェクトが走るとそちらに注力しがちに。● コストパフォーマンスの高いものから優先的に着手すると、工数が大きいアプリケーション全体に関わる問題については優先度が上がりづらい
19
レガシーコード改善を進めるためのアプローチ20
継続的にコード改善を行えるチーム体制に21これまでの開発体制(~2023/3)● コードの改善も含め、全てのタスクを1つのバックログで管理し優先度を設定● チームメンバーはバックログの優先度順にタスクに着手ConversionOnboardingRetentionProductBacklogSprintBacklogCodeRefactoring
継続的にコード改善を行えるチーム体制に22変更後の開発体制(2023/4~)● 中長期的な技術的課題のみの優先度に絞って開発を行うチームを分割● 技術的課題の解決による指標を設定し改善できるようにするConversionOnboardingRetentionProductBacklogSprintBacklogCodeRefactoringProductBacklogSprintBacklog
継続的にコード改善を行えるチーム体制に23新体制のモチベーション● チームの目的と責任範囲を明確にすることによる認知負荷の低減● 安定した改善のための工数が確保● アプリケーション全体に関わるような中長期で取り組む必要のある問題についても着手できる● 人数が増えてきたこともあり、チームを今後どのようにスケールさせていくかの実験的な取り組みでもある
継続的にコード改善を行えるチーム体制に24メトリクス・指標の作成やチームの目標設定● 目標の設定によりチームの存在意義が明確に● 開発チームのパフォーマンスを表す指標としては「Four Keys」が有名だが、デプロイ頻度などモバイルアプリ開発と完全にマッチしない部分もある● 開発におけるリードタイムや、アーキテクチャ適応度関数、レガシーコード比率、変更障害率などのチームの実情にあった可視化を行い改善する
継続的にコード改善を行えるチーム体制に25認知負荷の種類から適切な境界を模索する● 課題内在性負荷○ 問題領域の本質的なタスクに関連するもの● 課題外在性負荷○ タスクが実施される環境に関連するもの● 学習関連負荷○ 学習を進めたり高性能を実現したりする上で、特別な注意が必要なタスクに関連するもの参考・Skelton Matthew, Pais Manuel 「チームトポロジー」日本能率協会マネジメントセンター
継続的にコード改善を行えるチーム体制に26まだまだ課題は山積み● iOS/Android共通の技術課題の解決● コード改善に対する適切なKPI・閾値の設定● リグレッションテストをはじめとしたQAコスト● etc…フェーズに合わせて適切にチームやアーキテクチャを進化させていく
ありがとうございました!DroidKaigi2023にもadbに関する内容で登壇しますので是非聞きに来ていただけると嬉しいです!27