Walka z wersją JDK w bashu – mały trik

Projekt używa kilku wersji Javy. Tak mniej więcej czterech, czyli od 6 do 9. Nic nadzwyczajnego, ale czasami mavenowi trzeba podstawić inne JDK. I tu zaczyna się robić ciekawie…

Listing 1. Domyślna konfiguracja JDK

$ echo $JAVA_HOME
/usr/lib/jvm/java-9-oracle

To nas nie zadowala z kilku różnych powodów. Maven co prawda ruszy, ale Java 9 poprzerzucała kilka przydatnych rzeczy i na przykład pluginy do generowania kodu nie za bardzo chcą działać. Jak sobie z tym poradzić?

Listing 2. Rozwiązanie proste

$ export JAVA_HOME=~/jdk-8

Tyle tylko, że jak będziemy chcieli coś zmienić, to znowu trzeba eksportować, a tu jeszcze dochodzą różne wydania w ramach „dużej” wersji języka. Można oczywiście to opędzić dodając odpowiedni skrypt i dodając go do $PATH! No nie…

Gdy uruchamiamy skrypt (proces) w bashu, to tworzona jest kopia wszystkich zmiennych środowiskowych i skrypt dział na tej kopii. Nie ma dostępu do zmiennych procesu rodzica. Inaczej mówiąc, jeżeli wykonamy kod z listingu 2 w skrypcie, to po zakończeniu skryptu, zmienna JAVA_HOME w aktualnej powłoce, będzie miała taką samą wartość jak przed wywołaniem skryptu.

To może aliasy? Aliasy mają to do siebie, że są rozwijane w ramach bieżącego procesu, ale nie mogą przyjmować parametrów. Można sobie zdefiniować kilka aliasów i mieć z głowy. Jeżeli jeszcze dodatkowo zautomatyzujemy tworzenie aliasów przy starcie powłoki, tak by opierając się na konwencji nazewniczej, generować alias per folder z JDK, to już miód. Osobiście ten pomysł nie przypadł mi do gustu. Bardzo mocny, ale ma pewną wadę. Jest zbyt dynamiczny jak na mój gust. Tak naprawdę nie wiem, co mam dostępne.

Opcją pośrednią jest zdefiniowanie funkcji w pliku .bashrc. Funkcja taka jest wykonywana w kontekście bieżącej powłoki. Mamy do niej dostęp i możemy ją swobodnie modyfikować.

Listing 3. Przykładowa implementacja.

use-java(){
    export JAVA_HOME=~/jdk-"$1"
}

Podsumowując, należy raz jeszcze wspomnieć, że skrypty (procesy) uruchamiane w powłoce są odseparowane od środowiska rodzica i nie mogą go zmieniać. Warto o tym pamiętać, bo pozwala, to na uniknięcie wielu uciążliwych błędów.

Code Review z Phabricatorem i Arcanistem

Nowa fabryka, nowy projekt, nowe wyzwania. Tak można by podsumować ostatnie trzy tygodnie w moim wykonaniu. Projekt został przejęty po innej firmie, która się zwinęła z rynku. Otrzymaliśmy niewydolne repozytorium svn z pełną historią, dokumentację i tyle. Kilka osób w zespole przeszło z tamtej firmy, ale jest to dla nich stan przejściowy. Co najważniejsze nie mamy, poza kodem, nic innego. Trzeba wszystko zestawić praktycznie od zera.

Dziś chciałbym opisać nasz pomysł na code review. Jednak zanim do tego przejdę, to krótkie wprowadzenie, które przybliży, dlaczego wybraliśmy takie, a nie inne rozwiązania.

Dlaczego Phabricator?

Jak już wspomniałem mamy kod, ale nie mamy żadnego narzędzia, które pozwoliłoby nam na organizację procesów. Nie mamy też budżetu na zakup JIRY, a charakter projektu, bankowy core, wyklucza wypchnięcie całości na rozwiązanie chmurowe w rodzaju Githuba czy Bitbucketa. Poszukiwaliśmy zatem rozwiązania opensource, bezpłatnego w opcji self-hostingu, oraz kompletnego. Kompletność oznacza, że w jedynym narzędziu, albo grupie narzędzi współpracujących ze sobą, mam dostęp do wszystkich elementów związanych z prowadzeniem projektu. Tak właśnie działa JIRA z przyległościami. Grupa narzędzi, które możne ze sobą łatwo zintegrować. Jednak JIRA jest poza zasięgiem budżetu. Po krótkim rozpoznaniu wybór padł na Phabricatora.
Phabricator jest otwarty, bezpłatny i zawiera wszystko, czego potrzebujemy. Jest obsługa zgłoszeń, wiki, kanban board, zarządzanie repozytoriami kodu, CI oraz narzędzia do code review. Całość napisana w php, co oznacza, że wystarczy bardzo prosta konfiguracja po stronie serwera. Do tego całość jest żywa, to znaczy aktywnie rozwijana, oraz sprawdzona przez większych graczy np. Ubera, Facebooka, czy Fundację Wikimedia. Proces instalacji i konfiguracji jest bardzo prosty i dobrze opisany w dokumentacji. Aktualizacja do nowszej wersji polega na zatrzymaniu serwisów, zrobieniu git pull i ponownym uruchomieniu serwisów.
Przejdźmy zatem do dania głównego tego wpisu, czyli narzędzia do code review.

Rodzaje Code Review

Przegląd kodu można prowadzić na wiele sposobów. Każdy z nich ma zalety i wady. Każdy może też być dobrze i źle wdrożony. Nie twierdzę, że nasz pomysł jest najlepszy z możliwych, ale na chwile obecną wydaje się najsensowniejszy. Przyjrzyjmy się jakie mamy możliwości i czym się różnią.

Przeglądy post-commit

Jak sama nazwa wskazuje przeglądy takie, są wykonywane na kodzie, który już znajduje się w repozytorium. Typowy proces pracy wgląda w tym przypadku w następujący sposób:

  • Anna commituje zmiany do repozytorium. Najczęściej na osobną gałąź.
  • Następnie tworzy CR request, czyli w narzędziu oznacza commit albo grupę commitów jako gotowe do przeglądu.
  • Mike wykonuje przegląd, dodają uwagi.
  • Anna wprowadza poprawki i rozszerza CR o kolejny commit. Rozszerzenie może dziać się automatycznie.
  • Mike akceptuje poprawki i zamyka CR

W tym momencie możliwe są dwa scenariusze. Zamknięcie CR automatycznie łączy gałąź ze zmianami z gałęzią główną. Warunkiem koniecznym jest możliwość złączenia bez konfliktów. Drugi scenariusz to ręczne łączenie gałęzi.
Takie podejście jest o tyle fajne, że jest bardzo proste w implementacji. Zazwyczaj nie wymaga żadnych dodatkowych narzędzi poza narzędziem do CR. Całość opiera się na poleceniach naszego VCS-a. W dodatku jesteśmy niezależni od silnika VCS. Wady są dwie. Po pierwsze przeglądany kod jest już w repozytorium. Po drugie nie wszystkie silniki VCS są, wstanie płynnie działać w ten sposób. Chyba najlepszym przykładem jest SVN i jego model tworzenia gałęzi. Dla dużej ilości danych będzie to powolne, a ciągły schemat nadawania numerów wersji będzie tylko przysparzał problemów. W dodatku nie mamy możliwości zablokowania commitowania do głównej gałęzi. Podobnie w git. Co prawda można tak skonfigurować narzędzia, by nie akceptowały commitów bezpośrednio do mastera i pozwalały jedynie na pull requesty, ale na „czystym” gicie jest to, co najmniej uciążliwe.

Audyty

W praktyce podejście post-commit nie służy do CR rozumianego jako element wewnętrznego procesu w zespole. Podejście to służy do audytu kodu przez podmiot zewnętrzny. Załóżmy, że dowieźliśmy sprint na czas. Jednym z artefaktów końcowych, jest opis zmian w kodzie w formacie podobnym, do tego którego używamy do CR. Nasz klient wysyła taki pakiet do na przykład usługi Veracode, gdzie zmiany są badane pod kątem luk bezpieczeństwa. Inaczej mówiąc, wszystkie zamiany wprowadzone przez zespół podlegają przeglądowi przez niezależny podmiot.
Phabricator wspiera ten model i co ciekawe jest to osobny moduł. Audyty są czymś niezależnym od CR. Jest to osobne menu.

Pull request

Wspomniałem wyżej, że w gicie można wykorzystać trochę inny mechanizm, a mianowicie pull requesty. Schemat działania jest podobny do poprzedniego. Też trzeba zacommitować zmiany do gałęzi w zdalnym repo (bare), a następnie wypchnąć zmiany do własnego repozytorium. Kolejnym krokiem jest stworzenie PR-ki do repozytorium docelowego. I działa to świetnie. PR-ka może zostać przejrzana i zaakceptowana bądź odrzucona. Kolejne zmiany w naszym repozytorium będą uwzględniane w PR-ce we w miarę zautomatyzowany sposób. Oczywiście o ile korzystamy z jakiegoś narzędzia w rodzaju githuba.
Zresztą jest to najpopularniejsza metoda pracy z repozytoriami na githubie. Ma jednak pewien feler. W pewnym momencie mamy dwa repozytoria, które mają w głównych liniach kodu dwie różne wersje kodu. Można to naprawić. Wystawiając PR gałęzi z naszego repozytorium do głównej gałęzi repozytorium docelowego… co efektywnie można zredukować do commitowania do gałęzi w repozytorium docelowym i w efekcie PR staje się takim post-commit CR, tyle tylko, że jest ładniej nazwane. Dodatkową wadą jest ograniczenie się do rozproszonych VCS-ów. Jeżeli chcemy zrobić coś takiego w SVNie, to musimy korzystać z mirroringu i personal upstreamów, które są zwyczajnym hakiem.

Przeglądy pre-commit

I tu dochodzimy do przeglądów wykonywanych przed commitem. Przy czym „przed commitem” oznacza, że zmiana nie wycieka poza nasze lokalne repozytorium. Na czym to polega. Zamiast wysyłać zmiany do zdalnego repozytorium, przygotowujemy patch file, który będzie podlegać przeglądowi. Taki patch file jest traktowany jako wsad do narzędzia CR. Akceptacja zmian pozwala nam na ich opublikowanie w zdalnym repozytorium.
Taki model jest przyjęty wśród programistów jądra. Linus ostatecznie akceptuje lub odrzuca zmianę. Zanim zmiana trafi do niego, jest oczywiście przeglądana przez opiekunów poszczególnych modułów, a oni otrzymują wstępnie przesiane zmiany przez opiekunów poszczególnych plików lub fragmentów kodu. Ci są adresatami zmian, które są tworzone przez zwykłych programistów. Oczywiście opisuję tu model w sposób uproszczony, ale to mniej więcej tak działa. Zaletą tego modelu jest to, że zmiana nie jest opublikowana przed akceptacją. W dodatku całość jest niezależna od systemu VCS, ponieważ opiera się na patch filach, które są standardem. Najpoważniejszą wadą jest użycie formatu patch file, który ma pewne ograniczenia m.in. w przeciwieństwie do PR nie można ich budować ze zmian, które mają różnych autorów. Drugą wadą jest konieczność przestrzegania procesu, bo narzędzia nie radzą sobie jeszcze z np. commitem bez zatwierdzenia CR. Tu na scenie pojawia się phabricator i jego narzędzie arcanist.

Dlaczego nie gerrit?

Tu dochodzimy do kolejnego pytania. Dlaczego nie użyć gerrita? Z bardzo prostej przyczyny. Gerrit pracuje tylko z repozytoriami git, a obsługa svn jest możliwa tylko poprzez git-svn. Tyle tylko, że git-svn wymaga gita, a my nie możemy go użyć w jednym z naszych projektów. W dodatku jest to kolejne narzędzie, które wymaga uwagi z naszej strony.

Dlatego arcanist

Arcanist jest konsolowym interfejsem phabricatora. Daje on dostęp do różnych modułów, ale my skupimy się na module differential, który służy do zarządzania CR.

Mała uwaga, w dokumentacji Differentiala jest mowa o pre-push CR. Wynika to z popularności gita i gitowej nomenklatury. W przypadku svn-a jest to oczywiście pre-commit.

Instalacja i konfiguracja projektu

Żeby móc korzystać z arcanista należy go zainstalować. W przypadku linuxów znajduje się on w pakiecie arcanist, który wymaga instalacji php7. Dodatkowo należy zainstalować najnowszą wersję pakietu php7.0-xml/php7.1-xml. Pakiet ten nie jest w podstawowej dystrybucji php i trzeba go samodzielnie zainstalować.

Po zainstalowaniu arcanista należy jeszcze skonfigurować projekt. Konfiguracja jest bardzo prosta. W katalogu głównym należy utworzyć plik .arcconfig, który jest prostym JSON-em:

Listing 1. Plik .arcconfig w wersji minimum.

{
  "phabricator.uri" : "http://phabricator.yourcompany.pl/",
  "repository.callsign" : "NAZWAREPO"
}

Zgodnie z dokumentacją minimalna konfiguracja może być ograniczona tylko do własności phabricator.uri, ale bez repository.callsign arcanist może mieć problemy z rozpoznaniem repozytorium projektu. Teoretycznie robi to automatycznie, ale nie zawsze to wychodzi. W szczególności gdy nazwa lokalna różni się od zdalnej.

Tworzenie CR

Proces tworzenia CR jest niezależny od silnika VCS, którego używamy. Phabricator wspiera git-a, svn-a i mercicurala więc nie jest źle. Po wprowadzeniu zmian w kodzie wystarczy w linii poleceń uruchomić:

Listing 2. Tworzenie CR

$ arc diff

Zostanie uruchomiony edytor, w moim przypadku jest to nano, w którym musimy wypełnić szablon z informacjami:

Listing 3. Szablon CR

<<Replace this line with your revision title>>

Summary:

Test Plan:

Reviewers:

Subscribers:

# NEW DIFFERENTIAL REVISION
# Describe the changes in this new revision.
#
# arc could not identify any existing revision in your working copy.
# If you intended to update an existing revision, use:
#
#   $ arc diff --update <revision>

Obowiązkowymi polami są tytuł, podsumowanie i plan testów. Pola Reviewers i Subscribers są opcjonalne i podajemy tam loginy. Po zapisaniu i wyjściu z edytora arcanist utworzy CR w phabricatorze. W tym celu używa crul-a.

Jeżeli pracujemy z gitem, to nie musimy wykonywać git commit, bo arc diff zrobi to za nas. W przypadku svn-a zostanie wygenerowany patch file i nie będzie zmian w repozytorium. Pytanie, które zmiany są brane do CR? Odpowiedź jak zawsze brzmi, to zależy. W przypadku svn-a jest są to zmiany, które są widoczne w svn status. W przypadku git-a są to zmiany widoczne w po zaaplikowaniu git merge-base origin/master ..HEAD. Inaczej mówiąc wszystkie różnice pomiędzy aktualna gałęzią, a zdalnym masterem.

Akceptacja CR i różnice pomiędzy VCS-ami

Jeżeli chcemy zobaczyć, jakie CR czekają na nas, wystarczy wydać polecenie arc list.

Listing 4. Lista oczekujących CR

$ arc list
* Needs Review D6: Testowe CR w svn

Należy tu zwrócić uwagę na identyfikator CR. W tym przypadku jest to D6. Będzie on nam potrzebny do dalszej pracy z arcanistem. Jeżeli CR-ka zostanie zaakceptowana, to wystarczy klepnąć zmianę i wysłać ją do repozytorium. Niestety nie ma jednego spójnego interfejsu do wykonania tej operacji.

Listing 5. Zamknięcie niezaakceptowanego CR w svn-ie

$ arc commit --revision D6

    Revision 'D6: Testowe CR w svn' has not been accepted. Commit this
    revision anyway? [y/N] N

Usage Exception: User aborted the workflow.

Oczywiście można wymusić zamknięcie CR i wysłać zmiany do repozytorium.

Listing 6. Zamknięcie niezaakceptowanego CR w git

$ arc land --revision d7
Landing current branch 'master'.
 TARGET  Landing onto "master", selected by following tracking branches upstream to the closest remote.
 REMOTE  Using remote "origin", selected by following tracking branches upstream to the closest remote.
 FETCH  Fetching origin/master...
This commit will be landed:

      - 4affd51 OK



    Revision 'D7: OK' has not been accepted. Continue anyway? [y/N] 

Usage Exception: User aborted the workflow.

Jak widać svn i git mają osobne polecenia. To nie jest najfajniejsze rozwiązanie, ale daje radę. Jeżeli CR zostało zaakceptowane, to nie otrzymamy komunikatu, że coś wisi, tylko zmiana zostanie wysłana na serwer. Tu właśnie wychodzi największa zaleta modelu pre-commit/pre-push w porównaniu do pull requestów. Zgłoszenie CR jest nieblokujące. Oczywiście, jeżeli ktoś odwali maniane i wyśle kod, który nie był przejrzany, to odpowiednia adnotacja pojawi się w historii CR. Winny zostanie już odpowiednio nagrodzony…

Za i przeciw

Czas na krótkie podsumowanie. Phabricator ma bardzo dobrze przemyślany mechanizm przeglądów kodu. W dodatku jasno rozgranicza przeglądy od audytów. Wspiera kilka różnych rodzajów repozytoriów. Co prawda interfejs nie jest spójny, ale różnice są minimalne. Całość jest nieblokująca i w przeciwieństwie do klasycznych gitowych PR łatwiejsza do zrozumienia.
Rozwiązanie nie jest pozbawione wad. Największą jest konieczność używania arcanista, który jest dodatkowym oprogramowaniem. Jeżeli używamy niestandardowego sposobu zarządzania commitami, to musimy zapomnieć o automatyzacji niektórych czynności. Gotowe rozwiązania muszą zostać dostosowane. Niektórych może też zaboleć, że całość jest w php, co powoduje, że kod jest rozszerzalny dla zespołów niephpowych.

Podsumowując, lubię i polecam. Pobawić się można, a potencjalne korzyści są duże. Jeżeli zatem szukasz narzędzia do ogarniania projektu, to phabricator będzie całkiem fajny.

Wrzutka chorobowa

Zasadniczo leżę i kwiczę. W zasadzie to cichutko pokwikuję. Bywa, zdarza się najlepszym. Oczywiście przeglądam sobie internety i trafiam na ten oto wywiad. Co w środku? Ano taka oto perełka:

Odwrócę pytanie. Czego absolutnie nie polecasz osobie uczącej się programować?

Pójścia na studia. Przynajmniej w Polsce. To będzie strata czasu i brak konkretnego przygotowania do pracy.

Kilka dni temu prowadziłem rozmowę rekrutacyjną do mojego teamu. Trafił nam się osobnik, który ogólnie rzecz ujmując, studiował dość dokładnie, licencjat robił już siódmy rok. Przy czym studiował kierunek spokrewniony – elektronikę. Jednak studia zapewne były tylko dodatkiem do pracy, bo pracował już z pięć czy sześć lat i to jako programista. Na czym poległ?

Poległ na dwóch prostych pytania, na które odpowiedź poznałby na studiach:

  • Co to jest transakcja?
  • Co to jest sekcja krytyczna?

Easy, prawda?

ps. Bohaterka wywiadu prowadzi podobno bloga technologicznego. Tyle tylko, że mało tam treści technologicznych, a więcej life stylowych.

Zawiodłem się na Fakapie, czyli recenzja podwójna

Okładka Zawód

Tytuł: Zawód Opowieści o pracy w Polsce To o nas
Autor: Kamil Fejfer
Rok: 2017
ISBN: 978-83-770-0294-0

Pierwsza z książek, której przyjrzymy się dzisiaj, jest chyba najważniejszą w 2017 roku książką poruszającą kwestie społeczne. Tyle tylko, że jest to książka marna. Mamy tu mieszankę treści wartościowych. Chociażby historię ratownika medycznego, laureatki studenckiego nobla, która nie za bardzo może znaleźć pracę zgodną z kwalifikacjami czy nawrócenia uberkuca po kuracji MLMem. Oraz treści chujowych jak płacz dziewczyny, która postanowiła studiować hobby (teatrologię czy coś w ten deseń) czy narzekania dziennikarki-freelancerki. I szkoda mi tej książki, bo autor spierdolił koncertowo arcyciekawy temat.
Czego mi w tej książce zabrakło? Przede wszystkim głębszej analizy, dlaczego rynek pracy wygląda tak, a nie inaczej. Rzuciła mi się w oczy wzmianka o „mentalności folwarcznej”, które to pojęcie, zresztą źle zapisane, bo chodzi o relację folwarczną, pochodzi z eseju Andrzeja Ledera pod tym samym tytułem. Weźmy teraz to pojęcie i zestawmy je z historią Katji Schrodinger, czyli autorki bloga o życiu z zespołem AspergeraW. Tyle tylko, żeby to zrobić trzeba umieć coś więcej niż wstawianie memów w internety.
Podsumowując. Mam wrażenie, że autor chce między wierszami powiedzieć „mi się udało frajerzy”. Tyle tylko, że wystarczy podejść do tej książki na spokojnie i widać miałkość. No cóż… w kapitalizmie nie wygrywa się umiejętnościami, a odpowiednim zapleczem. Niech ono nawet składa się z ludzików, lubiących dłuższe teksty na memach…

Okładka Fakap

Tytuł: Fakap. Moja przygoda z korpoświatem
Autor: Dan Lyons
Rok: 2017
ISBN: 978-83-240-4220-3

To może coś zza oceanu. Dan Lyons to dziennikarz zwolniony z Newsweeka w ramach redukcji. Po dość długim okresie bezrobocia trafia do tzw. „fabryki kontentu” w HubSpocieW, czyli startupie. 52-letni dziennikarz technologiczny, który ma na koncie poważne artykuły i jest autorem wywiadów z najważniejszymi osobami w świecie IT, musi zmierzyć się z całkowicie innym światem. Światem słabo opłacanych dzieciaków, którym zrobiono pranie mózgów i wmówiono, że pracują w najlepszej firmie na świecie. Mamy tu, oczywiście, elementy typowego korpoświata z kopaniem się po jajach, podkładaniem świni i podpierzaniem zasług. Całość doprawiona wszechobecnym sloganem „jest bosko”.
I właśnie tu wychodzi największa zaleta tej książki. Jak na dłoni widać, że w Polsce to my jesteśmy jeszcze daleko za cywilizacją białego człowieka, funfact w HotSpocie pracują praktycznie sami biali, co jest nie lada wyczynem w USA.
Warsztatowo książka jest świetna, widać tu rękę profesjonalisty. To, czego mi brakuje, to próba analizy, dlaczego system działa. Autor wskazuje co prawda na mechanizm opcji i stara się go wytłumaczyć w prosty i zrozumiały sposób, ale dla osób spoza amerykańskiego kręgu kulturowego ten mechanizm może wydawać się niejasny. Szczególnie że sposób wyceny oraz wyznaczania granicy opłacalności wymaga trochę rozeznania w mechanizmach giełdowych.
Podsumowując. Fajne czytadło. Nie jest to typowy reportaż, ale też nie jest to opowiadanie „na faktach”. Epilog „miażdży”, a dla zainteresowanych artykuł wspomniany w książce znajdziecie tu.

Na koniec warto się pokusić o porównanie tych dwóch książek. Obie dotykają tego samego problemu. Rynek pracy zmienił się wraz ze wdrożeniem neoliberalnych reform pod koniec lat 70-tych. Problemy, które obserwujemy w Polsce, nie są niczym niezwykłym w gospodarkach opartych na liberalnym podejściu. Rzecz w tym, że USA miały za sobą cztery dekady budowania bogactwa, gdy zdecydowano się na odejście od keynesowskiego modelu gospodarczego. Polska nie miała okazji na stworzenie odpowiedniego zaplecza społecznego, przed przyjęciem „dobrodziejstw” neoliberalizmu. I to niestety widać.

ps. następna w kolejce recenzenckiej jest „Prześniona rewolucja” Ledera. Więc będzie grubo.

RoomOverflowError, czyli o JDD 2017

W dużym skrócie było zacnie.

W szczegółach to powiem tak. Jarek Ratajski zjechał adnotacje z góry do dołu. Następnie wykonał nawrót i poprawił. Świetna prezentacja o tym, że warto czasami wrócić do podstaw języka, zamiast korzystać z rozwiązań w rodzaju Springa. Później Tomek Kleszczyński opowiedział o Kotlnie. Bardzo podstawy, ale miało to ręce i nogi. W tym samym czasie Przemysław Hojnacki mówił o chatbotach. Trochę wyszła z tego prezentacja marketingowa narzędzi i jakoś tak sztywno było. Nie sztywno było za to na prezentacji Tomka Borka, który przeszedł przez historię Javy, a następnie skompilował to, co będzie w i o Javie 9 na JDD. Szkoda tylko, że organizacja dała ciała z rzutnikami.

Potem był obiadek i młodzi programiści mogli przeżyć chwilę „historycznej grozy”, stojąc w kolejkach po papu.

Po obiadku poszedłem na prezentację Heinza Kabutza o Fork/Join i sposobach na zwiększenie utylizacji sprzętu. Z prezentacji twardych to była chyba najlepsza w pierwszym dniu. Przy okazji załapałem się na promocję kursów robionych przez jego firmę. Wyglądają całkiem zacnie. Potem udałem się na prezentację Piotra Wittchena o reactive streamach w bibliotece standardowej. Może byłem już nieogarnięty, ale jakoś tak mi to nie pasowało. Odpuściłem po 20 minutach. Ostatnia sesja tego dnia, w której uczestniczyłem to opowieść Mateusza Gajewskiego o germańskim oprawcy. Dla niezorientowanych:

Świetna prezentacja o tym, jak działa dług techniczny i jak sobie z nim radzić. Później udałem się do speakers cornera by pozalegać…

A później była impreza… i zaprawdę powiadam wam alkohol to zuo…

Drugi dzień zacząłem od prezentacji Jarka Pałki o Javie 10. Była moc… może troszkę wczorajsza, ale była. Jarek mówił nie tylko o tym, co nas czeka, ale też opowiedział, dlaczego niektóre rzeczy działają tak, a nie inaczej. Później znowu odstaliśmy w kolejce po obiad, a potem coś pierdolnęło i się zrobił RoomOverflowError. Slajdy tutaj. Dzień zakończyłem na prezentacji Ewa Nestorowicz i Dominika Dzienia o tokenach U2F. Fajna mięsna prezentacja z dodatkami hardwerowymi (żeby między ząbkami chrupało). Na koniec poszedłem na prezentację Piotrka Przybyła o graylogu. Powiem tak, ze wszystkich prezentacji na tegorocznym JDD, ta była chyba najlepszą w kategorii „pójdę jutro do pracy i to wdrożę”. Świetnie opowiedziane i były przykłady.

Podsumowując. W końcu dotarłem na JDD. Było super. Tyle tylko, że znalazłem trzy wady. Po pierwsze, całość na strasznym zadupiu. Po drugie drugiego dnia koniec o 18:15 to był mocno poroniony pomysł. Po trzecie drugiego dnia przerwy na kawę po obiedzie były na wodzie i sokach, bo kawa się skończyła, a co gorsze nie było nic na ząbek 🙁 Po 17 to prawie wszyscy już o jedzeniu myśleli.

Sendbajt

Bo w speakers cornerze na jdd pojawił się ten temat

Sendbajt
Copyright 1998 by oscyloskop

Jest to opowiesc o najbardziej chyba spektakularnej grupie hackerskiej w historii Netu oraz najgenialniejszym hackerze wsrod seniorow. Pan Jan S. , bo o nim mowa zaczal sie co prawda interesowac komputerami dopiero w wieku 68 lat lecz efekty jego zainteresowan przerosly jego nasmielsze oczekiwania.
Ale zacznijmy od poczatku.
– Pamietam jak dzis. To bylo w 1987 roku… bylem wlasnie wtedy na poczcie po swoja emeryture (u pani Halinki z 3 okienka) kiedy po raz pierwszy zobaczylem komputer. Stal na biurku przykryty pokrowcem – wspomina pan Jan. Wtedy jeszcze nic nie wskazywalo na to ze komputery stana sie zyciowym hobby pana Jana.
– W roku 1989 w bibliotece wojewodzkiej, gdzie czesto zagladalem tez byly juz komputery… pamietam, ze po raz pierwszy (i ostatni) usiadlem wtedy przed klawiatura. Kompletnie nie wiedzialem co mam zrobic, wiec najpierw przeczytalem cztery razy to co bylo napisane na monitorze. Potem jakos juz poszlo… Tego samego dnia wypozyczylem ksiazke o rosyjskich maszynach cyfrowych z ktorej dowiedzialem sie co to jest bit i bajt oraz kto to jest Lenin.
Od tej pory zaczal sie intesywny okres w zyciu pana S. Cale dnie spedzal w czytelni pochlanialac ksiazki o komputerach, systemach operacyjnych, sieciach komputerowych , ale nie tylko. W kregu zainteresowan pana Jana znalazla sie rowniez telefonia i budowa modemow, co zreszta zaowocowalo w pozniejszym czasie rewolucyjnymi metodami stosowanymi przez grupe „Sendbajt” Ale nie uprzedzajmy faktow. Na poczatku 1989 roku poznal pan S. niejakiego Mieczyslawa R., rowniez emeryta, ktory wiekszosc zycia spedzil na instalowaniu sieci telefonicznych oraz pracy na Strowgerze. Mietek (jak o nim mawial pan Jan) byl wtedy zgorzknialym 64 letnim emerytem, dysponowal jednak duza wiedza praktyczna i dlatego wlasnie pan Jan postanowil zawrzec z nim spolke w celu wyciagniecia od niego mozliwie duzo wiedzy (byc moze juz wtedy istnialy w glowie Jana S. zarysy szatanskiego planu ktory pozniej przyniosl slawe jemu oraz grupie „Sendbajt”).
Kolejny rok pan Jan spedzil razem z Mietkiem na dalszym intensywnym szkoleniu w bibliotekach i nie tylko. Prenumerata „Bajtka” otorzyla mu oczy na wiele zagadnien o komputerach o ktorych dotad nie wiedzial nic. Nieodzownym elementem zycia staly sie nocne rozmowy z Mietkiem przy kubku kakao, w czasie ktorych prowadzili ozywione duskusje a to o plikach, a to o sytemach Dos, Unix a to o protokolach sieciowych lub modemowych. Czasami w domu pana Jana pojawiala sie takze pani Bozenka – zona pana Mietka. Przygotowywala im kakao i przysluchiwala sie o czym rozmawiaja. Czasem tez zadawala pytania, ktore jednak nie zawsze mialy sens.
Gdzies tak w sierpniu 1990 pan Jan stworzyl swoj pierwszy program – byl to generator liczb losowych totolotka napisany w basicu commodore 64. Niestety program istnial tylko na kartce z notesu, a to z tego prostego powodu, iz pana Jana nie bylo stac nawet na najtanszy komputer 8 bitowy. Pozniej przyszla nauka assemblera. Okazalo sie ze pan S. ma do tego nadzwyczajny talent. Juz po miesiacu nauczyl sie wszystkich rozkazow procesora 8086. Po kolejnych 3 miesiacach zmudnej nauki mial opanowane wszystkie przerwania i byl w stanie pisac i debuggowac programy w assemblerze i to jedynie za pomoca kilku kartek papieru kancelaryjnego i olowka z gumka.Kiedy pan Jan dowiedzial sie juz dostatecznie duzo o komputerach i systemach operacyjnych przyszla pora na gruntowne studiowanie sieci, zwlaszcza rozleglych. W ciagu pol roku intensywnego wkuwania polaczonego z cwiczeniami praktycznymi pan Jan zdobyl tak wiele informacji, ze mogl np. zakodowac dowolny tekst na ciag znakow ASCII po czym zamienic to na ciag zer i jedynek oraz podzielic na pakiety wyposazone w sume kontrolna, bity stopu, parzystosci i takie tam. Po wielu treningach okazalo sie ze potrafi on z pamieci podac 1 kB plik binarny (ewentualnie zaszyfrowac go np. metoda xor w czasie rzeczywistym). Pan Mietek takze nie proznowal – na polecenie pana Jana zbudowal specjalny aparat telefoniczny z dwoma mikrofonami oraz z trzema sluchawkami.
Mowi pan Jan:
– Tak pod koniec roku 1991 mialem juz duzo wiadomosci i wiedzialem dokladnie czego chce. Chcialem dostepu do niezliczonych zasobow wiedzy zgromadzonej na wszystkich komputerach swiata. – Mowiac to pan Jan wzrusza sie bardzo i widac, ze silnie to przezywa.
– Przelomem byl styczen 1992. Czytalem wlasnie o najnowszych metodach modulacji sygnalu w pasmie telefonicznym, kiedy wpadl Mietek z nowym „Bajtkiem”. Byla tam opublikowana lista wszystkich BBS-ow w Polsce. Postanowilismy sprawdzic te numery. Pozniewaz ja nie mam telefonu, ubralem sie cieplo i poszlismy nie opodal do automatu. Wg „Bajtka” w naszym miescie byly 3 BBSy. Drzacymi rekoma wykrecilem numer pierwszego BBSu i w chwili gdy chcialem wrzucic zeton Mietek powstrzymal mnie i sam energicznie przywalil w aparat centralnie od frontu. Spojarzalem na niego ze zdziwieniem, ale nie bylo czasu na wyjasnienia gdyz w tym momencie nastapilo polaczenie, a ja w sluchawce uslyszalem dzikie piski o duzym natezeniu wpadajace wprost do mego ucha. W pierszym odruchu wypuscilem sluchawke z reki, ale zaraz sie opamietalem i Mietek podal mi sluchawke znowu. Tym razem bylem juz przygotowany i staralem sie rozroznic poszczegolne dzwieki. W mlodosci bylem miedzy innymi muzykiem jazzowym, wiec od razu wylapalem czestotliwosc nosna na 1200 Hz. Slychac bylo regularne sekwencje piskow. Powtorzylo sie to w sumie szesc razy i modem po drugiej stronie sie wylaczyl. Czasu nie bylo duzo, ale juz po tym pierwszym polaczeniu zorientowalem sie, ze mam do czynienia z jakims modemem 2400 a takze rozpoznalem rodzaj modulacji. Za chwile wykrecilismy ten sam numer raz jeszcze i tym razem sprobowalem nawiazac lacznosc. Gwizdanie do mikrofonu niewiele pomoglo, wiec wpadlem na pomysl zeby Mietek wymawial „aaaaaaaa” na czestotliwosci ok 2400 hz a ja w tym czasie wydawalem odpowiednie piski w celu przeprowadzenia handshake’u oraz uzyskania polaczenia z komputerem odleglym z predkoscia przynajmniej 300 bps. Probowalismy jakies 4 razy zanim sie to udalo. Jednak po odebraniu wiadomosci wstepnych oraz zalogowaniu sie do BBSa jako anonymous polaczenie zostalo przerwane, poniewaz Mietek zaniosl sie nagle straszliwym kaszlem. Mnie zreszta tez rozbolalo gardlo od wydawania piskow, oraz reka od notowania zer i jedynek. Prace takze utrudnial fakt, ze musialem jednoczesnie nadawac i deszyfrowac dane. Nalezalo zdecydowanie opuscic budke i udac sie do domu w celu obmyslenia innej strategii, zwlaszcza, ze wokolo zebral sie tlumek mlodych osob przygladajacych sie nam dosc dziwnie. No coz, to moje pierwsze polaczenie z modemem bylo moze niezbyt udane ale za to wiele sie nauczylem.
Co robil pan Jan S. w nastepnych dniach? Otoz zdal on sobie sprawe ze w pojedynke z Mietkiem wiele nie zdzialaja. Potrzebowali pomocy fachowcow. Na pierwszy ogien poszla pani Bozenka, ktora jako regularna bywalczyni coniedzielnej mszy swietej dysponowala odpowim glosem z ktorym pan S. wiazal duze nadzieje.
– Pani Bozenko, pani bedzie pelnila w naszej grupie funkcje generatora fali nosnej.
– Lo Jezu! A co to jest? W imie ojca!
– Spokojnie pani Bozenko, to nic trudnegom niech no pani powie „aaa”.
– Aa
– Ale tak dlugo „aaaaaa” i tutaj, do mikrofonu prosze.
– Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
– Dobrze. No widzi pani? Trudne? Nietrudne. Panie Mietku, odczytal pan czestotliwosc na oscyloskopie?
– Niewiarygodne! Dokladnie 2400 Hz panie Janie!
– Fantastycznie! Jest pani najstarszym generatorem fali nosnych telefonicznych na swiecie.
– No wie pan?
– Zartowalem, he he.
– Panie Janie a jak bedzie sie nazywala nasza grupa?
– Juz to przemyslalem proponuje „Sendbajt”. Moze byc ?
– Eee. Dobra.
W kolejnych dniach pan Jan pokazywal pani Bozence jak ma sie zachowywac generator fali nosnej, zwlaszcza w przypadku renegocjacji polaczenia oraz zaklocen na linii. Pan Mietek przechodzil intensywny kurs HTMLa (oczywiscie w wersji zerojedynkowej). Po tygodniu do grupy „Sendbajt” dolaczyla jeszcze pani Wanda – dobra znajoma pani Bozenki, ktora wg niej spiewala najglosniej i najpiekniej w calym kosciele.
– Bardzo dobrze! – ucieszyl sie pan Jan – pani bedzie naszym nadajnikiem oraz modulatorem!
– Ale nic nie wiem! Nie umiem! – plakala pani Wanda.
– Jak to nic ? Niech pani powie „pi pi pi pioooupipaupioiopppipipiapappe pi pi”
– pi pi pi pioooupipaupi… jak bylo dalej?
– …oiopppipipiapappe pi pi …jeszcze raz!
– pi pi pi pioooupipaupioiopppipipiappe pi pi …dobrze?
– Opuscila pani jedno pa, ale korekcja bledow modemu odbiorczego powinna sobie z tym poradzic.Poza tym doskonale.Panie Mietku!
– Slucham.
– Prosze przebudowac nasz aparat tak aby drugi mikrofon byl polaczony szeregowo z pierwszym poprzez uklad, ktory pan zaprojektuje tak aby sygnal z drugiego mikrofonu modulowal sygnal pierwszego fazowo, amplitudowo lub czestotliwosciowo w zaleznosci od polozenia przelacznika p3… Druga sluchawka ma miec dodatkowy filtr srodkowoprzepustowy na 1200 Hz …zreszta tu ma pan wstepny projekt.
– Jasna sprawa, tylko co z tymi krokodylkami, zostaja jak sa ?
– tak, i niech pan skoluje jakies 50 metrow czarnego kabla telefonicznego.
– To sie da zrobic.
Nastepny tydzien uplynal na przygotowaniach. Pan Jan zarywal noce symulujac na kartce mala siec ethernet na szesc komputerow. Bawil sie kopiujac pliki miedzy stanowiskami lub uruchamiajac programy na serwerze. Zabawa ta kosztowala go co prawda dwie ryzy papieru do kserokopiarek ale jego wiedza o dzialaniu sieci wzrosla niepomiernie.
– Nasza pierwsza akcja? No coz, to bylo w piwnicy naszego bloku. Okolo godziny 23:00 zaopatrzeni w latarki, hackomat (jak nazwalismy nasz przyrzad) oraz koszyk na ziemniaki i torbe na kompoty zeszlismy do piwnicy. Mietek od razu odszukal skrzynke z napisem >TP< i wyjal z torby pek kluczy. Po chwili nasz hackomat byl na lini i mielismy dialtone.Wg planu najpierw wykrecilem numer do naszego znajomego BBSu. Panie zajely miejsca przy mikrofonach, Mietek przylozyl swoja sluchawke do ucha, ja swoja i przygotowalem papier i kredki (olowki mi sie juz wtedy skonczyly) Pierwsza proba zalogowania sie nie powiodla, poniewaz pani Wanda z wrazenia krzyknela do mikrofonu i zdalny modem nas rozlaczyl. Jednak za drugim razem udalo sie doprowadzic do polaczenia, co prawda tylko 120 bps, ale jak na poczatek to chyba i tak niezle. Mietek szybko zalapal o co chodzi pozniej juz sam odbieral i deszyfrowal wiadomosci. Dzieki temu ja moglem sie zajac przetwarzaniem danych. Naprawde byloby z nami krucho, gdybu nie to, ze Mietek pozyczyl od swojego syna kalkulator. To byl taki prosty kalkulator, ale mial co trzeba, tzn dodawanie i mnozenie. Kiedy juz sie zalogowalem do systemu pierwsza rzecza jaka zrobilem bylo przejecie praw menedzera BBSu wg mojej metody obmyslonej z pol roku wczesniej. Nie spodziewalem sie ze pojdzie az tak latwo. Niestety po 15 minutach polaczenia pani Bozenka nie wytrzymala i powiedziala ze nie moze dluzej krzyczec "aaaa", ze ona tez chce byc procesorem i inne takie bzdury. Przez nia zerwalismy takie swietnie zapowiadajace sie haczenie. Ale nic to. Zdazylem i tak skasowac wiekszosc plikow systemowych. Kiedy Mietek doprowadzil swoja zone do porzadku i moglismy juz kontynuowac postanowilismy sprobowac czegos innego.Polaczylismy sie z serwerem dosyc duzej firmy L*** z naszego miasta. Okazalo sie ze maja aktywne konto guest. Nic prostszego. Po wejsciu do systemu w ciagu 5 minut zdobylem uprawnienia roota i ku mojej nieopisanej radosci okazalo sie ze serwer ma lacze z inernetem. Niedowierzajac sprawdzilem cala kartke obliczen czy sie nie pomylilem czasem przy dodawaniu liczb ujemnych w systemie osemkowym, bo z tym mialem zawsze troche klopotu. No ale wszystko sie potwierdzilo. Zakrylem mikrofon reka i krzyknalem do Mietka: Udalo sie! Jestesmy w Internecie! niestety nasze panie wytwarzaly taki zgielk, ze prawdopodobnie mnie i tak nie usluszal. Ale ja juz bylem tam gdzie chcialem byc zawsze. Pierwsze co zrobilem do polaczylem sie z serwerem firmy Seagate Technologies (znalem dobrze ich system operacyjny z jednej ksiazki) i wlamalem sie na strone WWW. Nie tracac czasu przekazalem paleczke naszemu specowi od HTMLa , czyli panu Mietkowi, sam zas zajalem jego miejsce. Tak jak sie umowilismy wczesniej Mietek dokonal zmian bezposrednio w kodzie html przy pomocy edytora dysku na serwerze. Teraz trudne zadanie czekalo pania Wande. Musiala nadawac przez 20 minut tekst naszego manifestu... Kolejne miesiace plynely grupie "sendbajt" szybko. Po pierwszych sukcesach na stronach WWW probowali wlamywania na amerykanskie serwery wojskowe i rzadowe, co bylo od zawsze skrytym marzeniem Jana S. Niestety, pomimo poprawienia (na skutek zaprawy czlonkow "Sendbajt") parametrow transmisji (dochodzila ona do 1200 bps ) nie dalo sie w dalszym ciagu sciagac wiekszych plikow binarnych. Rekordem grupy byl download kodu zrodlowego do Internet Explorera v 2.0 (po wlamaniu na serwer firmy Microsoft). Poprawilo to nawigacje w sieci www gdyz pan Mietek nauczyl sie tego kodu na pamiec i robil po prostu za przegladarke (jak bylo trzeba to szkicowal na kartce jpgi i gify zeby kazdy mogl podziwiac szate graficzna danej strony). Tymczasem pan Jan zaliczal coraz to nowe miejsca www, haczyl i ewentualnie niszczyl serwery internetowe jeden za drugim. Jednym slowem grupa rozwijala sie i z dnia na dzien stawala sie w Sieci coraz bardziej popularna. Na wszystkich administratorow padl blady strach. Wiekszosc z nich zaczela do wymiany informacji uzywac tradycyjnej poczty snail-mail, do tego stopnia byli sterroryzowani przez czlonkow grupy "Sendbajt". Oczywiscie przez caly ten czas grupa korzystala podczas uprawiania swego procederu z roznych numerow telefononow, poczatkowo sasiadow z bloku, ale pozniej pan Mietek wynalazl swietne miejsce kolo przedszkola dwie ulice dalej. Chodzili tam wiec nocami, wpinali hackomat i siadali w krzakach, z daleka od ludzi. Pewnie sie spodziewacie, ze w koncu policja nakryla grupe "Sendbajt" i zirytowani admini ukamienowali za miastem jej czlonkow, wzglednie Jan S. wyladowal w wiezieniu jak przystalo na hackera-legende ? Otoz nie. Dzialalnosc grupy trwalaby zapewne po dzis dzien gdyby pan Jan nie odkryl nowej pasjii zyciowej - mianowicie wedkarstwa. No niestety bez pana Jana grupa "Sendbajt" szybko sie rozpadla. Spotykaja sie jednak czasem w piwnicy jak za starych czasow i przesiaduja na IRCu lub pan Jan sciaga sobie stronki o wedkarstwie. Poza tym sa szczesliwi. Admini tez, ze cala sprawa przycichla... Nadal wydaje im sie ze ich systemy sa dobrze zabezpieczone i moga spac spokojnie. Niech spia...

Slowsort w Elixirze i testująca dokumentacja

Za trzy dni będzie premiera Javy 9. Dlatego właśnie czas napisać coś o Elixirze. Dziś na tapecie ląduje jeden z ciekawszych elementów języka, czyli wykonywalna dokumentacja.

Chwila teorii

Gdy dokumentujemy jakiś fragment kodu, to często aż prosi się dołączyć jakiś przykład. Coś w rodzaju dla takich danych otrzymasz taki rezultat. Wszystko fajnie, bo taki przykładowy happy path pozwala na zrozumienie kodu. Z drugiej strony przykład zazwyczaj kopiujemy z testów, bo tam jest gotowe, a później, jak się testy zmienią, to już niekoniecznie aktualizujemy dokumentację.
A gdyby tak w dokumentacji zaszyć testy i niech narzędzia martwią się jak to uruchomić?

Chwila praktyki

Na tapetę wziąłem algorytm SlowsortW. Z kilku powodów. Po pierwsze jestem w trakcie pisania kursu ze struktur danych na potrzeby naszego centrum szkoleniowego i implementacja slowsorta jest całkiem fajnym ćwiczeniem. Proste, a jednocześnie nietypowe. Po drugie chcę wykorzystać ten kod w czasie mojej prezentacji na JDD. Po trzecie, jak już implementować coś głupiego, to niech to będzie naprawdę głupie 😀

Kod wygląda tak:

Listing 1. implementacja Slowsort w Elixirze

defmodule Slowsort do
  @moduledoc """
  Documentation for Slowsort.
  """

  @doc """
  Example implementation of Slowsort algorithm.

  ## Examples

      iex> Slowsort.sort([0])
      [0]

      iex> Slowsort.sort([1,0])
      [0, 1]

      iex> Slowsort.sort([3, 11,  1, 0, 22, 2])
      [0, 1, 2, 3, 11, 22]
  """
  def sort(numbers) do
    l = length numbers
    slowsort(numbers, 0, l - 1) # we need maximum index that is length - 1
  end

  defp slowsort(numbers, i, j) when i>=j, do: numbers

  defp slowsort(numbers, i, j) do
    m = Integer.floor_div((i + j), 2)
    slowsort(numbers, i, m)
              |> slowsort(m + 1, j)
              |> swap(j, m)
              |> slowsort(i, j - 1)
  end

  defp swap(numbers, j, m) do
       max_left = Swap.nth(numbers, m);
       max_rigth = Swap.nth(numbers, j);
       swap(numbers, j, m, max_rigth, max_left)
   end

   defp swap(numbers, j, m, mr, ml) when mr < ml, do: Swap.of(numbers, j, m)
   defp swap(numbers, _, _, mr, ml) when mr >= ml, do: numbers
end

Do tego oczywiście są jeszcze testy:

Listing 2. Zestaw testów

defmodule SlowsortTest do
  use ExUnit.Case
  @moduletag timeout: 1000
  doctest Slowsort

  test "the empty array" do
    sorted  = Slowsort.sort []
    assert sorted === []
  end

  test "the simple array of two elements" do
    sorted  = Slowsort.sort [1, 0]
    assert sorted === [0, 1]
  end

  test "the array of many elements" do
    sorted  = Slowsort.sort [3, 11,  1, 0, 22, 2]
    assert sorted === [0, 1, 2, 3, 11, 22]
  end
end

Technicznie są tu dwa zestawy testów. Zwróćcie uwagę na dokumentację funkcji sort. Zdefiniowana jest tam sekcja Examples, która wygląda jak fragment kodu w markdownie. I rzeczywiście, jeżeli wygenerujemy dokumentację, to otrzymamy jakiś nagłówek. Znacznie ciekawiej jest, jeżeli uruchomimy testy za pomocą mix test.

Listing 4. Zrzut z testów

Compiling 1 file (.ex)
......

Finished in 0.1 seconds
6 tests, 0 failures

Uruchomiono sześć testów. Trzy zdefiniowanie w slowsort_test i trzy zdefiniowane w dokumentacji.

Podsumowanie

Możliwość zdefiniowania prostych testów bezpośrednio w dokumentacji jest bardzo fajnym rozwiązaniem. Pozwala to na jednoczesną aktualizację testów, jak i dokumentacji. Szkoda, że w Javie nie ma takiego narzędzia. Oj szkoda…

Kod dostępny jest tutaj.

Przekwalifikowanie się na…

Dziś super krótko, bo ostatnie dwa tygodnie miałem mocno obłożone, a kolejne trzy udowadniają, że można jeszcze więcej.

Jak ktoś w dyskusji podnosi argument, że zawsze można się przekwalifokować, to polecam lekturę Tuwima

Murarz domy buduje,
Krawiec szyje ubrania,
Ale gdzieżby co uszył,
Gdyby nie miał mieszkania?

A i murarz by przecie
Na robotę nie ruszył,
Gdyby krawiec mu spodni
I fartucha nie uszył.

Piekarz musi mieć buty,
Więc do szewca iść trzeba,
No, a gdyby nie piekarz,
Toby szewc nie miał chleba.

Tak dla wspólnej korzyści
I dla dobra wspólnego
Wszyscy muszą pracować,
Mój maleńki kolego.

Bo kto cię uratuje, jak ratownik medyczny zostanie web developerem?

Poniedziałkowo

I pamiętaj, ktoś może mieć gorszy poniedziałek niż ty. Nawet jeżeli jest tylko bakterią:

ps. wiem, że nie ma nic wspólnego z programowaniem, ale powinno trafić na JVMBloggers

Gdzie trenować swoje umiejętności?

Ta naprawdę to nie jest post, a jedynie zaproszenie na stronę, na której zbieram linki do serwisów, gdzie można trenować kodowanie. Forma strony jest lepsza, bo aktualizacja jest prostsza w porównaniu z aktualizacją posta 😀

Gdzie trenować swoje umiejętności?