Dam się poznać: mój projekt open source

Zgodnie z zapowiedzią w poprzednim wpisie (o prokrastynacji), postanowiłam wziąć udział w konkursie Daj się poznać organizowanym przez Macieja Aniserowicza z bloga devstyle.

Oznacza to, że w ciągu najbliższych dwóch miesięcy (lub do odwołania) dwa razy w tygodniu będę publikowała tu wpisy na temat mojego projekciku open source. Zrobi się trochę bardziej technicznie. Mam nadzieję, że nie pociągnie to za sobą exodusu Czytelników zaglądających tu w poszukiwaniu lżejszych tekstów okołoprogramistycznych. Postaram się zachować przyjazny ton.

Na co mi to?

Jedno słowo: motywacja.

Cztery słowa: najlepiej pracuję pod presją.

Wielu przyjaciół naiwnie wierzy w moje nieprzebrane pokłady ambicji i samozaparcia. W rzeczywistości, jak uczeń z oślej ławki, robię coś tylko wtedy, kiedy wiem, że ktoś na pewno mnie sprawdzi. W związku z tym pracę nad każdym większym przedsięwzięciem (nie przepadam za słowem „projekt”, chociaż akurat tu akurat pasuje) rozpoczynam od poszukiwań sprawdzacza.

Bądź moim sprawdzaczem.

Jeśli ktoś pokusi się o merytoryczne komentarze i podpowiedzi: tym lepiej dla mnie.

A na co mi sam blog? O tym chyba tutaj: O mnie.

Mój pomysł: szafbook

szafa
To jest moja garderoba. Praca nad dzisiejszym wpisem wymagała ode mnie między innymi uprzątnięcia sterty prania zalegającego na oknie i na desce do prasowania.

Opis problemu

  1. Mam dużo ubrań, a ciągle chodzę w tych samych, bo nie pamiętam, co jest w dolnych pokładach mojej szafy.
  2. Mam trochę ubrań na wymianę – z których wyrosłam 😉 ja lub moje dziecko.

Rozwiązanie i zarys funkcjonalności

Wymyśliłam sobie aplikację, która umożliwi mi skatalogowanie zawartości szafy oraz jej  przeszukiwanie, a także udostępnienie jej zawartości znajomym i ewentualną wymianę bądź wypożyczenia.

Szkic wymagań:

  1. Użytkownik zarządza jedną lub więcej szafami.
  2. Dodaje do szafy ubrania wraz ze zdjęciami i krótkim opisem. Ubrania są umieszczane w odpowiedniej kategorii (ręcznie lub poprzez analizę tekstu, a w bajkowej wersji full-wypas także przez analizę obrazu). Metadane muszą, oczywiście, zawierać rozmiar.
  3. Użytkownik może udostępnić szafę do przeglądania komuś ze swoich znajomych.
  4. Możliwe są wymiany i wypożyczenia.
  5. Dostępne jest semantyczne wyszukiwanie, np. „wszystkie czarne topy” albo „szalik pasujący do tego swetra”.

Technologie

Przyznam, że kusiła mnie szaleńcza idea stworzenia aplikacji webowej w Haskellu. Ostatecznie doszłam jednak do wniosku, że wolę uzupełnić swoją coraz bardziej dziurawą wiedzę na temat Javy. To mój ulubiony język programowania, a nie dotykałam go właściwie od dwóch lat (ponieważ wybór zajęć determinowała dziedzina, a nie preferencje programisty). W tym czasie tworzyłam za to kod w: Perlu, Pythonie, C++, Rubym, R.

Dlatego mimo że JEE to temat nudny i oklepany, tym właśnie chcę się zająć. Wśród rzeczy, których chcę użyć, nauczyć się, przypomnieć sobie lub o nich napisać, są:

  1. Java 8,
  2. jakiś framework webowy, pewnie Spring Boot,
  3. microservices (?),
  4. Maven,
  5. jakieś narzędzie do analizy statycznej,
  6. JUnit,
  7. Git/GitHub,
  8. jakieś darmowe narzędzie do ciągłej integracji, pewnie Jenkins,
  9. jakieś narzędzie do przetwarzania danych RDF/OWL,
  10. któraś nierelacyjna baza danych,
  11. Android w dalekiej, dalekiej przyszłości 🙂

Mój pomysł podoba mi się, bo:

  1. Mogę rozwiązać istniejący problem (być może tylko mój).
  2. Bardzo rzadko mam okazję pisać coś od zera.
  3. Zorientuję się, co się dzieje w Javie.
  4. To przedsięwzięcie da się przekuć w serię przyjaznych wpisów na temat różnych technologii.
  5. Wszystko to trochę wygłup. Zawsze w cenie.

Mój pomysł nie podoba mi się, bo:

  1. Temat jest „dziewczyński”.
  2. Technologie, których chcę użyć, są pospolite.
  3. Od strony technicznej to nic odkrywczego.
  4. Wątpię, żebym w czasie trwania konkursu była w stanie wyprodukować aplikację wartą pokazania.

Informacje techniczne

  1. Wpisy konkursowe będę oznaczać tagiem daj się poznać.
  2. GitHub: https://github.com/1nk4/szafbook
  3. www: http://szafbook.pl/

PS.

Zespół cieśni nadgarstka to najwyraźniej przypadłość nie tylko czynnych programistów i pracowników linii produkcyjnych, ale także młodych matek noszących coraz cięższego stwora.

erlich
Pora zabrać się do roboty! Nie mam profesjonalnych ortez, jak Erlich. Zamiast nich używam ochraniaczy do jazdy na rolkach. Naprawdę pomagają.

Ekshibicjonistyczny wpis o prokrastynacji i diecie informacyjnej

Dziś o marnowaniu czasu w Internecie.

Zaczęło się od tego, że…

Postanowiłam wziąć udział w konkursie Daj się poznać. Konkurs wymaga utworzenia projektu open source i blogowania o postępach prac. Jako że różnych hobby[1] mam więcej niż Java bibliotek ORM (hłe, hłe), a moment w życiu nie zachęca do rzucania się z motyką na cokolwiek – potrzebowałam zewnętrznej motywacji do działania.

Czas pokaże, czy wystarczy mi determinacji do samego końca. Póki co, rozmyślam o prokrastynacji i szkodliwych nawykach. Z tej okazji kolejny raz wróciłam do przełomowej dla mnie książki Information Diet Claya A. Johnsona.

Jeszcze jeden brzydki wyraz

Prokrastynacja” to nie jest ładne słowo. Nie ma go w „Słowniku języka polskiego” PWN, a to prawie zawsze oznacza, że istnieje już poprawne polskie słowo oznaczające dokładnie to samo. Najpiękniejszy wolny przekład, z jakim się spotkałam, to „kunktatorstwo”, ale bliżej sedna jest chyba zwykłe „zwlekanie”.

Prokrastynację najczęściej powoduje niepokój (przed porażką lub, o dziwo, sukcesem), a jej najbliższym pomagierem jest, oczywiście, Internet.

Najlepsze remedium na prokrastynację…

… to sprawowanie opieki nad niemowlęciem. Takie odkrycie z ostatnich trzech miesięcy 🙂 Mimo że mam „aniołka”, który płacze tylko, gdy ma realny problem, to znalezienie chwili na kreatywny namysł graniczy z niemożliwością. W efekcie wiem, że kliknięcie w ten jeden kuszący link istotnie zwiększy ryzyko, że pracę nad kolejną linijką (gdy wreszcie się za nią zabiorę) przerwie rozdzierający wrzask. To naprawdę skuteczny wspomagacz dyscypliny.

Siła nawyku i obiecany ekshibicjonizm

Czas się przyznać. Nawet przy dziecku mam potężny problem z pozbyciem się jednego szalenie szkodliwego i trochę wstydliwego nawyku. Czytam w wannie. Uwielbiam czytać w wannie. Nie od święta i nie zawsze przy świecach. Prawie codziennie. Rano. Książkę, ale także głupoty w Internecie.

Mądrzejsi od mnie twierdzą, że nawyk składa się z trzech elementów: wyzwalacza, reakcji oraz nagrody, i że można tę sekwencję wykorzystać do świadomego wytworzenia nawyków pożądanych. Chciałabym, po dzwonku budzika, na autopilocie lądować w lesie na przebieżce z psem (póki mąż w domu), a nie w wannie w stanie półhibernacji! Trzymaj za mnie kciuki.

Czy nabijasz się z milionów Polaków bezmyślnie wpatrzonych w telewizor?

Jak wielu moich przyjaciół, nie oglądam telewizji. Mogę sobie gratulować, że wiele dzieli mnie od statystycznego Polaka, który spędza przed telewizorem zatrważające 4,5 godziny dziennie. Tylko że… Nie czarujmy się. Internet niekoniecznie jest lepszy, a w wydaniu większości (do której pewnie należę) zdecydowanie taki nie jest.

Internet to największy zasób wiedzy na świecie, a jednocześnie największy zasób głupoty.

Pamiętaj, że mózg staje się najlepszy w tym, w czym regularnie go ćwiczysz. Czy warto wyspecjalizować się w podążaniu za clickbaitem (odmieniłam, a co)?

Dieta informacyjna

Autor Information Diet porównuje konsumpcję informacji do konsumpcji żywności.

Tak jak w przypadku jedzenia, najzdrowsza jest informacja nieprzetworzona, pochodząca z samego źródła. Zatem nie wiadomości na portalach i w tygodnikach opinii, tylko artykuły naukowe, notatki agencji prasowych, potwierdzone relacje świadków, poparte źródłami analizy ekspertów. Porównanie wbrew pierwszemu wrażeniu nie jest na wyrost. Autor wskazuje informacyjne odpowiedniki śmieciowego jedzenia i tłumaczy, jakie mechanizmy sprawiają, że nabieramy się na jedno i drugie.

Co ciekawe, problemu nie rozwiązuje samo publiczne udostępnienie źródeł (np. rządowych raportów na temat wydatków), ponieważ czytelnik musiałby jeszcze do nich sięgnąć. Porównanie z książki: zalanie rynku brokułami nie sprawi, że ludzie zaczną odżywiać się zdrowo. Musimy zdobyć się na świadomy wysiłek.

Tak jak w przypadku jedzenia, w przypadku informacji również można przejść na dietę.

  • Odmawiać sobie klikania linków w stylu „a wtedy stało się TO”.
  • Trenować interwałami utrzymywanie uwagi i koncentracji.
  • Sięgać do źródeł.
  • Sprawdzać pochodzenie zdjęć (w Google Images można szukać zdjęć podobnych do danego zdjęcia oraz wcześniejszych wystąpień tego samego zdjęcia w artykułach).
  • Zaglądać do magazynów prezentujących przeciwną opcję polityczną.

Istnieją narzędzia pozwalające zwiększyć produktywność przy komputerze. Jednym z nich jest RescueTime, które śledzi naszą aktywność i przedstawia raporty na temat czynności wartościowych i nie. Narzędzie jest konfigurowalne i podobno bezpieczne.

Zadanie domowe

Chciałabym zaproponować Ci zadanie domowe.

Jeśli jeszcze tego nie robisz: następnym razem, kiedy poruszy Cię wiadomość przeczytana w Internecie, postaraj się dotrzeć do samego źródła. Znajdź nagranie, cytat, raport z badań. W wersji „z gwiazdką” sprawdź dodatkowo, czy w ogóle i w jaki sposób piszą na ten sam temat media z przeciwnej opcji.

Dzielę się swoimi wynikami: news, który mnie zbulwersował, okazał się niestety niepodkolorowaną prawdą. Kandydat na prezydenta, poseł i ojciec trzech córek faktycznie insynuował że nieatrakcyjna (jego zdaniem) kobieta powinna cieszyć się z molestowania.

 

[1] Do bardzo niedawna sądziłam, że mój nadmiar zainteresowań jest głęboką patologią. Natknęłam się jednak na cudowne wystąpienie Emilie Wapnick na TED i odetchnęłam z ulgą. Polecam.

[2] Obrazek w nagłówku pochodzi stąd: https://sketchport-hrd.appspot.com/drawing/5795385024970752/hotdog. Okazało się, że nie potrafię narysować hot doga.

10 migawek z kursu programowania funkcyjnego w Haskellu

Od dwóch miesięcy dość rzadko udaje mi się mieć wolne obie ręce. Przyczyna jest dobrze widoczna na załączonym obrazku 🙂 W grudniu udało mi się jednak ukończyć kurs  Introduction to Functional Programming w portalu edX.  Poniżej moje notatki i wspomnienia. Przykłady prezentowane w materiałach z kursu są napisane w Haskellu (i rzeczywiście tego języka chciałam się nauczyć), ale autorzy stawiają sobie za cel przedstawienie uniwersalnych zasad programowania funkcyjnego. Wiele zadań domowych można było wykonać w wybranym innym języku funkcyjnym, na przykład w Scali.

Czasem uda nam się trochę popracować!
Czasem uda nam się trochę popracować przy biurku z podnoszonym blatem!
1. Funkcje można definiować na kilka różnych sposobów.

Żeby nie było, że „programowanie funkcyjne” to tylko szumna nazwa: w Haskellu tę samą funkcję można zdefiniować na kilka sposobów, w zależności od potrzeb i osobistego stylu.

Poniżej kilka różnych definicji tej samej prostej funkcji. Dla zabawy zdefiniujmy funkcję przyjmującą jeden argument. Funkcja zwróci dodatnią wartość logiczną wtedy i tylko wtedy, gdy przekazany jej argument liczbowy będzie poprawną odpowiedzią na wielkie pytanie o życie, wszechświat i całą resztę.

Definicja z użyciem wyrażeń warunkowych:

Inne wyrażenia warunkowe (guarded expressions):

Dopasowanie do wzorca:

Najprostsza definicja świata, czyli zwykłe wyliczenie wartości:

Zachęcam do potestowania.

2. Lambdy to tylko funkcje bez nazwy.

Programowanie funkcyjne wtargnęło przemocą do wielu popularnych języków, więc nie spodziewam się zaszokować tłumów tą informacją. Ci jednak, którzy jeszcze nie wyszli poza świat obiektów, mogą odetchnąć z ulgą: lambdy to tylko funkcje bez nazwy. Przydatne w różnych okolicznościach, na przykład kiedy funkcja ma być użyta tylko raz i ma bardzo krótką definicję.

W Haskellu lambdy wyglądają tak (backslash, zwany też ukośnikiem wstecznym, ma w zamierzeniu przypominać grecki znak λ):

A tak, dla porównania, wyglądają w Javie:

Skąd taka nazwa? Inspiracją i matematyczną podstawą języków funkcyjnych jest rachunek lambda.

3. Praca z listami to sama przyjemność.

Na obronie pracy magisterskiej zadano mi pytanie, po czym na pierwszy rzut oka poznać kod napisany w języku Lisp. Właściwa odpowiedź jest dość prosta – po listach!

W Haskellu również listy przetwarza się bardzo przyjemnie. Można wygodnie dopasowywać je do wzorców, dzieląc listy na głowę i ogon, jak w tej poniższej definicji:

Użycie:

Jak widać w ostatnim przykładzie, wzorzec (head:tail) nie zostanie dopasowany do pustej listy.

Można także bardzo wygodnie generować listy, nawet nieskończone, przy użyciu dość intuicyjnej składni tzw. list comprehension. Oto przykład, trudniejszy w słownym opisie niż w implementacji: lista kwadratów tych liczb od 1 do 10, które są podzielne przez 2.

Ładne, prawda?

4. Brak stanu i inne wymagania.

Nie ma jednej obowiązującej definicji programowania funkcyjnego. Według wielu, jest to wręcz najgorzej zdefiniowany paradygmat programistyczny.

Jednym z najistotniejszych wyznaczników kodu funkcyjnego jest brak stanu – ta sama funkcja wywołana z tymi samymi argumentami powinna zawsze zwracać tę samą wartość, najlepiej bez efektów ubocznych (tj. zmieniania czegokolwiek w tle, np. wartości pól obiektu). W dużej mierze właśnie ta właściwość spowodowała renesans popularności języków funkcyjnych. Dlaczego jest to aż tak istotne?

  • Programując w ten sposób, niejako „w prezencie” dostajemy kod doskonale poddający się zrównoleglaniu. Osobne wątki nie muszą co chwilę zsynchronizować zmieniającego się, współdzielonego stanu.
  • Kod składający się z funkcji bez efektów ubocznych jest nieporównywalnie prostszy w zrozumieniu i utrzymaniu.
  • Wyniki raz wywołanych funkcji można zapamiętać w cache, by przy kolejnym wywołaniu z tymi samymi argumentami, po prostu sięgnąć do już wyznaczonej wartości.

Inne ważne cechy języków funkcyjnych to możliwość definiowania: funkcji wyższego rzędu (funkcji, które zwracają inne funkcje lub przyjmują inne funkcje jako argumenty) oraz, oczywiście, lambd.

5. Upierdliwa obsługa operacji I/O.

Czytanie z wiersza poleceń w Javie nigdy nie należało do przyjemności. Musimy pootwierać piętrowe strumienie, czytać z nich, sprawdzając, czy zostało coś jeszcze do pobrania, a na koniec pamiętać o ich zamknięciu (ok, w Javie 7 pojawił się interfejs AutoCloseable, wystarczy tylko pamiętać o jego użyciu).

Haskell pokazuje nam jednak, w pewnym sensie, że może być jeszcze gorzej. Dlaczego? Ponieważ odczytanie ciągu znaków z wejścia wymaga złamania nagięcia ograniczeń, które stanowią o sile języków funkcyjnych.

Funkcja, za pomocą której będziemy pobierali znaki z wejścia, siłą rzeczy musi zwracać odmienne wyniki dla tego samego argumentu. Co gorsza, musi też w tle zmieniać stan naszego świata (przy kolejnych wywołaniach znaki są konsumowane i inny znak czeka w kolejce na odczytanie).

Dla zachowania czystości kodu, a właściwie w celu oddzielenia kodu czystego od „skażonego”, operacje I/O w Haskellu są opakowywane w akcje. Całość „nieczystego” przetwarzania odbywa się wewnątrz akcji, z której na koniec możemy wyciągnąć czystą wartość za pomocą operatora <-.

Wygląda to stosunkowo niewinnie:

ale warto mieć świadomość, co dzieje się pod spodem. W rzeczywistości dotykamy tu najbardziej chyba przerażającego elementu języka, czyli monad. Kod powyżej czyta linię ze standardowego wejścia i wypisuje ją bez zmin na standardowe wyjście.

6. Brzydkie słowo na „m”.

Monady.

Tysiące tutoriali w Internecie. Długie wpisy (po polsku na przykład ten świetnie przygotowany i napisany tekst Jacka Laskowskiego), godzinne nagrania wideo. Duma lub poczucie wyższości osób, które wreszcie to zrozumiały, więc oficjalnie potrafią programować funkcyjnie.

Offtopic: słowo „monada” kojarzy mi się przede wszystkim ze zbiorem opowiadań „Zamknięty świat”, co dowodzi chyba, że nie była to lektura dla dziecka w podstawówce.

Wytłumaczenie, czym są monady, to temat na osobny, długi wpis – jak ten, który linkuję powyżej. W dużym uproszczeniu (zresztą moje rozumienie tego tematu to nadal właśnie duże uproszczenie): monady to kontenery, które pozwalają na tworzenie łańcuchów operacji, porównywanych do linii produkcyjnych, gdzie każde kolejne stanowisko dodaje coś od siebie. Za pomocą monad można symulować zmiany stanu i dodawać efekty uboczne. Monada obowiązkowo musi definiować dwie operacje, nazywane najczęściej return (włożenie wartości do kontenera) i bind (wyjęcie wartości w celu wstawienia jej do kolejnej funkcji zwracającej monadę; w Haskellu służy do tego operator >>=).

Podstawy teoretyczne monad to teoria kategorii. Po drodze trzeba jeszcze zrozumieć, czym są funktory i monoidy. Zainteresowanym polecam lekturę rozdziału poświęconego monadom w (dostępnej za darmo) książce Learn You a Haskell for Great Good!. Sama wrócę tam jeszcze wiele razy.

7. Istnieją frameworki webowe dla Haskella. Serio.

Można pisać aplikacje webowe w Haskellu. Istnieją gotowe frameworki. Więcej niż jeden! Osobiście znam kogoś, kto napisał w tym języku sklep internetowy.

8. Wyjście poza imperatywną strefę komfortu otwiera oczy raz na zawsze.

Kurs, przynajmniej na początku, wydał mi się bardzo prosty. Uznałam wstępnie, że Haskell ma zaskakująco niski próg wejścia – bo przecież nie programowałam wcześniej w żadnym języku funkcyjnym. Podczas rozmów z innymi kursantami dotarłam jednak do innej przyczyny: przez kilka lat sporo programowałam w Prologu. Wygląda na to, że kiedy raz podejmie się wysiłek przestawienia się na inny sposób myślenia – w tym wypadku nieimperatywny, nieobiektowy i mniej algorytmiczny – o wiele łatwiej wnika się w kolejne dziwactwa.

9. Programowanie funkcyjne, nie funkcjonalne!

Łatwo wpaść w pułapkę tłumaczenia angielskiej nazwy functional programming jako „programowanie funkcjonalne”. Nawet polska Wikipedia dopuszcza ten termin, a przecież jest on pozbawiony sensu! Functional znaczy „oparty o funkcje” (w sensie matematycznym), po polsku „funkcyjny”. „Funkcjonalny” to „związany z działaniem” lub „dobrze spełniający swoją rolę”. O programowaniu funkcyjnym można co prawda powiedzieć, że jest funkcjonalne… 😉 Jednak w pełni poprawna jest tylko pierwsza nazwa.

10. Można wziąć kasę za kurs online, w którym po wiedzę o najtrudniejszych zagadnieniach odsyła się do zewnętrznych stron

Kurs Haskella był pierwszym kursem online, za który zapłaciłam – i dobrze się stało, ponieważ bez takiej motywacji na pewno odpadłabym po którejś nieprzespanej nocy.

Tym boleśniej odczułam fuszerkę, na jaką pozwoliła sobie ekipa z Uniwersytetu Technicznego w Delft. Wiedza przekazana w ramach kursu nie była wystarczająca do odrobienia zadań domowych w jego drugiej części. Co gorsza, w wykładach pominięto właśnie te bardziej problematyczne zagadnienia, począwszy od tego „czym, u licha, jest ta monada?”.

Opisy niektórych zadań domowych rozpoczynały się niepozornym poleceniem przeczytania treści zawartych na zewnętrznej stronie, a zewnętrzne strony wyglądały jak, nie przymierzając, strony man w Linuksie. Suchar.

Przekwalifikowanie – mrzonka czy realna szansa?

Chociaż nie zawsze da się to rozpoznać po ubiorze bądź stylu życia* i niekoniecznie jest to sprawiedliwe, zarobki w miarę doświadczonych programistów czynią z nich jednych z najlepiej wynagradzanych ludzi w Polsce.

Nie wszyscy zajęli się informatyką z powodu absolutnej pasji. Kodowanie to bardzo przyjemna, satysfakcjonująca i stanowiąca wyzwanie praca – jednak wielu znanych mi programistów do poczucia osobistego spełnienia potrzebuje również samorealizacji w nieco bardziej humanistycznych dyscyplinach.** Być może dlatego nierzadko słyszę kolegów po fachu sarkających na bezrobotnych absolwentów kierunków miękkich. „Po co szedł na takie studia?”, „Wiadomo, że praca jest gdzie indziej”, „Niech się przekwalifikuje, przecież my też co chwilę od podstaw uczymy się czegoś nowego”.

Opinie te bywają powtarzane zdecydowanie i bez zastanowienia. A jednak nie tak dawno byłam świadkiem sytuacji, w której absolwent teatrologii (nie wymyślam tego!) zapytał zaprzyjaźnionego programistę, od czego zacząć przekwalifikowanie się… a programista zbladł. Co innego teoretyzować o zmianie w cudzym życiu, a co kogoś przekonać i przyjąć choć część odpowiedzialności za jego rozwój, a ostatecznie także sukces bądź porażkę.

W tym wpisie postaram się odpowiedzieć na pytanie, czy da się zostać programistą na późniejszym etapie życia i podzielę się wskazówkami na temat tego, jak zacząć.

Warunki konieczne

Skoro popyt jest tak duży, czy programistą może zostać każdy? Skrócona odpowiedź brzmi: absolutnie nie!!! Jednak z powodzeniem może się to udać całkiem sporej grupie osób, które wcześniej nie rozważały tej profesji.

Następujące cechy i umiejętności uważam za konieczne do rozpoczęcia nauki w tym kierunku:

1. Analityczne, uporządkowane myślenie

Programowanie to w dużej mierze praca kreatywna, ale ten rodzaj kreatywności ma niewiele wspólnego z twórczym chaosem. Musisz być w stanie myśleć algorytmicznie: wyraźnie definiować kroki prowadzące do uzyskania wyznaczonego celu. Musisz przykładać uwagę do szczegółów. Musisz przewidywać, co może pójść nie tak, jak niestandardowo może się zachować klient, jakie problemy mogą wystąpić. W dużej mierze sprowadza się to do tego, że programista powinien mieć stosunkowo wysoki iloraz „matematycznej” („tradycyjnej”) inteligencji.

2. Cierpliwość

Materiału do przyswojenia jest dużo. Tworzenie prawdziwych, złożonych aplikacji trwa i wymaga współpracy wielu osób. Co prawda istnieją trendy wytwarzania oprogramowania od strony interfejsu użytkownika, gdzie od razu widać włożony wysiłek, jednak musisz być gotowy na żmudną pracę, która długo nie przynosi widocznych efektów (oprócz przechodzących testów – bo oczywiście będziesz pisać testy).

3. Radość z pisania kodu

Większość znanych mi programistów bardzo wcześnie zaczęła zdradzać smykałkę do kodowania. Sama spędziłam długie godziny nad otrzymanym na komunię Commodore 64, programując quizy i przelatujące przez ekran rakiety ASCII Art (następnie mój rozwój zatrzymał się na lata na tym etapie). Jeśli jednak nie zostałeś odpowiednio zachęcony za młodu, postaraj się możliwie szybko znaleźć odpowiedź na pytanie: „czy sprawia mi to przyjemność?”. Po pierwszym kursie programowania lub po pierwszej przeczytanej książce – spróbuj rozwiązać prosty problem programistyczny (np. na sprawdzarce takiej jak ta: http://acm.timus.ru/). Jak było? Udało Ci się? Co czułeś, kiedy program działał coraz lepiej? Ogromną satysfakcję, a może ulgę, że wreszcie koniec? To bardzo ważne.

4. Znajomość angielskiego

W dzisiejszych czasach nie da się programować bez dobrej (biernej) znajomości (pisanego) angielskiego. Większość kursów (o których zaraz) jest po angielsku. Dokumentacja, którą będziesz czytać jest prawie zawsze po angielsku. Gotowe rozwiązania popularnych problemów są opisane po angielsku, np. na http://stackoverflow.com/. Być może uda Ci się dorwać podręcznik po polsku (warto), ale większość ratujących tyłek, aktualnych treści istnieje jedynie w języku angielskim.

Przydadzą się

Po pierwsze, na pewno przyda Ci się mentor. Życzliwa osoba już pracująca w zawodzie, o którym myślisz, skłonna poświęcić Ci trochę czasu i wskazać kierunki rozwoju. Znasz kogoś takiego? Doskonale. Nie znasz? Jeśli mieszkasz w większym mieście, przejdź się kilka razy na spotkania lokalnych User Groups***. W przeciwnym razie możesz spróbować uzyskać wsparcie w grupach i na forach w Internecie.

Po drugie – czy znasz języki obce? Jeśli tak, to tym lepiej dla Ciebie. Im więcej tym lepiej. Język programowania to też język, który ma swoją składnię i semantykę. Jeśli zdołałeś opanować język obcy (analitycznie, czyli potrafisz narysować drzewo składniowe zdania), w Twoim mózgu powinny już być wydeptane najważniejsze ścieżki umożliwiające korzystanie z języka programowania.

Jak się nauczyć?

O ile znasz angielski, a jak tłumaczyłam powyżej, właściwie musisz go znać, to masz do dyspozycji ogrom wiedzy przedstawionej w portalach MOOC (Massive Open Online Course, czyli masowe otwarte kursy online), takich jak Edx czy Coursera. W większości przypadków kursy składają się z wykładów, ćwiczeń praktycznych (w postaci testów) oraz zadań programistycznych, sprawdzanych albo automatycznie, albo przez innych uczestników kursu. To doskonały punkt startowy.

Oprócz tego są podręczniki, dokumentacje języków programowania, a także warsztaty**** (często darmowe) organizowane przez różne społeczności, np. Geek Girls Carrots.*****

Jaki język?

Uparcie utrzymuję, że najbardziej przyszłościowy (liczba ofert pracy, przeznaczenie) język, którego można się w miarę szybko nauczyć od podstaw, to Python. Ale możesz rozejrzeć się, czego potrzebują i uczą w Twojej okolicy.

Rozmowa o pracę

Są firmy, które nigdy nie zatrudnią początkującego programisty. Są szefowie gotowi pracować tylko z pasjonatami, od podstawówki piszącymi wirusy. W niektórych przypadkach takie wymagania mają sens, w innych niekoniecznie. Uwierz jednak, że istnieje masa firm gotowych podjąć ryzyko przyjęcia kogoś niezbyt doświadczonego i przeszkolenia go.

Nie będę tu powtarzać tradycyjnych porad na temat pisania CV i przygotowania do rozmowy rekrutacyjnej. Najważniejsze: nie ściemniaj! Jeśli jesteś w stanie psychicznie znieść porażkę, po nieudanej rekrutacji dopytaj, czego Ci zabrakło i spróbuj rozwinąć się trochę w tym kierunku.

Warto pamiętać, że informatycy w firmach wytwarzających oprogramowanie to nie tylko programiści. Do branży możesz wejść trochę „od tyłu”, na przykład jako tester. Mimo wszystko zachęcam do rozpoczęcia procesu zmian od przyswojenia jednego przynajmniej języka programowania.

Licz się z tym, że…

1. Będziesz się ciągle uczyć

Taki zawód. Jeśli chcesz coś w nim osiągnąć i mieć pewność zatrudnienia, będziesz co jakiś czas przerabiać nową książkę, nowy blog, nowe kursy. Nawet jeśli w pracy nie będziesz siedzieć po godzinach (rozsądni szefowie wiedzą, że liczba błędów wprowadzonych podczas nadgodzin często niweluje jakąkolwiek płynącą z nich wartość dodaną), ale czasem po pracy,  w prywatnym czasie, będziesz musiał przysiąść nad nową technologią.

2. Twoja głowa będzie stale w pracy

To również wynika ze specyfiki zawodu. Nierozwiązane problemy będą się za Tobą wlekły. Spędzisz wiele wieczorów, zastanawiając się, dlaczego to u licha nie działa. Dobra strona medalu: niejednokrotnie przekonasz się, że Twój mózg pracował, kiedy spałeś, a że niemożliwy do rozwiązania problem następnego dnia okaże się trywialny.

3. Koledzy z pracy nie raz zdziwią się, że czegoś nie wiesz

Nauczyłeś się pierwszego języka programowania. Na trzeciej z rzędu rozmowie rekrutacyjnej napisałeś test na 80%, pokazałeś, że jesteś odpowiedzialnym i zdeterminowanym człowiekiem – i dostałeś pracę. Pierwszego dnia przychodzisz do biura, dostajesz swoje pierwsze zadanie i nagle okazuje się, że kompletnie nie wiesz, jak zacząć. Znasz język, ale co oni mówią o LDAP, kontroli wersji, bazie danych…? W tym momencie wróć do punktu 1. Będziesz się ciągle uczyć. W obliczu nieznanych problemów spróbuj najpierw skorzystać z Google. Jeśli nie dajesz rady – poproś o pomoc. Zadbaj o to, żeby nigdy nie pytać dwa razy o to samo.

Studia informatyczne trwają pięć lat i nie polegają jedynie na nauce programowania. Ich absolwenci często sami nie zdają sobie sprawy, że niektóre zagadnienia nie wchodzą w zakres wiedzy ogólnej i mogą być komuś (bądź co bądź) w branży kompletnie nieznane. Przełknij dumę, uzupełnij luki, znajdź sobie miejsce w organizacji. Będzie dobrze.

4. Na początku możesz zarabiać mniej niż dotychczas

Nie tylko możesz zarabiać mniej niż dotychczas, ale na dodatek może to być mniej, niż zarabia o połowę od Ciebie młodszy dzieciak w sąsiednim kubiku. Nie przejmuj się, to tymczasowe. Nie ma lepszej metody nauki programowania niż w prawdziwej pracy – potraktuj to jako (opłacaną przecież!) inwestycję w siebie.

Uwaga: z awansami i podwyżkami w firmach informatycznych różnie bywa. Czasami jedyną metodą na zauważalną podwyżkę jest przejście do innej firmy.

Czy płeć ma znaczenie?

Serio, nie wiem.

Kobiecie, która chce się przekwalifikować, tak samo jak początkującej praktykantce, paradoksalnie może pomóc stereotyp „damy w opałach”. W zmaskulinizowanym biurze możesz pozwolić otoczyć się mentorską, dżentelmeńską i trochę protekcjonalną opieką, o ile całe Twoje jestestwo nie protestuje przeciwko takiemu stawaniu sprawy. Ostrzegam jednak – takie łatki trudno potem zgubić.

Czy znam ludzi, którym się udało?

Tak!!!

Słowa klucze: odwaga, wytrwałość, inteligencja, ciekawość.

A jeśli się nie uda?

Wysiłek włożony w przyswojenie tych kwestii i tak nie pójdzie na marne. Podstawy programowania będą coraz bardziej potrzebne do wykonywania innych zawodów. Wyraźnie to widać np. w dziedzinie biotechnologii.

Przypisy


* Nie piję tu przesadnie do stereotypu niedomytego informatyka. Uważam się za informatyka domytego, a jednak mam na koncie kuriozalne doświadczenie ze sklepu Zara, gdzie na podstawie nieformalnego i powyciąganego ubioru zostałam potraktowana jak złodziejka.

** Zdaniem wielu, stanie w takim rozkroku jest przepisem na porażkę. Polecam wystąpienie Larry’ego Smitha na TED, zatytułowane „Dlaczego nie zrobisz wielkiej kariery”. Jako świeżo upieczona matka karmiąca mam ostatnio dużo czasu na oglądanie takich wykładów, więc od czasu do czas będę się dzielić perełkami 🙂

*** Od razu ostrzegam, że poziom i kultura lokalnych społeczności programistycznych bywają różne. Niektóre są bardzo przyjazne dla początkujących, inne pielęgnują profesjonalny poziom i zadzierają nosa 😉

**** Odmienne od mojego zdanie na temat szkół programowania ma autor tego artykułu w portalu TechCrunch: Coding Academies Are Nonsense. Wrzucam jako ciekawostkę.

***** Powiem szczerze, że cykliczne spotkania Geek Girls Carrots nieco mnie rozczarowują, ponieważ są dużo bardziej startupowe niż programistyczne. Niezależnie od tego, organizacja tworzy i promuje sporo wartościowych kursów programowania dla początkujących.

Konkursy algorytmiczne a przedwczesna optymalizacja

Z algorytmami mam trochę jak z grą w szachy. Lubię sobie czasem pogłówkować, ale nigdy nie wystarczyło mi wytrwałości, żeby przysiąść, poczytać, zapamiętać i wznieść się na naprawdę wysoki poziom. W przypadku algorytmów, na (moje) szczęście, do potraktowania sprawy poważniej w pewnym stopniu zmusiły mnie uczelnia i życie zawodowe.

Wspominałam już, że mam ostatnio więcej czasu niż zwykle. Mimo że mój tymczasowo zalany prolaktyną mózg ma problemy z obliczeniem należnej reszty przy zakupach, postanowiłam rozerwać się, rozwiązując zadania ze startujących właśnie Potyczek Algorytmicznych. Potyczki to otwarty konkurs programistyczny organizowany przez Uniwersytet Warszawski, w którym przez kilka dni rozwiązuje się zadania online, a na koniec najlepsi uczestnicy zapraszani są do rywalizacji w stacjonarnym finale.

W weekend zapoznałam się z zadaniami z rundy próbnej i przeżyłam nieprzyjemne zaskoczenie. Okazało się, że udostępniana uczestnikom konkursu sprawdzarka nie przeprowadza kompletu testów, ani nawet reprezentatywnego ich podzbioru. Zamiast tego, testuje program jedynie na jednym bądź dwóch prostych przykładach par wejście/wyjście podanych w treści zadania. Dopiero po zamknięciu danej rundy nadesłane przez uczestnika konkursu rozwiązanie jest poddawane całemu pakietowi testów.

Czy umknął mi jakiś nowy trend? Tego typu podejście to norma czy wyjątek?

Takie stawianie sprawy budzi mój głęboki opór, ponieważ, cytując klasyka:

Przedwczesna optymalizacja jest źródłem wszelkiego zła.

– Donald Knuth

Przedwczesna optymalizacja to (u)znany antywzorzec projektowy. Po pierwsze, problemy często leżą zupełnie nie tam, gdzie się ich spodziewamy. Po drugie, optymalizacja często zmniejsza czytelność kodu. Jeśli nie jest potrzebna (program w oryginalnej wersji wykonuje się w czasie w zupełności akceptowalnym dla klienta), prowadzi do samych problemów, jak dodatkowe godziny pracy następnego programisty, który musi utrzymywać nieintuicyjnie napisany kod. Po trzecie wreszcie, jeśli nie zdefiniujemy granicy, optymalizować można właściwie w nieskończoność, lub przynajmniej do poziomu operacji na bitach.

Czy o to powinno chodzić w konkursie algorytmicznym? Rozumiem, że TDD (programowanie sterowane testami) dominuje w „przemyśle”, a konkursy rządzą się swoimi prawami, ale nie wydaje mi się dobrym pomysłem stawianie ich w takiej opozycji do dobrych praktyk.

PS. Smaczku całej sprawie dodaje fakt, że, przynajmniej w przypadku zadań próbnych, nie podano limitu czasowego, który obowiązuje w automatycznych testach…

PS2. Wykres w nagłówku w oryginalnej wersji był opisany, ale ostatecznie postanowiłam zamienić go na tematyczną zagadkę. Stawiam piwo pierwszej osobie, która poda pełne opisy X, Y, K i E 🙂

10 rad z obu stron frontu dla początkujących liderów projektów IT

W obliczu czekających mnie niebawem zmian – trochę mniej pracy, trochę więcej rodziny – koncentruję się na porządkach i podsumowaniach. Dziś pozwolę sobie znów oddryfować od kwestii technicznych, tym razem po to, by podzielić się spostrzeżeniami na temat wyzwań stanowiących codzienność liderów w projektach informatycznych. Piszę z własnego doświadczenia w tej roli, ale wplatam tu również garść przygód i wniosków podpatrzonych u swoich szefów oraz znajomych. W końcu uczyć się można nie tylko na własnych błędach.

1. Nie traktuj utraty pracownika w kategoriach osobistej porażki.

Punkt najdłuższy, bo najtrudniejszy.

Są ludzie (bardzo cenni), którzy muszą czuć, że stale się rozwijają. Istnieją firmy (bardzo cenni), które potrafią zapewnić ciągły rozwój pracownikom każdego szczebla.

W większości przypadków główną motywacją pracownika są pieniądze. Można doceniać miłą atmosferę w pracy i bogatą ofertę szkoleń, ale większość osób wstaje co rano do roboty, żeby po powrocie móc prowadzić (wy)godne życie. Pracodawca z kolei może dbać o morale i przydzielać rozwojowe zadania, jednak jego nadrzędnym celem musi być osiąganie zysków. Zyski zaś często pochodzą z najnudniejszych projektów w dobrze rozpoznanych, trywialnych obszarach.

Choćby lider posiadł umiejętność stawania na rzęsach, z każdego zespołu, zwłaszcza większego, w którymś momencie ktoś odejdzie. Potencjalnych przyczyn jest bez liku. Zmęczenie niejasnymi procedurami w firmie. Zbyt niskie zarobki. Ciekawsza oferta z innej firmy, bliższa zainteresowań danej osoby. Rozwój prowadzący do poszukiwań większych wyzwań. Kryzys w życiu prywatnym. No najgorsza z opcji z punktu widzenia lidera: jego koszmarny, chaotyczny styl zarządzania.

Oczywiście, pytanie o przyczynę zawsze warto zadać i sobie, i podwładnemu. Odejście pracownika bywa zaskoczeniem, z kategorii przykrych. Łatwo dać się ponieść emocjom i wznieść się na poziom niemalże oskarżeń o zdradę. Mimo że sama padłam kiedyś ofiarą agresywnego oskarżenia o brak lojalności podczas zmiany pracy, to postawiona po raz pierwszy i drugi wobec czyjegoś wypowiedzenia, musiałam świadomie zdusić w sobie urazę i silną atawistyczną chęć odwetu.

Jestem przekonana, że warto wspierać rozwój swoich podopiecznych, nawet jeśli ostatecznie przerosną przez to macierzystą firmę. Pracownikowi należy się wdzięczność za poświęcony czas i realne osiągnięcia, a nie wypominanie (niewypowiedzianych najczęściej) zadań, których przez swoje odejście nie zdążył zrealizować.

Co z pracownikiem, który faktycznie zniknął z dnia na dzień i zostawił za sobą zgliszcza? Proponuję uczcić jego zniknięcie kieliszkiem szampana. A potem załatać procedurę rekrutacji.

2. Wspieraj rozwój swoich podopiecznych.

Jak wyżej. Niech czują, że oprócz pieniędzy praca daje im coś jeszcze. Stawiaj przed nimi wyzwania, którym zdołają podołać, jeśli się wysilą. Możliwe, że w końcu przerosną firmę i odejdą, ale w takiej sytuacji będą wspominać ją – i Ciebie jako lidera – z wdzięcznością.

3. Krytykuj konstruktywnie.

Zarówno wygłaszanie, jak i przyjmowanie krytyki jest trudne. Istnieje sporo literatury i kursów dedykowanych temu zagadnieniu. Można stosować obciachowe triki, np. „na kanapkę”: pochwała, gorzkie słowo, na koniec znów coś na podniesienie na duchu. Moim zdaniem najważniejsze jest trzymanie się jednej humanitarnej zasady: słowa krytyki mają służyć rozwojowi. Przekazanie negatywnej oceny nie ma być okazją do odreagowania. Spróbujcie razem zrozumieć, co poszło nie tak i dlaczego. Jak uniknąć problemów w przyszłości? W jakim obszarze dana osoba powinna się dokształcić, jakie reguły poznać? Jakich zadań zwyczajnie nie należy jej przydzielać?

Beznadziejne przypadki są rzadkie. Najtrudniejsze sytuacja, z jaką sama się spotkałam, to osoba omyłkowo zatrudniona powyżej swoich kwalifikacji: kontaktowa, pracowita, ale niezdolna do efektywnego ogarnięcia przydzielonej jej odpowiedzialności.

4. W piętrowej korporacyjnej strukturze dbaj o równowagę lojalności wobec szefa i wobec podwładnych.

Ochrona plemiennych interesów i rodzinna atmosfera w zespole projektowym to jedno, ale nie możesz też w nieskończoność ukrywać niekompetencji sympatycznego członka zespołu przed wspólnym szefem. Za niepowodzenie ostatecznie zapłacicie wszyscy. Zakładam, że mój szef powinien mieć ogólne wyobrażenie na temat mocniejszych i słabszych stron osób, z którymi pracuję – głównie po to, żeby mógł w razie potrzeby sensownie przesuwać je pomiędzy projektami. Absolutnie bez skarżenia, kto akurat dzisiaj się spóźnił albo wypchnął kod do repozytorium bez przeprowadzenia elementarnych testów.

Uważaj również na zasłanianie się szefem. Musisz ogłosić niepopularną decyzję, a może nawet sam się do jej podjęcia przyczyniłeś? Najłatwiej powiedzieć „cierpię z wami, ale góra tak chciała”. Są rzadkie sytuacje, w których takie podejście to najmniejsze zło – decyzja jest nieodwołalna, a czasu na dyskusję brak. Staraj się jednak zachować uczciwość i nie maluj szefa jako wcielonego diabła, gdy faktycznie robisz z niego kozła ofiarnego. Uczciwość nakazuje przyjąć odpowiedzialność za własne decyzje. Poza tym, brak zaufania do wyższych szefów i przekonanie o życiu w oblężonej twierdzy pogorszy poczucie bezpieczeństwa członków zespołu, a ostatecznie także ich wydajność i lojalność wobec pracodawcy.

5. Wysyłaj maile z podsumowaniem, w obie strony.

Szefowi (bądź klientowi) regularnie ślij maile podsumowujące status projektu i pytania o sprawy wymagające jego decyzji bądź opinii. Polecam wypunktowanie najważniejszych elementów na samym początku.

Do „dzieci” pisz przede wszystkim po spotkaniach. Przypominaj najważniejsze poruszone kwestie (np. terminy) oraz wysokopoziomowy przydział zadań (do niskopoziomowych zadań jest specjalny system, prawda?). Na wypadek gdyby ktoś nie uważał, nie zrozumiał, był nieobecny.

6. Dbaj o kulturę szczerości i odpowiedzialności.

Deleguj. Nie musisz wszystkiego robić sam. Sprawdzaj na koniec – ale deleguj też sprawdzanie (np. przeglądy kodu pomiędzy programistami). Wstydliwe wpadki omawiaj prywatnie. Jeśli się powtarzają – na forum, najlepiej bez wskazywania winnych.

Stwórz atmosferę, w której pracownik będzie wolał od razu przyznać się do błędu, niż tygodniami go tuszować.

7. Konflikty duś w zarodku.

Znam menedżerów całkowicie obojętnych na konflikty pomiędzy pracownikami. Niektórzy w ogóle ich nie widzą, inni decydują się nie wtrącać.

Dla mnie przyjazna atmosfera w pracy (a przynajmniej w podstawowej komórce rodzinnej jaką jest jeden projekt) to absolutny priorytet. Chcę, żeby pracownicy mogli nawzajem na siebie liczyć. Energia utracona na konflikty i „polityczne” rozgrywki to niepowetowana strata dla wszystkich zaangażowanych stron.

Z własnego doświadczenia dorzucę jeszcze to: ufaj swojej intuicji i w razie czego szybko pozbądź się zakały. Ktoś jest trudny we współpracy, ale nie potrafisz sprecyzować dlaczego i myślisz, że może tylko Tobie się tak wydaje? Odrzuć taką osobę od razu. Trudno tu nawet polegać na podpytywaniu zespołu – źle pojęta lojalność i niechęć do donosicielstwa zachwiała kiedyś posadami mojego projektu.

8.Nie ignoruj praw i spraw mniejszości.

Miło i wygodnie żyje się w gronie osób bardzo podobnych do nas. Nikt nikogo nie zmusza do weryfikacji zastałych poglądów, wszyscy śmieją się z tych samych żartów. Niemało menedżerów zatrudnia według tego klucza – O, lubi Star Wars i Philipa Dicka! Wpisuje się w nasz kulturowy kod, więc na pewno będzie dobrym programistą.

Różnorodność bywa jednak otrzeźwiająca. Inne tło społeczne może wygenerować przydatne refleksje niedostępne dla monolitycznego kulturowo zespołu. To zysk, ale wprowadzenie do zespołu kogoś odmiennego (pierwszej kobiety, przedstawiciela innej religii, obcokrajowca, skrajnego introwertyka) wymaga przebudowania codzienności i chwilowego z(a)burzenia komfortu. Nie chcę powtarzać wywodów na temat seksizmu w miejscu pracy, ale dzięki własnym nieprzyjemnym doświadczeniom doskonale rozumiem osoby narażone na (najczęściej niezamierzone) przejawy dyskryminacji.

Dla mnie jako lidera stresującym momentem było dodanie do regularnie żartującego z Kościoła zespołu osoby, która w CV pochwaliła się religią. Ostatecznie jakość wspólnych obiadów nie ucierpiała na odpuszczeniu tego akurat tematu.

Odmienności kulturowej nie należy, rzecz jasna, mylić z brakiem kultury.

9. Przyznawaj się do własnych błędów. Zwłaszcza, jeśli są zabawne.

Dobry humor zawsze w cenie. Poza tym, jak zdążyłam już wspomnieć, wierzę, że uczyć się można nie tylko na własnych błędach, więc te ciekawsze lub zabawne warto pokazać. Wreszcie, jeśli przyznasz się sam, zmniejszasz szanse, że ktoś znajdzie błąd i wprost ci go wytknie 🙂

10. Ciągle się kształć, ale pogódź się z tym, że w pewnych obszarach będziesz wiedzieć mniej od swoich podwładnych.

Lider w projekcie informatycznym musi mieć wiedzę techniczną. Programiści nie szanują szefów, którzy kompletnie nie znają się na rzeczy.

Oczywiście, w skomplikowanym projekcie z dziesięcioma inżynierami trudno się spodziewać, żeby każdy był w stanie zastąpić każdego. Lider nie może wszystkiego zrobić sam, a dziesięciu liderów niekoniecznie stworzy działający projekt. Powinien jednak wiedzieć, czym zajmuje się i na jakim jest etapie każdy z podwładnych. Czy wykonuje swoją pracę wystarczająco dobrze? Dlaczego korzysta z takich, a nie innych rozwiązań?

Jeśli czujesz, że zaczynasz się gubić w pracach programisty lub podprojektu, poproś o prezentację dla laików.

Rada numer 10 zadziała też po odwróceniu:

10′. Pogódź się z tym, że w pewnych obszarach będziesz wiedzieć mniej od swoich podwładnych, ale ciągle się kształć.

—-

Jakie są Wasze doświadczenia w tej dziedzinie? Pominęłam coś ważnego? Napisałam głupoty? Może dla Was liczą się zupełnie inne aspekty? Chętnie poczytam.

Ciągła Integracja: jak skonfigurować proces budowania na serwerze Bamboo?

Ten wpis jest uzupełnieniem artykułu Ciągła Integracja: anioł stróż dobrego programisty, gdzie obiecałam pokazać konfigurację procesu budowania na konkretnym przykładzie serwera Atlassian Bamboo.

Co jest potrzebne? Parę słów na temat konfiguracji serwera i agentów

Żeby zdefiniować proces budowania przy użyciu Bamboo musimy mieć dostęp do:

  1. Serwera Bamboo, który będzie zarządzał naszymi procesami budowania (inaczej buildami lub planami budowania).
  2. Agentów Bamboo, czyli serwerów roboczych, które będą realizowały zadania zlecone przez Serwer Bamboo.

Kod serwera i agentów jest napisany w Javie. Serwery robocze, które chcą pełnić rolę agentów Bamboo i przyjmować zadania związane z procesem budowania, muszą zarejestrować się na serwerze.

Bamboo można, po wykupieniu licencji, zainstalować na własnym serwerze – z taką instalacją mam do czynienia na co dzień w pracy. Druga możliwość to skorzystanie z chmury firmy Atlassian. Wszystkie użyte w tym wpisie zrzuty ekranu pochodzą z wersji demonstracyjnej w chmurze (Bamboo Cloud). Główny serwer Bamboo działa wówczas w chmurze firmy Atlassian, natomiast agentów (serwery robocze) musisz uruchomić w chmurze Amazon EC2 w oparciu o obraz systemu dostarczony przez Atlassiana. Architekturę tego rozwiązania przedstawia poniższy rysunek.

1
Architektura Bamboo w wersji pochmurnej (http://devopscloud.net/2011/03/25/setting-up-a-windows-ami-for-use-with-elastic-bamboo/)

Przy okazji drobna uwaga z kategorii troubleshooting: spędziłam parę godzin na próbach zrozumienia, dlaczego, mimo że moja instancja w chmurze EC2 bez problemu uruchamia się na żądanie serwera, nie realizuje żadnych wyznaczonych przez serwer zadań. Wreszcie okazało się, że odpowiedni obraz systemu z zainstalowanym agentem Bamboo jest dostępny tylko, jeśli jako lokalizację wybiorę region „US East (N. Virginia)”. W przeciwnym razie uruchamia się czysty system, niezdolny do współpracy z serwerem Bamboo. Być może od czasu moich prób problem został już rozwiązany.

Struktura Planu Bamboo

Proces budowania (ang. build) w świecie Bamboo jest określany mianem Planu Budowania (ang. Build Plan).

Tabela poniżej przedstawia elementy tworzące strukturę takiego planu.

Projekt
  • Może zawierać wiele planów.
  • Wyświetla zbiorczy raport dla wszystkich swoich planów.
  • Łączy się z innymi aplikacjami (np. JIRA do zarządzania zadaniami, Crucible do przeglądów kodu).
Plan
  • Dzieli się na Etapy, które wykonywane są sekwencyjnie.
  • Definiuje domyślne repozytorium kodu.
  • Określa, kiedy uruchomić proces budowania (wyzwalacze planu).
  • Wysyła powiadomienia o wynikach kolejnych przebiegów.
  • Pozwala definiować zmienne planu.
Etap (Stage)
  • Dzieli się na Porcje Pracy, wykonywane równolegle na wielu agentach jednocześnie (jeśli są dostępne).
  • Etap (tj. wszystkie Porcje Pracy) musi się zakończyć powodzeniem, żeby wykonany został kolejny etap.
Porcja Pracy(Job )
  • Steruje wykonaniem listy Zadań, sekwencyjnie na tym samym agencie.
  • Zbiera wymagania poszczególnych zadań, by wybrać agenta z odpowiednim zestawem umiejętności (ang. capabilities).
  • Definiuje artefakty.
Zadanie (Task)
  • Zadanie to atomowa jednostka pracy, np. pobranie kodu z repozytorium, wywołanie polecenia Maven, uruchomienie skryptu.

Kompletna dokumentacja w języku angielskim jest dostępna na stronie https://confluence.atlassian.com/display/BAMBOO/Bamboo+Documentation+Home.

Utworzenie planu

Po pierwsze, w nowszych wersjach firma Atlassian ukryła przed użytkownikami link do Bamboo. Jeśli masz już konto w Jira/Bamboo Cloud lub dostęp do firmowej instalacji, oto jak przejść do panelu Bamboo:

Link do konfiguracji Bamboo
Link do konfiguracji Bamboo

Tworzenie planu:

Tworzenie nowego planu (procesu budowania)
Tworzenie nowego planu (procesu budowania)

Po utworzeniu planu możemy przejść do jego konfiguracji (na rysunku widać plan, który został już kilka razy uruchomiony – kolorowe ptaszki i wykrzykniki to historia jego kolejnych przebiegów):

5
Historia wyników i przejście do konfiguracji planu

Repozytorium kodu źródłowego

Plan ma na celu testowanie, budowanie i być może wdrażanie kodu źródłowego. Kod powinien być przechowywany w dobrze zorganizowanym repozytorium. Bamboo pozwala połączyć się ze wszystkimi najpopularniejszymi repozytoriami (w przypadku rozwiązań niestandardowych można jeszcze uciec się do pomocy pluginów). Repozytoria kodu źródłowego (w widocznym na rysunku przykładzie jest do publiczne repozytorium GitHub) konfiguruje się w zakładce Repositories:

Dodanie definicji repozytorium kodu źródłowego
Dodanie definicji repozytorium kodu źródłowego

Wyzwalacze

Wspomniałam w poprzednim wpisie, że każdy proces budowania ma swoje wyzwalacze. Możesz chcieć uruchamiać go ręcznie, automatycznie o określonej porze, albo po zmianie w wybranym repozytorium kodu. Jeśli zakończyłeś już konfigurację repozytoriów, możesz przejść do zakładki Triggers i tam zdefiniować wyzwalacze:

Kiedy uruchomić plan?
Kiedy uruchomić plan?

Ręczne uruchomienie planu przez wyznaczone osoby (zakładka Permissions pozwala na definicję uprawnień) zawsze jest możliwe, dlatego tej opcji nie ma na rozwijanej liście. Do dyspozycji masz: odpytywanie repozytorium o zmiany (sam wyznaczasz interwał dla tych zapytań), reakcję na sygnał z repozytorium, planowanie w oparciu o składnię cron oraz możliwość prostszego wskazania konkretnej godziny, o której plan ma zostać wykonany.

Powiadomienia

Skoro wiesz już, kiedy będzie uruchamiany plan, możesz podjąć decyzję kto, kiedy i jakim kanałem ma być powiadamiany o jego wynikach. Podstawowe źródło informacji to oczywiście raport widoczny poprzez interfejs www serwera,  gdzie wyniki odpowiednich planów „palą się” na czerwono bądź zielono. Warto wprowadzić wśród programistów dyscyplinę zerkania tam przynajmniej rano, po przyjściu do pracy. Oprócz tego możesz jednak stworzyć proste reguły powiadamiania konkretnych osób – np. mailem – o powodzeniu bądź niepowodzeniu procesu. Służy do tego zakładka Notifications.

Dobra rada – nie przesadzaj z powiadomieniami, ponieważ w końcu programiści przekierują je do katalogu spam. Informuj tylko te osoby, które naprawdę powinny wiedzieć o awarii lub samym fakcie uruchomienia danego planu.

Kto powinien wiedzieć o wynikach?
Kto powinien wiedzieć o wynikach?

Tworzenie etapu (Stage)

Domyślnie plan składa się z jednego etapu (Default Stage). Jeśli etapów będzie więcej, zostaną wykonane sekwencyjnie, przy czym niepowodzenie jednego z etapów zatrzyma wykonanie kolejnych. Dodatkowe etapy możesz tworzyć, korzystając z przycisku Create stage w zakładce Stages.

Tworzenie etapu (stage) w procesie budowania
Tworzenie etapu (stage) w procesie budowania

Tworzenie porcji pracy (Job)

Etap składa się z jednej lub więcej porcji pracy. Na powyższym rysunku widać etap zawierający dwie porcje pracy (Job1 i Job2) oraz możliwość dodania kolejnych (Add Job).

Uwaga! – porcje pracy są wykonywane równolegle; ich kolejność na liście nie ma najmniejszego znaczenia (Bamboo sortuje je alfabetycznie). Jeśli masz dyspozycji tylko jeden serwer roboczy, to oczywiście zostaną wykonane jedna po drugiej – w kolejności, na którą nie masz wpływu.

Każdej porcji pracy przypisane jest kilka właściwości:

  1. Zadania (patrz niżej)
  2. Artefakty (również niżej)
  3. Wymagania

Wymagania to oczekiwania wobec serwera roboczego, który może podjąć się wykonania danej porcji pracy (i zdefiniowanych w niej zadań). Możemy zażądać dostępności określonych bibliotek, nałożyć wymagania na nazwę serwera itp. Wymaga to pewnej konfiguracji po stronie agenta Bamboo. Serwer Bamboo sprawdza wymagania w czasie rzeczywistym i od razu informuje, ile agentów potrafi wykonać daną porcję pracy.

W poniższym przykładzie żaden agent nie spełnia wymagań (zerowych), ponieważ nie została uruchomiona żadna instancja w chmurze 🙂

Definicja wymagań porcji pracy wobec serwera roboczego (agenta Bamboo)
Definicja wymagań porcji pracy wobec serwera roboczego (agenta Bamboo)

Tworzenie zadania (Task)

Zadanie to najmniejsza, atomowa jednostka pracy w planie Bamboo. Zadania są definiowane w ramach jednostek pracy i są wykonywane sekwencyjnie. Uwaga – niepowodzenia są raportowane na poziomie jednostek pracy: nie dostaniesz czytelnej informacji, które z zadań spowodowało problem (chyba że w dobrze zorganizowanych logach lub na postawie informacji o tym, który test nie przeszedł).

Bamboo predefiniuje wiele zadań. Pobranie danych z repozytorium, wykonanie budowania przy użyciu narzędzia takiego jak Maven – w takich sytuacjach musisz tylko wypełnić odpowiedni formularz, np. wskazując odpowiednie ze zdefiniowanych repozytoriów.

Poniższy zrzut ekranu przedstawia widok jednego z dwóch zadań w ramach jednostki pracy. Jest to predefiniowane zadanie pobrania kodu z repozytorium kodu źródłowego.

Zadania w ramach porcji pracy
Zadania w ramach porcji pracy

Jeżeli musisz zrobić coś niestandardowego – jak niezalecane specjalnie wysłanie przeprowadzonych przez Twój plan zmian w kodzie do repozytorium – możesz poszukać odpowiedniego pluginu (lub samodzielnie go napisać), albo użyć zadania Script, w którym samodzielnie napiszesz kod dla odpowiedniej powłoki w systemie operacyjnym agenta:

Niestandardowe zadanie: zawsze można napisać skrypt!
Niestandardowe zadanie: zawsze można napisać skrypt!

Artefakty

Artefakty, czyli dodatkowe produkty planu budowania, jak wspomniałam już wcześniej, są dostępne na etapie jednostek pracy (jobs), ale wygenerować je trzeba przy użyciu zadań. Kod przedstawiony na powyższym rysunku zapisuje do pliku wartość jednej ze zmiennych Bamboo (ich lista oraz zasady definiowania własnych są dostępne tutaj). Możemy oznaczyć ten plik jako artefakt planu. Artefakty można pobierać (także przez przeglądarkę) oraz współdzielić pomiędzy etapami (a w nowszych wersjach serwera również pomiędzy planami).

Oto, jak wygląda gotowy do pobrania artefakt:

Artefakt gotowy do pobrania po udanym przebiegu planu
Artefakt gotowy do pobrania po udanym przebiegu planu

Uwaga! – przy definiowaniu artefaktów należy pamiętać o tym, że ścieżkę do nich podaje się względem katalogu roboczego danej jednostki pracy. Jeśli korzystasz ze ścieżek bezwzględnych na serwerze, możesz sprawdzić wartość zmiennej bamboo.build.working.directory.

Testy

Testy mają kluczowe znaczenie dla całego procesu ciągłej integracji. Technicznie sprowadzają się jednak do zwykłego, predefiniowanego zadania Bamboo: odczytu wskazanego przez Ciebie (w katalogu roboczym) pliku JUnit/XML.

Troubleshooting (na podstawie własnych, bolesnych doświadczeń):

  1. Jeśli w planie były nieprzechodzące testy, a w kolejnym przebiegu testów brak, Bamboo uzna to za błąd kompilacji.
  2. Kilka wersji Bamboo przejawiało następujący błąd: katalog z wynikami testów nie był odświeżany, jeśli plan został wykonany „zbyt szybko”.
  3. Jeśli chcesz dopuścić nieprzechodzące testy (np. na potrzeby TDD), musisz skorzystać z opcji dodania ich do kwarantanny.

Podsumowanie

Rysunek przedstawia podsumowanie kilku ostatnich przebiegów w planie budowania Bamboo, wraz z informacją o przyczynie uruchomienia planu i o liczbie testów:

Podsumowanie ostatnich przebiegów planu budowania wraz z informacją o liczbie testów i przyczynie uruchomienia procesu
Podsumowanie ostatnich przebiegów planu budowania wraz z informacją o liczbie testów i wyzwalaczu

Dla każdego z przebiegów możesz bardzo intuicyjnie doklikać się do informacji o testach, commitach do repozytorium i odpowiedzialnych za nie osobach. Wspominałam już o możliwości synchronizacji Bamboo z innymi produktami firmy Atlassian. Możesz, na przykład, utworzyć zadanie w Jirze w oparciu o nieudany przebieg:

Możliwość utworzenia zadania w Jirze w oparciu o nieudany przebieg procesu budowania
Możliwość utworzenia zadania w Jirze w oparciu o nieudany przebieg procesu budowania

Miłej zabawy!

Wsadźcie sobie w **** ten apostrof

Nadal potrzebna powtórka z poprzedniego bloga. Krótko i do rzeczy.

Apostrof to znak, który w poprawnej polszczyźnie stosowany jest tylko w wyjątkowych okolicznościach, a jednak wylewa się z połowy reklam i ulotek oraz z mojej tablicy na Facebooku (uprzejmie proszę o zwrócenie uwagi na brak apostrofu w ostatnim słowie).

Nie rażą mnie przesadnie typowe dla krótkich internetowych tekstów uproszczenia: brak polskich znaków, skróty, zubożona interpunkcja. Usprawiedliwiają je pośpiech, lenistwo, świadomość ulotności internetowych treści. Nie rozumiem natomiast kompletnie, po co masa podejmuje dodatkowy wysiłek wepchnięcia do tekstu nadmiarowego i niepoprawnego znaku ’.

Postaram się krótko wyjaśnić, kiedy faktycznie należy użyć apostrofu podczas odmiany wyrazów obcojęzycznych, a zwłaszcza obcojęzycznych nazwisk.

Jeśli ktoś nazywa się Adam Nowak, w dopełniaczu użyjemy formy Adama Nowaka. Czy Twoim zdaniem, gdyby Adam Nowak nie był czystej krwi Polakiem, tę odmianę trzeba by zapisać jako Adam’a Nowak’a? Oczywiście, że nie… Skąd w takim razie biorą się potworki takie jak odmiana James’a Bond’a?!

Wbrew pozorom, sprawa jest prosta: apostrofu używamy wtedy, kiedy nazwisko kończy się niewymawianą literą (najczęściej jest to samogłoska e) i intuicyjnej odmiany po prostu nie da się sensownie zapisać po polsku. Apostrofu użyjemy zatem, odmieniając nazwisko Remarque (Remarque’a), ale nie Heller (Hellera).

I TYLE.

Jeśli chcesz podrążyć głębiej, serdecznie zachęcam do zakupu dzieła pod tytułem „Polszczyzna na co dzień”. To nieocenione źródło informacji w wielu przypadkach, w których kończą się kompetencje tradycyjnych słowników.

Na koniec zadanie domowe (dla chętnych). Spróbuj odmienić następujące nazwiska:
house

  1. Sherlock Holmes
  2. Bruce Eckel
  3. Spock
  4. Clark Gable
  5. Alain Resnais

Google w gąszczu danych: fotograficzny skandal i uczenie maszynowe dla laików

Dwa tygodnie temu media obiegła wieść o skandalicznej wpadce Google Photos. System automatycznego rozpoznawania twarzy i obiektów na zdjęciach zaklasyfikował dwie czarnoskóre osoby jako „goryle” i utworzył dla nich specjalny album o tym właśnie tytule.

Wśród tłumaczeń Google – a trzeba firmie przyznać, że zareagowała bardzo szybko – najbardziej spodobało mi się wyznanie, że twarze białych osób niejednokrotnie są rozpoznawane i podpisywane jako foki albo psy.

Moją uwagę przykuły komentarze czytelników, którzy domagali się „natychmiastowej zmiany algorytmu”. Pomyślałam, że to dobra okazja, żeby napisać kilka słów o uczeniu maszynowym i wyjaśnić, że za tę wpadkę nie odpowiada algorytm w klasycznym znaczeniu tego słowa.

Algorytm to skończony ciąg jasno zdefiniowanych czynności, koniecznych do wykonania pewnego rodzaju zadań. Ludzie stosują algorytmy w swoim codziennym życiu, mniej lub bardziej świadomie (każdy z nas wie mniej więcej, jakie kroki należy wykonać w celu wymiany  zepsutej żarówki). Jeżeli jednak chcemy skłonić do działania komputer, musimy powiedzieć mu wyraźnie i jednoznacznie, jak ma postąpić w określonej sytuacji.

Jedną z metod zapisu algorytmów są schematy blokowe. Poniższy diagram przedstawia schemat blokowy algorytmu sprzątania po swoim psie w miejscu publicznym.

algorytm-pies
Algorytm sprzątania po swoim psie w miejscu publicznym

Przykład pięknego „poważnego” algorytmu znajdziesz w moim poprzednim wpisie.

Algorytmy można badać i porównywać, dzięki czemu powstają ich coraz szybsze i sprawniejsze wersje. Istnieje jednak grupa problemów, które algorytmom nie poddają się najlepiej. Chodzi albo o zadania bardzo skomplikowane, w których rozpisywanie kroków zajęłoby całe lata, albo o takie, które ludzkie mózgi wykonują bardzo szybko, ale ich nosiciele sami nie są w stanie odpowiedzieć na pytanie, jak to się dzieje. Doskonałymi przykładami są tutaj rozpoznawanie twarzy i rozpoznawanie mowy. Sprawa nie jest trywialna. Wiadomo, że istnieją choroby, które odbierają ludziom wymienione przed chwilą umiejętności, nie zaburzając przy tym zdolności logicznego myślenia.

Problemy z opisanej kategorii można rozwiązywać przy użyciu uczenia maszynowego. Jest to dziedzina, która od lat dziewięćdziesiątych nabiera coraz większego znaczenia, w miarę jak wzrasta moc obliczeniowa komputerów i wraz z dostępnością coraz większej ilości danych w Internecie. Dominują dwa nurty: pierwszy oparty na sieciach neuronowych (mających naśladować budowę ludzkiego mózgu), drugi na statystyce i rachunku prawdopodobieństwa.  Poniżej przedstawię prosty (żeby nie użyć mocniejszego słowa) przykład statystycznego uczenia maszynowego.

Jak to działa? Rozważmy popularne zadanie wykrywania spamu. Jeżeli przeanalizujemy tysiąc maili, z których połowa została przez użytkownika oznaczona jako spam, a połowa to normalne, pożądane treści, będziemy w stanie wyciągnąć jakieś wnioski. Możemy, na przykład, utworzyć listę słów, które pojawiły się w wiadomościach i podliczyć, ile razy dane słowo pojawiło się w wiadomości oznaczonej jako spam, a ile razy w wartościowej wiadomości. W ten sposób dla każdego ze słów wyznaczymy prawdopodobieństwo „bycia spamem”. Kiedy pojawi się nowa wiadomość, możemy, w oparciu o listę słów, wyliczyć całkowite prawdopodobieństwo (ryzyko), że dana wiadomość to spam.

Poniżej przykładowy prosty model i związane z nim wyliczenia. Proszę pod żadnym pozorem nie uczyć się z tego statystyki!!!

Wiadomości otrzymane przez użytkownika, zaklasyfikowane przez niego jako wartościowe treści albo spam:

Treść wiadomości Klasyfikacja
Ciociu, jak będzie okazja, kup mi nad morzem wisiorek z bursztynem. Ok.
Okazja! Tylko dzisiaj kup viagrę za 30 zł! Okazja! Spam.

Analiza słów zawartych w wiadomościach:

Słowo Wystąpień „spam” Wystąpień „ok” Prawdopodobieństwo, że to spam
ciociu 0 1 0
kup 1 1 1/2
okazja 2 1 2/3
viagrę 1 0 1
wisiorek 0 1 0

Próba automatycznego oszacowania, czy nowe wiadomości należy wrzucić do folderu „spam”:

Treść nowej wiadomości Prawdopodobieństwo, że spam?
Ciociu, kup wisiorek. (0+1/2+0)/3 = 1/6 = 16.6%
Ciociu, kup viagrę. (0+1/2+1)/3 = 1/2 = 50%
Kup viagrę. (1/2+1)/2 = 3/4 = 75%

Można spotkać się z terminem „algorytm uczenia maszynowego”, ale należy pamiętać, że najczęściej mamy w tej kategorii do czynienia z matematycznymi metodami, które dadzą kompletnie odmienne wyniki w zależności od tego, na jakim zbiorze danych zostaną wytrenowane.

Jakie są efekty? Raczej dobre. Nie da się jednak dogodzić wszystkim, a już na pewno nie na podstawie jednego, wspólnego zbioru danych. Większość z nas chce, aby reklamy środków na powiększenie penisa automatycznie trafiały do katalogu „spam” lub do kosza, ale ktoś przecież takie środki kupuje i wówczas z pewnością chce się dowiedzieć, kiedy dotrze do niego upragniona przesyłka. Poza tym, zbiór danych użyty do trenowania może okazać się za mały, za duży, błędnie opisany lub niewystarczająco reprezentatywny.

Co dokładnie stało się w przypadku Google? Najprawdopodobniej dane wykorzystane do uczenia nie były wystarczająco reprezentatywne – występowali na nich głównie biali ludzie, więc system uwzględnił jasny kolor skóry jako istotny wyznacznik bycia człowiekiem. Warto dodać, że autor (i obiekt) fotografii, które rozpętały całe to zamieszanie, sam jest programistą i od razu zaznaczał, że wie co się stało. Pytał tylko retorycznie „skąd wzięliście te dane?”. Najbardziej wstydliwa możliwość, choć raczej mało prawdopodobna, jest taka, że podczas trenowania użyte zostały zdjęcia opatrzone rasistowskimi komentarzami, które system potraktował jako pewnik.

Problem nie jest łatwy do naprawienia. Być może firma do końca nie wie, skąd pochodziły dane. Być może trenowanie trwa wiele dni. Zgodnie z aktualnymi doniesieniami, etykieta „gorillas” została na wszelki wypadek kompletnie usunięta z systemu.

Elegancki algorytm miesiąca: Kadane

Mój pracodawca niespodziewanie wpadł na pomysł poddania wszystkich programistów testom algorytmicznym. Plan niepokojący, zwłaszcza dla „seniorów”, wobec których oczekiwania są wysokie, a którzy na co dzień raczej nie implementują własnoręcznie ekstrawaganckich algorytmów sortowania.

Na szczęście (niekoniecznie dla efektów pracy projektowej) w ramach zachęty otrzymaliśmy możliwość uczestnictwa w pięciodniowym kursie algorytmicznym. Mam za sobą dwa takie dni i muszę powiedzieć, że wrócił mi zapał do programowania, jakiego nie czułam od lat!

Urzekł mnie pewien króciutki i bardzo elegancki algorytm rozwiązujący problem znalezienia podciągu o największej sumie.

Problem

Niech dana będzie tablica (ciąg) liczb o długości co najmniej 1.

4 -10 3 29 -3 12 -5 4

Zadanie polega na znalezieniu w tablicy spójnej podtablicy o największej sumie elementów i zwróceniu tej sumy. W naszym przypadku całkowita suma elementów tablicy to 34, natomiast maksymalna suma podciągu elementów to 41. Elementy składające się na tę maksymalną sumę oznaczyłam kolorem czerwonym.

Programujesz?

Poświęć chwilę na rozwiązanie tego problemu. Jaką złożoność obliczeniową ma Twój program?  Brute force to pewnie O(n2). O(nlogn)? Nieźle. Ile masz linii?

Niniejszym przedstawiam przepiękny, pięciolinijkowy algorytm o złożoności liniowej, czyli O(n).

Programowanie dynamiczne

Eleganckie rozwiązanie tego problemu jest oparte na pomyśle określanym mianem „programowania dynamicznego”. Co to znaczy?

Można zauważyć, że niektóre problemy algorytmiczne da się podzielić na mniejsze podzadania.

  • Jeżeli podzadania te są od siebie niezależne, w ramach uproszczenia warto zastosować metodę „dziel i zwyciężaj” – w ten sposób działa wiele dobrych algorytmów sortowania (np. quicksort).
  • Jeśli podzadania w jakiś sposób na siebie nachodzą i jedne wyniki są inkrementacyjnie zależne od drugich, można spróbować użyć programowania dynamicznego.

Programowanie dynamiczne przypomina stosowanie rekurencji, z tą różnicą, że potrzebne nam wyniki cząstkowe wyznaczamy tylko raz. Wynik możemy konstruować wstępująco (najpierw wynik dla najmniejszego podproblemu, potem narastająco dla coraz większych zadań) lub zstępująco (definiujemy „rekurencyjną” zależność pomiędzy wynikiem większego problemu a problemami mniejszymi, tyle że potrzebne nam wyniki zapamiętujemy w jakimś buforze i nie wyznaczamy ich ponownie).

Algorytm Kedane’a

Implementacja w Pythonie dla tablicy A wygląda tak:

I już!!!

Jak to działa?

Najpierw wyznaczamy wynik dla najmniejszej tablicy, o długości jeden. Suma elementów tablicy o tej długości (największa, najmniejsza i każda inna suma) to oczywiście wartość jedynego elementu (A[0]).

Przez cały czas działania algorytmu będziemy utrzymywać dwie zmienne: max_total to nasz najlepszy napotkany do tej pory wynik, natomiast max_local to najlepszy wynik zawierający aktualnie obsługiwany element.

Przechodząc przez kolejne elementy,  za max_local każdorazowo podstawiamy większą z dwóch liczb: aktualny element x lub dotychczasową wartość max_local zwiększoną o x.

Jeśli nowy wynik lokalny jest większy od max_total, zamieniamy wartość max_total.

Ostatnia wartość max_total jest naszą odpowiedzią dla problemu wielkości całej tablicy.

Studium przypadku

Zakresy w tabeli oznaczyłam odpowiednim formatowaniem. Zielone elementy składają się na max_local, a podkreślone na max_total.

Zatem, dla naszej początkowej tablicy, algorytm będzie przebiegał następująco:

Element 0
4
  • max_local = 4
  • max_total = 4
Element 1
4 -10
  • max_local = max(-10,-10+4) = -6
  • max_total = max(4,-6) = 4
Element 2
4 -10 3
  • max_local = max(3,-6+3) = 3
  • max_total = max(4,3) = 4
Element 3
4 -10 3 29
  • max_local = max(29,3+29) = 32
  • max_total = max(4,32) = 32
Element 4
4 -10 3 29 -3
  • max_local = max(-3,32-3) = 29
  • max_total = max(32,29) = 32
Element 5
4 -10 3 29 -3 12
  • max_local = max(12,29+12) = 41
  • max_total = max(32,41) = 41
Element 6
4 -10 3 29 -3 12 -5
  • max_local = max(-5,41-5) = 36
  • max_total = max(41,36) = 41
Element 7
4 -10 3 29 -3 12 -5 4
  • max_local = max(4,36+4) = 40
  • max_total = max(41,40) = 41

Ładny, prawda? 🙂

Posłowia

  1. „Algorytm Kadane’a” piszemy z apostrofem, inaczej niż na przykład „Algorytm Kruskala”. Swego czasu, doprowadzona do ostateczności nadużywaniem apostrofu w polskim Internecie popełniłam wpis na ten temat. W najbliższej przyszłości zamierzam odświeżyć go i opublikować także tutaj, gdyż plaga ta zatacza coraz szersze kręgi.
  2. Pamiętam, że w poprzednim wpisie (Ciągła Integracja: anioł stróż dobrego programisty) obiecałam pokazać, jak stworzyć plan na serwerze Bamboo. Jeszcze chwilka.

Milsza strona programowania