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.

7 comments:

  1. Ogromny plus za rekomendację mybatis. Już kilka projektów wstecz doszliśmy do podobnych przemyśleń i biorąc pod uwagę prędkość kodowania, możliwości i lekkości aplikacji mybatis niestety albo i stety w połączeniu z guice-m bije spring-a z hibernate-m na głowę. Są to jedynie nasze osobiste przemyślenia, więc bardzo proszę o wyrozumiałość.

    ReplyDelete
  2. Odnośnie sekcji "Czy używanie O/RM na zatem sens?" to powiedziałbym, że właśnie odwrotnie: w systemach (modułach) klasy "prosty crud" użycie orm można przyjąć jako deafultowe ponieważ sprzyja rapid developentowi.

    W skompilowanych domenach nic nie jest proste i ficzery orma takie jak lazy loading czy kaskady potrafią dać w kość:P

    Brakuje po prostu w jpa przełącznika simple/full mode. W simple działałaby tak jak ibatis.

    ReplyDelete
  3. a może tak po prostu użyć bazy obiektowej? Na przykład darmowego db4o, które przy małej ilości równoległych zapytań bije wydajnością hibernate-a na głowe.

    ReplyDelete
  4. tak, ale w większości organizacji pewnych założeń nawet się nie dyskutuje. na przykład: baza relacyjna to jeden z takich dogmatów:)

    ReplyDelete
  5. Dlatego trzeba wyjść z zaścianka i promować inne rozwiązania ;) Wiadomo, że do firm nowe technologie docierają z opóźnieniem, ale to nie znaczy, że nie można próbować tego zmieniać. Nie od razu rzym zbudowano. A stagnacja i udawanie, że nie ma problemów z koncepcją ormów jako taką niczego nie zmieni. Użytkownika koncowego nie interesuje czy pod spodem jest baza relacyjna czy obiektowa czy dokumentowa. Ma działac, pozatym działac szybko ;)

    ReplyDelete
  6. Dominik, db4o tak nie bardzo darmowe jest jeśli chcesz go użyć w komercyjnym produkcie. Jest ew neoDatis ale wygląda jakby przestał się rozwijać ;(

    ReplyDelete
  7. Jedną z głównych zalet ORM jest możliwość cache'owania encji (first-level cache). Wymaga to architektury stanowej (stateful), czyli np. Stateful EJB albo konwersacje Seam oraz używanie rozszerzonego kontekstu utrwalania (extended persistence context). Taka architektura minimalizuje obciążenie bazy danych, co w wielu przypadkach jest wąskim gardłem systemu.

    ReplyDelete