wtorek, 23 marca 2010

Koszt wykorzystania wzorców projektowych

Podczas dzisiejszej prezentacji na temat Software Craftsmanship i Wzorców Projektowych, którą przeprowadziłem w ramach lubelskiego JUG padło szereg pytań odnośnie:
- kosztu posługiwania się w kodzie wzorcami
- presji czasu
- komplikacji

Jest to pewien ogólny i często powtarzający się zestaw pytań, dlatego sądzę, że warto rozwiać kilka wątpliwości i nieporozumień.

Część programistów widzi wykorzystanie wzorca jako niepotrzebną komplikację, która wprowadza dodatkowy narzut na wytworzenie kodu.

Generalnie jeżeli chodzi o poziom komplikacji to wzorce powinny redukować złożoność przypadkową oraz zwiększać czytelność złożoności właściwej. Jeżeli mamy sytuację odwrotną to wzorzec został wykorzystany niepoprawnie lub niepotrzebnie.

Odnośnie narzutu czasowego to obserwuję dziwne przeświadczenie jakoby dopisanie interfejsu czy kilku linijek kodu potrzebnych na podzielenie kodu na większą ilość pudełek (klas) było jakoś niezwykle czasochłonne;) Sam proces myślowy również nie powinien się znacząco wydłużyć. Albo wiem jaki wzorzec użyć albo nie wiem. To nie jest tak, że zastanawiam się nad tym godzinami.

Warto zwrócić uwagę na fakt, że katalog Wzorców Projektowych Ogólnego Przeznaczenia jest dosyć bogaty.

Owszem, część z nich jest dosyć wyrafinowana pod względem koncepcyjnym lub pod względem konstrukcji kodu. Przykładowo taki Visitor, Component Tree, Bridge, Proxy, Builder, Flyweight, Memento prowadzają pewien narzut, ale są to narzędzia, które wybieramy do misji specjalnych. Na pewno nie należą do codziennego wachlarza technik.

Natomiast Strategia, Stan, Dekorator, Template Method, Command to lekkie "skróty myślowe" wynikające wprost w paradygmatu Object Oriented. Nie ma w nich doprawdy nic nadzwyczajnego.

Osobiście traktuję część z nich jako "atomowe klocki", z których powinno budować się rozwiązania. Są to byty niemal tej samej klasy ciężaru co IFy, pętele czy metody. Biegłe opanowanie lekkich wzorców sprawia, że poszerzają one nasz zestaw podstawowych "klocków myślowych". Budujemy z nich najpierw mentalne modele, a później naturalnie pojawiają się w kodzie.

Operując lekkimi wzorcami na poziomie podstawowych klocków nie mamy narzutu czasowego podczas developmentu. Natomiast poziom komplikacji ulega znacznemu obniżeniu, ale tylko dla tych czytelników kodu, który posiadają taki sam zasób skojarzeń jak jego twórca - czyli operują tym samym słownictwem branżowym.

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

Potrzeba posiłkowania się wzorcami "lekkiego" kalibru wynika ze słabej siły wyrazu języków wywodzących się z C++ takich jak np Java. Przykładowo brak domknięć kompensujemy sobie strategiami. Doprawdy nie jest niczym strasznym i pracochłonnym opracowanie interfejsu z jedną metodą oraz kilku jej implementacji. Ilość kodu "biznesowego" nie ulega zwiększeniu (ew redukcji) natomiast pojawiają się jedynie dodatkowe "opakowania" dla niego w postaci zgrabnych i eleganckich klas.

Jeżeli ktoś aż tak bardzo nie pała chęcią do pisania kodu to może powinien zostać trubadurem;)

Ciężki kaliber wzorców również może czasem przydać się do emulacji brakujących elementów składni, takich jak:
- double dispatch emulowany przez wzorzec Visitor
- lazy evaluation emulowany przez wzorzec Proxy.

13 komentarzy:

marcin pisze...

Ależ koszt wprowadzania wzorców faktycznie występuje. Jeśli podążysz trzecią drogą - wskazaną przez kogoś z tyłu sali na wykładzie - i najpierw nawalisz (metodą na Jana) górę kodu a potem zaczniesz w niej grzebać żeby następnego dnia w ogóle się w tym połapać, to wzorce faktycznie kosztują - a i jeszcze przy okazji refactoringu można coś schrzanić.

Jeśli musisz najpierw napisać masę kodu bo nie bardzo wiesz o co kaman w danym problemie to czemu nie zrobić tego test first? Dzięki temu, gdy dochodzisz do momentu w którym musisz zrefactorować właśnie zaimplementowany kawałek systemu masz przynajmniej testy, które mogą pokazać ci ,że źle się zaczyna dziać. Ok, dochodzi koszt napisania testów, ale dzięki nim refactoring kupy g***a do wzorców jest bezpieczniejszy i w rezultacie szybszy (pomijając już aspekt dodatkowej specyfikacji wymagań w postaci testów, bo to nie zawsze wychodzi).

Mateusz Mrozewski pisze...

Prezentacji nie widziałem i dyskusji nie słyszałem, ale zastanawiam się, czy koszta były wspominane w kontekście wytwarzania oprogramowania czy też całego cyklu życia?

Wzorce to coś, co wymaga doświadczenia i wprawy, aby można było je poprawnie ... no właśnie, stosować? Czy z góry powinniśmy wprowadzić strategie, jeśli wydaje nam się, że może być potrzebna (podkreślam: wydaje nam się). Inna sprawa, jeśli mamy dużą wiedzę i doświadczenie i po prostu wiemy, że tego potrzebujemy.

W przeciwnym wypadku potrzebujemy czegoś, co zweryfikuje nasz design. Tutaj świetnie sprawdza się TDD. Możemy zweryfikować nasz design, bezpiecznie refaktorować i przy okazji testować. Czy to jest dodatkowy koszt? W idealnym świecie jest to standard wytwarzania a nie dodatkowy koszt.

A jeśli nie jest to standard, to czy z takiej inwestycji może być jakiś zwrot? Tak, w utrzymaniu. Czystszy, uporządkowany kod, łatwiejszy do zrozumienia to łatwiejsze utrzymanie - a zatem niższy koszt (albo co najmniej zbalansowany) w kontekście całego cyklu życia oprogramowania. A jak łatwiejsze utrzymanie to i łatwiejsze rozwijanie.

A programowanie to nie tylko klepanie kodu "na Jana" (nie znałem tego określenia, dobrze użyłem? :-) a również budowanie własnego warsztatu: stosowanie narzędzi, nabywanie umiejętności, wiedzy, doświadczenia.

Jeśli ktoś tego nie chce robić, to trubadur to niezbyt dobra alternatywa :) Bo śpiew i grę też trzeba ćwiczyć :)

iirekm pisze...

Stojąc przed pokusą zastosowania wzorca należy siebie spytać: czy jak dziś nie zastosuję tu tego wzorca to czy w przyszłości będę mógł go łatwo wprowadzić w razie potrzeby?
Jeśli odpowiedź jest "tak, łatwo można będzie to wprowadzić" - nie stosuj wzorców, stosuj jedynie KISS (keep it simple stupid), YAGNI (you aren't going need it). Wymagania się zmieniają i jak dzisiaj ci się wydaje ten wzorzec tu odpowiedni jutro może być inaczej - zbędna praca.
Jeśli odpowiedź jest "ciężko będzie to zmienić jak dziś nie zastosuję tu wzorca" - zastosuj wzorzec. Dotyczy to zwłaszcza elementów architektonicznych: jak dziś mam trzy warstwy to ciężko będzie wprowadzić dodatkową czwartą za miesiąc. Jak jakaś superważna klasa używana przez wiele innych klas będzie się za miesiąc musiała zmienić, koszt takiej zmiany też może być kosztowny.

Paweł Badeński pisze...

Moze troche offtopowo, ale co tam...
Podobnie jak Mateusz prezentacji ani nie widzialem ani nie slyszalem (ale jesli macie nagrania bardzo chcialbym obejrzec). Natomiast ten zestaw pytan slyszalem juz w permutacji z chyba kazda dostepna metoda. Ciesze sie, ze pojawia sie w kontekscie Software Craftsmanship, bo coraz bardziej zaczynam byc zwolennikiem pogladu ze wszystkie te problemy wynikaja wlasnie z braku mentoringu w naszym fachu (a czy w ogole mamy fach to pytanie do wujka Boba ;)). Nie mowie, zeby na nie nie odpowiadac, ale chyba warto rozwazyc, ze problem jest systemowy. Chcialbys robic dobrze, ale nie wiesz jak - a ze juz wielokrotnie probowales sam i bylo wolno, wiec masz podobne obawy do kazdej nowej praktyki/metody. Tak sie troche motamy wydaje mi sie.

ToJaJarek pisze...

Ja myślę, że kluczowym problemem jest właśnie to: "Jeśli musisz najpierw napisać masę kodu bo nie bardzo wiesz o co kaman w danym problemie... " pisanie kodu bez projektu samo w sobie jest kosztem bez sensu, wzorce projektowe wymagają pomysłu na całość a jak tego pomysłu nie ma (jeszcze) - brak analizy i projektu??? - no to mamy klops.

Sławek Sobótka pisze...

Panowie, dziękuję za dyskusję i cieszę się, że temat znajduje zainteresowanie. Dla mnie osobiście jest on dosyć istotny.

@marcin - zastanawiałem się nad tym od jakiegoś czasu, ale nieco od innej strony - bardziej systemowo (ukłon w stronę Pawła B.) biorąc pod uwagę "naturę" developerów. Ludzie mają różne "skrypty kognitywne - jedni preferują najpierw ogólnie połapać się o co chodzi zanim zaczną cokolwiek robić, inni preferują jakkolwiek poeksperymentować. Oczywiście pierwsze podejście nie zadziała gdy kompletnie nie da się ruszyć zanim nie zaczniemy błądzić. Z tym jest różnie – cechy osobnicze, nie da się uogólnić.

Pytanie tylko co jeżeli refaktoryzacja dotknie poziomu, który jest mocno testowany – testy do wywalenia.

@Mateusz – odnośnie długoterminowych inwestycji to wszyscy raczej się zgadzaliśmy. Pytania były odnośnie np projektów start upów w kontekście czy warto jeżeli nie wiadomo co będzie dalej działo się projektem. Stąd mój tekst o lekkości i taniości niektórych technik (wzorców) bazowych.

Poruszyłeś też ciekawą kwestię "wydaje nam się" – z czasem właśnie intuicja działa z wysokim prawdopodobieństwem. Zastanawiałem się nad kwestią czy stosować czy nie i moje przemyślenia są takie: niestety aby biegle czymś władać to trzeba nieustannie ćwiczyć – samo przejrzenie katalogu rozwiązań nie daje dobrych rezultatów. Przez jakiś czas niestety trzeba pobrudzić trochę kodu niepotrzebnymi wzorcami aby nabrać biegłości w korzystaniu z nich i intuicji kiedy w ogóle mają sens. Jak inaczej można by to zrobić?

@Paweł – i tu właśnie dochodzimy do problemu profesji i monitoringu, o którym piszesz. Podczas prezentacji poruszył ten temat Wojtek R. ale jakoś nie został on pociągnięty dalej. Chirurg uczy się na zwłokach, architekt mostów na symulatorach fizyki. Póki co my musimy eksperymentować i brudzić kod na czym? Jak rozwiązać ten problem? Jaka jest tutaj rola systemu edukacji?

@Irek – zgadza się. Tylko jak nabrać taką intuicję? Właśnie metodą prób i błędów – tylko gdzie ten plac zabaw? Ale to nie wystarczy. Po każdej próbie i po każdym błędzie musi nastąpić refleksja nad przyczynami, kontekstem i działającymi „siłami”.

Sławek Sobótka pisze...

@ToJaJarek - osobiście też tak myślę, ale biorąc pod uwagę różne "skrypty kognitywne" jakimi mogą kierować się ludzie nie upierałbym się, że tak musi być w każdym przypadku.
http://www.racjonalista.pl/kk.php/s,4588

Mateusz Mrozewski pisze...

@Sławek: oczywiście nie da się od razu dobrze wprowadzać wzorców (przynajmniej niektórych) jeśli się nie ma doświadczenia. Trzeba pisać, analizować, refaktorować, próbować doprowadzić kod do perfekcji. Jeśli coś nam się nie podoba, to zastanawiamy się jak to poprawić. Jak się nie da, to tego nie robimy tego na siłę. Jak nie wiemy - to pytamy :) Materiałów jest dużo, a najważniejsze są chęci - a po drodze trochę kodu pewnie i tak popsujemy - to też forma nauki :)

Sławek Sobótka pisze...

Właśnie o to mi chodziło:)

Wzorce mają jeszcze tą zaletę, że dzięki nim nie musimy totalnie na ślepo próbować i eksperymentować na niskim poziomie. Już nie musimy szukać samej formy.

Ktoś już to zrobił i daje nam rozwiązania (klocki) wyższego rzędu. Nasz wysiłek to polega "tylko" na znalezieniu dla nich sensownych zastosowań w swoich problemach.

Paweł Badeński pisze...

@Sławek: Natknalem sie ostatnio na bardzo ciekawy tekst - Rozdział 12 (Apprentice Developers) książki McBreen'a "Software Craftsmanship", którego pierwsza sekcja nosi tytuł "We Must Reverse the Decline in the Quality of Developer Training". Polecam lekturę - stosunkowo duży fragment można znaleźć na Google Books.

A i jeszcze, nie wiem czy mówiłeś na prezentacji o książce Kerievskiego "Refaktoryzacja do wzorców projektowych". Tu nie wspomniałeś, a może warto - również ją polecam każdemu :D

Sławek Sobótka pisze...

@Paweł - dzięki za polecenie tekstu... Zauważono w nim ciekawą patologię - nauka przez "sink or swim". Jeżeli ktoś się nie utopił to pewnie będzie powtarzał zachowanie, które jakoś się sprawdziło.

Co do "Refaktoryzacja do wzorców projektowych" to nie mówiłem o tej książce. Jest to jedna z tych pozycji, które trzeba bardzo wnikliwie studiować, więc nie jest to niestety dobry materiał na godzinną prezentację.

Dodam jeszcze, że imho styl refaktoryzacji przedstawiony przez autory jest miejscami zbyt zachowawczy, ja robiłbym od razu bardziej drastyczne kroki. Ale to oczywiście zależy od tego czy mamy ten komfort poruszania się w znanym terenie czy musimy poruszać się po omacku jak słoń w składzie porcelany;)

Mateusz Mrozewski pisze...

Po 4Developers mam już pełen obraz :) Świetna prezentacja pod każdym względem. Całej naszej ekipie się podobała. Gratulacje :)

Sławek Sobótka pisze...

Dzięki:)
Cieszę się, że trafiłem w gusta.

Jeżeli będziecie mielic zas to w wolnej chwili napiszcze jakiś feedback odnośnie prezentacji - np. co dodać, do wyrzucić, co zmienić.