「プロダクトコード探索&改修」入門

この記事は、「株式会社エス・エム・エス Advent Calendar 2023」7日目の記事です。

qiita.com


Webサービスが長期間運営されると、成長に伴い複雑なプロダクトコードが蓄積されます。このような長寿サービスは多くの人が関わってきたということでもあり、様々な思いや依頼のもとにプロダクトコードが少しずつ変わってきています。そんな長いサービスに対して手を加えるとき、関わってきたすべての人たちがコミュニケーションできる範囲内にいるとは限りません。そのため、いまあるプロダクトコードから当時の意図を汲み取り、手を加えるという場面は多く存在すると思います。

これらの場面に直面する話は多くあれど、実際にどのように読み進めていくかというのはあまり多くは語られていないと思っています。そこで今回は「過去携わった人が近くにおらず、GitHub上でバージョン管理されたコードを読み解きながら改修をする」というようなシチュエーションを想定して探り方と直し方のアプローチ例をご紹介できればと思います。

どのようにアプローチするか

今回は、以下のような改修の依頼を題材に、大きく3つのステップに分けて取り組み方の例をご紹介していきます。

『TOPページのリストアイテムの並べ順を更新日時が「更新日:2022-11-20」の形式になっているので、その値をもとに日付の降順に並べ替えてほしい』

1.変更箇所にあたりをつける

まずは改修する機能とソースコードの位置に関してあたりをつけます。これは改修依頼の内容によってアプローチは変わりますが、一番直感的な追い方は「改修箇所のユニークな部分から特定する」というやり方がよいと思います。

たとえば今回ののような改修の話であれば、"更新日:"という文字列を手がかりに探すということができます。もちろん扱っているフレームワークの構造などから「TOPページ」というところを手がかりに探すこともできるので、自身の持ち合わせている知識や利用しているフレームワークの特性を活かしてで特定していくのがよいと思います。

変更する場所がわかったら次は歴史を追っていく作業です。

2.GitHubのblameとhistoryの機能を利用して「何故行われたのか」を追う

ソースコードを改修するときに「なぜ今の形になっているのか」というのを確認する作業が必要な場合が多いです。その時に役に立つのがblameです。blameは直訳すると「非難」という意味なので物騒な言葉ではあるのですが、GitHubでソースコードを探すときには大変有効に利用できます。

GitHubのblameの機能を利用すると、行単位に「いつ」「誰が」「どのコミットで」変更してくれたのかを可視化してくれます。

この機能を使うことにより、目星をつけた改修箇所のコミットを確認できるので差分を確認することができます。また、コミットがわかるので、コミットに紐づくPullRequestも確認することができます。PullRequestを見ることができればdescriptionを読むことができるので、そこから新しい情報を入手することができます。文章そのものも有益な情報ですが、JIRAやbacklogなどの別サイトで管理されている依頼情報を追うこともできたりするので、当時の背景理解を助けてくれます。

またhistoryの機能を使うとそのファイルが過去に行われてきた変更を確認することができます。commitによってはrevertしているなどで直前のコミットだけでは変更の真意まで読み解けないときがあるので、そのようなときにhistoryを使って過去のコミットを順を追っていくことで得られる知見もあります。

この過去の内容を追うときに念頭においたほうがいいのは「該当箇所にどんな変更があり、何故その変更が行われたか」です。例えば最初に挙げたリストアイテムの表示順を並べ替えたいという話であれば、何故最初に昇順で実装されていたのか、その後変更がされた形跡があるかというのは一度調べておくといいかと思います。これを調べることにより現在の担当者が知らなかった背景が見つかったりする場合もありますし、逆に当時何も考えて作られていないことがわかれば修正してしまってもなんの問題もないという裏付け材料になるので、調べておくことのメリットは大きいです。

3.前後比較ができる状態で改修をかける

変更箇所がわかり、修正する内容に関しても憂いがないことがわかったらあとは直すだけです。ただ直す際に気をつけなければいけないのは「関係ないところを変更してしまわない」ということです。

例えば今回の改修依頼の例でいくと、並び順は降順になったが、リスト表示するアイテムがおかしくなってしまう、などの事象が起きてはいけないので、その点に関して修正前後で問題がないかというところを確認する作業が必要です。

修正する箇所にテストコードがあり、修正した箇所以外に変更が加わっていないかということが検証できるのが一番良いのですが、歴史の長いコードベースの場合はちゃんとテストコードが用意されていないこともあります。そのため、予め「修正前後を確認できる方法」を用意しておいたほうがいいと思います。

修正前後を確認できる方法というのは、テストコードを書き足すということでも実現できます。もともの改修前の箇所に関してテストコードを書き足し、その後改修とワンセットでテストコードも書き換えるというやりかたです。こうすることにより元の仕様の理解も深まり、また未来コミットログを見た人がどういう振る舞い変化を期待して直したかというのもわかりやすくなります。

ただ、テストコードが継ぎ足すのが構造上難しい箇所もあると思います。その場合は一般的にマニュアルテストと呼ばれているようなテストケースを文章で書き起こし、それを実施するというのも方法の一つだと思います。その場合はPullRequestのdescriptionに行ったテストケースに関する情報があれば、未来の人に何をしたかを残すこともできます。

ここで大事なのは「修正したい場所と修正する場所に近いところがちゃんと壊れていないかを確認する工程を踏む」ということを意識づけてやるところなので、テストコードでもマニュアルテストでも確認作業を踏む、踏んだ足跡を残せるとよいかと思います。

過去を探ることで、足場を固めて改修する

歴史のあるプロダクトコードはビジネスの成長に合わせて無理をしていることもあります。そのようなプロダクトコードに手を入れるときに当時の背景を理解するということは改修の手助けになることがあります。過去を知るチームメンバーに色々と話を聞けるとよいのですが、もしそのようなメンバーがいない場合、GitHubでソースコードを使うことで断片的にでも情報を探ることができます。

また断片的に得られた情報から改修を行う際は、テストコードなどで足場を固めて改修をしていくとバグを生み出す確率を減らすことができます。下記のPullRequestでは今回のアプローチで紹介していたような探りを入れ、そこに対し既存実装にあわせたテストコード(RSpec)を追加、そのRSpecを元に既存実装から改修実装に切り替え、最終的に影響が他に伝搬してないかを確かめつつ改修しています。かなり複雑な箇所の改修でしたが、大きな不具合を出すことなく改修ができました。

これらのアプローチを無意識にやっている方が多い部分もあるとは思いますが、もしこの記事で少しでも学びや再発見があれば幸いです。


こちらの文章は直近入社エントリを書いた高田の提供でお送りしました、明日のアドベントカレンダーもお楽しみに!