Comment on Entity/Repository Model for Hubzilla
harald@hub.volse.no@hub.volse.no 5 days ago
Example entity: Addon
MR: https://framagit.org/hubzilla/core/-/merge_requests/2315
This is just an example, as a base for further discussion. I chose to implement an entity class for the
I have ignored some of the columns of the table, as they seem to be unused.
A few things to note:
Other than that I think it should be fairly straight forward. I've added a few helper functions to make things a bit more readable, and reduce code duplication.
The basic premise is that all interaction with the database table should go through the entity class. The calling code does not need to know how it's stored, or even that the data is stored in a database.
Likewise, the object has all the information needed about itself, as well as the methods needed to interact with it or manipulate it.
Once constructed the object is valid! There's no need to check the validity of the object in code that receives one. This internal consistency should be maintained by the object itself. This is part of the reason we make the properties
Looking at the other entity classes defined so far, they do none of these measures. Properties are public, so they can be manipulated by anyone without the object itself not even being aware. They provide getters and setters, but don't do any validation in any of them, and the same with the constructor.
I hope this can be a useful starting point for the discussion, despite it's not the most interesting we would need.
MR: https://framagit.org/hubzilla/core/-/merge_requests/2315
This is just an example, as a base for further discussion. I chose to implement an entity class for the
addon table, because it's small, and relatively easy to reason about.I have ignored some of the columns of the table, as they seem to be unused.
A few things to note:
- I've made the constructor private. This prevents the class from being instantiated by outside code. This may not be correct for all entities, perhaps not even for this one, but it keeps things simple by giving us more control over how the constructor is invoked.
Instead of constructing the object directly, they are created via the static initializer functions. I've just included a couple of examples, but more can of course be added. - The object properties are declared as
readonly, this reduces the need for "getters" while keeping the class simple. It may seem a bit strange at first, but in cases where a changed object is needed, just create a new one instead. Also remember the lifetime of an object is for the current request only, at maximum.
Other than that I think it should be fairly straight forward. I've added a few helper functions to make things a bit more readable, and reduce code duplication.
The basic premise is that all interaction with the database table should go through the entity class. The calling code does not need to know how it's stored, or even that the data is stored in a database.
Likewise, the object has all the information needed about itself, as well as the methods needed to interact with it or manipulate it.
Once constructed the object is valid! There's no need to check the validity of the object in code that receives one. This internal consistency should be maintained by the object itself. This is part of the reason we make the properties
readonly, or private if readonly is not a viable option.Looking at the other entity classes defined so far, they do none of these measures. Properties are public, so they can be manipulated by anyone without the object itself not even being aware. They provide getters and setters, but don't do any validation in any of them, and the same with the constructor.
I hope this can be a useful starting point for the discussion, despite it's not the most interesting we would need.
Wondering if DB stuff could live in a separate class/namespace without complicating everything too much to have entity and data separated.
See commit 8a79b5a3.
It's rough, but should give a general idea. I think it's possible to take it even further, making the entities themselves more declarative, apart from the actual functionality they bring.
I think which parts to split out, and how will become more obvious as we add a few of these classes.
Also, I forgot to mention. I completely disregarded error handling in the example to keep it simple and focused on the main issues.