コード品質 レッスン4

コードスメルの見つけ方

長すぎるメソッドや重複コードなど、設計上の問題を示唆するコードスメルの種類と見つけ方を学ぶ

コードスメルとは

コードスメル(code smell)とは、 それ自体がバグではないものの、設計上の問題を抱えている可能性を示す「兆候」のことです。 「臭い」がするからといって必ず腐っているとは限りませんが、確認する価値のあるサインです。

代表的なコードスメル

長すぎるメソッド(Long Method)

1つの関数が何十行、何百行にもなり、複数の責任を抱えている状態。 スクロールしないと全体が把握できない関数は分割の候補です。

重複コード(Duplicated Code)

同じ、あるいはよく似たロジックが複数箇所に存在する状態。修正時に1箇所を直し忘れるバグの温床になります。

巨大なクラス(Large Class / God Object)

1つのクラスがあまりに多くのフィールド・メソッドを抱え、無関係な責任まで担っている状態。

多すぎる引数(Long Parameter List)

関数が5個・6個と多くの引数を取る状態。呼び出し側での順序間違いを誘発しやすくなります。

分岐だらけの条件式(Switch Statements / 深いネスト)

同じ種類の条件分岐があちこちに散らばっていたり、if文が何重にもネストしている状態。

コード例で見るコードスメル

// スメルあり: 長すぎる関数 + 重複ロジック + 深いネスト
function processOrder(order) {
  if (order) {
    if (order.items && order.items.length > 0) {
      let total = 0;
      for (const item of order.items) {
        if (item.category === "book") {
          total += item.price * 1.08; // 書籍は8%軽減税率想定
        } else {
          total += item.price * 1.1;
        }
      }
      if (order.coupon) {
        if (order.coupon.type === "percent") {
          total = total * (1 - order.coupon.value / 100);
        } else if (order.coupon.type === "fixed") {
          total = total - order.coupon.value;
        }
      }
      return total;
    }
  }
  return 0;
}

// 改善: 責任ごとに関数を分割し、ネストを浅くする
function calcItemsTotal(items) {
  return items.reduce((sum, item) => sum + calcItemPrice(item), 0);
}

function calcItemPrice(item) {
  const taxRate = item.category === "book" ? 0.08 : 0.1;
  return item.price * (1 + taxRate);
}

function applyCoupon(total, coupon) {
  if (!coupon) return total;
  if (coupon.type === "percent") return total * (1 - coupon.value / 100);
  if (coupon.type === "fixed") return total - coupon.value;
  return total;
}

function processOrder(order) {
  if (!order?.items?.length) return 0;
  const total = calcItemsTotal(order.items);
  return applyCoupon(total, order.coupon);
}

分割後は各関数が単一の責任を持ち、それぞれ独立してテストできるようになります。

コードスメルを見つけるコツ

  • • 関数名を考えるときに「〜して〜する」のように「と」でつながる場合は責任過多のサイン
  • • 同じ処理を2回コピペした瞬間に、抽出のタイミングだと意識する
  • • 静的解析ツールの複雑度(Cyclomatic Complexity)警告を無視しない
  • • コードレビューで「読みにくい」と感じたら、それ自体がスメルの兆候

ポイント

  • • コードスメルはバグではなく「設計上の問題を示唆する兆候」
  • • 長すぎるメソッド・重複コード・巨大クラス・多すぎる引数・深いネストが代表例
  • • 責任ごとに関数を分割することで多くのスメルが解消される
  • • レビュー時の「読みにくさ」の感覚自体を見逃さない

確認クイズ

1 / 3

コードスメルの説明として最も適切なものはどれか?