Stevan Little wrote:
On May 29, 2010, at 11:20 PM, Darren Duncan wrote:
2. Besides the ability to introspect or perform powerful searches on
your objects using SQL/etc, I see another big advantage of using
database storage without serialization as portability. You can have
applications written in different programming languages sharing the
same database and the same objects, because they don't contain
Perl-specific data formats.
KiokuDB mostly uses JSON and JSPON as the storage format, which is not
Perl specific. The serialization format we store in is dependent on the
Moose class definition, so in that way it is not terribly portable.
An advantage of not using serialization like JSON, but rather storing each
object attribute as a database member attribute, is that the DBMS itself can
then most easily be defined to enforce the consistency of your objects, so
someone accessing the database by some way other than KiokuDB, or using a buggy
version of KiokuDB, is less likely to be able to corrupt the data. As for how
to get the database to do that, one general answer is CHECK constraints, though
that is a fallback to where terser/simpler kinds of constraints don't do the job.
A relational database can map to an object structure of any language
fairly easily. Add attributes/columns for mutually heterogeneous
data, like when you would add object attributes, and add tuples/rows
for mutually homogeneous data, like when you would use arrays or sets.
And then you get the impedance mismatch. You are ignoring inheritance,
which is not really possible in a relational model.
I wasn't ignoring inheritance, but rather was just being terse by giving
examples rather than every relevant detail.
As for inheritance, a relational model can handle that just fine.
You also have several options for how to lay it out, depending on what you're
going for.
One option in the general case is to have a distinct database relvar/table per
each instantiatable class, which has one attribute/column per class attribute,
plus an extra attribute/column to hold an ID value for the object. When a class
composes a role or inherits from a class, the attributes defined in the others
plus those defined directly in the first class would each have a corresponding
attribute in the relvar/table attribute/column, so that each attribute of the
object of that class has a place to be stored. And so, when multiple classes
compose the same attributes, their corresponding relvars/tables all have
common-named/typed attributes/columns corresponding to said.
Another option in the general case is to also have a database relvar/table for
each role or non-instantiatable class as well, which is then the only one having
the attributes/columns that the corresponding declares, and then the
relvars/tables mentioned in the previous paragraph then wouldn't have these but
instead would have matching ID values to relate records in them to ones in the
others.
Generally speaking, with the exception perhaps of Moose classes where every
single object can have different names or kinds etc of attributes, rather than
those being class-defined, I would think the best design is for the database to
have exactly the same granularity of component data as the Moose objects do.
Just where each object can have different attributes, then the database could
probably be designed like a key-value store, but that's less ideal.
One should think about the database schema like they think about their code. It
is just as reasonable to change the schema as it is to change what classes you
have or what attributes they have. The schema *is* code, and the data it holds
is like objects of classes. No more, and no less.
Remember, objects are graphs not sets of tuples.
And graphs can be represented as sets of tuples, such as where tuples have 2
attributes that name connected graph nodes. For that matter, objects only
*represent* graphs themselves.
Now, all that I've had to say here isn't meant to diminish that the JSON
serialization approach is useful and probably a best fit for many usage scenarios.
But at the same time, relational databases are very powerful and their
strengths, of ensuring that data is consistent and making it easier to search,
should be utilized, where it makes sense to do so. Using a relational database,
without exploiting the features that make them uniquely powerful, is like
wasting the tools you have.
Perhaps a reasonable analogy is people who use Perl 5 but write their Perl code
as if they were using Perl 4, and were faking references rather than using real
references, structures, and objects. Sometimes I think of that when I hear of
people just dumping objects as a serialized string in a relational database.
-- Darren Duncan