この記事の目的
開発中に「マジックナンバー」と言う聞き慣れない(恥ずかしながら)言葉を耳にし、その意味と問題点を調べたのでまとめました。また、Railsにおける「マジックナンバー」への対応策の一つを紹介したいと思います。
この記事で以下のことが分かると思います。
- マジックナンバーとは何か
- 開発におけるマジックナンバーの問題点
- その解決策の一つであるrailsのgem "config"の扱い方
1. マジックナンバーとは
マジックナンバーとは、ハードコーディングされた数値のことです。
ハードコーディングとは、固有名詞・固有値をソースコード内に直接埋め込んだコードのことです。
ソースコードとは、開発者がコーディングしているファイルの内容のことです(index.html, stylesheet.cssなど大体そうかと)。
ハードコードの中でも数値のことを、プログラミングにおいて「マジックナンバー」と呼びます。
# ハードコードの例
<li>
<p>山田太郎<p>
<p><span>23</span>歳です</p> # 23がマジックナンバー
</li>
<li>
<p>田中花子</p>
<p><span>73</span>歳です</p> # 73がマジックナンバー
</li>
:
上記はSNSにおけるユーザー一覧の例です。恐らく、こんな直接的な書き方はしないと思います。
一般にマジックナンバーはNGとされています(そもそもハードコードがNGなのかな...)。
その理由を次に説明します。
2. マジックナンバーが何故いけないのか
一般にマジックナンバーは、コーディングの際に避けるべきだ、と言われています。その主な理由は3つだと思われます。
- 数字だけ見ても何を意味しているか分からない[可読性が低い]
- 変更する場合は全てのマジックナンバーが利用されている場所を変更する必要がある
[保守性が低い] - セキュリティの安全性が下がる[脆弱性を生む]
3つの理由の説明はその他のサイトでも説明されていると思います。ここでは、少し具体的なマジックナンバーを使ってしまいそうな例を提示してみます(実体験)。
def show
@product = Spree::Product.find(params[:id])
@related_products = @product.related_products(4) # マジックナンバー
end
この4
という数値が何を意味しているか、このコードを見ただけでは分かりません。
これは下の画像における表示個数の個数を表します。このように、実際の機能に対してコードの意味が伝わりにくくなってしまうのがマジックナンバーの良くない点です。
これ以降では、Railsにおけるマジックナンバーに関する対応策であるconfig
と言うgemの扱いを簡単に紹介したいと思います。
[画像挿入]
3. Railsにおける定数管理のgem "config"
以下で具体的な使い方は説明しますが、このgemのいいところは以下の2つだと思います
- 定数の意味をソースコード内で表現できる
- 一箇所で定数を管理できる
これがリソースです。
rubyconfig/config
gem "config"は、定数管理を指定のYAMLファイルを用いて一箇所で行う為のgemです。場合によっては環境毎に(development, production, test)定数の値を変更することもできます。
ここでは、簡単な方法を一つ紹介し、先程の例を解決したいと思います。
4. gem "config"の使い方
ここでは最も簡単だと考えられる、一つのファイルで定数を管理する方法を示します。
その場合config/settings.yml
のみ書き込むことで定数管理を実現します。
(1) gem "config"の準備
gem "config"
$ bundle install
$ rails g config:install
create config/initializers/config.rb
create config/settings.yml
create config/settings.local.yml
create config/settings
create config/settings/development.yml
create config/settings/production.yml
create config/settings/test.yml
append .gitignore
以下のようにファイルが追加されます(自動的に.gitignoreに追加されていました)。
(2) 定数を管理する
config
では、木構造のように定数を管理します。
今回は「商品の個数」の中で、「上限の数値」「テストの際の数値」といった定数を定義します。(このように記載することで、先程の例を解決します)
products_count:
max_count: 4
test_count: 10
このファイルにて定数の管理を、一括で扱います。また、定数への意味付けも可能になります
[可読性上がる]。
(3) - 1 定数を取り出す
定数は以下のように記載することで取り出すことができます。
$ rails c
[1] pry(main)> Settings.products_count.max_count
=> 4
[2] pry(main)> Settings.products_count.test_count
=> 10
設定に応じてSetteings. ~ .~
の~部分を置き換えることで、定数を取り出すことが可能になります。
(3) - 2 定数を取り出す(ファイル内で)
以上を参考に先程の例を、このように解決することができます。
def show
@product = Spree::Product.find(params[:id])
@related_products = @product.related_products(Settings.products_count[:max_count])
end
マジックナンバーを比べていた時に比べ、可読性が少しは上がります(恐らく)。
以上です。この記事が少しでも参考になるといいな、と思います。
余談
マジックナンバーには、エンジニアの方にコードレビューして頂いた際に出会いました。「実装要件を満たした」と思った自分に対して、予想のできない指摘が飛んできました。実務の世界では当たり前のことができていない、本当にまだまだなのだな、という実感を沸いた経験でした。
リソース
以下を参考にさせて頂きました
https://wa3.i-3-i.info/word12868.html
https://qiita.com/RyoheiHashimoto/items/38ec132bd2852238295e
https://it-biz.online/it-skills/hard-coding/
また、gem "config"に関しましてはその他多くの説明が存在しますので、詳細はそちらを参考にすると実装が捗るかと思います。