Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CUEを使ったJSONテンプレート管理

 CUEを使ったJSONテンプレート管理

Kazuma Arimura

December 02, 2022
Tweet

More Decks by Kazuma Arimura

Other Decks in Marketing & SEO

Transcript

  1. 2022 導入背景 GET /_search { "query": { "bool": { "should":

    [ { "match": { "name.first": { "query": "shay", "_name": "first" } } }, { "match": { "name.last": { "query": "banon", "_name": "last" } } } ], "filter": { "terms": { "name.last": [ "banon", "kimchy" ], "_name": "test" } } } } } Elasticsearch Query DSL • JSON型 • 複雑な条件の場合、ネストが深くなる • 条件の組み合わせによって、ブロックを挿入 する箇所を変えたいケースがある → クエリをコンポーネントで管理しつつ、 それらを組み合わせてクエリを組みたい
  2. 2022 導入背景 GET /_search { "query": { "bool": { "should":

    [ { "match": { "name.first": { "query": "shay", "_name": "first" } } }, { "match": { "name.last": { "query": "banon", "_name": "last" } } } ], "filter": { "terms": { "name.last": [ "banon", "kimchy" ], "_name": "test" } } } } } クエリビルダに求める条件 • 柔軟にJSONが構築できること • 複雑なクエリになっても可読性が高いこと • 学習コストが十分に低いこと • 型安全性が守れること ◦ ❌ interface{}の乱用
  3. 2022 CUE CUEとは? CUE is an open source data constraint

    language which aims to simplify tasks involving defining and using data. 特徴 • 基本的にJSONのsuperset • CUE自体はGoで記述された言語 ◦ 文法的にはJSON + Go • 値のvalidationが詳細に定義可能 • 各種IDEのサポートが豊富 • Goのpackageが公式で提供されている Logo from: https://cuelang.org/
  4. 2022 Data binding / validation Goのプログラムから変数のバインディング、また型・値のバリデーションが可能 min?: *0 | number

    // 0 if undefined max?: number & >min // must be strictly greater than min if defined. minmax.cue type minmax struct { Min int `json:"min"` Max int `json:"max"` } func main() { data := minmax{Min: 10, Max: 100} v := cuecontext.New().CompileBytes(template) filled := v.FillPath(cue.ParsePath(""), data) compiled, err := filled.MarshalJSON() } bind.go Structから 値をバインド
  5. 2022 Data binding / validation min?: *0 | number max?:

    number & >min minmax.cue func main() { data := minmax{Min: 10, Max: 100} v := cuecontext.New().CompileBytes(template) filled := v.FillPath(cue.ParsePath(""), data) compiled, err := filled.MarshalJSON() fmt.Printf("err: %v\njson:%s\n", err, compiled) } bind.go err: <nil> json:{"min":10,"max":100} out
  6. 2022 func main() { data := minmax{Min: 10, Max: 5}

    v := cuecontext.New().CompileBytes(template) filled := v.FillPath(cue.ParsePath(""), data) compiled, err := filled.MarshalJSON() fmt.Printf("err: %v\njson:%s\n", err, compiled) } bind.go Data binding / validation min?: *0 | number max?: number & >min minmax.cue 不正な値 err: cue: marshal error: max: invalid value 5 (out of bound >10) json: out
  7. 2022 Reduce boilerplate in your data list/mapを渡してイテレーション #name: { first:

    string last: string } #names: [... #name] #names: [ {first: "jiro", last: "sasaki"}, {first: "taro", last: "tanaka"}, ] attendees: [ for name in #names { {"name": "\(name.first) \(name.last)"} }, ] { "attendees": [ { "name": "jiro sasaki" }, { "name": "taro tanaka" } ] }
  8. 2022 Reduce boilerplate in your data 複数のCUEを結合 { term: {"name":

    "taro tanaka"} } term.cue { query: {} } query.cue { function_score: { query: {} random_score: {} } } function_score.cue
  9. 2022 Reduce boilerplate in your data 複数のCUEを結合 ※ FillPathで指定するValue同士は同一のcuecontextから生成される必要あり func

    mergeCue() { ctx := cuecontext.New() term := ctx.CompileBytes(termTemplate) query := ctx.CompileBytes(queryTemplate) score := ctx.CompileBytes(scoreTemplate) merged := query.FillPath(cue.ParsePath("query"), term) compiled, _ := merged.MarshalJSON() merged = score.FillPath(cue.ParsePath("function_score.query"), term) compiled, _ = merged.MarshalJSON() } merge.go
  10. 2022 パフォーマンス検証 他のJSON生成方法と比較した際のパフォーマンスについて検証 比較対象 • encoding/json • text/template シナリオ •

    1層のみのシンプルなJSON • 5層のネスト、リストありなJSON • testing.Bによるベンチマークでns/opとallocs/opを比較
  11. 2022 総合的な検討 encoding/json text/template cue-lang/cue 可読性(小規模) ◦ ◦ ◦ 可読性(大規模)

    ☓ ◦ ◦ 開発効率 △ ☓ ◦ 学習コスト ◦ △ △ 型安全性 ◦ ◦ ◦ 処理パフォーマンス ◦ ◦ ☓
  12. 2022 総合的な検討 クエリビルダに求める条件 • 柔軟にJSONが構築できること • 複雑なクエリになっても可読性が高いこと • 学習コストが十分に低いこと •

    型安全性が守れること encoding/json text/template cue-lang/cue 可読性(小規模) ◦ ◦ ◦ 可読性(大規模) ☓ △ ◦ 開発効率 △ ☓ ◦ 学習コスト ◦ △ △ 型安全性 ◦ ◦ ◦ 処理パフォーマンス ◦ ◦ ☓ WINNER👑 → 全て条件を満たした上で、複雑になった場合の可読性・開発効率から CUEを選択