Sunday, December 23, 2012

Čas dát NHibernatu sbohem #1 - nízká transparentnost

Mám rád frameworky. Použít sílu, inteligenci a práci ostatních, kterou nabízí zdarma, mi přijde jako dobrý nápad, který šetří lidské zdroje a člověka učí. Proto také v našem .NET produktu HP Service Virtualization používáme NHibernate, Spring.NET, NUnit atd.

Ostatně princip ORM je dobrý nápad. Team, starající se o persistenci, rychle nabootuje do problematiky persistence, nevynalézá kolo s různými koncepty jako je optimistic locking, session handling, podporuje relativní přenositelnost mezi databázemi a persistentní úroveň napíšete za zlomek času. V následujicí sérii článků bych rád popsal pár postřehů, proč se skoro po třech letech chceme NHibernatu na našem produktu zbavit. Pořadí problému se nemusí nutně shodovat s jejich závažností :-)

Poslední dobou slýchávám názor, že jsou věci složité jinak by je dělal každý. Tohle tvrzení je skoro v rozporu s dobrými programátorskými mravy :-) Asi před rokem jsem četl knížku Tajemství inovací Steva Jobse. Ač nejsem milovník Apple, kniha ve mě zásadně vylepšila náhled na složitost naprogramovaného kódu. Od té doby se snažím dbát na jednoduchost všeho co dělám.

NHibernate je vysoce konfigurovatelný, umí mnoho věcí nastavit, často velmi umě schovává hodně složitou funkcionalitu za jednoduché koncepty. Přesto to pro složitější aplikace nemusí stačit.

Jeden příklad složitosti za všechny. Hibernate Session. Výborný koncept, který umí pomocí optimistického přístupu cachováním šetřit přístup do DB. Zaručuje dokonce prakticky vyšší izolační level než standardní Read Committed - pokud jednou načtete entitu, dostanete během životnosti session vždy stejnou instanci - samozřejmě s určitými vyjímkami. Což jsou přesně ty složitosti o kterých mluvím.

Problém je, že tento koncept musíte vystavit mimo databázovou vrstvu, např. s použitím Transaction API ve Springu v komponentách, které řeší transakce. Jakmile tohle uděláte, nemáte věci pod kontrolou. Potom pracuje se session, alespoň na pozadí, váš celý tým. Všichni členové pak musí umět správně se session fungovat, vědět kdy co dostanou, kdy mají co updatovat, kdy refreshovat. Handlování práce se session začne prorůstat mimo databázi. Mužete ho sice skrýt za repository, ale už je vidět.

Pokud je počet uživatelů podobného API větší, vždycky se najde pár jedinců, kteří jej používají špatně. Vše se později zvrtne k tomu, že místo šetřeni dotazů do databáze se queruje vždycky.

V kombinaci s magičností sklouzneme zákonitě k tomu, že bychom lépe spali, kdybychom si session komponentu psali sami, vynutili si jasný lifecycle manažovaných entit a měli vše pod kontrolou, protože celý zbytek teamu nerozumí detailně session logice a nemá čas číst stovku stránek NHibernate manuálu.

Proč magičností? Springové transakční API handluje lifecycle session. Rádi bychom během celého processení jednoho callu na náš server měli session jako unit of work. Springové transakční API se bohužel nechová tak, že bychom mimo něj poznali, kdy vytvárí novou session a kdy ji znovupoužívá - což je chování, kterého chceme dosahnout. Tímto přesně zajistíme konzistenčnost během celého zpracování.

Další magičnost? Např. v Second Level Cache není občas jasné proč je držena starší entita než očekáváme a několik dnů strávených debugováním NHibernate knihoven nenese ovoce. Musíte potom obcházet celý koncept, tu a tam session či cache clearovat nebo naopak flushovat, aby se v ní objevilo to správné. Začíná se to pak celé nebezpečně hákovat.

NHibernate je mocný nástroj, ale jako vždycky věci normalizuje. Zjednodušení konceptu má vždy velkou nevýhodu a to skrytí určitých věcí o kterých rozhoduje sám framework za vás. Pokud je ale chcete měnit, musíte si přepsat tu a tam nějakou komponentu. Prostě vám občas nesedí defaultní chování.

Pokud tohle chcete, raděj se HNibernatu vyhněte.

Co bude příště? Performance. Kdy a proč se vyhnout NHibernate, když chcete vysokou performance.

0 comments: