Saturday, March 12, 2011

Po co O/RM?

Oprócz tego, że JPA, Hibernate, TopLink i stado podobnych są fajne to jaki konkretnie jest z nich pożytek? Ale tak konkretnie: jaki?

Wydaje mi się, że zakres stosowalności O/RM jest dużo węższy niż, po wstępnym zachłyśnięciu się technologią, mogłoby się wydawać. Poniżej zebrałem parę argumentów, za O/RM, które często mi się obijały o uszy plus moje wątpliwości, czy rzeczywiście to są wystarczająco mocne argumenty.

1. Niezależność od konkretnej bazy danych
Ok, ale jak często zmieniasz bazę danych? 2 czy 3 razy w tygodniu? Może, gdy tworzy się soft, którzy będzie miał różne wdrożenia i różnych klientów, w różnych środowiskach, to mooooże to być jakiś argument. Z drugiej strony, gdy tworzymy, takie oprogramowanie, to zazwyczaj mamy bazę, którą rekomendujemy, a klient się na to godzi, bo nie ma innego wyjścia

2. Automagiczne generowanie schematu
Fajne podczas prototypowania, ale soft produkcyjny oparty o automatycznie wygenerowany schemat z encji, które miały tylko @Entity, @Id i @OneToMany, to brzydactwo. Autogenerowanie uczy złego nawyku, że baza danych to pikuś i nie trzeba się nią przejmować.

Otóż, trzeba. Jedyne słuszne spostrzeżenie entuzjastów O/RM jest takie, że baza danych i obiekty to dwie różne bajki. Model obiektowy powinien być tworzony przez ludzi, którzy się na tym znają, a model danych (schemat bazy) przez innych dedykowanych temu specjalistów. Natomiast O/RM jest po to, aby jedno z drugim ożenić.

3. Programista obiektowy powinien zapomnieć o bazie danych
Akurat baza danych da o sobie zapomnieć, dobre sobie! Kto zapomniał jak się pisze w SQL, ręka w górę...

Po pierwsze: ewoluujący w trakcie rozwoju projektu model, często wymaga modyfikacji mapowań, co siłą rzeczy nie pozwala zapomnieć o bazie danych.

Po drugie: mapowania, podobnie jak baza danych wymagają profilowania, np.: nie za dużo joinów w zapytaniach, czy występuje n+1 select problem, jakiego rodzaju zapytania są najczęstsze itd. Takie profilowanie, wymaga jednak analizy generowanych przez O/RM SQLi. I znów baza danych zagląda nam przez ramię.

Po trzecie: w 8/10 projektach, których w ten czy w inny sposób uczestniczyłem programiści wspomagali się procedurami składowymi, trigerami itp,, w poważaniu mając idealistyczny koncept zapominania o bazie danych.

4. Wygoda użytkowania
No nie wiem... O/RM jedne problemy rozwiązuje, ale za to wprowadza szereg innych. Żeby dobrze korzystać ze zmapowanego modelu, trzeba mieć dogłębną świadomość relacji, trzeba wiedzieć jak są obiekty ze sobą powiązane, gdzie jest lazy, a gdzie eager, gdzie jest kaskadowość, a gdzie jej nie ma, kto jest właścicielem relacji itp. Inny jest sposób pracy z modelem z włączony filtrem OpenSessionInView, inny bez niego.

Te ograniczenia są dla mnie sporym usztywnieniem. Staram się zapomnieć o bazie danych, ale muszę jednocześnie zawsze pamiętać o sposobie mapowania do bazy i mapowania pomiędzy obiektami.

5. JPA pozwala używać różnych dostarczycieli presystencji
Owszem pozwala, ale jaka z tego korzyść dodana? Używanie JPA w celu uniezależnienia się o konkretnego frameworka to mit. JPA, jak to standard, rozwija się dość powoli, a programiści chcąc poradzić sobie z bieżącymi problemami, używają rozwiązań (np.: adnotacji) specyficznych dla danego dostarczyciela i wspaniała idea niezależności bierze w łeb.

6. Nie ma bałaganu z DTO dzięki obiektom detached
Trochę racja trochę nie. Bardzo często na widoku potrzebujemy pokazać dane przekrojowe, pochodzące z wielu obiektów domenowych. Fragmenty modelu trzeba spłaszczyć oraz najczęściej przepakować do DTO.

Czy używanie O/RM na zatem sens?
Sądzę, że ma. Widzę tu następujące kryterium w modelu domenowym występują złożone relacje pomiędzy obiektami i chcemy z tych relacji korzystać.

To relacje między obiektami są największą wartością dodaną O/RMów. Egzekwowanie kaskadowości, leniwości może w bogatych i złożonych modelach uprościć programowanie kodu biznesowego. Jeśli zaś mam prościutki (i często anemiczny) model zawierający jedynie @Entity @Id @OneToMany i koncentrujemy się na operacjach CRUD na encjach, to O/RM jest zdecydowanie na wyrost, stanowi niepotrzebną warstwę pośrednią

Jeśli nie O/RM, to co?
Czyste JDBC (a jakże!) plus biblioteki pomocnicze. Rozwiązania takie jak mybatis (dawniej iBatis) albo klasa narzędziowa JdbcTemplate z stajni Springa oraz sensowne przemyślenie architektury z udziałem DAO w bardzo wielu przypadkach naprawdę wystarcza.