piątek, 16 grudnia 2011

Skręt kości promieniowej i łokciowej, czyli rzecz o myszkach

Awaria mojej głównej myszki (czyli tej której używam do codziennej pracy, w odróżnieniu od specjalnej do gry ze znajomymi w CoD) skłoniła mnie do napisania kolejnego posta na temat Sprzętu.

Dawno, dawno temu, jako początkujący użytkownik peceta byłem przekonany, że jego głównym elementem, decydującym o ogólnym "ekspiriens" jest procesor i akcelerowana karta graficzna:) "Dziś sam jestem dziadkiem" i pytany przez nietechnicznych znajomych oraz nietechniczną rodzinę doradzam, że najważniejsze elementy zestawu to: krzesło, klawiatura, myszka i matryca (w sensie jej jakości) - reszta zależy już tylko od budżetu:)


Warto wiedzieć, że klasyczne "płaskie" myszki wymuszają nienaturalne (skręcone) ułożenie kończyny górnej i prowadzą do:
  • Skrętu wzajemnego położenia kości promieniowej i łokciowej w naszym przedramieniu,
  • Naprężeniu mięśni przedramienia (wynika z powyższego)
  • Ucisku na naczynia krwionośne (wynika z obu powyższych)

Jeżeli się nad tym chwilę nie zastanowić, to ułożenie dłoni na płaskim blacie tak aby do niego przylegała wydaje się normalne. Ale spróbujcie układać dłoń na zmianę na blacie: w pozycji "do spoliczkowania" i w pozycji "płaskiej", aby powoli zacząć uświadamiać sobie co się dzieje z Waszymi kośćmi i mięśniami.

Wielu z nas skarży się na bóle w okolicach nadgarstka. Ja sam w pewnym momencie miałem problem z utrzymaniem kierownicy w prawej ręce podczas powrotu z pracy do domu.
Jako rozwiązanie polecam tego typu konstrukcje.
Osobiście od ok 5 lat używam modelu Vertical Grip i w tym momencie każde zetknięcie mojej odzwyczajonej od tortur ręki z "płaską" myszką skłania do refleksji: ale po co?

UPDATE:
Przesiadłem się na Vertical Mouse 4, która jest jeszcze bardziej pionowa, ale jakością wykonania bije Vertical Grip na głowę. Na stronie (po prawej na górze) widać dobrze co dzieje się z kośćmi, o których pisałem wyżej.

środa, 14 grudnia 2011

DDD na platformie Java EE 6

Dzisiaj coś dla miłośników Enterprise Edition.

Nieustannie rozwijamy projekt ilustrujący implementację zaawansowanych technik Domain Driven Design i architektury Command-query Responsibility Segregation.
Dotychczasowa implementacja oparta na Springu doczekała się swego lustrzanego odbicia na platformie Java EE6
W projekcie znajdziecie między innymi kilka sztuczek w CDI oraz przykłady wykorzystania silnika zdarzeń w modelowaniu biznesowym (dowiecie się również dlaczego budowany Events<> jest nieco ułomny:).

Więcej szczegółów na blogu projektu.

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

W najbliższych planach aplikacja kliencka na Androidzie w architekturze Eventually Connected Client.

środa, 30 listopada 2011

Geneza boskich klas

Zarówno po dzisiejszej konferencji softdevcon jak i zeszłotygodniowej JDD kilka osób prosiło mnie o powtórzenie tekstu o "boskich klasach", którym staram się rozbudzić uczestników prezentacji o DDD. Postanowiłem nieco rozszerzyć opowiastkę...



Narodziny

Każda boska klasa ma swój początek jako niewinny ośmiotysięcznik - klasa zawierająca osiem tysięcy linijek kodu.



Eskalacja

Zmiany w ośmiotysięczniku wymagają specjalnej wyprawy. Śmiałek wspina się przez kilka dni na wysokość ok piątego tysiąca próbując zrozumieć logikę/ironię kodu po czym zakłada tam bazę - rozgrzebuje kod kilkoma enterami aby zrobić sobie nieco miejsca, w którym to następnego dnia (bo aktualnie opada z wycieńczenia i niedoboru podstawowych neuroprzekaźników w mózgu) zacznie drążyć tunelik jako fundament dla nadbudówek.

Poczynania śmiałka powodują oczywiście niejednokrotnie lawiny, które rozrywają na dole i tak już nieszczelne siatki bezpieczeństwa testów.

Kolaps

Z czasem ośmiotysięcznik rozrasta się aby w końcu zapaść się grawitacyjnie pod własnym ciężarem. Powstaje wówczas osobliwość, z której wyłania się Boska Klasa - klasa, która wszystko wie, wszystko potrafi i jest połączona ze wszystkim w każdym możliwym wymiarze.

Boska klasa aby istnieć potrzebuje ofiar. Najlepsze są młode, niewinne praktykantki. W swej naiwności opartej na akademickich wierzeniach we wszechmoc Maszyny Turinga składają się w ofierze na ołtarzu Boskiej Klasy...

Z czasem udaje im się wyrwać z grawitacji osobliwości, ale już nigdy nie będą takie jak wcześniej...

wtorek, 1 listopada 2011

DDD must read

Od dłuższego czasu nosiłem się z zamiarem napisania posta poświęconego modelowaniu agregatów - różnym podejściom i wynikającym z nich konsekwencjom.
Właściwie temat nie jest związany ze specyfiką DDD, a ogólnie z modelowaniem obiektów biznesowych z zachowaniem ich enkapsulacji, które dzięki niej są bardziej odporne na zmiany.

Skoro jednak w sieci istnieją już materiały z dobrą ilustracją graficzną oraz przykładami w kodzie, to oszczędzę sobie pisania i pozwolę polecić ich lekturę każdemu kto zajmuje się modelowanie lub projektowaniem obiektowym (heh kto z czytelników się nie zajmuje "przy okazji" innych spraw?):

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

Tak jak pisałem wcześniej tematyka jest ogólna, nie związana stricte z DDD i lektura powinna być pożyteczna dla każdego.

niedziela, 9 października 2011

Konferencja Warsjawa - kolejny warsztat DDD&CqRS Leaven

Zapraszam na konferencję Warsjawa, która odbędzie się w najbliższą sobotę (15 października) w Warszawie.

Warto dodać, że konferencja jest całkowicie darmowa:)

Podczas konferencji będziecie mogli uczestniczyć między innymi w naszych warsztatach, poświęconych projektowi DDD&CqRS Leaven.

Szczegółowy program warsztatów: https://github.com/warszawajug/warsjawa2011/wiki/Warsztaty-DDD-i-CqRS.

środa, 5 października 2011

Persystentny Multi-Listener, czyli... Saga

Persystentny multi-listener... jak to pięknie brzmi...:)

Cóż to takiego?

Listener - czy obiekt słuchający zdarzeń,
mulit - czyli chodzi o wiele zdarzeń,
persystentny - czyli posiadający trwały stan.


Podczas ostatnich warsztatów z zakresu projektu DDD-CqRS Leaven wspomniana wyżej technika modelowania czasu spotkała się z zainteresowaniem wielu osób. Nic dziwnego, jest to dosyć nowy pattern; również na szkoleniach wzbudza zawsze największe emocje. Głównie dlatego, że ciężko pogodzić się z myślą, że coś tak złożonego można modelować i implementować w tak prosty i przyjemny sposób:P

Pattern ma swoją oficjalną nazwę, brzmi ona Saga. Jeżeli saga kojarzy się senior developerom z sagą rodziny Carringtonów, to dobrze się Wam kojarzy. Saga to coś co może rozciągać się w czasie niczym telenowela. Saga jest patternem służącym do orkiestracji wielu zdarzeń, które mogą zajść w rozproszonym systemie w nieokreślonej kolejności. Czas pomiędzy zajściem zdarzeń może być relatywnie długi, dlatego należy persystować jej stan w czasie oczekiwania na kolejne zdarzenie.

Przykład:
Wyobraźmy sobie system, w którym mamy moduły: sprzedaży, płatności i magazynu.
W module sprzedaży możemy zatwierdzić obiekt biznesowy Zamówienie. Zamówienie rzuca wówczas zdarzenie biznesowe ZatwierdzonoMnie zawierające id tegoż zamówienia.
W module płatności możemy dokonać wpłaty. Być może jest to przedpłata dokonana wcześniej niż zatwierdzenie zamówienia... Moduł ten rzuca zdarzenie niosące informację o zajściu faktu dokonania wpłaty.
Oba zdarzenia są orkiestrowane przez sagę Zakupy. Jeżeli otrzyma ona oba zdarzenia (pasujące po id biznesowym) i stwierdzi, że jesteśmy "kwita" wówczas może wysłać sygnał do modułu magazynowego aby przygotować paczkę do wysyłki.

Oczywiście możemy tego typu proces zaimplementować w inny sposób niż zdarzeniowy, ale jeżeli zależy nam na decouplingu modułów systemu (wraz z wszystkimi konsekwencjami: skalowanie, testowanie, rozszerzalność, otwartość na dodawanie pluginów, redukcja architektury Speaghetti na poziomie modułów) to warto posłużyć się Sagą.


Udi Dahan dosyć dobrze wyjaśnia motywację oraz szczegóły koncepcyjne: Saga Persistence and Event-Driven Architectures dlatego nie chcę powtarzać, tego co zostało napisane ponad 2 lata temu.

Jak widać w powyższym linku technicznie Saga to złożenie 2 wzorców: Observer i Memento. O ile observera każdy zna choćby z bibliotek graficznych i wszechobecnych tam onClickListenerów, o tyle Memento jest mniej znanym patternem. Jeżeli ktoś oglądał film pt. Memento o człowieku, który miał problem z transferem danych z pamięci podręcznej (kora przed-czołowa) do pamięci długotrwałej (hipokamp) to skojarzenie jest również poprawne. Memento to pattern służący obiektom na wysyłanie do siebie informacji na przyszłość. Tak jak bohater filmu, który zapisywał i tatuował sobie na rękach informacje o tym co należy zrobić w przyszłości:)

Natomiast zainteresowanych szczegółami implementacji Sagi odsyłam do przykładu w projekcie DDD&CqRS Leaven:



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

Jako ciekawostkę dodam, że niektóre szyny komunikatów w .NET wspierają mechanizm Sagi niejako "z pudełka"...
Techniczny komunikat (message) jest traktowany na poziomie logicznym jak zdarzenie (event). Ichnie "Message Driven Beany" reagaujące na wiele zdarzeń to po prostu Sagi. Do tego automatyczne ładowanie i zapisywanie Memento, kończenie albo usypianie sagi oraz drobny szczegół: obsługa współbieżności...
Natomiast my w swym świecie Javy wciąż szukamy uber-frameworka webowego, który daje złudzenie, że każdy system jest CRUDem...

środa, 28 września 2011

Zapraszamy na warsztaty z "wypiekania zaczynu" (DDD, BDD, CqRS)

W najbliższą sobotę (1 października) organizujemy w ramach lubelskiego JUGa otwarte warsztaty z zakresu:
- modelowania z wykorzystaniem Domain Driven Design
- procesu Behavior Driven Development (w tym wykorzystanie JBehave, Selenium i Agentów)
- architektury Command-query Responsibility Segregation

Warsztaty będą przeprowadzone na podstawie materiałów z otwartego i darmowego projektu DDD+CqRS Leaven.

Szczegóły wydarzenia na stronie JUGa.


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

Dla zainteresowanych z innych zakątków Polski informacja: planujemy tego typu inicjatywy podczas zbliżających się konferencji branżowych - szczegóły wkrótce.

sobota, 24 września 2011

java.util.Calendar a sprawa Polska, czyli gdzie są moje 24 minuty?

Jako członek rady programowej tegorocznej konferencji Java Developers' Day mam zaszczyt zaprosić Was do konkursu na śmieszną (może przez łzy) i ciekawą (może pouczającą) anegdotę z codziennej pracy.

Strona konkursu Z pamiętnika dewelopera historii kilka… zawiera szczegółowy regulamin i opis nagród. Planujemy dodatkowo podczas konferencji umożliwić podzielenie się swoimi "przygodami" w formie stand up comedian:)



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

Gdyby ktoś z lenistwa nie kliknął linka pod którym znajdują się zgłoszone historyjki, to zamieszczam kopię własnej:

Tytuł: java.util.Calendar a sprawa Polska, czyli gdzie są moje 24 minuty?

Problem:

Duży system, w którym klientem do serwera były applety. Na wielu formularzach istnieje możliwość edycji czasu pewnych zdarzeń. Czas edytowany przez zwykłe pole tekstowe w formacie godzina:minuty. Niestety, na niektórych formularzach można zaobserwować następujące schorzenie: wpisujemy pewien czas, zapisujemy, następnie gdy ponownie edytujemy rekord, czas jest zawsze cofnięty o 24 minuty! Liczba 24 kojarzy się każdemu z ilością godzin w dobie tak więc jest to doskonale zwodnicza wartość…

Tło techniczne:

Czas – z powodów, które pamiętają już tylko prastarzy Słowianie programujący w technologiach z epoki krzemu łupanego – był zapisywany w bazie danych jako: 01.01.1900 godzina_z_formularza:minuta_z_formularza:00.000

Kluczowy jest tutaj pierwszy stycznia roku 1900.

Zapis i odczyt działały poprawnie. Komunikacja applet – serwisy serwera poprzez Spring Remoting (zdalne wywołanie metod Beanów Springa, serializacja paramentów i wyników i wyjątków).
Czas był przesyłany w DTOsach w postaci obiektów klasy java.util.Calendar (służącej lepiej lub gorzej do manipulacji czasem) zamiast java.util.Date (służącej jako kontener na czas).
Calendar jest o tyle sprytną klasą, że jej obiekty badają lokalizację systemu operacyjnego na którym żyją. W przypadku podpisanych appletów robiły to na maszynach klienckich po ich przesłaniu i deserializacji.

Warto wiedzieć:

Po tygodniu poszukiwań okazało się, że głęboko w kodzie kalendarza istnieje logika, która uwzględnia następujący fakt: pewnego dnia w 1904 4. sierpnia 1915 roku na terenie Polski dokonano standaryzacji czasu, tak aby dopasować go do globalnych stref czasowych i przesunięto wówczas wskazówki o 24 minuty:)

A panowie z Suna (niestety) odrobili lekcje z historii…

sobota, 17 września 2011

Przyśpiesz swoje środowisko dev - ramdisk

Dziś post sprzętowy. Do tej pory nie poruszałem tego typu tematyki na blogu, ale prywatnie hardware interesuje mnie nie mniej niż software:)

Jak wiadomo w większości codziennych juzkejsów dysk jest wąskim gardłem naszego narzędzia pracy. Standardowym sposobem na przyśpieszenie maszyny jest wymiana dysku na SSD. Na dzień dzisiejszy aby tak na prawdę przyśpieszyć codzienną ogólną pracę (mieszanka zapisów i odczytów) trzeba wydać relatywnie sporą sumę na na prawdę szybki dysk.

Można jednak pójść znacznie dalej z prędkością odczytu/zapisu pokusić się o stworzenie dysku w pamięci RAM. Dysk tego typu jest widziany w systemie tak samo jak zwykłe dyski. Na starcie może on pobrać swój obraz z HDD/SSD do RAM i od tej pory pracujemy na pamięci, która jest bardzo blisko procesora. RamDisk może oczywiście periodycznie utrwalać się na dysku klasycznym (mając więcej niż 1 rdzeń w procesorze nie jest to problem).

Tutaj przegląd RamDisków dla Windows: http://www.raymond.cc/blog/archives/2009/12/08/12-ram-disk-software-benchmarked-for-fastest-read-and-write-speed/.
Od kilku dni testuję na Win7 x64: http://memory.dataram.com/products-and-services/software/ramdisk który jest darmowy do 4GB.

Na taki dysk można skopiować całe środowisko dev: JDK (wystarczy skopiować), Eclipse, Maven+Repo, Servery... Po prostu śmiga!

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

Dokupując RAM zwróćcie uwagę oczywiście na taktowanie (tak aby było maksymalne na jakie pozwala szyna) ale również na latencją CAS http://pl.wikipedia.org/wiki/CAS_latency. Przykładowo DDR3 1066MHz w wersji CL7 jest o 10% szybszy niż w wersji CL9. A różnica w cenie kości 4GB to dosłownie kilka zł:)

Rozwiązaniem lepszym niż RamDisk (który zapisuje obraz na HDD/SDD) byłby soft, który buforowałby w RAM wskazane katalogi i udostępniał je przez interfejs sterownika dysku. Tak aby po prostu w tle synchronizować się z klasycznym dyskiem wprost do wskazanych katalogów - bez obrazu dysku. Rodzaj stałego obszaru cache dysku. Znacie może tego typu rozwiązania softwareowe (bo istnieją mniej więcej tego typu sprzętowe kontrolery do dysków ssd)?

wtorek, 30 sierpnia 2011

Zaczyn DDD+CqRS

Jak pewnie zauważyliście, częstotliwość publikowania postów spadła ostatnio dosyć znacznie. A to za sprawą mocnego zaangażowania w nowy projekt - projekt ilustrujący techniki modelowania Domain Driven Design oraz wybrane podejścia do implementacji architektury Command-query Responsibility Segreation.

Projekt osiągnął poziom wersji Beta pierwszego Milestonea, tak więc już oficjalnie możemy go upublicznić: http://code.google.com/p/ddd-cqrs-sample/.



Zaczyn?
Nazwa ociekająca folklorem jest ilustracją idei: projekt to coś więcej niż Sample ale zdecydowanie nie jest to kolejny Framework - więcej na ten temat na wiki.
Gwoli wyjaśnienia: zaczyn to coś z czego powstaje chleb.

Odeszliśmy od formy frameworka przekonani przez samego Grega Younga (twórcę CqRS i propagatora DDD). Greg przekonał mnie podczas prywatnych rozmów, że framework dla CqRS delikatnie mówiąc nie ma sensu:)



Zawartość projektu odpowiada na pytania techniczne, które pojawiają się tak często, że uznaliśmy, że czas stworzyć sampla ilustrującego nasze podejście. Do tej pory istnieją dwa takie Sample napisane w Javie - my jednak chcieliśmy pójść nieco dalej. Tak więc projekt jest sumą doświadczeń jego twórców.

Co w nim znajdziecie:
- ilustracja wszystkich Builiding Blocków DDD (bez uproszczeń technicznych)
- ilustracja zaawansowany technik DDD (Bounded Context to nie są akademickie rozważania)
- ewolucyjne podejście do architektury warstwowej, różne poziomy separacji CqRS (na tym etapie nie wprowadzamy Event Sourcingu - wyjaśnienie powodów na wiki)
- pragmatyczne podejście do CqRS
- część bardzo specyficznej wiedzy wyniesioną przez nas z wiosennego szkolenia Grega Younga
- modelowanie czasu poprzez zdarzenia i dosyć nową technikę modelowania czasu: Sagi
- kilka eleganckich trików z wykorzystaniem Springa i Hibernate:)
- techniki testowania: jednostkowe, integracyjne i akceptacyjne
- połączenie JBehave (Behavior Driven Development) z Selenium
- już niedługo: nasz własny pomysł na uogólnienie historyjek tak by wspierały zarówno testowanie przez GUI jak i przez API



Zainteresowanych zapraszamy do:
- wiki - kilkadziesiąt stron A4 plus trzy wizualizacje w Prezi
- SVN - aktualnie ok 150 klas platformy zaczynu oraz przykładów DDD
- grupy dyskusyjnej
- bloga


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

Teksty techniczne z zakresu DDD i CqRS będę publikował na nowym blogu. Natomiast niniejszy będzie wciąż prowadzony jako miejsce na tematy pozostałe.

piątek, 12 sierpnia 2011

Wygeneruj sobie PDFa - Facelets (JSF) + CSS3 + Flying Saucer

Dzisiejszy post będzie nietypowy: dużo kodu i kilka speszyl-haków:)

Pokażę jak szybko i raczej bezboleśnie generować PDFy na podstawie HTMLa + CSS3 z wykorzystaniem szablonów w wydaniu Facelets.

Założenia

Oczywiście do generowania PDF możemy podejść na wiele sposobów. Możemy np. użyć natywnego api lub nawet zastosować Open Office postawionego w trybie servera (bez GUI) i korzystać ze wszelkich narzędzi do tworzenia dokumentu, aby na końcu "zapisać jako" pdf.

Natomiast w tym poście zakładam, że chcemy rozwiązać sprawę najprościej jak się da, bez potrzeby studiowania autystycznej dokumentacji.

Generujemy PDF

Na początek potrzebujemy biblioteki: http://code.google.com/p/flying-saucer (w paczce mamy ITexta i xercesa). Flying saucer to wspaniałe narzędzie, które przykrywa iTexta wygodnym api: na wejściu podajemy urla do strony, a na strumieniu wyjściowym dostajemy PDFa. Strona może odwoływać się do CSS3, w którym definiujemy nagłówki, stopki, numerowanie stron, podział stron. Wszystko zostanie kolejno opisane w dalszej części.

Pdfy będziemy zwracać z następującego servletu:
@SuppressWarnings("serial")
@WebServlet("/programy_szkolen_pdf/*")
public class PdfServlet extends HttpServlet {
	
	private static final String FONTS_PACKAGE = "fonts";
	private static final String FONTS_DIR = "/" + FONTS_PACKAGE + "/";
	
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {				
		
		response.setContentType("application/pdf");
		OutputStream os = response.getOutputStream();
		
		String url = getUrl(request);

		try {
			ITextRenderer renderer = initRenderer();
			
			renderer.setDocument(url);
			renderer.layout();
			
			renderer.createPDF(os);
		} catch (Exception ex){
			throw new ServletException(ex);
		}
		
		response.flushBuffer();

	}

	private String getUrl(HttpServletRequest request) {
		String pdfServletPath = request.getServletPath();
		
		String cp = request.getContextPath();
		String program = request.getRequestURI();
		
		program = program.replace(cp + pdfServletPath, "");
		program = program.substring(0, program.length() - 4); // cut .pdf
				
		String url = "http://localhost:8080" + cp + program + ".xhtm?pdf=true";
		
		return url;
	}
}

Jak widać API latającego spodka jest proste:
- posługujemy się obiektem rendererm który posiada stan
- ustawiamy mu URL do strony, którą chcemy skonwertować na PDF
- wołamy metodę układającą pdf
- wynik kierujemy do strumienia odpowiedzi servletu.

I to generalnie byłoby wszystko:)

Zostało kilka szczegółów...
Metoda getUrl w moim przypadku robi pewne oszustwo operując na ścieżkach

Użytkownik woła servlet:
/programy_szkolen_pdf/szkolenie-java-start.pdf
btw: zauważcie jak zamapowany jest servlet: @WebServlet("/programy_szkolen_pdf/*")

A servlet wskazuje latającemu spodkowi adres:
http://localhost:8080/strona/szkolenie-java-start.xhtm?pdf=true

Zakładam, że zasoby do renderowania znajdują się na tej samej maszynie, stąd localhost.
Do czego służy parametr pdf dowiemy się za chwilę:)


Mamy jeszcze nieco smutnych szczegółów technicznych w naszym latającym spodku.

Renderera trzeba zainicjować - metoda initRenderer.

Jeżeli w PDF chcemy używać polskich (lub jakichkolwiek innych barbarzyńskich znaków), to musimy zarejestrować w rendereze fonty, których używamy w CSS (Arial, Verdana, cokolwiek). Służy do tego metoda renderer.getFontResolver().addFont
Ja napisałem prosty automat, metodę findFonts(), który automatycznie wyszukuje plików z fontami w *pakiecie* zdefiniowanym w stałej FONTS_PACKAGE. Chodzi o to aby uniknąć konfigurowania ścieżek. Po prostu skanujemy pakiet z class path.
Zatem do odpowiedniego pakietu należy sobie wkopiować (np z systemu) fonty. Oczywiście katalog powinien być niedostępny z sieci aby nie być posądzonym o dystrybucję komercyjnych fontów - jeżeli takowych używacie.

	
	private ITextRenderer initRenderer() throws IOException, DocumentException{
		List fonts = findFonts();
		
		ITextRenderer renderer = new ITextRenderer();
		
		for (String font : fonts) {
			renderer.getFontResolver().addFont(FONTS_DIR + font,
					BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
		}			
		
		return renderer;
	}

	private List findFonts() throws IOException {
		Enumeration resources = getClass().getClassLoader().getResources(FONTS_PACKAGE);

		URL resource = resources.nextElement();
		File directory = new File(resource.getFile());

		List fonts = new ArrayList();
		if (!directory.exists()) {
			return fonts;
		}
		File[] files = directory.listFiles();
		for (File file : files) {			
			fonts.add(file.getName());
		}
		return fonts;
	}


Szablony

Dlaczego Facelets i JSF 2?

Do tej pory różnego rodzaju strony tworzyłem w PHP z wykorzystaniem Smarty. Po kilku doświadczeniach uznałem to za... powiedzmy niewygodne.

Chcę być dobrze zrozumiany - Smarty są ok dla pewnej klasy problemów: np wówczas gdy mamy kontent w bazie danych (jakiś CMS), pobieramy kontent jako wiersze i rozsmarowujemy po po "dziurkach" w szablonie. Wówczas imperatywne API Smarty (w postaci obiektu, na którym wołamy metody definiujące zmienne szablonu) jest jak najbardziej ok.

Natomiast ja w klasach problemów typu strona firmowa, preferuję przechowywać kontent (strzępy konwentu) w plikach XHTML. W takim wypadku praca z imperatywnym API to po prostu pomyłka. Jako "weteran" aplikacji webowych czuję się jak ryba w wodzie poruszając się w kodzie. Baza i CMS jedynie mnie ogranicza.

Dlatego tworząc nową wersję strony formowej zdecydowałem się na coś... delikatnie mówiąc... zastawiającego. Użycie JSF - standardu prezentacji enterprise (która ma swoich fanów jak i anty-fantów) do stworzenia strony www :O

Okazało się, że jeżeli nie używać formularzy (pomijamy większość faz cyklu obsługi żądania), nie używać ManagedBeanów, a jedynie składania kawałków XHTMla to okazuje się, bo jest to bardzo produktywne narzędzie.

Przykład:
strona http://bottega.com.pl/szkolenie-jsf-2
wygląda jak każdy widzi.

Jest wyraźnie podzielona na kontent merytoryczny i ozdobniki w postaci nagłówka, stopki i paneli bocznych.

A tak wygląda jej kod:

	
	
		
			
	

	Java Enterprise Edition

	JSF 2
	
		Java Server Faces 2

	Projektanci, programiści

	2 dni

	50% wykłady / 50% warsztaty

			
	
		

Program został skontrowany tak aby przedstawić zagadnienia w kontekście konkretnych problemów, które ilustrują praktyczne wykorzystanie każdej z funkcjonalności JSF. Program szkolenia zawiera rozszerzenie o najlepsze praktyki projektowe i architektoniczne. Tematyka szkolenia obejmuje wszystkie cechy frameworka JSF 2.0 istotne z punktu widzenia developera aplikacji.


Znaczniki ui:definie definiują wartości zmiennych, które będą używane w szablonie.
Wartości to czysty kod XHTML, który jest na bieżąco validowany przez edytor.

Stronę możemy zawołać na 3 sposoby:
- podając jej url: http://bottega.com.pl/szkolenie-jsf-2
- renderując ją do pdf: http://bottega.com.pl/programy_szkolen_pdf/szkolenie-jsf-2.pdf (wówczas nasz servlet przekaże adres http://bottega.com.pl/szkolenie-jsf-2.xhtm?pdf=true) do Flying Saucera
- zagnieżdżając w pływającej ramce na facebooku podając adres http://bottega.com.pl/szkolenie-jsf-2.xhtm?fb=true

W każdym z tych przypadków oczekujemy innego wyglądu.

Zatem znacznik ui:composition wskazuje szablon: template="/layout/training_template.xhtml"

Plik ten układa w odpowiednich miejscach parametry szkolenia. Szablon ten odpowiada jedynie za fragment strony (układ info o szkoleniu), ale nie zawiera np. nagłówka, stopki, ani bocznych boxów.



		Szkolenie: 
		

	
		

Informacje ogólne


Jak widać, szablon ten definiuje 2 zmienne: title i body. Wartości tych zmiennych zawierają w sobie XHTMLa oraz wartości zmiennych z dekorowane pliku - znacznik ui:insert.

Warunkowe renderowanie

Pomarańczowy przycisk "Zapytaj o szkolenie" jest niepożądany w przypadku wersji PDF i facebook, dlatego został warunkowo renderowany, przy pomocy panelGroup i atrybutu rendered:



Bean UrlChecker będzie opisany już za chwilę.


Wybór szablonu docelowego

Szablon szkolenia, nie jest szablonem "ostatecznym". Jest on dekorowane znowuż przez szablon wybierający szablon główny: template="/layout/dispatching_template.xhtml"

Jest to warstwa pośrednia pozwalająca w jednym miejscu przechowywać kod, który potencjalnie ulegnie zmianie. Tak oto wygląda dispatching_template.xhtml:


	


Jak widać nie dodaje żądnej wizualizacji a jedynie deleguje dekorowanie do kolejnego szablonu. Z tym, że nie mamy tutaj konkretnej ścieżki a jedynie wyrażenie wyliczane w Javie (tak w normalnym języku programowania a nie w jakimś pokracznym języku opartym o znaczniki):

@ManagedBean
public class UrlChecker {

	public String getTemplateName(){
		if (isPdf())
			return "template_pdf";
		
		if (isFacebook())
			return "template_facebook";
		
		return "template";
	}
	
	public boolean isStandard(){
		return ! (isPdf() || isFacebook());
	}
	
	public boolean isPdf(){		
		return "true".equals(getParameter("pdf"));
	}
	
	public boolean isFacebook(){		
		return "true".equals(getParameter("fb"));
	}
	
	private String getParameter(String name){
		ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();				
		return externalContext.getRequestParameterMap().get(name);		
	}
	
	
}

Zatem jeżeli zawołamy naszą stronę w ten sposób:
http://bottega.com.pl/szkolenie-jsf-2.xhtm
to w wyniku otrzymamy zawartość dekorowaną szablonem template_pl, który zawiera banner, stopę i boczne boxy

jeżeli natomiast w ten sposób:
http://bottega.com.pl/szkolenie-jsf-2.xhtm?pdf=true
to szablon dekorujący template_pdf_pl doda nagłówek i stopkę dla dokumnetu

a takie wywołanie
http://bottega.com.pl/szkolenie-jsf-2.xhtm?fb=true skutkuje zastosowaniem niemal niewidocznego szablonu dla facebooka.


Podsumowanie dekorowania


Mamy zatem następującą hierarchię treści:

szablon: szablon www | szablon pdf | szablon facebook
szablon: dispatcher
szablon: training
strona: konkretne szkolenie

Czyli na najwyższym poziomie mamy trzy perspektywy (szablony) spojrzenia na dane merytoryczne zawarte w plikach opisujących szkolenie.

Inne strony nie będące programem szkoleń po prostu pomijają szablon training_template i są dekorowane wprost szablonem dispatcher template


Układ dokumentu PDF w HTML i CSS3

Składanie stron w HTML jest dosyć łatwe. Wręcz banalne w porównaniu z natywnym API lub autyzmem Open Office.

Szablon pdf to zwykły XHTML:
<head>


</head>

<body>
  
!!! TUTAJ trzy warstwy opisane poniżej !!!
<</body>

Style po komentarzy "Specific Elements" są *kluczowe*.


Wewnątrz pierwszej warstwy mamy kolejno kolejno:

nagłówek:


stopkę:


zawartość:

Program szkolenia




Na zakończenie bonus dla wytrwałych

Jak wołać w JSF 2 metody z parametrem? Zapewniam, że może się przydać w bardziej wyrafinowanych szablonach:)

Tak robimy to w Seam od 5 lat:




Natomiast w czystym JSF trzeba wykonać kilka prostych kroków aby uzyskać możliwość stosowania powyższej składni:
http://ocpsoft.com/java/jsf2-java/jsf2-how-to-add-the-magic-of-el-el2-to-jsf/

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

Mam nadzieję, że udało mi się pokazać, że w Javie można efektywnie a przy tym czysto i elegancko zbudować stronę.

Przy innej okazji pokażę jak Filtry Servletów w dosłownie kilku linijkach biją na głowę autystyczne htaccess:)

A Smarki?... Już nigdy więcej:)

niedziela, 24 lipca 2011

Domain Driven Design - prezentacja z konferencji Confitura 2011

Prezentacja jest już dostępna na Vimeo.
Miejscami kod przykładów może być mało czytelny ale przyjrzeć im się można z bliska na Prezi.

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

Przy okazji chciałbym podziękować wszystkim, którzy wyrazili swe opinie w ankiecie konferencyjnej. Jest to dla mnie najcenniejsze źródło informacji. Z 22 opinii tekstowych, 20 z nich odbieram jako bardzo ciepłe i przyjazne. Wasze słowa są na prawdę motywacją do tego aby następnym razem poświęcić jeszcze więcej czasu (po obejrzeniu video uznałem, że czas należy poświęcić również na kurs emisji głosu i dykcji oraz logopedę:)

Cieszę się, że niektórym przypadło do gustu poczucie humoru - z uwagi na poprawność nie mogłem powiedzieć wszystkiego co miałem na myśli:)

Jeszcze bardziej ciesze się z tego, że kilka osób zadeklarowało chęć zgłębiania tematu.

Co do czasu trwania prezentacji, to temat jest na tyle obszerny, że podczas prezentacji można jedynie zasugerować odbiorcom kierunki do własnych dalszych poszukiwań. Stąd pojawiły się również tematy bardziej zaawansowane (potraktowane zdawkowo jako zajawki) aby skorzystali również uczestnicy znający temat główny.

Pojawił się jeden zarzut co do użycia prezi. Moim zdaniem jest to narzędzie, które pozwala doskonale pokazywać ogół jak i szczegóły na zasadzie skalowania poziomu abstrakcji. W tym konkretnym przypadku zawiódł projektor, którego ubogi zakres barw nie pozwolił na wyświetlenie schematu warstw, co mogło być mylące.

Na koniec pozdrowienia dla osoby, która uznała język prezentacji za "bardzo lakoniczny" a efekty za "przytłaczającą ilość wodotrysków" - no cóż... jestem tylko prostym programistą, który próbuje jakoś nieudolnie opowiadać o swoich doświadczeniach i przemyśleniach a braki językowe i retoryczne próbuje nadrabiać/tuszować wodotryskami;P

Rozkład ocen prezentacji:
5: 62
4: 33
3: 8
2: 1
1: 2
Średnia: 4.43396226415094

piątek, 15 lipca 2011

Fowler o CqRS

Koncepcja architektury CqRS doczekała się oficjalnego błogosławieństwa przez samego guru współczesnej inżynierii oprogramowania - Martina Fowlera.

/*
*Pamiętam jak jeszcze w kwietniu Greg Young opowiadał mi
* o swojej pierwszej prezentacji na temat CqRS,
* gdzie w pierwszych rzędach siedzieli: Uncle Bob, Eric Evans i Martin Fowler.
* Po prezentacji Evans podszedł i powiedział:
*bardzo słaba prezentacja, zrozumiałem tylko 30%:)
*/

Tak więc możemy uznać, że CqRS wchodzi do kanonu stylów architektonicznych - z zastrzeżeniem jednak co do zakresu stosowalności: okiełznanie chaosu w złożonych częściach systemu i potrzeba skalowania. Czyli w sumie otrzymujemy pogodzenie dwóch skrajnych interesów: elegancki model (np. DDD) z wysoką wydajnością.
"So while CQRS is a pattern I'd certainly want in my toolbox, I wouldn't keep it at the top."

Warto zwrócić też uwagę, że Fowler wyraźnie rozróżnia CqRS, który jest stylem architektonicznym od Event Sourcingu, który jest jedną z możliwych technik persystencji. Z obserwacji mogę powiedzieć, że często jest to zbyt silnie utożsamiane, ale należy pamiętać, że zawsze można mieć jedną z tych rzeczy bez drugiej.

Z ciekawych kontekstów, w których Event Sourcing zaczyna mieć sens oraz mocno się opłaca, jest wykorzystanie porcji zdarzeń jako wektorów uczących dla Sztucznych Sieci Neuronowych. Nie mówi się o tym zbyt wiele w mainstreamie, ale ES jest naturalną i od dawna stosowaną techniką w tych klasach systemów. Próba przeniesienia ES na systemy gdzie nie ma takich zastosowań na pewno się powiedzie, pytanie tylko jakim kosztem w stosunku do jakich zysków...?


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

Wiele osób pyta o postępy w przygotowywaniu naszego DDD-CqRS Sampla w Javie.
Pierwszy milestone zbliża się dużymi krokami. Mamy trzy małe konteksty domen z przykładami każdego Building Blocku. Stos biznesowy jest ilustrowany zarówno klasycznie serwisami jak i commandami, gdzie mamy kilka ciekawych technik takich jak asynchroniczność i filtrowanie duplikatów. Sagi docelowo będą działać na JMS. Stos prezentacji ilustruje kilka typowych optymalizacji odczytu.

Chętnych, którzy chcieliby ocenić projekt przez jego upublicznieniem zapraszam do kontaktu.

poniedziałek, 4 lipca 2011

Domain Driven Design - Sposób na projektowanie złożonych modeli biznesowych (plus niespodzianka)

W ostatnim numerze Software Developer's Journal ukazał się artykuł mojego autorstwa: "Domain Driven Design - Sposób na projektowanie złożonych modeli biznesowych".

Tekst przeznaczony jest zarówno dla początkujących jaki i średnio zaawansowanych praktyków DDD.
Początkujący znajdą w nim:
- ogólną ideę oraz zakres stosowalności podejścia
- przykłady kodu
a średnio zaawansowani mogą zapoznać się między innymi z:
- technikami komunikacji zdarzeniowej pomiędzy Bounded Context
- nową koncepcją Sagi biznesowej

Zachęcam oczywiście do pobrania i przeczytania całego numeru SDJ, ale dla wygodnych link bezpośredni do tekstu: pobierz.

Dla wzrokowców przydatna może być prezentacja ilustrująca architekturę systemu wykorzystującego DDD: Domain Driven Design - A place for everything and everything in its place. tekst artykułu jest niejako narracją do tej prezentacji.


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

Przy okazji zdradzę informację związaną z tematem posta. W firmie Bottega pracujemy dla Was nad upublicznieniem projektu-sampla (wraz z dokumentacją) ilustrującego w realny i niestrywializowany sposób wszystkie techniki DDD oraz kilka możliwych podejść do implementacji CqRS.

Aktualnie dla środowiska Javy istnieją tylko 2 projekty oscylujące wokół tej tematyki (za: http://cqrsinfo.com/examples) a nasz będzie charakteryzował się:
- prezentacją szerokiego wachlarzu technik DDD w różnych kontekstach
- praktycznym rozwiązaniem typowych wyzwań i problemów projektowych
- gotowym do użycia szkieletem: Spring, Maven, JPA, klienty webowe i zdalne (Android, Ajax)
- kompletna wiki opisująca ideę oraz wyjaśniająca wszystkie szczegóły techniczne, podjęte decyzje projektowe i architektoniczne oraz omawiająca możliwości zmiany podejścia i jego rozbudowy
- wsparciem dla testów integracyjnych oraz metodyki Behavior Driven Developemnt
- wsparciem dla skalowania w środowisku cloud
- racjonalnym podejściem do CqRS bez niepotrzebnego onanizmu technicznego
- i co najważniejsze: nie tworzymy kolejnego frameworka! Formą dystrybucji będzie "zaczyn" (zaczyn to coś z czego wyrasta chleb - ten prawdziwy:)
To Ty jesteś architektem i decydujesz jak wygląda Twój kod!
- sample będzie oczywiście całkowicie darmowy i otwarty

niedziela, 12 czerwca 2011

Trawienie Confitury

Na parking dotarliśmy o 0850 po 2 godzinach podróżny na dystansie 170km (widocznie gdzieś po drodze nastąpiło lokalne zagięcie czasoprzestrzeni). Następnie udaliśmy się do punktu rejestracji na 3. piętrze...

STOP!

Przepraszam, zapomniałem, że blog to nie zeszyt do polskiego, a post to nie sprawozdanie z wycieczki do muzeum w 4. klasie podstawówki;P



Na wstępie gratulacje i uznanie dla organizatorów za rozmach oraz podziękowania dla wolontariuszy.





Chciałbym podzielić się przemyśleniami z kilku prezentacji:

Pisz po pijaku, przeglądaj na trzeźwo
Bezkompromisowa i nonkonformistyczna forma. Wspaniała interakcja z publicznością, bez puszenia się i pokazywania jaki to ja jestem mądry. Doskonałe zakończenie dnia.

W momencie kiedy Piotr wniósł sześciopak piwa i żołądkową (bo poprzednicy rozdali wszystkie gadżety przeznaczone na nagrody dla uczestników) pomyślałem tylko: "wiedz, że coś się dzieje":)

Na prezentacji mieliśmy błyskotliwą syntezę dwóch - popularnych ostatnio w "miękkim" IT - koncepcji:
- Model mózgu składającego się z "procesorów" Rich i Linear
- Model kompetencji Braci Dreyfus
Synteza polegała na postawieniu tezy, że ekspert w danej dziedzinie (piąty poziom Dreyfus) myśli nad problemem głównie "procesorem" Rich.
Nie wiem czy istnieją badania potwierdzające tą hipotezę, ale mnie się podoba, bo wydaje się brzmieć sensownie - póki co "kupuję to".
To do czego dotarłem w literaturze tematu i co wiadomo na pewno, to fakt, że ekspert na pewno czasem (w twórczym uniesieniu) myśli mniej, jest to zjawisko tak zwanego "lśnienia" polegające na tym, że podczas małej aktywności mózgu (zużycie energii) dochodzi do wykonania dużej i przełomowej pracy intelektualnej. Zjawisko to można obserwować na rezonansach.

Widziałem duże zainteresowanie publiczności, więc polecam materiały:
- Pragmatic Thinking and Learning: Refactor Your Wetware - dowiecie się z niej na temat modelu R/L oraz kilkunastu innych arcyciekawych i przydatnych w życiu sprawach. Autor dokonał syntezy wieli zagadnień z psychologii, socjologii, kognitywistyki podając je na tacy tak abyśmy nie musieli już sami szukać. Najlepsza książka jaką czytałem w zeszłym roku. Książki pisane przez programistów zawsze są dobre...
- Developing Expertise: Herding Racehorses, Racing Sheep - prezentacja na temat Dreyfus.
Materiał z kategorii "musisz zobaczyć".
- Wspinaczka do profesjonalizmu - artykuł na temat Dreyfus, który popełniłem w zeszłym roku dla Software Developer's Journal.
Miło było usłyszeć na prezentacji kilka odniesień do tekstu:)

Wracając do prezentacji Piotra, warto zapamiętać dwie rady praktyczne - techniki na uruchamianie Rich "procesora":
- odwracanie problemu: jeżeli nie wiemy jak zoptymalizować kod, to może zastanówmy się jak go spowolnić; jeżeli nie wiemy jak zaprojektować ergonomiczne GUI, to zastanówmy się jak zaprojektować je w sposób ultra-autystyczny.
Dlaczego to działa? Odsyłam do książki "Pragmatic Thinking and Learning" a później dalej...
- pair programming: niewiele osób uświadamia sobie, co się dzieje podczas programowania w parach. Mianowicie driver programując (czyli myśląc symbolicznie) pracuje na swoim "linearnym procesorze" a pilot zwolniony z tych czynności może uruchomić "procesor rich" i dokonywać myślenia syntetycznego na zasadzie nieświadomego pattern matching.




Play!Framework - ewolucja w świecie aplikacji webowych
Można opowiedzieć o frameworku webowym w sensowny i poukładany sposób tak aby było od razu wiadomo o co chodzi i kiedy oraz do czego mogę go użyć?
Można!
Brawa dla Wojtka. Konkretnie, na temat, dobrze dobrane przykłady kodu, dobre rysunki, szeroki zakres wiedzy i wszystko w 45 min! Wyszło lepiej niż filmiki na oficjalnej stronie frameworka.
Szczerze mówiąc to zacząłem rozważać Play jako narzędzie do pewnych klas problemów. Dzięki Wojtek.


Warto zwrócić uwagę na prezentację jako wzór do naśladowania:
- kod na Youtube z komentarzem na żywo prowadzącego (na pewno się nie wywali i nie będziemy tracić czasu na słuchanie nieśmiesznych tłumaczeń, że na prezentacji nigdy nie działa)
- szeroki wachlarz tematów do omówienia do wyboru wg zainteresowania słuchaczy (z uwagi ograniczony czas prezentacji).

Jeszcze raz brawo.



Quo Vadis IT
Pana Tomasza pamiętam jeszcze z zamierzchłych czasów studenckich, gdy przyjeżdżał na nasze rodzime uczelnie i priczował na temat technologii Microsoftu. Dałem się wówczas uwieść - ale tylko na chwilę:)

Prezentacja bardzo ciekawa, z uwagi na tematykę. Spojrzenie na branżę IT z wysokości 10km, co pozwala zauważyć powtarzające się w czasie patterny.

Widać było też na jakim poziomie i jak wnikliwie MS analizuje potrzeby oraz nawyki Userów (prywatnie i w pracy) oraz jak dobrze rozumie przemiany społeczne i mentalne zachodzące w czasie.

Miazga. My robaczki siedzimy sobie i męczymy się z kodzikiem, podczas gdy wysoko ponad naszymi głowami ktoś obserwuje i planuje rzeczywistość na kilkanaście lat do przodu.




Re-fuck-toryzacja czyli sprowadzanie sp****go kodu na właściwe tory
Paweł - dzięki za odniesienie do posta na temat radzenia sobie ze złożonością.
Muszę jednak zwrócić uwagę, że to co wyszło podczas refaktoryzacji to nie była Strategia a raczej zmodyfikowany Chain of Responsibility. Zmodyfikowany w taki sposób, że każde ogniowo łańcucha odpowiadało na pytanie "czy umiesz zająć się problemem", a jeżeli tak to "zajmij się". Czasem stosuję takie konstrukcję - łańcuch zarządzany przez "managera" - zębatkę.

Taka "zębatka" może być sama w sobie implementacją interfejsu strategii. Czyli mamy złożenie 2 patternów: strategia na wyższym poziomie (wariacje rozwiązania dużego problemu), a jedną z implementacji strategii może być taka zębatka zarządzająca łańcuchem małych ogniw, które coś tam sobie liczą (mikro problemiki wchodzące w skład jednego z wariantu rozwiązań problemów wyższego rzędu).

Teledysk na koniec - rotfl. Dobre zdjęcia, ładny dom:)


Co do mojej prezentacji, to jak zwykle: trema, przez którą wychodzi inaczej niż się planowało. Gadzi mózg podpowiada, że jeżeli stoisz sam bez broni i bez schronienia przed liczną grupą jakiś osobników to najpewniej za chwilę zginiesz. Ehh instynkt.


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

Przy okazji podzielę się jednak ciekawą obserwacją odnośnie psycho-akustyki (którą ostatnimi czasy nieco się interesuję). Z uwagi na wielkość sali, konstrukcję ścian, siłę oraz ustawienia nagłośnienia (i kilkanaście innych niesprzyjających uwarunkowań pomieszczenia) pojawił się efekt echa. Nie pogłosu, który jest do zniesienia a echa, które jest dla mówiącej osoby zabójcze.

Jako, że jestem tak zwanym słuchowcem (nie jest to takie proste, ale przyjmijmy na potrzeby posta, że jest coś takiego jak słuchowcy) to taki efekt nie jest tylko drażniący. U mnie niemal uniemożliwia mówienie. Przez chwilę myślałem, że się rozpłaczę ucieknę ze sceny hehehe.

Nie wiem czy ktoś włączył tłumienie fal obitych, ale nie widziałem nikogo majstrującego przy wzmacniaczach. Jednak po kilku minutach efekt echa zniknął. Ehh mózg ma niesamowitą zdolność do kompensowanie bodźców. A to co słyszymy jest tylko tym co nam się wydaje:)

środa, 8 czerwca 2011

Degustacja Confitury


Confitura odbędzie się 11 czerwca ale już dziś możecie sprawdzić czy warto przyjść na jedną z prezentacji.

Abstrakt: Domain Driven Design - Wszystko ma swoje miejsce i wszystko jest na miejscu




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

W branży można spotkać się z dwoma podejściami do prezentacji:
- niespodzianka
- możliwość obejrzenia wcześniej

Ja preferuję drugie podejście z tego samego względu, dla którego sprawdzam dema gier, czytam wyrywki tekstu z książek w księgarni oraz sprawdzam recenzje filmów - po prostu oszczędność czasu:)

wtorek, 7 czerwca 2011

Zawiązywanie sznurowadeł - robisz to źle



...sprawdź i przekonaj się, video trwa tylko 3 minuty:)

Zweryfikowałem wczoraj na butach biegowych z wyślizganymi od użytkowania sznurowadłami. Działa!

TED jak zwykle "uczy i bawi".


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

Swoją drogą ciekawe ile jeszcze takich oczywistych oczywistości robimy nie do końca dobrze...

"live long and prosper":)

poniedziałek, 6 czerwca 2011

Rekrutacja

Temat zadań rekrutacyjnych dla developerów przewija się w branży co jakiś czas. Ostatnio znowu odżył ze względu na odbicie do tak zwanego kryzysu.

Post jest głosem w dyskusji, jaka toczy się na grupie Warszawa JUG, którą to czytam namiętnie ze względu na spektrum tematów oraz aktywność członków.

Dyskusja zaczęła od pytania o słuszność lub nie wymagania wiedzy na temat sortowania kolekcji obiektów w Javie. Chodzi o użycie biblioteki standardowej/trzeciej a nie o implementację od zera sortowania bąbelkowego (bo i o takich kuriozach się słyszy).

Wydaje mi się, że dyskutowanie nad treścią zadań bez określenia kontekstu to podchodzenie do problemu od złej strony.

Zaczynając rekrutację musisz odpowiedzieć sobie na kilka pytań: kogo poszukuję, do jakich klas problemów, do jakich typów zdań, z kim ma pracować i jakie są plany na przyszłość (co do tej osoby, co do całego teamu).

Pracując w różnych firmach jako lider techniczny zajmowałem się między innymi rekrutowaniem pracowników. Straciłem rachubę, ale w sumie przewinęło się ok 100 osób. Pamiętam jakie błędy robiłem, głównie na poziomie założeń. Teraz pomagam klientom znajdować odpowiednich ludzi na określone stanowiska.

Inny skillset będzie potrzeby dla kogoś kto dodaje ficzery biznesowe a inny dla kogoś kto rozwiązuje łamigłówki na poziomie optymalizacji lub algorytmicznym. Inny dla kogoś kto projektuje systemy/frameworki a inny dla kogoś kto implementuje aplikacje. Inny dla kogoś kto implementuje sexi gui a inny dla kogoś, kto modeluje złożone domeny biznesowe. Inny dla kogoś kto kreuje kierunek dla nowych projektów a inny dla kogoś, kto utrzymuje legacy.

Na skillset składa się wiele wymiarów - znajomość języków i technologii to tylko jeden z nich. Czasem wystarczający a czasem nie (czasem pomijalny?). Temat jest generalnie bardzo szeroki i wchodzi głęboko w psychologię - np. typy osobowości, z których wynikają sposoby myślenia, predyspozycje, słabe i mocne strony. Generalnie nie ma ludzi perfekcyjnych, każdy ma słabe strony, chodzi o to aby "w boju nie wystawiać tych miękkich części na ciosy" - po prostu dobierać ludzi do zadań/wyzwań
Ale to wymaga też zrozumienia wyzwań jakie pojawią się w projekcie oraz zrozumienia cech jakie lepiej lub gorzej predysponują śmiałka do podjęcia wyzwania:)

Strategia dla teamu jest prosta: wzajemne uzupełnianie się cech - a z tego gratisowo dostajemy efekty synergiczne:)
Podstawowym narzędziem może być model Belbina - ale to dopiero początek układanki.

Ignorowanie aspektów miękkich i kompletowanie zespołu na zasadzie: "dawać mnie tu sześciopak programistów" sprawdzi się owszem w niektórych przypadkach. W rekrutacji do projektów Komisji Europejskiej w Luksemburgu jednak już nie zadziała...


Wracając do zadania z sortowaniem kolekcji przez bibliotekę standardową... Zastanówmy się co ono sprawdza. Na pewno to czy ktoś już tego używał, czyli czy otarł się o ogólne programowanie w Javie (i ew. proste wykorzystanie w algorytmach). Oczywiście kandydat mógł nie mieć do tej pory okazji sortowania niczego - zdarza się.

Skoro tak, to nie miał tez okazji przeczytania żadnej książki poświęconej programowaniu w Javie. Po prostu nie da się nie trafić na sort. Prawdopodobnie ilość artykułów jakie pochłonął jest niewielka (tak elementarna rzecz jak sortowanie pojawia się z prozaicznej konieczności nawet w zaawansowanych tekstach).

Jaki wniosek możemy wysnuć na tej podstawie... hmmm... ja się wstrzymam z wnioskowaniem, czekam na propozycje w komentarzach. Nie zakładałbym jednak, że zawsze poszukujemy kogoś, kto "traci czas" na czytanie książek...

Ale na pewno jeżeli kandydat nie potrafi podać odpowiedzi, warto sprawdzić w jaki sposób ją zdobędzie i na ile ją zrozumie.

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

Co do zadań ogólno-programistycznych to wdzięcznym tematem jest napisanie utilsa obliczającego pole prostokąta. Tak utilsa, statyczną metodę, beż żadnych Object Oriented, w przestrzeni Euklidesowej, zwykłe a * b.

Co sprawdzimy? Coś co można określić stylem.
1. nazwy parametrów - od czego zależy dobór? a,b czy może x,y albo width,height? szczegół? tak, ale jednak...
2. dobór typów. kiedy własne typy? co z jednostkami? wynik jest w kwadracie - jakie operacje są na nim dozwolone później? czy jest to problem naszego utilsa? szeroki temat do dyskusji...
3. sprawdzanie wartości wejściowych - sprawdzać czy nie, od czego to zależy?
4. nazwy, nazwy, nazwy
5. jakie wyjątki? dlaczego?
6. komentarze. a może nie ma takiej potrzeby? dlaczego?
7. testy! a może nie;P dlaczego?

Nikt nie zarzuci wymogu znajomości bibliotek (ew. junit/testng), egzotycznych algorytmów, wyrafinowanej składni, fizyki kwantowej. Wzoru na pole prostokąta jednak bym nie podawał w treści zadania;)

Tego typu zadanie oczywiście nie zaważy na przyjęciu/odrzuceniu kandydatury na stanowiska develoepra aplikacji postawionych na stosie 10 frameworków, ale potencjalnie może wskazać wygodne dla kandydata miejsce.

niedziela, 5 czerwca 2011

Obraz konkurencji

Osobiście nie miałem nigdy okazji pracować z developerami z Indii, ale z opowieści wielu znajomych z branży wnioskuję, że jest to ciekawa przygoda...

Natrafiłem dziś na artykuł, którego autor zdaje się znać sytuację od podszewki: Guru i trzej idioci.

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

Tekst można polecić również tym, którzy narzekają na polski system edukacji:)

środa, 1 czerwca 2011

Sposoby enkapsulowania złożonej logiki biznesowej

W ostatnim poście poruszyłem pewne podstawowe zagadnienia z zakresu projektowania obiektowego, ale jak słusznie zauważyli komentatorzy przykład jest na tyle trywialny, że narzucające się proste rozwiązania są w zupełności wystarczające.

Podejdziemy do problemu raz jeszcze, tym razem w bardziej realistycznym kontekście aplikacji biznesowej.

Mamy zatem ten nieszczęsny OrderItem - nieszczęsny, ponieważ przykład pochodzi z książki, którą ostatnio recenzowałem. Klasyczny model zamówienia: Order-OrderItem-Product


W książkowym przykładzie OrderItem jest obiektem domenowym (rich model) i posiada oprócz stanu również zachowanie - odpowiedzialności biznesowe. Autor książki nawiązuje do Domain Driven Design, dlatego będę się posługiwał Building Blockami modelowania DDD.

Nasz OrderItem zawiera metodę getShippingCost(), która nie jest getterem a metodą biznesową - oblicza koszt dostawy danej pozycji na zamówieniu.

Sugerowana w książce rozbudowa modelu to dodanie nowych klas dziedziczących po OrderItem, które zmieniają sposób liczenia kosztu. Problemy z tym podejściem opisałem w poprzednim poście, w skrócie: w takim obiekcie biznesowym mamy wiele odpowiedzialności, więc prowadzanie dziedziczenia aby zmienić jedną z nich szybko doprowadzi do eksplozji kombinatorycznej bytów.

<dygresja>
Zacznijmy od tego, czy w ogólne taka metoda powinna należeć do tej klasy? W rzeczywistym systemie obliczenie kosztów dostawy zależy zapewne od wielu czynników - nie tylko od zamawianego produktu, ale również od tego kim jest klient, od miejsca dostawy, od reszty zamówienia itd.
Być może cała wiedza znajduje się w klasie OrderItem... Być może wyżej - w Order... Być może nie... wówczas należy wynieść cały problem do osobnego SerwisuBiznesowego (BuildingBlock modelowania DDD).

Nawet jeżeli dziś cała wiedza znajduje się w OrderItem czy nawet w Order, ale w przyszłości zmienią się wymagania i będziemy musieli implementować dziwne akrobacje aby w OrderItem/Order zdobyć potrzebne do obliczeń obiekty.

Generalnie serwis rokuje na lepszy design modelu (serwis biznesowy jest częścią modelu w DDD). W DDD nie chodzi o to aby całą logikę rozsmarować po encjach/agregatach/vo. Nic podobnego. Prosta reguła "kciuka" dla początkujących może być taka: encje/agregaty/vo posiadają metody używane wielokrotnie. Specyficzne metody używane jeden raz znajdują się w specyficznych serwisach biznesowych

Jednak te rozważania nie mają wpływu na dalszą część posta. Abstrahując od tego, którym miejscu umieścimy odpowiedzialność obliczeń wciąż możemy stosować techniki opisane poniżej.

W dalszej części, dla uproszczenia, zakładamy, że większość potrzebnej wiedzy znajduje się w OrderItem.
</dygresja>


W realnej aplikacji obliczenie kosztu dostawy:
- zależy od wielu czynników (rodzaj produktu, klient i jego rabaty, miejsce docelowe, składowe zamówienia, historia zamówień itd)
- jest złożone (załóżmy kilkanaście-kilkaset linijek kodu)

Ta więc rozważania z poprzedniego posta (i komentarzy) gdzie proponowaliśmy switche albo Mapy strtegii się nie aplikują.

Przy standardowym podejściu kod będzie wyglądał mniej więcej tak:

class OrderItem{
  Money getShippingCost(){
    if if if if if
      //17 liniek obliczen
    if if if if
      //50 liniek obliczen z ifami
  }
}
... i wcale nie spodziewajmy się "eleganckiego" switcha, który załatwia sprawę. Mamy tutaj do czynienia z potworkiem rzędu setek linijek, brak ustalenia jednego poziomu abstrakcji, nieustanne skoki mentalne po różnych poziomach oraz potencjał na to, że biznes będzie się komplikował i z czasem wyhodujemy ośmiotysięcznika.

Generalnie przy standardowym podejściu kodzik będzie przeplatał w sobie 3 rodzaje odpowiedzialności:
1. zdecydowanie który scenariusz/algorytm obliczania kosztu zastosować
2. sam algorytm
3. ew. pozyskanie dostępu do danych potrzebnych do obliczeń

Czyli w jednym miejscu mamy 3 rodzaje zależności, o których pisze Misko Hevery.
- colaboration
- construction
- call


Aby uniknąć tego poziomu smutnej złożoności, proponowane w poprzednim poście rozwiązanie (czwarte) sugeruje aby:
1. odseparować samą logikę obliczenia kosztu od reszty kodu.
Wprowadzamy interfejs Strategii, np

interface ShippingCostCalculator{
  Money calculateCost(...);
}

2. kawałki kodu stanowiące każdy z algorytmów pakujemy do osobnej klasy implementującej ten interfejs, np ForeginShippingCostCalculator, LargeItemShippingCostCalculator

2.a co jeżeli wysyłamy duży przedmiot za granicę? tworzymy trzecią klasę ForeginLargeItemShippingCostCalculator? Nie! Z pomocą przychodzi Decorator Design Pattern.

ShippingCostCalculator calculator = new ForeginShippingCostCalculator(new LargrItemShippingCostCalculator());
}

3. kawałki logiki wybierającej, którą konkretną politykę stworzyć chowamy w Fabryce.
I nie jest jeden switch ale kłębowisko ifów

Możemy fabrykować cały agregat:
//fabrykowanie całego agregatu

  class OrderItemFactory{
  OrderItem createOrderItem(...){
    ShippingCostCalculator calculator = //100 ifów;
    return new OrderItem(calculator);
  }
}

albo jedynie strategię:

//fabrykowanie jedynie strategii

  class ShippingCostCalculatorFactory{
  ShippingCostCalculator createShippingCostCalculator(...)
    ShippingCostCalculator calculator = //100 ifów;
    return calculator;
  }
}

Wybór podejścia - co fabrykować: agregat czy strategię zależy do tego w którym momencie mamy wiedzą potrzebną do wyboru kalkulatora. Przed czy dopiero po powołaniu do życia OrderItema.

Generalnie lepiej jest posługiwać się Agregatem i ukrywać szczegóły typu istnienie strategii, ale nie zawsze jest to możliwe.

Tutaj jako agregat traktujemy OrderItem a nie Order, bo tak to wygląda w rzeczywistych systemach, np. klasy ERP - widziałem.

3a. co jeżeli aby wybrać konkretny kalkulator potrzeba znać np aktualnie zalogowanego użytkownika? Lub ogólnie: jakiś kontekst, którego brakuje w OrderItem?
Taka Fabryka może być komponentem zarządzanym (EJB, Speing Bean, itd) i możemy do niej wstrzykiwać potrzebne informacje.

class ShippingCostCalculatorFactory{
  @Inject
  LoggedUser loggedUser;  //logged user to obiekt apliakcyjny (niebiznesowy), trzymany w sesji

  ShippingCostCalculator createShippingCostCalculator(...)
    //if (loggedUser.role == ADMIN)
    ShippingCostCalculator calculator = //100 ifów ;
    return calculator;
  }
}

3b. co jeżeli któraś konkretna strategia obliczania kosztu potrzebuje informacji o zewnętrznym kontekście (np zalogowanym userze)? Chodzi o przypadek gdy metoda z interfejsu strategii nie ma w parametrze tego co potrzebuje implementacja. Fabryka może przekazać kontekst do konkretnej strategii przez jej konstruktor.

class ShippingCostCalculatorFactory{
  @Inject
  LoggedUser loggedUser;  //logged user to obiekt apliakcyjny (niebiznesowy), trzymany w sesji

  ShippingCostCalculator createShippingCostCalculator(...)  
    ShippingCostCalculator calculator = //100 ifów ;
    calculator = new XyzCalculator(loggedUser.getUserId());
  
    return calculator;
  }
}


Podsumowując:
Rozdzielamy silny coupling (współpracy, tworzenia, wywołania) do osobnych "pudełek".
Strategie: tylko obliczenia;
Fabryki: ecydowanie o typie strategii oraz ewentualnie składanie obiektów (przekazywanie szerszego kontekstu do strategii lub dekorowanie strategii)

Dzięki rozdzieleniu możemy niezależnie testować jednostkowo Agregaty i Strategie (Polityki w nomenklaturze DDD). A to za prawą fabryk, w których mieszkają operatory new. Agregaty są od nich wolne, więc mamy możliwość mockowania/stubowania strategii na czas testów.



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

Tak jak pisałem w poprzednim poście: wprowadzenie Strategii zaczyna się nam opłacać dopiero przy złożonych modelach biznesowych. Pokazałem tutaj dodatkowo złożenie Strategii i Dekoratora wraz z idiomem Fabryki oraz wystrzykiwaniem zależności. Dopiero w synergii technik tkwi prawdziwa siła.

Ważne jest to aby w ogóle modelować złożoność. Jeżeli nie modelujemy złożonego problemu a jedynie "zamiatamy go pod dywan" w postaci ukrytych gdzieś głęboko ifów to model szybko upada na twarz;)

Podstawowa zasada Domain Driven Desigm mówi: make explicit what is implict. Czyli wydobywajmy ważne koncepcje biznesowe na powierzchnię. Nie ukrywajmy ich w ifach w linijkacj od 5000 do 6000.

A czy jest coś ważniejszego w modelu biznesowym niż różne sposoby liczenia pieniędzy?;)

Na koniec jedna uwaga: zawsze gdy pokazuję na warsztatach tego typu przykłady część uczestników jest wręcz urzeczona "pudełkowaniem" złożonej logiki w małe, eleganckie pudełeczka. Inni z kolei preferują jedno pudło (np procedurę) ponieważ łatwiej im ogarnąć jedno pudło niż wiele małych, nawet kosztem tego, że w tym jednym pudle jest, powiedzmy delikatnie - bałaganik.

Wszyscy różnimy się mocno pod względem oceniania tego co jest proste. Więcej na ten temat: O programiście-pisarzu i programiście-konstruktorze.

Koszt Dostawy

Odnośnie poprzedniego posta - Jacek L. zadał pytanie o przykład podejścia do liczenia kosztu dostawy.

Mamy kilka możliwości...

Załóżmy, że ma my klasę:

class OrderItem{
  //pola
  metodaBiznesowa1(){..}
  metodaBiznesowa2(){..}
  metodaBiznesowa3(){..}
}


Co jeżeli mamy różne rodzaje/odmiany itemów, gdzie zachowanie tych metod różni się - innymi słowy algorytmy są różne?

1. Rozwiązanie na switchach:

metodaBiznesowa1(){
  switch(jakisParametr){
    case x: return ...
    case y: return ...
  }
}

Konsekwencje: wszelkie zmiany wymuszają "grzebanie" w corowym kodzie biznesowym, czyli jego "brudzenie" czyli ponowne testowanie (nie jest to problem jeżeli mamy pokrycie testami automatycznymi:)

2. Rozwiązanie struktura i algorytmy danych
Generalnie podobne do poprzedniego z tym, że z wyniesieniem kodu biznesowego na zewnątrz - podane dla uzupełnienia wachlarza możliwości:

class OrderItem{
//gettery i settery
}

class BusinessService1{
  doSth(OrderItem oi){
    switch(oi.getSth())
    //...
  }
}

3. SŁABE (ale to zależy od szerszego kontekstu) rozwiązanie z dziedziczeniem:

Tworzymy specjalne klaski dziedziczące po OrderItem, w których nadpisujemy odpowiednie metody biznesowe.

Konsekwencja: mnożenie bytów.

Co jeżeli:
- OrderItem1 nadpisze metodę metodaBiznesowa1
- OrderItem2 nadpisze metodę metodaBiznesowa2
a OrderItemBum chce mieć obie metody biznesowe 1 i 2 takie jak klasy wymienione poprzednio?
Eksplozja kombinatoryczna!

Dziedziczenie jest dobre, ale wówczas gdy klasa ma ściśle określoną odpowiedzialność (jeden powód do zmiany). Wówczas nie ma możliwości zajścia eksplozji kombinatorycznej oraz mamy zwykle pewność zachowania Liskov Substitution Principle.

Co jeżeli klasy dziedziczące są wymagane ponieważ dodają nowe atrybuty?
Wówczas rozwiązanie z dziedziczeniem zaczyna się bronić. Jednak wciąż może dojść do eksplozji klas.
Wówczas lepiej łączyć rozwiązanie z dziedziczeniem z rozwiązaniem 4.

Innym podejściem jest unikanie dziedziczenia i zastosowanie Archetypu Biznesowego Product.

4. Wprowadzenie wzorca strategii.

class OrderItem{
  metodaBiznesowa1(){
    return strategiaBiznesowa1.go(...);
  }
  metodaBiznesowa2(){
    return strategiaBiznesowa2.run(...);
  }
  metodaBiznesowa3(){..}
}

StrategiaBiznesowa1,2 są interfejsami. Konkretne implementacje zajmują się szczegółami.
Unikamy eksplozji kombinatorycznej z podejścia trzeciego dlatego, że w tym przypadku ilość klas to suma możliwych strategi dla każdej metody biznesowej a nie ich iloczyn.

Ale zostawmy autystyczne miary ilościowe... Ten design się po prostu "czuje". Tak jak w naiwnym szkolnym przykładzie: samochód zawiera skrzynię biegów - pasującą do interfejsu (śruby, tryby). Samochód w żadnym wypadku nie dziedziczy po skrzyni biegów:)
//Chociaż kiedyś na rekrutacji ktoś na pytanie o nieksiążkowy przykład dziedziczenia odpowiedział mi: "telefonistka dziedziczy po telefonie".


Skąd OrderItem posiada strategieBiznesowe?

a) OrderItem pobiera z fabrykStrategii - niedobre ze względu na testability

b) OrderItem ma je "wstrzyknięte" z zewnątrz przez FabrykiItemów, które go tworzą lub przez RepozytiumItemów, które pobierają go z bazy.

ew. Fabryki/Repozytoria tworzą nadrzędny agregat (np Order), który zawiera w sobie itemy, ale to zależy od domeny - mechanizm jest ten sam.

To jaką staregięBiznesową "wstrzyknąć" jest decyzją biznesową, tak więc Fabryki/Repozytoria zawierają taką logikę odciążając coupling tworzenia od coplingu używania.
Więcej o rodzajach couplingu dowiemy się od ekspertów Google.

Warto zauważyć, że sama Strategia semantycznie jest niczym innym jak Funkcją (w kontekście programowania funkcyjnego) przekazaną na prawach First Class Citizen. Jedynie syntaktycznie mamy niezręczność wynikającą ze składni Javy;)

Wprowadzenie Wzorca Strategii zaczyna się nam opłacać pod warunkiem, że:
- spodziewamy się pojawiania się kolejnych strategii w przyszłości
- chcemy testować jednostkowo niezależnie logikę OrderItema od logiki StrategiiBiznesowych


Pośrednim rozwiązaniem prowadzącym w kierunku wzorca - dającym potencjał na łatwy refaktoring w przyszłości jest:
1. wyciągnięcie interfejsu
2. dostarczenie jedynej implementacji jako serwisu ze słczami w stylu rozwiązania drugiego.

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

O opłacalności wprowadzenia Strategi możemy mówić również na poziomie modelowania.

Np w DDD nie mówi się Strategia lecz Polityka. Polityki są częścią modelu - obok encji i kilku innych "klocków".
Skutkuje to tym, że zaczynamy pokazywać wariacje istotnych zachowań biznesowych w modelu (diagramach, itd) a co za tym idzie zaczynamy o nich mówić (wchodzą do Ubiquotus Language)
Co najważniejsze: zaczynamy zauważać te arcy-ważne z biznesowego punktu widzenia komponenty - już nie siedzą w słiczach w linijce numer 5000 w serwisie-ośmiotysięczniku;P

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:)

czwartek, 19 maja 2011

Stosowalność Wzorców Projektowych

Temat Wzorców Projektowych budzi wiele emocji. Niektórzy są ich zagorzałymi fanami, inni podchodzą z pogardą twierdząc, że w rzeczywistym świecie są bezużyteczne.

Wzorce Projektowe są jedynie narzędziem, a emocjonalne podchodzenie do "młotka" jest po prostu nieracjonalne. Dlatego zaproponuję nieco inne podejście - kontekstowe.

Swoją drogą ciekawe, że podczas rozmów coraz częściej słyszę z ust wytrawnych programistów wyraz irytacji nad bezkontekstowym podejściem naszej branży do wszelkich technik, praktyk, metodyk, produktów, rozwiązań. Mówi się, że jesteśmy sterowani modą bardziej niż Mediolan lub Paryż;)
Odczuwa się silne zmęczenie marketingiem.

W swojej karierze programistycznej miałem okazję pracować nad systemami różnej klasy. Przez klasę rozumiem klasę problemów jakie stanowiły główne wyzwania. Ale to praca trenera i konsultanta dała mi dostęp do wglądu w spektrum klas problemów, w ilości jaką standardowo kolekcjonuje się w okolicach emerytury.

Piszę o tym aby przejść do kontekstu stosowalności Wzorców Projektowych. Z moich obserwacji wynika, że kontekst ten jest rozpięty na 2-wymiarach: wspomnianej już klasie problemu oraz w wymiarze osobowości (otrzemy się o aspekty psychologii programistów).


KONTEKST KLASY PROBLEMU

Jeżeli jesteśmy w kontekście aplikacji biznesowych, a nasza praca polega na implementowania kolejnych wymagań, to stoją przed nami wyzwania typu:
- okiełzanie nielogicznych wymagań
- modelowanie narzędzia dla biznesu (naszej aplikacji), który działa z natury procesowo
- tworzenie intuicyjnego GUI
- wpasowanie się w istniejącą bazę danych, która była projektowana przed III Wojną Mandżulską, w czasach gdy nikt jeszcze tak na prawdę nie rozumiał domeny.

W tym kontekście często nie potrzebujemy nawet używania technik OO - aczkolwiek programujemy z użyciem obiektów (bo niby jak inaczej w mainstreamowych językach?).

Z szerokiego wachlarza Wzorców Projektowych możemy posłużyć się w tym kontekście - w pewnych bardziej złożonych - przypadkach:
- Strategią - jeżeli mamy odmiany tego samego zachowania/czynności biznesowej. Podejście promowane przez ten wzorzec staje się ostatnio modne za sprawą języków funkcyjnych. By czymże innym na poziomie syntaktycznym jest przekazanie obiektu implementującego interfejs z jedną metodą niż zwykłym przekazaniem funkcji na poziomie semantycznym?
- Łańcuchem Odpowiedzialności - łańcuch zaczyna się nam opłacać gdy chcemy modelować podejmowanie decyzji o tym, który z wariantów logiki biznesowej chcemy wykonać. Opłaca się gdy spodziewamy się modyfikowania ilości wariantów.
- Specyfikacją - pozwala na przejrzyste modelowanie złożonych reguł określających czy dany obiekt biznesowy powinien podlegać jakiemuś przetwarzaniu. Opłaca się gdy reguły są zawiłe i istnieją pomiędzy nimi zależności logiczne. Złożony wzorzec, że wystąpić kilka razy w całym kodzie.
- Stanem - bardzo złożony wzorzec, może wystąpić raz, może dwa w średniej wielkości systemie. Pozwala na przejrzyste modelowanie maszyny stanów, dla obiektów biznesowych, które mają np różne statusy i w zależności od statusu a) mogą lub nie przechodzi w inne oraz b) inaczej się zachowują. Opłaca się gdy mamy wiele statusów i zawiła logikę sterującą zachowaniem zależnym od statusów.
- Metodą Szablonową - prosty wzorzec, klasyka polimorfizmu, pozwala modelować różne warianty algorytmów biznesowych. Z czasem gdy sytuacja się komplikuje przestaje się opłacać i warto dokonać refaktoringu do Strategii.
- Fasadą - trywialny wzorzec, który nie zasługuje na miano wzorca, ale wygodnie upraszcza to co najpierw skomplikowaliśmy;)
- Dekoratorem - wprowadzenie dekoratora zaczyna się nam opłacać gdy chcemy !w runtime! (nie podczas programowania czy kompilacji) decydować o dodawaniu nowych zachowań. Bardzo silny, ale rzadko logika biznesowa daje się tak elegancko zamodelować.

Pomijam Singletona, który w większości przypadków jest antywzorcem zabijającym testowalność. Poza tym jego istnienie w modelu biznesowym rzadko bywa sensowne.

O ile pojawienie się w aplikacji biznesowej wielu przypadków wykorzystania Strategii, Metody Szablonowej, Fasady jest normalnym zjawiskiem o o tyle duża ilość Łańcuchów, Dekoratorów czy Stanów wskazuje na overengineering i "chorobę wzorcową".

Pozostałe wzorce z katalogu nie mają zbyt dużej szansy na potencjalne pojawienie się w aplikacji biznesowej - po prostu służą do rozwiązywania problemów innych klas.

W aplikacjach biznesowych za to więcej pożytku niosą wzorce innego rodzaju:
- sposoby modelowania, oraz strategicznego modelowa z zestawu Domain Driven Design
- archetypy modeli biznesowych
- najlepsze praktyki odnośnie Usability



Jeżeli natomiast jesteśmy w kontekście tworzenia oprogramowania klasy: platforma, framework, server, wysokowydajny dedykowany portal, oprogramowanie specjalistyczne typu: narzędzia do projektowania/komponowania, itp wówczas stajemy przed problemami zupełnie innej klasy:
- otwartość na rozbudowę z jednoczesną ochroną publicznego api przed zmianami core,
- wydajność, oszczędność pamięci,
- bezpieczeństwo,
- giętkość api,
- wyważenie ograniczeń
- itp.

Przeglądając kody źródłowe tego typu aplikacji możemy dostrzec wiele wystąpień wzorców lub struktur do nich podobny zmodyfikowanych z powodu pewnych intencji. Czasem są po prostu nazwane inaczej z powodu niewiedzy autora - ale ciekawe jest, że wpadł na pewne pomysły niezależnie, nie znając wzorca wcześniej.

Oprócz wspomnianych wcześniej wzorców opłacalne w tym kontekście dodatkowo mogą być:
- Builder - aby odseparować plany budowy obiektów od ostatecznego kształtu konstrukcji. Opłacalny gdy przewidujemy pojawianie się kolejnych "produktów"
- Visitor - aby umożliwić użytkownikom api wprowadzanie nowych zachowań poprzez dodawanie swojego kodu zamiast modyfikowania biblioteki/frameworka. Double Dispach dla ubogich np. w celu otwarcia core na rozbudowę
- Proxy - aby umozliwić model programistyczny w stylu Aspect Oriented
- Mediator - śmietnik na chaos sieci współpracujących obiektów. Jeżeli musisz mieć chaos, to explicite ogranicz jego zakres.
- Most - jeżeli masz niestabilny core i chcesz zaryzykować publikowanie stabilnego api
- Prototyp - jeżeli chcesz fabrykować wiele klas i nie chcesz tworzyć analogicznej do nich, lustrzanej hierarchii fabryk.
- Flyweight - jeżeli musisz mieć ogromną ilość obiektów, ale część ich pół możesz uwspólnić, ponieważ nie jest to ich zmienny stan - oszczędzasz pamięć.


Podając przykłady dla obu klas problemów chciałem pokazać, że po prostu inni programiści/projektanci/architekci mogą żyć w innym świecie. To że coś jest dla nas bezużytecznie, nie oznacza, je jest to bezużyteczne w ogólności.

Wrzucanie wszystkich programistów do jednego worka (najlepiej wspólnego worka z Informatykami;) powoduje utratę kontekstu a co za tym idzie rozmycie wymaganych do danego zadanie kompetencji.

Warto też zastanowić się nad klasami problemów jakie nas intrygują i rozwijać odpowiedni skillset - bez odpowiedniego poziomu kompetencji pewne klasy projektów będą dla nas zawsze zamknięte.



KONTEKST OSOBOWOŚCI

Chyba każdy programista przyzna, że zależy mu na zaprojektowaniu najprostszego rozwiązania. Być może to poszukiwanie prostoty jest tym, co przyciąga ludzi do programowania - no może za wyjątkiem robotników umysłowych napędzanych chęcią łatwego (hehe naiwni) zarobku.

Problem leży w postrzeganiu prostoty.
Niektórzy mówią, że jakieś podejście jest proste jeżeli można szybko zacząć się w tym orientować. I nie ważne, że później okaże się to pogmatwane w szczegółach. Ważne aby szybko zacząć "łapać" o co chodzi, a później - trudno, świat jest pogmatwany.
Inni mówią, że coś jest proste, jeżeli u swoich założeń ma dające się dokładnie zrozumieć fundamenty, które pozwalają wyobrazić sobie całe rozwiązanie mentalnie. Nie ważne, że może na początku trzeba zainwestować czas - dużo czasu - w zrozumienie pryncypiów i nowych rzeczy, które powierzchownie wydają się złożone. Jeżeli później okaże się, że było to proste, to mówią, że jest to proste.

Które podejście jest lepsze - jak zwykle, zależy to od kontekstu. W kontekście IT np. może zależeć od ograniczeń czasowych, czyli tego ile czasu możemy poświęcić. Innym ograniczeniem może być opłacalność w perspektywie czasu (czasem robimy eksperyment biznesowy i zobaczy jak się to rozwinie:). Dlatego w każdym przykładzie wzorca pisałem o tym kiedy może się nam opłacać wprowadzenie danej konstrukcji.

Strategia poznawcza, jaką przyjmuje nasz mózg w podejściu do prostoty (musi być proste od razu, musi być proste docelowo) wiąże się mocno z typem naszej osobowości.
- część z nas jest zorientowana na postrzeganie podobieństw, inni na postrzeganie różnic - model meta-programów .
- część z nas jest otwarta na nowe doświadczania, inni są bardziej konserwatywni - model Big 5.
- część z nas ma swój wewnętrzny świat, w którym modeluje postrzeganą rzeczywistość, inni są nastawieni na natychmiastowe działanie i niemal namacalne doświadczanie - model MBTI
- część z nas żyje w przyszłości, w jakimś jej modelu, inni żyją tu i teraz w czasie.


MODEL DREYFUS


O modelu kompetencji Braci Dreyfus pisałem już kilkakrotnie. Tutaj przytoczę tylko poziom Competent. Rozwijając jakąś umiejętność, na tym poziomie w naturalny sposób zaczynamy szukać najlepszych praktyk, wzorców (nomen omen). Tak więc naturalne jest, że rozwijając kompetencję pod tytułem "Programowanie/Projektowanie OO" w pewnym momencie zaczniemy szukać wzorców.
Na kolejnych etapach rozwoju tej kompetencji będziemy zadawać pytanie, kwestionować, szukać szerzej. Jednak na trzecim poziomie (Competent) katalog wzorców daje dużego kopa i pozwala po prostu zoptymalizować proces uczenia się. Jak powiedział Jim Copelin, z czasem odrzucasz "boczne kółka od swego rowerka" i przestajesz mówić o wzorcach, po prostu intuicyjnie robisz to co należy.


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

Czasem można spotkać głosy, że wzorce projektowe są "zbyt akademickie". Hmm moim zdaniem wręcz odwrotnie. Do katalogu wzorców nie trafiają żądne rozwiązania, które nie są odkryte i przedyskutowane przez community praktyków. Oczywiście, stosując zbyt wyrafinowany wzorzec do zbyt błahego problemu będziemy odczuwać przerost formy nad treścią. Ale wówczas powodem jest nieumiejętne użycie w nieodpowiednim kontekście - czyli jego niezrozumienie.

Aby nabrać wyobrażenia o tym, co to znaczy "akademickie" podejście do OO należy zapoznać się z tym tekstem.