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.

Where Next?

Popular in Questions Top

Tee
can someone please explain to me how Enum.reduce works with maps
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
earth10
Hi, I’m just starting to build a side-project with Elixir and Phoenix and doing some basic test with Elixir alone. What strikes me is th...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
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
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New

Other popular topics Top

sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 42842 311
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
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
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35953 110
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
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement