recording rants for amusement later

This commit is contained in:
Gabor Körber 2023-12-21 20:59:46 +01:00
parent 52a69e4695
commit fca4582084

51
NOTES.md Normal file
View File

@ -0,0 +1,51 @@
# SeaORM
## Some Rant about ORM Implementations
#### Entity, ActiveModel, Model
SeaORM tries to implement (those #@!$) DDD ideas in much detail, creating this multitude of fixed struct names, like user::Model, user::Entity, user::ActiveModel, where each operation still needs us to import the Trait itself, most code is hidden behind macros, and you still end up having to call "insert" on the active model, instead of a repository object.
At least the activemodel, unlike in implementations like Django's ActiveRecord pattern, seems to support dirty flags, given you have to define fields as enums "Set()" and "NotSet" in the model. This probably will make it easier to save models without creating huge SQLs, or micromanaging which fields are touched, or resaving data that was actually unchanged, allowing more transparent PATCH implementations.
When it comes to writing ORM Code, SeaORM is rather bulky, and complicated, somehow the opposite of what I expect from an ORM implementation. At least however, it is concise, and you can access all your model parts, like Columns, by the same pattern, and allow nice filter patterns (e.g. user::Column.Name.contains(...)) that could be expanded by implementing additional functions on them.
So, once one accepts the concept, it works mostly well, and as it forces you with the tools to separate database concerns from your main code base, you are tempted to write your own repositories and value objects for interacting with the storage layer.
Why functionality implemented on Entity could not have been implemented for Model instead, I am not sure. Also, having access to the Model and ActiveModel type from Entity, would be at least easier, if you could just `pub use table::Entity as MyModelName`, and access `MyModelName::Model`, or `MyModelName::ActiveModel`, respectively, instead of sometimes using the module name, and then alternating between Entity and Model.
It also kind of sucks, to have Entity as a name, as imho the more prevalent use of that word is in ECS systems, where it kind of means the same thing, but not really, while in the context of DDD Storage mechanisms, pardon my hot take, it is just a waste of good nomenclature.
I have yet to find out, how i can move the automatically generated `entity` and `migration` folders to some subdirectory, like "crates", given putting them in the workspace is rather daunting, and is not a nice thing in general, imho, if not adjustable, but I am fairly sure that works out somehow.
I also don't see the reason, why I would separate the migration app from the entity app, and not manage the whole thing in one layer instead, given I have to now look for version changes of sea-orm in 3 Cargo.tomls for 1 project. It seems to be an overabstraction, that is dictated by the tooling, mainly sea-orm-cli.
However, this may be mitigated, or may be "accepted" by the user, as it is only a problem for a certain point of idealism, and might be easily defended in a discussion by anyone, who thinks that layers are things you cannot have enough of, and tons of Uncle Bob quotes.
#### Source of Truth
In Diesel my main issue was, that the source of truth was never clear for models, as the tools rewrote the schema.rs, while the migration could also be generated from changing the schema itself.
Here SeaORM clearly shows 2 approaches, either migration first, or entity first. However, where Diesel seems to grow into a better workflow, and started to have autodetection of migration changes, even generating a migration (instead of an entity), from a current table seems unsupported in SeaORM, which means, either you accept writing migrations manually, and using that as your state of truth, or you lose all migration support.
The entity first approach, is, as expected, not the main mindset.
#### Ease of Use and the ORM Idealism
Most ORMs come with some idealisms behind it.
For example, if you look at SQLAlchemy in the Python world, sometimes you have the feeling, the authors never really wanted to write an ORM, as you need some SQL statements at least, usually to set up databases.
I would say, Diesel is very similar in that mindset, as they only later introduced a programmatical migration language, and instead, expect you to write SQL in their tutorial.
Django may have it's flaws, but the ORM of Django clearly has a source of truth: the Model. Changing the Model leads to auto-detected migrations, which means, you can automate checking model changes in the CI/CD. Also, the model language of django nearly covers all aspects of SQL, except the DEFAULT value, which seems to be hard to implement, as most ORMs don't support it.
SeaORM seems like a weird cross-over. While I would have said, Diesel tries to go into the direction of full automation, and might one day finally solve it's source of truth issue, if it finally starts to introduce more options to define models, and throws away the idea of a common generated schema file, SeaORM seems not to bother, as probably most users of it work with the migration workflow in mind, and "there is is this a documented way to create entities in the database from code", even if that never really ties into their migration syntax.
Both ORMs force you to put your models in certain places, even if SeaORM is more flexible if you just don't use sea-orm-cli, while diesel just won't run otherwise, and therefore expect the database layer to be some global service layer, which is fine in a microservice world, but kind of sucks in a modular monolith. So putting database models in various applications, like you might be used from Django, is not really a thing.
It is better to just see your storage layer as a global database layer, and implement local value objects that implement From<T> for the storage layer objects, and some repositories, that do all the ORM work behind the curtain.
It's not like that is a bad thing, given this is also one of the downsides I witness in django projects, where models start to become swiss army knives around a domain topic.
## Accepting Fate
#### Generating Entities from a Database
sea-orm-cli generate entity -u postgresql://miniweb:miniweb@localhost:54321/miniweb -o entity/src --lib