Background
After reading Elixir in Action I came with a (slightly modified for my evil purposes) module that I very originally call the ProcessRegistry
. Now this module works and is fine, it also has a behaviour defined, but everything is in the same file and it feels tangled to me, specially after reading this post from pragmatic Dave Splitting APIs, Servers, and Implementations in Elixir.
Code
So, following is the file called ProcessRegistry:
defmodule Clint.IProcessRegistry do
@type via_tuple_type ::
{:via, module, {module, {module, any}}} |
{:via, module, {module, {module, any}, any}}
@callback lookup(tuple) :: [{pid, any}]
@callback update_with_value(tuple, any) :: {any, any} | :error
@callback via_tuple(tuple) :: via_tuple_type
@callback via_tuple(tuple, any) :: via_tuple_type
end
defmodule Clint.ProcessRegistry do
@behaviour Clint.IProcessRegistry
alias Clint.IProcessRegistry
###############
# Public API #
###############
@impl IProcessRegistry
def lookup(key), do: Registry.lookup(__MODULE__, key)
@impl IProcessRegistry
def update_with_value(key, new_value), do:
Registry.update_value(__MODULE__, key, fn _old_value -> new_value end )
@impl IProcessRegistry
def via_tuple(key), do:
{:via, Registry, {__MODULE__, key}}
@impl IProcessRegistry
def via_tuple(key, value), do:
{:via, Registry, {__MODULE__, key, value}}
@spec start_link() :: {:ok, pid} | {:error, any}
def start_link, do:
Registry.start_link(keys: :unique, name: __MODULE__)
#############
# Callbacks #
#############
@spec child_spec(any) :: Supervisor.child_spec
def child_spec(_) do
Supervisor.child_spec(
Registry,
id: __MODULE__,
start: {__MODULE__, :start_link, []}
)
end
end
It’s a fairly small file with 53 lines, but it has a couple of things that bother me:
- The Contract and the Implementation are defined in the same file. I really don’t like this.
- According to pragmatic Dave, the API and the implementation are mixed together.
For the first point, I don’t really think there will ever be another implementation of ProcessRegistry
that doesn’t use Elixir’s Registry
. Yes, I could go on an adventure and re-invent the wheel, but what for?
How many of you had to re-implement registry’s functionality for your own projects after Elixir 1.4? What is so bad about the current implementation of Registry (or so lacking) that would make you re-implement it? Short summary, I don’t really think I need a Contract for this, because I don’t see a future where ProcessRegistry
will have (or need) an implementation that doesn’t use Elixir’s Registry.
The second point is even more contentious. From what I understand, even without the behaviour, Dave would not approve of my “mixing of concerns” between the API and the Registry module. He would define a module called ProcessRegistry
with the API, and then inside a folder with the same name he would create a module with a completely useless name like impl
and there I would have the calls to Registry.
I attack this idea based on the fact Dave likes to complain about useless folders and boilerplaty code, but I find that in my specific case, this is what I would be creating - more boilerplate and indirection.
Opinions
- Have you read Dave’s small article? What do you think?
- How can I improve this module and this code? Let me know !