4 ms·
I love it too but I'll push a little on "sanest out-of-box" web framework. template/view rendering is a bit more complex than it needs to be. totally understand
by colbyh 10y ago
I love it too but I'll push a little on "sanest out-of-box" web framework. template/view rendering is a bit more complex than it needs to be. totally understand that it's a side effect of pattern matching but I'd appreciate a little less "magic" when it comes to matching views to render statements.
and not to throw yet another buzzword at this post but Phoenix is the best framework I've found yet for smaller networked services. so enjoyable to build with.
- bpicolo 10y agoI mean, I have a bone to pick with most web frameworks in that they leave a lot out of what I'd consider ready-to-go for an app. Phoenix does a number things better than most, like sane JS env, consideration of production vs dev configs, and some other stuff. Most out-of-box apps are too simple, and most web framework app skeletons are insanely overdesigned and, frankly, miserable. Certainly there are a number of big frameworks (django, rails) that can give you most things out of the box, but I'm not a fan of heavyweight frameworks in general. I think Phoenix strikes a great balance
- chrismccord 10y agoI'm genuinely curious what you feel is too magical with how we handle rendering? Templates are compiled as `render/2` function clauses on the view module, so there's no magic going on. As you said, we do lean on pattern matching, but that's a product of the language and how you structure a large amount of your own code, not anything tricky we're doing. For example, if I have an `user/index.html.eex` template for a `UserView` module, I can render it with: View.render(UserView, "index.html", name: "colbyh") At compile time, we simply precompiled the index.html.eex template as a `def render("index.html", assigns) ...` function clause. Now imagine I want a `bio.html` template. Instead of making a template file, I can literally do this in my view: def render("bio.html", assigns) do "Bio: name: #{name assigns.name}" end ... View.render(UserView, "bio.html", name: "colbyh") => "Bio: name: colbyh" And it Just Works exactly because there's no magic going on. Templates are just function calls, whether they are precompiled from a template engine or defined by the user manually.
- bpicolo 10y agoI think the confusion mostly lies in the Views. The difference between controllers and Views and why views are actually necessary to render templates is not especially obvious, and it almost feels like the explicit view layer isn't entirely necessary. (From the developer API perspective, and not necessarily the framework design perspective)
- chrismccord 10y agoThe distinction between views and templates is something that does trip folks up sometimes when coming from other areas that make no distinction or use the terms interchangeably. For us, this distinction is extremely important: - templates are just functions - Views render templates and serve as a presentation layer
- phlakaton 10y agoI'm just starting to learn Elixir and Phoenix. Here are two little bits of "magic" that have thrown me for a loop so far: 1. @var's in templates are not module attributes (though they do seem to be convenient!) 2. The form for `use` is different in Phoenix than it is in Elixir proper – instead of passing opts, you pass an atom that selects the implementation of __using__ you want. (This bit of magic makes no particular sense to me – why wouldn't you just use a submodule, say MyApp.Controller, that has the correct and single __using__ attached?)
- colbyh 10y agoyou can define `__using__` any way you want, and phoenix's default isn't technically any different. it's just a convention that you can choose to use or not, personally I try to rip out a lot of what the `web.ex` file does because I like being more explicit.
- true_religion 10y ago> The form for `use` is different in Phoenix than it is in Elixir proper – instead of passing opts, you pass an atom that selects the implementation of __using__ you want. This isn't really true. If you check out the ExUnit, you can pass something like "use ExUnit.Case, aysnc: true" and it'll setup your module to run tests asynchronously. You can pass any atom/value combination into use. HTTPoision.Base, and ExAws to name a few other projects also have the convention of passing options into __using__. To me, the confusion comes from the fact that the Elixir get-started documentation doesn't say anything about this. It is however listed in the Kernel forms that "use Module" actually just translates to Module.__using__([])