特集

.NET開発者のためのリファクタリング入門

株式会社ピーデー 川俣 晶
2004/12/08

Page1 Page2 Page3 Page4

◆データに関する書き換え

 このカテゴリは、「フィールドのカプセル化」(getXXXやsetXXXなどのアクセサ・メソッドを利用してクラスのメンバ変数を書き換える)や、「サブクラスによるタイプコードの置き換え」(データの分類を示す定数値などを派生クラスにより置き換える)、データに関する書き換えを含む。

 これらは比較的よく行われる書き換えと思われるので、この記事ではサンプル・コードによる紹介は割愛する。

 ただしフィールドのカプセル化を行う場合、『リファクタリング プログラミングの体質改善テクニック』ではアクセサ・メソッドへの置き換えを行うが、Visual Basic .NET(やC#)ではプロパティへの置き換えの方が望ましい、といった相違が発生することに注意が必要である。この書籍で紹介されているリファクタリング・カタログは、主にJava用ということになるが、プログラム言語が変わればそれに応じてカタログの一部を補正して適用する必要も発生する。そのような変更は、何らリファクタリングの理念を損なうものではなく、より的確にリファクタリングを行うために必要とされるものだろう。

◆条件記述の単純化に関する書き換え

 このカテゴリは、条件判断の記述の書き換えを含む。例えば、すでに紹介した「制御フラグの除去」や、連載:熱血VBプログラマ応援団「第11回 継承とは隠された条件判断である」で解説しているような「ポリモーフィズムによる条件記述の置き換え」などを含む。

 このカテゴリで特に筆者が注目するのは「ヌルオブジェクトの導入」である(注:カタカナで「ヌル」という表記はnullの発音として必ずしも適切ではないが『リファクタリング プログラミングの体質改善テクニック』の表記を踏襲している)。

 ヌルとは、Visual Basic .NETでの「Nothing」に相当するものである。Nothing値のチェックが繰り返し現れるとき、「ヌルオブジェクトの導入」を行うことができる。

 Nothing値のチェックが繰り返し現れる、というのは、例えば以下のようなケースである。

Public Class ログ
  Public Sub 書き込み(ByVal メッセージ As String)
    Console.WriteLine(メッセージ)
  End Sub
End Class

Public Module メイン処理
  Public Sub 処理実行(ByVal 記録先 As ログ)
    If Not 記録先 Is Nothing Then
      記録先.書き込み("処理を開始します")
    End If
    ' ……何かの処理……
    If Not 記録先 Is Nothing Then
      記録先.書き込み("処理進行中")
    End If
    ' ……何かの処理……
    If Not 記録先 Is Nothing Then
      記録先.書き込み("処理を完了しています")
    End If
    ' ……何かの処理……
    If Not 記録先 Is Nothing Then
      記録先.書き込み("処理を終了しました")
    End If
  End Sub
End Module
リスト8 Nothing値のチェックが繰り返し現れるコード例

 ここでは処理実行メソッドの引数がNothingでなければ、引数のオブジェクトを通じてログへの書き込みを実行している。そのため、書き込みを行う回数と同じ数のNothing値の判定が記述されていて煩雑である。しかし、この判定を単に取り除くことはできない。Nothing値を持つ引数を経由して書き込みメソッドを呼び出すことはできないためである。

 このサンプル・コードからNothing値の判定を取り除き、シンプルにするには、「ログ」クラスを継承して、何も出力しない「ヌルログ」クラスを作ることである。そして、Nothing値を渡す代わりに、ヌルログ・クラスのインスタンスを渡すようにすればよい。以下にそのように書き換えた例を示す。

Public Class ログ
  Public Overridable Sub 書き込み(ByVal メッセージ As String)
    Console.WriteLine(メッセージ)
  End Sub
End Class

Public Class ヌルログ
  Inherits ログ
  Public Overrides Sub 書き込み(ByVal メッセージ As String)
  End Sub
End Class

Public Module メイン処理
  Public Sub 処理実行(ByVal 記録先 As ログ)
    記録先.書き込み("処理を開始します")
    ' ……何かの処理……
    記録先.書き込み("処理進行中")
    ' ……何かの処理……
    記録先.書き込み("処理を完了しています")
    ' ……何かの処理……
    記録先.書き込み("処理を終了しました")
  End Sub
End Module
リスト9 リスト8にヌルオブジェクト(「ヌルログ」クラス)を導入した例

 後は、処理実行メソッドを呼び出す際、「メイン処理.処理実行(Nothing)」と記述していたところを、「メイン処理.処理実行(New ヌルログ)」と書き換えるだけでよい。

 この「ヌルオブジェクトの導入」は、Visual Basic 2005やC# 2.0で導入される予定のNullableな(Nothing/nullという値を取り得る)データ型とは想定する対象が異なることに注意が必要である。これらのデータ型は、Nothing/nullという値を取ることができないデータ型(整数など)が、Nothing/nullという値を取ることができるようにしてくれる効能がある。それに対して、「ヌルオブジェクトの導入」はもともとNothing/nullという値を取ることができるデータ型に対して、Nothing/null値を渡さないようにする書き換えである。

◆メソッド呼び出しの単純化に関する書き換え

 このカテゴリは、メソッドの名前の変更や、引数の変更などを含む。興味深いものも多いのだが、比較的分かりやすいものが多いと思うので、具体的なサンプル・コードを使っての紹介は割愛する。

◆継承に関する書き換え

 このカテゴリは、継承関係にあるクラス間でメソッドやメンバ変数を派生クラスに移動させたり、基本クラスに移動させたりする書き換えや、委譲と継承の置き換えなどを含む。比較的込み入った話が多くなり、サンプル・コードも長くなりがちで記事に収まりそうもないので、具体的なサンプル・コードを使っての紹介は割愛する。

リファクタリングとツール

 リファクタリングを行うに当たっては、2種類のツールが役に立つ。1つは、リファクタリングの書き換えを自動化するツールである。もう1つは、単体テストのフレームワークである。

 ここで注意が必要なのは、リファクタリングの自動化ツールの役割である。多くの人たちがリファクタリングのツールとして思い浮かべるのは、このリファクタリングの書き換えを自動化するツールであることが多いように思われる。しかし、彼らの話を聞いてみると、これには二重の誤解が含まれているケースがしばしばある。

 第1の誤解は、このツールを使わないとリファクタリングができないという思い込みである。リファクタリングはソース・コードを書き換える作業にすぎず、テキスト・エディタを使って書き換えてもリファクタリングはできる。

 第2の誤解は、ツールを操作すれば、それだけでリファクタリングが完了できるという思い込みである。残念ながら、ツールは直接的なソース・コードの書き換えを自動化してくれるだけで、どこを書き換えるべきかは教えてくれない。つまり、リファクタリングの知識がなくても、ツールがあればリファクタリングできるというわけではない。そして、ツールは残念ながらリファクタリング・カタログに含まれるすべての書き換えを自動化してくれるわけではない。ツールがサポートしていない書き換えは、プログラマが手動で行う必要がある。

 これらの制約があるとしても、リファクタリングの自動化ツールはリファクタリング作業の効率アップのために有益であり、導入を検討する価値がある。

 しかし、リファクタリングに真に必須のツールはもう1つの単体テストのフレームワークの方である。こちらは、なければほぼリファクタリングは不可能になるといってもよいぐらい重要なものである。

 一体なぜ重要なのか。

 その理由は、ソース・コードを書き換えてよい理由と直結している。すでに、以下のように書いた。

 一方、問題なく動いているコードを書き換えることは、明らかにまずい選択であるというのが経験的な真理である。書き換えれば、どこにバグが混入するか分からない。

 このような問題があるにもかかわらず、リファクタリングはソース・コードを書き換えることを求める。それが可能になるのは、「自動化された単体テスト」というテクニックを併用することが前提であるためである。そして、「自動化された単体テスト」を行うために、ほぼ必須となるのが単体テストのフレームワークというツールである。

 自動化された単体テストとは、メソッドなどを呼び出して戻ってきた値をチェックするテスト・メソッドの集合体である。ソース・コードを書き換える前に、書き換える対象のテスト・メソッドを記述しておけば、誤った書き換えを行った場合に即座にそれを検出することができる。ここですでに書いた以下の文章を思い出していただきたい。

 リファクタリングによる書き換えは、常にソース・コードの一部分だけを、機能を変えない形で行われる。つまり、リファクタリングを適用してもプログラムの機能は一切変化しない。

 つまり、リファクタリングによる書き換えに機能変更はあり得ない。そのため、事前に作成したテスト・メソッドは、(呼び出し対象のメソッドのインターフェイスに変更がなければ)リファクタリング後にも有効なテストとして機能する。以下のような手順で書き換えを行えば、それは100%の保証ではないものの、かなりの安全性を維持できるといえる。

(まだ作っていなければ)テスト・メソッドの作成
テスト・メソッドを実行し動作確認
リファクタリングによる書き換え
再度テスト・メソッドを実行し動作確認
(その後も頻繁にテスト・メソッドを実行し、機能が壊れていないか確認)

 逆にいえば、この手順を守らないリファクタリングは、一切行うべきではない。時として、リファクタリングはよいことなのに実行したら怒られたという話を聞くことがあるが、もし上記手順を守らない書き換えを行っているのであれば、それは怒られて当然である。

まとめ

 プログラミングの世界には、宗教的、信念的、盲目的な要素が入り込みやすい。それに対して、リファクタリングは科学的、合理的、形式的なスタイルを導入する。

 例えば、「現実に存在するものと対応するクラスを定義すればプログラムがうまく構築できる」と思うのは宗教的な態度である。なぜなら「現実に存在するもの」という概念が抽象的すぎるし、異なる法則性が支配する物理世界とプログラミングの世界を同じモデルで扱うことが最善であると考えるのは根拠が薄弱であり信念的である。そして、それがうまく機能しなかったとき、もともと無理のある方針であったことに気付かないのは盲目的である。

 これに対して、リファクタリングは具体的にそこにあるソース・コードに着目し、そこに見える文字の並びのパターンだけを見て、意味を解釈しない。着目するものは誰が見ても同じに見えるものだけに限られるという意味で客観性があり、科学的といえる。

 そして、リファクタリングによる書き換えには過去の経験の集積に基づく合理的な理由が与えられる。さらに、内容を考慮することなく、あらかじめカタログで与えられたパターンからパターンへ形式的な書き換えが行われる。形式的であるということは、抽象的な信念と異なり、誰もが共有できるということである。その点で、リファクタリングは人と人との共同作業の安定した基盤になり得るものである。

 このような特徴を持つリファクタリングではあるが、これはいわゆる「銀の弾丸」(何もかも解決してくれる万能解)ではない。リファクタリングは、機能を追加するわけでもなければ、バグを見つけてくれるわけでもない。あくまで、ソース・コードをよりシンプルにしてくれるだけである。

 故に、本当にプログラマが活躍するのは、リファクタリングの終了後といえる。より正確にいえば、プログラマが活躍したいと思っているのに、それを阻むソース・コードの混迷を打ち払い、活躍の場を生み出すのがリファクタリングといえるだろう。もし、解決すべき問題を持ちながら手に負えないソース・コードに困っているのなら、リファクタリングを試してみてはいかがだろうか?End of Article

 

 INDEX
  [特集] プログラミングの生産性をアップするリファクタリング入門
    1.リファクタリングの目的
    2.何のためにソース・コードを書き換えるのか?
    3.リファクタリング・カタログ(1)
  4.リファクタリング・カタログ(2)/リファクタリングとツール
 


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間