I’ve recently finished Designing Elixir Systems with OTP. It is an excellent book, and I highly recommend reading it!
Modelling the logic with pure data structures without using the DB is central to the architecture. In many cases, the core/entities have a relational structure. There is an excellent talk about it by Richard Feldman (the example is in Elm, but the same rules apply).
The problem is many to many relationships. An example from the above talk a student can attend many courses and courses have many students. In such situations, Richard recommended using dictionary (map in Elixir) id => %Student{}
That seems like a pretty clean idea, but I am not sure what to do with new records. Let’s say I want to add a new student to the course. I should generate a new id for that record. However, I should decouple the model from the DB, so I shouldn’t use DB id. But what should I use then? Other ids might be integers from the DB, and I don’t want to clash.
My end goal is a function like save(old_model, new_model)
that checks what changes need saving and performs the writes.
I have a couple of ideas, but neither is very compelling.
Idea 1:
Using something like {:db, id}
for stuff read from the DB and {:new, id}
for new stuff. That makes the save
function trivial. The downside is that I am leaking persistence details to the model/core.
Idea 2:
Introduce ids that are unrelated to DB. E.g. a student id might be a string "student-1"
. That would be unrelated to the DB id. When reading a particular set of courses, I would need to translate student.id: 237
to "student-1"
, student.id: 250
to `“student-2” and so on. That should work, but I need to keep the translations dictionary somewhere in case I need to update the student.
Do you have any other ideas for persistence? Or maybe an idea of using a map is not a good one, and I should the relationships differently?