Why were Phoenix Contexts introduced? A (brief) history.

Notes

People frequently struggle with Phoenix Contexts.

Why were they introduced?

When I explain the history to them, it becomes a little more clear. So, here’s a brief history.

Back before Phoenix 1.3, Phoenix had a very MVC directory structure (much like a Rails app has today), meaning we had:

  • Models
  • Views
  • Controllers

But in Phoenix 1.3, the Phoenix team decided to change that. This was the new slogan:

Phoenix is not your app

The Phoenix team separated the “web” portion from what I typically call the “core domain”.

And that’s when we got the _web separation that we see in Phoenix apps today. So, now we have MyAppWeb and MyApp namespaces that match the my_app_web/ and my_app/ directories.

But that still leaves the question: what should we do with the type of code that lives in a controller or LiveView?

Take this product creation in a controller as an example:

def create(conn, params) do
  %Product{}
  |> Product.changeset(params)
  |> Repo.insert()
  # assign and redirect
end

How we create a product is domain knowledge. So it would be nice for the product-creation pipeline to live in the MyApp portion of the app.

And that’s why Phoenix Contexts were introduced. They are meant to be the interface through which our web layer talks to our core domain layer.

So, now the web layer calls the Checkout context:

def create(conn, params) do
  Checkout.create_product(params)
  # assign and redirect
end

Hope that helps you understand them better.

P.S. If you want more info on how DDD can help with naming your Phoenix Contexts, check out my ElixirConf 2023 talk: Creating Better Phoenix Contexts with DDD

Want the latest Elixir Streams in your inbox?

    No spam. Unsubscribe any time.