Skip to main content

Č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.

Comments

Popular posts from this blog

NHibernate performance issues #3: slow inserts (stateless session)

The whole series of NHibernate performance issues isn't about simple use-cases. If you develop small app, such as simple website, you don't need to care about performance. But if you design and develop huge application and once you have decided to use NHibernate you'll solve various sort of issue. For today the use-case is obvious: how to insert many entities into the database as fast as possible?

Why I'm taking about previous stuff? The are a lot of articles how the original NHibernate's purpose isn't to support batch operations, like inserts. Once you have decided to NHibernate, you have to solve this issue.

Slow insertion
The basic way how to insert mapped entity into database is:
SessionFactory.GetCurrentSession().Save(object);But what happen when I try to insert many entities? Lets say, I want to persist
1000 librarieseach library has 100 books = 100k of bookseach book has 5 rentals - there are 500k of rentals It's really slow! The insertion took exactly

Git on Windows: MSysGit

I have started to use Git today. I read a lot of discussions that there is no good tool for Windows platform. After forethought I have decided to used TortoiseGit. I also feared of difficult work related with Git as a lot of articles mentioned many instructions. As I already said, I have decided to use TortoiseGit, because I'm used to work with TortoiseSvn, but for start, MSysGit is enought. So this article is about MSysGit, next will be about TortoiseGit.

How to start with MSysgit on local machine?
Download and install Git for WindowsCreate source code directory for your git appRight click the directory at your favorite file browser. Menu should contain item "Git init here". It initializes chosen directory to be git-abled :-)It was your first usage of Git.

Commit data to local Git repository

Now, you can add any file, your first source code, to created directory. If you are prepared to commit any changes to your local git repository, follow next instructions.
Right-click th…

Java, Docker, Spring boot ... and signals

I spend last couple weeks working on java apps running within docker containers deployed on clustered CoreOS machines. It's pretty simple to run java app within a docker container. You just have to choose a base image for your app and write a docker file.

Note that docker registry contains many java distributions usually based on open jdk. We use our internal image for Oracle's Java 8, build on top of something like this docker file. Once you make a decision whether oracle or openjdk, you can start to write your own docker file.

FROM dockerfile/java:oracle-java8
ADD your.jar /opt/your-app
ADD /dependencies /opt/your-app/dependency
WORKDIR /opt/your-app
CMD ["java -jar /opt/your-app/your.jar"]
However, your app would probably require some parameters. Therefore, last line usually calls your shell script. Such script than validates number and format of those parameters among other things. This is also useful during the development phase because none of us want to build …