コード清掃の技術
これまで、コードを「書く」ことに光を当てた記事は数多くありました。
しかし、コードを「消す」ことに焦点を当てた記事はあまり無かったような気がします。
そこで今回は、これまで数多のコードを消してきた私が、コードを「消す」際に考えていることをまとめます。
主に初心者向けの内容にはなりますが、少しでも業務でコードを消す際の参考になれば幸いです。
コードを消す場面について
業務の中でコードを消す場面は数多くあります。
例えば、以下のような状況です。
- アプリケーション自体を閉鎖する
- アプリケーションの一部の機能を削除する
- 不要になったロジックを削除する
不要になった変数やコメントの削除まで含めたら、多くの方が「コードを消す」行為を経験しているのではないでしょうか?
なぜコードを消す必要があるのか
では、なぜコードを消す必要があるのでしょうか?
それは、不要なコードがあると、アプリケーションの仕様の把握や変更にかかる時間が増加し、ビジネスのアイデアを反映するスピードが低下してしまうからです。
要は、こういう流れです。
一度このような負のスパイラルに陥って「硬直化」してしまったアプリケーションを復活させるのは至難の業です。
一つの機能を消すには、以下のように多くの労力が必要となります。
- アクセスログなどから使っているか使っていないかの調査をする
- ステークホルダーに消しても問題ないか確認する
- コードを消す際の影響範囲を調査する
- コードを消す
- 消した後に動作テストをする
- リリースをする
普段の業務の中で、このような「ビジネス上の分かりやすい付加価値のない作業」に時間を割く機会はほとんど訪れません。
その結果、アプリケーションは漸進的に硬直化し、誰も触れない(触りたくない)腫れ物アプリと化していくのです。
コードを消す際に意識すべきこと
では、どのようにコードを消していけばいいのでしょうか?
私が実際にコードを消す際に意識していることは以下の二つです。
- スコープを意識してコードを消す
- 徹底的に消す
スコープを意識してコードを消す
コードを消す際には、必ずスコープを意識します。
スコープを意識することで、「消す範囲」が明確になるからです。
例えば、privateメソッドを消す場合は、そのクラス内で使われている箇所のみを調べたらいいです。
一方、publicメソッドの場合は、ソースコード全体まで調査範囲を広げる必要があります。
消す際の漏れを無くすためにも、今消しているもののスコープはどこかは常に意識しながら、一つ一つコードを消すようにしましょう。
徹底的に消す
一度コードを消すと決めたら、徹底的に消すようにします。
中途半端に残すようなことはしません。
なぜなら、中途半端に残してしまうと、将来そのコードに触れる人がそのコードをどう扱えばいいか分からず、改修の速度が低下してしまうからです。
中には「このコードを消すと影響が怖いな..」と思うコードやパッケージもあるでしょう。
それも、(影響範囲をしっかりと調べた上で)全て消すようにします。
では、どうすればコードを全て漏れなく消せるのでしょうか?
私が実践しているのは、依存先から依存元に遡りながら消す方法です。
例えば、あるAPIを消す役割を与えられたとします。
そのとき、まずは実際にAPIを叩いている箇所(依存関係の末端)を探します。
その処理を行っているメソッドがfind
メソッドだとします。
次に、そのfind
メソッドを使っている箇所を検索して探します。
これを使っているのが、getData1
メソッドとgetData2
メソッドだとします。
そこで次は、これらを使っている箇所を探して消していきます。
このように、依存先から依存元へと遡りながら消していくことで、多くの場合は漏れなくコードを消すことができます。
あとは、これらのメソッドや処理の中で使われている変数やパッケージ、コードコメントなども忘れずに消すようにしましょう。
変数やコメントなどを消すときのコツは、複数のフォーマットで検索することです。
例えば、SampleAPI
というAPIを叩く処理を消す対応を任されたとします。
このとき、以下のように様々なフォーマットで検索します。
- sample-api
- sample_api
- sampleApi
一つのアプリケーション内部でも複数のフォーマットが使われているのはよくあることなので、この点は意識しておくと、消し忘れの確率を下げることができるでしょう。
消しやすいコードを書く
コードを迷いなく消すためには、そもそも消しやすいコードを書くことも大切です。
個人的にコードを消しやすくするために重要だと考えていることは以下の4つです。
- 疎結合・高凝集なコードを書く
- DRYなコードを書く
- ユニットテストを書く
- ボトムアップ式でコードを書く
疎結合・高凝集なコードを書く
プログラミングをする上でよく聞く原則ではありますが、疎結合・高凝集はコードを消す上でも非常に重要です。
なぜなら、疎結合・高凝集であるほど、コードを消した際の影響範囲が把握しやすくなるからです。
影響範囲が明確なコードは、コードを消す際の「怖さ」が低減するので、消す際の心理的負担も低くなります。
疎結合・高凝集を実現する上では、様々なテクニックが提唱されています。
Colocationというモジュールやデータをなるべく近くに配置する設計思想や、インターフェースを利用する方法など様々です。
この記事では詳細な解説はしませんが、以下の記事はとても分かりやすく疎結合・高凝集についてまとめられているのでおすすめです。
DRYなコードを書く
同じようなメソッドや処理が大量にあれば、その分実装を消す際の影響範囲の特定やテストにかかるコストは上がってしまいます。
そのため、なるべくDRY(Don't repeat yourself)に書く意識も持っておくと良いでしょう。
とはいえ、何でもかんでもDRYにしていいわけではありません。
例えば、テストなどは、過度にDRYにし過ぎると可読性が悪化してドキュメントとしての価値が下がってしまうのでDRYにし過ぎない方が良いという意見もあります。
何も考えずに共通化するのではなく、「共通化したら将来困りそうか」を一考した上で共通化するようにしましょう。
ユニットテストを書く
テストはソフトウェアを変更する恐怖心を下げてくれる薬のようなものです。
しっかりと既存の動作を担保するテストが書かれていれば、その分コードを消したり変更したりする際の心理的負荷は下がります。
そのため、普段からしっかりとユニットテストを書く習慣は付けておきましょう。
また、コードを消す際に対象のコードのユニットテストが書かれていない場合は、なるべく既存の動作を担保するユニットテストを書いた上でコードを消すのがよいでしょう。
ボトムアップ式でコードを書く
ボトムアップ式、つまり「必要なコードやパッケージのみを積み上げる」方式でコードを書くのも、将来的に消しやすいコードを書く上ではとても重要です。
よくあるのが、「おそらく不要だけど一応この処理(パッケージ)を入れておこう..」という考え方です。
確かに、これでもアプリケーションは「動く」と思います。
しかし、実装時点で必要かよく分からないものを、将来見た人が必要かどうか判断できるはずがありません。
必要かどうか分からないものは怖くて消せないので、そのコード(パッケージ)は負債として永遠に残り続けます。
そのため、基本的には必要なときに最小限必要なコードを導入して、少しでも必要かどうか迷うものは入れないようにしましょう。
そうすることで、最終的には「アプリケーションを動作する上で最小限必要なもの」の集合体としてのアプリケーションが出来上がります。
そもそもコードを書かない
ここまで、「コードの消し方」「消しやすいコードの書き方」について書いてきました。
しかし、当たり前の話として、そもそもコードを書かなければコードを消す必要もありません。
そのため、新たに実装を依頼された場合は、そもそもそれは実装する必要があるのか?他の手段で代替できないかを考えるようにしましょう。
また、どうしてもコードを書く必要がある場合も、「よりシンプルなアーキテクチャにできないか」「もっと少ないコード量で済まないか」は常に考えながら実装するとよいでしょう。
コードは書いた時点で管理コストが発生する負債となります。
負債はなるべく減らす努力をし続けることが大事です。
ソフトウェアをちゃんと"ソフト"ウェアにしよう
ソフトウェアは、その名の通り、ソフト
つまり必要に応じて形を柔軟に変えることができるのが最大の強みです。
しかし、不要なコードが大量に混ざっていて変更が難しくなったソフトウェアは、次第にハードウェア
へと変貌していきます。
ハードウェア
になってしまったソフトウェアは誰にも改修ができなくなり、ビジネス上の競争力を失います。
最終的に待ち受ける結末は、サービスの終了か、大きな時間的・経済的な痛みを伴うリプレイスでしょう。
そのような結末を迎えないためにも、日頃から不要なものは書かない・削除するメンテナンスを繰り返して、ソフトウェアを柔軟に保ち続けることが大切です。
まとめ
- 不要な機能が発生したらすぐに消そう
- 消しやすいコードを書こう
- そもそもコードを書かないで済まないかを考えよう
Discussion