プログラミングでやっておきたい最低限のリファクタリング

どうも、tatsuです!

今回は私が思う、プログラミングをする上で最低限やっておきたいリファクタリングについてお話しようと思います。

※説明するにあたってプログラミング言語はjavaを使用します。

リファクタリングとは?

リファクタリングとは、プログラムの振る舞いを変えずにコードの保守性を高める作業のことです。

要はソースを綺麗にしましょうということですね。

ただ上から順番に処理を長々と書いていったコード(スパゲッティコードと言います)でも動くには動きます。

ですが、後から処理が変更になってソースコードを修正するときどう思うでしょう?

ソースコードを書いた本人は覚えているかもしれませんが、他の人がそのコードを見てすぐに理解できるでしょうか?

はたまた、処理の変更がすぐに行われるとは限りません。
何か月か経ってからソースコードを見た時に、自分が書いたものだとしても覚えているでしょうか?

 
このようなことが起きないように、最低限のリファクタリングはしておくべきです。

なので私が思う最低限やっておいてほしいリファクタリングを厳選しましたので、特に初心者の方の参考になればと思います。

最低限やっておきたい3つのリファクタリング

それでは順番にどうぞ!

マジックナンバーの定数化

まず以下のソースコードを見てください。

// 挨拶を出力するメソッド
public void outputGreeting(int greetingType){
  if(greetingType == 1){
    System.out.println("おはよう");
  }else if(greetingType == 2){
    System.out.println("こんにちは");
  }else{
    System.out.println("こんばんは");
  }
}

引数の値によって出力する挨拶の文言が変化するメソッドです。

この例でいうと、マジックナンバーは「1」と「2」です。

これは以下のようにすべきです。

public static final int MORNING = 1;
public static final int AFTER_NOON = 2;
public static final int NIGHT= 3;

// 挨拶を出力するメソッド
public void outputGreeting(int greetingType){
  if(greetingType == MORNING ){
    System.out.println("おはよう");
  }else if(greetingType == AFTER_NOON ){
    System.out.println("こんにちは");
  }else{
    System.out.println("こんばんは");
  }
}

このように数値を定数として定義しておくことで、その数字が何を意味するのか一発で分かるようになりました。

今回の例は簡単なのであまり必要性を感じないかもしれませんが、スパゲッティコードにマジックナンバーがあると結構しんどいです。笑

また、定数にしておくことでその数字を複数箇所で使用しても、変更するときに定数の値を変えるだけで済みます。

定数にしておかないと使用した箇所全てを直さないといけないので保守性が下がります。

 
といった感じでマジックナンバーを定数化することを意識してやってみてください!
また、enumクラスを使うとより良いでしょう。[Java] 覚えておきたいenumの使い方

フラグを使用しない

よく「○○Flag」を使って1が立っていたら処理を分岐させるといったプログラムを見かけます。
以下のソースコードを見てください。

int errorFlag = 0;
for(int i = 0; i < 10; i++){
  // getErrorMessageメソッドからエラーメッセージを取得
  String errorMessage = getErrorMessage(i);
  // エラーメッセージがあった場合、フラグを立ててループから抜ける
  if(!errorMessage.equals("")){
    errorFlag = 1;
    break;
  }
}
if(errorFlag == 1){
  // errorFlagが立っていた時の処理
}

通常フラグの使い方として取りえる値は0と1が一般的ですが、人によっては違う判断基準(1と2みたいな)にしているかもしれません。

その場合、errorFlagの値が何だったらエラーで何だったらエラーじゃないのかわからなくなってしまうことがあります。

なので以下のようにするとわかりやすいです。

boolean isError = false;
for(int i = 0; i < 10; i++){
  // getErrorMessageメソッドからエラーメッセージを取得
  String errorMessage = getErrorMessage(i);
  // エラーメッセージがあった場合、フラグを立ててループから抜ける
  if(!errorMessage.equals("")){
    isError = true;
    break;
  }
}
if(isError ){
  // エラー時の処理
}

どうでしょう?
型をboolean型、名前をisError(エラーかどうか)という風に変更しました。

こうすることで取りえる値はtrueかfalseに限定されるとともに、isErrorという名前にすることで「値がtrueならエラーなんだな」と理解することができます。

このように、2値を取る変数の場合はフラグを使用しない方がわかりやすいです。

また、3値以上をとる「○○種別」のような変数は、リファクタリング「マジックナンバーの定数化」でも説明したように定数化しましょう。

同じ処理を2度書かない

通称「DRYの原則」と呼ばれています。
Don’t Repeat Yourself(繰り返し同じことを書かない)という意味です。

ようは、同じ処理を複数書いていたら1つのメソッドとして抽出しましょう。
まずは以下の例を見てください。

public static void main(String args[]){
  String name1 = "○田 ○男";
  String name2 = "×山 ×子";
  
  // 苗字のみ出力する ※splitは引数の文字で分割する関数
  String[] nameArray1 = name1.split(" ");
  String[] nameArray2 = name2.split(" ");
  System.out.println("苗字は" + nameArray1[0]);
  System.out.println("苗字は" + nameArray2[0]);
}

苗字を出力する処理では名前の数だけ同じことを繰り返しています。

これを1つのメソッドに抽出してみましょう。
その結果が以下になります。

public static void main(String args[]){
  String name1 = "○田 ○男";
  String name2 = "×山 ×子";
  
  // 苗字のみ出力する
  outputLastName(name1);
  outputLastName(name2);
}

// 引数でわたってきた名前を分割して苗字を出力する
private void outputLastName(String name){
  // ※splitは引数の文字で分割する関数
  String[] nameArray = name.split(" ");
  System.out.println("苗字は" + nameArray[0]);
}

どうでしょう、mainメソッドの中身が少しすっきりしましたね。
さらに苗字を出力する処理を変更したくなった場合にも、outputLastNameメソッドを変更するだけなので保守性も高いです。

今回の例のように、共通化する部分がわかりやすい場合もありますし、逆に経験がないと気づかないような場合もあります。

このリファクタリングは経験を積みながら少しずつ慣れていくとよいのではないでしょうか。

まとめ

いかがでしたか?

初心者の方向けに、少しでしたがリファクタリングを紹介しました。

プログラミングを何年もやっている人ですら、今まで指摘を受けていなければ今回紹介したリファクタリングさえ行っていない人も多いかと思います。

なのでこれができているだけでも大分保守性の高いコードが書けると思いますので、ぜひ取り込んでみてください!

それでは!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です