niedziela, 27 lipca 2014

Rozszerzenia do "Coderetreat" i "Game of Life"

Global Day of Coderetreat stanowi niesamowitą pomoc w sianiu eksplozji wiedzy w kierunku jednostek programistycznych wciąż uwięzionych w rozwiązywaniu problemów programistycznych przy pomocy tandemu for-if (powtórz n razy). Aby było łatwiej zachęcić ludzi do udziału wydarzenie odbywa się w porze roku kiedy najłatwiej odpalić samochód a wszyscy są opaleni i wypoczęci - czyli na przełomie listopada i grudnia.

Aby nie robić kolejnego CRUDa pracujemy z ciekawszym problemem czyli Grą w życie (nie mylić z "grą życie", którą uprawiamy na codzień). I chociaż ludzie czasem narzakają, że ciągle jest to samo ćwiczenie i można by wrzucić coś nowego to jednak co roku scenariusz przebiegu zdarzeń mówi co innego.

Najpierw większość ludzi jedzie proste rozwiązanie z tablicą dwu wymiarową i wali w komórki albo booleany albo inty. Później mamy trudną do przetestowania gigantyczną metodę main lub kilka mniejszych metod z (niestety) wszędzie rozsianymi iteracjami po tablicach. To czego przez ostatnie dwa lata prowadzenia coderetreat nie udało mi się wyjaśnić to to to to, że rozwiązanie samo w sobie nie jest istotne - właśnie dlatego je wywalamy na końcu (oj jak tego ludzie nie lubią!).

Ważna jest obserwacja, ważny jest proces nauki, ważne jest wyciągnięcie wniosku i zrozumienie jak dana decyzja wpływa na całokształt rozwiązania i dalsze decyzje. Np. fajne byłoby olśnienie, że jeśli każde miejsce kodu jest świadome tego, że operujemy na tablicy dwuwymiarowej to jakakolwiek próba zmiany tego konkretnego aspektu będzie boleć.

Poza Object Calisthenics

Object Calisthenics(link) to zbiór ciekawych ograniczeń, których nazwy nich*ja nie mogę zapamiętać. Ograniczeń - bo formuła ćwiczeń jest dosyć ciekawa - zamiast narzucać (no dobra trochę się narzuca), że dane rozwiązanie jest lepsze - staramy się zaprogramować rozwiązanie z ograniczeniem np."metody maks 5 linii" i pomóc uczestnikom ćwiczeń samemu wyciągnąć wnioski.

Do niedawna Object Calisthenics to była taka obiektowa nirwana ale ale jak już i w javie pojawiły się "strzałki" to warto zerknąć na inne nirwany i zapoznać się z mechanizmami, których w javie do tej pory nie było albo jeszcze nie ma.

Wyrzucić długopisy i ołówki

... i przesiąść się do painta (nie nie to tylko żart prowadzącego).

Generalnie wiele zespołów na początku dużo dyskutuje o rozwiązaniach i nic a nic nie koduje :( i chyba dlatego wymyśloną sesję "nic nie gadamy tylko piszemy". A można zacząć inaczej. Zastanówmy się co jest potrzebne na samiutkim początku? Mamy komórki i jest też jakaś plansza. I tyle wystarczy by zacząć

trait GameOfLifeBlueprint{
 type Board
 type Cell
}

Słówko "type" należy czytać "jest sobie jakiś typ" (w sensie abstrakcyjnym a nie w sensie "patrz na niego ale typ"). I tyle - decyzje co to będzie za typ odkładamy na później...

I tak dalej

No dobra komórki są gdzieś położone na planszy. Przydałoby się je jakoś namierzyć

trait GameOfLifeWithCoordinates extends GameOfLifeBlueprint{
 type Coordinates
 def findCell(c:Coordinates)(implicit b:Board):Cell
}

I już mamy planszę, komórki i współrzędne a cały czas nie wiadomo co tam siedzi - i to jest poniekąd dobre bo mamy wciąż swobodę podejmowania decyzji. No i podejmujemy decyzje. Zamiast bawić się z tablicami przestrzeń za symuluje nam mapa. Kto chce 2D ma 2D a kto DDD ten ma 3D.

trait MapBasedGame extends GameOfLifeWithCoordinates{
 type Board=Map[Coordinates,Cell]
 val board:Board=Map[Coordinates,Cell]()
}

trait GameOfLife2D extends MapBasedGame{
 type Coordinates=(Int,Int)
}

trait GameOfLife3D extends MapBasedGame{
 type Coordinates=(Int,Int,Int)
}

To co jest jeszcze nie określone to Cell - no to wio

trait GameOfLifeWithStandardCells extends GameOfLifeWithCoordinates{
 trait GameCell
 case class LiveCell() extends GameCell
 case class DeadCell() extends GameCell
 type Cell=GameCell
 implicit val board:Board

 def lifeNeighbours(c:Coordinates)(implicit b:Board):Int
 
 def evolve(c:Coordinates):Cell=(findCell(c),lifeNeighbours(c)) match {
  case (DeadCell(),3)=>LiveCell()
  case (LiveCell(),2)=>LiveCell()
  case (LiveCell(),3)=>LiveCell()
  case _ => DeadCell()
 }
}

Przydałoby się ogarnąć jakieś zalecenia co i w jakiej kolejności zaleca się deklarować. W każdym razie powstało coś na wzór Metody Szablonowej także jak ktoś chce jakies wzorce projektowe to je ma.

No to gramy...

...ale jeszcze nie teraz bo nie chce psuć zabawy uczestnikom (a tak naprawdę nie chce mi się tego implementować bo jeszcze muszę dzisiaj spodnie sobie wyprasować). W każdym razie będzie to mniej więcej wyglądało tak :

object NormalGame extends GameOfLife2D with GameOfLifeWithStandardCells{
 def lifeNeighbours(c:Coordinates)(implicit b:Board):Int={...}
 def findCell(c:Coordinates)(implicit b:Board):Cell={...}
}

A Jak chcemy mieć więcej komórek to też łatwo idzie :

trait GameOfLifeWithZombieCells extends GameOfLifeWithStandardCells{
 case class ZombieCell() extends GameCell
 def zombieNeighbours(c:Coordinates)(implicit b:Board):Int
 
 override def evolve(c:Coordinates):Cell=(findCell(c),lifeNeighbours(c),zombieNeighbours(c)) match {
  case (DeadCell(),3,3)=>ZombieCell()
  case (LiveCell(),2,2)=>ZombieCell()
  case (LiveCell(),3,_)=>LiveCell()
  case _ => DeadCell()
 }
}

object ZombieGame3D extends GameOfLife3D with GameOfLifeWithZombieCells{
 def lifeNeighbours(c:Coordinates)(implicit b:Board):Int={...}
 def findCell(c:Coordinates)(implicit b:Board):Cell={...}
 def zombieNeighbours(c:Coordinates)(implicit b:Board):Int={...}
}

Jakie ograniczenie?

No i cała magia coderetreat polega na tym aby za bardzo nie wchodzić w teorię ale by dać ograniczenie i pozwolić każdemu na własne skórze odczuć uwagi i wnioski. Tutaj można dać "wszystkie typy abstrakcyjne" albo "jeden typ abstrakcyjny na trait" ale to na razie jest jedna wielka improwizacja z mojej strony także zobaczymy co przyszłość przyniesie.

Z kronik "Maintenance City"

Przypomniało mi się zabawne zdarzenie z 2011 kiedy jeszcze nie prowadziłem a tylko uczestniczyłem w CR. Siedzimy sobie i robimy pair programming no i nagle koleś się zawiesza. Pytam "co się dzieje" a ten prawie ze łzami w oczach "o kurde od roku chyba nie robiłem nowej klasy w Eclipse". No to pozdrowienia dla wszystkich we wspólnej walce na awans z low cost centre utopia na to co tam jest następne.

środa, 16 lipca 2014

Tragedia wspólnego kodu

Scenka1

Facet idzie sobie przez las i napotyka gościa wycinającego siekierą choinki
- Panie co pan robisz! Dlaczego dewastujesz las?
- Nie dewastuję lasu tylko zaciągam dług leśny. Będą święta, na choince powieszę bombki to rodzina będzie zadowolona. No a później posadzę nowe choinki w to miejsce.
- A kiedy to zrobisz?
- no za trzy sprinty...

Scenka2

Facet idzie sobie przez osiedle i spotyka gościa, który wywala gruz do piaskownicy
- Dlaczego dewastujesz plac zabaw?
- Nie dewastuję placu zabaw tylko zaciągam dług osiedlowy. Kładę teraz nową boazerię na ścianę i musiałem skuć trochę. Ale jak już skończę to obiecuję, że ogarnę cały plac zabaw.
- a kiedy to zrobisz?
- no za trzy sprinty...

Scenka3

Facet idzie sobie po piętrze w firmie i patrzy a tu gościu piszę metodę na 500 linijek i 20 ifów
- Panie co pan robisz! Dlaczego dewastujesz kod?
- Nie dewastuję kodu tylko zaciągam dług techniczny. Jest koniec sprinta i trzeba domknąć velocity bo inaczej nam targety polecą. Ale jak już to ogarniemy to potem poprawię.
- a kiedy to zrobisz?
- no za trzy sprinty...

Obecna metafora

Obecnie panująca metafora długu technicznego jest na pewno lepsza od braku jakiekolwiek metafory jako, że przecież dzięki niej w końcu ludzie nie do końca techniczni obdarowani ogromną mocą decyzyjną mogą w pewnych ramach mentalnych zrozumieć, że czasami jak działa to nie znaczy, że jest dobrze (a być może jest dobrze ale dobrze nie będzie).

Jednak pojawia się jednocześnie korpo-zagwostka : bo jak tu pokazać na zebraniu rady wydziałowej, że zaciągnęło się dług pragmatycznie, zainwestowało go pragmatycznie , spłaciło pragmatycznie i liczy zyski również pragmatycznie?

Oczywiście istnieje klasyczny algorytm rozwiązywania tego typu problemów : zmierz cokolwiek co generuje jakiś wykres i jedziemy z targetami - może na początek 120% pokrycia kodu?

Najlepszy tekst jaki do tej pory słyszałem to target : "zmniejszyć dług techniczny o 50%". No i oczywiście programiści nie mogą się z tego głośno śmiać bo mają do spłacenia kredyty, dziecku trzeba zeszyty kupić i psa zaszczepić. No i leci kabarecik. Kilka lat temu sam pisałem testy jednostkowe do 500 linijkowych metod z 30 ifami, które to metody napisali "ludzie, którzy już tu nie pracują" - target spełniony, pokrycie kodu zwiększone do 60% - nieustające pasmo sukcesów trwało.

Gdyby to nie wynikało jasno z powyższych rozważań to model "długu technicznego" pomimo swoich nieocenionych walorów edukacyjnych wydaje się na pod pewnymi względami a może i na dłuższą metę zwyczajnie ku*wa lewy. Jednocześnie istnieje być może coś ciekawszego, coś z zupełnie innej beczki...

Jak to wyszło na wyspach wielkanocnych

Cała historia jest opisana szczegółowo tutaj : Zjebka na wyspach wielkanocnych - a tak w skrócie to:

  1. Pomiędzy 400AD a 900AD na wyspy wielkanocne przybywają kontraktorzy z Polinezji i zaczynają nowy greenfield project
  2. Z czasem dzielą się na 12 teamów i zaczynają projekty budowy zajebistych takich dużych pomników głów
  3. Każdy z 12 managerów chce jebnąć najfajniejszą głowę z kamienia - bo generalnie im większa głowa wyrzeźbiona tym więcej respektu na wyspie,lepsze bonusy świąteczne i miejsce na parkingu bliżej wejścia.
  4. Aby przytachać kamienie na plaże gdzie znajdują się stanowiska pracy - używano ściętych drzew jako rolek (taki framework).
  5. Projekty idą zgodnie z planem - kolejne głowo-kamienie milowe są budowane
  6. Mija kilka wieków i na wyspie nie ma już żadnych drzew a co za tym idzie cały ekosystem poooszedł w pizdu.
  7. Na początku szesnastego wieku na wyspę przypływają Europejczycy i zastają garstkę ledwo żyjących mieszkańców (zdaje się, że około 3-10% populacji przetrwało)

A był to wstęp do szerszego zjawiska, które nazywa się..

Tragedia wspólnego pastwiska

Tutaj trzeba poruszać się ostrożnie bo powyższe zjawisko może być zbyt łatwo nad interpretowane "trzeba ludzi kontrolować bo się pozabijają" - co jak zobaczymy nie do końca o to tu chodzi

W 19 wieku angielski ekonomista zauważył, że jak chłopom dać wolną rękę to każdy maksymalizując swój zysk wprowadzi owce czy tam krowy na łąkę - a że każdy chce jak najbardziej nakarmić swoją zwierzynę to szybko wyeksploatują całe pole i będzie kicha dla wszystkich. Niby koleś miał trochę racji ale ważny jest tutaj kontekst sytuacji - otóż ci chłopi wcale nie byli właścicielami ziemi, z której korzystali. Lądem władał tzw. "Suweren" lub była zwyczajnie niczyja.

Własność prywatna - ale czyja?

Pod koniec 20 wieku kilku ekonomistów przypatrzyło się całej teorii i znaleźli pewną istotną zjebkę - otóż w orginale nie rozróżniano dwóch diametralnie różnych sytuacji : "korzystanie z ogólno dostępnego dobra" oraz "korzystanie z dobra będącego własnością wspólnoty". Okazuje się, że w tym drugim przypadku wspomniane wspólnoty ludzi jakoś same rozkminiały zasady korzystania z lasu,jeziora czy łąki. Rozwiązywali oni sami także tzw. "Efekt gapowicza": (Syndrom wesołego Cześka).

Jedna taka pani (Elinor Ostrom) przeprowadziła nawet dogłębne badania i obserwacje, w trakcie których zauważyła następujące niepokojące zjawisko :

  • Jest sobie las a obok lasu wieś
  • Mieszkańcy wsi korzystają z dóbr leśnych a jednocześnie jak ktoś przekombinuje to dostanie parę sęków gdyż mieszkańcy wsi tak po trochu uważają las za część wspólnoty
  • W państwie brakuje kasy
  • Las staje się tzw. "własnością publiczną"
  • Ludziom narzuca się reguły i mają w zasadzie po trochu już w dupie czy ktoś je łamie - od tego momentu to już bardziej sprawa indywidualnej etyki aniżeli społecznego współużytkowania wspólnego dobra

I kilka cytacików :

Ostrom demonstrated that, within communities, rules and institutions of non-market and not resulting from public planning can emerge from the bottom up to ensure a sustainable, shared management of resources, as well as one that is efficient from an economical point of view. Besides the village of Törbel, Ostrom shows examples of common lands in the Japanese villages of Hirano and Nagaike, the huerta irrigation mechanism between Valencia, Murcia and Alicante in Spain, and the zanjera irrigation community in the Philippines.

The first condition for the institutional basis of the success of these mechanisms is the clarity of the law (Who can do what? What can one not do? Who punishes whom? And how?). In addition to being clear, the rules must be shared by the community. This is why another essential element of self-government is the establishment of methods of collective and democratic decision-making, able to involve all users of the resource.

Furthermore, the mechanisms of conflict resolution must be local and public, so as to be accessible to all individuals of a community. Besides mechanisms of graduated sanctions, a mutual control of the resource among the users themselves must be established.

Więcej tutaj : http://www.aei.org/article/economics/elinor-ostrom-and-the-solution-to-the-tragedy-of-the-commons/

Jak to się ma do jakości kodu

Kilka obserwacji z życia wziętych :
  • Czasem - zwłaszcza na początku projektu - programista może skończyć prace nad taskiem szybciej implementując totalnie zjebany kod bez testów
  • Niska jakość kodu jebnie w cały zespół w przyszłości
  • Jeśli zespól jest poddany pseudonaukowym korpo-praktyką w stylu ocena performensu "risorsa" przez menadzera to pojawia się dodatnie sprzężenie zwrotne pomiędzy szybszym skończeniem taska a nagrodą
  • Jeśli zespół (a czasami trudno mówić o zespole bo ludzie są oceniani indywidualnie) ma narzucone reguły kodu to tak mentalnie z założenia widzi właściciela tych reguł poza zespołem
  • Jeśli właściciel kodu jest poza zespołem to można go traktować jako "dobro ogólno dostępne" z narzuconymi restrykcjami
  • Jest jeden wyjątek gdzie takie narzucone restrykcje są dobre ale jednak w praktyce widzę, że tworzy się często "korporacyjne reguły kodu" i wali po całości unifikacją. To tak jakby każdemu w korpo kazać nosić ten sam rozmiar buta.

Zastanówmy się nad taką metaforą - kod projektu jako wspólne dobro - ale wspólne dobro czego konkretnie? W lesie są drzewa, w morzu są ryby a na łące trawa (dla krów) - co jest w kodzie? W kodzie są szybkie postępy pracy, sukcesy projektowe, potencjał awansu i abstrakcyjny banknot pieniężny. Teoretycznie ktoś waląc haka na kodzie zagarnia te wszystkie rzeczy dla siebie utrudniając jednocześnie osiągnięcie tych samych rzeczy innym. - i jeszcze raz - Syndrom wesołego Cześka

A teraz zastanówmy się co by się stało gdyby tak zespół stał się właścicielem kodu i żaden szczebel menadżerski się w to nie wpierdalał? Tutaj nawiążemy do tego tekstu pisanego italikiem kilka akapitów wyżej :

  • Ostrom demonstrated that, within communities, rules and institutions of non-market and not resulting from public planning can emerge from the bottom up to ensure a sustainable, shared management of resources - czy zespół może "oddolnie" stworzyć reguły użytkowania kodu? Ano może
  • The first condition for the institutional basis of the success of these mechanisms is the clarity of the law (Who can do what? What can one not do? Who punishes whom? And how?). In addition to being clear, the rules must be shared by the community. - wspólne reguły kodu na które każdy w zespole się godzi? Tutaj będzie zaraz jedno ALE
  • Besides mechanisms of graduated sanctions, a mutual control of the resource among the users themselves must be established. - wypisz wymaluj code rewiu.

Ten model znacznie bardziej podoba mi się od porównywania pisania kodu do zaciągania "długu". Niby jest fajnie bo można do góry wysłać wiadomość, że teraz trzeba trochę posprzątać bo kilka placków gówna powstało z okazji dedlajnu. Z drugiej jednak zjawisko pracy z "długiem" raz, że sprawia, że niektórzy myślą, iż rozumieją z czym pracują a tak jest niekoniecznie. No a dwa to pomija ważne aspekty pracy grupowej jak choćby problem radzenia sobie z pasażerem an gapę - i po raz trzeci - Syndrom wesołego Cześka

Jedno małe duże ALE

Jest jedna taka sytuacja w życiu kiedy nawet najbardziej zagorzały przeciwnik wszelkich ograniczeń da się poprowadzić za rękę - jest to tzw "tutorial level" - kiedy nasza wiedza jest zerowa i zwyczajnie czujemy każdą komórką ciała, że czerpiemy wartość z wykonywania poleceń.

Tak jest oczywiście w teorii bo w praktyce działa też inny ciekawy efekt. Otóż np. taka Łódź do niedawna była głównie "maintenace city" i wiele osób siedziało po kilka lat wklejając tu i tam linijkę kodu aby zadziałało (R&D w Łodzi - Refactor and Deployment). Jak ktoś robi takie rzeczy kilka lat i widzi w ogłoszeniach o pracę "senior java developer wymagane 3 lata doświadczenia" to ma prawo pomyśleć , że on jest właśnie takim senior developerem i cały proces odbywa się raczej nieświadomie w ramach tzw. "warunkowania społecznego".

I teraz jak np. ktoś przychodzi do tego ludzika i próbuje go przekonać, że np trzy zagnieżdżone fory z piętnastoma ifami w środku nie są najlepszym pomysłem, to następuje wewnętrzny konflikt pojęciowy pomiędzy "uważam się za doświadczonego developera" a "okazało się, że moim kodem można straszyć dzieci jak nie będą chciały jeść zupki". Prowadzi to do tego, że wiedza o tym jak konkretne decyzja w kodzie wpływają na konkretne metryki i co tak naprawdę zyskujemy/tracimy poprzez stworzenie abstrakcji lub zagnieżdzenie ifa - ta wiedza niekiedy musi być wtłoczona w zespół lekko na siłę. Zakładając, że problem Cześka został wyeliminowany a reszta ludzi wykazuje "oświecony egoizm" -> http://en.wikipedia.org/wiki/Enlightened_self-interest - wtedy wszystko się ułoży. Oczywiście jestem świadom tego, że na mnie działają te same procesy - od czasu "funkcyjnego przebudzenia" staram się znajdować krytykę do każdego konceptu który badam.

To podobnie jak kiedyś miałem taką historię jak się dowiedziałem, że nie należy dokarmiać dzikich kaczek chlebem bo im puchnie to w brzuchy i implodują czy coś takiego. Czyli ludzie mogą chcieć dobrze ale z powodu braku wiedzy robią źle.

Także na dzień dzisiejszy : CZYSTY KOD=MODEL KODU JAKO DOBRA WSPÓLNOTY+ZESPÓŁ WŁAŚCICIELEM KODU + ODPOWIEDNIA ILOŚĆ NAPOMPOWANEJ WIEDZY O JAKOŚCI KODU

Epilog

Na pewno warto model kodu jako ograniczonego dobra wspólnego otwiera nowe ścieżki nazwijmy to "badań" aniżeli metafora "długu" i warto by się przyjrzeć schoćby temu : http://en.wikipedia.org/wiki/Socio-ecological_system - i przestać udawać, że problem jakości kodu sprowadza się do kilku metryk w sonarze i, że się poprawi po trzecim sprincie. A no i akurat na courserze zaczyna się kurs "social psychology" - https://class.coursera.org/socialpsychology-002

Trochę linków :