środa, 26 sierpnia 2009

Jeszcze prostota czy może już prostactwo?


Chyba każdy z nas zastanawiał się nad tym co takiego urzekło go w programowaniu, że wybrał właśnie to zajęcie. Co takiego przykuwa nas na długie godziny do komputera i powoduje, że zapominamy o zwyrodnieniach kręgów szyjnych i nadgarstków, o zakrzepach w żyłach głębokich,...

Niektórzy odpowiadają, że pociąga ich możliwość tworzenia i kreowania. Inni lubią mieć kontrolę i możliwość decydowania. Są też tacy, którzy pławią się w masochistycznej rozkoszy (choć nigdy się do tego nie przyznają) lawirowania pomiędzy ograniczeniami różnego rodzaju.

/*
 *Przypadki gdy ktoś po prostu "miał Pascala na studiach"
 *i przypadkiem został zatrudniony z jakiejś "łapanki"
 *a później "tak już zostało" pominę w tych rozważaniach.
 */


Jest jednak jeden wzorzec, który powtarza się byt często aby go zignorować. Mianowicie - większość z nas podkreśla, że największą przyjemność sprawia poszukiwanie prostoty, elegancji i harmonii. Nasze umysły nieustannie poszukują zgrabnych modeli pewnych wycinków modelowanego świata. Nic nas tak nie cieszy jak elegancka i prosta forma.

Po tym przydługim wstępie czas przyznać się co sprowokowało mnie do napisania tego posta: prezentacja Jonathana Dahl Programming and Minimalism.

Szczerze polecam tą prezentację (to tylko ok pół godziny). Pomimo ogromnego stresu w jakim był prelegent jest to aktualnie prezentacja numer 2 na mojej liście prezentacji dla programistów. Wyprzedza ją tylko znakomita Developing Expertise: Herding Racehorses, Racing Sheep o której pisałem tu: The Unforgiven.

Jonathan Dahl dokonał czegoś niezwykłego i pięknego zarazem. Pokusił się o próbę syntezy zasad minimalistycznej prostoty, występujących w języku naturalnym, muzyce oraz programowaniu oczywiście. Szczególnie ciekawie brzmi część przedstawiająca przekrojowo sinusoidalne zmiany komplikacji w muzyce - począwszy od Mozarta a skończywszy na Punk Rocku:) Być może dowiecie się z niej dlaczego pewne gatunki muzyki Wam odpowiadają a innych kompletnie nie trawicie... wszystko zależy od preferowanego poziomu komplikacji "figur" akustycznych.

Ale wracając do kontekstu programistycznego... Prezentacja, którą się tak zachwycam traktuje o programowaniu stricte w dosyć zdawkowym wymiarze. Ot mamy jakąś funkcję w Ruby - pogańskim języku, którego nie rozumiem. Jedna jej wersja została upstrzona składnią, którą zna pewnie 5% programistów tegoż języka, natomiast druga (o identycznej funkcjonalności) zawiera prostego ifa. Wniosek: prostota w programowaniu to podstawa. Dziękujemy i do widzenia.

Chciałbym jednak rozwinąć ten temat, ponieważ z moich obserwacji wynika, że o ile wszyscy powtarzają jakoby prostota była ich świętym Graalem to samo pojęcie prostoty w programowaniu jest mocno rozmyte. Nieraz spotkałem się z sytuacją gdy pewien mniejszy lub większy kawałek kodu był oceniany jak majstersztyk lub kupa guano.

Od czego to zależy?
Nawet w tak dobrze zdefiniowanej domenie jak muzyka mamy sytuacje, gdy pewien utwór/twórca/gatunek/styl "się podoba" lub "się nie podoba". Klasycznym przykładem jest Chopin, którego się uwielbia albo nienawidzi:)
Odwołując się do wspomnianej wyżej prezentacji: zależy to od stopnia komplikacji i możliwości jej ogarnięcia przez odbiorcę. Pewne formy są zbyt banalne, pewne zbyt skomplikowane (wydają się wręcz chaotyczne) a pewne w sam raz nam odpowiadają.
Większość umysłów ścisłych jest jak inż. Mamoń - podoba im się to co już znają. Mechanizm jest prosty: znając jakiś wzorzec (utwór) wiemy czego się spodziewać w danej chwili i cieszymy się gdy słyszmy właśnie to czego się spodziewamy. Przypomnijcie sobie jak irytująca jest nagła zmiana kawałka albo różnego rodzaju zakłócenia;P

Wyobraźmy sobie przykładowy problem, którego rozwiązanie można zapisać w jednej klasie z jedną metodą, która ma powiedzmy 10 ekranów a na nich 100 ifów. Ktoś może powiedzieć, że jest to rozwiązanie najprostsze, ponieważ "wszystko po kolei widać", wystarczy się dobrze wczytać;)
Inne podejście może wymagać powiedzmy 5 interfejsów i 10 klas. Każda klasa zawiera parę linijek kodu. Ktoś może stwierdzić, że jest to rozwiązanie zbyt skomplikowane ponieważ aby zorientować się co się dzieje, "trzeba skakać po wielu plikach" i "nie widać całego przebiegu".

Kto ma rację? To oczywiście zależy od preferencji. Jedni wolą wiele prostych pudełek składających się na bardziej wyrafinowaną strukturę, inni będą preferować jedno pudło, w którym jakoś się połapią.


Aby nie szukać konkretnego przykładu zbyt daleko przyjrzyjmy się strumieniom w standardowej bibliotece Javy. Pamiętacie jeszcze swoje pierwsze z nimi spotkanie?;P Dziesiątki klas, jakieś interfejsy, pokręcone konstruktory. Pierwsza reakcja? Panika i odrzucenie. Ja chcę przecież tylko odczytać głupi tekst z pliku a to panie takie pokomplikowane.

Natomiast znając pewną ogólną zasadę - wzorzec dekoratora całość nagle okazuje się być piękna w swej prostocie. Trudno stwierdzić co cieszy bardziej: elegancja tego rozwiązania czy prostota używania i niezwykła łatwość składania złożonych strumieni.

//===========================
Problem prostoty nie jest jednowymiarowy. Nie zawsze problem polega jedynie na tym po prostu działało. Często musi jeszcze dać się zrozumieć, zmienić, rozbudować, skalować, optymalizować, itd. Wówczas kryteria prostoty i elegancji zmieniają wartości.

Bardzo łatwo wówczas pomylić szlachetną prostotę z pospolitym prostactwem. Linia pomiędzy nimi jest zwykle cienka.

Słynny cytat Einsteina "rzeczy powinny być tak proste jak to możliwe" niesie ze sobą na prawdę głębokie przesłanie...

7 komentarzy:

MZ pisze...

kiedy to Mamoń napisał magisterkę?

Przemek pisze...

Trafiłeś bezbłędnie odniesieniem do inżyniera Mamonia. Kto zna Dekoratora, bez problemu odnajdzie się w strumieniach Javy.

Warto jednak dodać też, że niedoświadczeni architekci upychają czasem wzorce w aplikację na siłę, bo właśnie o nich przeczytali i nie zdążyli jeszcze wypróbować. To często z tego powodu słychać skargi nt. skakania po kilku plikach. Widziałem już nieraz np. wyciąganie interfejsów "dla zasady", mimo że posiadały one tylko jedną implementację, a żaden framework ich nie wymagał.

Sławek Sobótka pisze...

@MZ: hehe racja, mój błąd. Inż. Mamoń:)

@Przemek: Znam to chorzenie - mania wzorców. Sam musiałem swoje odchorować zanim nabrałem dystansu.

Ale niestety nie widzę innej drogi aby tak na prawdę "poczuć" wzorce. Trzeba się nimi zachłysnąć, stosować ile się da i gdzie się da;) A dobry smak i intuicja odnośnie dobory wzorca i w ogóle słuszności jego stosowania w danym przypadku przyjdzie z czasem...

Niestety w tak zwanym międzyczasie spłodzimy niezłe koszmarki (lekarz też musi uczyć się na trupach;P)

jacenty pisze...

Moim zdaniem (a propos strumieni w javie), kiedy musimu pisać kod w rodzaju:

BufferedReader rd = new BufferedReader(new InputStreamReader(connection.getInputStream()));

po to, żeby odczytywać ze strumienia linia po linii, to nie ma w tym nic pięknego. To po prostu źle zaprojektowana biblioteka.
Odwoływanie się do wzorców nie zmieni faktu, że to jest po prostu niezgrabne.

Sławek Sobótka pisze...

Ze strumieniami w Javie jest jak ze wspomnianym w poście Chopinem - albo się go kocha albo nienawidzi (ja podpisuję się pod drugą opcją).

Zapytam zatem jak widziałbyś API biblioteki, która pozwala na czytanie linia po linii z dowolnego wejścia z opcjonalną możliwością buforowania, kompresji i szyfrowania?

jacenty pisze...

Zawsze się można wygłupić wymyślając takie API na poczekaniu, na potrzeby dyskusji...
Ale najogólniej - jest taka zasada, że rzeczy proste powinno się dać zrobić prosto, a rzeczy złożone powinno się dać zrobić również prosto :-) o ile to możliwe.

Myślę, że czytanie linia po linii powinno być dostępne z dobrodziejstwem inwentarza dla każdego wejścia tekstowego, natomiast kompresja i szyfrowanie mogłyby wymagać dekorowania odpowiednimi typami strumieni.

Z drugiej strony, takie zawiłe API zmusza do tworzenia kodu adaptującego, który z dużą dozą prawdopodobieństwa będzie tworzony z myślą o dziedzinie problemu, i w ten sposób zgodny z jednym z artykułów z 97 rzeczy...

Z trzeciej strony - bardziej zawiłe API - więcej roboty dla konsultantów, trenerów, firm szkoleniowych...

Sławek Sobótka pisze...

Zgadzam się, że brakuje pakietu (o nazwie powiedzmy java.support), który by przykrywał zawiłe API fasadami. Każdy zwykle robi go sobie sam na poziomie organizacji...

Ale jak sam zauważyłeś... Sun od początku to zaplanował. Java jest tylko masłem, po którym ślizga się prawdziwy biznes - konsultacje i szkolenia ze strumieni;) Niestety jak pokazało życie nie udało się przy pomocy tych dochodów uratować firmy (pewnie nie docenili programistów i API było jednak zbyt proste);P