RubyKaigi 2016 2日目の基調講演は、Test Double社のCo-FounderであるJustin Searlsさんです。
Justinさんは古いコードのメンテナンス、リファクタリングについて話しました。技術面のみならず、経営層にリファクタリングの重要性を説く方法にまで触れた、大変興味深い講演です。そして、発表ではSuture 🏥という、リファクタリングを支援するgemがお披露目されました。とても盛りだくさんの内容でしたが、絵文字を盛り込んだスライドなどの工夫が凝らされ、笑いあり、驚きありの、あっという間の1時間でした。
メンテナンス性の重要さ 〜後期の成功に求められるもの〜
Justinさんは今日の問いとして、次のことを挙げました。
「古いRubyを簡単にメンテナンスできるようにできるか?」
Rubyが成功を納めたことに間違いはありません。しかし、初期の成功と後期の成功では求められるものが異なります。初期の成功では、簡単にものが作れることができることが大事です。しかし、言語が一度成功した後、継続して発展していくためには、今度は別のことが問題となります。理由としては、人気が出てより批判的に見られるようになること、仕事に使われるようになるので、より重大なものになっていくことなどが挙げられます。ですから、後期の成功で鍵となるのは、古いもののメンテナンス性だとJustinさんは主張しました。
そこで、冒頭の問いに繋がります。
リファクタリングとは「新機能の実装やバグ修正に先立ち、それらを簡単に行うために前もって変更を加えること」
問いに答えるべく、具体的にレガシーなコードをリファクタリングしていく段階に移っていきます。 その前に、Justinさんは今日用いるリファクタリングとレガシーコードの意味を次のように定義しました。
- リファクタリング::新機能の実装やバグ修正に先立ち、それらを簡単に行うために前もって変更を加えること
- レガシーコード::自信を持って変更できるほど十分に理解していないコード
リファクタリングは技術的にも、ビジネス的にも難しい
リファクタリングが一般的に難しい理由として、以下の3つが挙げられました。
- どれくらいかかるか時間を見積もるのが難しい
どれくらい作業が必要になるかも、どれくらいリスクがあることなのかもわからないため。
- ビジネス的な視点からは価値が見えない
リファクタリングをした結果得るのは同じ振る舞いであり、どんな価値が生まれたのかわからないため。
- 往々にして、リファクタリングはとても複雑な箇所に施すことになるため、そこの箇所の開発を止めなければならなくなる
複数の変更をそこにマージするのが難しくなるため。
複雑なコードであればあるほど、重要性も増すことも難しさの一因として挙げていました。
また、コストとリスク、それとビジネス的な優先度を照らし合わせたとき、リファクタリングは最も理解を得るのが難しいエンジニアの仕事であるとJustinさんは自身の経験に基づき述べました。
そこで、リファクタリングをより簡単に行うための一環として、まずビジネス的な優先度を上げるための3つの作戦を検討していきました。
ここでの前提として、ビジネス的視点によれば、リファクタリングは「道路工事」のように見える、という仮定があります。すべてが止まり、交通量はゼロになり、しかしお金ばかりが普段の勢いと変わらず出ていくという状態です。これは、ビジネス的な視点から見れば魅力的ではありません。
ですから、次のような作戦を立てられます。
作戦1. 不安を煽る
「リファクタリングをしないと、____ なことになりますよ!」
- 例1. 「リファクタリングをしないと、いつかすべてを書き直さなければならなくなりますよ!」
- 例2.「リファクタリングをしないと、メンテナンスコストは今より相当高くつくことになりますよ!」
しかし、例1については遠い未来の話であり、証明が困難です。例2については、定量的にはかることができず、実感を得ることができません。
作戦2. コストを取りこむ
自己規律とプロ意識によってコストを取り込むこともできます。新機能を追加するときには通常、計画を立て、開発をし、テストを書くという活動をするでしょう。ここに前もってリファクタリングの段階を盛り込むことによって、新機能について、それぞれもう少し時間をかけることもできます。これができれば、大変素晴らしいことです。
しかし、これを実現するにはほとんどの人が持ち合わせていない厳しい自己規律が要求されます。さらに、時間が押してくると、真っ先に落とされるのはこのリファクタリングの時間です。そして、時間が押してくるというのは、ほとんどのチームが経験することです。ですからこの方法もそこまで効果的ではありません。
作戦3. 人質をとる
上記2つに代わる作戦として、人質をとるのはどうでしょうか。経営陣によりバックログの優先度が機能1, 2, 3, 4と設定されたとき、チームとしてはそれにNoと言い、機能1を作ったらその後はリファクタリングをやらないとダメだ、機能3の前にはまたリファクタリングが必要だ、という具合に要求し返すのです。
しかし、これは問題をはらんでいます。対立的だからです。基本的にやっていることは、開発チームを急かす経営陣を咎め、もっとゆっくりじっくりとやる必要があると主張することです。これでは、経営陣のチームに対する信頼を損ねます。コードを書いてもらうためにたくさんのお金を払っているのに、毎回立ち止まっての修正が要求されるようでは、仕事を遂行する能力がないと思われてもおかしくありません。
このように、リファクタリングを売り込むのは難しいのです。
そこでJustinさんは次のように主張し、方向を変えます。
「自分たちはプログラマーだし、今さら文化を変えられるとは誰も思っていない。だから、短期的な解決法はそこにはないのではないだろうか。」
ビジネス方面で攻めてもしかたがなく、自分たちはプログラマーなのだから、技術で解決しようという熱い方向転換です。
リファクタリングのコストを下げる
リファクタリングが高コストである理由を、Justinさんは次のように説明しました。
- プレッシャーを感じる。たくさんのことを一度に把握してなければならない
- 多くのことを短い時間で行わなければならない
- ツールがない。新しいものをつくるツールはあふれているが、古いコードのメンテナンスを支援するツールは少ない
Justinさんはそもそもリファクタリングが怖いそうです。
では、リファクタリングのコストを低くするにはどうすればよいでしょうか。現時点では次のツールが使えます。
- リファクタリングパターン
- 仕様化テスト
- A/Bテスト / 実験
ここではそれぞれ、リファクタリングパターン、仕様化テスト、A/Bテストの資料として、『リファクタリング:Rubyエディション』、『レガシーコード改善ガイド』、Scientist!を紹介しました。
Development、Testing、Staging、Production、すべての環境で使えるツールは?
仕様化テストもA/Bテストも、それだけでは、次の4つの環境
Development, Testing, Staging, Production
には対応できません。
その4つの環境で十分に力を発揮するツールはどのようになるでしょうか。まだ存在しないものの、話をしなければならないということで、JustinさんはTDDことTalk Driven Developmentで、代わりにgemを作ることにしました。
Suture
以後はSutureの説明です。Sutureの発音は「スーチャー」が近いです。
「外科手術としてのリファクタリング」
Sutureとは、手術後に傷口を縫合した縫い目のことです。外科手術的なリファクタリングを想起する言葉として良いと思い選んだそうです。「リファクタリングを外科手術のようにあつかう」という意味が込められています。
外科手術の目的は、恐ろしい箇所に処置を施し安心できるようにすることです。そして、外科手術には事前の入念な計画や柔軟なツール、一貫したプロセスが求められます。Sutureにはそういった機能やワークフローが備えられています。
Sutureが持つ一連の機能とワークフローについて、コード例を実際にリファクタリングしていく形で説明がされました。pure function, mutationの場合の両方について、それぞれ段階的に解説されていきます。Sutureを使い、レガシーコードがリファクタリングされていく様子を、基調講演の動画で是非ご確認ください。16:40頃からSutureの説明が始まります。
ここからは英語ではなく、Justinさんはコミュニティの一番の共通言語であるRubyで語ってくださいました;)
https://speakerdeck.com/searls/surgical-refactors
Suture 🏥
おまけ
さすがです。