josefrichter

josefrichter

Nested response tuples - best practices?

Hi, in some situations I need to broadcast a message from genserver, need to say it’s error, what kind of error, and also return the element that caused the error. So I end up with something like this:

{:enrollment_processed, {:error, {:already_enrolled, enrollment}}}

I guess it’s kinda ugly and error prone. What’s the best practice to deal with this?

a) tuple with more than 2 elements
{:enrollment_processed, {:error, :already_enrolled, enrollment}}

b) merge error + type of error
{:enrollment_processed, {:already_enrolled, enrollment}}

c) other solutions?

Note I need to have enrollment in this message, because based on that I can broadcast it to the right channel and the liveview can report which enrollment wasn’t saved.

Most Liked

josefrichter

josefrichter

Thank you both. I went for flat tuples and more verbose code. I guess it’s better to have multiple smaller and simpler handler functions that are clearer and easier to reason about, especially if you look at them a few years later, or come into the project from the outside.

dimitarvp

dimitarvp

To be fair I wouldn’t even use :enrollment_processed because that implies that it finished successfully. Whatever you opt for IMO the first element of the tuple should be something along the lines of :enrollment_failed and then 2nd element and further should elaborate on why did it fail.

dom

dom

Consider two message shapes:

  1. Nested: {:processed, {:ok, item}} and {:processed, {:error, item}}
  2. Flat: {:succeeded, item} and {:failed, item}

The “nested” option makes it possible to write a generic handler for “processed”:

def handle_info({:processed, status}, socket) do
   update_status(status)
end

…but leads to extra destructuring if you have two separate handlers:

def handle_info({:processed, {:ok, item}}, socket) do
   set_succeeded(item)
end

def handle_info({:processed, {:error, item}}, socket) do
   set_failed(item)
end

The “flat” option forces you to use two handlers, but they’re more readable and efficient than the two handlers of the “nested” option:

def handle_info({:succeeded, item}, socket) do
   set_succeeded(item)
end

def handle_info({:failed, item}, socket) do
   set_failed(item)
end

So I’d recommend nesting as much as you need for pattern matching, and not more.

Last Post!

davearonson

davearonson

Yes, remember, you are communicating mainly to other developers (including yourself many months later). If we were communicating mainly to the machine, we would (still) be writing in binary.

Where Next?

Popular in Questions Top

jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
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
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New

Other popular topics Top

grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 54006 488
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
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
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New

We're in Beta

About us Mission Statement