新人こそリファクタリングをやれ! ~マイクロサービスの最古のサービスをリファクタリングした話 ~

Ryusei Ikezawa
FiNC Tech Blog
Published in
Dec 28, 2021

こんにちは。FiNC Technologies(以下、FiNC)の サーバーサイドエンジニアをしている Ryusei (@ryusei_i_1025)です。

僕はエンジニア1年目なのですが、FiNCのマイクロサービスの最古の巨大サービスのリファクタリングをしてきました。
その内容と学びを一部ご紹介します。

FiNCでは、マイクロサービスを採用しています。
それぞれのチームがサービスのオーナーとなって、担当サービスをプロダクションレディとなるように管理しています。
大抵、マイクロサービスの中には、巨大な神サービスが存在すると思いますが、
僕が所属するチームは、2021年4月にこの最古の巨大サービスの担当になりました。

このサービスは、FiNCの歴史を物語っています。2013年に作られてから、現在までFiNCの中枢機能として、ビジネスを支えてきたサービスです。
現CEOの 南野 (@tentenmitsunori)、CTOの篠塚 (@shinofumijp)、VPoEの鈴木 (@kenjiszk) がコミットしてきた履歴があります。
会社の規模に合わせて、このサービスは大きくなっていく一方で、使われないコードや負債となってしまった部分もあります。
この巨大サービスをリファクタリングするプロジェクトがスタートしました。

プロジェクトが始まった経緯

2021年3月に、「あるAPIのパフォーマンスが悪いので直そう」という提言がSREチームからありました。
そのAPIでは、一般ユーザーには不要な、他のマイクロサービスへ毎回問い合わせているなどの問題が表面化しました。
また使われていないAPIが無数にあること、過去の知識が失われて、使われているのかどうかわからないコードをリファクタリングしていくプロジェクトが発足しました。

第1回目のコードリーティングの議事録

4月から週次で時間を取って、アプリケーションチームとSREチームでコードリーディングを始めました。
まずは、重要と思われるファイルを1つずつ読み、コード上にコメントを残したり、デッドコードを消したりしました。

プロジェクトで行ったこと

リファクタリングは、僕の先輩であるアプリケーションチームのリーダー主導で進んでいきました。その中で行ってきたことをいくつかご紹介します。

コメントを追加しながらコードリーディング

認証周りなど複雑な処理を行なっているメソッドで、毎回処理を読まなくてもわかるように具体的にコメントを入れていきました。
すぐにリファクタリングできるものは、その場で書き直しますが、影響範囲の大きいものやリファクタリング方針がすぐに決まらないものは一旦コメントを入れたりしました。

コードリーディングはペアプロ的に行うことが多く、情報を全員で出しながら進めていきました。

既存コードの可読性をあげる

PRのdescription

例えば、各APIクライアントのclassに散らばっていた依存先のendpointのパスを1つのmoduleにまとめることで、依存関係を可視化しました。
1箇所にまとめ、サービスへの依存関係が明確になり、その後、削除できる依存先がわかるようになりました。

過去に使われていた実装を消す

バージョニングされているAPIの削除
controllerの削除に伴ったserviceクラスなどの削除

すでに止まっているビジネスで使用していたAPI、バージョンを切っていたなど確実に使われていないAPIを削除しました。
PR2つで、消えた行数は、46,178行でした。
使われていないコードを消すことで、controller周辺のコードがかなり見通しがよくなりました。

APMを見てAPIを消す

DatadogのAPMを見て、直近1ヶ月でリクエストがほとんどないAPIを探し、関連ファイルを削除していきました。
基本的に「叩かれていないAPI = 使われていないAPI」と判断して良いのですが、中には、数ヶ月1回叩かれることがあり、実は残すべきAPIがあったりします。
実際に、productionへリリースする前に関係者に報告やヒアリングをしたり、staging環境でしばらくエラーが起きないか確認しておくことが重要でした。

unicorn から puma へ

このサービスはRailsを採用していて、元々unicornで動いていました。
以前から社内ではこのサービスのpumaへの移行の検討を行ってきましたが、実施はされていませんでした。
スレッドセーフや、タイムアウトなど1つずつ懸念を潰して、移行しました。

移行に伴うリファクタリングのPR

定期実行されているジョブの整理

定期実行のジョブは、消し忘れが多く、不要なものが残っていました。
それらのジョブを消すことで、依存サービスの通信が減らすことができました。
また、マシンリソースの消費を減らすことができました。

得られた効果

消せたコード行数

結果として、12月時点で、1,800以上のファイルを削除、87,000以上の行を削除しました。
不要なディレクトリやコードが消えて、全体的に見通しが良くなりました。

Docker イメージの変化

Dockerfileを書き直し、ずっと手を入れていなかったDockerのイメージを改善しました。
最終的に、脆弱性の指摘の数が 3重要 + 749 その他 から 3 に減りました。
また、サイズが774MBから520MBに減少しました。

マシンリソースの変化

レイテンシの変化
使用メモリの変化

このモノリスサービスに依存している周辺サービスの整理も行うことで、マシンリソース消費が減りました。

リファクタリングは 「No pain No gain」だと思います。
過去1ヶ月、使われていないAPIやジョブでも、数ヶ月に1度実行されることがあります。ただし、それを考慮しすぎると、消せるコードが少なくなってしまいます。
悲鳴が上がっても、少しは許容してもらえるようなハンドリングや調整、理解を得られるとリファクタリングプロジェクトは進めやすいのかなと思います。

新人こそリファクタリングをやれ!

「新人エンジニアこそリファクタリングはやっていこう」というのが僕の意見です。

コードリーディングのメリット

歴史のあるサービスのコードリーディングでは良くも悪くも見本になります。
今よりもアーキテクチャが古かったり、コーディング規則が強くない場合もあるので、アンチパターンを確認することができたり、一方で、今後にも参考になるお手本のようなコードもあります。
さまざまなパターンを学ぶことができました。

PRのdescriptionの重要性がわかる

コードを読んでいると、実装の意図が不明なコードもあります。
コミットを辿り、Pull Requestを見ると、No description だったりします。
Pull Requestが作成された時点では、作成の文脈や合意がチーム内で取れていたりするので、descriptionを書かない選択もあったかと思います。
ただし、将来読んだ人にはその文脈や合意はわからないので、冗長なくらい書くことの重要性を肌で感じました。

Datadogなどのモニタリングツールに慣れる

リファクタリングにおいて、APMやslow queryを見ることになるので、Datadogなどのモニタリングツールの使用は避けられないです。
普段、機能開発をするだけでは監視ツールに触れることが少なかったのですが、リファクタリングプロジェクトを通して、ツールに慣れることができました。

ステークホルダーを見つける

モノリスサービスなので、関係するサービスが多かったです。
エンジニア、ビジネスどちらも必然的に関係者が増えます。
そのサービスに関連する箇所を変更していく過程で、誰が何に詳しいのか、どこに知見や経緯がまとまっているかがある程度わかるようになります。
その結果、その後の業務がしやすくなることもあると思います。

失敗してもちょっとは許してくれるはず!

どうしてもリファクタリング、負債の解消は効果が見えづらいため、実行の優先度が下がってしまうこともあります。
重要性についての合意が取れているなら、リファクタリングにチャレンジしていくべきです。
リファクタリングで少しくらい失敗しても、その姿勢は評価してくれると思います。リスクは抑えつつ、どんどんチャレンジしていくべきだと思います!

まとめ

今回は新米エンジニアがリファクタリングプロジェクトで行ってきたことをご紹介しました。
リファクタリングで負債を解消するというメリットだけでなく、成長や新たな発見ができるといったメリットはあると思います。
これからもリファクタリングを続けて、より管理しやすいサービスにしていきます。
また横展開を行い、知見を他サービスに応用していきます。
新人エンジニアはどんどんチャレンジしていきましょう!

--

--