きり丸の技術日記

技術検証したり、資格等をここに残していきます。

YAMLのブロックを変数化し、変数を参照して共通化する(アンカーとエイリアス)

設定ファイルの一部値を修正漏れが発生したことで、障害が発生した 経験は無いでしょうか。また、タイムアウト値等の連携システムごとに大きく変わらない設定値を記載するのを面倒に感じたことは無いでしょうか。

今回の記事では、YAMLのアンカー、エイリアス、マージ機能を使って、YAMLの反映漏れや記載内容の削減を目指します。

ゴール

設定ファイルから、下記2つのURLを生成します。アンカー、エイリアス、マージ機能を使って、設定ファイルをリファクタリングします。

http://localhost:80/twitter http://localhost:10080/facebook

※ポートやエンドポイントは例です。

副次効果


設定値を纏められるので、数値の単位を揃えることができます。設定ファイルと実装は異なるので、単位が違っていてもいいですが、少なくとも混乱はしなくなります。

(例)

twitter:
  timeout: 3 # 3ミリ秒?3秒?
facebook:
  timeout: 3000 # 3000ミリ秒?3秒?

アンカーとエイリアスを使って共通化

アンカー(Anchor)は変数宣言、エイリアス(alias)は変数使用です。

&を付与するとアンカーとなります。&timeout 3と使用すると、timeoutという変数に3が設定されています。

*を付与するとエイリアスとなります。*timeoutと使用すると、3と置換されます。

下記例では、hostprotocolporttimeoutの値を共通化しています。

# 置換前のYAMLファイル
external:
  twitter:
    host: localhost
    protocol: http
    port: 80
    timeout: 3
    endpoint: twitter
  facebook:
    host: localhost
    protocol: http
    port: 10080
    timeout: 3
    endpoint: facebook
# アンカーとエイリアスを使用して共通化したファイル
external:
  common: 
    host: &host localhost
    protocol: &protocol http
    port: &port 80
    timeout: &timeout 3
  twitter:
    host: *host
    protocol: *protocol
    port: *port
    timeout: *timeout
    endpoint: twitter
  facebook:
    host: *host
    protocol: *protocol
    port: 10080
    timeout: *timeout
    endpoint: facebook

マージを使って共通化

アンカーとエイリアスでは変数ののみを共通化しました。マージ機能を使用すると、変数のキーの両方を共通化できます。

マージ機能を使用するには、<<とエイリアスを組み合わせます。

ただし、YAMLの仕様としては、マージという機能は定義されていないようです。なので、使用するライブラリでマージ機能が実装されているかどうかを確認してください。

下記例では、host: localhostprotocol: httpport: 80timeout: 3を共通化した&commonというアンカーをマージしています。

また、Facebookのportを10080でcommonを上書きしています。

external:
  common: &common
    host: localhost
    protocol: http
    port: 80
    timeout: 3
  twitter:
    <<: *common
    endpoint: twitter
  facebook:
    <<: *common
    port: 10080 # 上書き
    endpoint: facebook

ブロックのアンカーとエイリアス

ブロックで定義したアンカーを使用する方法を記載します。次の設定ではtwittertwitter2は同一の設定がされています。

OpenAPIやSwaggerではエラーレスポンス、同一のパスパラメータを何度も定義することがあるため、アンカーとエイリアスを使いこなすことで、記載量を減らせます。

external:
  common: &common
    host: localhost
    protocol: http
    port: 80
    timeout: 3
  twitter: &twitter
    <<: *common
    endpoint: twitter
  twitter2: *twtitter

GitHubソースコード

github.com

YAMLの定義

https://yaml.org/

https://yaml.org/refcard.html

https://yaml.org/spec/1.2/spec.html

JSONの定義


今回の記事とは関係ないですが、JSONを設定ファイルとしている場合も同様に共通化できないか調べてみたので残しておきます。結論としてはできないようです。

なので、JSONとYAMLを選択できる場合に、YAMLに軍配が上がるかと考えています。

ただし、個人的には読みやすさだけでいうと、YAMLの配列記述とか分かりづらいのでJSONの方が好きです。

www.json.org

終わりに

動けばいい、ということで設定ファイルは雑に扱われがちのように感じます。設定ファイルを雑に扱った結果、設定ファイルを読み込んで実装するプログラムはもっと雑になります。

この記事を読んだことで、設定ファイルのリファクタリングという別観点を植え付けることができれば幸いです。


もしこの記事が役に立ったのであれば、はてぶ、Twitterでの記事の拡散、Twitterのフォローもよろしくお願いします。

私の励みになります。

参考記事

CircleCIの「YAMLの記述」 circleci.com

フューチャー技術ブログの「一周回って、人間が読み書きする設定ファイルはJSONが良いと思った」 future-architect.github.io

類似記事

Javaでプロパティのテストを書く方法(こちらで動作検証しながら、リファクタリングしていました) nainaistar.hatenablog.com