マジックナンバーを定数に置き換える|コードに散らばった「4」が、何の4なのか分からなくなった
post_status == 4 と自分で書いたコードを、半年後に読み返した。
この4が何を指しているのか、書いた本人が思い出せなかった。
半年前に自分で書いたコードを開いて、手が止まった。
そこには if ($post['post_status'] == 4) と書いてあった。
4。
この4が何を指しているのか、書いた本人である僕が思い出せなかった。
調べたら「公開」だった。
ついでに9が「非公開」で、1と2は使っていなかった。
どこにも書いていない。
僕の頭の中にだけあって、その頭のほうがもう覚えていなかった。
マジックナンバーとは、意味を説明しない数字のこと
コードの中に直接書かれていて、それ自体では意味の分からない数値や文字列を、マジックナンバーと呼ぶ。
魔法の数字、という言い方だけれど褒め言葉ではない。
なぜそれで動くのか誰にも説明できないのに、消すと壊れる。
その不気味さのほうを指している。
厄介なのは、書いている最中はまったく困らないところだ。
4が公開だということを、その瞬間の僕は当然知っている。
知っているから、わざわざ書き残す理由が思いつかない。
困るのは半年後で、そのときにはもう本人がいない。
正確には本人はいるのだけれど、記憶のほうがいない。
4の意味は、コードのどこにも書いていなかった
自分のCMSを post_status で grep してみたら、4は十数か所に散らばっていた。
投稿を保存するところ。
一覧を絞り込むところ。
公開判定をするところ。
管理画面で行の色を変えるところ。
全部ばらばらのファイルにあって、全部ただの4だった。
この状態がなぜ怖いかというと、数字を変えたくなった日にどうにもならないからだ。
たとえば「予約公開」という状態を足したくなって、番号を振り直すことになったとする。
grep で出てきた4のうち、どれが post_status の4で、どれがまったく別の意味の4なのかを、目で見分けないといけない。
配列の4番目かもしれないし、リトライ回数の4かもしれないし、単なる余白の4pxかもしれない。
検索は数字を見つけてくれるけれど、数字の意味までは教えてくれない。
定数にすると、名前のほうが説明を持ってくれる
やったことは単純で、数字に名前をつけただけだった。
ファイルの先頭で const POST_STATUS_PUBLIC = 4; と定義しておいて、判定するところを if ($post['post_status'] == POST_STATUS_PUBLIC) に書き換える。
それだけで、読んだ人が4の意味を推理しなくてよくなる。
「コメントで『4は公開』と書けばいいのでは」と思うかもしれない。
僕もそう思って、しばらくそうしていた。
ただ、コメントは平気で嘘をつく。
値だけ変えてコメントを直し忘れる、というのを僕は何度もやった。
定数なら、定義を変えれば使っている場所が全部同時に変わる。
説明と実体が同じものになるので、そもそもずれようがない。
名前をつけるという意味では、変数名の話と根っこは同じだと思う。
前に変数名は未来の自分への手紙だという書き方をした。
あれが「入れ物に名前をつける」話だとすれば、こっちは「中身そのものに名前をつける」話だった。
数字だけではなく、文字列も同じ穴に落ちる
マジックナンバーという言葉から数字だけを想像していたけれど、実際にやられたのは文字列のほうが多い。
'SYSTEM' という登録者名を、投入スクリプトのあちこちに直接書いていた。
ある日それを 'BATCH' に変えようとして、書き換え漏れが出た。
半分が SYSTEM のまま、半分が BATCH になって、あとから「どっちが正なのか」を調べる羽目になった。
区切り文字も同じだ。
カンマ区切りの ',' をそこらじゅうに書いていると、タブ区切りに変えたくなった瞬間に総当たりが始まる。
意味のある値は、数字でも文字でも扱いは変わらない。
全部を定数にすればいい、というわけでもなかった
この話をすると、つい端から端まで定数化したくなる。
僕も一度やって、読みにくくして戻した。
ループの i++ の1。
配列の先頭を指す0。
半分にするための2。
こういう数字に const ONE = 1; と名前をつけても、読む人の理解は一歩も進まない。
むしろ定義を見に行く手間が増えるぶん、遠回りになる。
僕が使っている線引きは、ひとつだけにした。
その値の意味を説明するのに、コードの外にある知識が要るかどうか。
4が公開だというのは、この CMS を作った人間しか知らない取り決めだ。
だから名前が要る。
0が配列の先頭なのは言語の決まりで、誰でも知っている。
だから名前は要らない。
直し方は、一度に全部やらないことだった
十数か所あると分かった時点で、まとめて置換したくなった。
それをやると、たいてい別の4まで巻き込んで壊す。
定数を定義する。
grep で出てきた場所をひとつ開く。
その4が本当に post_status の4かを目で確かめる。
置き換えて、画面を開いて、まだ動くことを見る。
次の場所へ行く。
ひどく地味で、実際に地味な作業だった。
ただ、ifの入れ子をほどいたときにも同じことを学んでいる。
壊れているコードを直すときにいちばん危ないのは、直す範囲を欲張ることのほうだった。
いま同じコードを開くと、POST_STATUS_PUBLIC と書いてある。
半年後の自分がここを読んでも、たぶん何も考えずに通過できる。
引っかからずに通過できるというのは、コードにとってはかなり上等な状態なのだと思う。
ほかにも書いています
note・スタンプ※noteは運営者が個人で書いているものです。
