czwartek, 31 sierpnia 2017

Szczepienia czyli utylitaryzm wciąż ma się dobrze

Zazwyczaj mało interesują mnie dyskusje, którymi tak emocjonują się ludzie w szczególności w mediach społecznościowych. Czasami jednak po przeczytaniu, chcąc nie chcąc, kilku komentarzy ciężko opanować wzburzenie. Tyle, że zamiast toczyć niekończącą się wymianę zdań na facebooku wolę zebrać swoje przemyślenia w jednym miejscu. Nie będą one dotyczyć tego czy szczepienia działają czy nie, lecz samego przymusu czy też obowiązku szczepień.

Zacznę od tego, że niniejszy post skierowany jest do ludzi wierzących w obiektywne wartości moralne. Jeżeli jesteś relatywistą moralnym to nic z tego tekstu do ciebie nie trafi. Dla tych, którzy nie wiedzą o czym mowa, relatywista moralny to ktoś, kto na pytanie:

Czy dobrze jest molestować małe dzieci?

odpowiada:

Jeżeli sam tak uważasz to jak najbardziej!

Najczęściej takie osoby charakteryzują sformułowania typu "każdy ma swoją moralność", "dlaczego moja moralność ma być gorsza od twojej" itp. Osoba wierząca w obiektywne wartości moralne uważa, że bez znaczenia jest co kto myśli, ponieważ są one niezależne od ludzkiej opinii.

Czytając te wszystkie dyskusje nie trudno zauważyć, że głównie pojawiają się dwa rodzaje argumentów. Pierwszy brzmi mniej więcej tak:

Jestem za tym by rodzice mogli decydować o szczepieniu dziecka ale tylko wtedy jeśli pokryją koszty leczenia jak to dziecko zachoruje.

Jak rozumiem logika jest mniej więcej taka, że skoro służba zdrowia jest "darmowa", a ci rodzice jawnie postępują przeciwko jej zaleceniom to niech płacą za swoje błędy. Darmowa oczywiście nie jest bo wszyscy za nią płacą w ten czy inny sposób ale to niewiele zmienia. Możemy to rozumieć też tak, że dlaczego wszyscy teraz mają się składać na leczenie dziecka, którego rodzic celowo nie szczepił (czyli celowo ryzykował). Problem polega na tym, że chcąc zachować spójność to zgodnie z tą logiką płacić (dodatkowo) za swoje leczenie powinny również osoby:

  • otyłe, gdy zachorują na choroby układu krążenia,
  • palące papierosy, gdy np. dostaną raka,
  • pijące alkohol, gdy wątroba zacznie szwankować,
  • wszyscy pracownicy nie stosujący się do zasad BHP, gdy już coś im się stanie,
  • osoby nie dbające o higienę osobistą,
  • osoby z chorobami wenerycznymi,
  • itp. itd.

Na dobrą sprawę to właściwie każdy znajdzie coś dla siebie. Argument ten podyktowany jest zapewne poczuciem sprawiedliwości (dlaczego ja mam płacić za błędy kogoś innego), tyle, że jedyny sprawiedliwy układ to taki kiedy każdy sam płaci za swoje leczenie. Tak jak każdy sam płaci za swoje jedzenie czy swój samochód.

Druga opinia pojawia się najczęściej w odpowiedzi na tę pierwszą:

Przymus musi być bo są osoby, których zaszczepić nie można i zdrowie gwarantuje im tylko duża liczba zaszczepionych osób, które blokują rozprzestrzenianie się choroby.

Tu dochodzimy do kwestii moralnej. Otóż to co tu widzimy to nic innego jak utylitaryzm. To taki pogląd, w którym uważa się, że dobre jest to co generuje najwięcej szczęścia. W tym przypadku będzie to zdrowie jak największej liczby osób. Utylitaryzm najczęściej kończy się w sytuacji, gdzie szczęście wielu osób zależy od twojego nieszczęścia. Dla przykładu, w szpitalu leży pięć osób. Każdej z nich trzeba przeszczepić inny organ. I tak się składa, że jest tam także zdrowa osoba, której organy idealnie "pasowałyby" dla tych pięciu osób. Zgodnie z utylitaryzmem dobrze byłoby poświęcić jej życie by uratować pięć. I nie ma ona nic do gadania.

Utylitaryzm jest częścią większej grupy poglądów zwanej konsekwencjonalizmem czyli czy dany czyn jest dobry czy nie określają jego konsekwencje. A konsekwencją takiego myślenia są oczywiście wszelkie państwowe przymusy. Przypuszczam, że gdyby można było z duża dokładnością stwierdzić, że śmierć dziecka pogodzi ze sobą na powrót skłócone małżeństwo to by powstało prawo nakazujące takie dzieci zabijać.

Utylitaryzm nie ma nic wspólnego z moralnością. Zdaje się, że jest on podstawą socjalizmu jaki dzisiaj widzimy. Prowadzi on tylko i wyłącznie do pozbawiania wolności. Niestety ludzie dzielą się na tych, którzy chcą żyć w wolności i tych co chcą żyć bezpiecznie. Tych drugich jest znacznie więcej ale jak mawiał Benjamin Franklin: "ludzie, którzy dla tymczasowego bezpieczeństwa rezygnują z podstawowej wolności, nie zasługują ani na bezpieczeństwo, ani na wolność".

piątek, 21 lipca 2017

Elm - frontend, który po prostu działa

Od dłuższego czasu pracuję nad aplikacją InkassoTrade. Projekt jest już uruchomiony i udostępniony publicznie więc mogę opisać nieco technologiczne jego aspekty.

InkassoTrade

Aplikacja skierowana jest głównie do firm mających problemy ze ściąganiem należności. Umożliwia (całkowicie za darmo!) wysyłanie monitów mailowych przy użyciu nieprzeciętnie zaawansowanego mechanizmu reguł. Pozwala też ona sprawnie zarządzać fakturami i wpłatami, a monity można dowolnie dostosowywać do swoich potrzeb.

Już praktycznie na samym początku podjęliśmy decyzję by interfejs pisać w Elmie. Miałem wcześniej już sporo doświadczenia pisania w tym języku ale zdecydowanie jest to mój największy projekt. Mimo, że czasem nie było różowo to w żadnym frameworku JS typu React czy Angular nie byłbym w stanie ukończyć frontendu w takim czasie. Jednak funkcyjny język i to statycznie typowany pozwala uniknąć wielu problemów.

Garść technicznych informacji

Na początek parę informacji o rozmiarze projektu:

  • Liczba linii kodu: 21286
  • Liczba bibliotek zewnętrznych: 15
  • Liczba portów: 2
  • Liczba linii kodu portów: 425
  • Rozmiar skompilowanego kodu (zminimalizowany i spakowany): 99,6 KB

O Elmie

Dla osób nie znających Elma powyższe dane mogą być nieco niezrozumiałe. Szczególnie jeśli chodzi o porty. Elm oprócz bycia funkcyjnym i statycznie typowanym językiem umożliwia podobnie jak Haskell kontrolowanie efektów. Oznacza to, że operacje takie jak pobranie aktualnej daty, wysłanie żądania HTTP czy wykonanie zewnętrznego kodu JavaScript nie da się wykonać bezpośrednio. Odbywa się to w zupełnie innym trybie, przypomina to trochę programowanie asynchroniczne w node.js. W Elmie każda aplikacja dzieli się na trzy podstawowe części:

  1. model - struktura, w której trzymany jest stan aplikacji
  2. view - funkcja, która zwraca kod HTML na podstawie modelu
  3. update - funkcja, która na podstawie akcji/zdarzenia i aktualnego modelu zwraca nowy model (aktualizuje go)

Dla przykładu powiedzmy, że mamy model, który zawiera liczbę kliknięć w jakiś przycisk. Mamy też widok, który rysuje go oraz obok wyświetla licznik kliknięć. Widok oprócz generowania samego kodu HTML "nazywa" także akcję, która ma się wykonać po kliknięciu. Natomiast funkcja update reaguje na daną akcję zwiększając licznik w modelu. Poniższy diagram sekwencji przedstawia ogólną zasadę działania:


Obrazek pochodzi ze strony elmprogramming.com, którą polecam przejrzeć podczas nauki tego języka.

Jeżeli czegoś nie można w danej chwili zrobić w Elmie to zawsze można wykorzystać do tego JavaScript. Taki kod może przesyłać dane do aplikacji przez tzw. port lub może odbierać przez niego dane wysyłane przez aplikację. Jak na takiej wielkości projekt to liczba portów jest niewielka. Wychodzi więc na to, że bardzo dużo rzeczy da się zrobić bezpośrednio w Elmie.

Dobre strony

Zacznę od tych dobrych stron, gdyż jest ich znacznie więcej. Oczywiście większość z nich wynika z samej natury funkcyjnych i statycznie typowanych języków. Jednakże Elm jest unikatowy w paru kwestiach:

  1. Wbudowany debugger - z racji tego, że wszystkie efekty wykonywane są spoza kodu aplikacji możemy ich historię wywołań przeglądać we wbudowanym debuggerze. Wystarczy tylko skompilować kod z opcją --debug i możemy przeglądać jak zmieniał się model aplikacji po każdej akcji. Dodatkowo tester, gdy napotka błąd może taką historię z debuggera wyeksportować i wysłać programiście. Programista wówczas ma ułatwione zadanie bo widzi co dokładnie tester robił i jak zachowywała się aplikacja.
  2. Virtual DOM - nie jest to nic specyficznego tylko dla Elma. Vritual DOM wykorzystuje także np. React ale dzięki niemu Elm jest naprawdę szybki. Nie skupialiśmy się w tej chwili w ogóle na wydajności interfejsu i pisaliśmy go w najprostszy możliwy sposób. Mimo to działa on całkiem sprawnie. Jest to doświadczenie dokładnie odwrotne do tego, które miałem przy pisaniu interfejsów w React'cie czy w ClojureScript'cie.
  3. Refactoring - kod tych rozmiarów co jakiś czas musiał przechodzić refactoring. Jest to normalne, gdyż z czasem jak nasza aplikacja rośnie widać coraz więcej schematów w kodzie, które można uogólnić. Kompilator Elma jest tu nieodłącznym przyjacielem programisty. Dzięki niemu nie tylko nie zapomnimy o żadnym miejscu do poprawy ale przede wszystkim komunikaty jakie zwraca są bardzo przyjemne.
  4. Separacja kodu - każdy programista webowy dobrze zna model MVC. W Elmie jest to oczywiście daleko bardziej posunięte ale przede wszystkim wymuszone. Programista nie może zmienić modelu w widoku, ani też zmienić widoku w funkcji update. Pozwala to uniknąć wielu problemów oraz kod wydaje się być bardziej przejrzysty.
  5. Formatowanie kodu - w tej kwestii Elm przypomina język Go. Dostępne jest świetne narzędzie o nazwie elm-format, które formatuje kod za ciebie. Jest to bardzo wygodne, gdy nie trzeba się zastanawiać ani później poprawiać formatowania.

Mniej przyjemne strony

Pisząć w Elmie natknęliśmy się również na parę trudności. By być uczciwym opiszę je pokrótce. Nie wpłynęły one specjalnie na całokształt projektu ale gdyby ich nie było to oczywiście zakończyłby się on szybciej:

  1. Brak wsparcia dla wysyłania plików - jest to znany problemy i programiści obchodzą go na różne sposoby. Elm potrafi przesyłać dowolne dane oprócz właśnie danych binarnych. Niektórzy obchodzą to przez kodowanie danych w base64 ale wymaga to również obsługi po stronie backendu. My zamiast tego rozwiązania postanowiliśmy wysyłać formularz w tle jako mulitpart/form-data. Tak czy siak obsługa plików wymaga napisania portu w JavaScript'cie, który się tym zajmie.
  2. Widgety/komponenty - najgorętszy temat na wszystkich forach i grupach dyskusyjnych dot. Elma. Nie ma jednej metody na ich definiowanie. Ba, nawet nie jest zalecane by wszystkie widgety tworzyć "na jedno kopyto". To nie jest jednak największy problem. Jest nim brak bibliotek z widgetami. Praktycznie każdą bardziej zaawansowaną tabelkę (z sortowaniem czy filtrowaniem) trzeba pisać od zera. Nie jest to oczywiście dużo roboty ale trzeba na nią poświęcić czas.
  3. Czas kompilacji - jak plików źródłowych przybywa czas potrafi się nieco wydłużyć. Szczególnie jak zmienimy plik, od którego zależą wszystkie moduły. Nie jest to jakoś szczególnie długi czas, w naszym przypadku kompilowanie kodu po raz pierwszy trwa ok. 1 minuty. Podobno planowana nowa wersja Elma ma ten proces znacząco przyspieszyć.
  4. Metaprogramowanie - przy coraz większym kodzie bardzo często chcielibyśmy aby pewne rzeczy działy się automatycznie. Dla przykładu, gdy mamy zdefiniowany typ menu, który może być stroną główną, listą faktur lub listą wpłat to bardzo często definiujemy sobie listę wszystkich możliwych kombinacji. Niestety Elm bez możliwości generowania kodu nie zadba o to by przy każdym dodaniu nowego menu funkcja zwracająca listę wszystkich menu się sama aktualizowała. Kompilator również tutaj nie pomoże w żaden sposób (np. nie wyświetli ostrzeżenia).

To wszystkie problemy, o których pamiętam. Zapewne większość z nich zostanie poprawiona w kolejnych wydaniach języka. Nie są to też problemy, które stanową blokadę przed używaniem tej technologii. Myślę, że zalety są na tyle duże, że nie można przejść obok Elma obojętnie. Jeśli w najbliższym czasie planujesz pisać aplikację webową to daj mu szansę.