リファクタリングとは、正常に動いているプログラムのソースコードを整理し、冗長なコードを削除したり、分かりにくいコードを分かりやすく変更することです。
バグの修正とは異なり、プログラムの動作は変えません。プログラムの内部構造を分かりやすくすることで、将来のコード変更時にコード理解のスピードアップ、新たなバグを作り込みにくくなる、など、メンテナンス性の向上につながります。
文章でいうと推敲のイメージです。書き終わったばかりでは冗長な言い回し、分かりにくい部分があるので、推敲することで読み手に分かりやすい文章にします。
リファクタリングと聞いてイメージできない方も多いでしょう。要は「コードの質を高める作業」という意味です。本記事ではリファクタリングの具体的な方法や効果について紹介しています。以下で詳しく見ていきましょう。
目次
リファクタリングとは?基本的な意味や特徴を解説
リファクタリングは、使用者からみたプログラムの動きは変えずに内部的なソースコードを変更するコード変更のことです。
リファクタリングすることでソースコードが見やすくなり、似たようなソースコードが整理されるので、自分だけでなく他の開発者やテスト担当者がみたときに理解しやすいため、ソフトウェア開発の作業効率アップにつながります。
また、ソースコードが整理されているためバグの修正、トラブルでも迅速に対応できるメリットもあります。
リファクタリングの意味・定義
コンピュータプログラミングにおいて、外部からみたプログラムの動きは変えずにプログラムの内部構造を見直し、分かりやすくすることをリファクタリングといいます。
リファクタリングの手法が開発される前は、一度完成したソースコードに手を付けてはいけない、と言われていました。理由は正常に動作したソースコードを変更したために、システム全体に影響するバグを作り込み、修正のために不要な時間とリソースを費やす可能性があるからです。
そのため、ソースコードの分かりやすさ、保守のしやすさの観点から整理されたプログラムを日常的に書いていく考え方が生まれました。
また、リファクタリングの手法(主な例:関数としてまとめる、命名の改善、条件分岐の低減)の総称として使われることもあります。しかし、十分に確立した技術ではなく「リファクタリング」に厳密な定義はありません。
リファクタリングの特徴と目的
完成したプログラムでも、変更はよくあります。ソフトウェア開発では、初期の開発のため仕様が不十分で改善したい、機能を追加したい、バグを修正したい、などよくあります。
そのとき、分かりにくいソースコードだと、内容の理解に時間がかかり、万が一誤った理解をした場合バグを作りこんでしまいます。
さらに、限られた時間の中で変更を行うため、ソースコードの簡素化を考える余裕はなく、最低限の必要な変更、追加をするのでソースコードが継ぎはぎのようになるのです。
そこで、ソース―コードが整理されていると内容の理解に時間がかからず、バグを作りこむ可能性も低くなるため、効率よく変更できます。
ただし、リファクタリングの結果、正しく動いていたプログラムが動かなくなることは避けなければならない、変更点の十分なレビュー、テストは行う必要があります。
リファクタリングのメリット・デメリットを整理
ソースコードが分かりやすければ、ソフトウェア開発者の内容理解のスピードアップ、変更時のバグの作りこみリスク減、メンテナンス性の向上などメリットばかりですが、一方でリファクタリングのデメリットもあります。
正常に動作していたプログラムに手を加えるため、もともとの動作に比べてプログラムの動きが悪化する先祖がえり(デグレード)は避けなければなりません。ここでは先祖がえりも含めてメリット・デメリットを整理します。
リファクタリングをするメリット
コードの複雑性が下がる
ソースコードの複雑性を下げる主な手法として、以下3点があります。
項目 | 内容 |
関数の機能分割 | 1つの関数内で複数の処理を実行していた場合、それを細分化し処理単位の関数に分割する。 |
冗長なソースコードの排除 | 冗長なソースコードがあった場合、処理を見直し簡素化したものに変更する。必要に応じて関数、クラスに分割してもよい。 |
明瞭な命名規則 | 分かりにくい関数名、変数名などを分かりやすく見直す。命名規則は事前に開発者同士で決めておくとよい。 |
複雑性が下がることでソース―コードが整理され、内容の理解に時間がかからない上に、バグを作りこむリスクも下げられるため、保守性の向上につながります。
また、ソースコードが簡素化されるためプログラムの処理速度のアップもメリットとして挙げられます。
コードの再利用性が上がる
似た処理が複数カ所に実装されたソースコードの場合、関数化、クラス化することで1つにまとめられます。使用したい場所でこの関数を呼び出すことで再利用できます。
また、既存のソースコードをより一般的な形で抽象化する手法もあります。抽象化することで汎用性が上がり、より再利用しやすいコードとなります。再利用することで関数化したモジュール単位でのテストが可能になり、テスト効率のアップにもつながります。
また、ソースコードの再利用はオブジェクト指向のプログラムと相性がよいです。もともとオブジェクト指向型プログラミングもコードの再利用性を重視しているため、Javaなどオブジェクト指向型プログラムであれば種類を問わずに適用できます。
バグが減少する
リファクタリングによりソースコードが簡略化すると、バグの発生するリスクが低減します。開発当初など時間が限られているため、最初から分かりやすいソースコードを書くことは難しいです。しかもソースコードを書いた本人も、しばらくたってから見直すと忘れていることもよくあります。
そこでリファクタリングにより、シンプルなコード、冗長なコードの排除、分かりやすい関数名・変数名に見直されたソースコードは理解も早いです。その上コードの誤りや不具合を見つけやすいため、誤用や混乱が減少します。
また、別の開発者やテスト担当者が見ても分かりやすいため、デバッグのしやすさ、バグの早期発見、将来的にバグの原因になりそうなところも推測できます。
リファクタリングのデメリットも知っておこう
リファクタリングに時間と労力がかかる
すでに正常に動いているプログラムなのでそのままでも問題はありませんが、将来的なメンテンナンス性を考えると、プログラムの内部構造の見直しが必要です。
リファクタリングでソースコードを分かりやすくするには、時間と労力が必要で、短期的にみるとコストが増えるのでデメリットです。
しかし、リファクタリングは機能追加やバグ修正によるコードの複雑化の防止、バグの早期発見につながるため、プロジェクト全体のコストの低減に効果的です。
プロジェクト全体として得られる効果と、リファクタリングにかかる時間と労力を比較し、コストを考える必要があります。
一時的にバグが増える可能性がある
一時的にバグが増える主な原因として進め方があります。一般的に正常な動作に影響しないように変更範囲を小さく区切りながら進めます。
変更の範囲を大きくすると、コードの構造やデザイン変更の範囲が把握しにくく、問題が発生した時の原因の特定に時間がかかります。また新規コードの追加で、既存のコードと動作の不整合も出てきます。
正常に動いているプログラムを変更するので、一時的にバグは増えますが、広範囲に手を加えず、小さく範囲を区切りながら変更とテストを繰り返す方法がおススメです。
バグが増える時期は一時的であるべきで、リファクタリングしたソースコードは分かりやすくなり、将来的なメンテナンス性も向上します。
リファクタリングミスで思わぬ不具合が発生するリスクがある
よくあるのが未定義の動作、条件分岐の誤りです。もともと正常に動作しているプログラムで、ソースコードを誤って理解したために定義されていない処理がバグを引き起こし、プログラムの動作が変わるケースです。
また、条件分岐(if文やswitch文など)でも正確に仕様を理解できないまま、コードを変更したために誤った経路をたどり、誤った結果になるケースです。
あと、メモリリークにも注意が必要です。一見すると正常に動作しているのですが、プログラムがメモリを適切に開放しないまま実行されるとメモリリークが発生します。実行を繰り返さないと発見できないため、テストも重要です。
いずれも作業前のレビューで対策できます。開発者同士のコミュニケーションをよく行い、誤った理解の回避、テスト観点などを共有しながら進めることが重要です。
リファクタリングの具体的な方法と手順
冗長なソースコードの排除、条件分岐の見直し、変数名の命名規則を行うと構造が単純化されるため、分かりにくいソースコードが原因のバグやシステムの劣化を防止できます。
分かりにくいソースコードは他者だけでなく本人も解読が難しく、ロジックを変更するときに負担がかかり、システム全体の保守性が低下します。
リファクタリングでは、様々なコード改善の作業が行われます。代表的な内容とプロセスの手順を解説します。
リファクタリングで行う代表的な作業
変数やメソッド名の変更、重複コードの除去、コメントアウトコードの削除、メソッドの抽出、インターフェースの抽象化など、コードの可読性・保守性・拡張性を高める様々な作業があります。
可読性を高めるリファクタリング
ソースコードの分かりやすさを表します。分かりやすいソースコードは他の開発者やテスト担当者がみたとき容易に理解でき、作業効率がアップします。
リファクタリングの主な手法は以下の3点です。
項目 | 内容 |
変数やメソッド名の変更 | 分かりやすい変数名やメソッド名に変更することで、処理の目的が明確になり開発者やテスト担当者が理解しやすくなる。 |
メソッドのパラメーターの削減 | メソッドで使用しているパラメーターの数を見直し、パラメーター数を削減することでメソッドの処理が理解しやすくなる。 |
変数の抽出 | (変数名ではなく)ソースコードの条件や複雑な式を変数に置き換えることで処理の目的が理解しやすくなる。 |
保守性を高めるリファクタリング
ソースコードの修正、変更、追加のやり易さを表します。手を加えやすいソースコードはバグの修正や機能の追加を容易にし、新たなバグの作り込みを低減します。
主な手法は以下の3点です。
項目 | 内容 |
重複コードの除去 | 同じコードをまとめて一つの場所に実装することで影響カ所が把握しやすくなるのでコードを変更しやすくなる。 |
条件分岐の単純化 | 複雑な条件分岐を単純化することで変更の個所が特定しやすくなり、コードの変更が容易になる。 |
コメントアウトコードの除去 | 使われていないコード、コメントを削除すると必要な処理だけになり、不要なコードの理解がなくなるので変更カ所が特定しやすくなる。 |
拡張性を高めるリファクタリング
新たな機能や要件の追加のしやすさを表します。柔軟に対応できるソースコードは拡張性の高いソースコードと言えます。
主な手法は以下の3点です。
項目 | 内容 |
メソッドの抽出 | 一つのメソッドで複数の処理を実装していた場合、処理単位にメソッドを分割することで、新たな機能を追加しやすくなる。 |
クラスの抽出 | 一つのクラスで複数の処理を実装していた場合、処理単位にクラスを分割することで、新たな機能を追加しやすくなる。 |
インターフェースの抽象化 | 抽象化したインターフェースを設けることで汎用性が向上し、新たな実装を追加しやすくなる。 |
リファクタリングのプロセスと手順
まず問題点の洗い出しから始め、リスク分析、実際のコード修正、テスト実施と段階的に進めていきます。コードレビューも重要なプロセスです。新たなバグの導入を避けるため、チーム内でコミュニケーションをとりながら慎重に進めましょう。
問題点の洗い出し
まず、チーム内でレビューを行い問題点の洗い出しを行います。普段、開発者が目にしているソースコードから、主に以下のポイントで抽出を行います。
-
- 分かりにくいコード
- 改善できそうなコード
- バグの件数が多いコード
- 処理が遅いコード
このとき、その理由と改善の方法も一緒にレビューし、まとめることをおススメします。
理由と改善の方法も一緒にまとめておくと、問題点とその理由と改善の方法が一つの情報として残るので、読み返したときに分かりやすいです。
さらに、次回のリファクタリングで同じレビューを省略でき、時間短縮になります。また、リストに残すことで、優先度から今回のリファクタリングを見送られたソースコードも、次回はリファクタリング対象として再検討できます。
リスク分析
問題点を洗い出したので、次はどのソースコードをリファクタリングの対象にするかを決めます。
リストに上がったすべてのソースコードを対象にできればよいですが、様々なリスクを考慮し優先度を決めます。主に以下のポイントで優先度をつけます。
-
- 可読性・保守性・拡張性からシステム全体のメリットを推測
- ソースコードが難解でバグを作りこむリスク
- 影響範囲が広く期間内にリファクタリングが完了しないリスク
- 十分なテスト期間が確保できないリスク
リファクタリングの注意点は、新たなバグを作りこまないことです。
システム全体でみたメリットと注意点を守るためのリスクを比較し、優先度をつけるとよいでしょう。
コードの修正
リファクタリング対象が決まったので、コードの修正に入ります。ここで気を付けることは一度に広範囲のコード修正は避け、できるだけ小さい範囲を進めていくことです。
主に以下の3つの流れで進めます。
-
- 変更の計画
- 小さな変更から進める
- リファクタリングの実施
変更の計画でリファクタリングの計画を立てます。対象範囲が広い場合は、段階的に進めるため計画は有効です。対象のソースコードごとに修正の手法もここで選定します。
計画に従い、小さな範囲に区切りながらリファクタリングを進めます。一度に広範囲に手を付けると手戻りが大きくなり、作業効率が低下します。小さい範囲で進めることで問題があったときの効率を落とさずに進められます。
テストの実施
テストは、リファクタリングで先祖がえりを確認するために重要です。
ソフトウェア開発の一般的なテスト計画と異なり、リファクタリングでは作業前のテストを追加で行います。主なテストの流れは以下の通りです。
-
- テストケースの作成
- テストの実行(リファクタリング前)
- リファクタリング
- テストの実行(リファクタリング後)
- 結合テスト
- レグレッションテスト
- パフォーマンステスト
テストケースの作成は修正時のリファクタリングの手法を参考にします。また、既存のテストケースの流用も可能です。
テストの実行(リファクタリング前)は、変更前のプログラムの動作を確認します。同じテストケースをリファクタリング後にも実行し、動作の比較を行います。
そのあとの結合テスト、レグレッションテストは、他のモジュールと組み合わせて既存の動作に影響がないことを確認します。最後のパフォーマンステストは、メモリリーク、パフォーマンスを検証します。
いずれのテストも正常動作を確認後、ソフトバージョン管理システムにソースコードを登録します。
コードレビュー
意図通りの変更だったか、開発者同士でソースコードをレビューします。レビュー対象は主に以下です。
-
- 変更の目的と意図
- コードの変更(冗長なメソッドや関数、重複したコード、冗長なクラス、複雑な条件分岐)
- 変数・関数名の命名規則
- パフォーマンス
- ドキュメントへ変更点の追加
変更の目的と意図も含め関係者でレビューします。ソースコードのレビューではレリファクタリングの前後が比較できると分かりやすいです。
リファクタリング後はパフォーマンスが向上するのが一般的です。パフォーマンス向上により処理の前後が入れ替わり、正しく動作しないこともあるので注意が必要です。
合わせて、リファクタリングの成果を資料にまとめ、関係者と共有すると次回につながりやすいです。
リファクタリングのテスト方法とツール
リファクタリングで先祖がえりを発生させないために、レビューの他にテストも行います。テストを行うことで予期しないバグを摘出できるため重要なプロセスです。
また、リファクタリング前のテストを行います。これはリファクタリング後のプログラムの動作が変更前と同じことを確認するためで、一般的なソフトウェア開発のプロセスと異なる点です。
リファクタリング後の動作確認方法
「テストの実施」でもご紹介しましたが、リファクタリング後のプログラムが期待通りに動作するか、テストで確認します。
一般的には、単体テスト、組み合わせテスト、システムテスト、レグレッションテスト、パフォーマンステストの流れで進めますが、リファクタリングでは変更前のテストを行い、同じテストケースで変更後も行います。変更前と後のテストを行うことで、ブログラムの動作の違いを確認し、先祖がえりを防ぎます。
リファクタリング支援ツールの紹介
おススメの支援ツールは以下の2つです。
OpenRewriteは、リファクタリングにおけるコードの変換や、プラグインが豊富で、オブジェクト指向プログラミングJava向けに開発されています。
コード変換でよいのは、ソースコードを抽象構文木(AST)として表し、ASTレベルで変換したあとコードに落とすので、コードの意図を変えずに変換できる点です。
またリファクタリングのプラグインも豊富で、冗長なコードのインスタンス化、不要コードの削除、ネストの深い条件分岐の改善など、コマンドを実行するだけで実現できます。
さらにJava向けに開発されているため、コードのコンバート(例:記載ルールをJava8→Java11へ変更)もできます。プログラム言語も定期的にバージョンアップされるので、コードのコンバートは有効です。
Lattixは、プログラムの構造や影響範囲を分析し、ソフトウェアの品質を定量的に評価するツールです。ソフトウェアの構造を俯瞰的に可視化できるため、構造上の問題点から改善につなげるために役立ちます。Java、Pythonもサポート対象です。
また、ソースコード変更時の影響分析も可能なので、変更によるソフトウェア品質の変化を把握できます。リファクタリングに活用すると、開発者の主観ではなく、定量的にリファクタリングの効果の高いソースコードを選択できます。
さらに、リファクタリングの結果を評価することで、効果の確認が可能です。継続して利用することで、ソフトウェア品質の向上につながります。
おすすめのリファクタリング関連書籍・参考書
ソフトウェア開発者のキャリアを積み、ソースコードを見ていて、なんとなく分かりにくい、私だったらこう書く、と思うときがあります。
初心者のときに書いたコード、他の開発者が書いたコードなど特に目につきます。リファクタリングで改善できるので、興味がある方に以下をおススメします。
以下の2冊は、リファクタリングについて体系的にまとめられ、また実用書としても活用できます。
「リファクタリング(第2版): 既存のコードを安全に改善する 」
Martin Fowler氏の名著が第2版として刷新されました。旧版は当時注目されたプログラミング言語Javaベースで書かれていましたが、第2版はJavaScriptになり、それに合わせてサンプルコードも変更されています。
初心者の目線に合わせて「コードの不吉な臭い」「リファクタリングはじめの一歩」の章にまとめられ、共感しながら読み進められます。また、サンプルコードもJavaScriptに更新されたので、個人のブラウザ上で自習しながら、オブジェクト指向の理解にも役立ちます。
「Java言語で学ぶリファクタリング入門」
こちらはプログラミング言語Javaを使ってリファクタリングを紹介しています。
6つの「不吉な匂いを示すセリフ」を上げ、リファクタリングの必要なコードの見つけ方を分かりやすく紹介しています。また「問題点と改善方法」で章立てされているので、知りたいことから章を選んで読むことも可能です。全体的に口語的で分かりやすく、適度に間隔・スペースがあるので読みやすいです。
本書を読むためにJava言語の基本的な知識が必要です、合わせて同著者の書籍もご案内します。
リファクタリングのまとめ
リファクタリングをすることで、ソースコードの可読性・保守性・拡張性が改善し、メンテナンス性が向上します。しかし、正常に動作しているプログラムを変更するので、新たなバグを作りこむリスクも発生します。
新たなバグの導入を回避するために、コードの変更は小さく区切って進めます。また、開発者同士のレビュー、進捗の共有など、コミュニケーションを取ることで予期せぬ問題を回避することができます。
プロジェクト全体で得られる効果と、リファクタリングにかかる時間と労力を比較することが重要です。
リファクタリングを効率よく進めるには、入門書、支援ツールの導入がおススメです。また、実績のある開発会社に依頼するのも効率的です。
リファクタリングに関する質問やご相談、開発会社の選定に迷った場合は株式会社Jiteraへの問い合わせください。貴社の要件をみたすアドバスができると期待します。