ppicom

ppicom

Designing Elixir Systems With OTP - isn't the integration pattern interfering with business logic?

Hello! :wave:

I recently completed the book and highly recommend it to anyone looking to deepen their understanding of OTP (especially if you’re relatively new to Elixir and Erlang, as I am).

Now, onto my question :grin: The authors’ approach to integrating the persistence layer using a poncho project—where a persistence_fn function is passed to the core project—raised an interesting thought for me.

The original implementation of the :answer_question handler creates a new Response, uses it to advance the Quiz (by calling answer_question and select_question), and concludes the quiz if no questions remain. Here’s the code:

def handle_call({:answer_question, answer, fun}, _from, {quiz, email}) do
  response = Response.new(quiz, email, answer)

  quiz
    |> Quiz.answer_question(response)
    |> Quiz.select_question()
    |> maybe_finish(email)
end

defp maybe_finish(nil, _email), do: {:stop, :normal, :finished, nil}

defp maybe_finish(quiz, email) do
  {
    :reply,
    {quiz.current_question.asked, quiz.last_response.correct},
    {quiz, email}
  }
end

After incorporating the poncho project and modifying the handler to expect an external function, the implementation changes as follows:

def handle_call({:answer_question, answer, fun}, _from, {quiz, email}) do
  fun = fun || fn r, f -> f.(r) end
  response = Response.new(quiz, email, answer)

  fun.(response, fn r ->
    quiz
    |> Quiz.answer_question(r)
    |> Quiz.select_question()
  end)
  |> maybe_finish(email)
end

defp maybe_finish(nil, _email), do: {:stop, :normal, :finished, nil}

defp maybe_finish(quiz, email) do
  {
    :reply,
    {quiz.current_question.asked, quiz.last_response.correct},
    {quiz, email}
  }
end

By default, fun retains the original behavior, but now the user can pass a custom fun. If the passed fun does nothing, Quiz.answer_question and Quiz.select_question will no longer execute, preventing the quiz from progressing.

Am I correct in understanding that this integration effectively allows a “third party” (the poncho project) to interfere with the core business logic? Or am I overlooking something? :thinking:

PS: I haven’t contacted the authors to paste that code in here. If it’s against the rules, I am happy to take it down.

Most Liked

JEG2

JEG2

Author of Designing Elixir Systems with OTP

Thanks for the support and high praise.

You have it right. As an author, you are usually wrestling with the balance of making the example meaty enough to be meaningful versus needing so much code that the examples go on and on for pages. It’s a difficult tightrope to walk.

Do I think this code is the best it could be? No. The function should probably be executed in some error isolating construct and the return value be ignored if it doesn’t conform to some strict protocol. Sadly, that would just require more code. As it is, that book is on the high side of what a lot of folks tolerate as far as lengthy examples go.

It’s worth noting that this design of persistence is not at all common in our community. I don’t expect you to run into a lot of examples like this. It’s far more common to see database constructs driving the initial design of the core business code, in my experience. You can read more about those tradeoffs in this thread.

I will say this, though. I stand by the value of the approach in the book. I wish more people would consider it. I acknowledge all of the tradeoffs discussed in the thread above. However, I often find that the state I want in the application differs significantly from how data is stored in long term persistence. For example, if I am managing a chess game, the running application cares about the current state of the board and where all the pieces are. But as a rich history of the game of chess has taught us, what we want to persist is the list of moves that can be used to recreate and study the game. These are two very different needs and I believe there’s a lot of value in separating those concerns.

That’s just one person’s opinion. Hopefully it will give you some fun new ideas and help you discover better designs for your own projects.

Thanks again for the kind words about the book.

lessless

lessless

Amen to that! I really wish people would use data models preserving context. The SQL model gives a lot of convenience but the costs are not always a part of the initial discussion.

And as you said the app/db impedance mismatch leading to anaemic domain models is a story that happens more often than not.

LostKobrakai

LostKobrakai

I feel like a big reason for people to go with database driven designs is doing „web“. Http is a stateless protocol and we‘re expected to always be able to „cold start“ serving requests through http. Adding stateful handling will always feel like more work in such an environment (it is) and more work needs justification. Justification however can only be provided having seen the potential benefits of an stateful approach.

LiveView is imo a great technology to explore constraints and benefits even in a web space, where you have static stateless renders as well as stateful connected processes.

I‘d phrase this differently. The provider of the implementation doesn‘t „infer“ with the business logic. It „provides“ the business logic. If it provides one where progress is impossible it just is this way. It‘s no other code‘s job to prevent this.

JEG2

JEG2

Author of Designing Elixir Systems with OTP

:wave:

No offense taken.

I have no notes. :smile:

Thanks you so much!

ppicom

ppicom

Hi there, James! :wave: Thanks for hopping on the thread, I really appreciate it :smile:

Yeah, that makes sense and, I totally understand. In all honesty, when I posted that question I was coming from a place of ignorance, not criticism (and I’m still in that place, I haven’t yet escaped that place :grin:). Moreover, one does not get many chances of saying “poncho project” in public, I couldn’t let this opportunity slip by!

Thanks for that as well. I found the code in the book profoundly insightful, and I hope I haven’t come across as judgmental or overcritical. My goal was to understand it better, not to nag about the code. After reading it I was left with a feeling of having missed something important that gnawed at my head, and went straight to the community to get the knowledge.

Thanks for sharing!

Where Next?

Popular in Chat/Questions Top

svetarosemond
I’m planning on purchasing Elixir in action second edition, and I was wondering if anyone could tell me based off the first edition, does...
New
nur
https://e.planaria.network/stack.png https://e.planaria.network Build a NoSQL DB, Build a Relational SQL Database, Build a Graph Datab...
New
pietrofxq
I’ve bought the following books: Programming Elixir 1.6 Programming Phoenix 1.4 Programming Ecto Functional Web Development with Elixir...
New
Lincxx
Hello, I’m sure this has been asked a bunch, but where to start. I do prefer vodeos over books, but recently I have found books to be mor...
New
sadcad
I love the Phoenix and Elixir docs, but I always tend to learn faster when I watch a video of someone explaining things and then I implem...
New
makeitrein
More Ecto questions! More madness! The context: there’s a list of books that I want to filter with a dropdown… The dropdown: looks some...
New
zervis
Hello, I’m about to dive into web development. I was thinking about Laravel or Ruby on Rails, but then I found Phoenix. Do you recommen...
New
Nvim
Anybody know of a Pragmatic Studio 40% off coupon code for video course like Phoenix?
New
shansiddiqui94
Hello, I have an interview coming up and I seem to have forgotten important concepts of Elixir. So I was wondering if you guys know of a...
New
AstonJ
It’s been a while since we asked this - I’m sure others (especially newcomers to the language) will be interested to hear how you’ve all ...
New

Other popular topics Top

srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
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
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
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
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
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
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

We're in Beta

About us Mission Statement