N
N
NubasLol2022-01-17 20:02:34
go
NubasLol, 2022-01-17 20:02:34

How to use transactions in "clean architecture" style code?

Repository example

https://github.com/bxcodec/go-clean-arch

I looked at examples, as above, read articles but did not understand for myself. What to do with transactions. After all, repository methods do not accept anything other than data. In the end, it's not entirely clear.

For example, I have OrderUseCase {orderRepository, paymentRepository}

And the newOrder() method

How to write it correctly so that creating an order and debiting funds from the user's account would be in a transaction. Or does it all need to be pushed into 1 repository, but then there will be code duplication, right?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
R
Roman Kitaev, 2022-01-18
@deliro

You need to understand that orderRepository and paymentRepository are abstractions, and in fact, data can be stored both in the same database and in completely different ones. For example, orderRepository is located on the S1 server in the Redis database, and paymentRepository is located on the S2, S3, S4 servers in the PostgreSQL database. Therefore, classical transactions are not applicable here. This can be neglected in most cases and not overcomplicated the system, or you can go the "right" way and use distributed transactions, for example, sagas https://microservices.io/patterns/data/saga.html

M
Michael, 2022-01-18
@Akela_wolf

Everything is pretty simple here. We have a layer of business logic that has 3 interfaces:
TransactionManager - the actual transaction manager
OrderRepository - order repository
PaymentRepository - payment
repository PAID" (I'm writing an example in Kotlin, I hope it's clear)

transactionManager.inTransaction {
  order.status = PAID
  paymentRepository.save(payment)
  orderRepository.save(order)
}

Actually further is already a question of implementation of TransactionManager. If we are dealing with a simple case, such as storing data in a SQL Database, then its implementation should be clear. If a more complex case is distributed transactions, or an empty implementation (transactionality is not supported). Of course, when injecting dependencies into a business logic module, the implementation of the transaction manager must correspond to the implementation of the repositories (it will be of little use if the transaction manager implements transactionality in the database, and the repositories implement storage in files). But this is a slightly different conversation, here factories and similar templates come to the rescue.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question