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.

9 komentarzy:

ToJaJarek pisze...

Kolejny bardzo dobry artykuł, jako analityk stosuję głównie DDD w tym:
- MVC (jako architektura całości)
- agregat
- domain model
- repository
- fabryka/prototyp (zależy od "klasy" problemu :))
- value object
- i troszke "nowy" State machine w systemach workflow

Unknown pisze...

Sławek, muszę przyznać, że wymiękam przy tych modelach meta programów, Big 5, MBTI i innych Dreyfusach czy Belbinach, skąd Ty to wszystko bierzesz???

Mnie nie starcza czasu nawet na przejrzenie newsów o jednym z tysiąca frameworków webowych...

A tak na serio, nie myślałeś kiedyś o jakimś wykładzie na konferencję związanym z aspektami psychologicznymi/samorozwoju/modeli uczenia itp. w odniesieniu do specyfiki branży software engineering? Przecież coraz więcej chętnych na tego typu tematy. A to wymaga przekrojowej wiedzy, szerokiego doświadczenia w branży i, nie bójmy się tego słowa, erudycji.

A, z całym szacunkiem, DDD i CQRS to relatywnie łatwe tematy, mnóstwo materiałów i przykładów w sieci. Choć oczywiście temat wart uwagi.

p.s.
Jednak z tym onanizmem javowców frameworkami i bibliotekami masz trochę racji, choć początkowo protestowałem, to jednak jak obserwuję ostatnie javowe konferencje, to mało jest o architekturze/wzorcach/archetypach, za to dużo o Buzzwords typu cloud, nosql.
A im więcej czytam o zagadnieniach koncepcyjnych typu ddd, cqrs, itp, tym częściej trafiam na strony/podcasty .netowców.

Sławek Sobótka pisze...

>Sławek, muszę przyznać, że wymiękam
>przy tych modelach meta programów,
>Big 5, MBTI i innych Dreyfusach czy
>Belbinach, skąd Ty to wszystko
>bierzesz???

Po prostu się tym interesuję. Kiedyś z czystej ciekawości, teraz wykorzystuję tą wiedzę w pracy.
Po prostu są mi bliskie ideały humanizmu, ale rozumieniu renesansowym - czyli całościowe poznanie człowieka i świata a nie niepełnosprawność techniczna, logiczna, matematyczna itp;)

Tutaj podałem linki do wiki, aby dać wskazówki i zajawki zainteresowanym. Ale nie ma drogi na skróty - rzetelna wiedza jest tylko w książkach.

>Mnie nie starcza czasu nawet na
>przejrzenie newsów o jednym z tysiąca
>frameworków webowych...

Heh mam ten sam problem, ale w pewnym momencie trzeba sobie ustalić priorytety.

>A tak na serio, nie myślałeś kiedyś o
>jakimś wykładzie na konferencję
>związanym z aspektami psychologicznymi/
>samorozwoju/modeli uczenia itp. w
>odniesieniu do specyfiki branży
>software engineering? Przecież coraz
>więcej chętnych na tego typu tematy.
>A to wymaga przekrojowej wiedzy,
>szerokiego doświadczenia w branży i,
>nie bójmy się tego słowa, erudycji.

Tak myślałem nad tym np. na okoliczność tegorocznej Confitury...
Zgłosiłem nawet temat "Mężczyźni są z Marsa, Kobiety z Wenus, a programiści dojeżdżają z Melmag" ale uznałem, że nie wyrobię się w czasie aby opracować na zadowalającym poziomie tą prezentację. DDD czy CqRS mam po prostu opracowane od dawna i jest to kwestia zmiany formy na bardziej konferencyjną.

>A, z całym szacunkiem, DDD i CQRS to
>relatywnie łatwe tematy, mnóstwo
>materiałów i przykładów w sieci. Choć
>oczywiście temat wart uwagi.

Tak, na konferencji chodzi o dotarcie do szerszego grona odbiorców i pokazanie im nowych kierunków do własnej eksploracji.

>p.s.
>Jednak z tym onanizmem javowców
>frameworkami i bibliotekami masz
>trochę racji, choć początkowo
>protestowałem, to jednak jak obserwuję
>ostatnie javowe konferencje, to mało
>jest o architekturze/wzorcach/
>archetypach, za to dużo o Buzzwords
>typu cloud, nosql.
>A im więcej czytam o zagadnieniach
>koncepcyjnych typu ddd, cqrs, itp, tym
>częściej trafiam na strony/
>podcasty .netowców.

heh widzisz... wiem co mówię... siedzę w tym community od 4 lat i obserwuję "patterny socjologiczne":)

Unknown pisze...

"emocjonalne podchodzenie do "młotka" jest po prostu nieracjonalne."
Powiedz to komuś kto nie trafił w gwóźdź.
Merytorycznie później ;)

Sławek Sobótka pisze...

@piotrb

hehe dobre, dobre

Niby tylko żarcik, jednak jest jest w nim też coś zastanawiającego (jak w każdym dobrym żarcie).

Część ludzi gdy przy przywali sobie młotkiem w palucha (umówmy się, że młotek i paluch to metafora), podochodzi do tego w taki sposób, że jest to ich wina. Np: "ale ze mnie lama, nie umiem używać młotka, muszę się doskonalić w tym kierunku".

Inni natomiast obwiniają młotek za zdarzenie. Np. ich psychiczny "system odpornościowy" personifikuje młotek i przypisuje mu złośliwe cechy po to tylko aby nie dopuścić do świadomości myśli, że to ze mną jest nie tak. Czasem widuje się osoby będące w furii, które po wypadku miotają młotkiem ze złości. O ile chwilę wcześniej miały problem pod tytułem "bolący paluch" to teraz mają problem "bolący paluch, zgubiony młotek, zniszczona szyba". Nie jest to może najmądrzejsze, ale dla nich działa - dając jakąś ulgę:)

ToJaJarek pisze...

@Piotr
Jak ktoś tym młotkiem regularnie nie trafia to faktycznie ma silne emocje ale co w związku z tym (tym kimś?)?

Marcin Juranek pisze...

Witam
Artykuł ciekawy. Ja mam pytanie, jak uczyć się wzorców?
Przecież nie mogę pchać tego gdzie popadanie.
Ile projektów muszę zepsuć żeby się tego nauczyć? i w którym momencie będę wiedział że idę we właściwym kierunku?

Sławek Sobótka pisze...

Dobre pytanie... chirurg uczy się na zwłokach, dentysta ma na początku pacjentów, których nie jest stać na doświadczonego specjalistę, muzyk ćwiczy na próbach zadnim wystąpi na koncercie...

Zacznę może od innej strony: po co się ich uczyć wcześniej, czy nie można by nauczyć się gdy będą potrzebne? Pytanie sprowadzi się na koniec do pytania o jajko i kurę. Z podejściem "nauczę się gdy będę potrzebował" wpadamy w pętlę: bez odpowiedniej wiedzy nie będziemy dopuszczeni do ciekawszych projektów, bez ciekawszych projektów nie nabędziemy odpowiedniej wiedzy.

Teraz odpowiadając na Twoje pytanie "jak się uczyć" - to zależy od tego jaki preferujesz styl uczenia się... Tutaj jeden z wielu modeli: https://en.wikipedia.org/wiki/Learning_styles#David_Kolb's_model

Odnosząc się do wspomnianego modelu: ja uczę się na przykładach, później praktykuję. Nie che mi się praktykować do póki nie "czuję", że warto. Więc moja droga była następująca: kilkanaście lat temu kupiłem sobie wszystkie książki jakie były dostępne w PL (wtedy nie było Amazona, ebooków itd) a było ich 6 i przeczytałem od deski do deski. W każdej z nich wzorce były przedstawione na innych przykładach. Gdzieś tak w połowie mój mózg zaczął redukować ilość danych (przykładów) w formę wzorców właśnie, czyli ogólnych receptur połączonych z wyczuciem co, kiedy, do czego.

Później było kilka projektów, gdzie wzorce posypały się z lekkim nadmiarem:) Tutaj ważna jest retrospektywy. Po zakończonym projekcie lub w trakcie jego utrzymania trzeba się zatrzymać i zreflektować: jakie były konsekwencje zastosowania danej techniki, co się opłacało a co, jak można by to zrobić inaczej. Bez refleksji nie ma moim zdaniem doświadczenia.

Czy taki sposób uczenia się jest dobry? Tak ale tylko dla osób o podobnym stylu uczenia się:P

Jarosław Żeliński pisze...

A ja dopisze od siebie do tego co Sławek napisał, starą anegdotę:

Przyjezdny w Warszawie rozgląda się i w końcu pyta przechodnia na ulicy:
- Panie, jak się dostać do filharmonii
- Ćwiczyć, kur...wa, ćwiczyć

Jako nie tylko analityk ale także architekt, odpowiem tak: wzorce projektowe to niekończąca się nauka i ćwiczenia, i podobnie jak chirurg: zanim zaczniesz komuś pomagać ćwicz długo na zwłokach....

Standardowym moim (niefakturowanym) moim zajęciem, jest analiza i projektowanie na podstawie informacji z audytów zwalonych projektów, te moje pomysły idą w 100% do szuflady, bo nikomu nie są już nikomu potrzebne, ale ja sprawdzam czy można było lepiej, ale faktem jest że nie raz po protu prowadzę projekty jeszcze raz od początku po kimś i wtedy mam obraz różnicy w praktyce.... Sprawdzone wzorce projektowe to zbawienie, niestety podnoszą koszt projektowania (za to koszt utrzymania spada drastycznie).