thiagomajesk

thiagomajesk

What's your process on splitting application logic?

Hello everyone!

There’s a common concern/ discussion I have with my peers and I’d like to collect insights from the community regarding this topic which is: how are you splitting the code between your contexts and schemas?

I’m a little bit more familiarized with DDD applications from my previous experiences as a software architect while the majority of my peers seem to come from a “classic” Rails MVC background. Because of this, I’m facing some challenges trying to articulate properly some architectural concerns regarding our application domain that are not usually implicit to them.

I acknowledge that DDD practices sound sometimes too conservative for people accustomed to a less structured way of building applications. Besides that, it goes without saying that the whole decision-making process becomes a lot harder than it should be because there’s too much convincing going on most of the time (IMHO, this wouldn’t happen if there were more overlapping knowledge in this specific area).

I framed some questions that might help us get this sorted out:

  • Are you using schema’s functions to return only Ecto changesets?
  • Where are you currently placing your domain/ model/ entity logic?
  • Do your schemas deal with “domain/model” concerns or not?
  • Are your contexts the only public interface between outside code and your schema?

As a side note: I’m looking for some objective and concrete techniques or concepts you’ve been applying to identify and organize your application logic with Elixir. I say this because I think this information would resonate better with more pragmatic people.

I think you got the gist. Please, feel free to elaborate further if necessary.

My best regards to everyone.

First Post!

sodapopcan

sodapopcan

I’m not really qualified to give advice here but I’ve been keeping an eye on this question for the past couple of hours and thought I’d share what I’ve grokked based on a lot of reading (including answers to such questions in this forum). I’m not sure where you are at with functional programming, but I do deal with similar things at work where we attempt to do DDD while still staying as true to The Rails Way as possible (and, of course, this doesn’t work out perfectly… you can only get so far banning belongs_tos!).

I would HIGHLY recommend reading and working through Functional Web Development in Elixir, OTP, and Phoenix (Functional Web Development with Elixir, OTP, and Phoenix: Rethink the Modern Web App by Lance Halvorsen). The biggest takeaway from that book for me is how to separate your “functional core”. This keeps all your domain logic completely independent. In the book it’s actually developed as its own “Application” (ie, library), then added into Phoenix as a dependency. With this in mind I would say: no, domain/model logic does not belong in schemas. I believe contexts should be the public interface between your business logic and your schemas (state/datastore).

As for your context question, as someone who has a decent grasp on DDD and read about and played with Phoenix contexts in a personal project I would yes, contexts should absolutely be the only public interface between schemas. I have no production experience with this, though, so I probably shouldn’t weigh in here.

If you do read the book I recommended, be aware that it’s a little out of date. You’ll have to adapt one example when it comes to using simple_one_for_one supervisors, and then the whole JS part of the book still uses Brunch instead of Webpack.

I have a few more thoughts but again, I’m not super experienced so I’ll leave at it this for now and hopefully others weigh in and can correct or back up anything I’ve said!

Most Liked

hlx

hlx

In Programming Ecto there is a chapter called “Optimizing Your Application Design > Separating the Pure from the Impure” which basically says that pure functions (with no side effect) can be placed in schemas while impure (with side effects like database access) can be placed in contexts. This means that changesets, queries and multi’s can go in the schema and the rest in the context.

I really like this idea and I’ve been using it a lot and it works well for me, but after reading Saša’s comment I’m eager to try out putting changesets as private functions in the context for this current project I’m working on.

sasajuric

sasajuric

Author of Elixir In Action

I personally don’t think that changeset functions belong to schema. About a year ago I’ve started consulting an agency, and proposed the team to write changesets as private functions in context modules, and that’s been working really well. In most cases I’ve seen, a changeset function is used in exactly one place, which is not a schema, so making this function public and moving it to another module makes little sense to me, and it complicates the reading experience. Even when it’s used in multiple places, there’s typically a strong cohesion between all callers (they work on the same data), so they are a part of the same context module, and hence changeset as a private function in that same module works fine.

We usually don’t have functions in schemas, but we may add some helpers for computing derived properties. E.g. say that the OrderItem schema has fields quantity and price. If I need a function total_price, I’d define it in the schema.

We mostly stay away from virtual fields. I think there was one case where we used it to store some derived value computed at the database level.

In context modules.

They are our main domain types, since we don’t transfer data from schemas to pure Ecto-independent data structures.

Schemas are returned from contexts to web tier, and they are used by controllers, resolvers, and views to produce the output. Therefore, they are not an internal implementation detail of contexts.

Note that I’m not suggesting this as a universal pattern, but it’s been working well for the client’s projects, which I’d categorize as small-to-moderately complex.

sasajuric

sasajuric

Author of Elixir In Action

When a context module grows large, we split it and/or extract some related group of private functions into internal private modules which are only used from within the context layer.

Last Post!

hlx

hlx

I highly recommend it.

After thinking about what @sasajuric said, I am definitely going to try out moving the changeset functions out of the schema to the contexts. After looking at Ecto.Changeset.prepare_changes/1 I realized that changeset functions can also become impure. That is not a big deal but one more reason to move them.

Where Next?

Popular in Discussions Top

AlexMcConnell
The reason that Rails is as popular as it is is because it’s very easy for relatively inexperienced developers to get a lot of work done....
588 20142 166
New
sergio
There’s a new TIOBE index report that came out that shows Elixir is still not in the top 50 used languages. It also goes on to call Elix...
New
acrolink
How does the two languages compare when it comes to server side application development? Any experiences or ideas? Thank you.
New
jer
I’ve been using umbrellas for a while, and generally started off (on greenfield projects at least) by isolating subapps based on clearly ...
New
AstonJ
If so I (and hopefully others!) might have some tips for you :slight_smile: But first, please say which area you’re finding most challen...
New
RudManusachi
What configs will make sense to put to runtime.exs? – A bit of how I configure apps: I have generic configs in config/config.exs, dev...
New
mmmrrr
Just saw that dhh announced https://hotwire.dev/ Is it just me or is this essentially live view? :smiley: Although I like the “iFrame-e...
New

Other popular topics Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

We're in Beta

About us Mission Statement