Understanding contexts in Phoenix 1.3

I think the new structure and general advise around contexts in 1.3 is excellent. Putting persistence behind functional interfaces really makes sense to me. I’d like to understand contexts a little more for this use case:

In 1.2 I had three models (as well as other standard account/user type functionality).

App.Competition # has_many :games
App.Team # has_many :games
App.Game # belongs_to :team, :competition

Now thinking in terms of contexts I was going to go with a kind of top level context with methods –

defmodule App.Play do
  def get_competition(competition_id)
  def get_team(team_id)
  def get_matches(competition_id)
  def get_game(game_id)
end

But as games also have many players, I thought it might be more logical to have contexts like so –

defmodule App.Games do
  def get_game(game_id)
  def add_player(game_id, player)
  def list_players(game_id)
end

These contexts line up roughly with top my level routes (/games/:id, /competitions/:id), and nested information are accessed via the top level context, like listing players. So my question is whether that makes good sense, or if I’m better having the single boundary with a module like Play, and accessing everything through that, with games and players abstracted behind the Play interface.

Many thanks in advance for any thoughts/advice.

4 Likes

That sounds perfect, yes.

When I am not sure how or if I should split things apart, I usually prefer to put everything in one place and then try to reason if they are good together or try to find a good boundary in there.

5 Likes

Thanks Jose.

So perfect to splitting them up or a single Play module? :joy:

1 Like

Perfect to a single Play module. :smiley: Worry about splitting them up later on, only if necessary.

1 Like

Hi,

I understand the concepts behind the contexts and totally agree with it. It’s useful layer of abstraction that can clean up the code in the controller and move the business responsiblity out of it, but now I’m the question is - are you planning to add shared code placeholder, like it was for models in web.ex?

I see that contexts are outside the web, which is obvious, but should I do something similar to web.ex eg. contexts.ex, where I would store something like alias MyApp.Repo?

1 Like

If you feel like it will improve your code, then sure. But it is likely best to import only what you need in the context.

3 Likes

When I am not sure how or if I should split things apart, I usually prefer to put everything in one place and then try to reason if they are good together or try to find a good boundary in there.

Oddly (or perhaps not) this same advice is given with respect to Microservices vs. Monoliths. One can draw close parallels between Elixir modules (and processes) and microservices (Erlang - Microservices Before They Were Cool).

In the Microservices literature they suggest that you should probably never start a project with Microservices, you should start with a monolith and figure out your application domain and model. Then, once you have a solid handle on the domain, you can add the complication of microservices.

4 Likes