Closed9
Clean ArchitectureでDBのTransactionをどう表現するか?
![youchan](https://res.cloudinary.com/zenn/image/fetch/s--zhnWI1gx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/61a56375f1.jpeg)
なんらかのアプリケーションを書いていて悩むはずであろう普遍的なトピックなのかと思っていたが、スタンダードなソリューションはなかった。
ある程度世に出ているものを羅列していこうと思う。
![youchan](https://res.cloudinary.com/zenn/image/fetch/s--zhnWI1gx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/61a56375f1.jpeg)
筆者の見立てでは、変更の原子性に関してもusecase
層(あるいはservice層
、つまりソフトウェアの機能要件を満たす振る舞いを表現する層)で書くべきだと考えている。
これが表現されていないと、usecase
層で表現されたデータ変更の原子性が担保されていなくても良いように認識されてしまう。Design Docなどのドキュメントで前提を補うことはできたとしても、可能な限り仕様に関しては見えるべきところで明確に表現するべきだ。
![youchan](https://res.cloudinary.com/zenn/image/fetch/s--zhnWI1gx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/61a56375f1.jpeg)
ここでいう原子性というのは「複数の処理を一つのまとまりとして扱うことで、その処理が完全に実行されるか、もしくは実行されないかのどちらかになることを保証する性質」を指す。
ACID特性のAの部分。
![youchan](https://res.cloudinary.com/zenn/image/fetch/s--zhnWI1gx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/61a56375f1.jpeg)
context.Context
に注入するパターン
Middlewareから
- 情報の作成・更新全てにトランザクションを張ることになる(そうしないこともできるが複雑になる)
- パフォーマンスに懸念
- 監査ログの収集する仕組みを構築する際に複雑化しそう
- commitと同時に監査ログを溜めなければならない
- 構造としてはシンプル
![youchan](https://res.cloudinary.com/zenn/image/fetch/s--zhnWI1gx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/61a56375f1.jpeg)
usecase
層相当のレイヤーで表現するパターン
- トランザクションの抽象化をどこで行うかが悩みポイント
- トランザクション相当の処理を
repository
層に生やすパターンもある
![youchan](https://res.cloudinary.com/zenn/image/fetch/s--zhnWI1gx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/61a56375f1.jpeg)
repositoryのレイヤーで書くことにした。usecaseの層で表現できて、詳細はrepositoryに隠せる。
func (t *Transaction) Do(ctx context.Context, runner func(ctx context.Context) error) error {
// ....
err = runner(ctx)
if err != nil {
// rollback
return err
}
return nil
}
このスクラップは2023/03/17にクローズされました