---
title: '"Tell, Don''t Ask" in Elixir: A Story of Pattern-Matching

  '
teaser: 'Write declarative Elixir code by applying "Tell, Don''t Ask".

  '
tags: web,phoenix,functional programming,elixir
author: Josh Clayton
published_on: 2016-12-21
---

["Tell, Don't Ask"] is a [well-covered][well-covered] [topic][topic] within
object-oriented programming communities. Its goal? Encourage encapsulation by
having the caller **tell** an object to do something instead of checking on
state and acting upon it. Almost at odds with the [control couple] code smell,
our goal is to have the caller issue explicit commands without concerning
itself with object state.

["Tell, Don't Ask"]: https://thoughtbot.com/blog/tell-dont-ask
[well-covered]: http://martinfowler.com/bliki/TellDontAsk.html
[topic]: http://c2.com/cgi/wiki?TellDontAsk
[control couple]: https://github.com/troessner/reek/blob/master/docs/Control-Couple.md

## "Tell, Don't Ask" in Elixir

[Is Elixir object-oriented?] From a paradigm perspective, Elixir is a
functional language when looking at aspects like immutability,
pattern-matching, and functions with inputs and outputs, focused on the sending
of messages to "objects" directly. How does "Tell, Don't Ask" translate?

[Is Elixir object-oriented?]: http://tech.noredink.com/post/142689001488/the-most-object-oriented-language

Thinking about the goal, let's do some mental mapping. In OOP, objects are a
blueprint with information containing behavior (methods) and data (state).
In FP, we have functions organized within modules, with state being captured in
various values (e.g. Elixir's Maps or Structs). We want to avoid having the
caller (a function) dictate paths based on information present in our data.

Let's write out some non-idiomatic Elixir and see what we can improve.

```elixir
defmodule Game.Lobby do
  def add_player(%{game: game} = lobby, player) do
    new_player = cond do
      is_binary(player) ->
        %Game.Player{name: player, id: Game.Player.generate_id}
      is_map(player) ->
        %Game.Player{} |> Map.merge(player)
      true ->
        %Game.Player{}
    end

    %{lobby |
      game: %{game | players: game.players ++ [new_player]}}
  end
end

defmodule Game.Player do
  defstruct id: 0, name: "New player", active: true

  def generate_id do
    UUID.uuid4()
  end
end
```

`Game.Lobby.add_player/2` doesn't feel right. There's a significant amount of
[feature envy] as it cares about the various shapes of `player` and how to
construct a `%Game.Player{}`. Also, why is `Game.Player.generate_id/0` public?
It seems all `Game.Lobby.add_player/2` should care about is managing its own
structure (the final two lines of the function).

[feature envy]: http://c2.com/cgi/wiki?FeatureEnvySmell

Instead of having `Game.Lobby.add_player/2` care about constructing players,
generating ids, and so on, let's **tell** `Game.Player` to handle that instead:

```elixir
defmodule Game.Lobby do
  def add_player(%{game: game} = lobby, player) do
    %{lobby |
      game: %{game | players: game.players ++ [Game.Player.new(player)]}}
  end
end

defmodule Game.Player do
  defstruct id: 0, name: "New player", active: true

  def new(name) when is_binary(name), do: new(%{name: name, id: generate_id})
  def new(a)    when is_map(a),       do: %__MODULE__{} |> Map.merge(a)
  def new(_),                         do: %__MODULE__{}

  defp generate_id, do: UUID.uuid4()
end
```

Here, we move player generation to the `Game.Player` module, where it can
determine how best to generate the struct instead of `Game.Lobby.add_player/2`.

## Write declarative (not imperative) code

By moving player creation logic from `Game.Lobby.add_player/2` to
`Game.Player.new/1`, we were able to call a single function to take the
appropriate action based on data. It is important to note that the data it's
acting upon specifically is behavior to construct a `%Game.Player{}`.

This becomes more important when using the [pipe operator], which shines as a
way to transform data.

[pipe operator]: <http://elixir-lang.org/docs/stable/elixir/Kernel.html#%7C%3E/2>

"Tell, don't ask" is a way to encourage developers to [write declarative code
instead of imperative code]. Imperative code asks questions before making
decisions; declarative code issues a command and expects it to be done
correctly.

[write declarative code instead of imperative code]: https://medium.freecodecamp.com/imperative-vs-declarative-programming-283e96bf8aea
