5 ms·
If you treat your storage as a separate subsystem you’ll likely not face the problem with `create_changeset`. I’m saddened to see that almost every Phoenix proj
by nesarkvechnep 4y ago
If you treat your storage as a separate subsystem you’ll likely not face the problem with `create_changeset`. I’m saddened to see that almost every Phoenix project is tightly coupled with the database as every context function calls the database and clean business logic is nowhere to be found. Also, why are we using the contexts directly in the controllers and keep the top-level module empty?
- sodapopcan 4y agoI get it--or maybe I don't deeply get it-- but I don't really find this a huge concern for most web apps. If I know that my app is never not going to have a db, then what is that extra step of that decoupling buying me? I still have fast tests due to transactional rollbacks, and I can even perform certain business logic in the db nicely with Ecto when it's a better fit than the BEAM.
- rapnie 4y agoJenny Shih did a conference talk about how Phoenix Contexts fit into Clean Architecture project organization. The slide deck is here (sample code is on Github): https://speakerdeck.com/jennyshih/context-driven-development-architecture-your-code-with-phoenix-context https://speakerdeck.com/jennyshih/context-driven-development...
- nesarkvechnep 4y agoThe talk is on YT and it’s easy to find by the title. I forgot to mention, whenever I see Ecto schema structs bubbling up to the views, I want to throw up.
- agentwiggles 4y agoThis confuses me as a relatively green Phoenix dev. Wouldn't this be standard practice? As I've been reading through Programming Phoenix, this is done all over the place. For example, the "show" action for a "user" calls into the Users context to get a User struct, then passes that struct into the view for rendering. How else would you do it? It would seem to me (admittedly, naively) that anything else would introduce an unnecessary extra layer between the context and the view. What am I missing?
- nesarkvechnep 4y agoIt might be an unnecessary layer but sometimes it might not be. By having structs that you persist and structs that are “bound” to business logic functions you can have clean business logic and treat the persistence as a side effect, which it ultimately is. If your application is a simple CRUD app, then yes, bubbling up Ecto schema structs to the vies is sufficient.
- OkayPhysicist 4y agoI'm not positive I see your complaint. Ecto is supposed to be exactly the translation layer between your business logic and your storage layout. Adding another translation layer on top of that just results in a half-baked implementation of half of Ecto. If your Ecto structs aren't useful throughout your application, then maybe you need to do a little more translating in the schema itself.
- dns_snek 4y agoWould you mind expanding on why that is what you do differently?
- melx 4y agoThe relevant Github repo https://github.com/jenny-codes/elixirlab https://github.com/jenny-codes/elixirlab
- jnsaff2 4y agoDo you have references to Phoenix projects where they are doing it right in your opinion?
- monooso 4y agoHello, article author here. Can you expand on what you mean by top-level module? My understanding of contexts (from the docs) is that they are intended to "...encapsulate data access and data validation." They're intended to be the layer of your application that talks to the database. Do you have a different approach?
- sodapopcan 4y agoI _think_ they are talking about treating the top level module as the facade for the whole application, which is something I've thought about doing a bunch. IE, it would be full of delegates to all your contexts and then _every_ public function is available off of it. I don't think this is a terrible idea but I like to draw boundaries and say "It's ok to reach one level deep from any point in the context tree". ie App.Chat.send_message/2 is cool, but MyApp.Chat.Messages.send_message/2.
- beckler 4y agoNot OP, but I think he might be hinting towards something like this: https://learn-elixir.dev/blogs/creating-reusable-ecto-code https://learn-elixir.dev/blogs/creating-reusable-ecto-code
- monooso 4y agoThe article you linked to reminds me of Chris Bailey's "compositional" Ecto query patterns post, which is worth a read if you haven't seen it before: https://cbailey.co.uk/posts/compositional_elixirecto_query_patterns https://cbailey.co.uk/posts/compositional_elixirecto_query_p...
- zachallaun 4y agoI don’t know what the person you’re responding to is getting at, but I found the article very useful! Exposing the changeset through the context is also useful in LiveViews when dealing with forms — once the changeset is valid, calling the relevant function with the same attrs should succeed. Re: the sibling comment referring to queries, nothing you’re doing in the article prevents that. Ecto’s changesets are often an unfamiliar concept, so I wonder if that’s where some confusion is coming from.
- Existenceblinks 4y agoYeah. Trying to teach specific practices confuses people. Naming and "context" should not matter (in a sense of consistency) much .. if at all. My take is "context" is just "module" and schema is just "type". I'd like to think in ML languages style.
- zachallaun 4y ago> Also, why are we using the contexts directly in the controllers and keep the top-level module empty? Because the context is the “public API” for the rest of your application to use. You can have as many layers below the context as you want, often purely functional, composable, and testable.
- nesarkvechnep 4y agoThe contexts are boundaries, places where you use process machinery and might call other subsystems, or services, but they’re not the application’s public API. You might want to check Bruce Tate’s book “ Designing Elixir Systems with OTP”.