正しい”関数リファクタリング”を理解しよう

はじめに

 本記事はソフトウェア技術関連する記事です。
 特定のプログラミング言語に限定した技術ではありません。但し、言語毎に「関数」と呼ばず「メソッド」と呼ぶなど用語の違いはあります。その点については、単語を置き換えながら記事をご覧下さい。

 関数リファクタリングは、様々なリファクタリング技術の中で、最も使用頻度が高い技術です。高度なリファクタリングを実践するためには、事前に関数リファクタリングが施されていなければならないケースも多々あります。
 しかしながら、間違った関数リファクタリングを身に付けてしまっているエンジニアがとても多いです。そのため、手戻りが発生したり、バグを埋め込んでしまっていたりすることがあります。リファクタリングは改善活動の一つであるため、本来良い活動のはずですが、リファクタリングに後ろ向きなエンジニアや開発プロジェクトを多く目にします。
 そこで、正しい関数リファクタリングを本記事で紹介します。この技術を習得し実践することで、品質の高いソフトウェアを構築し、その結果として現在・未来の価値を高めてもらいたいです。

本題

 正しい関数リファクタリングの方法を、「リファクタリングの動機」「関数の中のどこを切り出せば良いか?」「処理を抽出し、新規関数を作る」「改良したい気持ちを抑える」の順に説明します。

リファクタリングの動機

 この記事を読んで下さっている方は、既に何らかの理由で関数リファクタリングをしたいという考えをお持ちだと思います。関数リファクタリングをしたいと思う動機の代表的なものを3つ列挙します。その他にも皆さんが思う動機から関数リファクタリングを実践して下さい。

 ・関数の1行1行を読まないと何をする関数か理解できないため
 ・関数の一部分を他の処理でも利用したいため
 ・大きすぎる関数が原因で関数の単体テストケース数が膨大になるため

関数の中のどこを切り出せば良いか?

 関数の中のどこを切り出せば良いかと考えると、とても悩んでしまいます。何故なら、その答えが分かれば、おそらく最初から関数を分割しているでしょう。
 この処理の仕様は、、、と考えるといつまでたっても関数リファクタリングが出来ません。仕様を考えず、プログラムのブロックに着目して下さい。クローンコードのブロック、if文/for文のブロックなどです。
 次に、着目したブロックと元の関数との間で行われるデータのやり取りを確認して下さい。次の3つに分類できます。
 (1) データのやり取りが無い
   (グローバル変数、ファイル内スコープ変数を使用する場合も含む)
 (2) 元の関数のデータを使う
 (3) 元の関数にデータを渡す
(1)は何も問題がありません。(2)は新規関数に引数を設ける必要があります。(3)は新規関数に戻り値を設ける必要があります。(2)(3)は場合によっては関数リファクタリングが出来ない可能性があります。本記事では個別の詳細ケースには触れませんが、注意をして下さい。

処理を抽出し、新規関数を作る

 前節で決定した抽出するブロックに適切な名前を考えましょう。おそらくそのブロックは単一目的の処理となる小さなブロックになっていると思います。そのようなブロックの名前付けは容易だと思います。「名は体を表す」です。
 考えた名前の関数を新規に作りましょう。前節の(2)~(3)に該当するか否かで引数、戻り値も付与しましょう。中身が空でも構いませんので、コンパイル・リンクを実施しましょう(Pythonなどの言語の場合は、目視確認)。おそらく何もエラーは出ないと思います。関数リファクタリングを実施する場合は、こまめにコンパイル・リンクを実施し、ケアレスミスを即座に解消できるようにしましょう。
 次に、元のソースコードから新規関数に、ブロックをコピー&ペーストをします。しかし、多くの方がここで2つの間違いを犯します。1つ目はいきなりカット&ペーストで関数を抽出してしまいます。おそらく、関数リファクタリングでミスなんて起きないと思っているためでしょう。元のコードを崩してしまうと、元の状態に戻しづらくなります。2つ目はコピーではなくコーディング(タイピング)をしてしまうことです。コーディング(タイピング)は新たなバグを埋め込む危険性があります。元のソースコードを必ずコピーしましょう。元のソースコードを活用し、新規関数がエラーなく成立するようにしましょう。
 新規関数のエラーが無い状態になれば、元のソースコードと新しい関数を置き換えましょう。特に戻り値を設けた場合は、慎重に置き換えをしましょう。

改良したい気持ちを抑える

 本来、関数リファクタリングはここで終了です。しかし、抽出した関数を見ると、「汎用性を高めたい」「もっとこうすると再利用性が高まる」など考えてしまいます。おそらくその考えは正しいと思います。しかし、関数リファクタリングの域を超えています。それはもはや“作り直し”です。
 ここまでの説明を読んで下さった方はもうお気づきだと思います。関数リファクタリングは元のif文やfor文などのロジックを変更しません。
 リファクタリングアレルギーがある人の話を聞くと、多くの方がリファクタリングと作り直しを混同しています。「リファクタリングをする」と決めたら、それ以上の改良をしたいという気持ちは抑えましょう。本記事で伝えたい大きなポイントはここです。「リファクタリング」と「作り直し」を区別するです。本当に作り直しすべきかは、リファクタリングを済ませてから改めて考えましょう。 

おわりに

 本記事では正しい関数リファクタリングを紹介しました。ポイントは下記の3つです。
 (1) 仕様を考えず、プログラムのブロックを機械的に抽出する
 (2) 抽出する関数を完成させてから、元のソースコードと置き換える
 (3) リファクタリングと作り直しを区別する
 
 関数リファクタリングの次は、クラス/ファイルリファクタリングをぜひ習得して下さい。もしあなたがソフトウェア開発プロジェクトに所属している方であれば、あなたのプロジェクトのQCDを改善する最も効果の高い技術です。
 一方で、リファクタリングは良い活動ですが、やはり手戻りであることは間違いありません。最初から良いソースコードを作ることが最善策です。そのために、構造化分析設計やオブジェクト指向分析設計など、分析設計技法を習得して下さい。
 

関連サービス

 ・セミナーサービス
  ・リファクタリングセミナー
  ・構造化分析設計セミナー
  ・オブジェクト指向分析設計セミナー
 
 ・テクニカルサービス
  ・ソースコード解析
  ・リファクタリング実践