Transactions with DDD and Repository Pattern in TypeScript: A guide to implementation | Part 1.

João Batista da Silva
2 min readNov 12, 2023

--

Photo by Clark Van Der Beken on Unsplash

Frequently in the world of software development, we come across situations that are real puzzles, where the pieces must fit perfectly so that the code works as expected and results in our intention.

I recently came across one of those situations: By applying the concepts of Domain Driven Design, I needed to perform a transaction operation with a repository pattern in typescript.

If we ignore the DDD concepts, this is a simple task, any ORM or database provide the ability to perform transactions by default, and use them is easy. But when it comes to decoupling and reuse, things get more complicated.

In this article series, i want to share the solution for my puzzle, explaining from the beggining to end, how i fit the pieces to get the expected result.

In the first part we will understand what the problem is, using simple examples to be clearer.
Remembering that this is a tutorial with medium complexity, it is necessary to have a little knowledge about Typescript, Domain Driven Design, Generic types and Repository Pattern.

The problem

One of the premises in using the repository pattern is the separation of data handling by entities, as in the examples

Here we are representing a book purchasing application, and we have two repositories to handle the account data and book inventory respectively.

So if we want to buy a book, then the following code snippet can be used:

This is precisely where the classic question arises: “What if one of the operations fails?”.
Maybe we can change our buyBook method to use Promise.all like this:

The promise will be reject immediately when any of our input promises reject, but…
Unfortunately, we know that this does not guarantee the integrity of the database, as it is still not possible to roll back successful changes if others fail. So our exit is not this way.

The true is this: To be performed correctly and guarantee the database integrity, our operations need to run into a transaction scope, normally provided by database.

So in the next part, let’s try using a database implementation and figure out how to do this.

Part 2 here!

--

--

João Batista da Silva

𝕊𝕠𝕗𝕥𝕨𝕒𝕣𝕖 𝔻𝕖𝕧𝕖𝕝𝕠𝕡𝕖𝕣 | 𝗟𝗼𝗼𝗸𝗶𝗻𝗴 𝗳𝗼𝗿 𝘁𝗵𝗲 𝗯𝗲𝘀𝘁 𝗻𝗲𝘅𝘁 𝘀𝘁𝗲𝗽 𝗮𝗻𝗱 𝘀𝗵𝗮𝗿𝗶𝗻𝗴 𝘁𝗵𝗲 𝗰𝘂𝗿𝗿𝗲𝗻𝘁 𝗼𝗻𝗲.