ORM je antipattern

mozek

Do diskusí o ORM, NotORM, SQL, noSQL a dalších tentokrát přidáme jeden poměrně radikální názor na ORM. Jeho autor vzbudil tímto článkem poměrně silnou a ostře polarizovanou diskusi mezi vývojáři. Přesto jeho argumenty stojí minimálně za přečtení a zamyšlení. Souhlasíte s nimi? Nesouhlasíte?

Článek je volně přeložen z anglického originálu ORM is an anti-pattern, který napsal Laurie Voss (technický vedoucí awe.sm, dříve např. Yahoo! Widgets) a vydal ho na svém blogu pod licencí CC-BY-NC-SA. Vydáváme ho zde se souhlasem autora a pod stejnou licencí.

Minulý týden jsem tweetnul o ORM, a od té doby se mě několik lidí ptalo, jak jsem to myslel. Já jsem sice o ORM už psal, ale to bylo v kontextu větší diskuse o SQL a já bych to nerad míchal dohromady. Takže v tomto textu se budu držet pouze problematiky ORM. Vynasnažím se být stručný, protože z předchozích článků o SQL vím, že lidé mívají sklon po první větě, která je naštve, přestat číst a rovnou komentovat (i kdyby třeba dál v textu bylo tvrzení vysvětleno).

Co je to antipattern?

Potěšilo mě, když jsem našel na Wikipedii obsáhlý seznam antipatternů, jak ze světa programování, tak i mimo něj. Proč považuju ORM za antipattern? Protože splňuje hned dvě kritéria, která podle autora knihy AntiPatterns odlišují antipatterny od špatných návyků. Konkrétně:

  1. Na začátku se jeví jako přínosné, ale postupem času se objevuje víc špatných důsledků, než těch dobrých
  2. Existuje alternativní řešení, které je ověřené a znovunasaditelné

Právě ten první faktor vedl, podle mého, k obrovské popularitě ORM: na začátku to vypadá jako dobrý nápad, a když se postupem času objevují problémy, už je pozdě něco měnit.

Co označuji jako ORM?

Hlavní cíl mé kritiky je ActiveRecord, zpopularizovaný v Ruby on Rails a portovaný do půltuctu dalších jazyků. Ale stejně tak lze většinu výhrad vztáhnout i na jiné ORM, jako Hibernate v Javě a Doctrine v PHP.

Výhody ORM

  • Jednoduchost: některé ORM nástroje vám budou tvrdit, že „odstraní nutnost znát SQL“. To je slib, který žádný z těch, co jsem viděl, nesplnil. Jiné jsou realističtější a prohlásí, že redukují množství SQL, ale dovolí vám jej používat, když bude potřeba. S jednoduchým modelem a s projektem v počátcích je to rozhodně výhoda: s ORM budete vyvíjet rychleji a efektivněji, o tom nepochybujte. Dost možná si ale zaděláte na problémy v budoucnu.
  • Generování kódu: odstraněním uživatelského kódu z modelů pomocí ORM otevřelo cestu generování kódu, „scaffoldingu“, které vám dá funkční rozhraní ke všem tabulkám na základě jednoduchého popisu schématu. Navíc můžete schéma změnit a vygenerovat kód nový. Zase – funguje to perfektně na začátku.
  • Efektivita je „good enough“: žádný z ORM, které jsem viděl, neprohlašuje, že zvýší efektivitu. Všechny říkají, že upřednostňují jednodušší kód před výkonem. A když náhodou začne být výkon nedostatečný, můžete přece nahradit pomalé volání ORM ručně napsaným SQL, není-liž pravda?

Problémy s ORM

Neodpovídající abstrakce

Nejzjevnější problém u ORM je, že jde o abstrakci, která nedostatečně abstrahuje od implementačních detailů. Dokumentace všech velkých ORM knihoven je běžně plná odkazů na koncepty z SQL. Někdy jsou představeny, aniž by bylo řečeno, že mají ekvivalent v SQL, jindy jsou zase představovány jako funkce pro generování SQL.

Celý vtip abstrakce spočívá v tom, že by měla zjednodušovat. Abstraktní vrstva nad SQL, která předpokládá, že znáte SQL, vlastně zdvojnásobuje množství věcí k naučení: musíte umět SQL, abyste chápali, jak položit dotaz, a musíte umět přimět svoje ORM, aby ho za vás položilo. Například v Hibernate se ještě učíte třetí jazyk, HQL, což je téměř-úplně-ale-ne-naprosto SQL, a to se pak do SQL překládá.

Zastánci ORM řeknou, že to neplatí pro každý projekt, že ne každý potřebuje složité JOINy, že ORM je řešení „80/20“, protože 80 procent uživatelů potřebuje pouhých 20 procent možností SQL, a právě to ORM zařídí. Ze své patnáctileté praxe vývojáře databázových projektů mohu říct, že tohle u mne neplatilo. Pouze na samotném začátku vývoje se můžete obejít bez JOINů nebo s naivními JOINy. Později se dostanete k tomu, že je nutné dotazy konsolidovat a vyladit. I kdyby 80 % uživatelů potřebovalo 30 procent schopností SQL, tak 100 % uživatelů nakonec bude muset ORM abstrakci obejít, aby jim to nakonec fungovalo.

Nesprávná abstrakce

ORM vám bude skvěle fungovat v případě, že opravdu nepotřebujete žádné relačně-datové funkce, ale v takovém případě máte jiný problém: používáte špatné datové úložiště. Režie RDBMS je enormní; to je jeden z nejdůležitějších faktorů, proč jsou  NoSQL úložiště o tolik rychlejší. Pokud jsou vaše data relační, tak se tahle režie vyplatí: vaše databáze nejen ukládá data, ona je reprezentuje a dokáže odpovědět na otázky ohledně těchto dat, a dokáže to díky zachycení vztahů mnohem efektivněji než procedurální kód.

Pokud vaše data relační nejsou, pak jen přidáváte spoustu nepotřebného zpomalení – v první řadě je pomalá RDBMS, a nad ní ještě postavíte další zpomalující vrstvu v podobě ORM.

Na druhou stranu pokud vaše data relační JSOU, tak se nakonec mapování na objekty rozbije. SQL je založené na relační algebře: výstupem SQL není objekt, ale odpověď na dotaz. Pokud váš objekt „je“ instancí X a „má“ několik Y, a každé Y „patří“ Z, jaká je správná reprezentace takového objektu v paměti? Měly by to být jen vlastnosti X, nebo by měly obsahovat i Y a/nebo i všechna Z? Pokud budete mít pouze vlastnosti X, kdy se dotážete na Y? A budete potřebovat jedno Y, nebo všechna? Ve skutečnosti to záleží na okolnostech – to je to, co mám na mysli, když píšu, že SQL odpovídá na otázky. Reprezentace objektu v paměti záleží na tom, co se s ním chystáte dělat. OO design nenabízí nic jako „kontextově senzitivní reprezentaci“. Zkrátka: Relace nejsou objekty. Objekty nejsou relace.

Zabitý tisícem dotazů

Důsledkem je další problém ORM: neefektivita. Když si vyzvednete objekt, které z jeho vlastností (sloupců tabulky) budete potřebovat? ORM to neví, tak si řekne o všechny (nebo požaduje, abyste specifikovali sami, čímž rozbíjí abstrakci). Na začátku to není problém, ale když začnete načítat tisíce záznamů najednou, každý s 30 sloupci, z nichž potřebujete jen tři, máte smrtelný zdroj neefektivity. Mnoho ORM nástrojů je také výrazně slabých ve vytváření JOINů a raději pokládají tucet dotazů k jednomu objektu. Jak jsem už psal výše, mnohé ORM výslovně říkají, že nejsou zaměřené na efektivitu, a některé nabízejí způsob, jak problémové dotazy vyladit. Problém, který jsem v praxi pozoroval, je ten, že málokdy najdete jediný dotaz, „stříbrnou kulku“, kterou stačí optimalizovat. Smrtící pro databázové aplikace není efektivita jednoho konkrétního dotazu, ale množství dotazů. ORM chybí kontext, takže nedokáže dotazy správně konsolidovat a musí se uchylovat ke kešování a dalším mechanismům, které mohou tento nedostatek kompenzovat.

Jaké jsou alternativy?

Doufám, že se mi podařilo předvést některé případy, kde mají ORM zásadní návrhové nedostatky. Ale k tomu, aby byly antipatternem, potřebují mít alternativu. Ve skutečnosti mají hned dvě:

Používejte objekty

Jestliže jsou vaše data objektová, přestaňte používat relační databázi. IT je v současnosti zaplavené různými key-value úložišti, které umožňují uchovávat elegantní datové struktury ve velkých počtech a přistupovat k nim rychlostí světla. Není žádný programátorský zákon, který by říkal: „Krok č. 1 při psaní webové aplikace je nainstalovat MySQL“. Masivní nadužívání relačních databází na každou situaci, kdy je potřeba uložit data, je jedním z důvodů, proč si SQL získává v posledních letech tak špatnou pověst. Ve skutečnosti je příčinou líný návrhář, který nehledal vhodné úložiště, ale použil RDBMS.

Použití SQL v modelu

V programování je extrémně nebezpečné prohlašovat, že k něčemu existuje Jediná Správná Cesta™ jak to udělat. Podle mých zkušeností je nejlepším způsobem, jak reprezentovat relační data v objektově orientovaném kódu, stále pomocí modelu: zapouzdření datové reprezentace do jediného místa v kódu je dobrý nápad. Ale pamatujte, že úkolem vaší modelové vrstvy není reprezentovat objekty, ale odpovídat na otázky. Vytvořte si API, které odpovídá na otázky, co mu pokládá aplikace, a udělejte to tak jednoduché a efektivní, jak je potřeba. Někdy budou odpovědi svérázné, takovým způsobem, který i novopečený OO vývojář označí za „špatný“, ale postupem času budete nalézat stále lepší průsečíky obou světů, což vám dovolí refaktorovat dotazy do efektivní podoby.

Někdy bude výstupem jednoduchý objekt X, který je snadné reprezentovat. Ale jindy může být výstupem matice agregovaných dat, nebo naopak jediné celé číslo. Odolejte pokušení zabalit všechno tohle do mnoha vrstev abstrakce, a přistupujte k datům podle jejich vlastní přirozenosti. Především odolejte klamu OO, že dokáže reprezentovat naprosto cokoli a všechno. OO samotné je abstrakcí, hezkou a velmi ohebnou, ale právě relační data jsou jednou z hranic OO. Předstírání, že objekty mohou dělat něco, co dělat nedokážou, je základní problém v každém ORM.

Shrnutí (TL;DR)

  • ORM je na začátku snadný k pochopení a vývoj s ním je rychlejší než psaní modelů se SQL
  • Jeho efektivita je na počátku dostatečná
  • Naneštěstí se s růstem komplexnosti projektu projeví nedostatky: abstrakce je rozbitá a nutí vývojáře používat pokročilé SQL
  • V nadsázce tvrdím, že se abstrakce ORM rozbije ne ve 20 % projektů, ale skoro ve všech.
  • Objekty nejsou správná cesta, jak vyjádřit výsledky relačního dotazu
  • Nemožnost jednoznačného mapování dotazů na objekty vede k zásadním neefektivitám v aplikacích, které používají ORM. Tyto neefektivity prostupují celý projekt, jsou distribuované a proto nemohou být odstraněny ani napraveny jinak, než kompletním opuštěním ORM.
  • Zkuste se pořádně zamyslet nad designem aplikace dřív, než mechanicky nasadíte relační databázi a ORM
  • Pokud jsou vaše data přirozeně objektová, tak použijte objektová úložiště („NoSQL“). Budou mnohem rychlejší než SQL s ORM.
  • Pokud jsou vaše data z podstaty relační, pak se zvýšená režie RDBMS vyplatí.
  • Zapouzdřete SQL dotazy do modelové vrstvy, ale navrhněte svoje API tak, aby vracelo data, potřebná pro vaši aplikaci; nepodlehněte pokušení příliš generalizovat.
  • Objektově orientovaný design nedokáže reprezentovat relační data efektivním způsobem; to je zásadní omezení OO designu a ORM ho nedokáže napravit.

(Podobný pohled nabízí i článek The Vietnam of Computer Science, kde je použití ORM svým průběhem přirovnáváno k Vietnamské válce. – pozn. překl.)

Začal programovat v roce 1984 s programovatelnou kalkulačkou. Pokračoval k BASICu, assembleru Z80, Forthu, Pascalu, Céčku, dalším assemblerům, před časem v PHP a teď by rád neprogramoval a radši se věnoval starým počítačům.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 150

Přehled komentářů

VM díky
blizz Re: díky
Jean To uz se resilo mnohokrat
....
fuzzy Re: ....
Re: ....
fuzzy Re: ....
Palo Re: ....
JS Svym zpusobem i OOP je antipattern
Allstar Re: Svym zpusobem i OOP je antipattern
talpa Re: Svym zpusobem i OOP je antipattern
okbob souhlas
logik Re: souhlas
fuzzy Re: souhlas
logik Re: souhlas
v6ak Re: souhlas
logik Re: souhlas
fuzzy Re: souhlas
Jirka Hradil Re: souhlas
fuzzy Re: souhlas
T Preco si budujes idealneho "nepriatela"?
fuzzy Re: Preco si budujes idealneho "nepriatela"?
T Re: Preco si budujes idealneho "nepriatela"?
fuzzy Re: Preco si budujes idealneho "nepriatela"?
T Re: Preco si budujes idealneho "nepriatela"?
georgiksk ORM je ORM a antipatern je antipatern :-)
fuzzy Re: ORM je ORM a antipatern je antipatern :-)
T Re: ORM je ORM a antipatern je antipatern :-)
fuzzy Re: ORM je ORM a antipatern je antipatern :-)
T Re: ORM je ORM a antipatern je antipatern :-)
fuzzy Re: ORM je ORM a antipatern je antipatern :-)
T Re: ORM je ORM a antipatern je antipatern :-)
Jirka Hradil Re: ORM je ORM a antipatern je antipatern :-)
Jirka Hradil Re: ORM je ORM a antipatern je antipatern :-)
Opravdový odborník :-) Re: ORM je ORM a antipatern je antipatern :-)
Jiří Knesl k SQL
HosipLan Re: k SQL
Ivan Re: k SQL
anon Re: k SQL
T Re: k SQL
Palo Re: k SQL
fuzzy Re: k SQL
blizz Re: k SQL
jay je to polopravda
estonto korektura
Martin Malý Re: korektura
lzap Moc pěkné + dodatek
tiso Re: Moc pěkné + dodatek
Opravdový odborník :-) Re: Moc pěkné + dodatek
Čelo Re: Moc pěkné + dodatek
Karel Minařík Re: Moc pěkné + dodatek
Opravdový odborník :-) Re: Moc pěkné + dodatek
Karel Minařík Re: Moc pěkné + dodatek
Palo Re: Moc pěkné + dodatek
Jirka Hradil Re: Moc pěkné + dodatek
blizz Re: Moc pěkné + dodatek
v6ak Re: Moc pěkné + dodatek
T Re: Moc pěkné + dodatek
BurgetR Objektivní zhodnocení?
Palo Re: Objektivní zhodnocení?
logik Re: Objektivní zhodnocení?
Opravdový odborník :-) Re: Objektivní zhodnocení?
Palo Re: Objektivní zhodnocení?
fuzzy Re: Objektivní zhodnocení?
T Re: Objektivní zhodnocení?
fuzzy Re: Objektivní zhodnocení?
BurgetR Re: Objektivní zhodnocení?
fuzzy Re: Objektivní zhodnocení?
Jirka Hradil Re: Objektivní zhodnocení?
Opravdový odborník :-) Re: Objektivní zhodnocení?
fuzzy Re: Objektivní zhodnocení?
Ondra Re: Objektivní zhodnocení?
Jaro Re: Objektivní zhodnocení?
Ondra Re: Objektivní zhodnocení?
Palo Tak toto je trochu moc
Palo Re: Tak toto je trochu moc
logik Re: Tak toto je trochu moc
Palo Re: Tak toto je trochu moc
logik Re: Tak toto je trochu moc
fuzzy Re: Tak toto je trochu moc
Opravdový odborník :-) Re: Tak toto je trochu moc
fuzzy Re: Tak toto je trochu moc
Jirka Hradil Re: Tak toto je trochu moc
Opravdový odborník :-) Re: Tak toto je trochu moc
Palo Re: Tak toto je trochu moc
Jirka Hradil Re: Tak toto je trochu moc
Palo Re: Tak toto je trochu moc
Jirka Hradil Re: Tak toto je trochu moc
Palo Re: Tak toto je trochu moc
fuzzy Re: Tak toto je trochu moc
Ondra Re: Tak toto je trochu moc
fuzzy Re: Tak toto je trochu moc
fuzzy Re: Tak toto je trochu moc
Palo Re: Tak toto je trochu moc
fuzzy Re: Tak toto je trochu moc
Palo Re: Tak toto je trochu moc
fuzzy Re: Tak toto je trochu moc
Ladislav Thon Re: Tak toto je trochu moc
Opravdový odborník :-) Re: Tak toto je trochu moc
fuzzy Re: Tak toto je trochu moc
fuzzy Re: Tak toto je trochu moc
logik Re: Tak toto je trochu moc
Palo Re: Tak toto je trochu moc
Jirka Hradil Re: Tak toto je trochu moc
Palo Re: Tak toto je trochu moc
Jirka Hradil Re: Tak toto je trochu moc
Palo Re: Tak toto je trochu moc
Jirka Hradil Re: Tak toto je trochu moc
Palo Re: Tak toto je trochu moc
Opravdový odborník :-) Re: Tak toto je trochu moc
logik Re: Tak toto je trochu moc
v6ak Re: Tak toto je trochu moc
fuzzy Re: Tak toto je trochu moc
MD Re: Tak toto je trochu moc
fuzzy Re: Tak toto je trochu moc
Jirka Hradil Re: Tak toto je trochu moc
fuzzy Re: Tak toto je trochu moc
Jirka Hradil Re: Tak toto je trochu moc
T Re: Tak toto je trochu moc
Karel Minařík Re: Tak toto je trochu moc
Michal Illich Re: Tak toto je trochu moc
fuzzy Re: Tak toto je trochu moc
Palo Re: Tak toto je trochu moc
T Re: Tak toto je trochu moc
Mintaka Pythonění s SQL
Pavel Zaujatý autor
voj-tech Souhlas, ale...
okbob Re: Souhlas, ale...
Jirka Hradil Re: Souhlas, ale...
Ivan Re: Souhlas, ale...
Jakub Linhart a já se ptám: jak pro koho...
J.A.V. ani A ani B
PCHe ORM je zlo
Pavel Tisnovsky Re: ORM je zlo
Ondřej Mirtes Stačí vzít do ruky kalkulačku...
okbob Re: Stačí vzít do ruky kalkulačku...
fuzzy Re: Stačí vzít do ruky kalkulačku...
okbob Re: Stačí vzít do ruky kalkulačku...
Ivan Re: Stačí vzít do ruky kalkulačku...
Opravdový odborník :-) Re: Stačí vzít do ruky kalkulačku...
okbob Re: Stačí vzít do ruky kalkulačku...
Opravdový odborník :-) Re: Stačí vzít do ruky kalkulačku...
fuzzy Re: Stačí vzít do ruky kalkulačku...
okbob Re: Stačí vzít do ruky kalkulačku...
fuzzy Re: Stačí vzít do ruky kalkulačku...
okbob Re: Stačí vzít do ruky kalkulačku...
balki Bulvar
BenBella Objektové DB a OQL
uf Proč vzniklo ORM?
kostelnik nevim jak se to učí ve školách teď...
Zdroj: http://www.zdrojak.cz/?p=3507