wtorek, 31 maja 2011

Przemyślane praktyki Java EE

Dziś krótka recenzja książki Adama Biena Real World Java EE Patterns - Rethinking Best Practices.

Zacznę od konkluzji: czy warto? Tak. To jak bardzo warto zależy od Twojego dotychczasowego backroundu, ale gwarantuję, że nawet eksperci Javy EE znajdą dla siebie kilka ciekawych kawałków. Pozycja konkretna, na temat, z przykładami wykorzystującymi ciekawe kruczki z np. EJB 3.1.

Na początku obawiałem się, że przemyślenia dotyczą trywialnych CRUDów - na crudach opiera się ostatnio cała współczesna literatura programistyczna jak i blogi. Nie dziwota, gdyż jest to bardzo wdzięczna materia - można na nich pokazać jak prosta i łatwa jest technologia X, a później radźcie sobie sami.

Autor w części rozdziałów wychodzi od crudów jednak za chwilę porusza bardziej zaawansowane tematy, racjonalnie argumentując kiedy opłacalne jest wprowadzenie bardziej złożonych mechanizmów platformy.

Dla kogo przeznaczona jest książka?
Przede wszystkim dla weteranów J2EE, którzy przesiadając się na Java EE powinni zapomnieć stare nawyki.
Dla osób zaczynających od EE 5 lub przechodzących z innych technologii (Spring) odniesienia do "starych" praktyk będą jedynie ciekawostką archeologiczną.

Ale tak jak pisałem, znajdziemy w niej kilka ciekawych kruczków, sporo gotowych rozwiązań oraz dużo gotowego kodu. Kruczki i best practices związane z transakcjami, kod użytecznych interceptorów, które łatają braki w specyfikacji;) oraz nieco praktyk odnośnie dobrego designu. Część praktyk odnośnie designu jest dyskusyjna, jednak autor wyjaśnia w dalszej części, że aplikują się w pewnych kontekstach, natomiast gdy wymaga tego problem, wówczas zaczynamy sięgać po inne rozwiązania. Przykładowo obiekty transferowe są dobre tylko wtedy gdy są dobre:) - z czym nie sposób się nie zgodzić. DAO jest usprawiedliwione tylko gdy wnosi wartość - tak ale dyskutować można nad tym co jest wartością.

Mimo dyskusyjności niektórych pomysłów trzeba docenić inicjatywę, ponieważ generalnie brakuje na rynku pozycji wychodzących poza przysłowiowy Hello World...


Na uwagę zasługuje fakt, że autor otwarcie mówi o proceduralnym stylu promowanym przez platformę.
Mówi też otwarcie o innych sposobach skalowania - bez rozpraszania obiektów pomiędzy warstwami...
nota bene zgodnie z zasadą Fowlera odnośnie rozpraszania: "Just don't":)



Nie byłbym sobą gdybym nie znalazł jakiś błędów koncepcyjnych...
Wiem, że w każdej książce technicznej (w sensie opisującej jakąś technologię) projektowanie Object Oriented jest potraktowane po macoszemu ale skoro już polecam książkę to zwrócę uwagę na 2 przykłady:

Rozdział "Persistent Domain Object (Business Object)"
Po wstępie o tym dlaczego opłaca się stosować model OO (rich model) zamiast proceduralnego (anemic model) mamy taki oto przykład:

Klasa OrderItem, która między innymi potrafi policzyć swój koszt metodą getShippingCost (jest to metoda biznesowa a nie geter)

Dalej dziedzicząca po niej klasa BulkyItem, która liczy koszt nieco inaczej - nadpisuje metodę getShippingCost a w niej woła super wersję tej metody!

@Override
public int getShippingCost() {
return super.getShippingCost() + 5;
}



Nie róbcie tego w domu ani w pracy!:)
1. OrderItem ma wiele odpowiedzialności, więc wprowadzanie nowej klasy i dziedziczenia tylko dlatego, że zmieniła się jedna z odpowiedzialności jest błędem projektowania obiektowego. Taki sposób rozumowania szybko doprowadzi do ekspolozji kombinatorycznej, gdzie każda zmiana logiki (oraz kombinacje tych zmian) zamieszczana jest w swojej klasie dziedziczącej. Strategia jest jednym rozwiązań. A jeżeli nie chcemy wprowadzać strategii, to już na prawdę lepszy będzie serwis liczący koszt na podstawie getterów z OrderItem. Dobry kod proceduralny jest zawsze lepszy od słabego kodu obiektowego!

2. Wołanie super wersji metody z nadklasy jest tak zwany smrodkiem (code smell). Skoro nadpisuję metodę to jest już nieważna. Generalnie wskazuje to na słaby design.



Kolejna rzecz na jaką należy uważać to rozdział poświęcony "konfliktowi" pomiędzy Domain Driven Design a SOA.

Niestety muszę powiedzieć, że konflikt ten jest pozorny i wynika z niezrozumienia architektury aplikacji dla systemów, w których stosujemy DDD.
Autor we wcześniejszych rozdziałach promował swój pomysł pod tytułem Gateway i ten styl przeniósł na implementację DDD.
Nigdy nie "publikujemy" Modelu Domeny jako "API". Wiąże się z wieloma przykrymi konsekwencjami, ale tutaj odsyłam do Evansa. Model domenowy przykrywamy właśnie procedurami w stylu SOA - po prostu podstawowy pattern DDD: warstwa Serwisów Aplikacyjnych. I po problemie:)
Było to powiedziane już 5 lat temu: DDD the opposite of SOA? Uh, no.

//========================================

Polecam rozdział pod tytułem "Retired Patterns" przypomina nam jak smutne i przykre bywało drzewiej programowanie w EE:)

2 komentarze:

Jarek Żeliński pisze...

Hm... na ile tam o kodzie a na ile o projektowaniu? ;), osobiście w ogóle unikam dziedziczenia w Modelu (dla DDD i nie tylko). Uzasadnienie dziedziczenia w warstwie Model jest moim zdaniem raczej trudne (tu raczej odpuszczamy wielokrotne używanie kodu bo nie ma modeli referencyjnych - analiza firmy metoda copy-paste jest zła), żadne "cudo" w naturze nie dziedziczy zachowania, obiekty dziedzinowe są z natury indywiduami :)

Sławek Sobótka pisze...

Problem właśnie w tym, że jeżeli jedyna wiedza o projektowaniu z jaką stykają się developerzy pochodzi z książek technologicznych, to trzeba dbać o jakość tej wiedzy...

A co do dziedziczenia to zgadam się. Na poziomie implementacji - owszem, czasem gdy mamy dobrze interfejs (1 odpowiedzialność) to po drodze wyciągamy klasę abstrakcyjną, po której dziedziczą konkretne - np szablon dla Strategii właśnie.

Ale Polityka to w DDD specyficzny Bulding Block. W pozostałych klockach modelu ciężko uświadczyć sensownego dziedziczenia.