関数抽出でリファクタリング

こんにちは。

今回のブログを担当させて頂きます、プログラマの姫野です。

さて、今回のテーマは「リファクタリング」です。

リファクタリング、行っていますか?
アプリケーション開発の保守をする上で非常に役にたつ、重要な作業です。

どのようなメリットがあるか、どうすればいいのか?を
今回は、実例を交えて紹介させて頂こうと思います。

リファクタリングのメリット

メリットを簡単に説明すると

  1. プログラムの流れが簡潔になる
  2. バグが見つけやすい(出にくい)コードになる
  3. バグを修正しやすい

以上が挙げられると思います。
これを怠ると、なんだかまずい事が起こりそうですね。

ソーシャルゲームでアップデートを繰り返しているうちにツギハギだらけのコードになっていた・・・
新しい機能を追加したが、既存のつくりが邪魔をして無理な実装になってしまった・・・

なんていう話を耳にしたことや、体験したことはないでしょうか?
新規機能を追加する上でも、バグ修正をする上でも時間がかかってしまうとてもまずい状況です。

特にソーシャルゲームだと、アップデートに始まり、実装期間の短さからスピードが優先されたりすることで、このような状況になっていることが多いのではないでしょうか?

それが解消できるリファクタリングはとても重要なものだと分かりますね。

実践

さて、一口にリファクタリングといっても、リファクタリング手法には様々な方法があります。
今回はその中でも「関数抽出」について説明していきます。

以下のようなソースコードがあるとします。
このコードで悪い点はどこでしょうか?

/// <summary>
/// 検索に使用するパラメータ
/// </summary>
struct SearchParam 
{
    /// <summary>
    /// 検索ID
    /// </summary>
    int key;
 
    /// <summary>
    /// 検索に用いる値
    /// </summary>
    int value;
 
    /// <summary>
    /// 比較方法(==,!=等)
    /// </summary>
    int compType;
}
 
/// <summary> 
/// 検索条件に合致したミッションを取得する
/// </summary>
/// <returns>検索条件に合致したミッション</returns>
Mission getMissionData()
{
    // ここでの値は全て仮です。
    // 適宜、置き換えてみてください!
  
    // 検索条件を設定する
    SearchParam[] param = new SearchParam[5];
  
    // ミッションをまとめるステージのIDの設定
    param[0].key = Search_Key_Stage_Id;
    param[0].value = 10;
    param[0].compType = Search_Comparison_Equal;
 
    // クリアしていないミッションの絞込み設定
    param[1].key = Search_Key_Clear;
    param[1].value = 0;
    param[1].compType = Search_Comparison_Equal;
 
    // 以下同様...
}

悪い点を関数抽出で直したものが以下になります。
見比べてみましょう。

/// <summary>
/// 検索に使用するパラメータ
/// </summary>
struct SearchParam 
{
    /// <summary>
    /// 検索ID
    /// </summary>
    int key;

    /// <summary>
    /// 検索に用いる値
    /// </summary>
    int value;

    /// <summary>
    /// 比較方法(==,!=等)
    /// </summary>
    int compType;
}

/// <summary>
/// 検索条件を設定する
/// </summary>
/// <param name="param">検索条件を設定する対象</param>
/// <param name="key">検索ID</param>
/// <param name="value">検索に用いる値</param>
/// <param name="compType">比較方法</param>
void setSearchParam(ref SearchParam param, int key,int value, int compType)
{
    param.key = key;
    param.value = value;
    param.compType = compType;
}

/// <summary>
/// 検索条件に合致したミッションを取得する
/// </summary>
/// <returns>検索条件に合致したミッション</returns>
Mission getMissionData()
{
    // ここでの値は全て仮です。
    // 適宜、置き換えてみてください!
 
    // 検索条件を設定する
    SearchParam[] param = new SearchParam[5];
 
    // ミッションをまとめるステージのIDの設定
    setSearchParam(ref param[0], Search_Key_Stage_Id,10, Search_Comparison_Equal);
 
    // クリアしていないミッションの絞込み設定
    setSearchParam(ref param[1], Search_Key_Clear, 0,Search_Comparison_Equal);
 
    // 以下同様...
}

「param[n].key」「param[n].value」「param[n].compType」
という重複していた部分がなくなり、「setSearchParam」というメソッドにまとまっているかと思います。
これが関数抽出です。

これにより3行の代入文が前後のコードを見ることなく、
検索パラメータを設定するための処理だということが分かるようになったのではないでしょうか?

まとめ

いかがでしたでしょうか?
関数抽出は重複している一連の処理を一つの関数にまとめて意味を持たせることができます。
意味を持たせることによって、改修を行う際に直すべき箇所を特定しやすくなります。
更に、関数の名前以外の機能を入れた時、それは間違ったコードとわかるので、
結果的に処理の流れがわかりやすいコードになっていくはずです。

関数抽出で快適な開発環境を作っていきましょう!

採用情報

クラウドクリエイティブスタジオではプログラマを募集しております。
ゲームにこだわりがある方、大歓迎です!ぜひ一緒にゲームを作りましょう!

コメント