こんにちは、id:masutaka26 です。先週に引き続いてのブログ更新です。
Ruby や JavaScript などのプログラミング言語では、依存関係を管理することでコードの再利用性を高めるとともに、バグの少ないコードを書くことが出来ます。ただ、LookML はプログラミング言語ではないため、同じ方法が使えません。
今回は LAMS という LookML Linter を導入することで、LookML の再利用性を高める糸口を見つけました。LAMS を紹介しつつ、その知見を共有します。
LAMS とは
LAMS (Look At Me Sideways) は LookML のスタイルガイドと Linter がセットになったツールです。準公式のツールなのかな?
LookML IDE に付属する LookML validator が文法的な誤りを検出するのに対して、LAMS はメンテナンス性の高い、もう一歩進んだ LookML を提案します。
2022-06-21 現在、4 グループ、32 個のルールが定義されています。
- Key Dimensions (K1 ~ K6)
- Other Fields (F1 ~ F6)
- Derived Tables (T1 ~ T15)
- Explores (E1 ~ E5)
導入方法
Linter を後から導入するのは辛いので、可能ならリポジトリを作るタイミングで導入するのが良いと思います。
README の Deployment Examples には、ローカルマシンで実行する方法や、GitHub Actions や CircleCI などで CI する方法がまとまっています。
今回は GitHub Actions を採用しました。git push するたびに LAMS が実行され、結果を Pull request 上で確認出来ます。参考までにコードを貼っておきます。
.github/workflows/ci.yml
name: CI on: push jobs: lams: name: LAMS LookML Linter runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: '16' # Use LTS https://nodejs.org/en/ - name: Install LAMS run: npm install -g @looker/look-at-me-sideways@2 - name: Run LAMS env: LOOKER_LICENSE_KEY: ${{ secrets.LOOKER_LICENSE_KEY }} run: make lams
Makefile 1
LAMS := lams LOOKER_LICENSE_KEY := ${LOOKER_LICENSE_KEY} REPORT_USER := feedmatic_report@example.com SOURCE := **/{*.model,*.explore,*.view,*.layer,manifest}.lkml .PHONY: lams lams: @$(LAMS) --reporting=yes --report-license-key=$(LOOKER_LICENSE_KEY) --report-user=$(REPORT_USER) --source='$(SOURCE)'
ルールの免除
manifest.lkml にこのように書くと、プロジェクト全体で任意のルールを免除することが出来ます。
# LAMS # rule_exemptions: { # F2: "Any explanatory message you would like" # F3: "Another explanatory message for a different rule" # }
dimension, measure, derived_table 単位でも免除することが出来ます。基本はこちらで免除し、無理そうなら manifest.lkml で免除すると良いでしょう。
初めから全てのルールをパスすることは少ないと思うので、必要に応じて免除すると良いでしょう。また、LAMS はあくまでスタイルガイドなので、必ずしも全てのルールに対応する必要はありません。
LookML の再利用性を高められた F1 ルール
32 個のルールのうち、今回は個人的に一番意義というか、感心した F1 ルールを紹介します。
例えば orders.view から users.view の count
measure を参照する、以下のような LookML があったとします。
LookML 書き始めの頃はこのように書きがちかと思いますが、F1 ルールでは NG です。orders.view が users.view に依存してしまうことで、orders.view の再利用がし辛くなるからです。そもそもこのケースでは LookML validation もエラーになるはずです。2
view: users {...} view: orders { ... measure: orders_per_user { sql: ${count} / NULLIF(${users.count},0) } } explore: orders {} # Errors :( explore: users { join: orders {...} }
解決方法がこちらです。まず、依存フィールドだけを抽出した users_orders.view を作ります。この view では sql_table_name や derived_table を設定しません。
view: users {...} view: orders {...} view: users_orders { # No need for a sql_table_name or derived_table measure: orders_per_user { sql: ${orders.count} / NULLIF(${users.count},0) } }
こうすることで少なくとも orders.explore は users.view に依存しないクリーンな LookML になりました。
explore: orders {} # Doesn't break like before!
次に users.explore で魔法を使います。users.view と users_orders.view の Join で通常指定するはずの sql_on ... ;;
の代わりに、空の SQL sql: ;;
を指定します。
explore: users { join: orders {...} join: users_orders { sql: ;; # Use `sql` instead of `sql_on` and put some whitespace in it relationship: one_to_one view_label: "Orders" # For cleaner explore UI } }
え?と思うかもしれませんが、これは妥当な LookML です。
Users explore が生成する SQL を確認すると分かりますが、orders_per_user
measure を選択しても Join 句は増えません。しかしこの measure が参照するテーブルは既存の users と orders だけなので、構文エラーになりません。
初見での理解は難しくなりますが、orders.view の再利用性が高まるのは大きなメリットです。
注意事項
K1 と K2 のように、一部のルールには依存関係があり、一方を免除するためには両方免除する必要があります。
あと、まだ Extension と Refinements に対応していません。Issue #46 によると、パーサー側は対応したそうで、あとは LAMS 本体を対応するだけだそうです。割と致命的な課題...。
まとめ
LookML の Linter である LAMS を紹介しました。うまく使うことで、再利用性やメンテナンス性の高い LookML を書くことが出来るかもしれません。
それでは良い Looker ライフを!(^^)/
-
Makefile を作ったのは、ローカルで実行しやすくするためです。↩