Nie oceniaj człowieka…

Kilka osób miało ból dupy o kalendarz Sii. Sii grzecznie przeprasza. Widać, że odrobili lekcję z zarządzania kryzysem w mediach społecznościowych.

Tyle tylko, że takie przepraszanie nie ma sensu. Powiem więcej ono jest szkodliwe.

Dobra, lecimy z koksem, czyli rozmowa kwalifikacyjna…

Mamy zazwyczaj trzy części.

W pierwszej oceniamy umiejętności twarde. Tu bez zmian.
W drugiej oceniamy umiejętności miękkie. Zgodnie z logiką przepraszania należało by wywalić tą część. Dlaczego? O tym za chwilę
W trzeciej oceniamy finanse, czyli czy poziom kandydata, jego oczekiwania i nasze możliwości pokrywają się na tyle, by go zatrudnić.

Wywalić ocenę osoby

Tyle mówi się o nie ocenianiu ludzi przez pryzmat wyglądu… zatem wyobraź sobie, że na rozmowę przychodzi (odsiew techniczny nastąpił) typowy Maciek. Nasz bohater lekko jebie cebulą i czosnkiem. Mamy zimę, a Maciek dba o zdrowie. Maciek z lekka się lepi i wygląda trochę jak żul. Poza tym miły chłopak, o szerokich zainteresowaniach, nie spędza czasu w piwnicy, ma jakieś tam swoje hobby, oczytany…

Po Maćku przychodzi typowy Leszek. Poziom wiedzy ten sam co Maciek. Tyle tylko, że nie sprawdził by się jako strach na wąpierze i strzygi. Poza tym miły chłopak, o szerokich zainteresowaniach, nie spędza czasu w piwnicy, ma jakieś tam swoje hobby, oczytany…

Którego zatrudnisz?

Maćka czy Leszka?

Zawsze oceniamy ludzi

Pierwsze wrażenie… około 5 sekund. Potem trzeba już wiedzieć, albo mieć tą naturalną umiejętność, jak je podtrzymać. Zapewne zatrudnisz Leszka, bo wywarł lepsze pierwsze wrażenie. Oceniłeś go przez pryzmat wyglądu. W dodatku tej części wyglądu, na którą ma bezpośredni wpływ, a zmiana może być stosunkowo łatwa.

Tu mała dygresja. Ocena na podstawie wyglądu dotyczy też cech, na które wpływu nie mamy np. koloru skóry, dysfunkcji fizycznych, czy pewnych zachowań, które są warunkowane naszym doświadczeniem. Nie mówię o tym aspekcie oceny, bo to zupełnie inna bajka.

Zatem oceniłeś naszych chłopaczków na podstawie wyglądu. Czy tego chcesz czy nie. Zatem podnoszenie larum, że ktoś wydał kalendarz z fotami dziewczyn w IT, to zwyczajna hipokryzja.

Liczy się zabawa

I tylko tyle. Czy kalendarz uprzedmiotawia uczestniczki sesji? Nie, one zapewne dobrze się bawiły i nie czuły się w uprzedmiotowione. Czy kalendarz „szczuje cycem”? Nie, po prostu nie. Równie dobrze można powiedzieć, że praktycznie każdy ubiór poza bardzo luźną burką jest szczuciem cycem. Serio, bo są ludzie, których podnieca widok dłoni, ramion czy łydki.

W czasie takiej sesji liczy się dobra zabawa i tyle. Powiem wam jeszcze jedno, wiele dziewczyn, obiektywnie ładnych i zadbanych, ma za sobą jakieś tam mniejsze czy większe doświadczenia w różnych formach modelingu. Czasami są to pojedyncze sesje „bo będzie fajnie”, czasami pierwsza praca w roli hostessy. I jest trochę większa szansa, że takie właśnie osoby zgłoszą się do firmowej sesji, a jak już się zgłoszą, to dzięki swojemu doświadczeniu będą umiały odpowiednio „podkręcić” zdjęcie.

Dlaczego?

Moim zdaniem ludzie, którzy zarzucają niestosowność takiej formie promocji mają niską samoocenę. Najzwyczajniej w świecie są zazdrośni, że ktoś może zrobić sobie zdjęcie, na którym wygląda super i jednocześnie dobrze się bawić. Dziwnym trafem ta choroba zazdrości, szczególnie o wygląd, zazwyczaj dotyczy dziewczyn. I coś jest w twierdzeniu, że największym wrogiem kobiety jest inna kobieta.

A może jakieś podsumowanie roku?

Trochę na blogu się działo 🙂 Zatem czas na małe podsumowanie.

Z rzeczy blogowych

Przekroczyliśmy 1000 postów, co mnie cieszy, bo po prawie 10 latach prowadzenia bloga mamy całkiem ładny wynik 🙂

W tym roku powstało ponad 100 postów, z czego zdecydowana większość w ramach blogowej wiosny. Cała ta zabawa potwierdziła tylko, że jestem w stanie jeszcze coś napisać 🙂

To, czego nie udało się zrobić, to nowy layout. Jakoś nie mogę znaleźć odpowiedniego, a i z grafikami mi jakoś nie po drodze 🙁
CHUJ! Zmiana nastąpiła.

Z rzeczy technologicznych

Zdecydowanie Kotlin i Elixir. Pierwszy z nich jest dla mnie wyborem numer 2 na JVM, a drugi głównym językiem funkcyjnym. Powiem szczerze, że szczególnie Elixir dał mi dużo w kontekście poszerzania swojej wiedzy i umiejętności.

Po stronie czystej Javy, za największy pozytyw tego roku muszę uznać cykl o Javaslang. Kolejne narzędzie w arsenale 🙂

To, co się nie udało, to rozkmina erlangowego OTP na poziomie pozwalającym na swobodne tworzenie aplikacji. Poległem też, jeśli chodzi o kursy na Courserze.

A co w community?

Na pewno sukcesem była kolejna edycja Chamberconf. Jak już jesteśmy przy konferencjach, to w końcu udało się i wystąpilem na Confiturze 🙂

Community to nie tylko konferencje. Zdecydowanie największym moim sukcesem jest tłumaczenie i rozwój Elixir School. Fajnie jest raz na pewien czas zrobić coś dla zabawy 🙂

Niestety umarł nam, znowu, wrocławski JUG.

Zawodowo i prywatnie

Nowa stara firma i praca trenera, to na pewno największy sukces zwodowy 🙂

A prywatnie? Kolejny release uważam za całkiem udany 🙂

Jak nauczyć się (kolejnego) języka?

Odpowiedź na to pytanie jest prosta – napisać coś w nim.

Tyle tylko, że co mam napisać? Oczywiście najprościej jest naskrobać kolejnego klona Pet Clinic, własny system blogaskowy, albo bibliotekę (taką z książkami). Nie przeczę, są to zacne metody, ale mają pewną wadę. Wymagają od nas znajomości języka i narzędzi na pewnym minimalnym poziomie. Bez tego dość szybko popadniemy w kłopoty i zniechęcimy się po „10 godzinach walki z jakimś mavenem, eclipsem i innym springiem”, gdy chcemy się nauczyć podstaw Javy. Projekty są dobre, ale jako „praca końcowa”. Na początek znacznie lepsze są mniejsze zadania, które pozwalają poznać składnię języka i pobawić się z kodem. Przykładem może być samodzielna implementacja zadań z książki Mazes For Programers. Przykładowy kod jest napisany w Ruby, co samo w sobie może być motywacją do poznania tego języka, ale jest też na tyle prosty i dobrze opisany, że można zaimplementować rozwiązania w innym języku.

Inną drogą jest wzięcie udziału w jakiejś formie rywalizacji. Począwszy od starego dobrego SPOJa, poprzez Project Euler, czy też Top Coder. W tym przypadku mamy dowolnie dużo czasu i nie mamy narzuconej kolejności zadań. Ma to swoje plusy, ale też minusy. Jednym z nich jest brak bata i zachęty do codziennej pracy. Dlatego też warto zainteresować się Advent of Code, która niejako wymusza na nas systematyczną, codzienną pracę.

Te wszystkie metody są doskonałe też wtedy, gdy chcemy nauczyć się kolejnego języka. Najpierw zróbmy rozwiązanie w nowym języku, a następnie w naszym głównym. Zobaczycie różnice.

Na koniec małe przypomnienie. Już 26 listopada będę mówił o Elixirze na InfoMeet, start o 9:30 w sali C. Będzie zabawnie 🙂

„Obiektywne” struktury danych w Elixirze

„Obiektywne”, bo nie „obiektowe”. Przymierzam się do opisania interoperacyjności java-elixir trochę ponad „użyj JInterface”, ale zanim do tego się zabiorę, potrzebujemy mieć kilka dodatkowych narzędzi.

Na początek jednak małe przypomnienie. Już za dwa tygodnie z małym haczykiem tzn. 26 listopada będę mówił o Elixirze na InfoMeet, start o 9:30 w sali C. Będzie zabawnie 🙂

Klasy, obiekty i cała reszta

W językach obiektowych jest prosto. Jeżeli potrzebujemy usystematyzować dane, to definiujemy klasę. Ma ona pola, pola mają wartości. Za czynności odpowiadają metody, które powinny mieć swoje odzwierciedlenie w interfejsach (DDD dla oszczędnych), to tego jest jeszcze element JavaBeans i gotowe. Jak mamy już nasze dane i klasę, to możemy tworzyć obiekty, które reprezentują pewien stan danych. Do tego dochodzą jeszcze kontenery jak na przykład listy, mapy czy sekwencje.

W językach funkcyjnych jest pewien drobny problem…

Podejście funkcyjne

W językach funkcyjnych mamy do dyspozycji m.in. czysto funkcyjne strukturyW, które w uproszczeniu można przyrównać do niezmiennych kolekcji z języków obiektowych (w rzeczywistości najbliżej do tych struktur mają kolekcje z pCollections). Jak jednak odwzorować „klasyczne” obiekty? Zazwyczaj robi się, to poprzez zagnieżdżanie i definiowanie własnych typów.

Na przykładzie Elixira

Osadzanie struktur

Trochę jak w JavaScriptcie 🙂 Czyli nasza złożona struktura to mapa map (o listach, sekwencjach itd. innym razem, ale to nuda jest i tak). Jak wygląda mapa w Elixirze?

Mapy w Elixirze definiuje się w prosty sposób:

Listing 1. Mapa z trzema elementami

iex > mapa = %{:A=> 1, 2=> :b, "C"=> "3"}
%{2 => :b, :A => 1, "C" => "3"}

Jako że Elixir jest słabo typowany, to zarówno klucze, jak i wartości mogą być dowolnego typu. Oczywiście mapy można zagnieżdżać:

Listing 2. Mapa map

iex > mapaMap = %{ "pole" => 1, :pole => mapa}
%{:pole => %{2 => :b, :A => 1, "C" => "3"}, "pole" => 1}

Jest tu jednak pewien „myk”, który będzie bardzo przydatny:

Listing 3. Mapa z kluczami – atomami

iex > mapa = %{:age => 32, :name => "Koziołek"}
%{age: 32, name: "Koziołek"}

Zwróćcie uwagę na, to co stało się z dwukropkami przy nazwach atomów. Zmieniły położenie i z przedrostka stały się przyrostkiem. Technicznie nadal jest, to mapa:

Listing 4. Typ naszej mapy to

iex > i mapa
Term
  %{age: 32, name: "Koziołek"}
Data type
  Map
Reference modules
  Map

I jeszcze jedna zagadka:

Listing 5. Czym jest lista dwuelementowych krotek?

iex > lista = [{:age, 32}, {:name, "Koziołek"}]
[age: 32, name: "Koziołek"]

Lista dwuelementowych krotek, w których pierwszym elementem jest atom, jest tzw. keyword list. Najlepszym odpowiednikiem tego terminu jest lista asocjacyjna. Tak też, to przetłumaczyliśmy w ramach ElixirSchool. W przypadku map jeżeli kluczami są atomy, to Elixir zapewnia spójne z listami asocjacyjnymi API. I jeszcze krótko o typie naszej listy:

Listing 6. Ano jest listą

iex > i lista
Term
  [age: 32, name: "Koziołek}]\n\n"]
Data type
  List
Description
  This is what is referred to as a "keyword list". A keyword list is a list
  of two-element tuples where the first element of each tuple is an atom.
Reference modules
  Keyword, List

Skoro wiemy już, że można zagnieżdżać mapy i możemy budować w ten sposób struktury podobne do JSON-ów, to rzućmy jeszcze okiem na definiowanie własnych typów.

Własne typy

Zanim zajmiemy się typami mała uwaga, własne typy w Elixirze warto definiować w ramach wydzielonego modułu, ponieważ przy bardziej złożonych strukturach będziemy też korzystać z definicji struktur.

Na początek zdefiniujmy sobie moduł User.Struct (można w nazwie, można zagnieździć, dostęp będzie taki sam), który będzie przechowywać informacje o strukturze użytkownika:

Listing 7. Moduł User.Struct

defmodule User do

  defmodule Struct do
      defstruct [age: nil, name: nil]
  end
    
end

Teraz dodajmy do naszej struktury typ, konwencja jest taka, że typ nazywamy t i będziemy się do niego odwoływać przez User.Struct.t (plus jedna metoda do testów):

Listing 8. Definicja typu

defmodule User do

  defmodule Struct do
      defstruct [age: nil, name: nil]

      @type t :: %User.Struct{age: integer, name: String.t}

      @type t(age, name) :: t :: %User.Struct{age: age, name: name}

  end

  @spec printInfo(User.Struct.t) :: nil
  def printInfo(user) do
    IO.puts("User name  is #{user.name} and age is #{user.age}")
  end

end

Mamy tu tak naprawdę dwa typy. t, który jest „właściwym” zdefiniowanym jako mapa pól dla struktury i t(age, name), który rozszerza t oraz pełni funkcję czysto pomocniczą jeżeli chcemy przedefiniować, któryś z elementów struktury. A jak tego używać?

Listing 9. przykładowe użycie

iex > user = %{:age=> 32, :name=>"Koziołek"}
%{age: 32, name: "Koziołek"}
iex > User.printInfo(user)
User name  is Koziołek and age is 32
:ok

Tworzymy sobie naszego użytkownika jako mapę i aplikujemy funkcję. Jeżeli coś popieprzymy, to dostaniemy błąd.

Podsumowanie

Własne typy w Elixirze nie są tak mocne, jak w Javie, ale też nie mamy do czynienia z językiem statycznie typowanym. Warto je jednak wprowadzać i używać, by zachować pewien poziom bezpieczeństwa w naszym kodzie. Miłe…

Jedno z dwojga – Either w akcji

Na początek kilka spraw organizacyjnych. Jak widać pisanie po wiosennym ruchu idzie mi średnio 🙂 Ale się staram. Powodów jest kilka, jeden ma 5 lat, drugi 2 miesiące 🙂 Do tego dość dużo pracy i zdecydowanie za krótka doba.

26 listopada będę mówił o Elixirze na Infomeet. Jak chcecie posłuchać dlaczego moim zdaniem warto, to zapraszam. Slajdy z prezentacji, która odbyła się w ramach targów KarieraIT tutaj. I lecimy z tematem.

Either kto to?

Jednym z problemów związanych ze zwracaniem wyników z funkcji (w rozumieniu zarówno metody obiektu, jak i „właściwej” funkcji) jest „upchnięcie” informacji o wyniku i jego poprawności. Klasycznie można taki kod napisać w następujący sposób:

Listing 1. Klasyczne podejście do problemu

public int sumUpTo(int limit) throws SumException{
	//....
}

Mamy sobie metodę, która rzuca wyjątek, jeżeli coś się jej nie spodoba. Takie rozwiązanie jest OK, lecz ma kilka wad. Po pierwsze wyjątek należy przechwycić. O ile wyjątków niekontrolowanych nie musimy obsługiwać w jawny sposób, to jednak w porządnie napisanym sofcie należy pomyśleć o jakimś mechanizmie do ich przechwytywania. Niestety w klasycznym podejściu walimy blok catch(Throwable) gdzieś wysoko i nam to rybka. Po drugie wyjątki są stosunkowo ciężkim mechanizmem. Wyrzucenie wyjątku kontrolowanego wymaga dodatkowej pracy od JVMki, by odpowiednio posprzątać stan aplikacji bardziej szczegółowy opis tutaj. Po drugie czasami narzucone API ogranicza nasze możliwości, jeśli chodzi o wyjątki i musimy korzystać z konstrukcji przechwyć-opakuj-rzuć. Zazwyczaj zamieniamy wyjątek kontrolowany na ogólny RuntimeException. Po trzecie taka metoda, nawet jak rzuca wyjątek niekontrolowany, to bywa trudnym przypadkiem, gdy chcemy korzystać z kompozycji, czy strumieni. Po prostu napiszemy się tych map i filter, a potem i tak trzeba try-catch, bo coś.

Rozwiązaniem jest użycie Either z biblioteki Javaslang. Jest to interfejs, który posiada dwie implementacje Left i Right. Dodatkowo istnieje konwencja, że poprawny wynik trafia do Right, a błędny do Left. Nie jest ona w żaden sposób weryfikowana, ale API niejako „promuje” użycie Rigth, gdyż funkcje domyślnie korzystają z tej wartości. Można zatem przepisać naszą metodę do:

Listing 2. Zmiana API na korzystające z Either

public Either<String, Integer> sumUpTo(int limit){
	//....
}

Either po co to?

Możemy potraktować Either jako rodzaj kontenera na wynik operacji. Jeżeli zakończy się błędem, to zostanie wypełniona jego lewa strona, w przeciwnym wypadku wypełniona będzie prawa. Bazując na tej informacji, możemy wprowadzić funkcje takie jak map czy filter. Pozwolą one na budowę odpowiedniego przepływu w aplikacji. Przykładowo jeżeli, chcemy wynik naszej funkcji zamienić na komunikat:

Listing 3. Wykorzystanie Either.map

public static void main(String[] args) {
	sumUpTo(10).map(s -> s + "").forEach(System.out::println);
}

Jeżeli z jakiegoś powodu nasza funkcja zwróci błąd, to wynik będzie… pusty. Po prostu mapowanie się nie wykona. Tu uwidacznia się pewna cecha Either. Jest on „stronniczy”, to znaczy gdy z nim pracujemy musimy określić, która strona nas interesuje. Funkcja map pracuje z wartością Right, ale jest też mapLeft. W dodatku mamy jeszcze projekcje…

Projekcje

Projekcje, to nic innego jak opakowane wartości. Dostarczają nam one odpowiednich funkcji w rodzaju map, filter itd., ale już w kontekście odpowiedniej wartości. By się do nich dobrać, należy wywołać right albo left na obiekcie Either. Kod z listingu 3 można zapisać jako:

Listing 4. Wykorzystanie projekcji

public static void main(String[] args) {
	sumUpTo(10).right().map(s -> s + "").forEach(System.out::println);
}

Jawnie opowiadając się po jednej ze stron, możemy skupić się tylko na interesującej nas części wartości albo błędzie.

Podsumowanie

Oczywiście nie przedstawiłem tu wszystkich możliwości Either. Zachęcam do zapoznania się z dokumentacją, kodem oraz samodzielnego eksperymentowania.

Elixir Mix – aktualizacja Hexa

W dużym uproszczeniu Hex jest managerem pakietów w Elixirze. Dokładniej pełni on rolę narzędzia do zarządzania pakietami, zależnościami oraz jest też repozytorium zależności. Coś jak Ivy dla Anta z konfiguracją do repozytorium Mavena. Rzecz w tym, że dziś rzeźbiąc sobie kod otrzymałem błąd:

Listing 1. Błędny błąd

[koziolek@koziolek-laptop learn_elixir (master)]$ mix test
** (UndefinedFunctionError) function Hex.SCM.managers/1 is undefined or private
    Hex.SCM.managers([lock: nil, env: :prod, hex: :exml, build: "/home/koziolek/workspace/learn_elixir/_build/test/lib/exml", dest: "/home/koziolek/workspace/learn_elixir/deps/exml"])
    (mix) lib/mix/dep/loader.ex:173: Mix.Dep.Loader.scm_manager/2
    (mix) lib/mix/dep/loader.ex:44: Mix.Dep.Loader.load/2
    (mix) lib/mix/dep/converger.ex:179: Mix.Dep.Converger.all/9
    (mix) lib/mix/dep/converger.ex:114: Mix.Dep.Converger.all/7
    (mix) lib/mix/dep/converger.ex:99: Mix.Dep.Converger.all/4
    (mix) lib/mix/dep/converger.ex:50: Mix.Dep.Converger.converge/4
    (mix) lib/mix/dep.ex:95: Mix.Dep.loaded/1

Szybkie sprawdzenie mix.exs niby wszystko ok, ale dla pewności dociągnę zależności:

Listing 2. Błędny błąd – bardziej gadatliwy

[koziolek@koziolek-laptop learn_elixir (master)]$ mix deps.get
A new Hex version is available (v0.13.2), please update with `mix local.hex`
Running dependency resolution
** (UndefinedFunctionError) function Access.Map.get_and_update!/3 is undefined (module Access.Map is not available)
    Access.Map.get_and_update!(%Mix.Dep{app: :exml, deps: [], extra: [], from: "/home/koziolek/workspace/learn_elixir/mix.exs", manager: nil, opts: [env: :prod, hex: :exml, build: "/home/koziolek/workspace/learn_elixir/_build/dev/lib/exml", dest: "/home/koziolek/workspace/learn_elixir/deps/exml"], requirement: "~> 0.1.0", scm: Hex.SCM, status: {:unavailable, "/home/koziolek/workspace/learn_elixir/deps/exml"}, top_level: true}, :deps, #Function<11.61161633/1 in Hex.Resolver.attach_dep_and_children/3>)
    lib/hex/resolver.ex:190: Hex.Resolver.attach_dep_and_children/3
    lib/hex/resolver.ex:150: Hex.Resolver.get_deps/4
    lib/hex/resolver.ex:109: Hex.Resolver.activate/5
    lib/hex/resolver.ex:31: Hex.Resolver.resolve/3
    lib/hex/remote_converger.ex:33: Hex.RemoteConverger.converge/2
    (mix) lib/mix/dep/converger.ex:89: Mix.Dep.Converger.all/4
    (mix) lib/mix/dep/converger.ex:50: Mix.Dep.Converger.converge/4

Czyli ok… rzeczywiście robiłem ostatnio update Elixira i trzeba by podbić wersję Hexa! Zatem lecimy z tematem:

Listing 3. Błędny błąd – brak zmian

[koziolek@koziolek-laptop learn_elixir (master)]$ mix local.hex
Are you sure you want to install archive "https://repo.hex.pm/installs/1.3.0/hex-0.13.2.ez"? [Yn] Y
* creating /home/koziolek/.mix/archives/hex-0.13.2
[koziolek@koziolek-laptop learn_elixir (master)]$ mix deps.get
A new Hex version is available (v0.13.2), please update with `mix local.hex`
Running dependency resolution
** (UndefinedFunctionError) function Access.Map.get_and_update!/3 is undefined (module Access.Map is not available)
    Access.Map.get_and_update!(%Mix.Dep{app: :exml, deps: [], extra: [], from: "/home/koziolek/workspace/learn_elixir/mix.exs", manager: nil, opts: [env: :prod, hex: :exml, build: "/home/koziolek/workspace/learn_elixir/_build/dev/lib/exml", dest: "/home/koziolek/workspace/learn_elixir/deps/exml"], requirement: "~> 0.1.0", scm: Hex.SCM, status: {:unavailable, "/home/koziolek/workspace/learn_elixir/deps/exml"}, top_level: true}, :deps, #Function<11.61161633/1 in Hex.Resolver.attach_dep_and_children/3>)
    lib/hex/resolver.ex:190: Hex.Resolver.attach_dep_and_children/3
    lib/hex/resolver.ex:150: Hex.Resolver.get_deps/4
    lib/hex/resolver.ex:109: Hex.Resolver.activate/5
    lib/hex/resolver.ex:31: Hex.Resolver.resolve/3
    lib/hex/remote_converger.ex:33: Hex.RemoteConverger.converge/2
    (mix) lib/mix/dep/converger.ex:89: Mix.Dep.Converger.all/4
    (mix) lib/mix/dep/converger.ex:50: Mix.Dep.Converger.converge/4

No i chuj… Mniej więcej tak to wyglądało:

Życie...

Wychodzi na to, że Hex się jednak nie zaktualizował i nadal wisi w jakiejś przedpotopowej wersji. Nauczony doświadczeniem z Eclipse+Maven wybrałem się do katalogu z repozytorium mixa, czyli ~/.mix/archives/ i wywaliłem wszystko co związane z Hexem, czyli plik hex.ez i katalog hex-0.13.2. Po czym wróciłem do katalogu z projektem i powtórzyłem instalację hexa i ściągnięcie zależności.

Co się okazało?

Ano okazało się, że aktualizacja Hexa nie podmienia pliku hex.ez

Listing 4. Błędny błąd – przyczyna, zwróć uwagę na daty

[koziolek@koziolek-laptop archives]$ ll
razem 392
drwxrwxr-x 3 koziolek koziolek   4096 paź 24 21:07 ./
drwxrwxr-x 3 koziolek koziolek   4096 maj 23  2015 ../
drwxrwxr-x 3 koziolek koziolek   4096 paź 24 21:07 hex-0.13.2/
-rw-rw-r-- 1 koziolek koziolek 262010 maj 19  2015 hex.ez
-rw-rw-r-- 1 koziolek koziolek 123280 maj 23  2015 phoenix_new-0.13.1.ez

Ręczne usunięcie tego pliku wymusza jego ponowne pobranie, już w aktualnej wersji.

Zależności w Elixirze, czyli wstęp do Mixa

Jakoś tak w ostatnich latach się porobiło, że każdy szanujący się język programowania powinien się dorobić narzędzia do zarządzania procesem kompilacji, zależnościami, czy wdrożeniem. Dla Javy jest to Ant, Maven i Gradle. Pierwsze dwa reprezentują podejście opisowe, a trzeci to po prostu DSL w groovym. Dla Scali będzie to SBT, dla Rubiego Rake itd, itp. Można jednak zaobserwować, że wszystkie te narzędzia dążą do modelu, w którym zamiast opisu i konfiguracji (w xml-u) mamy wykonywalny skrypt. Jest to rozsądne, ponieważ daje programiście znacznie większe możliwości w zakresie kontroli procesu kompilacja-testy-wdrożenie niż w przypadku narzędzi w rodzaju mavena. Tu po prostu piszesz kawałek kodu i po problemie.

W przypadku Elixira narzędziem tym jest Mix. Dostarczany jest wraz z paczką języka i pracuje w oparciu o plik mix.exs, w którym zdefiniowany jest najzwyczajniejszy w świecie moduł. Musi on zawierać funkcję project zwracającą listę asocjacyjną (oryginalna nazwa tej struktury to keywords) z konfiguracją oraz używać (makro use) Mix.Project. Na przykładzie:

Listing 1. Przykładowy plik mix.exs

defmodule ElixirExample.Mixfile do
  use Mix.Project

  def project do
    [app: :elixir_example,
     version: "0.1.0",
     elixir: "~> 1.3",
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     deps: deps()]
  end

  # Configuration for the OTP application
  #
  # Type "mix help compile.app" for more information
  def application do
    [applications: [:logger]]
  end

  # Dependencies can be Hex packages:
  #
  #   {:mydep, "~> 0.3.0"}
  #
  # Or git/path repositories:
  #
  #   {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
  #
  # Type "mix help deps" for more examples and options
  defp deps do
    []
  end
end

Listing 1. zawiera plik, który powstaje po wywołaniu polecenia mix new. Jak widać jest w nim kilka dodatkowych rzeczy. Po pierwsze lista zależności została przesunięta do prywatnej funkcji deps. Jest to o tyle wygodne, że w przypadku większych aplikacji, gdzie lista zależności jest długa, kod będzie czytelniejszy. Ciekawostką jest możliwość wykorzystania zarówno repozytorium binarek Hex jak i wskazanie taga w repozytorium z kodem źródłowym (git). Po drugie mamy tu funkcję application, która odpowiada za wygenerowanie pliku .app, który opisuje z jakich zasobów korzysta aplikacja, jaka jest jej struktura i jak powinna zostać uruchomiona. Jest to element pochodzący bezpośrednio z erlanga.

I to są podstawy, które pozwalają nam na rozpoczęcie zabawy z programowaniem w Elixirze trochę bardziej skomplikowanych rzeczy niż proste zabawki z użyciem REPLa iex.

Mocno spóźniony protest

Oczywiście chodzi o #czarnyprotest. O ile sama idea jest słuszna, ponieważ przerwanie ciąży jest normalną procedurą medyczną i jej wykonanie nie powinny podlegać karze, to wykonanie jest mocno spóźnione.

Język

W projekcie nie ma nic nadzwyczajnego, ale wynika to z użytego języka.

Nie popełnia przestępstwa […] uchylenia bezpośredniego niebezpieczeństwa dla życia matki dziecka poczętego.

Mówiąc prościej, dopóki kobieta nie jest umierająca, żaden lekarz nie zaryzykuje odsiadki, by ją ratować. Nawet jak będzie umierająca, to jeżeli coś pójdzie nie tak i płód obumrze, to od prokuratora zależy los lekarza.

Sam język prawa nie jest jednak problemem. W dyskusji o aborcji obowiązuje język tzw. ruchu pro-life. Mówi się o ochronie życia poczętego, o dziecku nienarodzonym itp. nowomowie. Chcąc prowadzić dyskusję w tej sprawie, jesteśmy niejako zmuszeni do korzystania z narzuconego przez jedną stronę języka.

Argumenty

Jak już przy dyskutowaniu jesteśmy. Dyskusja z grupami typu Ordo Iuris nie ma sensu. Dla nich jest, to dyskusja ideowa w dodatku o jednym z aksjomatów przyjętej filozofii. Żaden rzeczowy argument, poparty danymi, badaniami, rzeczywistymi zdarzeniami nie ma tu sensu. Równie dobrze można dyskutować z papieżem o istnieniu boga.

Dlaczego protest jest spóźniony?

Ponieważ protestować trzeba było te 20 lat temu, gdy przepychano przepisy. Ok, ale większość z nas w tym czasie zdzierała kolana w piaskownicach i na trzepakach. Tak. Dlatego słusznym czasem na protest przeciwko zaostrzeniu prawa oraz ogólniej durnemu kompromisowi aborcyjnemu powinny być ostatnie wybory. Jak pytam znajomych wstawiających hash tagi czy w ostatnich wyborach głosowali na partię, która nie chce zaostrzenia prawa/zachowania kompromisu to okazuje się, że nie… Powiedzmy sobie szczerze, w Polsce wszystkie partie znajdujące się w parlamencie mają konserwatywny światopogląd. Sorry Winnetou, trzeba było myśleć nad urną.

I dlatego też protest ten jest bezsensowny. Spotkałem się z argumentem, że jak ustawa przejdzie, to kolejne wybory PiS przegra. Nie przegra, bo kolejne wybory są za 3 lata z hakiem, a do tego czasu będziemy mieli znacznie więcej znacznie ciekawszych tematów. Zresztą tak samo, jak przyjęcie tej ustawy nie zaszkodzi też obsadzanie stołków misiewiczami. PiS ma jeszcze dużo czasu, a ludzie zapominają o tego typu duperelach.

ps. Michał, czyli młodszy nurgling już w domu 🙂

Chemiczny konkurs od DZone – rozwiązanie w Elixirze

O ile rozwiązanie w Javie możecie sobie podejrzeć w repozytorium, a jego omówienie będzie w przyszłym tygodniu, to dziś pokażę, jak można rozwiązać zadanie w Elixirze.

W praktyce całość sprowadza się do kilku (dokładnie 22) linii kodu:

Listing 1. Rozwiązanie w Elixirze

defmodule Chemicals do
  import Enum, only: [map: 2, uniq: 1, min: 1, member?: 2]
  import String, only: [downcase: 1, split: 3 ]
  
  def main(args) do
      {_, [name|t], _} = OptionParser.parse(args)
      symbols = name |> downcase |> split("", trim: true )|> generateValidSymbols
      IO.puts member?(symbols, t|> List.first |> downcase )
      IO.puts length(symbols)
      IO.puts min(symbols)
  end

  def generateValidSymbols([head|tail]) when length(tail) == 1 do
      tail|> map( &(head  <> &1))
  end

  def generateValidSymbols([head |tail]) do
      symb = tail |> map( &(head  <> &1))
      uniq(symb ++ generateValidSymbols(tail))
  end

end

Kluczem są funkcje generateValidSymbols, które zwracają listę wszystkich poprawnych symboli dla podanej nazwy. To samo napisane w Javie (z zachowaniem tej samej logiki) to zdecydowanie więcej kodu. Co tu się dzieje?

Funkcja przyjmuje jako parametr listę liter z nazwy pierwiastka i od razu dzieli ją na pierwszy element (potocznie głowę – head) i resztę (ogon – tail). Jeżeli ogon ma długość 1, co weryfikuje strażnik, to elementy są łączone. Inaczej dla każdego elementu ogona tworzony jest symbol, a lista tak wygenerowanych symboli jest łączona z listą symboli wygenerowanych z ogona. Z tak powstałej listy usuwane są duplikaty. Następnie za pomocą kilku prostych testów sprawdzamy, czy symbol, podany jako drugi parametr, znajduje się na liście, jak duża jest lista, który symbol jest pierwszy w kolejności alfabetycznej.

A najwięcej czasu zajęło mi sprawdzenie jak to cholerstwo uruchomić, bo nie jest to takie oczywiste 🙂