SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

実例で学ぶ、コード品質の高め方

どうやってコード品質を上げるのか? 実例で学ぶリファクタリング

第3回 ステップ・バイ・ステップで学ぶC++コードのリファクタリング

リファクタリング実践

 以上でリファクタリングの概要を押さえたら、早速実践といきましょうか。低品質コードをリファクタリングしてみましょう。以下は、オンラインショップの商品とその価格に関するコードの例です(C++)。2つの異なる製品カテゴリー(Tシャツとジーンズ)の合計価格と平均価格を計算し、これらの情報を標準出力に表示しています。

#include <iostream>
#include <vector>
#include <map>

int main() {
    std::map<std::string, std::vector<double>> products = {
        {"T-Shirts", {29.99, 34.99, 24.99, 19.99}},
        {"Jeans", {49.99, 59.99, 69.99, 79.99}}
    };

    // T-Shirtsの合計価格と平均価格を計算
    double totalTShirts = 0.0;
    for (double price : products["T-Shirts"]) {
        totalTShirts += price;
    }
    double averageTShirts = totalTShirts / products["T-Shirts"].size();

    // Jeansの合計価格と平均価格を計算
    double totalJeans = 0.0;
    for (double price : products["Jeans"]) {
        totalJeans += price;
    }
    double averageJeans = totalJeans / products["Jeans"].size();

    std::cout << "Total price of T-Shirts: $" << totalTShirts << std::endl;
    std::cout << "Average price of T-Shirts: $" << averageTShirts << std::endl;

    std::cout << "Total price of Jeans: $" << totalJeans << std::endl;
    std::cout << "Average price of Jeans: $" << averageJeans << std::endl;

    return 0;
}

 コンパイルして実行する場合は、C++11のオプションをつけてください。

$ g++ -std=c++11 -o main main.cpp

ステップ1:コードレビュー

 まずはコードを読んでみてください。このコードのどこに問題があり、どんな改善をすべきでしょうか?

 正直に言うと、このぐらい小さなプログラムであれば、実際にはリファクタリングを行う価値はほとんどありません。全体を把握するのに、大した時間はかかりませんし、冗長と言っても製品は2つだけです。今回は記事の都合上、上記のソースコードを題材にリファクタリングしていきます。読者の皆様は、上記のコードが大規模なコードベースの一部であったり、将来的には扱う商品数が拡大していったりというような想定のもと、以下のリファクタリングにお付き合いいただければと思います。

 いかがでしょう? すぐに思いつくこととしては、Tシャツ、ジーンズ、と、商品ごとの合計価格や平均価格を計算する部分が冗長に記述されていることですね。このロジックを関数化して切り出せば、似たようなコード(重複コード)を削減でき、メンテナンス性・可読性が上がりそうです。また、そもそも現状の設計では製品数が増えて来たら対応できません。製品の合計や平均を計算するというような基本的な処理は、このプログラムに限らずプロジェクト全体で度々使う可能性があります。別の関数として抽出することで再利用性を高めることもできます。

 指摘の箇所としては同じになりますが、単一責任の原則(Single Responsibility Principle)という別の観点からも、オリジナルコードには問題があります。main関数がデータの初期化、処理、出力という複数の責任を持っています。これらの責任を分割することで、各部分を独立して変更・拡張できるようになります。

 以上で、リファクタリングの基本線は見えてきました。合計と平均価格を計算するための関数を定義して、main関数から切り出してシンプルにするとともに、今後、他のコードから再利用できるようにしてみましょう。

ステップ2:関数の抽出

 まずは、main関数には手をつけずに、合計価格と平均価格を計算する関数を実装してみましょう。コード例は以下のようになります。

#include <iostream>
#include <vector>
#include <map>

// ステップ2: 商品価格の合計と平均を計算する関数の実装
std::pair<double, double> calculateTotalAndAverage(const std::vector<double>& prices) {
    double total = 0.0;
    for (double price : prices) {
        total += price;
    }
    double average = prices.empty() ? 0.0 : total / prices.size();
    return {total, average};
}

int main() {
    // 省略: オリジナルのコードと同じ
}

 製品の合計価格と平均価格を計算する簡単な関数CalculateTotalAndAverageを実装しました。12行目がややわかりにくいかもしれませんが、価格のリストが空でないかを確認し、空でない場合だけ合計価格をリストの要素数で割って平均価格を計算しています。つまり、リストが空の際に0で割り算されて例外が発生することを防いでいます。

 ここでは三項演算子と呼ばれるものを使っています。三項演算子の使い方は以下の通りです。

 条件 ? 真の場合に評価される式 : 偽の場合に評価される式;

 関数名や変数名は、チームの別のメンバーが読むことを意識して、わかりやすいものをつけましょう。実は筆者は関数名・変数名を考えるのが苦手なのですが、そんな時こそChatGPT の出番です。仕様を入力して、あるいはコードを直接貼り付けて、「適切な関数名を提案して」とお願いするといい感じの名前が出てきます。お試しあれ。

 ここで一度、コードをコンパイルして生成された実行形式ファイルを実行してみます。エラーや警告なくコンパイルが完了し、オリジナルと同じ出力結果が得られることを確認しましょう。先に述べたとおり、リファクタリングとは「プログラムの外部から見た動作を変えずにソースコードの内部構造を整理すること」です。プログラムの外部から見た動作が変わっていないかどうか確認するため、リファクタリングの際には、コードに変更を加える毎にコンパイルを通し、テストを行うことを習慣化してください。

次のページ
ステップ3:既存のコードの置き換え

この記事は参考になりましたか?

実例で学ぶ、コード品質の高め方連載記事一覧

もっと読む

この記事の著者

浅原 明広(株式会社Sider)(アサハラ アキヒロ)

 日本IBM、株式会社フィックスターズなどで、半導体製造装置や医療画像機器など、大小様々な組み込み製品向けのソフトウェア開発プロジェクトに従事。 現在、フィックスターズ子会社の株式会社Sider にて、ソースコードのコピペ管理ツール『CloneTracker』を開発・提供。最新のツールや方法論を用いた、ソフトウェア開発者体験の向上に強い関心を持つ。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

千葉 滋(東京大学情報理工学系研究科教授)(チバ シゲル)

東京大学 情報理工学系研究科 創造情報学専攻 教授

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/18854 2024/01/18 11:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー