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
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
mudasobwa
Just blogged on the general approach to creating easily extendable applications with plugin support.
New
brainlid
In a 2 day spike, I created my own Elixir-based AI Personal Fitness Trainer! The surprising part for me was how useful and helpful I foun...
New
danschultzer
How to set up the Content Security Policy header with Phoenix LiveView and support inline styles and scripts with CSP nonces.
New
PragTob
Elixir is a great language, but some behavior can be unintuitive, confusing and in the worst case lead to bugs. So, I took a look at 10 E...
New
New

Other popular topics Top

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
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
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
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New

We're in Beta

About us Mission Statement