Recenzja książki "Hibernate. Od Nowicjusza do Profesjonalisty"

Z Jacek Laskowski - Wiki Projektanta Java EE

Spis treści

Książka w ogóle

  • Tytuł: Hibernate. Od Nowicjusza do Profesjonalisty
  • Autorzy: Dave Minter oraz Jeff Linwood
  • Wydawnictwo oryginalnego wydania: Apress
  • Rok wydania: 2006
  • Wydawnictwo polskiego tłumaczenia: Power Net
  • Rok tłumaczenia: 2007
  • Strona domowa: http://www.hibernate.pl

Książka w szczególe - recenzja

Jest to moja pierwsza recenzja książki i prawdę powiedziawszy nie wiem od czego zacząć. Wciąż namawiam innych do recenzji książek, które otrzymujemy w ramach grupy Warszawa JUG i to jeszcze w dodatku w języku angielskim, a tu proszę, nawet po polsku jest mi trudno zacząć.

Książkę Hibernate. Od Nowicjusza do Profesjonalisty przeczytałem kilka dni temu i czas pokaże, czy recenzje powinno się robić świeżo po przeczytaniu książki, czy wręcz przeciwnie, po kilku dniach, kiedy w końcu poczujemy ten smak, który sprawił, że książkę czytało się przyjemnie lub też nie.

29 stycznia 2007 umieściłem na swoim Notatniku wpis Hibernate. Od Nowicjusza do Profesjonalisty - książka wydawnictwa Power Net o przekazaniu mi książki Hibernate. Od Nowicjusza do Profesjonalisty przez wydawnictwo Power Net do recenzji. Kiedy ostatnio podchodziłem do lektury, wiedziałem, że było to bardzo dawno temu, ale żeby aż tak?! Nie, tego się nie spodziewałem. W międzyczasie zapoznałem się ze specyfikacją Java Persistence API i przyznam, że czym więcej czytałem o JPA i EJB3, tym mniej chciałem przeczytać książkę. W dodatku, w międzyczasie nadchodziły inne książki i ta traciła na ważności. Do tego wydawało mi się, że nie był to moment powrotu do technologii sprzed JPA. Z drugiej strony, wciąż na jednym z najwyższych miejsc wyszukiwania informacji w Sieci, które sprawiły, że osoby były kierowane na mój Jacek Laskowski - Notatnik Projektanta Java EE było słowo Hibernate oraz jeden z bardziej popularnych artykułów, który de facto rozpoczął moją działalność "literacką" - Hibernate - tniemy koszty dostępu do danych relacyjnych. Moja narastająca niechęć do lektury książki, jak i ciekawość, co takiego sprawia wciąż niemalejące zainteresowanie Hibernate, sprawiły, że w końcu zabrałem się za nią i ją przeczytałem. I muszę przyznać, że wcale tego nie żałuję! Jeśli do tej pory sądziłem, że mogę obyć się bez Hibernate, to w tej chwili nie jestem już tego taki pewien. Wiele z funkcjonalności Hibernate, które wydają się mi się teraz niezwykle użyteczne - zapytania kryteriowe (Criteria Query API), zapytania przez przykład (QBE - Query by Example), filtrowanie wyników, potraktowanie plików XML jako źródeł danych, podobnie jak bazy danych czy mnogość zdarzeń, których można nasłuchiwać, sprawia, że postrzeganie przeze mnie Hibernate stało się całkowicie odmienne i to na jego korzyść. Wszystko za sprawą lektury książki. Niestety wszystkie te cudeńka pojawiły się dopiero pod koniec książki, a nawet nie w swoim dedykowanym rozdziale, tylko w dodatku, więc i pewien niesmak pozostał. Ciekawość została rozpalona, a książka już się skończyła i czekam na kolejne.

To jest doskonały moment, aby napisać o potencjalnych odbiorcach książki. Z pewnością nie jest to książka dedykowana dla zaawansowanych graczy Hibernate, chociaż systematyczne wprowadzanie materiału może przyczynić się do ułożenia wiedzy i poukładania jej w logiczną całość. Mogę również stwierdzić, że książka nie jest dedykowana stricte dla nowicjuszy. Jest tam wiele materiału wprowadzającego, jednakże przeplatanego dużą dawką "ciężkiej" teorii, nie zawsze przystępnie wytłumaczonej (a nawet przetłumaczonej), więc wielu nowicjuszy może pozostać w stanie osłupienia, czy to możliwościami Hibernate, czy skomplikowanym przedstawieniem tematu, jeszcze na długo po przeczytaniu książki. Zatem dla kogo jest dedykowana ta książka? Sądzę, że dla wszystkich, zgodnie z tytułem książki. Ot, taki paradoks. Pewne rozdziały książki są dla początkujących (rozdziały 1-9), a pozostałe (rozdziały 10-11 oraz dodatek A) dla graczy bardziej zaawansowanych, mających pewne doświadczenie z Hibernate oraz innymi rozwiązaniami ORM. Dodatki B-D można śmiało ominąć bez większej straty poznawczej tematu, bo mam wrażenie, że lekko się zdeaktualizowały. Oczywiście rozdziały dla nowicjuszy są przeplatane wiedzą z "górnej półki", co sprawia, że czasami długo zastanawiałem się, co autor miał na myśli oczekując przedstawienia tematu w sposób dla początkujących, a tu nieoczekiwanie wyjaśnienie wymagające całkowicie innego rozumowania, bardziej zaawansowanego (np. sekcja Strategia nazewnicza w rozdziale 2 "Integracja i konfiguracja Hibernate'a"). Rozdziały dla zaawansowanych są faktycznie na najwyższym poziomie merytorycznym i tam już nudzić się nie można. Z najwyższą rezerwą podchodziłem do rozdziału 6 "Odwzorowania z adnotacjami", gdzie prezentowano Hibernate jako dostawcę JPA. Wydaje mi się, że gdyby ta książka powstawała dzisiaj, Hibernate przedstawiany byłby jako ten dostawca JPA, który wpłynął na ostateczną postać specyfikacji JPA i rozpisywanoby się o wielu tych możliwościach Hibernate, które nie znalazły się w JPA, a powinny. Na czas pisania książki (rok 2006) autorzy potraktowali JPA jako pewien element funkcjonalny Hibernate bez większego entuzjazmu i szczególnego zagłębiania się w temat, co może być potraktowane jako plus (w końcu była to książka o Hibernate, a nie JPA) lub minus (traktując JPA jako specyfikację Java EE 5, a Hibernate jako produkt realizujący ją, więc tym samym warto byłoby podkreślać znaczenie realizacji specyfikacji JPA w wykonaniu Hibernate z dostarczeniem nowych funkcjonalności).

Nie mógłbym również nie ocenić tłumaczenia oraz samej jakości książki w ogólności (okładka, kartki, itp.). Tutaj niewiele można zarzucić. Tłumaczenie jest bardzo profesjonalne, choć do tej pory nie mogę uznać odmiany słowa Hibernate przez wszystkie możliwe przypadki, więc było o Hibernate, ale również Hibernate'em, Hibernate'owi i Hibernate'a. Wiele innych tłumaczeń zostało dobranych starannie i nieskromnie napiszę, że wiele z nich było zgodnych z moimi. Później zastanawiałem się, czy przypadkiem nie było tak, że wiele z owym "moich" tłumaczeń, zostało właśnie zapożyczonych z tej książki. Jakość książki pod względem okładki, kartek, klejenia i w ogóle formatu jest doskonała. Książka nie rozkleja się przy czytaniu, okładka pozostaje w dobrym stanie przy czytaniu, więc jest zgodnie z moimi oczekiwaniami. Ostatnio zrobiłem się fanem czytania w różnych miejscach, więc zabieranie książki ze sobą nie jest dla mnie czymś nadzwyczajnym i warto, aby wydawca rozważył format kieszonkowy, który można zmieścić wszędzie, a najlepiej w boczną kieszeń "bojówek". Może wydanie książek w dwu formatach - typowym oraz kieszonkowym - byłoby ciekawym sposobem na dotarcie do szerszego grona czytelników?

A teraz więcej o merytorycznej stronie książki.

Rozdział 1: Hibernate 3. Wprowadzenie jest dobrym wstępem do Hibernate 3.2, chociaż trochę mało przekonujący, jeśli czyta go osoba wkraczająca w świat ORM, podczas gdy dla praktyka może być zbyt pobieżna. Miałem wrażenie, że początki rozdziałów dla autorów książki były traktowane w stylu "skoro trzeba coś napisać jako rozpoczęcie, to napiszmy cokolwiek, aby tylko rozpocząć". Wspominałem już o użyciu wszystkich odmian słowa Hibernate, więc należy się na to przygotować już od samego początku, właśnie od tego rozdziału. Co mnie zraziło w nim to użycie słowa framework bezpośrednio, bez tłumaczenia, podczas gdy można byłoby użyć chociażby (wciąż zdumiewająco mało popularny) szkielet aplikacyjny.

W Rozdziale 3: Tworzenie prostej aplikacji użyto narzędzia Apache Ant, co wydaje się być trochę archaiczne w porównaniu z uproszczeniami dostarczanymi przez Apache Maven, bądź Apache Ivy, które znacznie sprawniej automatyzują wiele z manualnie wykonywanych czynności w Ancie, a przede wszystkim niwelują konieczność samodzielnego pobierania zależności projektowych, sprowadzając tę czynność do deklaratywnego ich określania. Jest to według mnie znaczące utrudnienie dla osób niezaznajomionych z Antem, którzy zakupili książkę w celu poznania Hibernate. Zresztą, na potwierdzenie moich słów, przytoczę, że listingi 3.1 i 3.2 są bodajże najdłuższymi w całej książce, a nie dotyczą bezpośrednio Hibernate (!) Na zakończenie rozdziału pojawiły się przykłady, których oczekiwałbym znacznie wcześniej. Niestety książka przedstawia Hibernate z użyciem Java SE 1.4, co wpływa na "ogołocenie" typów, które w Java SE 5 są typami sparametryzowanymi, np. Set w listingu 3.9. A skoro już przy nim jesteśmy, to zastanawiająca jest sensowność przypisywania egzemplarza typu HashSet w konstruktorze klasy Category (public Category(String title)), kiedy pole adverts już ma tę wartość przypisaną podczas inicjalizacji klasy (private Set adverts = new HashSet()). Trzeba przyznać, że odzwyczaiłem się od stosowania plików XML do wyrażania moich wymagań konfiguracyjnych i ich studiowanie było dla mnie nie lada wyzwaniem. Czasy adnotacji zmniejszyły ilość informacji zapisywanych w plikach XML, sprowadzając je do roli elementu pomocniczego, raczej rzadko stosowanego. Stąd lektura listingów 3.11 i dalszych sprawiła mi nie lada problem w ich przyswojeniu, a ich utworzenie scedowałbym na narzędzia wspomagające, np. Hibernate Tools, czy użyłbym wręcz adnotacji (o których będzie mowa w kolejnym rozdziale). Dodatkowo, w przypadku stosowania plików XML wyłania się na plan pierwszy konieczność znajomości mechanizmu kluczy obcych i ich konfiguracji, co dla początkujących (a ten rozdział im głównie był poświęcony) może stanowić znaczące wyzwanie. Zresztą zdania typu I tym razem może wydawać się to skomplikowane... (str. 46) lub Ta część rozdziału może wydawać się zawiła... (str. 48) tylko to potwierdzają. Skorzystanie z klasy ThreadLocal w klasie sample.dao.DAO w listingu 3.15 wymaga większego niż podstawowy poziom posługiwania się językiem Java, a w dodatku nie umieszczono żadnego, nawet zdawkowego, wyjaśnienia jego znaczenia. A szkoda. Listing 3.17 korzysta z transakcji do odczytania danych z bazy danych. Czy konieczne jest użycie transakcji podczas odczytu?! Nie sądzę, a powoduje dodatkowe i niepotrzebne skomplikowanie kodu źródłowego podczas przedstawiania Hibernate. Zastanawiająca jest implementacja metody public Category create(String title) throws AdException, gdzie zwraca się null (return null) po utworzeniu encji Category. Podobna implementacja metody create(), tyle, że dla encji Advert, już nie dostarcza tego typu ciekawostek (patrz strony 58-59). Zdaje mi się, że jest to błąd (oryginału, czy tłumaczenia?). Ciągłe odnoszenie się do Anta jako narzędzia uruchamiającego przykład I tym razem czerpiemy szczegóły z wiersza poleceń skryptu Anta bądź szczegóły dotyczące reklam podaje zadanie narzędzia Ant (oba na stronie 61) nie upraszczają zrozumienia tematu przewodniego - Hibernate. Wydaje się, że lektura rozdziału 3 może sprawić, że dbano w nim o szczegóły niekoniecznie związane bezpośrednio z Hibernate. Rozdział 4: Cyklu życia trałych obiektów rozpoczyna się dosyć "sztywno". Jest to przede wszystkim "zaleta" bezpośredniego tłumaczenia tekstu z j.angielskiego na polski. Moją szczególną uwagę zwróciło zdanie rozpoczynające się od Ze względu na Hibernate'a..., gdzie wyróżnia się dwa typy obiektów: rozpoznawane przez Hibernate oraz nie. I właśnie takie przedstawienie faktów nie spodobało mi się jako rozpoczęcie rozdziału. Zastanawiam się wciąż, czy jest to duch oryginalnej wersji książki, czy tłumaczenia, gdzie przedstawienie metody EntityManager.refresh() w sekcji Odświeżanie encji zostało przedstawione jako...odświeżanie encji. Wprawdzie napisano mechanizm odświeżania obiektów z reprezentacji bazy danych, to jednak nie napisano, co dokładnie odświeżanie oznacza, np. wczytanie danych z bazy danych do encji. W końcu książka pretendowała do miana przewodnika, również i dla nowicjuszy. W osłupienie wprawiło mnie całkowicie niespodziewane przytoczenie metody call() jako mniej efektywnego sposobu na usuwanie encji z bazy danych na stronie 77. Sądzę, że powinno być delete(). Ogólnie ocena treści w rozdziale 4 jest wysoka, ze względu na dużo wartościowej treści, ale zdecydowanie za "sztywno", co może spowodować, że nowicjuszom może sprawić nie lada wyzwanie intelektualne.

Rozdział 5: Wprowadzenie do odwzorowań przedstawia w/g mnie najtrudniejszy tematem w całej specyfikacji JPA oraz ogólnie w reprezentacji danych w relacyjnej bazie danych. Stąd nie ukrywam, że nie mogłem doczekać się, aby zapoznać się z jego treścią. Moje oczekiwania nie zostały spełnione, gdyż temat został przedstawiony w sposób słabo dla mnie przyswajalny. Wciąż czuję pewien niedosyt wiedzy na ten temat. Sądzę, że czytanie specyfikacji byłoby znacznie przyjemniejsze i efekt ostateczny byłby dużo lepszy. Na zakończenie rozdziału przedstawiono kilka spostrzeżeń nt odwzorowań (np. Korzystanie z właściwości opartych na formule SQL), które nie są poparte żadnymi przykładami, co sprawia, że nie mają wielkiej siły sprawczej, gdyż mogą być po prostu niezrozumiane.

Rozdział 6: Odwzorowania z adnotacjami rozpoczyna się ponownie mało zachęcająco. Co rozdział to miałem wrażenie, że autorzy nie potrafią rozpocząć tematu, mając jednak świadomość, że wstęp do rozdziału jest konieczny, wręcz obowiązkowy, więc był, ale czy zgodnie z oczekiwaniami? Jak wspomniałem już wcześniej, książka została wydana w roku 2006, więc część informacji w niej zawarta zdeaktualizowała się, przez co opis Funkcje Javy 5 może sprowokować do uśmiechy na twarzy (co wszystkim się zdecydowanie przyda). Niestety rozdział nie ustrzegł się przed poważniejszymi błędami merytorycznymi, gdzie w sekcji Dokonywanie wyboru napisano, że zgodnie z EJB 3, musimy użyć adnotacji do reprezentowania informacji o odwzorowaniach. (z podkreśleniem na słowo musimy). Nie jest to oczywiście prawdą, gdyż dla niezainteresowanych adnotacjami mamy do dyspozycji deskryptory odzworowania (dla encji), czy deskryptor ejb-jar.xml (dla pozostałych typów ziaren EJB). Podczas przedstawiania różnych rodzajów odwzorowywania struktury dziedziczenia encji na strukturę relacyjną w bazie danych nie poparto ich sekcją wady i zalety, gdzie możnaby napisać o wpływie różnych sposobów odwzorowania ze względu na kolumny NOT NULL. Nie mógłbym jednak nie wspomnieć, że to właśnie ta książka sprawiła, że uzmysłowiłem sobie możliwość przypisywania adnotacji do całych pakietów za pomocą mechanizmu package-info.java. To była jedna z tych informacji, dla których oceniam książkę bardzo wysoko, właśnie za zwrócenie mojej uwagi na taki mały szczegół języka Java i specyfikacji JPA. Jest to ten moment, w którym po wielu trudach człowiek zdaje sobie sprawę, że warto było poświęcić swój czas na przeczytanie książki. Kolejnym wartościowym elementem było przedstawienie adnotacji @Where. Jeszcze nie tak dawno ktoś pytał o to na grupie pl.comp.lang.java i dopiero po lekturze książki dowiedziałem się do czego ona służy i...zaczęło mi jej od razu brakować w specyfikacji JPA (!)

Rozdział 7: Tworzenie odzworowań Hibernate w plikach XML zawiera częściowe powtórzenie informacji z rozdziału 6, gdzie powtórnie opisano Odwzorowania relacji dziedziczenia. Może to i dobrze, bo tym razem autorom udało się przedstawić temat w bardziej przystępny sposób.

Rozdział 11: Filtrowanie wyników wyszukiwania był kolejnym argumentem potwierdzającym słuszność decyzji o przeczytanu książki. Jeśli do tej pory sądziłem, że Hibernate to kolejny projekt realizujący podejście ORM to teraz mam świadomość, dlaczego jest to narzędzie na miarę naszych potrzeb, wykraczających poza ramy specyfikacji JPA. Zapowiada się wprowadzenie pozostałych elementów Hibernate do specyfikacji JPA 2.0, więc już niedługo takie funkcjonalności jak filtrowanie wyników wyszukiwania nie będą wyłącznie domeną Hibernate, ale i pozostałych dostawców JPA. Już nie mogę się doczekać.

Podsumowując, bez żadnych oporów mogę śmiało napisać, że książka warta była poświęconego jej czasu. Zdarzyło mi się już kilkakrotnie do niej zaglądać w poszukiwaniu informacji, więc spełnia się nadal. I treść książki, jak i jej polskie tłumaczenie sprawiają, że książka należy do obowiązkowych lektur każdego programisty Java. Polecam!

Literówki, użycie żargonu, itp.

W tej sekcji zawarłem moje uwagi odnośnie stylu i tłumaczeń, które w moim przekonaniu powinny być poprawione w kolejnych wydaniach książki, bądź należałoby zwrócić na nie uwagę przy tłumaczeniach innych książek.

Rozdział 2

  • "Będziemy następnie musieli osadzić pozostałe wymagane biblioteki", gdzie "osadzić" traktowane jest jako "dołączyć" - str. 13
  • "Hibernate może logować statystyki", gdzie logować staje się rejestrowaniem, czy odnotowywaniem - str. 14
  • Literówka w słowie "połączniu" - str. 18
  • "nie musimy używać hibernate.prefix do konfigurowania właściwości" - prefix występuje jako substytut properties? - str 21
  • "elementu ładującego klasy Javy" jako ładowarka klas albo mechanizm ładowania klas? - str. 22
  • "addXML(String): wybiera obiekt String" i podobnie "addCacheableFile(String): ...wybiera ścieżkę do pliku" - wybiera jako akceptuje czy pobiera? - str. 22
  • "które odwzorowują do metod" możnaby zastąpić "których wartości obsługiwane są przez metody" str. 23
  • Akapit rozpoczynający się od "Chociaż możemy wprost określić..." powinien zostać jeszcze raz przemyślany - str. 23
  • "po prostu zwraca nieuprawnioną nazwę klasy Javy" - nieuprawnioną jako niekwalifikowaną bądź krótką - str. 24
  • "będzie AccessGroup" powinno być "będzie AccessGroups" - str. 24
  • "entity persisters" przetłumaczone jako "utrwalaczy sesji", co obecnie w erze JPA tłumaczone mogłoby być jako "zarządcy trwałości" - str. 25

Rozdział 3

  • "narzędzie kompilacji Ant" powinno być "narzędzie budowania Ant" - str. 29
  • "Umożliwianie logowania" - w żargonie stanowi to dwuznaczny tytuł - uwierzytelnianie bądź rejestrowanie/zapisywanie/śledzenie zdarzeń. W tym przypadku tytuł sekcji możnaby zastąpić "Włączanie komunikatów" - str. 35
  • Błąd w nazwie parametru konfiguracyjnego "hibernate.connection.pool" - powinno być "hibernate.connection.pool_size" - str. 36
  • "Klasa Message obiektów POJO" - co to znaczy?! - str. 38
  • Na rysunku 3.2 umieszczono kolumnę message do tabeli łączącej "Link_Category_Advert" podczas, gdy nie powinna ona tam być zgodnie z listingiem 3.14.
  • "nie został jeszcze załadowany (w wyniku opóźnionego wczytywania)" - załadowany powinno zostać zastąpione słowem wczytany (jako to zrobiono w nawiasach) - str. 51
  • Użycie słowa "kwerenda" (rozdział 3) podczas, gdy w późniejszych rozdziałach stosuje się "zapytanie" (rozdziały 9 i 10). Zresztą "zapytanie" użyte jest również później w rozdziale 3 - str. 54
  • "do uzyskiwania encji User" - uzyskiwania należałoby zastąpić pobraniem jak wcześniej na stronie - str. 54
  • "jeśli nasze zapytanie zidentyfikuje więcej niż jeden obiekt" - zidentyfikuje powinno być zwróciłoby - str. 54
  • "przykładu podający wszystko razem" - podający należałoby zastąpić prezentujący - str. 60
  • Użycie słowa "serwletu" zamiast "servletu" (podobnie jak ze słowem volvo) - str. 62
  • "komponenty sesji EJB" zamiast poprawnego tłumaczenia "ziarna sesyjne EJB" bądź ostatecznie "komponenty sesyjne EJB" - str. 62
  • "logujący interfejs API" - ??? - str. 64
  • "które jest przeprowadzone z zadania typu java task narzędzia Ant" - mogłoby być zastąpione "przez wykonanie zadania java narzędzia Ant" - str. 64

Rozdział 4

  • "ani nie utrwala w nich zmian" powinno być "ani nie utrwala ich zmian" - str. 65
  • Jeśli decydujemy się na tłumaczenie "web services" to zgódźmy się na "usługi sieciowe" zamiast "aplikacja sieciowa", która mogłaby wskazywać na "aplikację internetową" (ang. web application) - str. 74
  • "Metoda getFlushmode()" powinno być "Metoda getFlushMode" - str. 75
  • "Zapytywanie obiektów" powinno być "Wyszukiwanie obiektów" - str. 80

Rozdział 5

  • Tytuł sekcji "Opóźnione wczytywanie", podczas gdy używa się również słowa "ładowanie" - brak konsekwencji - str. 86
  • Literówka w słowie "dozwala" powinno być "pozwala" - str. 93

Rozdział 6

  • "Java 5 została wprowadzona pod koniec 2004 roku" powinno być "Java 5 została opublikowana pod koniec 2004 roku", bądź "wydana" - str 95
  • "Generyczność" powinno być "Typy sparametryzowane" bądź "Typy generyczne"
  • Nadmiarowy odstęp w nazwie adnotacji "@Generated Value" - powinno być "@GeneratedValue" - str. 136

Rozdział 7

  • Termin "user type" został przetłumaczony niepoprawnie na "Klasa typu użytkownika", podczas gdy jest to "Klasa typu zdefiniowanego przez użytkownika" - str. 147

Rozdział 9

  • "posiada metodę o nazwie Query()" powinno być "posiada metodę o nazwie createQuery()" - str. 210
  • "Logowanie używanego wyrażenia SQL" powinno być "Odnotowywanie używanego wyrażenia SQL" bądź "Monitorowanie używanego wyrażenia SQL" - str 214
  • "ogólnie dostępnej bazy danych HSQLDB" powinno być "otwartej bazy danych HSQL" i już bez angielskiego terminu (zresztą jest on niepoprzedzony skrótem ang.)
  • Podkreślnik w "z klasy org.hibernate._Hibernate" niepotrzebny - str. 226
  • "w logu" powinno być "w dzienniku zdarzeń" - str. 226

Dodatek A

  • META-INF/configuration.xml powinno być (chyba) META-INF/persistence.xml - str. 250
  • Niezgodność między rysunkiem A.1 a listingiem A.13 - p_id powinno być product_id bądź na odwrót - str. 260-261
Osobiste