これはクラスター Advent Calendar 2023(シリーズ2)の15日目の記事です。
昨日は @rizumi さんの「2023年に実施したチーム施策を振り返る」でした。
こんにちは、クラスターの分析チーム1に所属している @kitta65 です。
この記事ではクラスターで行っている分析の話…ではなく、趣味で作ったコードフォーマッタの話をしようと思います(実際に作ったのが以下です)。
最初にクラスターのデータ活用環境についても、少しだけ触れます。
クラスターのデータ活用環境
クラスターの分析用データは、一度BigQueryに集約されます。私たちのチームはそのデータに対してdbtというツールで必要な変換を施し、LookerというBIツールでKPIの集計・可視化などを行っています。
実はLookerで利用するLookMLという言語がやや曲者で、フォーマッタなど周辺のツール群がそこまで充実していません。需要がありそうだから作ってしまおうというのがこの記事の趣旨です。
実装
code -> ast
LookMLはこんな見た目をしています。Qiitaのシンタックスハイライトが効かなくて悲しいです。
# this is comment
view: view_name {
derived_table: {
sql: select column_name from table_name ;;
}
dimension: dimension_name {
primary_key: yes
sql: ${TABLE}.column_name ;;
}
measure: measure_name {
type: count
}
}
まずはこれを以下のように抽象構文木(AST)として整理します。
自力で構文解析するのも楽しいです2が、parser generatorを使うと楽ができます。今回larkというPython製のparser generatorを利用したら、30行程度の定義3で上記のような抽象構文木が得られました。
フォーマッタ向けにparser generatorを選ぶ際は、コメントを扱いやすいかどうかに注意するとよさそうです。larkはコメントの内容や位置といった、ASTには直接含まれない情報にもアクセスできる点で便利でした。
ast -> code
抽象構文木ができたら、改行やインデントを整えて文字列として出力するだけです。今回はシンプルにPythonの文字列操作だけで実装してしまいました。
ちゃんとやるなら、既存のフォーマッタのプラグインとして実装する4方向性もありだったと思います。
実装時にハマりがちだったのは冪等性の問題です。特に、複数回実行してもコメントの位置を変えないのが意外と難しくて、慎重にテストしています。
また、これはLookMLに特有の悩みですが、SQLやHTMLといった他言語がしばしば埋め込まれます。それらについてはsqlfmtなど他のフォーマッタを呼び出すよう設計しています。
その後
実装完了してからしばらく寝かせていたのですが、せっかくだから最近チームの皆にも使ってもらうことにしました。Lookerの開発はなるべく専用のIDE上で完結させたいので少し悩んだ結果、GitHub Actionsを使って任意のタイミングでフォーマットを整えるPRを出す方法に落ち着きました(スクショのような感じ)。一か月ほど試しましたが、チームの反応は悪くないです。普段LookMLを書いているよという人は、よければ使ってみてください。
以上です。
明日は @Swanman さんの記事です。
-
分析チームの業務内容に興味のある方は、メンバーの登壇レポートをご覧ください(メタバースのデータ分析とはなにをやっているのか)。 ↩
-
読んだのはだいぶ前ですが、Go言語でつくるインタプリタという本はゼロから構文解析器を作るので面白かったです。 ↩
-
https://github.com/kitta65/lkmlfmt/blob/main/lkmlfmt/lkml.lark ↩
-
例えばPrettierにはプラグインを作成するための親切なチュートリアルがあります。今回はPythonで完結させたかったので、使いませんでしたが。 ↩