Slide 1

Slide 1 text

1 The Future of encoding/json Go Conference mini 2023 Winter IN KYOTO Shunta Komatsu

Slide 2

Slide 2 text

2 About me ● Shunta Komatsu ● Backend Engineer at Merpay ○ Developing the payment platform ● Likes ○ Dogs ○ Neovim

Slide 3

Slide 3 text

3 このセッションの目的 ● 現在提案されている encoding/json/v2 について理解してもらう ● 興味を持った方が discussion に参加することで Go コミュニティに貢献する きっかけを作る

Slide 4

Slide 4 text

4 Agenda 1. encoding/json/v1 package の問題点 2. encoding/json/v2 package の紹介 3. パフォーマンスとマイグレーション 4. 議論の動向

Slide 5

Slide 5 text

5 encoding/json package 使ったことありますか?✋

Slide 6

Slide 6 text

6 encoding/json package encoding/json は 5 番目 に多く import されている (らしい) Marshal (encode) Unmarshal (decode)

Slide 7

Slide 7 text

7 encoding/json package json パッケージができたのは 2008 年

Slide 8

Slide 8 text

8 encoding/json/v1 package の問題点

Slide 9

Slide 9 text

9 encoding/json/v1 package の問題点 1. 機能不足 2. API の欠陥 3. パフォーマンスの制限 4. 動作上の欠陥

Slide 10

Slide 10 text

10 機能不足 ● 92 個の encoding/json 関連の proposal や feature request

Slide 11

Slide 11 text

11 機能不足 ● 92 個の encoding/json 関連の proposal や feature request

Slide 12

Slide 12 text

12 機能不足

Slide 13

Slide 13 text

13 機能不足 ● 92 個の encoding/json 関連の proposal や feature request

Slide 14

Slide 14 text

14 機能不足

Slide 15

Slide 15 text

15 API の欠陥 ● io.Reader から unmarshal できない ○ json.Unmarshal は []byte を引数に取る ○ io.Reader を入力するためには中間デコーダが必要 ■ json.NewDecoder(r).Decode(v) ■ 末尾の文字列を許容するなどの直感に反する動作 (#36225)

Slide 16

Slide 16 text

16 API の欠陥 ● Marshal, Unmarshal や MarshalJSON, UnmarshalJSON は動作を設定 するオプションを受け付けない ○ 動作を設定するためにはやはり Encoder, Decoder が必要

Slide 17

Slide 17 text

17 ● MarshalJSON は []byte を返すので、その分のメモリをアロケートする必要 がある ● MarshalJSON と UnmarshalJSON は内部で 2 回テキストの解析を行うため 効率が悪い ○ オブジェクトの型情報の収集 -> 値のパース ● ストリーミングの欠如 ○ Encoder.Encode と Decoder.Decode は io.Writer と io.Reader を引数に取るにも関わらず、JSON 値全体をメモリにバッファ する パフォーマンスの制限

Slide 18

Slide 18 text

18 動作上の欠陥 ● RFC (RFC 8259) に定義されている JSON の仕様とのズレ ○ invalid な UTF-8 が許容されている ○ JSON object の key の重複が許容されている

Slide 19

Slide 19 text

19 動作上の欠陥 ● MarshalJSON と UnmarshalJSON は reflection を使っているため、アド レスが取得できないと定義していても呼び出されない ● unmarshal は case-insensitive に行われる ● 返されるエラーの型に一貫性がない ○ 構造化されたエラーを返したり、構造化されていないエラーを返す

Slide 20

Slide 20 text

20 encoding/json/v2 package の紹介

Slide 21

Slide 21 text

21 encoding/json/v2 の思想と目標 ● (ほぼ) 後方互換を保つ ● より正確に ● よりパフォーマンス良く ● より柔軟に ● 使いやすく、誤用しにくい ● unsafe package は利用しない

Slide 22

Slide 22 text

22 Overview https://github.com/golang/go/discussions/63397

Slide 23

Slide 23 text

23 encoding/json/jsontext package https://github.com/golang/go/discussions/63397

Slide 24

Slide 24 text

24 encoding/json/jsontext package ● Encoder と Decoder は JSON token と value の読み書きをする ○ JSON テキストを純粋なストリーミング形式で処理する ● NewEncoder と NewDecoder はオプションを受け付ける

Slide 25

Slide 25 text

25 ● 可変長の Options 型によって動作の設定が可能 ● Options interface は jsonopts package に定義されている Options type https://github.com/go-json-experiment/json/blob/master/jsontext/options.go

Slide 26

Slide 26 text

26 SyntacticError type ● JSON の文法に準拠していないことに起因するエラーは SyntacticError と して返される

Slide 27

Slide 27 text

27 encoding/json/v2 package https://github.com/golang/go/discussions/63397

Slide 28

Slide 28 text

28 encoding/json/v2 package ● Marshal, Unmarshal ○ v1 の Marshal と Unmarshal とほぼ同じ ● MarshalWrite, UnmarshalRead ○ []byte の代わりに io.Writer と io.Reader を受け付ける ● MarshalEncode, UnmarshalDecode ○ *jsontext.Encoder と *jsontext.Decoder を受け付ける

Slide 29

Slide 29 text

29 https://github.com/golang/go/discussions/63397 デフォルトの挙動の変更

Slide 30

Slide 30 text

30 ● key を case-sensitive に比較する デフォルトの挙動の変更

Slide 31

Slide 31 text

31 ● invalid な UTF-8 を許容しない デフォルトの挙動の変更

Slide 32

Slide 32 text

32 ● key の重複を許容しない デフォルトの挙動の変更

Slide 33

Slide 33 text

33 Struct tag options ● v2 は以下の struct tag をサポート ○ omitzero <- new! ○ omitempty ○ string ○ nocase <- new! ○ inline <- new! ○ unknown <- new! ○ format <- new!

Slide 34

Slide 34 text

34 ● omitzero ○ 値がゼロ値のときは marshal 時に省略される Struct tag options

Slide 35

Slide 35 text

35 ● format ○ serialize するときの format を指定できる Struct tag options

Slide 36

Slide 36 text

36 Options type ● 可変長の Options 型によって動作の設定が可能 ● Options interface は jsonopts package に定義されている https://github.com/go-json-experiment/json/blob/master/options.go

Slide 37

Slide 37 text

37 SemanticError type ● Go と JSON 間で値を関連付けるときに発生するエラーは SemanticError として返される

Slide 38

Slide 38 text

38 encoding/json/v2 package https://github.com/golang/go/discussions/63397

Slide 39

Slide 39 text

39 パフォーマンスとマイグレーション

Slide 40

Slide 40 text

40 パフォーマンス https://github.com/go-json-experiment/jsonbench/blob/master/images/benchmark-marshal-concrete.png

Slide 41

Slide 41 text

41 パフォーマンス https://github.com/go-json-experiment/jsonbench/blob/master/images/benchmark-unmarshal-concrete.png

Slide 42

Slide 42 text

42 マイグレーション

Slide 43

Slide 43 text

43 議論の動向

Slide 44

Slide 44 text

44 golang/go で議論中

Slide 45

Slide 45 text

45 今すぐ参加できる discussion marshal 時に nil slice と nil map を空の JSON array や object として扱う か、JSON null として扱うか

Slide 46

Slide 46 text

46 今すぐ参加できる discussion 新しい Options を提案することも可能

Slide 47

Slide 47 text

47 Summary

Slide 48

Slide 48 text

48 個人的な所感 ● パフォーマンスや API の柔軟性、RFC への準拠による正確性に加えて、後方 互換性やマイグレーションにつても考慮されており、提案は全体的によく考えら れている ● これ以上パフォーマンスを上げる場合は 3rd party の JSON ライブラリによう にコード生成やアセンブリレベルでの最適化が必要 ○ 標準パッケージがやるべきではない? ● JSON の文法を処理する jsontext pacakge と Go の値と作用する json package に分けるアイデアは綺麗な設計

Slide 49

Slide 49 text

49 まとめ ● encoding/json/v2 は v1 が持っている機能不足、API の欠陥、パフォーマ ンスの制限、動作の欠陥といった問題点を解決・向上する提案 ● jsontext と json の 2 つのパッケージに分けることで、”JSON の文法的な 処理” と “Go の値との相互作用を行う意味的な処理” を効率的に実装している ● repository: https://github.com/go-json-experiment/json ● discussion : https://github.com/golang/go/discussions/63397

Slide 50

Slide 50 text

50 References ● “The Future of JSON in Go” by Joe Tsai at GopherCon 2023 (link) ● https://github.com/go-json-experiment/json ● https://github.com/golang/go/discussions/63397

Slide 51

Slide 51 text

51 よい JSON ライフを!👋