How to Delegate with Defdelegate

Let me know if this sounds familiar:

You start working on a project. You add a schema (let’s say User). You create a User context module around functionality for a User. Everything is going well.

Three months later, that User now has several schemas associated with it (Roles, Settings, etc.) and the User context is now 500 lines long. But all the functions seem to make sense here.

Hit to close to home?

Code without defdelegate

defmodule Example.Users do
def get_user(id), do: #...
def get_user_by_email(email), do: #...

# 500 lines later

def get_roles_for_user(user_id), do #...

def get_settings_for_user(user_id), do #...

#....
end

Other languages have techniques to handle this, but Elixir has a secret weapon we can wield to tame our context. That weapon is known as defdelegate. By definition defdelegate “defines a function that delegates to another module.”

Now that we have our sword, let us go to war!

We will start by making two new modules and move the get_roles_for_user and get_settings_for_user to each one respectively.

defmodule Example.Users.Roles do
  def get_roles_for_user(user_id), do #...
end
defmodule Example.Users.Settings do
  def get_settings_for_user(user_id), do #...
end

Finally, we update our Users module, delegating the functions we moved using defdelegate.

defmodule Example.Users do
def get_user(id), do: #...
def get_user_by_email(email), do: #...

defdelegate get_roles_for_user(user_id), to: Example.Users.Roles
defdelegate get_settings_for_user(user_id), to: Example.Users.Settings

#....
end

We have now cleaned up our Example.Users module while keeping our API the same. No upstream changes to code are needed!

Using defdelegate to Refactor

defdelegate can be a great refactoring tool. But don’t overuse it. Focus its use on keeping your API consistent for you and your users. Sometimes it’s better to create a new module instead.

defdelegate responsibly!

More Posts by Bryan Joseph:

Kubernetes, Delivered

Deploy your first app within 24 hours. Book a demo to get started.