Saturday, March 19, 2011

Generowanie danych dla widoku

Spotkałem się niedawno z ciekawym rozwiązaniem dotyczącym sposobu generowania danych dla widoku. Warto je opisać.

O co chodzi?
W większości aplikacji musimy dostarczać do widoku różnego dane by je zaprezentować użytkownikowi. Mogą być to dane, na których użytkownik bieżąco pracuje i które widzi na stronie albo dane służące go produkowania raportów, z którymi użytkownik nie wchodzi w interakcję.

Często wystarcza nam przesyłanie do widoku obiektów detached. Przy złożonych modelach domenowych przesyłanie fragmentów modelu domenowego nie jest wygodne. Chociażby z tego względu, że widok często wymaga danych przekrojowych, pochodzących z różnych miejsc modelu. Radzimy sobie wtedy za pomocą obiektów DTO tworzonych na potrzeby konkretnych widoków (Rysunek 1).






Rysunek 1: Generowanie DTO z modelu domenowego

W zależności od skomplikowania obiektów transferowych, generowanie ich można umieścić albo w samych obiektach domenowych albo scentralizować w usłudze Transfer Object Assembler.

Gdy ilość sposobów prezentowania danych dramatycznie wzrasta (raporty, ekrany), okazuje się, że kod związany z obiektami transferowymi zaśmieca projekt i coraz trudniej go utrzymywać.

Pierwsze rozwiązanie
Pierwszy pomysł to przeniesienie odpowiedzialności generowania obiektów DTO na SQL np. z wykorzystaniem biblioteki myBatis. Pamiętajmy, że chodzi o obiekty tylko do odczytu.




Rysunek 2: ORM dla modelu domentowego myBatis dla DTO

Powoduje to dwa problemy. Po pierwsze: znów w miarę rozrastania warstwy widoku a wraz z nią rożnych sposobów (przekrojów) prezentowania danych, zarządzanie zapytaniami SQL nawet umieszczonymi w plikach XML jest uciążliwe. Po drugie pojawia się dualizm: z jednej strony ORM zarządza modelem domenowym, z drugiej wcinamy się gdzieś z boku SQLem, aby pobrać dane dla widoku.

Mapowanie widoków bazodanowych
Rozwiązanie, z którym się spotkałem, polega na zepchnięciu generowania danych przekrojowych bazę danych i reprezentowania ich w postaci widoków bazodanowych. Obiekt DTO mapujemy jako encje na w zdefiniowane w bazie widoki.
W usłudze, dzięki której pobieramy dane z bazy udostępniamy wyłącznie możliwość odczytu.

Ciekawe jakby można nazwać obiekt taką usługę. DAO, Repository? Jakoś kłóci się z tym, co zwyczajowo rozumiemy przez tego typu usługi. Wydaje mi się, że dobrą (na razie ogólną) nazwą będzie PresentationDataService.




Rysunek 3: ORM mapuje widoki bazodanowe

Urzekająca jest symetryczność tego rozwiązania: to co obiektowe jest po stronie obiektów, to co bazodanowe po stronie bazy danych, a ORM wykorzystany jako pomost pomiędzy tymi dwoma światami.

Tymczasowa niespójność danych
W opisanym rozwiązaniu kluczowym aspektem jest wydajność. Po pierwsze: umieszczamy dane dla prezentacji w widoku zmaterializowanym.
Wydajność można dramatycznie poprawić jeśli zgodzimy się na tymczasową niespójność danych. Na przykład: użytkownik dodaje nowego pracownika i otrzymuje komunikat: "Twoje zmiany pojawią się w systemie w ciągu 10 minut.". Okresowe przeliczanie widoku zmaterializowanego jest zdecydowanie wydajniejszym rozwiązaniem niż robienie tego na każde żądanie użytkownika.
Oczywiście jeśli baza danych nie wspiera widoków zmaterializowanych to używamy tabeli tymczasowej i sami klepiemy kod aktualizujący.

Przeszukiwanie dużych ilości danych
Poniższe rozwiązanie dotyczy sytuacji, gdy mamy w bazie kilka milionów np.: klientów oraz złożone kryteria wyszukiwania. Mówiąc o złożonych kryteriach mam na myśli zmienną liczbę parametrów, po których będziemy wyszukiwać (w zależności od potrzeb wynikających z sytuacji biznesowych). Przy stałej liczbie parametrów można stworzyć odpowiednią ilość zapytań QL. Przy zmiennej liczbie parametrów najwygodniej posługiwać się obiektami Cirteria udostępnianymi przez dany ORM. Znów kluczową sprawą jest wydajność przeszukiwania.

Tabela pośrednia z kryteriami wyszukiwania
Pomysł polega na utworzeniu w bazie danych pomocniczej tabeli (widoku zmaterializowanego), która z jednej strony zawiera iloczyn kartezjański wszystkich atrybutów wyszukiwanego obiektu, a z drugiej namiar na odpowiedni wiersz w tabeli związanej z właściwym obiektem, który spełnia kryteria wyszukiwania.





Rysunek 4: Pomocnicza tabela z kryteriami wyszukiwania

Pytanie otwarte: Czy pośrednia tabela kryteriów i odpowiednie jej poindeksowanie rzeczywiście przyśpieszy wyszukiwanie obiektów?

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.

Thursday, March 10, 2011

PEA(2): Kontekst środowiskowy systemu

To jest artykuł z serii Proces ewolucji architektury.

9 rano, siadasz z ludźmi, którzy chcą, żeby zaprojektować architekturę systemu. Twoja wiedza domenowa = null.

Zaczynają zasypywać cię gradem szczegółów.

10.30 mózg przestaje absorbować informacje. Czujesz się jak po całym dni w obcym kraju, gdzie musiałeś wytężać 100% uwagi, żeby zrozumieć choć trochę co do ciebie mówią. Naturalna reakcja obronna organizmu jest zabawna - chce ci się spać. O, żeby zdrzemnąć się choć na minutkę... Stop!

Zbuduj sobie ogólne overview na sytuację. Określ kontekst środowiskowy systemu, z kim on współpracuje i jakie informacje wymienia z otoczeniem:

  • trzymaj się na dość dużym poziomie ogólności; na tym etapie szczegół to twój wróg, uśpi cię szybciej niż myślisz

  • definiuj: nazwy systemów, odpowiedzialności systemów (jednym zdaniem), nazwy operacji wykonywanych pomiędzy systemami (czego chce jeden od drugiego?), nazwy protokołów (tylko nazwy)

  • unikaj: formatów przesyłanych danych, sposobów nawiązywania połączeń itp; jeszcze nie jest na to czas


Nie wstydź się bazgrać
Celem tych działań jest zrozumienie z czym masz do czynienia, ani brylowanie znajomością UMLa. Na tym etapie diagram komponentów wcale nie jest bardziej profesjonalny niż prostokąty nabazgrane na kartce. Diagram to tylko umowa co do formatu rysunków, jeśli kredki odpowiadają ci bardziej dlaczego ich nie używać?

Wednesday, March 9, 2011

Lean Architecture: for Agile Software Development


Nie, to nie jest recenzja książki, a raczej gorące jej polecenie. Lektura tak mnie zachwyciła, że aż musiałem wpisać to na blogu, co poskutkowało dorzuceniem nowej etykiety, a o ile pamiętam liczba etykiet na moim blogu nie zmieniła się od początku jego powstania. Słowem: WIELKIE wydarzenie.

Nie znajdziesz w tej książce supertajnych wzorców w postaci UML, nie poczytasz o wyższości jednej technologii nad drugą. Jest ona o tym, o czym być powinna: o budowaniu zrozumienia dziedziny, o tworzeniu porządnego softu i o ludziach, którzy są w to wszystko zaangażowani. Wymagająca lektura nie-na-jeden-wieczór, ale warto!