Library configuration - multi-instance

Let me see if I can clarify this a bit. If we have this code:

config :my_lib, MyRepo,
  adapter: Sandbox # value is determined at compile time

defmodule MyRepo do
  defp adapter do
    # Even if next line is called during app boot, it uses a compile time value
    Application.get_env(:my_lib, MyRepo)[:adapter]
  end
end

The adapter isn’t actually being “compiled” into the MyRepo module. Its always being fetched from the application env. That means its possible to do something like this:

# The adapter is set from when `config.exs` was initially run
Sandbox = MyRepo.adapter()

# Update the config...
Application.put_env(:my_lib, MyRepo, [adapter: DBAdapter])

# Now the adapter has changed
DBAdapter = MyRepo.adapter()

Its possible to compile the adapter directly into the module doing something like this:

defmodule Repo do
  defmacro __using__(_opts) do
    quote do
      @before_compile unquote(__MODULE__)
    end
  end

  defmacro __before_compile__(env) do
    a = Application.get_env(:my_lib, Repo)[:adapter]

    quote do
      def adapter do
        unquote(a)
      end
    end
  end
end

defmodule MyRepo do
  use Repo
end

This will cause the adapter function to be hard-coded with the adapter module into MyRepo.

Hopefully that provides some clarity :).

Everything else seems spot on to me :+1:.

In my applications and services I’ll often use this pattern:

defmodule Server do
  def start_link(opts) do
    GenServer.start_link(__MODULE__, state, name: opts[:name] || __MODULE__)
  end

  def foo(server \\ __MODULE__, args) do
    GenServer.cast(server, {:foo, args})
  end
end

This gives me a lot of flexibility when testing the server and provides reuse. But, I don’t tend to use this pattern in libraries because it can create name conflicts if 2 different users try to use the default name. Passing the name around can definitely be annoying, but I haven’t found a better pattern that still provides the same level of flexibility. At this point I’m used to passing the name or a pid as the first argument to my function calls.

Likewise :slight_smile: