設定値のバリデーション
Ruby の Web アプリケーションのコードに外部から注入したい定数値は https://github.com/railsconfig/config で管理して、スキーマ定義してバリデーションを行ってはどうかという話です。
config
名前が一般名詞すぎて分かりづらいんですが、config という gem があります。Ruby で書かれたライブラリで、Rails や Sinatra などの Web アプリケーション等において、定数値を管理するためのライブラリです。config/settings.yml という YAML ファイルを用意して key-value のペアを書いておいてあげると、Settings.foo や Settings.bar というようにその値にアクセスできるというものです。
よく使う機能として、開発環境でのみ読み込む config/settings/development.yml を用意したり、本番環境でのみ読み込む config/settings/production.yml を用意したりという機能があります。例えば開発環境だと、config/settings.yml と config/settings/development.yml が deep merge されたものが読み込まれるという感じです。
同じような機能を持った別のライブラリとして https://github.com/settingslogic/settingslogic があります。自分も前までは settingslogic を利用していましたが、config のバリデーション機能を利用するようになってからは config を使うようになりました。
インターフェースの統一
そもそも設定値とはなんぞやという話ですが、The Twelve-Factor App では、環境によって変わる値が設定値だとしています。それで、その設定値は環境変数として格納すべきであるという話です。とはいえ、今のところ環境ごとに変わらないながらも設定値として注入するのと同じインターフェースで扱いたいような値もあると思います。将来的に環境ごとに変わるようになるかもしれない値や、明らかにアプリケーションのロジックと関係の無い定数などです。
これらの値をまとめるインターフェースとして、アプリケーション内からは必ず config gem を通してアクセスするようにすると良いのではないかと考えています。「これらの値」に説明的な名前を付けるなら、「アプリケーションのコードに注入したい定数値」という感じでしょうか。config gem では YAML の中に ERB を埋め込める機能がある (YAML 評価前に一度 ERB として評価される) ので、環境変数は ERB で展開し、そうでない値は直接 YAML にリテラルとして書いておくことで、これらの定数値をまとめて config gem で管理しようという感じです。
ちなみに YAML 内に環境変数を展開することになるので、環境変数が YAML 相当の表現力を持つことになります。"1" であれば Integer の 1 になるし、"[1, 2, 3]" であれば Integer の Array になるということですね。
設定値のスキーマ定義
環境変数だけで管理すると、文字列としての表現しかできないので貧弱であるとか、コードを見てもどういった値が期待されているのか読み取りづらいという懸念もありまました。
似たような話が以下の発表資料でも話されていました。この発表資料の話では JSON Schema での解決を試みています。
https://docs.google.com/presentation/d/12d9qdyNK1u7DquYAGZDs6_q9SiVm8c-QX1LIcmwP7d8/edit
実は config gem には、予め期待するスキーマを定義しておいてバリデーションを行う機能が付属しています。これを利用すると、アプリケーションに注入したい定数値の型を保証しつつ、ドキュメンテーションの要素も兼ねられます。個人的にはこの機能はかなり役に立つものだと思っているのですが、あまり言及されている様子を見かけません。なのでこの記事で取り上げてみています。
このスキーマ定義の機能を利用することで、
- この値が文字列として与えられているべき
- この値が与えられているときはこの値も与えられているべき
といった内容が検証でき、環境変数の渡し忘れや定数の書き忘れなども防止でき、その値を参照するコードを読むときにもどういう値が期待されているのかある程度予測が付きます。
おわり
config gem の紹介を交えたアプリケーションの設定値の話でした。