aoのプログラミングブログ

あおのエンジニア学習日記

初心者のプログラミング学習記録。

マジックナンバーとは何か、なぜ避けるべきなのか

f:id:ao_pro_21:20220125114026p:plain

コードレビューでマジックナンバーを指摘され、マジックナンバーとは何か?なぜ駄目なのか?を調べたのでメモ。

概要

マジックナンバーとは、直接ソースコードに記述された数値で、その意味が不明なものを言う。
コードの可読性を下げ、修正や変更の際に問題が起きやすくなる。
これを避けるために、数値は定数化して、定数名の形で値を参照すべき。

問題のコード

class HomeController < ApplicationController
  def index
    @reads = Read.includes([task: :user],[task: :book]).order(read_on: :desc).limit(50)
  end
end

マジックナンバーとは何か

ハードコーディングをした際に、実際に記述された値のことを、マジックナンバーと言います。

  • ハードコーディング
    ソースコードの中に固定値をそのまま記述してしまうことを、ハードコーディングと言います。
    以下のように、~.limit(50) と数値を直接記述している状態です。
@reads = Read.includes([task: :user],[task: :book]).order(read_on: :desc).limit(50)

つまり上記の 50マジックナンバーです。

なぜ避けるべきなのか

なぜ避けるべきなのか、以下のマジックナンバーの例から説明します。

税込み価格の計算

tax_included_price = price * 1.08

1.08マジックナンバーです。

1. コードの可読性が下がる

良いコードとは「他人(そして後の自分)が読んで意味のわかるコード」です。
つまり、「誰もがひと目で何の数字かわかること」が必要です。
1.08 ではその数値が何を表すのかが明確ではありません。

1.08 って言ったら消費税じゃん…と思ってしまいますが、
よく考えると、消費税率は時代によって変動するものです。また、日本の消費税率を知らない人がコードを見たらさっぱりわからないですね。

2. 修正や変更時にミスの温床になる

もし税率が変わったら、
コード内の 1.08 の数字をすべて探し出し、ひとつひとつ修正しなければいけません。
探し漏れ、修正漏れが起きることは予想に容易いです。

定数化で解消する

マジックナンバーを解消するには定数化することです。 問題のコードを実際に直してみましょう。

class HomeController < ApplicationController

  MAX_READS = 50

  def index
    @reads = Read.includes([task: :user],[task: :book]).order(read_on: :desc).limit(MAX_READS)
  end
end

これで、他の人が見ても reads を取得する最大値だなとすぐにわかりますし、 取得件数を変更するときには MAX_READS の値を変更するだけで済みますね!

おまけ

定数の命名時の注意点

良いコードを書くためバイブル「リーダブルコード」では、
限界値を含めるときは minmax を使うことをおすすめしています。
「未満(限界値を含まない)」なのか「以下(限界値を含む)」なのか明確にするためです。
上記では、limit(50) =「最大50件まで」と指定しているので、定数に MAX_ を使っています。

参考