リファクタリングとは何か、リファクタリングを効率的かつ安全に行うためにVisual Studio 2017が提供している支援機能の概要を見ていこう。
最近のVisual Studioは、バージョンアップごとにリファクタリングのサポート機能も強化してきている。もはや「知らないと損」といって差し支えないだろう。そこで、本特集では前後編にわたってリファクタリングとVisual Studio 2017(以降、VS 2017)のサポート機能について解説していく。
なお、プログラミング言語はC#で解説していく。Visual Studioのリファクタリングサポート機能の範囲は言語によって差があり、C#が最も広いからだ(Visual Basicも、ほぼ同等のリファクタリングサポート機能を持っている)。
今回は、リファクタリングとは何なのかをおさらいし、リファクタリングにVisual Studioなどのツールを使う意義を考えてみよう。そして最後には、実際に簡単なリファクタリングを試してみる。
「リファクタリングとはソースコードを書き換えることである」という回答は、残念ながら正解とは言えない。その意味には「リライティング」(rewriting)という呼び方がふさわしいだろう。
リファクタリングとは、「ソースコードを、その外的な振る舞いを変えることなく、きれいなメンテナンスしやすいコードに書き換えること」である。
リファクタリングを世に知らしめたマーチン・ファウラー氏の定義は、次のようだ。
「リファクタリングとは、ソフトウェアの外部の振る舞いを保ったままで、内部の構造を改善していく作業を指します」
※新装版「リファクタリング」(ISBN978-4274050190、2014年発行)の「はじめに」より
docs.microsoft.com(旧MSDN)のWebサイトでも、以下のように同様な定義をしている。
「Refactoring is the process of modifying code in order to make it easier to maintain, understand, and extend, but without changing its behavior.」
(試訳:「リファクタリングとは、保守しやすく、理解しやすく、拡張しやすいコードにするためにそれを変更するプロセスですが、その振る舞いを変更しません」)
※「Refactoring, Code Generation and Quick Actions in Visual Studio」(2017年3月23日付)より
リファクタリングとは、コードを単に書き換えるだけでなく、そこに条件が2つ付いているのだ。
従って、バグ修正や機能追加を伴う書き換えは、リファクタリングではない。また、メンテナンスのしやすさを犠牲にして高速化を図る書き換えも、リファクタリングではないのである。
リファクタリングとは何かについては、本稿では定義を示すにとどめる。その詳細やリファクタリングのサポートツールに頼らない具体的な手法については、上に引用したマーチン・ファウラー氏の「リファクタリング」(以降、「リファクタリング本」)を読んでいただくのが一番だ。また、少々古い記事だが「特集:.NET開発者のためのリファクタリング入門」も参照していただきたい。
上の定義で挙げた2つの条件は、成功基準と言い換えることもできる。リファクタリング作業が終わったときに2つの条件を共に満たしていれば、リファクタリングに成功したといえるからだ。
この2つの成功基準を満たしたかどうかは、どのように判定したらよいのだろうか?
外的な振る舞い(外部設計と言い換えてもよい)が変わっていないことは、テストによって確認できる。
言うのは簡単だが、しかし、大きなハードルが立ちはだかっている。次の2点だ。
ここで「正しい」とかっこ書きにしたのは、要件定義などに照らして正しいという意味ではなくて、リファクタリング前のコードと一致しているという意味である。その「正しい」外部設計がなくては、リファクタリング後にいくらテストをしてみても、外的な振る舞いに変化があったかどうかは分からない。
とはいうものの、アプリ全体の振る舞いを細大漏らさず完璧に記述した外部設計書には、筆者はお目にかかったことがない(恐らく実務的に不可能だと思う)。また、仮にそのようなものがあったとしても、リファクタリングした部分の振る舞いの不変性を確かめるためにどれだけの範囲をテストすればよいかも分からないだろう(1行のリファクタリングのためにアプリ全体のフルテストが必要だろうか)。リファクタリングの影響が及び得る範囲に限定した外部設計があればよいのだ。
リファクタリングの影響が及び得る範囲に限定した外部設計とは、リファクタリングの規模によるが、多くはメソッドのレベルかクラスのレベルだろう。その粒度の「正しい」外部設計書が用意されていればよいのだが、しかしこれまた、メソッドやクラスのレベルで外部設計書を書いていることはまずないだろう。
その解決策となるのが、「テスト駆動開発(TDD)」である。テストコードから書き始めることで、コードが完成したときにはその外部設計に対する自動テストも出来上がっているのだ(ただし、現状はUIを除いたロジック部分だけとするのが現実的)。この自動テストはコードの外的振る舞いを「正しく」表現できている。TDDで作られた自動テストは「正しい」外部設計なのである。
TDDによって、リファクタリング前に「正しい」外部設計(=自動テスト)が得られ、リファクタリング後に再びその自動テストを実施すれば、コードの振る舞いが変わっていないと確信できる。また、2つ目の課題であるテストを実施する手間も、自動テストならばないに等しい(さらにVS 2017 Enterpriseエディションでは、Live Unit TestingをONにしておくとバックグラウンドで自動的にテストを実行してくれるので、全く手間いらずだ)。
なお、UI部分をTDDで作るのは、現状では不可能ではないがとても困難である。UI部分に関しては、まだ外部設計書のメンテナンスと手動テストの方が有利であろう。ただし、UI部分のコードが一通り完成し、その外部設計が完全にフィックスできた後ならば、「コード化されたUIテスト」を作成するとよい。その自動化テストは、やはり「正しい」外部設計であり、テストを実施する手間も大幅に削減されるからだ。
さて、全てのリファクタリングには自動テスト(またはUIの「正しい」外部設計書と手動テスト)が必須なのかというと、そうでもない。テストをしなくてもコードの外的な振る舞いが変わっていないことを確信できればよいのだ。それが本稿の主題である。
メンテナンスしやすさのうち、名前やコメントの的確さなどは主観によるしかない。それ以外では、自動的に計測して数値化できる部分もある。
名前についてはここで言うまでもないだろうが、不適切に名付けられているとコードが理解しにくくなる。合計を求める「CalcAve」メソッドなどが不適切な例だ(「CalcSum」などとすべき)。理解しにくいということは、メンテナンスしにくいことにつながる。理解しやすさの面からは、業務に固有な名詞や動詞などには日本語を使うのも一案だ。また、コメントも同様に、コードと異なる説明が書いてあったりすると理解の妨げになる。
計測は、さまざまな指標(および、その測定方法)が提案されているが、いずれも手作業で勘定するのは大変だ。ここはツールに頼ることにしよう。VS 2017では、次の5つの指標が計測できる(「コードメトリックス」という)。
各指標の意味は、MSDNの「コード メトリックス値」をご覧いただきたい(この文書は少々古いのだが、本稿執筆時点ではdocs.microsoftにある最新版は未翻訳だった)。
リファクタリングにおいては、この中の保守容易性指数を参考とするとよいだろう(次の画像)。ただし、例えば、コードを読みやすくするための説明用変数の導入(Extract Variable)を行うと、(変数が増えたために)保守容易性指数が下がってしまうこともある 。そのような保守容易性指数の特徴を把握した上で、想定外に保守容易性指数が下がってしまったら、リファクタリングに失敗したと判断してよいだろう。もちろん、保守容易性指数が大きく上がったのなら、リファクタリングに成功したと太鼓判を押せる。
Copyright© Digital Advantage Corp. All Rights Reserved.