初めに
社内でのリファクタリング地位向上のため、いくつかリファクタリングに関する記事を書きます。
今回は「なぜリファクタリングをしたほうがいいのか?」という話で、僕の意見というよりは、書籍リファクタリングの著者であるMartin Fowler 氏の主張のまとめ、という感じです。
ちなみに書籍リファクタリングはいくつか種類があります。
-
リファクタリング(第2版)既存のコードを安全に改善する
-> サンプルコードはJavaScript -
新装版 リファクタリング 既存のコードを安全に改善する
-> サンプルコードはJava -
リファクタリング:Rubyエディション
-> サンプルコードはRuby
リファクタリングとは
リファクタリングとは、ソフトウェアの外部の振る舞いを保ったままで、内部の構造を改善していく作業を指します。
例として、引数に年齢を渡すと成年か否かを判定する adult?
というメソッドをリファクタリングしてみます。(言語は Ruby
です)。
- before (bad)
def adult?(a)
if !(a < 18)
true
else
false
end
end
adult?(18) #=> true
adult?(17) #=> false
適当すぎる引数名 a
や直感に反する条件式、ガタガタなインデント等により理解が難しいコードだと思います。
これをリファクタリングすると… 🧹
- after (better)
def adult?(age)
age >= 18
end
adult?(18) #=> true
adult?(17) #=> false
より理解しやすくなったのではないでしょうか?
(成年年齢の18(歳)がマジックナンバーであることは許してください🙏)
なお、Fowler 氏によると、プログラムのパフォーマンスを向上させるための変更はリファクタリングとは別物、ということです。
参考: bliki: IsOptimizationRefactoring
リファクタリングをする理由
では、どのような課題を解決するためにリファクタリングをするのでしょうか?
- ソフトウェア設計を改善する
短期的な目標を実現するための変更(システム障害を収束させるためのパッチ、ちょっとした機能追加等)、コードの設計を理解しないままでの変更により、設計は少しずつ崩れていきます。これらの累積により、コードを読んで設計を把握することが難しくなります。
定期的にリファクタリングを行うことで、コードをよい状態に保つことができます。
- ソフトウェアを理解しやすくする
コードは一度書かれると、その後は不特定多数の開発者から読まれることになります。
「プログラムが動作すること」だけが目的とされ、将来の開発者(自分を含む場合もある)のことを考えずに書かれたコードは問題を引き起こします。理解しづらいコードは、仕様変更や機能追加、バグの調査等の邪魔になるでしょう。
定期的にリファクタリングを行うことで、コードの目的がより伝わるようになり、実現したいことを明確に表現することができるようになります。
- バグを見つけやすくする
コードが理解しやすくなれば、バグも見つけやすくなります。
定期的にリファクタリングを行うことで、バグが少ない堅牢なコードになります。
- 機能追加等を速める
これまでの設計の改善、理解しやすさの向上、バグの減少というのは、どれも品質の向上です。
ではリファクタリングが開発の生産性にどう影響するかというと、仮説ではありますが、上がります。以下に示すのは、累積した機能の量(縦軸)と時間(横軸)との関係の擬似的なグラフです。(引用:Fowler 氏の DesignStaminaHypothesisより)
まずい設計(青い線)のプロジェクトでは、既存のコードベースにどのように機能を追加するかを検討する時間が徐々に増えていきます。そしてようやく機能を追加したとしても、バグが起こり、その修正に更に時間がかかるようになります。
一方で優れた設計(オレンジの線)のプロジェクトでは、新たな機能を追加する際にどこをどのように変更したらよいか、把握がしやすいです。バグを埋め込んでしまう恐れも小さく、もしバグが生じたとしてもデバッグがしやすいです。
巨大なコードベースで素早く機能を追加し続けるには、リファクタリングは不可欠です。
なぜリファクタリングは行われづらいのか?
メリットが大きいリファクタリングなのですが、なぜか後回し(または全く行われない)になってしまうプロジェクトは多いのでは?という気がしています。
その理由を、自分の経験だったり、色々調べてみたりしていくつかあげてみました。あくまで一般論として捉えていただけると幸いです🙏
- 「動いているコードに触るな」
自動テストの仕組みがないレガシーシステムでは、なぜ(どうやって)動いているのかわからない複雑怪奇なコードが多く、変更を加えると高確率でデグレを引き起こすそうです。
そうして「動いているコードに触るな」という格言が生まれ、リファクタリングをするという選択肢そのものがなくなってしまうのかと思いました。
- 重要度は高いが緊急度は低いと認識されている
🗣「まずリリースしよう!あとでリファクタリングすればいいから!」
そう言って作られた(最悪の場合、作られることすらない…)Issue
は、バックログの奥底に眠り続けているのではないでしょうか?
「木こりのジレンマ」に例えると、リファクタリング(”斧を研ぐ”)をしたほうが中長期的な開発効率が上がるのに、短期的な成果を求めて目先の諸々のタスク(”木を切る”)に精一杯になってしまう、という感じですね。
- コードを読み書きする人以外にはその価値が伝わりづらい
リファクタリングの恩恵を直接的に受けるのは、コードを読み書きする人だと思います。
しかし、ソフトウェア開発に携わる人全員がコードを読み書きするわけではありません。プロジェクトのスケジュールを調整して納期を守ることに心血を注ぐ人、ユーザの要求をヒアリングして要件定義する人、UI/UXデザイナー、…etc.
それらの人達に価値を提供するためにコードを読み書きするほうが、リファクタリングより優先されるということは十分考えられそうです。
- 評価されにくい
ソフトウェア開発における生産性だったり設計の良し悪しというの計測不能に近いです。そのため、定量的な評価がしづらいです。ということは、リファクタリングという行為そのものも評価しづらい組織が多いのではないでしょうか?
- 「〇〇の機能をスケジュール通りにリリースしました!」
- 「3ヶ月でバグ修正のIssueを50個捌きました!」
のほうが評価しやすい気がします。
残念ながら、評価されにくいタスクというのは価値があったとしても多くの人に敬遠されがちですよね。
余談ですが、書籍 A Philosophy of Software Design では、雑なコードをもの凄いスピードで書き上げる人のことを tactical tornado
と呼んでいて、組織によっては経営陣から最大級の評価を受けるようです。
そして、将来 tactical tornado
が書いたコードの面倒を見る他の開発者は、経営陣から見てわかりやすい成果を上げることに苦しみ、tactical tornado
よりずっと低い評価が与えられます。
この状況は、変更容易性に優れるコードを書きたい・書くことができる開発者にとって居心地がいい訳がなく、プロジェクトから開発者が離れていく原因にもなりそうですね💀
終わりに
皆さんのグループ・チーム(過去に所属した組織も含め)ではどうでしょうか?
全タスクに対するリファクタリングの割合を大きくした成功体験をお持ちの方は、ぜひコメントいただきたいです🙏