GoのライブラリのコードリーディングがSagaパターンを学ぶきっかけを与えてくれた
※ この記事ではSagaパターンの体系的な説明は行なっていません!
はじまり
Go のライブラリである samber/lo を眺めていたところ、ある文言が目に止まる。
Transaction
Implements a Saga pattern.
Saga pattern
?聞いたことあるようなないような。
おそらくトランザクション関連のデザインパターンか何かであろう。
聞き覚えがあるかも怪しいワードであるが、実装を読めばこのデザインパターン?アーキテクチャ?が何であるかがきっと少しは分かるであろう。
業務で使ったこともないし今後使うかも不明だが、知っていたら格好良くてお洒落な気がする。
そのような愚かなモチベーションでソースコードを読み始めた。
コードリーディング
件の実装は retry.go というファイルの関数 NewTransaction
辺りが該当するようだ。
処理の再試行、後退の制御等を司るような実装がであることが予想される。
早速中身を深掘りする。
関数 NewTransaction
を呼び出すと、構造体 Transaction
が返る。
Genericな関数、構造体となっており関数呼び出し時に型パラメータを渡す必要がある。
この段階では何をする関数、構造体なのかはさっぱり予測がついていない。私は弱い。
構造体 Transaction
の定義を確認する。
フィールド steps
に実行したい処理を追加していき、複数の処理が最終的にトランザクション処理となるような気がする。
追加、削除はメソッド経由でのみ許可したい理由があってPrivateなフィールドにしているのであろう。
構造体 Transaction
のフィールド steps
の型で使用されていた構造体 transactionStep
を見てみる。
フィールド exec
は実行したい処理、onRollback
は exec
の処理を後退する処理と考えられる。
やりたいことが分かってきた気がする。
ここからは構造体 Transaction
に生えているメソッドを読んでいき、ここまでで予想したことの答え合わせを行う。
メソッド Then
は実行したい処理と後退処理を引数で受け取り、それぞれを構造体 transactionStep
のフィールドにセットし、レシーバの構造体 Transaction
の フィールド steps
に追加する。
これはトランザクション処理の下準備だ。
戻り値が更新後の構造体 Transaction
であるので、メソッドチェーンが可能!(Go らしくないと言われることもあるが、メソッドチェーンが好物)
これが最後だ、メソッド Process
。
レシーバの構造体 Transaction
の フィールド steps
の要素である関数を昇順に実行していく。
途中でエラーが発生すれば、当該処理から降順に後退処理を実行していく。
また、メソッド Then
のリーディング時に雑に読み飛ばしていたが、実行したい処理と後退処理はどちらもジェネリックな型の引数を受け取り、同じ型を返している。
後続の処理に値をバケツリレーできるようになっているのだ。イケている。
おわり
素敵なコードだった。読んでいて普通に楽しかった。
コードの意味はちゃんと分かったつもりであるが、あくまでSagaパターンの一実装を知っただけであるし、もう少し上位のレイヤーで用いられるようなデザインである気がする。(マイクロサービスまたぎのトランザクションとか?)
今誰かに「Sagaパターンって何?」と聞かれてもモゴモゴしてしまうレベルではあるが、Sagaパターンっていう用語が出てきた時にふんわりとイメージはつくレベルには到達できたと思う。
もう少し体系的に知りたい気持ちが出てきたので、記事漁りでも始めます。
内容に誤りやわかりにくい点ありましたら、お気軽にコメントして頂けると幸いでございます。
Discussion