Tidying Up the Interface

As we left it, our server works but is ugly to use. Our callers have to make explicit GenServer calls, and they have to know the registered name for our server process. We can do better. Let’s wrap this interface in a set of three functions in our server module: start_link, next_number, and increment_number. The first of these calls the GenServer start_link method. As we’ll see in the next chapter, the name start_link is a convention. start_link must return the correct status values to OTP; as our code simply delegates to the GenServer module, this is taken care of.

Following the definition of start_link, the next two functions are the external API to issue call and cast requests to the running server process.

We’ll also use the name of the module as our server’s registered local name (hence the name: __MODULE__ when we start it, and the __MODULE__ parameter when we use call or cast).

otp-server/2/sequence/lib/sequence/server.ex
 defmodule​ Sequence.Server ​do
 use​ GenServer
 
 #####
 # External API
 
»def​ start_link(current_number) ​do
  GenServer.start_link(__MODULE__, current_number, ​name:​ __MODULE__)
 end
 
»def​ next_number ​do
  GenServer.call __MODULE__, ​:next_number
 end
 
»def​ increment_number(delta) ​do
  GenServer.cast __MODULE__, {​:increment_number​, delta}
 end
 
 #####
 # GenServer implementation
 
 def​ init(initial_number) ​do
  { ​:ok​, initial_number }
 end
 
 def​ handle_call(​:next_number​, _from, current_number) ​do
  { ​:reply​, current_number, current_number+1 }
 end
 
 def​ handle_cast({​:increment_number​, delta}, current_number) ​do
  { ​:noreply​, current_number + delta}
 end
 
 def​ format_status(_reason, [ _pdict, state ]) ​do
  [​data:​ [{​'State'​, ​"​​My current state is '​​#{​inspect state​}​​', and I'm happy"​}]]
 end
 end

When we run this code in IEx, it’s a lot cleaner:

 $ iex -S mix
 iex>​ Sequence.Server.start_link 123
 {:ok,#PID<0.57.0>}
 iex>​ Sequence.Server.next_number
 123
 iex>​ Sequence.Server.next_number
 124
 iex>​ Sequence.Server.increment_number 100
 :ok
 iex>​ Sequence.Server.next_number
 225

This is the pattern that just about everyone uses in the Elixir world.

I have a different view. However, it certainly isn’t mainstream, so feel free to skip the next section if you want to avoid becoming tainted by my heresies.