How do you structure your models save/load code?
-
[email protected]replied to [email protected] last edited by
In python I put my base models in
models/__init__.py
. The bases have things for managing data behind the scenes, adding common utility methods, etc. If I’m using another library or method to serialize data I’d put it in a separate utility script somewhere, it’s probably going to be useful to more than just data models and it’s easy enough to import.Then each file that defines models has a
from models import BaseModel
or whatever else is needed, keeping each file relatively short and focused to what it needs to do. -
[email protected]replied to [email protected] last edited by
First option for each object. Unless things get bigger/tons of serializers/etc... then we move to the second-ish model.
To be honest, I usually just use whatever the framework has as best practices so that when new team members get on-boarded, theres less friction.
-
[email protected]replied to [email protected] last edited by
Usually my models only store data, meaning the files that contain them don't have much code. The decision also depends on the tools you are using and who you are working with. I would fallback to the rule of separation of responsabilities and write a new class for the purpuse of serializing the model (which could and should also serialize similiar models). This way is universal in any language and can easily be understood by future you and colleages.
-
[email protected]replied to [email protected] last edited by
Related code should go together as much as possible, for maintainability.
If this results in too much code together, it's time to think about other ways to structure the code so that each thing the user can do fits into as few files as possible, but not too many things the user can do share a file.
-
[email protected]replied to [email protected] last edited by
First option for small codebases. Second option when you know your codebase will grow large enough to break things apart into multiple packages.
The thing is, you typically need dependencies for de-/serialization. You only want those dependencies in the parts of the codebase that actually do the de-/serializing. And your model will likely be included in pretty much everything in your codebase, so the de-/serializing code should not be in there.
Well, unless your programming language of choice supports feature flags with which the de-/serializing code + dependencies can be excluded from compilation, then you can think about putting it into the model package behind a feature flag. -
[email protected]replied to [email protected] last edited by
Storage concerns should be separate from the data model.
-
[email protected]replied to [email protected] last edited by
Usually the serialization/deserialization code, I keep with the model. The part where a file or whatever comes in, I leave that to the caller to decide on. In other words, the model knows how to serialize and deserialize itself, but not where it's being serialized to or deserialized from.
Then again, in C#, it's usually just a couple attributes on my model, and in Rust, it's usually just a couple derives. It's rare I actually write much, if any, serialization logic by hand.
-
[email protected]replied to [email protected] last edited by
Models should contain or inherit their own serializers/deserializers.
Either put the generic serialization in a base Model class, or make the base Model class defer implementation to a reusable Serialization helper class, preferably an off the shelf library.
-
[email protected]replied to [email protected] last edited by
The models in my project have several ways of doing it. On the server side, there’s a function that accepts data from the DB, and a function that accepts data from the frontend. Same with serializing. One function to serialize the data for the DB and one to serialize for the frontend. On the frontend, it’s simpler, since it only sends/receives to/from the server.
That’s mostly abstracted away in a top level class called “Entity”. It’s only if you need to do something special that you’d reimplement those functions. My data abstraction library is open source at https://nymph.io/ if you wanna check it out. It’s what runs my email service, https://port87.com/.
-
[email protected]replied to [email protected] last edited by
I prefer to just throw the state into a database. Each table has their own "repository" type that knows how to save/load models and then I have "manager" types that use "repository" types to compose larger, feature-specific domain models.
I usually just use Sqlite for it's simplicity but I'm not opposed to Postgres via Docker.
-
[email protected]replied to [email protected] last edited by
You should group your source files by domain, then by feature, e.g. 'src/foo/model' and 'src/foo/exports'.
Is serialization/deserialization the only aim of these structures ?
If not, that code should definitely be separated, so as to evolve separately from the structure itself.If it is the only aim, the code should also be separated, so you can change your serialization type (e.g. from JSON to XML) without impacting the model.
Also you might need another export for compatibility with another software, and you don't want your model file to grow with the 10 formats you support.