Telephone +44(0)1524 64544
Email: info(at)shadowcat.co.uk

Sat Dec 22 00:30:00 2012

Slides for the talk future-of-dbix-class at yapc-na-2009

The future of
DBIx::Class

-

Matt S Trout

-

Catalyst
DBIx::Class
Moose

-

Shadowcat Systems Limited
http://shadowcat.co.uk/

-

North West
England

-

Web Development
Consultancy

-

international
client base

-

"mst
doesn't
sleep"

-

no, I just work
on too many
time zones ...

-

-

Conference
Driven Development

-

Conference
Driven Design

-

works if they
tell me they
accepted
the talk ...

-

-

The past of
DBIx::Class

-

Class::DBI

-

the "classic"
perl ORM

-

Schwern

-

Tony
Bowden

-

Class::DBI::Sweet

-

Christian
Hansen

-

ActiveRecord
:include

-

"you can't
do that in
Class::DBI"

-

two days
later ...

-

fighting the
superclass

-

backwards
compatibility

-

bugwards
compatibility

-

unrefactorable

-

new research
project

-

DBIx::Class

-

start from
scratch

-

Class::DBI
test suite

-

composite
keys

-

join and
prefetch

-

component
system
via MI

-

very
experimental

-

then people
deployed it!

-

they deployed
our trunk to
production!

-

AAARGH!

-

stable
release
cycle

-

never
finished
researching

-

lots of
design
mistakes

-

lots of
new tools
available

-

time for
a rethink

-

this one -is-
refactorable

-

-

The present of
DBIx::Class

-

What did we
get right?

-

making
everything
objects

-

Schema
object

-

multiple
connections

-

central
object for
schema +
connection

-

Storage
and Cursor
objects

-

hides away
backend
specifics

-

auto-increment
limit syntaxes
DBD weirdnesses

-

(even DBI)

-

ResultSource
object

-

table/view
metadata

-

not tied to
the class

-

relationships

-

near side
far side
join condition

-

no single
column
assumptions
for keys

-

Result
Class

-

inflate_result

-

minimal
protocol

-

don't even
need objects

-

ResultSet

-

virtual
view

-

lazy
persistence
backed
collection

-

pure
functional

-

(sort of)

-

chainable
updatable
cacheable

-

EXTENSIBLE

-

-

digression

-

ResultSets
fucking
rock

-

ResultSets
were an
accident

-

trying to
factor things
out cleanly

-

need an 'aha'
moment to
use them right

-

I don't like
aha moments

-

they remind
me of failing
to learn lisp

-

they remind
me of failing
to learn monads

-

they remind
me of failing
to learn git

-

"learning this
will make you
a better
programmer"

-

great

-

what about
being done and
down the pub?

-

Result Class
vs.
ResultSource
object

-

inflate_column
vs.
add_relationship

-

list context
vs.
scalar context

-

search() args
vs.
find() args

-

aha moments
indicate
conceptual
inconsistency

-

sometimes that means
UR CONCEPTUALISIN
IT COMPLETELY WRONG

-

(so you should
still learn lisp
for that aha)

-

usually it just
means the UI
is retarded

-

(see git)

-

essential
vs.
implementation
complexity

-

better
understanding

-

better
conceptualisation

-

better
implementation

-

DBIx::Class
sucks

-

because it
raised our
expectations

-

understand
(ab)use
hate
improve

-

-

The present of
DBIx::Class

-

What did we
get wrong?

-

... most
things ...

-

lots of
details

-

filter
vs.
single
accessor

-

find() deflates,
search() doesn't

-

connection
attached to
schema
instance

-

details?

-

underlying
design
mistakes

-

persistent
vs.
non persistent

-

why should
"in the same
database"
be special?

-

query
handling

-

SQL::Abstract
AST has too
much DWIM

-

too much
DWIM?!

-

hard to
introspect

-

can't do
inference

-

objects know
too much

-

->insert

-

why should it
care it's
persisted?

-

$rs->next

-

stupid
stupid
STUPID

-

implicit
iterators
are BAD

-

each %hash
anyone?

-

(even 5.8.8's
Data::Dumper
gets it wrong)

-

ORM

-

O/R
Mapper

-

where's the
mapper?

-

one class
<->
one table

-

one class
<->
one view

-

we can fake
it with
delegation

-

search() doesn't
understand
that though

-

-

so, are we
fucked?

-

NO

-

(because we
didn't get to
the pub in time
to pull ...)

-

designed
to be
refactored

-

lots of
tests

-

(CDBICompat
has better
tests than
Class::DBI)

-

rebuild
refactor
re-use
rebase

-

-

The future of
DBIx::Class

-

persistence
backend

-

  class CD;

  has id ...
  has title ...
  has year ...

-

  class MusicDB;

  has cds => (
    isa => HashMap[CD, over => 'id'],
    ...
  );

-

  my $music = MusicDB->new;
  my $cd = $music->cds->add({
    title => 'Morning Rain'
  });
  is($cd, $music->cds->{$cd->id});

-

  my $db_schema = schema {
    table cds {
      column id auto_increment;
      column title ...
    }
  }

-

  my $store = Data::Store->new(
    driver => 'DBI', # DBIx::Class :)
    schema => $db_schema,
  );

-

  # this is a complete guess
  my $music = $store->connect(
    dsn => $dsn
  )->associate(
    'MusicDB',
    cds => 'cds'
  );

-

what's my
point?

-

uniform
data APIs

-

a collection is
a collection is
a collection ...

-

perl array
directory
database table

-

we shouldn't
care about what
data -is-

-

we should care
about what it
can -do-

-

Data::CapabilityBased

-

capability?

-

a role with
a default
implementation

-

and a
validation
test suite

-

Data::Collection::Capability::Mappable

-

  $coll->map(sub {
    ...
  });

-

  $coll->map_by('title');

-

  method map_by ($attr) {
    $self->map(sub ($x) {
      $x->$attr;
    });
  }

-

  class DBIx::Class::ResultSet;

  method map_by ($attr) {
    if ($self->_has_relationship($attr)) {
      return $self->search_related($attr);
    }
    ...
  }

-

semantic
queries

-

  use Data::Query qw(expr);

  $coll->grep(expr {
    $_->name eq 'Bob'
  });

-

  array?
  grep { $_->name eq 'Bob' } @array

-

  resultset?
  WHERE name = 'Bob'

-

SQL::Abstract 2
provides an
explicit AST

-

Data::Query
backend generates
to the AST

-

introspectable
means
transformable

-

  $_->city eq 'Pittsburgh'

-

  WHERE city = ?

-

  JOIN cities city ON
  city.id = tbl.city_id
  WHERE city.name = ?

-

-this- is
the M in
ORM

-

-

streams

-

  my $stream = $rs->as_stream;
  while (my $obj = $stream->next) {
    ...
  }

-

compatibility?

-

  class DBIx::Class::ResultSet;

  method next {
    $self->_implicit_stream
         ->next;
  }

-

-

store !=
connection

-

default
connection
object

-

dynamically
scoped

-

composite
connections

-

sharding
balancing
query slaves

-

-

observability

-

$foo->bar($baz);

-

how do we
track this?

-

Variable::Magic

-

tie on
perl5 v8

-

  method update (...) {
    store_for($self)
      ->update(...);
  }

-

can't build
it the other
way around

-

-

scoped
flushing

-

  $obj->foo($foo);
  $obj->bar($bar);
  $obj->baz($baz);

-

when do I
UPDATE?

-

  UPDATE tbl SET foo = ?
  UPDATE tbl SET bar = ?
  UPDATE tbl SET baz = ?

-

  $obj->update; # :)

-

  $store->flush;

-

  flush_at_end {
    ...
  }

-

  $obj->foo($foo);
  $obj->bar($bar);
  $obj2->baz($baz);

-

  UPDATE tbl SET
  foo = ?, bar = ?

-

-

Data::CapabilityBased
design sketch
is on CPAN

-

discussion will
happen on the
dbix-class list
and channel

-

these slides
will be on
http://shadowcat.co.uk/

-

Any
Questions?

-

Thank
You

-

irc.perl.org #dbix-class
http://lists.scsys.co.uk/
these slides will be on
http://shadowcat.co.uk/