dimitarvp

dimitarvp

Advice how to go about library configuration from Elixir 1.9 and on?

Hey everybody,
In light of the recent Elixir 1.9 announcement, I’d like the first library I write to not use Mix.Config. (It is an sqlite3 library with an Ecto 3 adapter.) To that end, I’ve come to several alternatives while thinking and sketching code, and I am curious what anybody has to say as a preference or recommendation.

  1. Process dictionary. I really like this but it comes with the arrangement that the user of the library will either (a) take special care to only use designated processes to interact with my library, or (b) will use it from anywhere they want but have to clean up the process dictionary keys after they are done with a task. As much as I like the process dictionary, it does really sound like going back to imperative languages where there’s an implied context / state to watch out for.

  2. Have a GenServer that centralises the access to the limited resource my library is managing (connections / open handles to a sqlite3 database [file]), and include helper functions that merge config options to the GenServer's state (a map). Clean, beautiful, makes perfect use of the OTP.

  3. Make the handle object used to initiate any operation in the library also encompass configuration. This I also like quite a bit since it’s a pure FP approach and doesn’t rely on implied context / state.


Other ideas are welcome as well.

I’m leaning towards starting with (3) because that will give the users of the library a GenServer-less use case. And then adding (2) because then the users of the library can also just name their sqlite connection and the OTP will take care of dispatching their calls to the appropriate GenServer.

Again, I like (1) a lot but it doesn’t feel right to me.

Opinions? Ideas? Criticisms?

Most Liked

tristan

tristan

Rebar3 Core Team

For runtime configuration of your library you simply document the configuration options that the user will put in their releases.exs.

I can’t say I’ve seen this much in Elixir so I may be off base here but in Erlang we put defaults in the .app/.app.src file under the env key. You can do the same with the application configuration in your mix.exs.

But this is all assuming a use case that makes sense to have configuration read in from the environment. It depends on the application whether that makes sense or if it is a case better to have the user passing in a a set of configuration values when calling a function in your application.

Also your (2) and (3) aren’t mutually exclusive. If you have an application that must start servers you likely want to give the user a way to start them in their own supervision tree and have them pass in configuration to the start_link of whatever they are starting from your application.

(1) should never be used :). Not that the pdict should never be used, just almost never, but for configuration I think it is safe to say just “never”.

wojtekmach

wojtekmach

Hex Core Team

Definitely pass the data around. If you use global configuration (e.g. application env) it means
you have less flexibility, you only have one configuration and so you can’t configure this
connection with X and that connection with Y.

As others have mentioned you likely have some startlink/init/connect/new/whatever function, so accept configuration there and pass it around to further calls. And if passing options is annoying to the users of the library they can (and often should) wrap the library with their own module.

LostKobrakai

LostKobrakai

I don’t think your options 1/2 really hit the nail for what the guidelines and removal of /config are meant to push people to.

If you have a library and no (configurable) processes are being started => accept config as parameters to functions. This could be supplying fresh config to each call, but also a config = MyApp.Config.validate(input) token to be passed around.

If you have processes being started, which need user configuration, let the user start those processes in their applications supervision tree and accept config as start arguments. Let your library functions receive a pid/registered name as argument to know which processes to call into (like e.g. GenServer.call). This isn’t really limited to a single process as well. What the user interacts with could just be a top level supervisor with many children.

If you have done the above things you can look into making configuration more convenient and less manual by additionally harnessing e.g. the application environment, process dictionary or having compile time config provided via macros (like e.g. Ecto.Repo does it). You could compile simpler API functions into some modules (MyModule.func(…) instead of Lib.func(MyModule, …)). This allows user to use those “limiting” configurations options if it fit’s their usage, but they can still go the more manual way and configure stuff via parameters/start arguments for more complex usecases.

jola

jola

There’s this approach, making the user explicitly pass init options.

I don’t understand what you mean about the 1.9 release though. It didn’t remove configuration, it just replaced Mix.Config with Config, and stopped generating a config folder for new projects (because libraries rarely need their own configuration). Those libraries still want to read configuration from the user though, so eg the phoenix generator will keep creating a config folder.

For compile time configuration, Config is still your best bet.

LostKobrakai

LostKobrakai

I’d say this can be reason enough to not want to restart a process.

Where Next?

Popular in Questions 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
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
pgiesin
This should be a simple problem but I just can’t seem to figure it out. I have a standalone Elixir app that won’t find the database. Dep...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
sacepums
Hey guys. I'm new to elixir and im really stocked about it. But I ran into a bit of problem - I need to convert a date sting, for examp...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
chewm
Hi guys, nice to meet you to the whole forum, I’m new here, I’m trying to configure visual studio code for elixir, right now the intellis...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
Exadra37
Sometimes I want to check if the input into a function is not a blank string. My first approach: defmodule Example do def do_stuff(s...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Other popular topics Top

sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
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
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
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

We're in Beta

About us Mission Statement