Avant de répondre à la question, je pense que certains antécédents s'imposent.
Le cœur du problème
Après des années d'interview et d'embauche de développeurs, j'ai appris deux choses:
La grande majorité des développeurs ont très peu d'expérience dans la conception de bases de données.
J'ai remarqué une faible corrélation entre ceux qui ne comprennent pas les bases de données et ceux qui détestent les ORM.
(Remarque: et oui, je sais qu'il y a ceux qui comprennent très bien les bases de données qui détestent les ORM)
Quand les gens ne comprennent pas pourquoi les clés étrangères sont importantes, pourquoi vous ne pas inclure le nom du fabricant dans le item
tableau, ou pourquoi customer.address1
, customer.address2
et les customer.address3
champs ne sont pas une bonne idée, en ajoutant une ORM pour le rendre plus facile pour eux de bogues de base de données d'écriture ne va rien aider.
Au lieu de cela, avec une base de données correctement conçue et un cas d'utilisation OLTP, les ORM sont dorés. La plupart du travail de grognement disparaît et avec des outils tels que DBIx :: Class :: Schema :: Loader , je peux passer d'un bon schéma de base de données à du code Perl fonctionnel en quelques minutes. Je voudrais citer la règle de Pareto et dire que 80% de mes problèmes ont été résolus avec 20% du travail, mais en réalité, je trouve les avantages encore plus importants que cela.
Abuser de la solution
Une autre raison pour laquelle certaines personnes détestent les ORM est qu'elles laisseront l'abstraction s'échapper. Prenons le cas commun des applications Web MVC. Voici quelque chose que nous voyons couramment (pseudo-code):
GET '/countries/offices/$company' => sub {
my ( $app, $company_slug ) = @_;
my $company = $app->model('Company')->find({ slug => $company_slug })
or $app->redirect('/');
my $countries = $app->model('Countries')->search(
{
'company.company_id' => $company->company_id,
},
{
join => [ offices => 'company' ],
order_by => 'me.name',
},
);
$app->stash({
company => $company,
countries => $country,
});
}
Les gens écrivent des routes de contrôleur comme ça et se tapent dans le dos, pensant que c'est du bon code propre. Ils seraient consternés par le codage en dur de SQL dans leurs contrôleurs, mais ils n'ont guère fait plus qu'exposer une syntaxe SQL différente. Leur code ORM doit être inséré dans un modèle, puis ils peuvent le faire:
GET '/countries/offices/$company' => sub {
my ( $app, $company_slug ) = @_;
my $result = $app->model('Company')->countries($company_slug)
or $app->redirect('/');
$app->stash({ result => $result });
}
Tu sais ce qui s'est passé maintenant? Vous avez correctement encapsulé votre modèle, vous n'avez pas exposé l'ORM, et plus tard, lorsque vous constatez que vous pouvez récupérer ces données dans un cache au lieu de la base de données, vous n'avez pas besoin de changer le code de votre contrôleur (et c'est plus facile écrire des tests et réutiliser la logique).
En réalité, ce qui se passe, c'est que les gens fuient leur code ORM sur tous leurs contrôleurs (et vues) et lorsqu'ils rencontrent des problèmes d'évolutivité, ils commencent à blâmer l'ORM plutôt que leur architecture. L'ORM obtient un mauvais coup sec (je vois cela à plusieurs reprises pour de nombreux clients). Au lieu de cela, masquez cette abstraction afin que lorsque vous avez véritablement atteint les limites de l'ORM, vous pouvez choisir des solutions appropriées à votre problème plutôt que de laisser le code être si étroitement couplé à l'ORM que vous êtes lié au porc.
Rapports et autres limitations
Comme Rob Kinyon l'a clairement expliqué ci-dessus, les rapports ont tendance à être une faiblesse des ORM. Il s'agit d'un sous-ensemble d'un problème plus vaste où le SQL complexe ou SQL qui s'étend sur plusieurs tables ne fonctionne parfois pas bien avec les ORM. Par exemple, parfois l'ORM force un type de jointure que je ne veux pas et je ne peux pas dire comment résoudre ce problème. Ou peut-être que je veux utiliser un indice dans MySQL, mais ce n'est pas facile . Ou parfois, le SQL est tellement compliqué qu'il serait préférable d'écrire le SQL plutôt que l'abstraction fournie.
C'est une des raisons pour lesquelles j'ai commencé à écrire DBIx :: Class :: Report . Jusqu'à présent, cela fonctionne bien et résout la majorité des problèmes que les gens ont ici (tant qu'ils sont OK avec une interface en lecture seule). Et bien que cela ressemble à une béquille, en réalité, tant que vous ne fuyez pas votre abstraction (comme expliqué dans la section précédente), cela rend le travail DBIx::Class
encore plus facile.
Alors, quand choisirais-je DBIx :: Class?
Pour moi, je choisirais la plupart du temps que j'ai besoin d'une interface avec une base de données. Je l'utilise depuis des années. Cependant, je ne le choisirai peut-être pas pour un système OLAP, et les nouveaux programmeurs vont certainement avoir du mal avec. De plus, je trouve souvent que j'ai besoin de méta-programmation et bien que DBIx::Class
fournit les outils, ils sont très mal documentés.
La clé d'une utilisation DBIx::Class
correcte est la même que pour la plupart des ORM:
Ne laissez pas fuir l'abstraction.
Écrivez vos damnés tests.
Apprenez à passer à SQL, au besoin.
Apprenez à normaliser une base de données.
DBIx::Class
, une fois que vous l'aurez appris, s'occupera de la plupart de vos tâches lourdes pour vous et facilitera l'écriture rapide des applications.