みてね Tech Blog
🤖

みてね Android アプリのリファクタでやったことを振り返る

に公開

こんにちは。「家族アルバム みてね(以下、みてね)」でエンジニアをやっている sou といいます。

一昨年から健康のために運動を始め、今は週 6 でランニングをしてます。ちなみに執筆時 2025/12/15 現在の私の VO2 max は 54 です。 54 だとまだまだなので欲を言えば 53 万くらい欲しいです[1]

さて、この記事では 2025 年の 7 月からドメインチーム内で始めた Android のコードベースにおけるリファクタリング活動について、どのように始めどのように進めているのかについて、ちょうど半年になるため個人的な振り返りも兼ねて紹介します。

この記事は MIXI DEVELOPERS Advent Calendar 2025 の 22 日目の記事になります。

みてねの開発体制について

本題に入る前にまず背景情報としてみてねの開発体制について紹介したいと思います。

みてねでは機能(ドメイン)ごとに開発を担当するチームが割り当てられており、それぞれが自立したスクラムチームを組んで開発をしています。

私が所属するチーム「 MERCH (マーチ)[2]」では主に写真プリントや DVD といった物理商品の注文関連を担当しており、新機能開発であったり既存機能の改善、および不具合の修正などを行っています。

また、みてねの機能ごとに分かれているスクラムチームの特徴として、エンジニアは基本的に一人ひとりがアプリとサーバの両方の実装を担当することになっています。そのため、私自身も iOS / Android とサーバ( Ruby on Rails )の実装をしています。

このような体制をとることで、オンボーディングやコードレビュー、日々のコミュニケーションを通じて馴染みの薄い技術領域への理解を深め、なるべく属人化せずに技術横断的な機能開発が進められる体制を整えています[3]

開発体制に起因する課題

アプリ・サーバ問わずに機能を担当するといってもそれぞれの技術領域で専門的知識が求められることには変わりません。

そのため、たとえばある Android の機能実装を進めるとして実装者とレビュアーがどちらも Android に詳しくないような場合、本来あるべき品質を保つことに対し課題がありました。

特に私の所属する MERCH では今年に入って新しいメンバーが入るまで Android の開発経験があるエンジニアがいない状態が続いており、過去のコードを参考に実装を進めるもののそれがやや古い知識をベースにしたものだったり、実は割れ窓となっているようなコードを参考にしてしまいそれに気が付かず負債を広げてしまうといったことも起きていました。

私自身もそのうちの一人で、 Android は入社してからキャッチアップしていたためしばらくは状況を理解できていませんでしたが、理解が進むにつれ以下のような問題があることに気が付きました。

  • ほとんどすべてのコードがアプリモジュール(アプリケーションのエントリーポイントとなるモジュール)で実装されている
  • Activity では Hilt を使用しておらず Dagger の低レベル API を直接使っていたり ViewModel でも HiltViewModel や savedStateHandle を使わず値を渡しており余計なボイラープレートが多い
  • Flow ではなく LiveData が使われており Null チェックが必要なほか、 SharedFlow のようなイベントを伝播させるようなロジックになっておらず Activity と ViewModel を相互に依存(密結合)させ ViewModel から Activity のメソッドを呼び出すことで UI イベントを処理しており、これが原因で Activity が本来のライフサイクルより長く生きてしまいメモリリークにつながるほか、コードリーディングの際に処理を追ったり自動テストを書くのが難しくなっている
  • 画面は Android View で構築されており DataBinding を使用している箇所も多く Compose 化するための移行コストが高い設計となっている
  • onActivityResult など Deprecated となっているコードが残っている

さらには Epoxy が現役で使われていたり[4]と私が当時気が付いていない問題が他にもあり、みてね全体で進めているモダン化に対しても MERCH が担当する領域については足並みが揃えられていない状況でした。

そこで、問題を解決するべく実際に何度か散発的に手を動かしてみたものの、担当するドメインの担当範囲の広さ、そして解消すべき問題の多さから単独で進めるのは限界があることが分かりました。

一方でコードベースはそうしている間にも増え、割れ窓が新たな割れ窓になるような状況も懸念されたため早めに手を打つ必要があるという認識を持っていました[5]

やや長くなりましたがここまでが背景、そしてここからが改善活動のためにやったことになります。

チーム内で仲間を集める

このような状況から以下のようなアプローチで問題を解決するのはどうかと考えました。

  • リファクタで優先すべき技術課題を決める
  • リファクタで優先すべきビジネスドメインを決める
  • これらをチーム内で合意し複数人で進める

そこで、チーム定例において課題について共有しこの取り組みに興味のあるメンバーを募集したところ、私の他に二人が参加表明してくれました。

活動の参加呼びかけ

ワークショップで課題認識を揃える

ざっくりとこのような資料を用意しワークショップを実施、具体的にどういったアクションをしていくかについて合意しました。

活動の背景と目的

最初のワークショップ

このときは前提が間違っていてもいいのでとにかくメンバー間で話をして認識を合わせることを優先しました。また、その際の叩きとして私見を含めることで、特に私が重視したいと思っている点について認識の齟齬がないかを確認できるようにしました。

齟齬があれば話し合ってより良い方向性で認識を揃えられればと思っていましたが、ここではみんな同じ課題認識としてスムーズに認識を合わせることができました。

ワークショップの結果

優先度を決めタスク化する

ワークショップにて洗い出したタスクを分類・集約し、それらの中からまず現実問題として対処可能なものを出しました。

ここでは特に以下の点に注意しました。

全員で一つの技術課題を解決すること

  • 一つの技術課題といっても多くのクラスに影響がある
  • 並列で作業を進めることが可能

先々までは決めないこと

  • 計画倒れにならないように、という面とまずはやってみようという面で
  • 進める中で手広く触ることになるため既存コードの理解が進みその中でもっと優先度を上げるべき課題があるかもしれないという思いもあった

修正が特定の範囲に留まり比較的小さい変更で済むこと

  • 修正が大きくなってしまうことでレビュー負荷が増す
  • モジュールの見直しが絡む修正はコンフリクトしやすく作業者の負荷が増すためなるべく小さい方が進めやすい
  • 早ければ数時間で終わる程度の作業であれば日々の業務の合間を縫っても進捗が出やすく停滞感を避けられる

これらを意識しコミュニケーションをしながらまず最初に取り掛かるべきタスクが決まりました。

ワークショップ後の様子

いざ改善!進捗を確認し必要に応じて話し合う

キックオフが終わり Next Action が決まったことで安心してしまいがちですがここからが本番です。ウィークリーの Slack リマインダをセットしその中で進捗報告や進める中で感じた疑問や気付きの共有、相談を行うようにしました。

リマインダーに関するやり取り

なお火曜に設定しているのは週の前半であればその週の計画に組み込みやすいこと、月曜が祝日となることが多いことが理由です。

私は特に言い出しっぺなのでなるべく進捗がゼロにならないように意識しましたが、それでも日々の業務や突発的な対応が重なったりすると進捗が出せない週がそれなりにありました。が、それも一緒に改善活動をやってくれているメンバーがなにかしら進捗を出してくれていることも多く、一人でやっているときよりも速度感を持って改善が進んでいきました。

実際の活動の様子(進捗報告)

活動を進める中で最初に立てた課題は早々に終わったため次のタスクをどうするか、また、その過程で理想系の認識合わせをするといった目的でその後も必要に応じて MTG を行い、戦略的に改善を進めていきました。

やってみてどうだったか

DI の Hilt 化は早々に終わり、その後 Repository のマルチモジュール化についても MERCH 担当ドメインについては大半を終えることができました。また、その過程でいくつかのクラスについては内部構造のリファクタも進め、密結合を解消したり iOS 側と実装を揃え認知負荷を減らしたりと修正前よりも開発時に意図せず誤った実装をしてしまうリスクを大幅に減らすことができました。

特にマルチモジュール化については Repository そのものをマルチモジュール化するために依存する全てのクラスを先に動かす必要があったため、依存の末端に位置する大半のクラスを適切なモジュールへ移すことができ、そのおかげで新たにクラスを追加する際にも本体となる app モジュールへ追加されるのを防ぎやすい構造にすることができたほか、 CI におけるビルド時間の大半を占める app モジュールから責務に応じたモジュールへクラスを移動することで多少なりともビルド速度についても改善できたのではないかと思います(ビルド速度についてはリファクタを漸次的に進めておりその間に他の機能開発も行われているため計測ができているわけではないです)。

期間としては半年弱ですが、その前の半年と比べ大幅に負債となっているコードは減っており、この活動は意味のあるものになったのではないかと思います。

私個人にとってはチームで動いていることで進捗報告が良いプレッシャーとなり、リマインダーがセットされている火曜を意識して手を動かすといった流れができて単独で進めている頃よりも進捗を出すことができました。ほか、改善活動自体が普段は触らないコードベースを触る機会になり、リファクタ後の動作検証によって当該機能そのものを理解するきっかけになり、結果的に Android の実装における新機能開発や改善、不具合対応といった様々な活動における瞬発力が上がりました。

また、 MERCH は LeSS ( Large-Scale Scrum )を採用しており 2 チームに分かれていますが、今回の活動に参加してくれたのはどちらも私とは別チームのメンバーでした。普段は一緒に開発する機会が少ないお二人と横断チームとして動くことができ、様々な知見を得るきっかけとなったためその点でも有益な活動でした。

一緒に活動いただいたお二人にはリファクタ作業に留まらず突発的にモブプロを開催していただいたりこの活動における課題感に対し MTG を設定していただいたりと活動をより良くするためにも色々と動いていただきとても感謝しています。

まとめ

この記事ではみてねの MERCH チームで行った Android の改善活動について紹介しました。

技術的な負債はどのようなプロダクトについても大なり小なりあるかとは思いますが、技術課題がビジネス上における喫緊の課題となる前にエンジニアが率先して手を打つことができ、同じ課題意識を持った仲間と一緒に解決できるような環境は必ずしも整っているとは限りません。

みてねでは 20% ルールとして自身が注力したい活動へ取り組める仕組みがあり、また、チームで物事を解決することに前向きなメンバーが揃っています。ぜひこの記事をきっかけにみてねのプロダクト開発に興味を持っていただけたら嬉しいです。

この記事が読者の方ご自身が所属するチームで技術負債をどのように解消するかを考える際の参考になりましたら幸いです。

脚注
  1. 書いていて気になったので ChatGPT に聞いてみたら 53 万もあると体重 60kg の場合に(体重とは別に) 1 分間で 45kg の酸素を取り込むことができるようですが、「そうなると肺・血液・ミトコンドリアすべてが即崩壊レベル」だそうです。即崩壊ってどうなっちゃうんだ。大変。 ↩︎

  2. Merchandising 領域を担当しているためその先頭5文字を取り MERCH です。全て大文字なのはその方が強そうだからだそうです。 ↩︎

  3. ただし SRE や CRE 、 DE のようにドメイン横断の職能単位チームもあり、それらのチームはこの限りではありません。 ↩︎

  4. Epoxy が使われていることで Kotlin を 2.1 へ上げる際のブロッカーになっていました。詳しくは chigichan24 さんのこちらの記事をご覧ください。
    https://zenn.dev/mitene/articles/2a977202c7c3f2 ↩︎

  5. 他のメンバーが改善に動けていないかというとそういうわけではなく、一部のメンバーは改善に取り組んでいましたが、日々のコードベースの修正量と比較し改善の規模が小さいこと、 iOS / Ruby on Rails といった他のリポジトリにおける課題もありそちらでも様々な技術的課題への対処や改善活動を行っているため Android にあまりリソースを割くことができていないといった状況でした。 ↩︎

みてね Tech Blog
みてね Tech Blog

Discussion