oliveiragahenrique

oliveiragahenrique

Pure functional module successful response format

I’m designing a pure functional data structure to manage banking accounts, a simplified version of it would be:

defmodule Account do

  defstruct balance: 0, limit: -500

  def new() do
    %Account{}
  end

  def deposit(%Account{} = account, amount) do
    new_account =
      %Account{account | balance: account.balance + amount}

    {:ok, new_account}
  end

  def withdraw(%Account{} = account, amount) do
    new_balance = account.balance - amount

    if new_balance >= account.limit do
      new_account =
        %Account{account | balance: new_balance}

      {:ok, new_account}
    else
      {:denied, "No funds", account}
    end
  end
end

My question is about when should I use the response pattern of {:ok, data} for sucess and {:error, reason, unchanged_data} for failures.

This sounds like the way to go here on this problem, but if I go with this pattern I lose the feature of do something like this:

account = 
  Account.new()
  |> Account.deposit(%{amount: 5000})
  |> Account.deposit(%{amount: 3000})
  |> Account.withdraw(%{amount: 1000})

I really like to design modules that could use the pipe operator like this, but how to do this when the module functions can fail?

If I just remove the :ok from the sucess response would solve the problem, but is this a good pattern?

What you guys think? How can I keep the pipe feature together with a good response check validation?

Marked As Solved

kokolegorille

kokolegorille

If the pipeline can break, I would use with

with {:ok, a} <- Account.deposit(Account.new(), %{amount: 5000}),
  {:ok, a} <- Account.deposit(a, %{amount:3000}),
  {:ok, a} <- Account.deposit(a, %{amount: 1000})
do
  # do something with a
else
  {:error, _} -> ...
end

Also Liked

bottlenecked

bottlenecked

@rrrene has written a series of articles on data flow patterns that perhaps could help. You may want to read up on the Token-based approach for your specific use case.

Where Next?

Popular in Questions Top

shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
logicmason
Hi there, I'm working through my first release with elixir/phoenix. I've built a release with distillery and found that it crashes when I...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
Fl4m3Ph03n1x
Background Let’s assume I have a typical GenServer that receives messages as requests, does some operation in a DB and returns responses....
New
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
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
idi527
I’ve been re-reading swift book again and noticed that multiline strings there don’t have a trailing line break, unlike in elixir iex(2)...
New

Other popular topics Top

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
sergio
I couldn’t find any guides that worked well with Phoenix 1.6.0 and esbuild. I hope this helps people test the waters and eases you into t...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
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
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
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
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

We're in Beta

About us Mission Statement