2024.10.01
自社の社内情報を未来の“ゴミ”にしないための備え 「情報量が多すぎる」時代がもたらす課題とは?
レガシーな実装を丁寧にリファクタしモダンな実装にする技術(全1記事)
提供:株式会社ディー・エヌ・エー
リンクをコピー
記事をブックマーク
手塚悠太氏:それでは、「レガシーな実装を丁寧にリファクタしてモダンな実装にする技術」について、手塚悠太が発表いたします。
自己紹介です。2019年にDeNAに中途入社し、当時はMOV、現在の名前はGOですね、こちらのタクシーアプリの乗務員さん向けアプリケーションを開発していました。またタクシーフードデリバリーサービス「GO Dine」のアプリケーション開発も担当をしていました。こちらのGO Dineは、Flutterを用いています。
その後、2021年8月から『グランブルーファンタジー』推奨ブラウザである「SkyLeap for Android」の開発に携わっています。
さてみなさん、リファクタリングはできていますか? 「機能開発や不具合修正がずっと続いてそんな暇がない」「プロダクトオーナーの理解が得られない」「リファクタリングで新たに不具合を出すのが怖い」などと思っていませんか?
本日はSkyLeapで実践した内容をもとに、レガシーな実装をモダンな実装にリファクタリングする技術をお伝えいたします。
本セッションの構成です。まず簡単にSkyLeapを紹介しまして、その後SkyLeapが抱えていた課題を紹介します。そしてリファクタリングを進めていくための必要な下準備。その後、実際にリファクタリングをしてSkyLeapはどのようになったのか。最後に、丁寧にリファクタリングをするためのTipsをお伝えします。
『グランブルーファンタジー』推奨ブラウザであるSkyLeapは、『グランブルーファンタジー』を快適に遊べるブラウザで、2019年8月3日にリリースされています。『グランブルーファンタジー』のゲームシステムに合わせて、任意のクエストにすぐアクセスできる「クイックアクセス」や、バトルをしながら編成を試行錯誤できる「2画面分割機能」などを提供しています。
このSkyLeapですが、課題を抱えていました。先ほど、リリースが2019年8月3日と紹介しました。実はこのアプリ、リポジトリが作られたのは2019年6月7日で、なんとリポジトリが作られてから2ヶ月もしないうちに正式リリースされました。
超特急でリリースされたのである程度仕方ない面はあるのですが、やはり技術的負債も多く残っていました。例えばUIスレッドでアクセスされるファイルやデータベース、バイナリデータのパース処理なんかも、UIスレッドで行われていました。
モバイルアプリでは、UIスレッドをブロックしてしまうと画面がフリーズするような動きになってしまうため、UXを大きく損なってしまいます。また、SkyLeapはJavaで開発が開始されており、Kotlin化も道半ばの状態でした。
そのほか、独自のDI処理とJavaとKotlinの混在などで、あちこちで強制アンラップがされていてNull-Unsafetyな状態、またRxにも問題が散見されている状態でした。
これらの技術的負債を解消するにも、まずはKotlinがほしいという結論になりました。当時のSkyLeap開発メンバーはJavaを主力としており、また当時利用を想定していたJavaライブラリとKotlinの互換性を検証する時間もなかった関係で、2019年でもフルJavaで開発されていました。
私がjoinした時点ですでに5割ほどはKotlin化されていましたが、やはり影響範囲が広いところや影響した時のインパクトが大きい部分に関しては、ずっと残り続けていました。どうせ各所リファクタリングするのであればCoroutineやFlowも使いたいので、まずはすべてKotlin化をするという方針になりました。
リファクタリングは、下準備がすべてと言っても過言ではありません。ここからはリファクタリングをするための下準備について紹介します。
まずは自分自身のプロジェクトを知りましょう。リファクタリングは、時に大きな範囲に影響を与えることがあります。万が一、不具合を引き起こした場合の影響範囲やプロジェクトのリスク許容度を評価します。例えば医療向けソフトウェアなど、プロジェクトによっては人や動物の生命、健康を直接害してしまう可能性があります。
また、金融系ソフトウェアでは他者の財産に大きく影響させてしまう可能性なども考えられます。このような場合は、リスク許容度は低いということになり、慎重にリファクタリングを進める必要が出てくるでしょう。
さらに、将来的な機能追加や売上の拡大などの見込みがなければ、リスクを取ってリファクタリングをする必要はないと判断されることも、時にはあるでしょう。
チームメンバーとの認識がそろっているかも重要です。リファクタリングの重要性の共通認識を作りましょう。
当事者だけ重要性を理解していても、プロダクトオーナーの理解を得られなければ、進めることはできません。SkyLeapには共通認識がありましたが、これがない場合は、まずはその共通認識を作る必要があります。
リファクタリングが必要なコードに目を瞑っていると、いずれ開発速度の低下、プロダクト品質の低下、プロダクトの寿命の低下、属人化の加速などがある、とよく言われます。しかしまれに見落とされるのが、リファクタリングを実施しないで開発がだんだん辛くなってくると、エンジニアの退職リスクが高まるということです。
実際にエンジニアがプロジェクトから離脱するところまで進んでしまうと、負のスパイラルとなって後戻りできなくなってしまいます。リファクタリングの必要性を感じている場合は、チームで議論を進めて共通認識を作るようにしましょう。
リファクタリングがなんとなく不安なのは、リファクタリングの前後で品質の担保に自信がないからと言えます。リファクタリング対象のテストコードがない場合やテストケースが不足している場合は、リファクタリング前に用意し、リファクタリング前後の品質を担保します。リファクタリングに入る前に、テストコードの充実を図っておくのもいいでしょう。
またリファクタリングの対象は、できるだけ細かくチケットを切って管理します。チケットには、そのチケットでやることとクローズできる条件を具体的に記載します。
例えばExampleRepositoryをKotlin化するというチケットであれば、やることにExampleRepositoryのテストコードを書く、必要なテストケースがなければそれも書く、IDEで自動変換をする、自動変換されたコードを最適化する、テストコードがPassすることを確認すると書き、その上で完了の条件としてやることがすべてできていることpull requestがマージされていることといった具体的な内容を記載するようにします。
こうすることで、チケットを開いたあとに「結局このチケットは何をすればいいんだっけ?」というオーバーヘッドを限りなく減らします。
これで下準備は完了です。最後にプランニングを行って、リファクタリングを実施しましょう。影響範囲が小さいものに関しては、スプリントに乗せて順次実行してもよいでしょう。
影響範囲が大きいものは、できるだけほかの作業を止めておきたいところです。ほかの大きな修正と大きなリファクタリングがコンフリクトしてしまうと、そのコンフリクトの解消ですら、不具合を呼んでしまう可能性があります。
そして、リファクタリングを実施したあとのQA計画やリリース計画も、このタイミングで行います。
さて、そんなSkyLeapがリファクタリングされてモダンに生まれ変わった結果を見ていきましょう。生まれ変わったと言いましたが、言い過ぎました。まだまだ直したいところは山ほどあるので、生まれ変わりつつある姿を見ていきます。
まずKotlin化に関しては、100パーセント完遂できています。SkyLeapでは、2020年の初頭でKotlin化するという決意のチケットが切られていました。実際に動きがあったのは2020年下期からで、2021年の下期に向けて主に独立したクラスなど、影響範囲が比較的小さい部分、もしくは限定的な部分に関して、機能開発と同時並行でKotlin化が行われていました。
そして今年度上期には機能開発をほぼほぼ止めて、ActivityやViewModelといったUIレイヤーや、それに密結合したテストが書きにくいクラスたちを一気に進めています。最終的には、このぐらいの差分量となりました。
Kotlin化以外では、主に現代のAndroidアプリケーション開発におけるデファクトスタンダードを採り入れていくように、リファクタリングを行っています。DIを独自で実装されていたものからDagger Hiltを導入したり、RepositoryやViewModelをCoroutineやFlowを使う構成に変更したり、UiStateを導入したり、Google Guavaを除去したり、Ktlintでフォーマットを保つなどを行なっています。
リポジトリなどはまだまだ改善の余地はありますし、そのうちUIに関してはJetpack Compose化もしていきたいという気持ちもいっぱいなので、まだまだリファクタリングは続いていきそうです。
さて最後になりましたが、丁寧にリファクタリングをするためのTipsをお伝えします。リファクタリングは、できるだけ影響を小さく抑えて行います。SampleRepositoryをリファクタリングするというこの例ですが、SampleRepository2つのメソッドのうち、1つだけをリファクタリングする例となります。
SampleRepositoryはインターフェイス化を行なって、古い実装はImpl、新しい実装をImpl2として作っています。インターフェイス化は必須ではありませんが、DIをしている場合は切っておくと差し替えるだけで済むので、よりやりやすくなると思います。
新しい実装のほうは古い実装に依存し、リファクタリングをするメソッドのみ実装を行います。それ以外の実装は、古い実装をそのまま呼び出します。こうすることで、影響範囲をリファクタリングしたメソッドのみに限定できます。
Kotlinのようにclass delegationのような機能がある場合は、そちらを用いてもよりシンプルになっていいと思います。
こちらは、t_wadaさんのツイートの引用です。これまでも何度かお伝えしていますが、t_wadaさんのツイートにあるように、影響範囲の小さいリファクタリングというものは定常作業に組み込んで絶え間なく実施していくといいでしょう。
SkyLeapは、2週間のスプリントでスクラムを組んでいます。スプリントレビューとレトロスペクティブの翌日の1日を改善の日に割り当てており、そこで細かなリファクタリングや改善を行う日として、スプリントの中に予約を行っています。また、必要に応じてスプリントの中に組み込んでしまうこともあります。
古い実装のAPIを削除できない場合は、@Deprecatedを付けて、今後呼び出されないようにしましょう。KotlinのDeprecatedアノテーションは高機能なので、任意のメッセージを設定するだけでなく、IDEの自動置き換えの機能で新しい実装に置き換えを行うように指示できます。
またDeprecationLevelの設定も可能で、単純に警告を出す状態のほかコンパイルエラーにさせたり古い実装をコード補完機能の対象から隠したりできます。どのやり方でもかまいませんが、今後新しい実装に気づかずに古い実装を使ってしまった、ということがないようにしましょう。
最後に、リファクタリングをする時は、目の前のリファクタリングに集中するようにしましょう。コードを直していると、周辺の実装も気になってきて「あっちもこっちも直したい」と思うようになります。
しかし範囲を広げてしまうと、影響範囲も無限に広がってしまいますし、時間も無限に足りなくなります。グッと我慢してチケット化だけを行って、機をうかがいましょう。SkyLeapでも、Kotlin化のほかにもっとリファクタリングしたい部分がまだまだたくさんあります。優先順序を見失わず、改めて計画を立てて実施するようにしましょう。ここまで来れば、リファクタリングを計画的に効率よく実施できる下地が作られているはずです。
以上で発表を終わります。ご清聴ありがとうございました。
株式会社ディー・エヌ・エー
関連タグ:
2024.10.29
5〜10万円の低単価案件の受注をやめたら労働生産性が劇的に向上 相見積もり案件には提案書を出さないことで見えた“意外な効果”
2024.10.24
パワポ資料の「手戻り」が多すぎる問題の解消法 資料作成のプロが語る、修正の無限ループから抜け出す4つのコツ
2024.10.28
スキル重視の採用を続けた結果、早期離職が増え社員が1人に… 下半期の退職者ゼロを達成した「関係の質」向上の取り組み
2024.10.22
気づかぬうちに評価を下げる「ダメな口癖」3選 デキる人はやっている、上司の指摘に対する上手な返し方
2024.10.24
リスクを取らない人が多い日本は、むしろ稼ぐチャンス? 日本のGDP4位転落の今、個人に必要なマインドとは
2024.10.23
「初任給40万円時代」が、比較的早いうちにやってくる? これから淘汰される会社・生き残る会社の分かれ目
2024.10.23
「どうしてもあなたから買いたい」と言われる営業になるには 『無敗営業』著者が教える、納得感を高める商談の進め方
2024.10.28
“力を抜くこと”がリーダーにとって重要な理由 「人間の達人」タモリさんから学んだ自然体の大切さ
2024.10.29
「テスラの何がすごいのか」がわからない学生たち 起業率2年連続日本一の大学で「Appleのフレームワーク」を教えるわけ
2024.10.30
職場にいる「困った部下」への対処法 上司・部下間で生まれる“常識のズレ”を解消するには