🔧

リファクタリングを定着させる方法

2023/11/22に公開

基本方針

リファクタリングそのものをゴールにしない

リファクタリングは外部から見た振る舞いはそのままに、コードの構成や構造のみを変更することを指します。つまり、リファクタリングそれ自体はプロダクトの利用者に価値をもたらしません。

なので「リファクタリングする」を目標地点に設定するのはよいアプローチではありません。

リファクタリングの後に書かれるコード、それによってもたらされる価値こそが評価されるべき対象です。

リファクタリングそのものは直接的な価値を生まないので、それ自体を評価対象と考えるのは筋が良いとは言い難いです。「1ヶ月かけてコードをきれいにしました」と言われても評価する側はどう評価していいのか分かりません。

そもそもリファクタリングすれば必ずよいコードになるわけではありません。書き換えたコードが次の開発に効果的であるかどうかもリファクタリングした時点では判断できないので、やはりその先を見据えるのが肝要です。

許可を求めない

対象となるコードベースに一番詳しいのは誰か。実際にコードを書く人間です。それは(多くの場合)これを読んでいるあなた自身です。

そのあなたがリファクタリングが必要だと判断したのならやればいい。許可を得る必要はありません。要不要の判断を「偉い人」に預けるのではなく、プロフェッショナルとして自身で判断しましょう。

どちらかと言うと「リファクタリングするので許可をください」と許可を求められた側が困ります。前述の通りリファクタリングそのものは直接的な価値を生まないので、それ単体で許可するとも何とも言いづらいものです。

長い時間をかけない

リファクタリングはプロダクトが生み出す価値を最大化する、あるいは価値を生み出す阻害要因を取り除くためにやるものです。そのリファクタリングのために日々の価値提供を止めてはいけません。

両者を完全に同時にやる必要はありません。外部から観測した時にプロダクトの前進が止まって見えなければよいのです。それには小さなリファクタリングを機能開発の合間に日常的に実施して、速いサイクルを回すことです。

一度のリファクタリングで周囲が不安を覚えるような時間をかけてはいけません。リファクタリングに許可が必要になるのは、時間をかけすぎるからです。直接的な価値を生まない行動に開発者がまとまった時間・期間を使うとなれば、マネージャーも不安を覚えて色々と確認したくなるのも無理からぬことです。

例えば1時間のリファクタリングに許可を求める必要はないでしょう。不慣れな場合はもう少し時間をかけたくなるかもしれませんが、それでも2時間あればそれなりのことができるはずです。

そのレベルの時間が捻出できない場合は、リファクタリング以前にチームとして信頼関係が築けていないなど別の問題がありそうです。

そもそも大規模なリファクタリングは成功率が下がります。本当に変更後のコードがいいかどうかは、そのコードの上で生活してみないと分かりません。

ビッグバン・リリースと同様にビッグバン・リファクタリングもリスクの高い行為であると言えるでしょう。とにかく小さくやりましょう。

逆に「リファクタリングをゴールとして」「許可を求めて」「長い時間をかける」とあなたの信頼は損なわれる可能性が高くなります。まずはこの3つを避けましょう。

仕掛けどころ

次の仕事の前工程に組み込む

リファクタリングしたくなる代表的な場面は「次のコードを書くのに現状が足を引っ張る」でしょう。

  • 以前は使っていたがもう乗り換えたライブラリに依存しているコード
  • 今では推奨されない書き方をしている部分

こういうのが残っていると、新しく書くコードの健全性を保つのが困難になります。

変更を加えようとしている部分にこうした課題がある場合は、事前にリファクタリングをして地ならしをします。

当時は適切であったコードも時間の経過やその後の要求によってそうでなくなることはよくあります。その負債を新たな仕事の前に返済しておくのは妥当な取り組みです。

また、こうしたリファクタリングは恩恵をすぐに受けられるので効果が判断しやすく、アプローチが今ひとつだった場合の軌道修正も容易です。

振る舞いを変更した後片付けとしてやる

  • コピペで済ませたところを再利用可能な形で切り出す
  • 既存の関数等を拡張して共通化する

こうしたリファクタリングは機能変更の後から別PRでやります。

逆に新しい機能を実装する時には、ちょっとした拡張で共通化できる場面でもコピペで済ませます。既存の関数等に少しでも変更を加えると、それを利用している全ての部分が影響範囲になるためです。

新たな機能は影響範囲を最小化して実現し、それによって適切でなくなったコードの負債を、その仕事を終える前に返済するのです。

その際にはPullRequestも別にしてリリースも段階的におこないます。

新機能のリリースと共通部分の変更を同一PRにすると、後者に問題があった場合にrevertするとリリースした新機能も引っ込んでしまいます。

レビューにおいて「機能変更はいいが、そのリファクタリングには同意しかねる」みたいなのが発生するとリリースが遅れる要因にもなるので、やはり振る舞いの変更とリファクタリングは別でやる方が望ましいでしょう。

リファクタリングに限らず、とにかくPullRequestは小さくすることが大切です。

https://zenn.dev/nekoya/articles/adc9ec4b08e4f3

優先的にリファクタリングする時間を確保する

ソフトウェアは変更しない部分が劣化していきます。正確には周りの変化に追従できずに取り残されていくのですが、感覚としては「放っておいたら劣化した」と表現するのがしっくりきます。

前述のアプローチだけでは変更が入らない部分は古いコードがずっと残り続けることになります。それこそ何年も。

ライブラリや記法の世代交代が進むと、古いコードが残っている部分に対して「手を入れるのが億劫だ」「できればこのへんは触りたくない」という意識が芽生えます。

これは危険信号です。プロダクト開発の優先順位の設定に邪念が混ざるようになります。

  • この機能を作るとよさそう
  • しかしコードの状況がよくないので手間が余計にかかる
  • かかるコストを考慮すると今やるべきではない

のようになると、その機能によってもたらす価値が本来よりも低く評価されることになりかねません。

放置されたコードは時間の経過とともに劣化を続けるので、その周辺にはどんどん手を入れづらくなります。

このネガティブなサイクルに陥る前に、あるいは陥り始めたと実感したらリファクタリングの優先度を普段よりも上げる時間をとりましょう。長い期間を確保する必要はありません。せいぜい数時間で十分です。例えば「金曜午後はリファクタリングを優先する」みたいな習慣付けをするのも一つの手でしょう。

その際に単なるリファクタリングで終わるのではなく、外から見える改善を後から少しでも加えられると理想的です。劣化して放置されたコードの周辺には「本当はやりたかった改善」が潜んでいる可能性が高いです。

それを加えることでリファクタリングが効果的であったのかを検証できる上に、その部分に手を入れることへの抵抗感も軽減されるでしょう。

チームとして「この時間は皆でリファクタリングする」みたいな時間を取る道もあります。そうした場面では事前にマネージャーやステークホルダーと合意を得ておくことも有効かもしれません。許可を得るというよりも、組織としての一体感を高めるための意識共有としての側面が強くなるとより効果が期待できます。

そうした場面でもPRは小さく切って進めて、確保した時間内にmergeしましょう。mergeしそこねたリファクタリングPRはだいたいタイミングを逃してそのまま打ち捨てられていきます。

日常の習慣にしよう

リファクタリングが開発サイクルにうまく取り込めないのは、多くの場合「普段からやっていないから」です。少しずつ、小さく、日常的にやっていきましょう。

Discussion