Are you using your objects, or are they using you?

Ovid on 2009-01-28T11:47:21

Want to have fun sometime? Take a moderately complex system, open up one of your tests which instantiates an object and put the following line in your test just after you've instantiated an object:

$DB::single = 1;

That sets a breakpoint so that when you run the test under the debugger (perl -d t/some_test.t), you can type 'c' and the code will run until it hits that line. So imagine this:

#!/usr/bin/env perl

use strict;
use warnings;

use Test::Most 'no_plan';

use My::ORM::Customer;   # ORM classes are great for this
use My::Test::Fixtures;
My::Test::Fixtures->load('customers');

my $customer = My::ORM::Customer->find({ id => 1 });
$DB::single  = 1;

Now assuming that your code has stopped just after the $customer object has been instantiated, type this in the debugger and be amazed:

m $customer

In the debugger, the 'm' command tells you which methods are available on an object and which classes they're from. I did this for a simple object we instantiate. It's for our ORM and it represents a table with 8 fields, two of which are only for auditing. 255 methods were listed. Two hundred and fifty-five. They are defined across twenty-seven classes. And frankly, I'm not convinced that this list is complete, but that's the debugger for you.

Just some food for thought.


Oh don't tease us...

Alias on 2009-01-28T14:40:07

... and how many of those were from UNIVERSAL:: ? :)

Re:Oh don't tease us...

Ovid on 2009-01-28T15:10:04

via UNIVERSAL: VERSION
via UNIVERSAL: a_sub_not_likely_to_be_here
via UNIVERSAL: can
via UNIVERSAL: isa

The full list of classes involved:

Class::Accessor::Grouped
Class::C3::Componentised
DBIx::Class
DBIx::Class::Co mponentised
DBIx::Class::Core
DBIx::Class::InflateColumn
DBIx::Class::Relatio nship
DBIx::Class::Relationship::Accessor
DBIx::Class::Relationship::BelongsTo
DBIx::Class::Relationship::HasMany
DBIx::Class::Relationship::HasOne
DBIx::C lass::Relationship::Helpers
DBIx::Class::Relationship::ManyToMany
DBIx::Class: :Relationship::ProxyMethods
DBIx::Class::ResultSourceProxy
DBIx::Class::Result SourceProxy::Table
DBIx::Class::Row
DBIx::Class::UTF8Columns
Exporter::NoWork
PIPs::ResultSourceBase::AuditedObject
PIPs::ResultSourceBase::ClipEpisode
PI Ps::ResultSourceBase::ContentObject
PIPs::ResultSourceBase::HasParentBrand
PIP s::ResultSourceBase::HaveIdentifiers
PIPs::ResultSourceBase::Pips
UNIVERSAL
U til::Class

(Note that all those extra spaces in the class names are artifacts of use.perl, not my list)

Of course, this doesn't do it justice because some "methods" are actually exported subroutines, so we can't really tell where they're from. And if a class overrides a method, the debugger won't tell you which classes have overridden which methods. This is particularly fun when you stumble across inheritance hierarchies which resemble graphs instead of trees.

Change ORM !

dami on 2009-01-29T16:32:33

Well, if 255 methods/27 classes are too much for your taste, change ORM!

DBIx::DataModel will only cost you about 50 methods in 3 classes (the exact number depends on how many relationships there are between this table and other tables).

(sorry, DBIC folks, I couldn't resist ...)

Re:Change ORM !

Ovid on 2009-01-29T17:56:34

Well, I doubt I could push that through at work, but I suspect that I'd be inclined to go the SQL dictionary route. Still, just glancing at it, DBIx::DataModel looks interesting.

Re:Change ORM !

Aristotle on 2009-01-31T14:11:03

No no, no SQL dictionary, you want to look at Fey.

Re:Change ORM !

Ovid on 2009-01-31T14:43:31

Ah, that looks lovely! And yes, better than a dictionary.

Re:Change ORM !

Aristotle on 2009-01-31T17:15:48

It is lovely! I have been using it for a while and it has worked out every bit as well as I had hoped for. Sometimes I had to change the shape of my queries a little to accommodate it, but I have yet to run into a wall due to the fundamental design. There were stumbling blocks in cases where I ran into corners that Dave hadn’t built out yet – f.ex. when I first started with it, it failed if you tried to join against a table alias, which I needed for my tag (as in “folksonomy”) joins. (I do those by adding a variable number of inner self-joins on the tag table, each join needing its own `WHERE` clause, depending on the number of specified tags.) However that was merely an issue of incomplete implementation and he has been very responsive about fixing my gripes.

I hope more people pick up Fey, and have been cheerleading for it for a while now. (See StackOverflow, f.ex.) With more people beating on it the rough edges would hopefully soon be smoothed out, and the principal design is exactly what I have always wanted when I examined ORMs: a way to layer those abstractive facilities on top of SQL that SQL itself lacks, while still writing queries directly, rather than implying them through navigation of an OO model of a query result.

Re:Change ORM !

zby on 2009-02-03T14:34:00

I know this is rather irrational - but the thing that off puts me from Fey is that the connection is kept in a singleton. This leads to the need of not very DRY declarations:



package Forum::Model::User; use Forum::Model::Schema; use Fey::ORM::Table;

has_table( Forum::Model::Schema->Schema()->table('User') );


It could be just:



package Forum::Model::User; use base Forum::Model::Schema;

has_table( 'User' )


I am acustomed to the DBIC way of having a normal Schema object that keeps the connection and represents the database.

Re:Change ORM !

Aristotle on 2009-02-03T15:56:25

I’m talking only about Fey::SQL, not Fey::ORM. I don’t use Fey::ORM at all.

But do to take up your concerns with Dave – he’s a reasonable guy.

Re:Change ORM !

zby on 2009-02-04T14:37:37

I've already asked him about the possibility of shortening the declarations. The answer was that that it probably mean too much magic - which is, in my opinion, only the consequence of using 'magic' signletons in the first place. I will not ask him about getting rid of that - since I would not expect any productive answer - this is too basic design choice to change in the mid-work.

Re:Change ORM !

Aristotle on 2009-02-04T14:51:10

Ah. Well, I am happy to remain blissfully unaware of these issues and to stick with Fey::SQL. :-)