czwartek, 22 marca 2012

Programistamag.pl - nowy periodyk branżowy

Wczoraj ukazał się premierowy numer nowego czasopisma dla programistów: http://programistamag.pl.

Znajdziecie w nim między innymi (popełniony przeze mnie) pierwszy z serii artykuł poświęcony podstawom Domain Driven Design - tak zwanym Building Blocks.

Seria poświęcona DDD będzie oparta o nasz referencyjny projekt Leaven.

Zachęcam do lektury i komentowania tekstu.

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

Dostęp do magazynu w formacie PDF jest bezpłatny; płatne wersje to Kindle i klasyczny druk.

środa, 21 marca 2012

Average polish Java developer is not an idiot for Zeus' sake!

If You live in Western Europe or US and visit Poland, You may strike general impression (looking at airport, cars, clothes fashion) that Poland is rather poor country.

Therefore: if society could not manage to generate wealthy "system", than You may infer that only logical explanation is that human beings living in given area must be somehow stupid. I don't know much about macro/psycho/social/ - economy, but let's temporarily agree about this hypothesis.

Average Java developer in Poland has mostly just a Master Degree (99,9%) in Computer Science (I guess that over 70%), usually there are just few Phds per company.

So, maybe Average Java developer in Poland is not a genius, but for Zeus' sake: when giving a talk at Java conference You don't have to explain to him/her that:
  • methods should be short
  • code should be simple, simple, simple
  • 2.0 - 1.1 is almost 0.9 when operating on doubles
  • duplication in code is bad (but not always!!!)
  • SSD is faster than HDD
We get it, really:P
And some of us even understand laser at the quantum level:PPP

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

33 Degree Conference was a great event (again), I would like to thank every single one for awesome vibes, see You next year:)))
Special thanks to Grzesiek!
Full conference summary at the weekend, after coming back home from workshop...

sobota, 17 marca 2012

Prezentacje na 33rd Degree

W najbliższy wtorek 20. marca będę miał przyjemność przedstawić dwie prezentacje podczas konferencji 33rd Degree.

Niezdecydowanych co do wyboru ścieżki uczestników zapraszam do zapoznania się z prezentacjami. Co prawda są to jedynie "ścieżki myśli" (raczej dla mnie, prowadzące wątek), które bez narracji zawierają max. 20% treści, ale mam nadzieję, że pozwolą Wam zorientować się czy tematyka i jej zakres może być interesująca lub nie.


Pierwsza prezentacja będzie poświęcona zagadnieniom "miękkim". Tradycyjnie wplatam "miękkie" wątki w każdą swą prezentację, jednak tym razem będzie to 100% treści (i zero kodu:) Jednak doszyć szybko doprowadzimy do "ścięcia" się białka i wyszukania "twardych" konkretów - co symbolizuje gubernator na pierwszym "slajdzie":)

abstrakt: Ścisły przewodnik po aspektach miękkich dla ekspertów IT





Druga prezentacja jest dla odmiany techniczna w każdym calu - konkretne problemy i konkretne techniki inżynieryjne ich rozwiązania.

abstrakt: Przewodnik po strukturyzacji systemu. 10,5 klasycznych technik programistycznych leżących u podstaw nowoczesnej inżynierii oprogramowania





//===============================
Materiały są w wersji Alpha, błędy nie zostały jeszcze poddane korekcie:)

piątek, 2 marca 2012

Racjonalne wykorzystanie JPA

W poprzednim poście opisałem klasyczny problem wydajnościowy N+1 Select Problem występujący podczas korzystania z Java Persistence API, wraz z kilkoma podejściami do zabezpieczenia się przed jego powstawaniem.

W komentarzach pojawił się pewien wątek, który chciałbym teraz rozwinąć...

Zastanowimy się nad racjonalnym wykorzystaniem narzędzia jakim jest maper relacyjno-obiektowy. Jak to zwykle z racjonalnym myśleniem bywa - niesie ono ze sobą zwykle dodatkowe skutki uboczne w postaci nieoczekiwanych korzyści. W tym wypadku będzie to dodatkowa poprawa wydajności.

Co? Po co? Dlaczego tak?

W jakim celu mapujemy świat relacyjny na obiektowy?
Być może po to aby:
  • Pobierać w wygodny sposób obiekty biznesowe - wraz z wygodnymi mechanizmami typu Lazy Loading
  • Wykonywać na nich operacje biznesowe zmieniające ich stan - możemy tutaj tworzyć zarówno anemiczne encje modyfikowane przez serwisy jak również projektować prawdziwe obiekty modelujące reguły i niezmienniki biznesowe (styl Domain Driven Design)
  • Utrwalać stan obiektów biznesowych - stan, który zmienił się w poprzednim kroku (korzystając z wygodnych mechanizmów wykrywania "brudzenia" i mechanizmu kaskadowego zapisu całych grafów obiektów)
Jeżeli używasz JPA do tych klas problemów, to używasz odpowiedniego młotka do odpowiedniej klasy problemu. Czyli pobieram obiekt (JEDEN, no dwa, góra cy;) biznesowy, zmieniam jego stan, zapisuję go.

Pisząc zmieniam stan nie mam na myśli "edytuję podpinając pod formularz". Mam na myśli logikę aplikacji (modelującą Use Case/User Story), która modyfikuje mój obiekt biznesowy (uruchamiając jego metody biznesowe lub settery jeżeli jest on anemiczny). Przykład gdzie Order i Invoice to obiekty persystentne:

 public void approveOrder(Long orderId) {
        Order order = orderRepository.load(orderId);

        //sample: Specification Design Pattern
        Specification<Order> orderSpecification = generateSpecification(systemUser);
        if (!orderSpecification.isSatisfiedBy(order))
            throw new OrderOperationException("Order does not meet specification", order.getEntityId());

        // sample: call Domain Logic
        order.submit();
        // sample: call Domain Service (Bookkeeper)
        Invoice invoice = invoicingService.issuance(order, generateTaxPolicy(systemUser));

        invoiceRepository.save(invoice);
        orderRepository.save(order);
    }

Link do kodu.


Zawsze?

Jeżeli natomiast chcę wyświetlić na ekranie dane, np. dane przekrojowe, np w postaci tabelki (ludzie biznesu uwielbiają tabelki, najlepiej aby dało się przestawiać kolejność ich kolumn;) to narzędzie pod tytułem JPA nie jest odpowiednim młotkiem do tego problemu. W tym wypadku na każdym etapie postępuję nieracjonalnie:
  • Pobieram z mapera listę obiektów (zamapowanych na całe tabelki w bazie) gdy potrzebuję na ekranie jedynie kilku kolumn z każdej tabelki (dla bazy nie robi to różnicy, ale gdy maszyna serwująca bazę lub klient je zdalna to wówczas zaznamy odczuwać skutki tej decyzji)
  • Mam możliwość korzystania z mechanizmu Lazy Loadingu, który nie ma sensu dla operacji typu "pobierz dane do wyświetlenia"
  • Silnik mapera wykonuje niepotrzebne operacje związane z LL i wykrywaniem "brudzenia" - przecież nie będę modyfikował tych obiektów, chcę jedynie coś wyświetlić
  • Zdradzam model biznesowy warstwie prezentacji. Być może w prostych aplikacjach z prezentacją w technologii webowej (ta sama maszyna pobiera i prezentuje dane) nie jest to problem - dodatkowo zyskujemy produktywność w pracy. Ale jeżeli klienty (nie klienci) są zdalne (np Android)? Zdradzanie modelu domenowego wiąże się z drastycznym spadkiem bezpieczeństwa (wsteczna inżynieria) oraz z koniecznością koordynacji prac zespołów pracujących nad "klientem" i "serwerem", że o zapewnianiu kompatybilności starszych wersji klientów nie wspomnę. Niby banały, jednak w niektórzy ewangelizatorzy EE zachęcają do zwracania encji ponad warstwę serwisów (sic!)


Klasa problemu <=> Klasa rozwiązania

W każdym systemie mamy wyraźnie rozróżnienie na odczyt danych i modyfikację danych. Pisałem już jakiś czas temu o paradygmacie Command-query Seapration, z którego wyłoniła się architektura Command-query Responsibility Segregation.

Nie chcę się powtarzać, zatem w materiałach bloga (link na górze po prawej) znajdziecie prezentację na ten temat, polecam też artykuł samego mistrza: Martina Fowlera.

Separacja

Tak więc donosząc się do pytania Andrzeja z poprzedniego posta: Jak najbardziej konstrukcja SELECY NEW MyDTO(encja.pole1, ecnja.pole2) FROM Encja encja jest na miejscu. W przypadku gdy chodzi o zwrócenie danych do prezentacji (modelowanych jako DTO) a nie pobranie obiektów biznesowych do wykonania na nich operacji biznesowych.

Separację możemy poprowadzić jeszcze "głębiej" i dokonać projekcji modelu domenowego, który utrzymujemy w III postaci normalnej do postaci płaskiej, odpowiedniej do odczytu. W tym celu możemy zastosować Widoki Zmaterializowane lub np. odświeżać model Read przy pomocy zdarzeń domenowych.

Najmniej racjonalną rzeczą jaką możemy zrobić to pobierać encje JPA i przepakowywać je na DTO. Po co pobierać te dane (ryzykując N+1SP) skoro i tak musimy wykonać pracę (kodowanie, załączenie automatu) przepakowania?

Wydajność ++

Ale zostawmy zaawansowane architektury przygotowane do skalowania...

Jeżeli już decydujemy się na pobieranie poszczególnych kolumn z bazy, to dlaczego nie użyć czystego SQL zamiast HQL (konstrukcji SELECT NEW)? Przecież skoro wiem, że pewnych miejscach pobieram dane jedynie do odczytu, to być może warto zestawić osobną pulę połączeń z bazą - połączeń read-only. Być może baza, której używasz będzie wówczas działać nieco lepiej...:)

W takim wypadku warto użyć lekkiego mapera typu myBatis, którego użyję w celu mapowania Result Set na paczki danych (DTO) a nie na obiekty biznesowe służce do wykonywania operacji biznesowych!

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

Pracując z Hibernate (od 2003r, od wersji 2.0) zawsze, w każdym jednym projekcie - małym i dużym (1200 tabel) dochodziło do sytuacji przepisania pewnych zapytań na czysty SQL z powodu wydajności. MyBatis na prawdę działa:)

Przykłady architektury, która wyraźnie rozdziela operacje odczytu i zapisu: Domain Driven Design & Command-query Responsibility Segregation sample project - Java, Spring, JPA