A conceptual question about responsibilities

Who should have the responsibility to deliver the information processed, the model or the controller?

Example I have

  #action
  def register(conn, _params) do

    employee  = Employee |> filter1
                         |> filter2
                         |> Repo.all 

    # company_type = Company  |> Repo.all 
    # others ..N
    # others ..N
    # others ..N

    changeset = Company.changeset(%Company{})
    render(conn, "register.html", changeset: changeset, employee: employee)
  end

view

<div class="form-group">
  <%= label f, :employee, class: "col-sm-2 control-label" %>
  <div class="col-sm-10">
    <%= select f, :employee,
    @employee |> Enum.map(&{&1.id, &1.name}),
    class: "form-control" %>
    <%= error_tag f, :employee %>
  </div>
</div>

Here the data are being processed in both the controller and the view

A possible approach --------------------------

defmodule Myapp.Service.Employee do
   
   def fetch_pairs(conn, repo, _params)
      employee  = Employee |> filter1
                           |> filter2
                           |> repo.all 
                           |> Enum.map(&{&1.id, &1.name})
   end      

end 

def register(conn, _params) do

    employee  = Service.Employee 
                |> Service.Employee.fetch_pairs (Repo, params)


    changeset = Company.changeset(%Company{})
    render(conn, "register.html", changeset: changeset, employee: employee)
  end


<div class="form-group">
  <%= label f, :employee, class: "col-sm-2 control-label" %>
  <div class="col-sm-10">
    <%= select f, :employee, @employee, class: "form-control" %>
    <%= error_tag f, :employee %>
  </div>
</div>

I am creating a service layer called to process the information, what would be the best way?

1 Like

The model I have do nothing. I have other modules that handle processing of data. Controllers/sockets/etc… take data from those other modules and massage them into the format that the output wants. I’m not entirely clear on what you are trying to structure though beyond that?

1 Like

I think this might be a case of the overloaded term “model” having widely varying definitions depending on which background you have in programming?

I think the proposed change from the repo call directly in the controller to the Myapp.Service.Employee module is exactly what @OvermindDL1 is referring to with the “other modules processing the data”. I personally call it a data access layer, but it can also be called a persistence layer or more generally a service layer. Although again, this could be one of those terms that means slightly different things to different people.

With those points in mind, I would say my approach is like @OvermindDL1’s, but the (relatively) anemic model seems to be called a “schema” now in Elixir, as Ecto is moving away from the term model (maybe because of the confusion?). Then the other modules are like your Service.Employee which interfaces with the repo, and the controller massages the info.

The only tweak I would see to your code would be in regards to this massaging part. I personally wouldn’t pass in the conn or params directly in your service layer. I would make that complete agnostic to the web interface layer (i.e. the controller) and to the presentation layer (i.e. the view). (Although with templated views, the lines between interface and presentation are a little blurred to me.)

So instead of def fetch_pairs(conn, repo, _params), I might pattern match out the actual parameters from the params. If there is actually anything needed from the conn, like for authorization or whatever, I would pull that out also. This way, your business layer and data/service layers are nice and cleanly testable alone, and you have a slightly cleaner separation between the layers. :smile:

2 Likes

I believe that the nicest way to separate responsibilities:

  • the ‘model’, which is just a data structure that knows how its representation is mapped to the database. As much as possible Plain Old Data. Some of these might be backed at other places than the database (JWT, only ephemeral, etc)
  • a ‘logic layer’ that works with different instances of these data structures, which handles the program logic, how the different data structures interact. Most error handling happens in this layer as well. And this is the part which is split across multiple processes in fancy ways, etc. This is the gist of your app, and is probably the largest part.
  • the ‘controller’ that is part of phoenix is just the web-facing interface of the representation layer. It is the only part that speaks HTTP, and does nothing more than being a ‘traffic cop’, relying for all app-specific things as much as possible on the logic layer.
  • The ‘view’ speaks HTML.
1 Like