『レガシーコード改善ガイド』駆け足ガイド〜 技術的負債とダンスを(7)

レガシーコード改善ガイドの重要用語を開発シーンに沿って駆け足に紹介します

Eiji Ienaga
時を超えたプログラミングの道

--

はじめに

前回は、『レガシーコード改善ガイド』のキーポイントの1つである、テストしたい対象とテストを妨げる要素の密結合を【切断】し、【接合部】【許容点】を作って、ユニットテストできるように変換する例を、JavaScriptのサンプルコードを使って解説しました。

今回は『レガシーコード改善ガイド』の全体感を、駆け足で解説します。レガシーコードを向き合う作戦を考えるときの頭出しの参考になれば幸いです。

難しい作業はペアプログラミング

ペアでレガシーコードに対峙する

レガシーコード改善は基本、難しい作業のため、ソロより【ペアプログラミング】で行うが望ましいです。難しい作業である外科手術は通常ソロでは行わないのと同様の考え方です。

長過ぎるメソッド、巨大クラス、依存関係が絡まった難しいコードを理解し、レガシーコード改善方針を立てて、ユニットテストができる構造へ変換し、テストを追加してリファクタリングし、新しい機能追加の作業は、1人よりペアの方がより安全に的確に行うことが期待できます。

既存コードの改善は危険な作業のため修正する際は、雑念をシャットアウトして取り組む【超集中編集】、1度に複数を相手するのではなく、1つづつステップバイステップで取り組む【単一目的の編集】を心がけます。静的型付け言語であれば【コンパイラまかせ】と、エディタの機能もうまく活用して修正箇所を特定しながら取り組みます。

既存コードを直に改善が難しい場合はスプラウト

レガシーコードをスプライトを使って改善

機能修正の際に、時間がないなどの理由から、1.既存のレガシーコードの振る舞い理解し、2.ユニットテストできるように慎重に依存関係を排除し、3.テストで保護して、4.リファクタリングで修正しやすくし、 5.新機能追加のステップは諦めざるえないことはあります。が、そのような状況でもできることがあります。

機能追加の際に既存コードは修正せずに、新しいクラスやメソッドを用意する【スプラウトクラス】【スプラウトメソッド】です。新しいクラスの追加であれば、既存コード修正と比べて制約が少なく【テスト駆動開発】で作ることも可能です。【スプラウト】の新しい領域を段階的に育てていきます。

システムレベルでステップバイステップの置き換えであればストラングラーになりますが、【スプラウト】はその小さい版と捉えてもらっても良いでしょう。

そのほか、既存コードを包み込んで機能を実現する、【ラップメソッド】【ラップクラス】の選択があります。

影響範囲調査のときに試行リファクタリング

新規機能の追加をする際に、影響範囲調査でソースコードを読むことがよくあります。その際、より深くレガシーコードを理解することを目的とした【試行リファクタリング】はオススメです。【試行リファクタリング】は、修正を捨てること前提でリファクタリングしながら読んでレガシーコードの理解を深める行為を指します。理解が主目的のため修正は必ず捨てます。

モデリングや図解で責務や依存関係を整理

CRCをカードやホワイトボードで!

対象のシステムの動きを理解する際は、コードを読む以外にも選択肢があります。カードを使ってオブジェクトの責務やオブジェクト間のメッセージのやり取りをチームメンバーと対話しながら理解を深める方法で、【白紙のCRCと呼ばれます。カードを使う代わりにホワイトボードに図解して整理もよいでしょう。

また、【影響スケッチ】を描いて、依存関係や効果的にユニットテストを入れるポイントを探します。ある機能群をテストするのに理想的な場所は【絞り込み点】と呼ばれます。

巨大クラスの分解を検討しているのであれば【機能スケッチ】を使って現状を整理し、分類します。

テストで保護して変更

祈るのではなく保護する

レガシーコードに対して新機能追加する前に【仕様化テスト】を使って修正対象の現在の動きをテストを使って明確にします。【仕様化テスト】は、ソフトウェアの振る舞いを明確にしてコードを修正しても壊れていないことを確認するためのテストです。既存コードがテストで保護できれば、リファクタリングや新機能追加ための既存コードの修正を自信を持って行うことができます。【編集して祈る】ではなく【保護して変更する】レガシーコード改善の基本になります。

(ユニットレベルは、いったん後回しにして、End2Endレベルのテストで保護して修正の選択肢も考えられます。が、『レガシーコード改善ガイド』は、依存関係を排除して、ユニットレベルで高速に実験を繰り返して、ビジネスロジックに集中できるプログラミング環境を整えることに価値を置く傾向があるため、書籍自体ではEnd2Endレベルのテストで保護して修正は取り扱っていません。)

だだし、ユニットレベルで【仕様化テスト】を記述して実行して確認しようにもできないことがあります。外部サービスに接続などの環境依存のコードと計算ロジックのコードが密結合しているや、確認したい計算結果に直接アクセスできないなどがテストを難しくする理由です。ユニットテストをできるようにするには、環境依存と計算ロジック【分離】し、確認したい計算結果を【検出】できるように修正が必要です。

慎重に依存関係を排除してユニットテストできるように修正する

接合部でテスト可能に

技術や環境依存のコードとテストしたい計算ロジックが密結合や計算結果にアクセスできないままでは、ユニットテストができません。依存関係の排除が必要です。テストしたい要素と難しくしている要素を慎重分離して、【接合部】【許容点】を作ってテストできる構造にするがレガシーコード改善の基本方針です。

【接合部】は、編集せずにプログラムの振る舞いを変えることができる場所で、【許容点】はその振る舞いを決定できる場所を指します。接合部と許容点を作る例については、前回を御覧ください。

依存関係の排除の方法は『レガシーコード改善ガイド』の3部で名前付けされて整理されています。【パラメータの適合】【メソッドオブジェクトの取り出し】【呼び出しの抽出とオーバーライド】【インタフェースの抽出】などなど

3回に分けて『レガシーコード改善ガイド』を紹介しました。テストがないコードがある状況で、テストで保護してリファクタリングし、機能追加しやすく読みやすくを目指すのであればぜひ手にとって欲しい一冊です。次回からは、リファクタリングを再入門していきます。

--

--