when using phoenix generators it creates MyAppWeb.ResourceController and put it inside /lib/my_app_web/controllers/resource_controller.ex file. I was thinking if it wouldn’t be better if it followed the elixir standards and have a MyAppWeb.Controllers.Resource in a /lib/my_app_web/controllers/resource.ex file.
I understand that this is done that way so phoenix can abstract the default view from the controller module name, but it could be an option passed to MyAppWeb when using it. Something like use MyAppWeb, controller: [default_view: ViewModule].
Well, people use alias a lot and having e.g. Users is going to be confusing, especially having in mind that Phoenix encourages you to have context modules with the model name in plural. So what would Users mean? The context or the controller?
Beyond the aliasing issue @dimitarvp mentions, the bigger concern IMO is the “tab problem”.
In short, having many files with similar / identical names can cause confusion when users have an editor that only displays the base name of the file as a label. In your example, is a tab labeled resource.ex the controller or the corresponding schema?
Rust had a similar (but bigger) situation a few years back; the “default” place to put code for a module foo was in foo/mod.rs - so if you had many crates open, ALL the tabs would be named mod.rs The thread of discussion is long and tangled, but you can start from the final RFC that changed the approach so that foo.rs would work.
Wouldn’t the easy solve there to use the :as option? Although as I type that I realize my approach in Elixir apps that have this problem is to just alias up to the namespace so I can reference X.Users and Y.Users in any module that needs to reference both.
Good point. It seems like the as option only really helps with the NS immediately above the mod isn’t enough to distinguish it but something higher up is. But I’ve never worked on a a system where that was true.
My rule of thumb for Elixir projects is: if your namespaces have 4 levels then it’s probably time to break apart your app.
As all such rules there are exceptions, obviously, but us the humans can only keep so much complexity in our heads.
BTW I never liked the “controller” moniker anyway. It’s IMO a misnomer and it would be more accurate as “HTTP inbound sink” (or something more brief than that; my English vocabulary isn’t great). The hell does it “control”?
If it were up to me I’d like have files like these:
This is exactly the approach I am using in my projects. Example controller. I really do not like the default approach where the “regular” naming scheme is broken. Thanks to that approach it router is IMHO much cleaner:
scope "/", LangustaWeb.Controllers do
get "/", Stories, :index
get "/newest", Stories, :newest
get "/newest/:name", Stories, :newest
get "/s/:id/*rest", Stories, :show
get "/t/:tags", Stories, :for_tags
get "/u/:name", Account, :profile
get "/login", Account, :login_form
post "/login", Account, :login
scope "/" do
post "/s/:story_id/vote/:vote", Votes, :story
get "/submit", Stories, :new
post "/submit", Stories, :create
delete "/logout", Account, :logout
See Mama, no Controller repeated over and over again.
However recently I am thinking about grouping the controller, view, and templates within single “domain-oriented” directory.
i’ve been doing that too. i’d love to see it as a standard in the framework, and I say that because generators usually direct people to a standard solution. i feel so weird on the projects that I’ve worked that are the necessity of custom plugs and people created and named plugs according to the “phoenix standard”.
personally I only use generators for migrations and everything else I create by hand so it doesn’t impact me that much. one other thing that I usually change is the folder names too:
@dimitarvp and @al2o3cr explained it beautifully. The alias/tab problem is untenable when you’d have a user.ex and User for the controller, the view, the struct, etc, and all the tests and what not. As a bit of history, I took the Controllers.User approach way back when I first started Phoenix and José is the one that recommended this change. So “standards” wise, this isn’t even a concern
vim and emacs: show full path by default, if it’s not showing for someone that person is already using something custom.
for the “alias” problem a simple change from UserController to Controllers.User, UserView to Views.User would do the trick, and it’s just 2 characters added. I think it even makes it easier to alias in most use cases.