jola

jola

Let libraries be libraries

I’ve been bumping into some rough edges recently with Elixir dependencies that use app config and start their own supervision trees and I want to petition the community to move towards better library design

First Post!

tubedude

tubedude

Thanks! finally I understood the critics I’ve been receiving in my library!

Most Liked

hauleth

hauleth

That is not true. You can 100% connect to different DBs using the same module. It is not common practice, because that is not the common problem, but it is fully supported and documented.

MyApp.Repo.start_link(
  name: :some_client,
  hostname: "client.example.com",
  username: "...",
  password: "...",
  pool_size: 1
)

It is not fully ergonomic, I agree, but at the same time that is not a common situation when you need such thing.


About the topic, I mostly agree with @jola. There are however grey areas sometimes. If you use Application just for env, then yeah, it is dumb, but there are situations when there is no point in having multiple instances of the processes provided by the library. Like in my systemd library, where there is no point in having multiple instances, and moving that to the user-side to manage processes for this would only make it worse wrt. UX.

Another thing is that sometimes the process running in the background should be transparent to the user. Like in my aww library. Some may argue, that cache there is a wrong approach and user should cache on their own. But at the same time, when you are using (most of the time indirectly) Erlang’s DNS resolver do you think that there is a cache for A and AAAA responses? Because there is one.

Another thing that uses their own supervision tree, but people do not think about it at all, is Telemetry. Yeah, really, there is supervision tree. To be fair, it would be impossible to implement without that tree (at least if we want to use ETS, after you fire :telemetry.persist() it is not needed anymore).

So I would say that it is a complex topic, but when in doubt - do not spawn your own supervision tree, you ain’t gonna need one probably.

mudasobwa

mudasobwa

Creator of Cure

Sometimes we want to take control over the supervision tree, sometimes we just expect the library to do its work once added to mix. Sometimes the configuration is an anti-pattern, in 99% of cases it’s not, specifically in modern environment when it’s all containerized. Also, starting an application is necessary if it needs to track the main application startup.

I finally came up to a compromise. I declare the application in my libraries, empty-handed by default. Then I got an option to have a config and I use it to start the supervision tree within the application.

cevado

cevado

A few years ago I wrote an article on that(and I just discovered that my abandoned blog is down bc the domain expired :person_facepalming:, i’ll send the link here if i’m able to get the old domain set or if i setup a new domain), I was way less polite and ranted a lot about the subject.

Supervision trees are not for DX, they’re for resiliency, DX is your libarary with good defaults so just a plain copy/paste of your docs resolve 90% of the needs someone have.

It feels really terrible when a library hijacks the power to define how your app starts and recovers, and supervision tree is about that, not about ease of use.

Again, needing just one instance of a supervision tree is not the issue, it’s aboult controlling how it gonna behave when it fails. If you just need one instance, make your childspec use a name scoped by your library, or allow it to optionally receive the name and default to getting the name from the application env that the user can set, the dev using it decides where it sits in their supervision tree, it doesn’t lose usability, it doesn’t hijack the control over what should bring the app down or not.

Not to the quoted people here, but people writing libraries need to remember once an application that your app depends doesn’t start it blocks the entire application of starting, I’ve had a lot of issues just because one particular library couldn’t start and it was impossible to start a new instance of the app no matter how I configured their library, I’d need to remove them of my dependencies to make it work.

For writing applications instead of libraries my rule of thumb is: can you assure there is no scenario where using your application as dependency will block the main app of starting? If you can’t assure that, create a worker and allow people to set their supervision tree appropriately to the place your library have in their systems.

Last Post!

Oliver

Oliver

Isn’t this just to a good degree a crutch for configurability and shared state problems?

I personally am lucky enough to only use true library dependencies, not being part of the elixir web dev world but the other… 5?.. percent or whatever, so these stacks and ecosystems people typically use do not impact me.

But then I create my own application stack and run into the same problems, how to efficiently share state and configuration around if needed, and often reinventing the wheel, I guess. Part of it is that there are so many options… do I want a full-fledged DB, a key-value in the application, or with ETS, or do I want to optimize for read-only values… what are my guarantees, my performance… ease of use vs. my own requirements. I guess some of this could benefit from a unified layer allowing you to switch between options and their guarantees. Maybe somebody already did that.

If an external application added to this mess, I would not be happy. That’s why I personally am somewhat biased against dependencies that are apps, not saying they have no place, but I’d rather have control over certain aspects of my system. I do badly enough on my own writing distributed systems…

Where Next?

Popular in Blog Posts Top

alexgaribay
I saw this thread so I decided to write about how we do it :smile:
New
blackode
https://medium.com/blackode This article comprises of two biggest changes of ExUnit. Arguments in the failure report Running mix tes...
New
paulanthonywilson
So you’re enjoying using WebSockets with Elixir’s Phoenix Framework, and you want to send some binary messages. Maybe it’s an audio clip,...
New
sheharyarn
In this article, I talk about the Elixir library Delta we at Slab just open-sourced, its various features including support for Operation...
New
brainlid
You are storing some Phoenix LiveView state in the browser. You want to retrieve that saved state as early as possible to improve the use...
New
ragamuf
Does the world need another How to create a blog article? Maybe not. But then again, creating something out of nothing is what we love....
New
victorbjorklund
I’m showing you how you can customise the phx.new generator to give you a new Phoenix project the way YOU want it. In this post I show yo...
New

Other popular topics Top

Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 49134 226
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
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
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

We're in Beta

About us Mission Statement