These two days I have been reading Phoenix 1.3. Learnt that the new generator by default puts schema inside contexts. After reading the post from @michalmuskala Putting Contexts in Context, I agree having context as module is a good idea. But is it worthy to have contextual schema?
I guess the benefit of putting schema inside context is similar to rom-rb which will have fewer couplings between database table and model schema. E.g. model schema can be just a partial of database table schema. And the disadvantage will be harder to define cross-context associations.
The best practice to define cross-context associations either is still in a grey area or will never exist (because YMMV). According to Putting Contexts in Context, the approaches to define cross-context associations will be:
-
Donβt use join at all. βSo, for example, instead of having an association, youβd only store the id. You can still access the data using the public interface of the other context.β
Cons: N+1 queries and worse performance. -
βHaving schema in each context reading from the same table (each having access to mostly different fields)β
Cons: fragmented schema and no single source of truth (sounds like how spaghetti begins). -
βHaving multiple tables that use the same primary key value (so you donβt have to keep a separate foreign key around).β
Cons: dirty hack around.
Since performance is one of the major reasons that makes me choose Elixir & Phoenix, I will opt out option 1. And I personally hate option 3. So last standing option 2.
Therefore to me, contextual schema VS non-contextual schema is a tradeoff of more couplings between database table and model schema
VS fragmented schema and no single source of truth
. I personally hate fragmented schema and no single source of truth
more. Hence, an out-of-context schema structure (or database-coupled schema structure) might be more handy for my general projects.
For example, if I am making a car dealer app, Phoenix 1.3 will give me contextual schema structure like this:
Contextual schema example
CarDealerApp
βββ contexts
βββ admin-edit-product
β βββ interfaces
β β βββ update-product
β βββ schema
β βββ product
βββ explore-product-plans
β βββ interfaces
β β βββ list-plans
β βββ schema
β βββ plan
β βββ product
β βββ user
βββ explore-products
β βββ interfaces
β β βββ list-products
β β βββ show-product
β βββ schema
β βββ product
β βββ user
βββ get-product-plan-quote
β βββ interfaces
β β βββ create-quote
β βββ schema
β βββ plan
β βββ product
β βββ quote
β βββ user
βββ registration
βββ interfaces
β βββ create-user
βββ schema
βββ user
In contrast, the out-of-context schema I propose will look like this:
Out-of-context schema example
CarDealerApp
βββ contexts
β βββ admin-edit-product
β β βββ changesets
β β β βββ to-update-product
β β βββ interfaces
β β βββ update-product
β βββ explore-product-plans
β β βββ interfaces
β β βββ list-plans
β βββ explore-products
β β βββ interfaces
β β βββ list-products
β β βββ show-product
β βββ get-product-plan-quote
β β βββ changesets
β β β βββ to-create-quote
β β βββ interfaces
β β βββ create-quote
β βββ registration
β βββ changesets
β β βββ to-create-user
β βββ interfaces
β βββ create-user
βββ schema
β βββ plan
β βββ product
β βββ quote
β βββ user
βββ validations
βββ plan_must_be_avaliable_in_region
βββ product_must_be_active
βββ quote_expiry_date_must_be_before_plan_expiry_date
βββ user_must_be_vip
Basically, I would still keep changesets contextual because itβs very common that contexts require different fields, etc. On the other hand, I would abstract the specific validations out of context since often they will be shared across contexts. validations
folder structure can be either flat or grouped by schema name, it can make sense in both ways and does not really matter.
What do you think?