henriquesati

henriquesati

How can I do a better code and architecture design with Elixir Erlang and FP principles

Hi, I’ve been developing a project for a few months and since the beginning i’ve been paying attention to the design of my code, writing it modular, well separated and those kind of things, but it’s been growing and i’m missing something I dont really know what. I’m often kind of lost of what a module or service returns, you now like when a module calls a module that calls a module that calls another module, and I caught myself open a few archives to check the returns. I think what is missing for me it’s some kind of architecture guide, something like interfaces to know exactly what x or y returns, so I’m here asking for some general or personal resources into that.
To give an example, I have the a controller that at some point calls another module

defp handle_answer(%{"payload" => payload, "status" => status, "meta" => meta}) when is_boolean(status) do
    case status do
      true -> handle_paid_pix(payload)
      false -> handle_failure_pix(payload, meta)
    end
  end

  defp handle_answer(_), do: {:error, FE.initerror("validation", "invalid payload")}

  defp handle_paid_pix(payload), do: TransactionRealm.handle_pix_paid(payload)
  defp handle_failure_pix(payload, meta), do: TransactionRealm.handle_pix_failed(payload, meta)

but then in this module I got more calls to another modules

 def handle_pix_paid(payload) do
    PixTransaction.handle_pix_paid(payload)
  end

  def handle_pix_failed(payload, meta) do
    PixTransaction.handle_failure_pix(payload, meta)
  end

    def handle_pix_paid(payload) do
        with {:ok, _} <- MnesiaPendingContractsDomain.update_payment_status({:payload,  payload, :pix_paid}),
            {:ok, _} <- EctoContractsDomain.update_payment_status({:payload, payload, :pix_paid}) do
            :ok
        else
            {:error, _} = error -> error
        end
    end

    def handle_failure_pix(payload, meta) do
        with {:ok, _} <- MnesiaPendingContractsDomain.update_contract_meta({:payload, payload, meta}) do
            :ok
        else
            {:error, _} = error -> error
        end
    end

I dont know if its on my mind but really feels like a terrible spagetthi code terrible typed and error prone. As I said at the beginnig designing that way was no problem, but i’m really a constraint that ties my code which makes it cohesive and well-fitted. Sorry if it’s a very abstract question, I tried to explain it as best I could.

Most Liked

garrison

garrison

Perhaps this is a silly reply but have you tried just not doing that? It’s not clear to me if these examples are your real code or not, or why you’ve chosen to structure your code in this way, but it looks like a lot of those functions aren’t actually doing anything, at all.

This is why I typespec all of my functions :slight_smile:

sodapopcan

sodapopcan

Definitely very abstract and I don’t know any resources off hand. My best advice would be to “unread” Clean Code :sweat_smile:

But seriously, I can point out a few things here.

As an easy one, there is little point in extract single-user private function calls (as in the case status do line). This doesn’t help readability at all, it just makes it so you have to keep jumping around to get the full picture.

This sorta continues on into the bit with handle_pix_paid. Seems that is abstracting over the complicated arguments required for Mnesia and Ecto ({:payload, payload, :pix_paid}) but you could just push that complexity into their respective modules and called them directly, something like MnesiaPendingCtractsDomain.complete_payment(payload). Just by the names too it seems like your modules may be way too granular. Without seeing the implementation, my intuition is that you are mimicking the OO service pattern. The best FP advice I can give you is to just start with simple functions. Start organizing as you need to. Again, since modules don’t hold state, they are much easier to refactor than classes since you can just move a function to another module with realative ease.

henriquesati

henriquesati

Not silly at all :slight_smile:

Where Next?

Popular in Discussions Top

Donovan
Hello everyone, I’m so glad to have discovered this awesome community. Thanks for creating it! This is my second post, and apologies for...
New
blackode
Elixir Upgrading is so Simple in Ubuntu and It worked for me Ubuntu 16.04 git clone https://github.com/elixir-lang/elixir.git cd elixir...
New
cvkmohan
The upcoming Phoenix 1.6 release looks very interesting. Became a habit to watch the commits - and - what they are bringing in. phx.gen...
New
New
PragTob
Hey everyone, this has been on my mind for some time and I’d love your input on it! TLDR: I feel like maps are superioer for storing and...
New
chulkilee
Here are the list of HTTP client libraries/wrappers, and some thoughts on HTTP client in general. I’d like to hear from others how they w...
New
AstonJ
If so I (and hopefully others!) might have some tips for you :slight_smile: But first, please say which area you’re finding most challen...
New
wmnnd
The Go vs Elixir thread got me thinking: Would it be too hard to implement a simple mechanism for creating Go-style static app binaries f...
New
griffinbyatt
Sobelow Sobelow is a security-focused static analysis tool for the Phoenix framework. For security researchers, it is a useful tool for g...
New
sashaafm
Piggy backing a bit on @dvcrn topic BEAM optimization for functions with static return type?, I’ve been trying to understand in a deeper ...
New

Other popular topics Top

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
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
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
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
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
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement