Behaviour implemented by a GenServer

I want to create a behaviour to abstract the usage of two different but similar in functionality libraries. This way I will be able to switch easily between one or the other in the lifetime of the project, depending of some criteria (is the lib efficient, good maintained etc).

Each of these library is implemented with a GenServer. For my behavior,

  • do I need to declare the GenServer functions (start_link etc) in my behaviour?
  • can I specify that my behaviour “inherits” the GenServer behaviour?
  • are the answer to the two questions above “no” and the user needs to look at the documentation to see he/she needs to call start_link before being able to use the other function of the behaviour?
1 Like

The behaviour specifies a set of functions which your module needs to define. A module can have multiple behaviours, but they should not overlap unless you know what you are doing.

Also why do you want to enforce a GenServer for your behaviours? This will shoot yourself in the foot when you later on decide to add a third module with that behaviour but implementing it using Ports or :gen_statem…

1 Like

Since the user will have to call start_link or start anyway, I thought it should be part of the contract. Somehow I wanted to make this explicit. I was expected that reading the behaviour would be enough for the users to use the concrete implementation, but I see your point now.

1 Like

start_link or start are not part of the GenServer behaviour, so you can safely make them part of yours.

2 Likes

Precisely. All the handle_call/cast/init callbacks are pretty much private GenServer API, and you should not be using it directly. These are public functions, yes, but external modules never call them. You can declare your API as behaviour and be done, the rest are implementation details.

2 Likes