Pokazywanie postów oznaczonych etykietą UP-DDD in Action. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą UP-DDD in Action. Pokaż wszystkie posty

niedziela, 14 grudnia 2008

UP-DDD in Action: Hermetyczne agregaty



Drogie dzieci - w dzisiejszym odcinku z serii UP-DDD in Action zobaczycie jak nasz bohater Bob Budowniczy rozprawia się z brakiem hermetyzacji i proceduralną ignorancją.



Kontynuując temat enkapsulacji rozpoczęty w poprzednim poście zobaczmy jak wygląda on w kontekście Domain Driven Design.

DDD opiera się na starych i sprawdzonych technikach obiektowych więc proceduralne łańcuszki typu "train wreck" zbesztane w poprzednim poście nie mają prawa pojawić się w kodzie aspirującym do miana DDD.

Analizując specyfikacje building blocks z DDD widać, że Encje, VO i Agregaty posiadające odpowiedzialność biznesową (nie będące standardowym anemicznym modelem) są w zgodzie z paradygmatem Abstrakcji.

Dodatkowe założenie odnośnie Agregatów jest takie, że hermetyzują one swą strukturę. Oznacza to, że nie powinny zdradzać szczegółów swych składowych. Agregat posiada root (główną encję), która publikuje niejako zestaw odpowiedzialności/zdolności w celu ochrony wnętrzności przed światem zewnętrznym. Jeżeli świat zewnętrzny nie wie nic o wnętrznościach agregatu, to wówczas implementacja agregatu może z czasem się zmieniać (aby nadążać za nowymi wymaganiami). Dzięki temu zmiany są lokalne i nie mają wpływu na świat zewnętrzny.

Weźmy na ten przykład arcy interesujący model zamówienia;) Niech zamówienie posiada datę, miejsce dostawy oraz listę zamówionych produktów. Zamówienie będące agregatem nie może na przykład udostępniać gettera do listy produktów ponieważ istnieje możliwość modyfikacji tejże listy "poza świadomością" samego zamówienia.
Zakładając iż tworzymy obiektowy model biznesu i jego reguł to chcielibyśmy aby każda operacja na produktach była wykonywana poprzez samo zamówienie, które jest swego rodzaju mózgiem biznesowym.

Obiekt zamówienia posiadając wiedzę o swych wnętrznościach może na ten przykład domówić dodanie do niego pewnego produktu jeżeli miejsce dostawy zawiera się w pewnej strefie, klient nie jest pełnoletni, albo data realizacji wykracza poza jakąś tam granicę pewnej akcji marketingowej.

W tym akurat przykładzie jakimś rozwiązaniem byłoby upublicznienie iteratora po iście zamówień. Ale załóżmy przypadek bardziej ogólny - nie chcemy zdradzać żadnych szczegółów i kropka.

No dobra, wystarczy tego teoretycznego bełkotu! W praktyce niestety często istnieje konieczność dobrania się do wnętrzności obiektu. Na przykład po to aby wyeksportować zamówienie do PDF lub XML. Że o takim szczególe jak jego wyświetlenie na GUI nie wspomnę;P

Podchodząc do zamówienia jak do struktury danych potrzebowalibyśmy procedur, które odpowiadają za przejrzenie wnętrzności zamówienia i stworzenie odpowiednio PDFa lub XMLa prezentującego dane o zamówieniu i jego wewnętrznej strukturze (GUI to problem osobny - wręcz filozoficzny, więc o nim osobny akapit później).

Na szczęście istnieje wzorzec projektowy Budowniczego. Idea wzorca jest prosta jak nie przymierzając budowa cepa. Zakłada ona istnienie dyrektora budowy i robotnika (budowniczego). Dyrektor wie CO trzeba zrobić a robotnik wie JAK to zrobić.



Na powyższym przykładzie klasa Order jest dyrektorem budowy. Gdy ktoś poprosi dyrektora o wyeksportowanie zamówienie wówczas on wydaje rozkazy delegując pracę do budowniczego. Dyrektor (zamówienie) wie skąd pobrać dane do eksportu - z własnych prywatnych wnętrzności. Natomiast robotnik (budowniczy) jest abstrakcją w najczystszej formie - interfejsem. Konkretny budowniczy wie jak zająć się surowcami przekazywanymi mu przez dyrektora budowy. Na przykład budowniczy PDFów zna doskonale jakiś silnik do generowania dokumentów. Budowniczy XMLi zna format w jakim należy zbudować plik tekstowy. Budowniczy DTO wie jak należy skonstruować obiekt transferowy.

Mamy tutaj doskonałe rozdzielenie odpowiedzialności: hermetycznych struktur biznesowych i wiedzy o ich semantyce od technicznych aspektów formatów danych eksportowych.

Powyższy przykład można rozszerzyć o mały aspekt optymalizacyjny. Bo co jeżeli dany budowniczy nie jest z jakiegoś powodu zainteresowany na przykład listą zamówień? Najprościej byłoby aby jego implementacja metody buildNextProduct() po prostu ignorowała przekazywane produkty. Niestety mamy wówczas niepotrzebną iterację. Zamiast tego możemy rozszerzyć interfejs budowniczego o metodę isProductListNeeded(). Iterujemy po liście jedynie wówczas gdy metoda zwróci wartość true.



Wspomniałem wcześniej o aspekcie GUI. Popularne frameworki zasadzają się na refleksji i wymagają by istniały gettery do składowych obiektu, które chcemy wyświetlić. Heh jednym ze sposobów na wyświetlenie zamówienie w JSF mogłoby być stworzenie takiej implementacji budowniczego, która tworzy jakiś UIComponent który to następnie dodajemy do widoku - niestety jak dla mnie jest to nakładanie gaci przez głowę.

Jakimś rozwiązaniem jest zastosowanie Data Transfer Objects. Czyli nasz agregat biznesowy może eksportować się do DTO, które to DTO jest bindowane z widokiem. DTO ma już gettery i settery więc doskonale pasuje do frameworków.

Rozwiązanie to ma oczywiście plusy dodatnie i ujemne.

Przede wszystkim dzięki przepakowaniu obiektów biznesowych do głupich DTO nie udostępniamy w warstwie UI metod biznesowych (pamiętajmy, że Agregaty je posiadają). Serwisy aplikacyjne posługujące się DTO nadają się wówczas do bycia Web Serwisami - nie chcemy przecież upubliczniać naszego modelu biznesowego oraz jego metod (odpowiedzialności). DTO mogą zawierać jedynie istotne z punktu widzenia usługi dane, prezentować je w spłaszczony (prostszy) sposób oraz stanowić warstwę interfejsu do systemu pod którą możemy swobodnie zmieniać nasz model bez obawy o ciągłe modyfikacje klientów.

W małych projektach zmniejsza to oczywiście w znaczny sposób produktywność (rapid developnent hehehe). Zamiast spokojnie stukać sobie przeglądarkę do bazy musimy nakładać gacie przez głowę i przepakowywać dane bawiąc się samemu ze sobą w kotka i myszkę:/


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

Swoją drogą to dziwne, że frameworki nie wspierają dobrych modeli programowania a skupiają się jedynie na przykryciu technikaliów takich jak na przykład HTTP, transakcje, rozproszenie obiektów, bindowanie danych warstwą abstrakcji...

Nawet frameowrki, które nazywają się dumnie frameworkami aplikacji nie wspierają żadnego modelu aplikacji a hermetyzują jedynie niskopoziomowe aspekty techniczne.

W którymś z następnych odcinków zobaczymy jak wygląda to w http://www.qi4j.org/

wtorek, 18 listopada 2008

UP-DDD in Action: Planowanie jest nieodzowne, Sir!

Prezydent Dwight Eisenhower tak oto wspominał czasy gdy był generałem armii amerykańskiej:
"In preparing for battle I have always found that plans are useless, but planning is indispensable."

Dziś kolejny post z serii Unified Process & Domain Driven Design in Action. Prace nad projektem wciąż w fazie analizy biznesowej więc post będzie raczej wypełniaczem (podtrzymującym serię) o charakterze "filozoficznym".

Jaką rolę w projekcie spełnia UML (dokumentacja w ogólności)? Są różne podejścia...

Może na przykład nie mieć żadnej roli. Organizacja może radośnie postępować według metodyki chałupniczo-garażowej. Metodyka ta zakłada 3-etapowy proces:

radosna twórczość - po podpisaniu kontraktu następuje pięciominutowa odprawa sześciopaku programistów po czym rzucają się oni na klawiaturę (jak nie przymierzając marynarz atomowego okrętu podwodnego na kozę w porcie) i klepanie na wyścigi. Nikt nie wiec po co, na co i jak, ale to nie szkodzi... byle się wyżyć.

kosy racławickie - wiadomo... burdel rośnie, projekt się sypie, co raz jakaś eskalacja. Najlepszym rozwiązaniem jest pospolite ruszenie: nadgodziny + "ochotnicy" do pomocy. Jak wiemy z doświadczenia jest to oczywisty antywzorzec zarządzania ponieważ nowi ludzie jedynie spowalniają pracę, ale kto by się nad tym zastanawiał - przecież każdy brakujący diagram UML można zastąpić skończoną liczbą studentów...

stawanie na kancie tego no... nosa! - tydzień do release. Ludzie funkcjonują w trybie zombie. Każdy brakujący diagram UML można zastąpić skończoną ilością sznurka do snopowiązałki...

Jeżeli opisana metodyka chałupniczo-garażowa sprawdza się wyśmienicie - na co wskazuje na przykład sam fakt istnienia organizacji (że o systematycznym zwiększaniu zysków nie wspomnę) to oczywiście jak najbardziej jest słuszna i nie powinno się jej zmienić bo jeszcze kruchy stan równowagi się posypie. Biznes to biznes - doskonale to rozumiem.

Na drodze logicznego rozumowania można z czasem uświadomić sobie, że jednak wydanie paru groszy na dokumentację zwróci się wielokrotnie w przyszłości. Metodyka chałupniczo-garażowa owszem przynosi świetne dochody, ale okazuje się, że mogłaby przynosić jeszcze większe gdyby nie tracić czasu na zmaganie się z burdelem i po prostu udokumentować wszystko. Pycha pomysł!

I tu pojawia się kolejna możliwa rola dokumentacji: kula u nogi. Po radosnym zaimplementowaniu trzeba jeszcze zrobić te cholerne rysuneczki i posiedzieć nad wordem. A tu nad głową stoi poganiacz i zadaje najgłupsze pytanie jakie istnieje: "na kiedy będzie gotowy następny moduł?". Na szczęście wspaniałe narzędzia mają funkcję wstecznej inżynierii - dwa kliki i zestaw pięknych prostokątów gotowy. Teraz jeszcze tylko wkleić to jakoś do worda, dokleić jakiś schemat bazy i z dyni. Hmmm nie tak szybko... za mało tej dokumentacji... ale wystarczy wkleić jeszcze trochę kodu źródłowego i bedzie. No dobra, nie odwalajmy chały - tylko same nagłówki klas i metod. Jak wciąż mało to można dokleić trochę reguł biznesowych z jakiś roolsów. Ktoś kazał robić dokumentację to się zrobi - "będzie Pan zadowolony"

Istnieją różne dewiacje w tym podejściu. Można na przykład analizą nazwać projekty ekranów - co prowadzi do ciekawej paranoi. Innym skrzywieniem jest traktowanie schematu bazy danych jako projektu systemu - również ciekawa paranoja.

W sumie to dokumentacja tworzona po fakcie ma jednak swoją wartość - oczywiście pod warunkiem, że ktoś ją aktualizuje:P



A gdyby tak potraktować diagramy UML jako narzędzie do eksperymentowania? Nie chodzi o sam fakt posiadania dokumentacji, ale proces jej tworzenia. Wysiłek umysłowy włożony w zastanowienie się o co w ogóle chodzi. Skupienie się na tym CO a nie JAK. Eksperymentowania, które polega na najpierw na notowaniu wyników analizy biznesowej. Później poddaniu ich wnikliwej i rzetelnej analizie systemowej, czyli odfiltrowaniu chaosu wprowadzone przez ekspertów biznesowych i wyciągnięciu z tego czystego ekstraktu. W wyniku otrzymamy diagramy Use Caseów i Obiektów Biznesowych - stąd już blisko do warstw logiki aplikacji i biznesowej. I nie chodzi bynajmniej o to aby jedynie przepisać bełkot klienta na jajeczka z ludzikami i cieszyć się, że mamy diagramiki Use Case. Tworząc diagramy warto się zastanowić nad każdą kreską i jajeczkiem - czy dany element ma sens, czy nie da się czegoś uogólnić i wyłonić reużywalnej abstrakcji, czy nie da się tego zrobić prościej - właśnie o to upraszczanie chodzi. Upraszczanie na etapie "eksperymentowania" w UML zwróci się na etapie kodowania.

Analogiczne eksperymenty w UML można przeprowadzać na etapie projektowania. Zanim zacznie się kodować warto przez chwilę popatrzeć z większej wysokości na całość bo można przypadkiem zauważyć uogólnienie prowadzące całkiem za darmo do reużywalności. Można też całkiem przypadkiem znaleźć miejsca dla jakiegoś wzorca projektowego i całkiem za darmo zapewnić w przyszłości większą giętkość systemu i jego otwartość na rozbudowę.

Z samego planowania może wyjść więcej dobrego niż z posiadania gotowych (wygenerowanych) planów...
No i jak by nie było - efektem ubocznym tworzenia dokumentacji jest jej posiadanie:)



//=================
UML sam w sobie jest po prostu jakimś tam pismem obrazkowym. Może ma nieco lepiej zdefiniowane reguły niż pismo jaskiniowców, ale wciąż - pismem obrazkowym;P

Sztuka stosowania UML nie polega na skrupulatnym rysowaniu prostokątów od ekierki i następnie ich kolorowaniu tak aby nie wyjść kredką poza kontur.

Nie chodzi o samą formę ale o proces myślowy, który zaszedł np. podczas obiektowej analizy domeny biznesowej. Prostokąty to tylko notatka z walki ze złożonością i chaosem.

sobota, 1 listopada 2008

UP-DDD in Action: Malutka Teoria Unifikacji

Planowałem stopniowo wprowadzać w fazy Unified Process, jednak jak widzę zniecierpliwieni czytelnicy już teraz zastanawiają się jak pogodzić ze sobą UP i DDD:) Maciek - specjalnie dla Ciebie zwiększamy tempo.

W skrócie UP zakłada etapowe przeprowadzenie projektu. Etapy mogą (powinny) być powtarzane iteracyjnie. Z kolei etap możemy podzielić na fazy. Fazy są właściwie spojrzeniem z rożnych poziomów abstrakcji na nasz system. W każdej fazie powstają na wyjściu pewne artefakty, które są wejściem do fazy następnej. Po ostatniej fazie zamykamy iterację i powinniśmy mieć działający system.

W dużym skrócie i uproszczeniu mamy fazy:
- analizy biznesowej
- analizy systemowej
- projektowania (opartego na założonej/wypracowanej architekturze)
- implementacji
Kiedyś popełniłem ich zgrubny opis i niech to nam na razie wystarczy (druga połowa posta). Póki co warto pamiętać, że w fazie analizy powstaje model dziedziny problemu a w fazie projektowania powstaje między innymi model obiektów biznesowych. Poczucie estetyki i intuicja biją na alarm: dwa modele to co najmniej o jeden za dużo! Gdzie jest Ockham ze swoją brzytwą?!

Domain Driven Design skupia się na fazie analizy systemowej i projektowania. Ojciec założyciel DDD (Eric Evans) dokonał niebywałego odkrycia;) Unifikacja! Co prawda nie jest ono na miarę GUT ale wnosi coś nowego do UP. Mianowicie utrzymywanie dwóch modeli: analitycznego i projektowego prowadzi do zasadniczego problemu: modele z czasem się rozjeżdżają. Cholera - nikt się chyba tego nie spodziewał (tak jak hiszpańskiej inkwizycji). Z czasem modyfikacje wprowadzane na poziomie projektu nie są aktualizowane na poziomie analizy. A z drugiej strony nowe odkrycia analitycznie nie są projektowane z braku czasu.

Zatem nie udawajmy, że wszystko jest git i nie oszukujmy się, że grzecznie będziemy pilnować spójności obu modeli. W brutalnej rzeczywistości komercyjnych projektów korporacyjnych to se ne da i kropka. Dobrze wiemy, że wystarczającym problemem jest już samo utrzymanie spójności pomiędzy implementacją a modelem projektowym:)

Zamiast walczyć z jakimś zjawiskiem, nauczmy się z nim żyć, albo jeszcze lepiej wykorzystajmy na własną korzyść. To właśnie postuluje DDD. Niech nasz projekt obiektów biznesowych będzie jednocześnie analitycznym modelem domenowym. Przecież sama koncepcja obiektowości powstała po to, aby struktury techniczne odpowiadały mniej więcej bytom z dziedziny problemu. Oczywiście analityk czasem musi się nagiąć nieco w stronę technikaliów i uszczknąć nieco ze swego pięknego modelu absolutu. Z drugie strony projektant musi zapomnieć o optymalnym modelu klas czy bazy. Na szczęście doświadczony projektant OO jest w stenie w miarę wiernie oddać strukturę domeny biznesowej. W razie czego kompromis to podstawa. Heh szczęście w nieszczęściu gdy analitykiem i projektantem jest jedna i ta sama osoba:)))



Opowiadając już konkretnie na pytania Maćka:
Wydaje mi się, że przepaść pomiędzy modelem analitycznym a projektowym nie powinna być problemem dzięki zastosowaniu starego indiańskiego triku architektonicznego - warstw.

Patrząc na projekt systemu i skupiając się na na warstwie logiki biznesowej powinniśmy widzieć nic innego jak analityczny model domenowy z UP. W DDD istnieje zestaw figur (zwanych building blocks) z których możemy budować model obiektów biznesowych. Tutaj ich opis.
A skupiając się na warstwie logiki aplikacji powinniśmy widzieć analityczny model przypadków użycia.



Dzięki temu, że takie "szczegóły" jak persystencja i prezentacja są wydzielone do innych warstw, warstwy logiki są "czyste" i możemy ich projekt - przy odpowiednim nastawieniu - traktować również jako model analityczny.

Odnośnie drugiej części pytania Maćka - o rzeczywistość: udało mi się ustalić dobre zasady współpracy z "ekspertami biznesowymi". Mam do nich dobry dostęp i możemy wspólnie tworzyć dokumentację analityczną - która przy okazji jest projektem moich warstw logiki:) Czyli przysłowiowe 2 pieczenie przy 1 ogniu. Jest to dla mnie bardzo ważne, ponieważ jak wszyscy pewnie wiemy logiczne rozumowanie nie jest mocną stroną "ludzi biznesu";) O myśleniu obiektowym możemy zapomnieć. Często dokumenty przez nich tworzone nie nadają się do czytania - a co dopiero analizowania.
Czasem dochodzi do takiej paranoi, że ktoś pisząc wymagania biznesowe niemal "szyfruje" w dokumencie prostą i oczywistą treść. Później analityk systemowy/projektant/programista musi to odszyfrowywać i domyślać się o so choszi.
Do tego nie każdy potrafi sensownie napisać parę stron, akapit czy choćby jedno zdanie! Pojawia się też problem kognitywny. Ja na ten przykład preferuję podejście top-down. Najpierw muszę uchwycić ogólną ideę a później mogę zgłębiać szczegóły. Krew mnie zalewy gdy muszę czytać czyjeś polucje, które akurat powstały w odwrotnym toku rozumowania.

Natomiast pismo obrazkowe (UML) ma to do siebie, że ciężko nabazgrać coś co jest kompletnie bez sensu. A w razie czego od razu widać:) Oczywiście sam fakt stosowania jakiegoś formalizmu nie implikuje, że dokumentacja musi mieć jakąkolwiek wartość oprócz dupochronu w razie szukania kozłów ofiarnych. O jakości dokumentacji stanowi tak na prawdę ilość pracy umysłowej włożonej w analizę.

Dlatego o wiele lepszym podejściem jest wspólne (ekspert biznesowy + analityk systemowy) tworzenie dokumentacji od razu w UML. Ekspert mówi, a analityk rysuje. Analityk pyta, ekspert odpowiada, analityk poprawia rysunek. Oczywiście nie zawsze mamy taki komfort.

//====================
Gdy się przyjrzeć z dystansem założeniem UP czy DDD można dojść do wniosku, że jest nic innego jak zestaw racjonalnych wytycznych. Są to oczywiste oczywistości, na które każdy kto jest skłonny do odrobiny refleksji wpadły sam - prędzej czy później. UP czy DDD jedynie zbierają i strukturyzują zestaw intuicyjnych zasad.

Aż dziw bierze gdy się zastanawiam jak w ogóle mogłem postępować (będąc zmuszanym) im wbrew i mało tego - coś tam powstało i nawet jakoś działa:P
Biedni spadkobiercy spuścizny...

sobota, 25 października 2008

Unified Process & Domain Driven Design in Action

Dzisiaj pierwszy post z nowej serii. Jest to odcinek pilotażowy tasiemca, który z założenia ma być od teraz głównym wątkiem tego blogaska. Zgodnie z tytułem blogaska - będzie holistycznie (hasło to przestanie być pretensjonalnym buzzwordem).

Przygotowuję się powoli do rozpoczęcia nowego projektu. Jest to któryś już z kolei projekt, w którym będę uczestniczył - tym razem jako team leader. Jak zwykle obiecuję sobie, że tym razem będzie bardziej profesjonalnie i że tym razem będzie to miało przysłowiowe ręce i nogi (oraz nie 3 ręce i nie 8 nóg).

W ciągu pięciu lat pracy dobrze nauczyłem się jak NIE podchodzić do projektów - jest to wiedza praktyczna. Marność nad marnościami. Jednak tym razem zamierzam zastosować nabytą w ciągu ostatniego roku wiedzę teoretyczną... Unified Process (krótki wstęp) będzie procesem wytwórczym według którego będę chciał postępować. Główne fazy UP to analiza i projekt. Aby im sprostać posłużę się wytycznymi Domain Driven Design (dotychczasowe wypociny).

Zatem zamierzam przeprowadzić studium przypadku. Od czasu do czasu będę relacjonował jak sprawdza się UP i DDD w praktyce. Oczywiście treść będzie obdarta z kontekstu biznesowego:) Przykłady z wiadomych względów zostaną podniesione na nieco wyższy poziom abstrakcji.

Dodatkowo całość będzie zanurzona w kontekście technologicznym. Sam jestem ciekaw jak frameworki udźwigną ambitne założenia DDD:) Nie będę zanudzał tutorialami o popularnych frameworkach - jest tego pod dostatkiem i każdy na pewno znajduje dla siebie materiały odpowiadające osobistym preferencjom kognitywnym.


Relacja pomiędzy UP a DDD polega na tym, że UP jako proces wytwórczy prowadzi przez kolejny fazy (analiza biznesowa, systemowa, architektura, projekt implementacja, testy, wdrożenie); fazy dodatkowo zapętlone w iteracje. Natomiast DDD jest sposobem myślenia o fazach analizy (OOA) i projektowania (OOD) jako całości.

//===================
Nie pozostaje mi nic innego jak zaprosić do śledzenia postów otagowanych "UP-DDD in Action"