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?

Odchudzanie komputera z nadmiarowego acz potrzebnego softu

Mam okazję pracować na kilku różnych komputerach. W domu jest to całkiem potężna maszyna z procesorem i7-6700k i 16GB RAM (mało, ale na razie OutOfMoneyError) oraz mocno przedpotopowy laptop (i5-430M 8GB RAM). W pracy mam desktopa, który próbuje działać i laptopa, który nawet nie próbuje. W domu Ubuntu, w biurze Win7. Problem komputerów biurowych jest nienaprawialny, ale na domowym laptopie postanowiłem trochę się pobawić.

Problem

Wraz z upływem czasu instalujemy różne oprogramowanie. A to potrzebny jest mySQL, a to Postgres, a to Tomcat7 albo jakiś Glassfish. Nie wspominając już o wszelakich MongoDB, Jenkinsach itp. wynalazkach. Po prostu nasza codzienna praca wymaga pewnych narzędzi na lokalnej maszynie. Po pewnym czasie ilość narzędzi i dodatków drastycznie wzrasta, a services mówi nam, że nie jest dobrze:

Listing 1. Aktywne serwisy na moim laptopie (wycinek)

$ services --status-all
 [ + ]  jenkins
 [ + ]  mongodb
 [ + ]  mysql
 [ + ]  postgresql
 [ + ]  virtualbox

A teraz niech jeszcze się okaże, że taki postgres potrzebny jest w kilku wersjach, bo coś tam, albo potrzebujemy bazę Oracle. O ile na dużej maszynie, to jeszcze jakoś zadziała, to na starym laptopie będzie już kiepsko. Co więcej serwisów tych potrzebujemy tylko wtedy, gdy pracujemy. Cały pozostały czas, to zapychacze pamięci i procesora. Co prawda skala problemu może nie być duża, bo takie mongo pochłania 1% CPU na 5 sekund. Przy ośmiu rdzeniach to tyle co nic, ale to jest puste mongo…

Rozwiązania

Zastanówmy się zatem, jak można rozwiązać ten problem – działania zbędnych serwisów. Od razu mówię, że rozwiązań jest kilka i wybór konkretnego jest mocno uzależniony od konkretnej sytuacji. Rozwiązanie preferowane przeze mnie nie musi być najlepsze dla ciebie. Choć w 95% przypadków i tak je wybierzesz 🙂

Nie uruchamianie serwisów przy starcie systemu

Pozwolę sobie to podsumować obrazkowo:

Jeżeli coś instalujemy jako serwis, to chcemy mieć serwis, ze wszystkimi konsekwencjami. Oczywiście, nie jest to takie proste. Jeżeli chcemy mieć kilka wersji postgresa, to możemy wybrać jedną, która będzie „tą główną”, a reszta będzie startować na żądanie. Jednak jak już mamy kilka wersji postgresa, to raczej będziemy chcieli inaczej zarządzać tym majdanem.

Delegacja

Delegacja jest chyba pierwszym pomysłem, jaki przychodzi do głowy wielu osobom, gdy mówimy o pracy z wieloma instancjami baz danych albo z CI. Polega na użyciu zdalnego rozwiązania. Tyle tylko, że my chcemy mieć serwis lokalnie. Takie rozwiązanie ma swoje zalety, bo uniezależnia nas od naszego komputera. Musimy zmienić komputer, nie ma problemu, bo dane są „gdzieś w sieci”. Tyle tylko, że brak sieci, to brak dostępu do danych. Zazwyczaj to prowadzi nas do instalacji lokalnych.

Pełna wirtualizacja

Pod pojęciem pełnej wirtualizacji rozumiem wykorzystanie na przykład VirtualBoxa. Tworzymy maszynę wirtualną, na niej instalujemy jakiś system operacyjny i następnie instalujemy interesujące nas oprogramowanie. Wszystko ładnie i pięknie działa. To rozwiązanie stosowałem już w kilku miejscach i zazwyczaj świetnie się sprawdzało. Ma ono jedynie tę wadę, że wymaga dość dużo zasobów. Narzut jest na tyle duży, że do naszej maszyny wirtualnej powinny trafić różne rzeczy, co oczywiście jest OK, ale w pewnym momencie mamy ten sam problem. Tyle że na wirtualce. Możemy jednak pójść w to rozwiązanie jeżeli chcemy pracować z technologiami z innego systemu operacyjnego. Na przykład mamy jakiegoś UX-a, a musimy skorzystać ze sraczyka… znaczy sie z IIS+MSSQLa.

Konteneryzacja

I to jest oczywiste rozwiązanie 🙂 Bierzemy Dockera i przygotowujemy sobie kilka obrazów. Jak potrzeba nam jakiegoś konkretnego softu, to uruchamiamy taki obraz i działa. Ale… no właśnie jest jedno, a w zasadzie dwa, ale. Pierwsze dotyczy uruchamiania oprogramowania, które nie jest przeznaczone dla naszego systemu operacyjnego. W tym przypadku się nie da, względnie takie oprogramowanie wymaga kombinowania. Drugim jest konieczność odpowiedniego, dodatkowego skonfigurowania oprogramowania. Przykładowo, jeżeli chcemy mieć kilka instancji postgresa, to niezbyt dobrym pomysłem jest składowanie danych w domyślnym katalogu. Po prostu będzie się to gryźć samo ze sobą. Dlatego musimy odpowiednio przygotować własny obraz albo skrypt, który uruchomi nam obraz z odpowiednimi parametrami. Zaletą jest stosunkowo niewielki narzut po stronie dockera (w sumie zerowy, bo wykorzystujemy istniejące mechanizmy jądra) oraz łatwość w użyciu.
Co więcej, jeżeli koniecznie chcemy całość odizolować, to możemy naszego dockera zamknąć w jakimś vagrancie, ale to już sztuka dla sztuki… choć użytkownicy maców często tak robią. Może wpływ opiatów?

Podsumowanie

Mojego prywatnego laptopa powoli przestawiam na model z dockerem. Jest to o tyle ważne, że ma on już kilka dobrych lat i po prostu nie działa już tak szybko, jak bym chciał. Wyczerpałem też możliwości rozbudowy zarówno jeśli chodzi o RAM, jak i dysk ssd. Pozostaje zatem kombinowanie z oprogramowaniem. Docker wydaje się odpowiednią ścieżką. Będzie działać z Ubuntu 14.04. Zapewnia znaczną elastyczność i łatwość w migrowaniu. Będzie dobrze 🙂

Część wspólna zbiorów z Guavą

Szybkie rozwiązanie problemu opisanego tutaj. Mamy dwa zbiory A i B, chcemy sprawdzić, czy wszystkie elementy ze zbioru A są obecne w zbiorze B. Najprościej jest to zrobić w następujący sposób:

Listing 1. Wykorzystanie API

public class SetsIntersectionExample {

	public static void main(String[] args) {
		// Smoki i gołe baby
		Fairy fairy = Fairy.create();

		Set<String> persons = Stream.generate(() -> fairy.person(PersonProperties.male())).limit(100)
				.map(Person::firstName)
				.collect(Collectors.toSet());
		// Magia, bo chcemy mieć pewność, że mamy istniejące imiona.
		Set<String> names = Sets.newHashSet((String) persons.toArray()[0], (String) persons.toArray()[1]);
		// end: Smoki i gołe baby
		
		System.out.println(persons);
		System.out.println(names);
		System.out.println(persons.containsAll(names));
	}
}

Takie rozwiązanie podał Jakub Dyszkiewicz i prościej się nie da. Cytując dokumentację:

Returns true if this set contains all of the elements of the specified collection. If the specified collection is also a set, this method returns true if it is a subset of this set.

źródło

Przy czym jest, to dość słabo zaimplementowane:

Listing 2. AbstractCollection.containsAll wygląda tak:

public boolean containsAll(Collection<?> c) {
    for (Object e : c)
        if (!contains(e))
            return false;
    return true;
}

Sprawa trochę się komplikuje, gdy chcemy mieć informację o części wspólnej obu zbiorów. Tu jednak z pomocą przychodzi Guava, która ma klasę narzędziową Sets, która znowuż zawiera metodę intersection:

Listing 3. Użycie Sets.intersection

public class SetsIntersectionExample {

	public static void main(String[] args) {
		// Smoki i gołe baby
		Fairy fairy = Fairy.create();

		Set<String> persons = Stream.generate(() -> fairy.person(PersonProperties.male())).limit(100)
				.map(Person::firstName)
				.collect(Collectors.toSet());
		// Magia, bo chcemy mieć pewność, że mamy istniejące imiona.
		Set<String> names = Sets.newHashSet((String) persons.toArray()[0], (String) persons.toArray()[1]);
		// end: Smoki i gołe baby

		System.out.println(persons);
		System.out.println(names);
		System.out.println(persons.containsAll(names));
		System.out.println(Sets.intersection(persons, names).size() == names.size()); // to samo co wyżej
		System.out.println(Sets.intersection(persons, names));
	}
}

Implementacja jest w tym przypadku podobna (taka sama złożoność), ale trochę bardziej skomplikowana, bo wynikiem jest SetView. Jedyny problem, jaki będzie tu nas drażnił, to duże zbiory danych. W takim wypadku wyszukiwanie części wspólnej będzie długotrwałe.

Z Javy 8 na Javę 9, czyli co wybuchnie

Małe rzeczy zawsze cieszą. Jedną z nich jest możliwość bezproblemowego migrowania z Javy 8 na Javę 9. Fajnie by było, gdyby taka migracja przeszła bez większych zgrzytów, dlatego warto czasami rzucić okiem, co wypluwa nam nasz kompilator.

A wypluć może on na przykład:

Listing 1. Co nam mówi kompilator

Warning:(30, 53) java: '_' used as an identifier
  (use of '_' as an identifier might not be supported in releases after Java SE 8)

Co prawda, jeżeli użyjemy podkreślenia jako parametru wyrażenia lambda, to będzie klasycznie fail:

Listing 2. Co nam mówi kompilator w lambdzie

Error:(30, 32) java: '_' used as an identifier
  (use of '_' as an identifier is forbidden for lambda parameters)

Jednak warto o tym pamiętać. W czym rzecz. W Javie 8 zaczęto wycofywać znak podkreślenia _ jako prawidłowy identyfikator zmiennej/parametru. Uzasadnienie od Briana Goetza jest takie:

Yes, we are „reclaiming” the syntactic real estate of „_” from the space of
identifiers for use in future language features. However, because there are
existing programs that might use it, it is a warning for identifiers that occur
in existing syntactic positions for 8, and an error for lambda formals (since
there is no existing code with lambdas.)

Your suspicion is mostly right, except that we are certainly NOT going to do
Scala’s „wunderbar”. However, things it might be used for include things like
„I don’t want to give this variable a name” (such as catch parameters that are
never used.)

źródło

Zatem, zanim przejdziemy na Javę 9, to warto przejrzeć swój kod źródłowy pod kątem tego problemu. W szczególności dotyczy to kodu starszego niż Java 8. Tu nie mamy żadnego ostrzeżenia.

Co w zamian?

Znak podkreślenia jest powszechnie stosowany jako marker „do olania”, ale w tej sytuacji nie można go już stosować w Javie. W zamian pozostaje stosowanie podwójnego znaku podkreślenia tzn. __ albo znaku dolara $.

Kiedy wypakować Optional

Odpowiedź brzmi najlepiej nigdy.

Pandora już raz rozpakowała Optionala i do dziś dzieci się o tym uczą w szkole. Zresztą można sobie, to opisać w następujący sposób.

Tygrys w klatce

Wyobraźmy sobie, że mamy do dyspozycji Tygrysa. Niech ma na imię Bonawentura.

Listing 1. Nasz tygrys

public class Tiger {
	
	private final String name;
	
	private State state;

	public Tiger(String name) {
		this.name = name;
		this.state = State.HAPPY;
	}

	// tu jest wielka zagadka zwana psychiką tygrysa – nie znamy dokładnego zachowania!
	
	public enum State{
		HAPPY, HUNGRY, ANGRY, SLEEPY;
	} 
}

Bonawentura, jak każdy rasowy samiec może być szczęśliwy, głodny, zły albo śpiący. Rodzi się on szczęśliwy, choć zestresowany (bo głodny):

Listing 2. Cud narodzin

public class TigerInTheCage {

	public static void main(String[] args) {
		Tiger bonawentura = new Tiger("Bonawentura");
		System.out.println(bonawentura);
	}
}

Pojawia się oczywiście mama tygrys i karmi naszego bohatera:

Listing 3. Mama tygrys na ratunek

public class TigerInTheCage {

	static MommyTiger momy = new MommyTiger();

	public static void main(String[] args) {
		Tiger bonawentura = new Tiger("Bonawentura");
		System.out.println(bonawentura);

		bonawentura.giveFood(momy);
		System.out.println(bonawentura);
	}
}

Wiadomo, samiec głodny, to zły, a jak najedzony, to śpi. A jak śpi, to jest mniej czujny i daje się zaskoczyć przez kłusownika:

Listing 4. Zły kłusownik

class Poacher implements Protector{

	@Override
	public Optional<Tiger> catchThem(Tiger tiger) {
		System.out.println("I catch the tiger!!!");
		tiger.goingCrazy(); // no to się ktoś wkurzył
		return Optional.ofNullable(tiger); // albo i nie
	}

	@Override
	public boolean isMom() {
		return false;
	}
}

Listing 5. I samo zdarzenie

public class TigerInTheCage {

	static MommyTiger momy = new MommyTiger();
	static Poacher poacher = new Poacher();

	public static void main(String[] args) {
		Tiger bonawentura = new Tiger("Bonawentura");
		System.out.println(bonawentura);

		bonawentura.giveFood(momy);
		System.out.println(bonawentura);

		Optional<Tiger> tigerInBag = poacher.catchThem(bonawentura);
		System.out.println(bonawentura);
	}
}

I teraz trzeba jakoś Bonawenturę spacyfikować. Kłusownik zna się na tygrysach, a zatem wrzuca coś do worka i nie ujawnia się. Dodatkowo zabezpieczył się odpowiednią klatką:

Listing 6. Karmienie tygrysa – robisz to dobrze.

public class TigerInTheCage {

	static MommyTiger momy = new MommyTiger();
	static Poacher poacher = new Poacher();

	public static void main(String[] args) {
		Tiger bonawentura = new Tiger("Bonawentura");
		System.out.println(bonawentura);

		bonawentura.giveFood(momy);
		System.out.println(bonawentura);

		Optional<Tiger> tigerInBag = poacher.catchThem(bonawentura);
		System.out.println(bonawentura);

		Try.of(() -> tigerInBag.map(t -> {
			t.giveFood(null);
			return t;
		}));
		System.out.println(bonawentura);
	}
}

Bonawentura jak widać, znowu podszedł spać, bo wrzucił coś na ząb. Kłusownik nie próżnował i sprzedał go na Oledroggo niejakiej Kaleszi, ta postanowiła obudzić Bonawenturę, a ten oczywiście się wkurwił:

Listing 7. Kaleszi nie powinna tego robić.

public class TigerInTheCage {

	static MommyTiger momy = new MommyTiger();
	static Poacher poacher = new Poacher();
	static Kaleszi kaleszi = new Kaleszi();

	public static void main(String[] args) {
		Tiger bonawentura = new Tiger("Bonawentura");
		System.out.println(bonawentura);

		bonawentura.giveFood(momy);
		System.out.println(bonawentura);

		Optional<Tiger> tigerInBag = poacher.catchThem(bonawentura);
		System.out.println(bonawentura);

		Try.of(() -> tigerInBag.map(t -> {
			t.giveFood(null);
			return t;
		}));
		System.out.println(bonawentura);

		kaleszi.playWith(bonawentura);
		System.out.println(bonawentura);
	}
}

Oczywiście, za telefon i dzwoni do kłusownika co dalej. Ten mówi, nakarm go i po sprawie. Zatem karmimy:

Listing 8. Karmienie tygrysa – robisz to źle.

public class TigerInTheCage {

	static MommyTiger momy = new MommyTiger();
	static Poacher poacher = new Poacher();
	static Kaleszi kaleszi = new Kaleszi();

	public static void main(String[] args) {
		Tiger bonawentura = new Tiger("Bonawentura");
		System.out.println(bonawentura);

		bonawentura.giveFood(momy);
		System.out.println(bonawentura);

		Optional<Tiger> tigerInBag = poacher.catchThem(bonawentura);
		System.out.println(bonawentura);

		tigerInBag = Try.of(() -> tigerInBag.map(t -> {
			t.giveFood(null);
			return t;
		}));
		System.out.println(bonawentura);

		tigerInBag.map(kaleszi::playWith);
		System.out.println(bonawentura);

		tigerInBag.get().giveFood(kaleszi);
		//... happy endu nie będzie
	}
}

No i ją zeżarł.

Podsumowanie

Optional jest co do zasady kontenerem, który ma chronić nas przed NPE. Jest to szczególny przypadek problemu. Inne kontenery takie jak Try chronią nas przed całym spektrum problemów. Jeszcze inne, jak Future pozwalają na bezpieczne przekształcanie wartości bez konieczności wykonywania operacji blokujących. Zatem decydując się na zamknięcie jakiejś wartości w kontenerze, należy założyć, że wszelkie operacje będziemy wykonywać w ramach tego kontenera. Rozpakowanie powinno nastąpić w miejscu, w którym wiemy, jak poradzić sobie z potencjalnymi fakapami. Na przykład w przypadku Optional, wiemy jak należy potraktować pustą wartość. Dla Try mamy gotowy mechanizm obsługi błędów, a Future najlepiej rozpakować w wątku, który może zostać zablokowany i nie będzie to boleć.

We don’t need a Kukiz

Zanim zbiorę się i napiszę konstruktywną krytykę Wojtka Seligi i jego farm programistów, to pozwolę sobie na szybki polityczny wpis. Poseł Jakubiak z klubu Kukiz’15 popiera badania psychiatryczne kandydatów na posłów i senatorów. Pomysł powraca co kilka lat w takiej lub innej formie. Ostatnia wersja została poroniona przez PSL, zawsze dziewicę.

A teraz na przykładzie takiej hipotetycznej ustawy, której treść znajdziecie poniżej, pokażę wam na czym polega psucie demokracji.

Ustawa

My naród… blebleble… bełt. Zmiana ustawy o wyborze posła i senatora, czy jak to tam się nazywaµ…

Art 1. Nałożenie obowiązku badań
§1. Każdy obywatel i obywatelka ubiegający się o mandat posła albo senatora zobowiązany jest stawić się prze kolegium lekarskim przy PKW nie później niż na 28 dni przed datą wyborów.
§2. Kolegium orzeka czy stan zdrowia psychicznego nie zagraża pełnieniu przez niego mandatu posła albo senatora.

Art 2. Kolegium
§1. Kolegium lekarskie przy PKW składa się z 40 ekspertów wybranych drogą losowania spośród wszystkich biegłych sądowych z zakresu psychiatrii, którzy są wymienieni na listach wszystkich sądów okręgowych.
§2. Losowanie odbywa nie nie później niż 3 dni po ogłoszeniu daty wyborów.
§3. Wylosowany biegły może odmówić wzięcia udziału w komisji nie później niż w przeciągu 7 dni od daty losowania.
§4. Na miejsce biegłego, który odmówił udziału w tej farsie, niezwłocznie losuje się zastępcę.

Art3. Komisja i przebieg badania
§1. Każdy kandydat wstaje przed kolegium złożonym z 5 biegłych wyłonionych drogą losowania spośród biegłych wylosowanych w Art2.§1.
§2. Kolegium dokonuje badania psychiatrycznego.
§3. W przeciągu 3 dni, ale nie później niż w dniu poprzedzającym wybory kolegium ogłasza wynik badania do wiadomości publicznej.
§4. Mając na uwadze tajemnicę lekarską w przypadku, gdy kandydat nie jest zdolny do sprawowania funkcji komisja zobowiązana jest do podania informacji następującej treści:

Kandydat «Imię i nazwisko kandydata» ubiegający się o mandat «posła/senatora» z ramienia komitetu wyborczego «dane komitetu» nie daje gwarancji prawidłowego sprawowania mandatu.

Art 4. Listy chorób wykluczających kandydatów
§1. Listę chorób psychicznych, które uniemożliwiają sprawowanie mandatu posła albo senatora ogłasza minister właściwy do spraw zdrowia nie później niż w dniu ogłoszenia daty wyborów.
§2. Lista zawiera
– nazwę choroby
– jej kod zgodny z rejestrem ICD 10

Art 5. Ustawa wchodzi w życie z dniem ogłoszenia w Monitorze Polskim.

Jakością nie odbiega od ustawy o ustroju sądów autorstwa PiSuaru… Przy czym mam nadzieję, że łapiecie o co chodzi. A teraz sobie usuniemy ciasteczkowego z Sejmu i polityki po całości. Jak pytacie? Paweł Kukiz gdzieś w okolicach 2003 roku przyznał, że jest alkoholikiem. Teraz przeczytajcie art.4§1 i rzućcie okiem na kody F10.1 i F10.2 z bazy ICD10. Elegancko, bo min. Zdrowia może dodać alkoholizm do listy chorób eliminujących i choćby skały srały, to Kukiz startować nie będzie mógł. Znaczy się, będzie mógł, ale z łatką osoby nienadającej się.

A co z konstytucją?

Ano art. 99 pkt 1 stanowi, że kandydat nie może być skazany na przestępstwo umyślne ścigane z oskarżenia publicznego. Jednocześnie art. 100 pkt. 3 mówi, że szczegóły wyboru określa ustawa. A my modyfikujemy ustawę. Kolegium tylko określa czy głosujesz na wariata czy nie… Pytanie czy zagłosujesz na osobę chorą psychicznie, jeżeli będziesz wiedzieć, że jest chora…

Sezon na przetwory zakończony, czyli wspomnienie po Confiturze 2017

Jak już wcześniej pisałem w tym roku na Confiturę pojechałem jako prelegent. Mam nadzieję, że moja prezentacja się spodobała. A teraz kilka słów o prezentacjach innych 🙂

Keep IT clean: mid-sized building blocks and hexagonal architecture in real life – Jakub Nabrdalik

Świetna prezentacja poświęcona temu, jak wykorzystać widoczność pakietową do modularyzacji swojego kodu. Modyfikator domyślny jest zazwyczaj kiepsko rozumiany przez programistów. W tej prezentacji Kuba, pokazał, dlaczego domyślny modyfikator w javie działa tak, a nie inaczej. Całość dopełniały przykłady z istniejącego kodu 🙂

A Hitchhiker’s Guide to the Functional Exception Handling in Java – Grzegorz Piwowarek

Grzesiek zna się na Javaslangu/Vavr i było to widać. Prezentacja była fajnie skonstruowana, a temat, obsługa wyjątków w „funkcyjny” sposób, bardzo ciekawy. W praktyce przeszliśmy przez kilka kontenerów w rodzaju Either czy Try. Był też Optional w wersji z vavr. Bardzo fajna prezentacja, a jeżeli miałbym się czegoś doczepić, to oznaczenie jej jako zaawansowanej. Podstawy to, to nie były, ale jakaś magia też nie.

DDD: Q&A – czyli co gryzie świadomego programistę/programistkę – Sławomir Sobótka

Na prezentacjach Sławka zawsze jest wesoło. Tak też było i tym razem. Choć sobie obiecałem, że nie będę się śmiał, to żarty jednak doprowadziły mnie do pionu. Sławek opowiedział o pewnych „najczęściej spotykanych pytaniach”, które trafiają jego i „jego komandosów”, gdy współpracują z klientami. Bardzo dobrze się tego słuchało. DDD jest dość skomplikowanym zagadnieniem i nic dziwnego, że ludzie ciągle zadają pytania o te same rzeczy.

3 kroki do TDD – Michał Lewandowski

Nie javowo, ale ogólnie. Bardzo dobrze opowiedziana historia, wspólna historia, programisty, który ewoluuje w zakresie TDD. Ciekawa forma, bo podział na rozdziały, który był jednocześnie taki „audiobookowy” świetnie się sprawdził. Bardzo podobała mi się sama prezentacja, ale najlepsze było podsumowanie, które odczarowało TDD.

——
Teraz był obiad, a potem moja prezentacja. Chyba wyszło OK?
——

Secure your Docker containers – Krzysztof Miksa

Trochę się zawiodłem. Z 40 minut ponad 20 to był Q&A, który trochę nie uciągnął prezentacji. Jednocześnie było tam kilka rzeczy, które zapewne włączę do programu kursu Dockera, który przygotowujemy w fabryczce.

Plantacje programistów – kolonializm XXI wieku – Wojciech Seliga

Prezentacja ta dostanie swój osobny post. Tu tylko w dużym skrócie – po raz pierwszy zgadzam się z większością tego co mówił Wojtek.

Spoina

Twoja baza JPudelka została zaktualizowana 🙂