---
title: "An intro to OTP in Elixir"
description: "In this installment in our series of introductory Elixir blog posts we’ll convert the FizzBuzz server from last time into an OTP app."
canonical: https://oozou.com/blog/an-intro-to-otp-in-elixir-20
locale: en
date: 2015-02-13
author: "OOZOU Team"
---

# An intro to OTP in Elixir

> In this installment in our series of introductory Elixir blog posts we’ll convert the FizzBuzz server from last time into an OTP app.

Published: 2015-02-13 · Author: OOZOU Team (Engineering) · 6 min read

**What is OTP?**

According to [the documentation](http://www.erlang.org/doc/), OTP — [the Open Telecom Platform](https://en.wikipedia.org/wiki/Open_Telecom_Platform) — is “a complete development environment for concurrent programming”, containing an Erlang compiler and interpreter, a database server ([Mnesia](http://en.wikipedia.org/wiki/Mnesia)), an analysis tool ([Dyalizer](http://www.erlang.org/doc/man/dialyzer.html)), as well as a lot of libraries. This latter part is what people generally refer to when talking about OTP.

**Behaviours**

One of the central [design principles of Erlang/OTP](http://www.erlang.org/doc/design_principles/des_princ.html) are application patterns, or “behaviours” in OTP lingo. They define generic implementations for common tasks, for example a generic server ([gen_server](http://elixir-lang.org/getting_started/mix_otp/3.html)) module. The application developer adds implementation specific code into a callback module which exports a set of specific functions. Unlike Erlang, Elixir provides default implementations for these functions, so you only have to override the ones you need.

**A FizzBuzz server using GenServer**

Enough theory, let’s write some code!

We use [mix](http://elixir-lang.org/docs/stable/mix/) to create a new project. Since we want the module name to be in [CamelCase](https://en.wikipedia.org/wiki/CamelCase) we have to provide the — module option, otherwise it would default to Fizzbuzz.

```
$ mix new fizzbuzz --module FizzBuzz
lang-bash
```

This command creates a whole application template, but for the purposes of this blog post we’ll only work on lib/fizzbuzz.ex.

Let’s start by letting our application know that we are implementing the GenServer OTP behaviour:

```
use GenServer
require Logger
```

We also required the [Logger module](http://elixir-lang.org/docs/master/logger/Logger.html), since we are using it for debugging purposes. Next we define the API for our clients.

```
def start_link do
   GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end

def get(n) do
  GenServer.call(__MODULE__, {:print, n})
end

def print(n) do
  GenServer.cast(__MODULE__, {:print, n})
end
```

FizzBuzz.start_link/0 is just a wrapper around [GenServer.start_link/3](http://elixir-lang.org/docs/stable/elixir/GenServer.html#start_link/3)which starts the server as a linked process, often as part of a [supervision tree](http://elixir-lang.org/docs/stable/elixir/Supervisor.html). Note that we start our server with the name option for which we use the module name (__MODULE__). This way other functions don’t have to refer to our server by PID.

FizzBuzz.get/1 and FizzBuzz.print/1 are our server’s main interface. They receive a number as an argument and return or output the corresponding FizzBuzz value. GenServer supports two request types: [calls](http://elixir-lang.org/docs/stable/elixir/GenServer.html#call/3) and [casts](http://elixir-lang.org/docs/stable/elixir/GenServer.html#cast/2). The former is synchronous and supposed to send something back to the client (our get function), whereas the latter is asynchronous and doesn’t necessarily return anything to the client (our print function).

It’s common to wrap the GenServer interface in our own client APIs, so the above pattern is worth remembering.

With that out of the way, we now go on to implement the necessary GenServer callbacks.

```
def init(:ok) do
  Logger.debug "FizzBuzz server started"
  {:ok, %{}}
end

def handle_call({:print, n}, _from, state) do
  {:ok, fb, state} = fetch_or_calculate(n, state)
  {:reply, fb, state}
end

def handle_cast({:print, n}, state) do
  {:ok, fb, state} = fetch_or_calculate(n, state)
  IO.puts fb
  {:noreply, state}
end
```

init/1 gets called by GenSever.start_link/3 and returns a tuple of the form `{:ok, state}`. In our specific case the state is a simple Elixir map (`%{}`).

handle_call/2 and handle_cast/2 are the core of our application. We use pattern matching on the first argument to specify that we handle messages of the form `{:print, n}`. The private function fetch_or_calculate/2 retrieves or calculates the value, and we then return the appropriate response. In the case of a call it will have the form `{:reply, response, state}`, whereas for a cast it will be `{:noreply, state}`. These are GenServer conventions, the [documentation](http://elixir-lang.org/docs/stable/elixir/GenServer.html) lists all possible answer types for every request type.

This is what the private helper looks like:

```
defp fetch_or_calculate(n, state) do
  if Dict.has_key?(state, n) do
    Logger.debug "Fetching #{n}"
    {:ok, fb} = Dict.fetch(state, n)
  else
    Logger.debug "Calculating #{n}"
    fb = fizzbuzz(n)
    state = Dict.put(state, n, fb)
  end
  {:ok, fb , state}
end
```

fetch_or_calculate/2 checks if the FizzBuzz value for n has been calculated before. If it has, we fetch it from the dictionary. If the value hasn’t been computed before, we do so and update the state by adding the newly computed value to it (Dict.put(state, n, fb)). Finally we return a tuple of the form `{:ok, value, state}` which we pattern match against in the handler functions.

That’s it, our FizzBuzz server is now ready for action! Here’s the complete code:

```
defmodule FizzBuzz do
  use GenServer
  require Logger

  ## Client API

  def start_link do
     GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
  end

  def get(n) do
    GenServer.call(__MODULE__, {:print, n})
  end

  def print(n) do
    GenServer.cast(__MODULE__, {:print, n})
  end

  ## Server Callbacks

  def init(:ok) do
    Logger.debug "FizzBuzz server started"
    {:ok, %{}}
  end

  def handle_call({:print, n}, _from, state) do
    {:ok, fb, state} = fetch_or_calculate(n, state)
    {:reply, fb, state}
  end

  def handle_cast({:print, n}, state) do
    {:ok, fb, state} = fetch_or_calculate(n, state)
    IO.puts fb
    {:noreply, state}
  end

  defp fetch_or_calculate(n, state) do
    if Dict.has_key?(state, n) do
      Logger.debug "Fetching #{n}"
      {:ok, fb} = Dict.fetch(state, n)
    else
      Logger.debug "Calculating #{n}"
      fb = fizzbuzz(n)
      state = Dict.put(state, n, fb)
    end
    {:ok, fb , state}
  end

  defp fizzbuzz(n) do
    case {rem(n, 3), rem(n, 5)} do
      {0, 0} -> :FizzBuzz
      {0, _} -> :Fizz
      {_, 0} -> :Buzz
      _      -> n
    end
  end
end
```

Time to use our code. In the project directory, fire up an iex session in the context of our application with the following command:

```
iex -S mix
```

Now we can start a server and compute some values:

```
FizzBuzz.start_link
4..6 |> Enum.map(&FizzBuzz.print/1)
```

Here’s the output generated by that command. Due to the asynchronous nature of the requests the outout, log messages and the function’s return value are interleaved:

```
4

10:54:58.026 [debug] Calculating 4
Buzz
[:ok, :ok, :ok]

10:54:58.028 [debug] Calculating 5
Fizz
```

Note how despite running in a separate process, the output of IO.puts happened in our iex session, since that’s the current [group leader](http://elixir-lang.org/getting-started/io-and-the-file-system.html#processes-and-group-leaders).

If we now try to fetch an already computed value (FizzBuzz.get(5)), we can see that it’s actually retrieved from the cache:

```
10:58:56.774 [debug] Fetching 5
:Buzz
```

**Summary**

In this post we explored how easy it is to implement server applications by leveraging OTP. Our FizzBuzz server is now ready to be deployed as part of a bigger Elixir application, offering features like supervision and hot code swapping.

**Resources**

- [Official OTP documentation](http://www.erlang.org/doc/)
- [Elixir OTP tutorial](http://elixir-lang.org/getting_started/mix_otp/1.html)
- [The Little Elixir and OTP Guidebook](http://www.exotpbook.com/)

---

Contact OOZOU: hello@oozou.com · +66 2544 0000 · https://oozou.com/contact

More for AI agents: https://oozou.com/llms.txt · every page has a markdown twin at its URL plus ".md"
