印刷 | 閉じる

Visual Basic 2005 のリファクタリング

原文: Refactoring in Visual Basic.NET 2005 by Developer Express Inc.
日本語訳: 杉下朋年 (http://www.mitene.or.jp/~sugisita/)

(注)この文書は Developer Express Inc. が公開している英文ドキュメント Refactoring in Visual Basic.NET 2005 の内容を私、杉下が個人的に翻訳し、Developer Express Inc. の許可を得て公開しています。
よって、訳文の内容については Refactor! の開発元、Developer Express Inc. による正式なものではありませんので、この文書に関する問い合わせは Developer Express Inc. ではなく、私個人にお願いします。

まえがき

Developer Express Inc. の Refactor! は Visual Studio .NET 2005 beta 2 のプラグインで、 開発者がソースコードを簡単かつ具体的にすることを可能とし、コードを読みやすくし、メンテナンスにかかるコストを抑えます。

リファクタリングとは?

リファクタリングとは動作しているコードに対して多くの小変更を行う過程をいい、外部へのふるまいを全く変更せずに内部構造のみを改善することをいいます。

2*4*5*3 という数式を検討することを例にとって考えてみましょう。
これは5を求めるという意味は変更せずに、1*2*3*4*5 に変換することができます。これらは意味合いとしては同じですが、後者の方が読みやすくなっています。
Refactor! はこのような事を動作コードに対して行います。

ちょっと前に開発者たちが面白半分で「わかりにくいコード大会」を開催し、誰がいちばん読みにくいコードを書けるかを競い合った時がありました。しかし非常に残念な話ですが、この時に意図的に複雑に作られたコードよりもさらに読みづらいコードが実際には非常に多く存在します。このような時、リファクタリングが導入されます。
リファクタリングの最終目標は動作はするが必要以上に読みづらくなった複雑なコードをより読みやすく、メンテナンスしやすい構造に調整することです。

Visual Basic は自身の文書化と、読みやすく維持しやすいコードの開発を薦められるようにデザインされています。しかしコードは時を重ねるにつれてさまざまな要因において成長し続け、結果として雑然とあるいは複雑になりがちです。Refactor! の持つ各機能はそのような複雑なコードを読みやすいコードにし、低コストでそれを維持するための手助けとなります。

なぜ Refactor! なのか?

他のリファクタリングツールでは見られない Refactor! の特徴的な動作は、たった1つのキー操作(ワンキーリファクタリング)のみで起動し、エディタのコード上で直接実行されるため、コードから離 れずにすぐに再構築が行えることです。
この操作方法はその他のリファクタリングツール製品全体に影響を及ぼすでしょう。

図1. ワンキーリファクタリング - Ctrl+~(日本語キーボードの場合、Ctrl+半角/全角)を押すと、現在使用可能なリファクタリング機能の一覧が説明付きでどこでも見られます。

Refactor! は言語に対しニュートラルなアーキテクチャで構築されていますので、Visual Basic.NET と C# の開発者に全く同一の機能を提供することができます。
Refactor Pro はその他の Visual Studio 言語向けのサービスを構築する開発者にとって利用可能な拡張機能を含んでいます。

リファクタリングの機能を紹介する前に、Refactor! を使って行ったすべての内容は Visual Studio 標準の Undo/Redo メカニズムによるロールバックが保証されていることを述べておきます。
もしリファクタリングの結果が期待した内容ではなかった場合、Ctrl+Z(または Undo 機能を提供するものは何でも)によりすべて元に戻す事も可能であるため、あなた自身がその内容を自由に評価することができます。

リファクタリング: パラメータ順序の再変更

メソッドシグネチャ内のパラメータ順序の変更を行い、同時にこのメソッドの全ての呼び出し元の変更を行います。
最も重要なパラメータを最初に表示させることは、メソッドのユーザビリティの改善につながります。このようなパラメータ定義の順序変更を必要とする際に使用します。

「パラメータ順序の再変更」はおそらく、Refactor! と他のツールとの違いを説明する上では恰好の例です。なぜなら、Refactor! のすべてのプロセスは非常にビジュアル化されており、コード上で 実際に変更内容を確認しながら操作できるからです。これこそパラメータ順序変更のやり方です。
単純にテキストカーソルをパラメータを持ったメソッド定義上に移動すれば、このリファクタリングを利用することができます。しばらく待っていると、リファクタリングスマートタグに一覧表示されたリファクタリング機能を確認できます。待つ必要がない場合、「ワンキーリファクタリング」キー(Ctrl+~)を押せばすぐに左右の矢印キーを使用してパラメータを左右に動かすことができます。

図2. エディタのコード上で直接順序変更が行われている様子 - 操作性低下となるモーダルダイアログは無い

この文書はまるでリファクタリングを表示上強調されているように思えるかもしれません。しかし試していただければわかりますが、これらは実際の動作の様子です。

リファクタリング: リネーム

このリファクタリングはローカル変数またはプライベートフィールドおよびプロパティ、メソッドのリネームを行います。このリファクタリングは定義と参照元の両方に影響があります。

意味を持った識別名を選択することはコードの読みやすさを改善するための単純な方法の1つです。Refactor! はこのプロセスを単純化してくれます。テキストカーソルを対象に移動し「ワンキーリファクタリング」キー(Ctrl+~)を押すと、名前の変更が始まります。名前の変更によって、その識別子へのすべての参照が薄い緑色のBOXでハイライトされます。各BOXへの移動はTabキーまたはShift+Tabキーで移動でき、そのうちの1つを変更すると全てに変更が反映されます。

図3. 「名前の変更」によって名前の一致するものが関連付けられ、変更されている様子

リファクタリング: メソッドの抽出

クラスベースのリファクタリングの中でもっとも洗練されているのは恐らく「メソッドの抽出」です。
このリファクタリングによってメソッド内部のコードの一部をメソッドの外にメソッドとして抽出することができます。その際、新しいメソッドを呼び出すコードを抽出元に記述する必要はありません。

このリファクタリングの使用方法はすでに何度も行ってきたように、コードを選択し、テキストカーソルを置き、「ワンキーリファクタリング」キー(Ctrl+~)を押します。すると選択したコードブロックを含む新しいメソッドが作成され、元の場所にはメソッドの呼び出しコードが追加されます。

例題として、シリンダのボリューム計算を考えてみましょう。後に再利用することを考慮に入れ、円の面積を求めるコードをメソッドとして抽出することにしたいと思います。
今回も同じようにコードを選択し、テキストカーソルを置き、「ワンキーリファクタリング」キー(Ctrl+~)を押します。コードはソースのメソッドから切り出され、対象メソッドを配置する場所をたずねられます。

図6. メソッドを抽出する場所を赤い矢印を使ってあらかじめ選択することができます。

すると、Refactor! は選択した場所に作成するメソッドにどれくらいのパラメータが必要かを判断し、規定の名前付けを行ったいくつかのパラメータ付きメソッドを作成し、メソッドのコードと呼び出しのためのコードを生成します。最後に「名前の変更」リファクタリングを使用して規定の名前を任意の名前で上書きします。

図7. メソッド抽出が完全に終わったコード - Refactor! で動作のためのパラメータを決定し、意味のある名前付けを行ってあります。

あなたは現にもっとも手早い手順があることをご存知でしょう。コードを選択し、切り取り、クラス内のメソッドの外側に貼り付け、Refactor! はメソッドを自動的に抽出します。

メソッド名と呼び出し元の双方が関連付けされ、緑色のボックスでハイライトされているところに注目してください。「メソッド抽出」は自動的に「名前の変更」リファクタリングを呼び出すようになっています。もし各変数が外側と同様に選択したブロックの内側に対しても参照している場合、Refactor! は動作上適切なパラメータをメソッドに自動的に付加し、必要であればそれを戻します。

リファクタリング: オーバーロードの作成

時々、既にあるメソッドを異なるシグネチャを持つパラメータによって使用したい場合あります。
「オーバーロードの作成」はオーバーロードの作成または規定のパラメータのコピーといったプロセスを自動化します。

もうおなじみですが、今一度練習してみましょう。テキストカーソルをメソッドのシグネチャに移動。「ワンキーリファクタリング」キーを押し、オーバーロードを作成する場所を選択します(オリジナルメソッドの上または下)。次にコピーされたメソッドシグネチャより削除したいパラメータを選択し、規定値を与えます。その後、Refactor! はいくつかの適切なデフォルトコードを作成しようと試みます。

リファクタリング: プロパティの抽出

選択したコードを新しい読み取り専用のプロパティへ移動します。抽出前のコードの元の位置には呼び出しのための適切なコードを挿入します。

プロパティの抽出は使用頻度が高い式を見つけた場合に、コードの大部分を新しい読み取り専用プロパティへと移動したい場合に役立ちます。
頻繁に用いられる式をプロパティとすることによって重複したコードがなくなり、コードが読みやすくなります。

リファクタリング: ローカル変数の導入

選択した式を使用して初期化される新しいローカル変数を作成します。状況に応じ、コードブロック内の式の全ての使用箇所を新しく定義されたローカル変数の参照に置き換えます。

 Button1.Text = "Hello World"

これは

 Dim lNewVariable As String = "Hello World"
 Button1.Text = lNewVariable

となります。

ローカル変数の作成は、コードブロック内に複雑な式や繰り返し何度も使われる計算があるとき、これらのいくつかの計算式を1回の呼び出しにまとめる場合に役立ちます。
これはコード管理の複雑化を減らすための手助けとなるでしょう。なぜなら、将来のコード変更は1箇所への隔離なのだから。
また、ローカル変数の作成はローカル変数を使用した計算式のコードの可読性、メンテナンス性改善のためにコードの置き換えを行う場合にも、ローカル変数が何の計算をしているのかが名前で判断できるため便利です。

リファクタリング: インライン化

ローカル変数への全ての参照を初期値に置き換えます。いわば、「ローカル変数の作成」リファクタリングの逆です。

 Dim AreaOfCircle As Integer = GetAreaOfCircle(Radius)
 Return AreaOfCircle * Height

これは

 Return GetAreaOfCircle(Radius) * Height

となります。

インライン化もまた、メソッドやプロパティに抽出されたコードブロックを評価したい場合に役立ちます。もし、選択されたコードブロックがそのブロックよりも前に定義されたローカル変数を参照していた場合、それらの参照をインライン化することによってローカル変数に依存したコードを排除することができます。

リファクタリング: 問い合わせによる一時変数の置き換え

ローカル変数のすべての呼び出しを変数の初期値を返すメソッドやプロパティによって置き換えます。
「問い合わせによる一時変数の置き換え」リファクタリングはクラス内部のその他のメソッドまたはプロパティから使用可能なメソッドまたはプロパティにすべきローカル変数が存在する場合に使用すると便利です。また、メソッド内のローカル変数の数を減らす際にも役立ち、メソッドの抽出やその他のリファクタリングによって内部的な依存性が減少します。

リファクタリング: 一時変数の分割

このリファクタリングは開発者がブロック中で別の目的で変数を再利用せずに新たに変数を作成したほうが良いといった問題を解決します。

図8. 変数 lSayHello はこのコードによって別の結果に置き換えられている。

これは変数の意味がその場所によって意味が変わるため、コードを理解することが困難となるので、悪い例としてアンチパターンの1つとされています。

図9. 「一時変数の分割」が新しい変数を作成して名前付けを行った後、「名前の変更」リファクタリングを起動します。

このリファクタリングは同じ変数に対して複数の割り当てを行う代わりに新しい変数を追加します。この際、変数の名前を何か意味のあるものにする機会を与えてくれます。

リファクタリング: 初期化の宣言への移動

ローカル変数の宣言と初期化または初期値の割り当てを1本化します。これは「初期化と宣言の分割」リファクタリングの逆です。

 Dim lSayHello As String
 lSayHello = "Hello World"

これは

 Dim lSayHello As String = "Hello World"

となります。

リファクタリング: 初期化と宣言の分割

このリファクタリングはローカル変数の初期化されている宣言を宣言と独立した初期化ステートメントに分離します。これは「初期化の宣言への移動」リファクタリングの逆です。

変換例

 Dim lSayHello As String = "Hello World"

これは

 Dim lSayHello As String
 lSayHello = "Hello World"

となります。

リファクタリング: 宣言を参照の近くに移動

ローカル変数の宣言ステートメントを最初の参照の近くに配置します。
このリファクタリングにより、宣言の配置が最適化されるため、読み取り可能な最大量が増します。
これはブロック内において排他的に使用する変数がある場合には「メソッドの抽出」等のようなリファクタリング中にブロック内で宣言を移動することができるため、特に効果があります。

リファクタリング: 条件記述の反転

この単純なリファクタリングは if ステートメントの条件式の反転や Then ブロックと Else ブロックの入れ替えを行います。

変換例

  If Radius <> 0 Then
     Return 3.14159 * Radius * Radius
 Else
     Return 0
 End If

これは

  If Radius = 0 Then
     Return 0
 Else
     Return 3.14159 * Radius * Radius
 End If

となります。

リファクタリング: 式の単純化

このリファクタリングは Quine/McClusky 単純化アルゴリズムを使用して、条件ステートメントの単純化を行います。
これは不必要な括弧の削除や否定式の切り替え、パラメータの順序変更、その他、式の戻り値に影響を与えることなく、式全体の読みやすくします。

(例) not (A<>0) をより単純に変換すると、A=0 となる。

条件式は機能性が増すにつれ増大してゆく傾向にあります。容易に条件式を簡素化できるということはコードを読みやすさをすばやく改良するための非常に低コストな方法となります。

リファクタリング: 定数の導入

このリファクタリングは文字列または数値を新しい定数に変換します。その際、定数に意味のある名前を与える機会を与えます。

変換例

 Private Function GetArea(ByVal Radius As Integer) As Integer
     Dim Area As Integer = 3.14159 * Radius * Radius
     Return Area
 End Function

これは

 Const Pi As Double = 3.14159
 Private Function GetArea(ByVal Radius As Integer) As Integer
     Dim Area As Integer = Pi * Radius * Radius
     Return Area
 End Function

となります。

「定数の導入」はマーチン・ファウラーのリファクタリングブックで述べられている、「シンボリック定数によるマジックナンバーの置き換え」と同じです。しかしながら、「定数の導入」は数値に加えて文字列もサポートします。

リファクタリング: フィールドのカプセル化

フィールドのカプセル化はフィールドを新たに宣言された読み書き可能なプロパティに置き換えます。

図10. SayHello フィールドをプロパティとして抽出します。

このリファクタリングはデータのすべての要求に対していくつかのアクセスロジックの追加を必要とする場合に使用します。
新しいプロパティは以前のフィールドと同じ名前を付けられます。この時、「名前の変更」リファクタリングが起動され、すべての参照が関連付けられますので、プロパティにさらに意味のある名前を付ける、絶好の機会となるのではないでしょうか。

図11. 新しい SayHello プロパティによってプライベートの _SayHello フィールドを参照する

まとめ

Refactor! は Visual Basic.NET 2005 開発者にとってコード単純化のパワフルなツールスイートです。各ツールはエディタのコード上で動作するため、従来のようなモーダルダイアログを使用した方法のように操作性が低下したり、コードから離れることなく、迅速に操作を行うことができます。

Refactor! のもっとも重要な特徴はリファクタリングをしやすくしてくれるところであり、コード構造の改善とともに、リスク面の削減ともちろんコストの面でも削減を図ることです。

C#の開発者は Visual Basic.NET と C# の両言語をサポートしている Refactor! Pro を購入することにより、Refactor! のアドバンテージを得ることができます。
Refactor! Pro は Visual Studio 2005 上の両言語のサポートだけではなく、Visual Studio.NET 2002 や Visual Studio.NET 2003  にも対応しています。
さらに、追加のリファクタリング機能があるのだけではなく、他のマネージ言語に対応したリファクタリングツールを自分で作成することも可能となります。

さらに詳しい情報は http://www.devexpress.com/Refactor

Refactor! for Visual Basic 2005 の入手(無償) http://www.devexpress.com/VBRefactor

 

印刷 | 閉じる