和風スパゲティのレシピ

日本語でコーディングするExcelVBA

ベタ打ち数値はすべてマジックナンバー?

マジックナンバーという用語をご存知でしょうか?


簡単に言うと、

Cells(R, 4) = Cells(R, 2) * Cells(R, 3)

この2、3、4など、コード中に直接入力された数値や文字列を指す用語です。


この3つの数値は、

  • 改修時に書き換えが面倒かつ危険(全部の2,3,4を見ないといけない)
  • コードだけで意味を読み取れない

という点で、しっかりとプログラムを組むなら無くさなければいけない数値です。


こんな風に定数を定義して↓

Enum 売上データ列
    購入日 = 1
    単価        ' Enum(列挙型の定数)は、ここから先が= 2,3,4と自動連番されるしくみ
    個数
    金額
End Enum

 
このコードに書き換えることで↓

Cells(R, 売上データ列.金額) = Cells(R, 売上データ列.単価) * Cells(R, 売上データ列.個数)
' ↑順に4,2,3が呼び出されるので冒頭と同じ処理

 

  • 列番号が読めるテキストになり、コードを読むだけで意味が分かる
  • 挿入や削除があっても、宣言部分を変更すればすべての値が書き換わる

と、コードのメンテナンス性・可読性を格段に向上することができます。

※ 詳細は定数を使って読みやすく変更に強いマクロを書く記事へどうぞ



さてこのマジックナンバーで、
ブログで取り上げたいご質問をいただきましたので紹介します。

 
月別売上表

↑こんな表を、「売上を月ごとのシートから取ってきて埋める」マクロにおいて、

Dim i As Long
For i = 1 To 12

    Cells(3, 2 + i) = Worksheets(i & "月").~~~

Next

↑作ったこんなコードに「マジックナンバーを無くすよう指示があった」そうです。

どうすればよいでしょう?


とりあえず、明らかなマジックナンバーである「Cells(3, 2 + i)」は、

' モジュールの最上部に
Const R月別売上表 = 3
Const C1st月別売上表 = 2

~~~~~

For i = 1 To 12
    Cells(R月別集計表, C1st月別集計表 + i) = Worksheets(i & "月").~~~
Next

とかで対応しましょう。

これで、シートのレイアウトを変えても、
コードの中身を読まずに最上部のConstだけをいじればよくなります。


他の定数の書き方としては、

Const Adrs月別集計表 = "C3:N3"

For i = 1 To 12
    Rnage(Adrs月別集計表).Cells(i)
Next

なんていうのも、おしゃれで読みやすいと思います。

この辺がメンテナンス性を意識したマクロを書く基本ですかね。



さて前置きが長くなりましたが、ここからが本題です。

For i = 1 To 12

↑これをどうするか、皆さん考えてみてください。






正解を発表します。



 

For m = 1 To 12

これでOKです。

これで分かりやすいコードになりましたね。



質問者さんは

Const Max_Month = 12

For i = 1 To Max_Month

というご指導をいただき腑に落ちなかったそうなのですが、私も
「違うだろう。もっとこう、あるだろう。」
と思ったので取り上げてみました。


「マジックナンバーを無くす」は、手段であって目的ではありません。

目的は「読んでわかること」「書き換えが楽なこと」です。


太陽太陰暦で決算書を作る企業でもなければ月の数は12で固定ですので、
「読んでわかること」だけを果たせばいいですね。


そのとき、定数にすることよりも、はるかに変数名の方が重要であるということは覚えておいてください。

適切な変数名がついていれば、ベタ打ちの数字だって意味を持つということです。


逆に言うと、「謎の変数名も一種のマジックナンバー」なんですよね。


特に無秩序に乱用される「i」には気を付けて、
適切な変数名に置き換えるとコードが見やすくなると思います。


というお話でした。

よろしければこちらの記事もどうぞ(´∀`)

www.limecode.jp