jlevy
Phoenix is not your Application - questions
Hi All,
I just watched @lance’s talk from ElixirConfEU and I want to talk about it ![]()
Lance discusses the idea of putting all of your domain logic in a vanilla OTP application, and then bringing that in as a dependency to a separate Phoenix application which is merely an HTTP interface for your existing application. I really like this idea but I had a few questions.
-
My understanding is that Phoenix is creating a new process for each HTTP request so that all can run in parallel. If we keep all of the domain logic in the Phoenix controllers/schema/changesets, we take full advantage of this parallelism. My understanding of the talk was to move the application logic to a separate GenServer, which is one process. Won’t we then have multiple Phoenix processes waiting in line to get a response from the single GenServer doing all of the work? Maybe in the real world (beyond an example app) we would need to create some sort of pool or dynamically spin up workers to handle each request?
-
How does it make sense to organize the code in the OTP Application? Would you want a separate GenServer for each domain model?
I’d appreciate any thoughts or guidance. Thanks!
Jeff
Most Liked
chrismccord
Lance’s example happened to use a GenServer to hold state, but it could as well have been a plain old module without state. So your first tradeoff isn’t relevant to splitting your domain concerns into an umbrella apart from your web concerns because you can still call directly into the domain module, i.e.: MyApp.Accounts.list_users(). That could be a function on the my_app application that is called from your my_app_web application, say in a controller, and internally it would look just like any code you’d bundle in the same application today. It might ask an Ecto Repo to fetch data, or hit disk, or anything, but it can all run in the caller’s process. Make sense?
- How does it make sense to organize the code in the OTP Application? Would you want a separate GenServer for each domain model?
No, some of your domain will definitely be modeled in processes because you’ll need to hold state, handle failures, etc, but this decision like above has no bearing in splitting your applications in an umbrella.
caveats: The time where processes may come into play even for seeming “pure” domain concerns are if you want to do service discovery or call into a process on the cluster with code not running in your current VM. In such cases, you could only ship a “client” module on the web side that messaged a discoverable process somewhere on the cluster. I’m exploring these ideas and how they’ll play into service discovery in Phoenix, but such concerns I would say aren’t relevant to your day to day decisions when thinking about umbrellas at this stage.
Qqwy
The main ‘problem’ I haven’t been able to wrap my head around, is where Ecto’s role (or that of any other persistence layer) lies in the ‘phoenix is not your application’ philosophy.
Of course it is possible to create applications that do not provide a persistence layer at all (As Joe Armstrong will no doubt remind you again and again
), but in many cases it provides useful because you either have more data than you can keep in memory at one time, or you only want to selectively use some of the data you previously stored, so iterating through it in a Relational database is faster than in plain Erlang/Elixir.
Phoenix integrates tightly with Ecto through phoenix_ecto. It seems that when one moves the persistence layer to its own part in an umbrella application, the advantages of Phoenix working with Ecto are lost.
In Phoenix’s philosophy as far as I’m understanding it right now, it seems like calling your database Repo directly should only be done from the controller-layer, to not couple your models tightly to the database. How would this become structured when the database-handling code is completely outside of Phoenix?
wojtekmach
Phoenix integrates tightly with Ecto through phoenix_ecto. It seems that when one moves the persistence layer to its own part in an umbrella application, the advantages of Phoenix working with Ecto are lost.
Which part doesn’t work for you? From my limited experiments, it works pretty well so far; my “domain logic” app exposes schemas and changesets to the web layer and because I use changesets I can use them in forms - which to me is the main benefit of the phoenix_ecto package.
In Phoenix’s philosophy as far as I’m understanding it right now, it seems like calling your database Repo directly should only be done from the controller-layer, to not couple your models tightly to the database. How would this become structured when the database-handling code is completely outside of Phoenix?
To follow Chris’ example above, I think instead of calling Repo from controllers e.g. Repo.all(User), you’d get it from the another app: MyApp.Accounts.list_users(). MyApp.Accounts.list_users() would presumably call MyApp.Repo.all(User) under the hood if it happens to use Ecto for persistence.
Last Post!
StevenXL
@anders Completely agree with your thoughts here. I haven’t gone through your source materials (assuming Fowler is the source), but Scott Wlaschin does a great job of summarizing DDD, Bounded Contexts, and Ubiquitous Language in the context of functional programming.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










