dimitarvp

dimitarvp

Seeking thoughts on advantages of the Repo.transact pattern vs disadvantages I’ve read about Ecto.Multi

Hello,

I am looking to more closely understand the advantages of the Repo.transact pattern and the quoted disadvantages of Ecto.Multi.

Repo.transact is quickly described in this blog post.

(Link to the original article by Sasa Juric is included in the post above.)

Here are four (4) points from the article, and my comments. I am quoting @sasajuric and @tomkonidas.


This function commits the transaction if the lambda returns {:ok, result}, rolling it back if the lambda returns {:error, reason}. In both cases, the function returns the result of the lambda.

Does Ecto.Multi ultimately not do that as well? Sure it’s not a direct response; in case of errors you get a tuple containing various state, including “changes so far”. I’d think that the rich choices offered by Ecto.Multi are welcome – you get to decide for yourself how do you want to react to problems. How is the Repo.transact feature the clear winner here?

One thing I can see is if we unify our error-handling code by utilizing shared helpers + including the Repo.transact in an even higher-level wrappers (business code). Is that the selling point – less boilerplate?


We chose this approach over Ecto.Multi, because we’ve experimentally established that multi adds a lot of noise with no real benefits for our needs.

I am very curious about this empirical evidence; I think having it spelled out somewhere would be hugely valuable both for new learners and more long-term users like myself. I can only imagine it’s the proposition that the else clauses of the with statement are hard to maintain? Or having to know the changeset functions (which I don’t view to be as negative thing as the blog post author seems to imply)?


As we can see, it is not the worst, but once we see the Repo.transact/2 way, it will be clear which is better.

It’s clear only insofar as the code is (1) shorter and definitely easier to read, and (2) has no else clause(s). Is that all? I am all for shorter and more readable code, I am almost religious about it too, but not all teams are open to code modifications on that basis alone. I am looking to understand if there’s more to this beyond code readability.

Perhaps the error-handling utilities we can combine with Repo.transact are the true value proposition here?


Another big benefit is that we do not need to go down to the changeset level for inserting, we could use our functions that perform Repo.inserts in them (Accounts.new_user_changeset/1 vs Accounts.create_user/1). This lets us compose many functions together from outside the context modules without having the need to expose your changeset functions.

Hmmm. I’ve been in 3 big-ish Elixir codebases (we’re talking 1000 - 3000 files) and I have never stumbled upon a problem that we the team would describe as “modules outside the Phoenix contexts have access to changeset functions and that is a problem”. I mean they are public; being able to call them is always on the table, this is not Java / C# / Rust et. al. where you can make functions (package|namespace)-private so you can limit who can actually call them.

A notable mention here is the boundaries library, made by Sasa Juric as well: Boundary - enforcing boundaries in Elixir projects. I’ve used it with success and I do like it but sadly I never managed to convince too many people of its value.

I am not sure I see the clear win here. Help me understand.


Maybe the actual root problem is that I worked as a contractor for several years and had to be very flexible – meaning that things that many of us as programmers would immediately agree on became actual contention points when working with different teams and CTOs. Or maybe I am just a bad developer advocate (would not surprise me :smiley:).

My summary of the advantages of Repo.transact would be (1) less boilerplate and (2) better separation of concerns. I respect and even worship both but I’ve met plenty of people who don’t so I am curious how would I sell them such a coding pattern better and be more convincing.

In any case: I am very curious as to why is the Repo.transact pattern deemed valuable (or not) by others. What other factors did I miss? Could you share your thoughts, please? Thank you.

Most Liked

sasajuric

sasajuric

Author of Elixir In Action

I wrote Repo.transact after seeing a lot of production code along the lines of what’s written in that excellent blog post by @tomkonidas.

The value proposition of Repo.transact is that control flow features such as passing data around, branching, early exit, can be implemented with standard Elixir features, such as variables, functions, and the with expression. The transactional logic is less special, and it doesn’t rely on some implicit behaviour of a function from some library.

Combined with the provable fact that the transact code is shorter (often significantly), even in such simple example as in that blog post, I have no doubt that the transact version is simpler and clearer.

That’s not to say that Multi is universally bad. The ability to provide each db operation as data is definitely interesting, and could be useful in the cases where the transactional steps need to be assembled dynamically (perhaps provided by the client code). But in the vast majority of cases I’ve encountered, I find the multi code needlessly difficult to read. This is true even in simple cases, and it becomes progressively worse if the transactional logic is more involved (e.g. if it requires branching early on in the transaction).

Hence, I strongly prefer transact, and it’s what I advise using in most situations.

27
Post #2
wojtekmach

wojtekmach

Hex Core Team

Repo.transact/2 was just released in Ecto v3.13.0.

wojtekmach

wojtekmach

Hex Core Team

I have created a PR for Repo.transaction_with:

https://github.com/elixir-ecto/ecto/pull/4577

Thanks everyone for feedback, in particular @sasajuric and @tomkonidas for writing about this.

Last Post!

wojtekmach

wojtekmach

Hex Core Team

We have no plans at the moment but yes it could be supported in the future.

Where Next?

Popular in Discussions Top

AstonJ
Are there any Elixir or Erlang libraries that help with this? I’ve been thinking how streaming services like twitch have exploded recentl...
New
und0ck3d
Hello everyone! A few days ago I’ve created a topic here about how people were creating CMSs with Elixir and Phoenix. I’ve been studying...
New
PragTob
Hey everyone, this has been brewing in my head some time and it came up again while reading Adopting Elixir. GenServers, supervisors et...
New
PragTob
Hello everyone, I know we had quite some threads (read through lots of them) about background job processing but it remains a hotly deba...
New
lucaong
Hello Elixir and Nerves community, I have been working for a while on an open-source embedded key-value database for Elixir, that I call...
230 14350 124
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
fireproofsocks
I’ve been working on an Elixir project that has required a lot of scripting. I usually reach for Elixir because I like it more (and in th...
New

Other popular topics Top

electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

We're in Beta

About us Mission Statement