Takie kuźwa przemyślenie

October 30th, 2014

Po wprowadzeniu chmielowego…

Jeżeli ktoś mówi, że ozusowanie umów zleceń to dokopanie najbiedniejszym to ja się kurwa zastanawiam czemu zlecenie == bieda? Przecież, skoro wszystkim tym jebanym januszom biznesu zależy na tym by społeczeństwo było zamożne, wystarczyło by ludziom dać te pieprzone UoP jako pierwsza opcję do wyboru.
Niestety cebulaki to taka grupa, która zakłada, że jak po roku z warzywniaka nie ma na Audi q7 to chuja a nie interes.
Dlatego biedzie najbiedniejszych (tych co nie wpychają się w tą biedę na własne życzenie chlając, ćpając i pierdoląc świat) najbardziej winny jest bieda biznes cebulowy, który myśli kategoriami ja-moje-najmojsze….

Pewien prosty lifehack I

October 7th, 2014

Dziś nie technicznie, ale hakiersko. W necie możecie znaleźć wiele stron z różnymi lifehack-ami, czyli rozwiązaniami prostych życiowych problemów. Czasami są to porady bardziej ogólne, czasami rozwiązania dla konkretnych wrzodów. Osobną grupą są serwisy DIY (ang. Do It Yourself), poświęcone konstruowaniu różnych poręcznych urządzeń, czy też “rozwiązań” do domu-ogrodu-biura.

Te kurewskie owocówki

Muszki owocówki, to jakaś plaga. Szczególnie teraz gdy owoców jest dużo, przerabiamy je i suszymy. Można z tym walczyć na kilka sposobów. Mój jest bardzo prosty. Bierzemy małą butelkę po wodzie mineralnej. Wrzucamy na dno ze dwa ogryzki i dolewamy trochę soku. Stawiamy w jakimś kącie. Muszki wlezą, ale już nie wylezą. Raz na pewien czas wystarczy butelkę zamknąć (niezbyt szczelnie) i wyrzucić. Jeżeli w okolicy są jakieś muszki poza naszą pułapką (nie wlazły, ale zwabiły się) to polewamy raidem. W jednym koncie jest bezpieczniej niż psikać po całym mieszkaniu.

A i jak byście czuli potrzebę łapania owocówek, to metoda “szybki i wściekły”, czyli klepanie łapami jak popadnie nie działa. Jak chcecie złapać owocówkę to róbcie to powoli. Na szybki ruch reaguje ona instynktownie i bardzo szybko. Na powolny nie reaguje prawie wcale (nie odbiera go jako zagrożenia, a jak się połapie co i jak to już jest za późno).

Guava Event Bus – bo Obserwator z JDK jest naprawdę chujowy

October 5th, 2014

Guava poza całkiem przyjemnym zestawem idiomów funkcyjnych czy zastępników kodu oraz narzędzi wszelakich posiada też pewne przydatne pakiety ;)

Jednym z nich jest pakiet com.google.common.eventbus, który zawiera kompletną szynę zdarzeń. Jest to idealny zastępnik dla implementacji wzorca obserwatora z JDK.

I na początek jeszcze dwa słowa o tym dlaczego porównuję event busa do obserwatora. Ponieważ event bus jest specyficzną formą implementacji tego wzorca. Przy czym obserwowany obiekt nic nie wie o rzeczywistych obserwatorach. Jedyne co robi to wysyła informację do punktu dostępowego, że zaistniała jakaś godna uwago zmiana. Obserwatorzy muszą tylko wiedzieć z jakiego typu komunikatem będą mieli do czynienia.

Dlaczego Obserwator jest chujowy

Nie chodzi o sam wzorzec, ale o to jak został zaimplementowany w Javie. A został zaimplementowany bardzo źle. Problem leży w klasie Observable, która jest klasą. Zatem jeżeli chcesz użyć wzorca obserwatora to musisz ją rozszerzyć, a to zamyka w praktyce hierarchię dziedziczenia. W sumie inaczej tego nie dało się zrobić, bo model dziedziczenia w Javie jaki jest taki jest i lepszy nie będzie.
Co prawda można było to rozwiązać w trochę inny sposób np. za pomocą interfejsu, domyślnej implementacji i zalecenia implementacji przez delegację, lecz nikt na to nie wpadł. Szkoda, bo jest to kolejny mały kamyczek, który uwiera gdy przywdziejesz buty programisty Java.

Pierwsze kroki

Najprostszy program demonstrujący działanie Guava Event Bus będzie wyglądał mniej więcej tak:

Listing 1. Prosty program

public class App {

	public static void main(String[] args) {
		EventBus eb = new EventBus();
		eb.register(new StringEventHandler());
		eb.register(new IntegerEventHandler());
		eb.post(new StringEvent("Hello World!"));
		eb.post(new IntegerEvent(42));

	}
}

Co tu się dzieje? Sercem systemu jest klasa EventBus. Ona reprezentuje szynę. Można jej nadać identyfikator. Można utworzyć wiele instancji tej klasy i mieć wiele szyn. Można w końcu użyć AsyncEventBus, gdzie w konstruktorze przekazujemy Executor i otrzymujemy system współbieżny.
Kolejne dwie linie to rejestracja obiektów nasłuchujących. Jak to wygląda w bebechu to powiem za chwilę. Generalnie obiektem nasłuchującym może być każdy obiekt. Ostatnie dwie linie to wysyłanie zdarzeń. Tu podobnie jak w przypadku obiektów nasłuchujących można wysłać dowolny obiekt.

Widać tu pewną wadę tego rozwiązania. Otóż brak silnego powiązania pomiędzy kodem naszych obiektów nasłuchujących, a Guavą powoduje, że trzeba ręcznie rejestrować te obiekty w ramach szyny. Z drugiej strony zawsze pozostaje AOP na konstruktorze ;)

Obiekty nasłuchujące aka obserwatorzy

Obiekt nasłuchujący będzie powiadamiany o zdarzeniu przez szynę (tę w której go zarejestrowaliśmy). Co powoduje, że szyna rozróżnia kto ma dostać jakie powiadomienie i jak ma być ono obsłużone (którą metodę należy wywołać). Przyjrzyjmy się jednemu z naszych obserwatorów.

Listing 2. Obiekt nasłuchujący

class StringEventHandler {

	@Subscribe
	public void handleEvent(StringEvent stringEvent) {
		System.out.println(stringEvent.get());
	}

}

Cała “magia” rozwiązania leży sobie w adnotacji @Subscribe. W momencie rejestracji obiektu w szynie ta wyszukuje wszystkie metody oznaczone ta adnotacją. Metody muszą być publiczne i mieć tylko jeden argument. Jeżeli nie będzie spełniony pierwszy warunek, to metoda zostanie pominięta (pod spodem jest wywołanie getMethods, które zwróci metody publiczne). Jeżeli metoda będzie miała więcej argumentów albo nie będzie miała ich wcale to dostaniemy IllegalArgumentException. Na podstawie typu argumentu szyna będzie decydowała czy dane zdarzenie jest przeznaczone dla tego obserwatora.

Obiekty zdarzeń

Jak napisałem wcześniej zdarzenia mogą być dowolnego typu, a zatem nie będę dokładnie omawiał ich konstrukcji. Warto jednak omówić jakie cechy powinna mieć dobra klasa reprezentująca zdarzenie.
Po pierwsze, i oczywiste, powinna być niezmienna. Klasy niezmienne mają tą przyjemną własność, że możemy przyjąć iż nikt nam nic w niej nie namieszał.
Po drugie na zdarzenia nie nadają się obiekty reprezentujące typy prymitywne czy String. Choć obiekty te są niezmienne to jednak bezpośrednia wymiana zdarzeń za ich pomocą będzie trudna. Musimy wtedy dopisywać jakieś parsery, matchery diabli wiedzą co, żeby mieć pewność to co otrzymaliśmy rzeczywiście potrafimy obsłużyć.
Po trzecie w większych systemach warto “zainwestować” i wyposażyć nasze obiekty w UUID. Szczególnie jeżeli stosujemy “przepychanie” zdarzeń po między różnymi szynami.

Hierarchia i typy generyczne, a zdarzenia

Poza wspomnianymi już wcześniej dobrymi praktykami związanymi z tworzeniem zdarzeń należy jeszcze przyjrzeć się jak dziedziczenie wpływa na obsługę zdarzeń. Guava dość dobrze radzi sobie z klasycznym modelem dziedziczenia opartym o rozszerzanie klas. Dobrze widać to w poniższym programie (typy wiadomości dobrane tylko po to by nie komplikować)

Listing 3. Hierarchia klas zdarzeń

public class HierarchyApp {

	public static void main(String[] args) {
		EventBus eb = new EventBus();
		eb.register(new IntHandler());
		eb.register(new NumberHandler());
		eb.post(1);
		eb.post(2L);
	}
}

class IntHandler{

	@Subscribe
	public void forInt(Integer i){
		System.out.println("Integer " + i);
	}

}
class NumberHandler{

	@Subscribe
	public void forInt(Number i){
		System.out.println("Number " + i);
	}

}

W przypadku pierwszej wiadomości, która jest typu Integer, który rozszerza Number w efekcie oba handlery otrzymają tą wiadomość. Druga wiadomość jest typu Long zatem otrzyma go tylko handler obsługujący nad typ.

Drugim modelem dziedziczenia jest generyczność. Z tym Guava całkowicie sobie nie radzi. Jeżeli w naszym pierwszym przykładzie zamienilibyśmy obsługę StringEvent i IntegerEvent tak by zamiast tych klas przyjmowały generyczny Event<T&gy; to oba obiekty nasłuchujące otrzymały by oba komunikaty. Efekt… kboom!

DeadEvent

Ostatnim podstawowym elementem do omówienia jaki nam został jest sposób obsługi wiadomości nieobsłużonych. Najprostszym przypadkiem takiej wiadomości jest przypadek gdy wysłaliśmy wiadomość, ale nie ma obserwatora, który może ja obsłużyć. W takim przypadku wiadomość zostaje opakowana w klasę DeadEvent i wysłana do klasy, która potrafi ją obsłużyć (sami musimy ją napisać i zarejestrować w szynie).

Podsumowanie

Guava Event Bus to świetne rozwiązanie pozwalające na wyrugowanie z naszego kodu silnej zależności od obserwatora z podstawowego API. Zaletą jest też stosunkowa prostota wdrożenia tego rozwiązania oraz całkiem rozsądna wydajność.
Wadą brak obsługi typów generycznych.

Jak spodobał Ci się ten wpis to użyj guzików poniżej by podzielić się nim ze swoimi znajomymi.

Złe pomysły to czasami jedyne pomysły

October 2nd, 2014

Guava w swojej funkcyjnej odsłonie jest opłacalna jedynie tam gdzie nie mamy do dyspozycji Javy 8. W tym starciu Guava jest bezbronna ponieważ ma uboższe API i nie ma w nim wielu podstawowych elementów np. konsumentów. Co prawda można ich dopisać, ale to zawsze jest jakiś hak.

Innym, nowym, elementem wprowadzonym w Javie 8, który powoduje, że konstrukcje Guavowe wydają się koślawe jest Method Ref, czyli jedna z form wyrażeń lambda. bez tej konstrukcji jesteśmy skazani na tworzenie klas potworków tylko po to by móc użyć ich w ramach FluentIterable

Na przykładzie

Mamy listę osób należy wypisać imiona kobiet. W Javie 8 napisałbym to tak:

Listing 1. Rozwiązanie z J8

public class BadThingsApp {

	public static void main(String[] args) {
		ArrayList<Person> persons = newArrayList(
				new Person("Ala"),
				new Person("Ania"),
				new Person("Zenon"),
				new Person("Gustawa"));
		persons.stream()
				.map(Person::name)
				.filter(n -> n.lastIndexOf('a') == n.length() - 1)
				.forEach(System.out::println);
	}
}

Wywołanie map w bardzo przyjemny sposób wybiera nam imiona z klasy Person. Podobnie użycie Method Ref do wypisania imion. Teraz to samo w Guavie BEZ użycia konstrukcji z J8.

Listing 2. Rozwiązanie z Guavą

public class BadThingsApp {

	public static void main(String[] args) {
		ArrayList<Person> persons = newArrayList(
				new Person("Ala"),
				new Person("Ania"),
				new Person("Zenon"),
				new Person("Gustawa"));
		FluentIterable.from(persons)
				.transform(new Function<Person, String>() {
					@Override
					public String apply(Person input) {
						return input.name();
					}
				})
				.filter(new Predicate<String>() {
					@Override
					public boolean apply(String input) {
						return input.lastIndexOf('a') == input.length() - 1;
					}
				})
				.transform(new Function<String, String>() {
					@Override
					public String apply(String input) {
						System.out.println(input);
						return input;
					}
				}).size();
	}
}

Mamy tu trzy dodatkowe klasy anonimowe. Nawet po wyrzuceniu ich do jakiś metod statycznych w ramach klasy Person (pierwsza) i ogólnego konsumenta albo loggera (trzecia) nie będzie to wyglądać zbyt przyjaźnie. W dodatku powiążemy klasę modelu z Guavą. Predykat też jest taki jakiś koślawy… Niestety takie życie.

Podsumowanie

Wcześniejsze wersje języka java posiadały dużo ograniczeń. Guava starała się temu zaradzić, ale była to tylko proteza. Dlaczego o tym dziś napisałem? Ponieważ w fabryce zarzucono mi iż nadużywam funkcyjnych idiomów z Guavy co powoduje, że powstaje wiele klas.
Cóż mogę powiedzieć. Komuś przeszkadza kilka klas, a jednocześnie nie przeszkadzają może nie ośmiotysięczniki, ale solidne klasy tatrzańskie (takie po 1800-2500 linii). Ech…

Jeżeli spodobał ci się wpis podziel się nim z innymi za pomocą przycisków poniżej :)

Modyfikacje w layoucie – czekam na opinie

October 1st, 2014

Kilka drobnych zmian w wyglądzie bloga. Inna czcionka, większy rozmiar, trochę zmodyfikowane listingi. Generalnie nie jest to jeszcze coś co podbije wasze serca, ale…

Po pierwsze czekam na opinie czy zmiany idą w dobrym kierunku. Ponieważ nie chciałbym robić całkowitej rewolucji z wyglądem, a pewne zmiany związane ze wzrostem usability bloga są jednak konieczne to się zapytuję czy to dobry kierunek.

Po drugie co byście powiedzieli na wprowadzenie trochę innego sposobu wyświetlania postów na głównej. To znaczy chciałbym by na głównej pojawiały się tylko “lead” tekstu, a po kliknięciu “czytaj dalej” przechodzilibyście już na pełną wersję.

:)

Funkcje w Guavie i dekoratory

September 30th, 2014

Najprostszy do zaimplementowania wzorzec obiektowy, poza singletonem, w programowaniu z użyciem Function i Guavy, czyli dekorator. Dlaczego najprostszy? Ponieważ jest to podstawa działania funkcji wyższego rzędu (ang. High Order Function), które znowuż są podstawą tworzenia trochę bardziej zaawansowanych zabawek.

Motywacja

klasycznym przykładem dekoratora jest budowanie GUI gdzie kolejne elementy staramy się “udekorować” pewnymi dodatkami. W moim przypadku dekorator rozwiązał trochę inny problem, ale podobnej klasy. Okazało się, że potrzebujemy logować wejście, wyjście i czas wykonania funkcji. Banał. Można napisać kod loggera bezpośrednio w funkcji i olać, co IMO, nie jest rozsądne. Z kilku powodów, ale dwa najważniejsze to wiązanie kodu funkcji z logowaniem, co jest wtłaczaniem pewnej dodatkowej odpowiedzialności oraz silne wiązanie pomiędzy funkcją, a logiem.
Powiedzmy sobie szczerze, im prostsza funkcja tym lepiej. Proste funkcje w Guavie można składać za pomocą predykatów i kompozycji w bardziej rozbudowane przepływy. Jeżeli wszyjemy na sztywno jakieś dodatkowe elementy do funkcji – grób mogiła. Nie ma szans na wygrzebanie się z tego gówna. To wynika z pierwszego powodu. Jedna funkcja – jedna odpowiedzialność. Drugi powód ma źródło w pierwszym Jeżeli naszą funkcję w jakiś sposób powiążemy z logowaniem to nie pozbędziemy się tego wrzodu na dupie bez grzebania w kodzie samej funkcji.
Sytuacja idealna – tworzymy sobie projekcik w którym są same funkcje podstawowe, plus kilka funkcji wyższego rzędu, które będą intensywnie używane bądź reprezentują pewne wiadome elementy systemu. Klient dowolnie składa te nasze funkcje tworząc odpowiednie przepływy biznesowe. O tym jak prosta powinna być funkcja innym razem.
Jeżeli zatem klient chce mieć w jednym przepływie logowanie danej operacji, a w innym nie to nasz kod powinien być tak przygotowany, by dodanie logowania było deklaratywne.

Prosta implementacja, czyli tu nie ma rocket science

Oczywiście nasza implementacja powinna opierać się na funkcjach tak by nie zaburzać konstruowania przepływów. Ponad to nie powinna ona zmieniać interfejsu funkcji dekorowanej. Inaczej mówiąc potrzebujemy czegoś co przyjmie nam naszą oryginalną funkcję jako argument zrobi swoje “czary mary” i przy okazji odpali tą oryginalną funkcję bez modyfikowania wejścia, po czym zwróci jej niezmodyfikowany wynik.

Listing 1. To nie jest rocket science

public class DecoratorLogger<I, O> implements Function<I, O> {

	private final Function<I, O> originalFunction;
	private final Logger logger;
	private Level level;

	public static <I, O> Function<I, O> info(Function<I, O> originalFunction){
		return new DecoratorLogger<>(originalFunction, Level.INFO);
	}

	public static <I, O> Function<I, O> warning(Function<I, O> originalFunction){
		return new DecoratorLogger<>(originalFunction, Level.WARNING);
	}

	public static <I, O> Function<I, O> serve(Function<I, O> originalFunction){
		return new DecoratorLogger<>(originalFunction, Level.SEVERE);
	}

	private DecoratorLogger(Function<I, O> originalFunction, Level level) {
		this.originalFunction = originalFunction;
		this.level = level;
		this.logger = Logger.getLogger(originalFunction.getClass().getCanonicalName());
	}


	@Override
	public O apply(I input) {
		Stopwatch watch = Stopwatch.createStarted();
		O output = originalFunction.apply(input);
		Stopwatch stop = watch.stop();
		logger.log(level, "", new Object[]{input, output, "" + stop.elapsed(TimeUnit.MILLISECONDS)});
		return output;
	}
}

Implementacja naiwna jest naiwna i ja o tym wiem. W tym konkretnym przypadku jest ona silnie powiązana z konkretnym zadaniem. W dodatku używam loggera z JDK, co oznacza, że mam dostępne poziomy. W przypadku użycia slf4j nie mam metody w rodzaju log przyjmującej poziom logowania. Nie jest to też zbyt uniwersalne rozwiązanie. Spróbujmy zatem czegoś innego.

Abstrakcyjny dekorator

Co robi nasz dekorator w tym przypadku? Robi COŚ przed wywołaniem funkcji, wywołuje funkcję, po czym robi COŚ po jej wywołaniu i następnie zwraca wynik. Wygląda to jak metoda szablonowa…

Listing 2. Dekorator abstrakcyjny

public abstract class AbstractDecorator<I, O> implements Function<I, O> {

	protected final Function<I, O> originalFunction;

	protected AbstractDecorator(Function<I, O> originalFunction) {
		checkNotNull(originalFunction);
		this.originalFunction = originalFunction;
	}

	protected abstract void before(I input);

	protected abstract void after(I input, O output);

	@Override
	public O apply(I input) {
		before(input);
		O output = originalFunction.apply(input);
		after(input, output);
		return output;
	}
}

Pozostało w sumie zrobić tylko kilka małych prac w naszym oryginalnym kodzie, ale to ćwiczenie dla ciebie. Pierwsza refaktoryzacja będzie oczywiście banalnie prosta, ale jak już ją zrobisz to zastanów się jak zachowa się kod w środowisku wielowątkowym.

Podsumowanie

Programowanie funkcyjne z użyciem Guavy choć jest bardzo mocno ograniczone w porównaniu do na przykład Scali to jednak daje nam możliwość wprowadzenie konstrukcji, których użycie będzie łatwe, proste i w miarę przyjemne. Możliwość użycia dekoratorów, które są najprostszymi funkcjami wyższego rzędu daje znowuż odpowiednie rozwiązania pozwalające na szybkie obudowywanie istniejącego kodu w pewne dodatkowe rozwiązania bez konieczności ingerowania w główny element. To już jest bardzo dobre :)

Jeżeli spodobał ci się wpis podziel się nim ze znajomymi korzystając z przycisków poniżej. Możesz też wysłać link do niego mailem lub przez komunikator.

Warsjawa 2014, czyli Koziołek strikes back

September 28th, 2014

W tym roku po raz pierwszy od dawien dawna wybrałem się na Warsjawę. I to w podwójnej roli jako uczestnik i jako prelegent/prowadzący warsztat.

Mój warsztat

Zacznę od mojego warsztatu. No nie wyszło… poszło do dupy :) Brak wprawy ale jak Venkat stwierdził

First three times sucks

Wnioski zostaną wyciągnięte i przeanalizowane. Poprawki wprowadzone, a za rok powinno być już zdecydowanie lepiej.

A teraz jako uczestnik

Piąteczek czyli dwie sesje.

Akka basics: remoting and clustering

Bardzo dobre warsztaty. Chłopaki (Piotr Kukiełka i Krzysztof Romanowski) przygotowali je bardzo dobrze i świetnie poprowadzili. Co prawda nagrody głównej nie wygrałem, ale nie żałuję, bo zabawa była przednia. Duża dawka wiedzy na początek i dużo radości jak udało się i całość “zaskoczyła”.
Co było na minus? IMO, chłopaki trochę nie docenili naszego talentu do psucia aplikacji. Postawili na szybko serwer, który miał zbierać informacje i nas oceniać, ale problemy sieciowe trochę zabiły fun.

Google App Engine – from 0 to working web application (with Eclipse)

Warsztaty Maćka Arkita zapowiadały się ciekawie, ale moim zdaniem dość efektownie “wybuchły”. Sam zresztą popełniłem dużo podobnych błędów (za dużo, za szybko i generalnie przeładowane), ale z oryginalnych elementów to trochę dystrybucja softu – jednak repo na githubie było by dobrym pomysłem.
Z rzeczy na plus to sposób przedstawienia materiału. Trochę metodyki żółtej kaczuszki, ale skutecznie. Świetna warsztato-prezentacja.

Sobota, czyli jedna sesja techniczna, jedna miękka i później moje warsztaty.

Electronics Fundamentals for Dummies (Arduino included)

Jacek Kunicki przyniósł Arduino i płytki prototypowe. Zatem nie było lutownicy. Za to był “olśnienie”, że warsztaty są całodzienne… auć… Co mi się spodobało to wstęp teoretyczny poświęcony podstawom działania prostej elektroniki. Prawo Ohma, budowa diody P-N, tranzystora NPN, generalnie lepiej niż na studiach tyle, że trochę bardziej “for dummies”. Później złożyłem sobie migadełko z użycie arduino i urwałem się na obiad. W popołudniowej sesji nie brałem udziału.
Co mi osobiście bardzo się spodobało to możliwość przełamania się jeśli chodzi o elektronikę. Jak siadasz do prądu to zazwyczaj jest taki trochę strach, że zaraz układ odwali Habemus Papam i zjarasz kasę. Tu było na spokojnie. Bez stresu… Super wyszło.
Za bolało, że warsztaty były całodniowe. Niestety braki organizacyjno-informacyjne wyszły :( Ale kod mam, listę części mam. Dokonam zakupów i będę się bawił :)

The Art of Giving Technical Presentations

Venkat… ok chyba tyle starczy. Prezentacja, a nie warsztaty. Było super.

Sama Warsjawa

Fajnie było, bo konferencja była świetnie zorganizowana. Ekipa zadbała o wszystko. Począwszy od dostępu do sieci, poprzez wodę, chillout room, a kończąc na zdawać by się mogło dupereli jaką był kindergarden.

Są jednak dwie rzeczy, które mnie trochę zaskoczyły i jedna, która była do dupy. Do dupy była organizacja afterparty po drugim dniu. Trzy knajpy, oddalone od siebie, gdzie trzeba przejść przez niezbyt dobrze zagospodarowane Pola Mokotowskie… mówię nie. Sorry, ale to nie było dobre. Nie służyło integracji uczestników. Pomysł sam w sobie OK. realizacja nie to miejsce i nie ten czas. Coś takiego można by zrobić np. we Wrocławiu, gdzie jest silne zagęszczenie klubów. Względnie jak jest nas mała, zwarta grupa przemieszczająca się w zorganizowany sposób (patrz angolskie wieczory kawalerskie).

Dwie rzeczy, które mnie trochę zaskoczyły to przede wszystkim lekki rozjazd pomiędzy wymaganiami co to języka prezentacji, a rzeczywistością. Odwrotne podejście polski jako baza i angielski opcja było by lepsze. No ale to nie bolało. Choć nastawiałem się na trzy godzinną pogadankę w ponglishu.
Druga rzecz to mocno randomowa rejestracja i drobne lekki bałagan z salami pierwszego dnia. Brakowało mi takiego jakiegoś spójnego sposobu informowania o tym gdzie co się dzieje. Szczególnie, że numeracja sal na MiMUW-ie jest hm… specyficzna…

Podsumowanie całości

Super było. Naprawdę fajna impreza, gdzie mogłem spotkać świetnych ludzi i nauczyć się wielu nowych rzeczy. Zarówno od strony technicznej (Akka, Arduino) jak i “miękkiej” (mój warsztat to było pasmo porażek). Dziękuję wszystkim za super zabawę i do zobaczenia za rok.

Jeżeli podobał ci się ten wpis podziel się nim ze znajomymi korzystając z przycisków poniżej.

Strażnicy, czyli coś czego mi brakuje w Javie

September 23rd, 2014

W sumie brakuje mi dobrej implementacji tego rozwiązania, bo można taką funkcjonalność mieć z wykorzystaniem np. AspectJ czy Type Annotations. Jednak o co chodzi?

Guardians of Erlang

Erlang posiada bardzo fajną konstrukcję zwaną strażnikami (guardians). Cóż to jest? Otóż mając jakąś funkcję możemy walidować argumenty w deklaratywny sposób. Nie wywołujemy żadnego wywołania czy też nie odwołujemy się do żadnej dodatkowej biblioteki. Całość opiera się na konstrukcjach języka.
Przykładowo funkcja attack_mod przyjmuje argument w postaci krotki, której drugi element musi być większy bądź równy 0. W Javie taki kod wyglądał by następująco:

Listing 1. Metoda attackMod

public int attackMod(UnitType type, int numberOf){
    checkArgument(numberOf>=0, "Number of unit must be >= 0");
    //...
}

Kod ten wykorzystuje klasę Preconditions z Guavy. Inną metodą w javie jest napisanie aspektu i użycie adnotacji @Min

Listing 2. Metoda attackMod z adnotacją

public int attackMod(UnitType type, @Min(0) int numberOf){
    //...
}

Ten kod już dużo bardziej przypomina to co chcemy osiągnąć. Jest deklaratywny i stworzony w oparciu o meta dane. Problemem będzie uruchomienie go. Mianowicie trzeba napisać sobie aspekt w rodzaju @Around(“execution(public * * (.., @Min (*), ..))”) oraz wpiąć go w trakcie uruchamiania.
Strasznie to upierdliwe, a w dodatku nie tak mocarne jak rozwiązanie w Erlangu. Tu implementacja będzie wyglądać następująco:

Listing 3. Funkcja attack_mod

attack_mod({Unit_name, Number_of}) when Number_of >=0 ->
  %%% ...
.

Strażnikiem nazywamy ciąg pomiędzy słowem when, a strzałką. Dlaczego rozwiązanie to jest znacznie fajniejsze niż te dostępne w Javie.

Strażnicy i dopasowania

Chyba najciekawszą cechą strażników jest możliwość ich wykorzystania w dopasowaniach (pattern matching). Wyobraźmy sobie, że o ile warunek nie mniejszy niż 0 będzie ok, dla wszystkich rodzajów UnitType, to już w zależności od rodzaju jednostki i liczebności inaczej będzie wyliczany modyfikator. Przykładowo niech orkowie jak będzie ich co najmniej 20 mają wyższy modyfikator (cecha “w kupie siła”), ale jednocześnie istnieje 10% szansy na to, że pokłócą się i modyfikator będzie wynosił 0 (cecha “Moja racja jest najmojsza”).
Wprowadzamy tu zatem dwa nowe elementy. Pierwszym jest dodatkowy zakres wartości, a drugim zmiana algorytmu w zależności od tego w którym zakresie wylądowaliśmy. Wyobraźmy sobie jak ten kod mógłby wyglądać w Javie. W najprostszym niezbyt obiektowym wykonaniu wyglądało by to mniej więcej tak:

Listing 4. Metoda attackMod po modyfikacjach

public int attackMod(UnitType type, int numberOf) {
	checkArgument(numberOf >= 0);
	switch (type) {
		case Marine:
			return 2 * numberOf;
			break;
		case Ork:
			if (numberOf >= 20) {
				return (int) (1.5 * numberOf * quarrel());
			}
			return (int) (1.3 * numberOf);
		break;
		case Human:
			return 1 * numberOf;
			break;
	}
}

Metoda quarrel zwraca 0 albo 1 w zależności od warunku losowego. Strasznie to syfne. W wersji bardziej obiektowej i bardziej javowej switch zastąpiony by został mapą, w której kluczami były by wartości enuma, a wartościami fabryki (wzorzec ProblemFactory) zwracające odpowiedni algorytm (strategię) w zależności od parametru numberOf. Z lekka masakra. Osobiście nie mam nic przeciwko tworzeniu dużej ilości wyspecjalizowanych klas. Java to język taki, a nie inny i ma swoje “odchyły”, a jednym z nich jest konieczność tworzenia specjalizowanego kodu by uzyskać dużą elastyczność. Popatrzmy jak problem można rozwiązać w Erlangu.

Listing 5. Funkcja attack_mod

-export([attack_mod/1]).

attack_mod({Unit_name, Number_of}) when Number_of >=0 ->
  attack_mod(Unit_name, Number_of).

attack_mod(marine, Number_of) ->
  2 * Number_of;

attack_mod(ork, Number_of) when Number_of < 20 ->
  1.3 * Number_of;

attack_mod(ork, Number_of) when Number_of >= 20 ->
  1.5 * Number_of * quarrel();

attack_mod(human, Number_of) ->
  1 * Number_of.

quarrel() ->
  Chns = random:uniform(10),
  if Chns == 1 -> 0;
    Chns > 1 -> 1
  end.

Chyba wygląda to trochę lepiej? W tym przypadku VM-ka erlanga sama dopasuje odpowiednią wersję funkcji do argumentów. Jest to zdecydowanie lepsze rozwiązanie niż to w Javie.

Oddziały strażników

Czyli rzecz o tym jak składać warunki. Jeżeli chcemy nałożyć więcej niż jedno ograniczenie na nasze argumenty możemy połączyć strażników. W takim przypadku przecinek będzie działać jak logiczne AND, a średnik jak logiczne OR.

Więcej niż deklaracja funkcji

Strażników możemy używać nie tylko na poziomie deklaracji funkcji. Znacznie przyjemniej używa się ich na poziomie konstrukcji case, która jest podobna do tej ze Scali i służy do obsługi dopasowań. W takim wypadku powyższy kod można przerobić na coś takiego:

Listing 6. Funkcja attack_mod z wykorzystaniem case

-export([attack_mod/2]).

attack_mod(Unit_name, Number_of) when Number_of >= 0 ->
  Mod = case Unit_name of
          marine -> 2;
          ork when Number_of < 20 -> 1.3;
          ork when Number_of >= 20 ->
            1.5 * Number_of * quarrel();
          human -> 1
  end,
  Mod * Number_of.

quarrel() ->
  Chns = random:uniform(10),
  if Chns == 1 -> 0;
    Chns > 1 -> 1
  end.

Całkiem ładne rozwiązanie. W dodatku bardziej zwięzłe niż to w Javie.

Podsumowanie

W Javie brakuje niestety takiego fajnego mechanizmu. Dodatkowym atutem Erlanga jest możliwość użycia atomów, które dodatkowo wprowadzają dodatkowe możliwości w przypadku dopasowań. Pozostając jednak przy deklaratywnym weryfikowaniu parametrów warto zapoznać się z możliwościami Javy w tym zakresie, bo choć użycie aspektów jest upierdliwe, to jest to całkiem efektywny sposób na pozbycie się nadmiarowego kodu.

Jeżeli podobał ci się ten wpis podziel się nim ze znajomymi korzystając z przycisków poniżej.

Suplement do Suppliera

September 18th, 2014

Na ostatnim spotkaniu wrocławskiego JUGa padło pytanie co do Suppliera z poprzedniego wpisu dotyczące tego jak należy zamykać BufferedReader. Trochę się niestety zamotałem i nie byłem wstanie udzielić dobrej odpowiedzi na to pytanie, ale po spokojnym przemyśleniu sprawy rzecz jest bardziej niż prosta.

Błogosławione niech będą rzeczy nowe w Javie 7

Dokładnie zaś konstrukcja try-with-resource, czyli możliwość trochę lepszego zapisu syfu związanego z zamykaniem zasobów. Efektywnie oznacza to, że wystarczy by nasz Supplier implementował interfejs Closeable:

Listing 1. Samo zamykający się Supplier

public class FileReaderViaSupplier implements Supplier<Optional<String>>, Closeable {

	private BufferedReader reader;

	public FileReaderViaSupplier(String filePath) {
		this(new File(checkNotNull(filePath)), UTF_8);
	}

	public FileReaderViaSupplier(File file, Charset charset) {
		checkNotNull(file);
		checkNotNull(charset);
		checkArgument(file.exists(), "File %s does not exist", file.getAbsolutePath());
		try {
			reader = Files.asCharSource(file, charset).openBufferedStream();
		} catch (IOException e) {
			checkState(false, e.getMessage());
		}
	}

	@Override
	public Optional<String> get() {
		try {
			String reference = reader.readLine();
			return Optional.fromNullable(reference);
		} catch (IOException e) {
			return Optional.absent();
		}
	}

	@Override
	public void close() throws IOException {
		reader.close();
	}
}

I to tyle.

Tradycyjnie już na koniec mała prośba jeżeli spodobał ci się ten wpis udostępnij go w mediach społecznościowych korzystając z przycisków poniżej. Jak masz pytania zadaj je w komentarzu. Postaram się zaspokoić twoją ciekawość.

Supplier z Guavy jako narzędzie odczytu plików

September 13th, 2014

Interfejs Supplier opisałem już pewien czas temu. Dziś chciałbym przedstawić pewne specyficzne zastosowanie tego interfejsu. Mianowicie stworzymy klasę, która będzie w oparciu o ten interfejs odczytywać pliki.

Prawie leniwe czytanie plików

Generalnie w Javie da się czytać pliki w sposób leniwy. Bierzemy sobie BufferedReader i wpinamy go w jakiś listener. Następnie uderzamy zdarzeniem “następna linia” i pobieramy linię. I tak aż się plik skończy.
W przypadku Supplier-a mechanika działania jest bardzo zbliżona. Z jedną małą różnicą. Musimy czytać “do przodu” jeżeli chcemy by odczyt był następnie wykorzystywany w ramach iteratorów. Te ostatnie zapewnią nam spójny interfejs z Guavą.
Co więcej o ile w przypadku “zwykłego” czytania plików możemy sobie zaryzykować zwrócenie wartości null lub wymuszenie obsługi weryfikowalnego wyjątku to gdy idziemy w kierunku idiomów funkcyjnych dobrze by było zamknąć jakoś te problemy.

Catched Exceptions i Guava

Dziś na skróty. Generalnie jedną z cech programowania funkcyjnego jest brak efektów ubocznych. Jednym z takich efektów jest rzucenie wyjątku. Wszystko ładnie pięknie, ale uruchommy sobie interpreter Erlanga (który językiem funkcyjnym jest) i napiszmy coś takiego:

Listing 1. “Brak efektów ubocznych”

Liczba = 1.
Wynik = Liczba / 0.

Oczywiście dostaniemy wyjątek. Jako, że Erlang hołduje idei “Let it crash” to jeżeli doprowadzilibyśmy do takiej sytuacji w programie to maszyna wirtualna by ubiła nam proces, a następnie go wznowiła.
My nie będziemy aż tak mili. Jeżeli coś się wywali to przepchniemy to na chwilę obecną do wyjątku nieweryfikowalnego i wyrzucimy… Let it crash :D

Przy czym należy pamiętać, że Guava udostępnia klasę narzędziową Throwables, która pozwala na opakowywanie i konwertowanie wyjątków. Tu będzie ona średnio przydatna ;)

Czytamy plik linia po linii z użyciem Supplier

Zakładam, że czytamy linia po linii, plik np. csv, a nie plik binarny, gdzie chcemy odczytać blok. Ogólne zasady będą takie same komplikuje się tylko zasady określające ile danych chcemy odczytać.

Zastanówmy się przez chwilę co powinno być efektem przeczytania linii z pliku? Zapewne obiekt typu String. Co jeżeli linia jest pusta? Nasz String powinien być pusty. W przypadku końca pliku będzie oczywiście null. Czy to nam odpowiada? Raczej nie. Szczególnie ten ostatni przypadek. Co prawda można by zamienić do na zwracanie pustego stringa, ale wtedy nie wiemy, że odczytujemy ostatnią linię, a nie np. pustą linię w środku pliku.

Pamiętajmy, że odczyt pliku będzie obudowany w dostawcę, a ten nie dostarcza metod iteratora typu hasNext. Oczywiście można napisać taki iterator (kolejny post będzie o tym). Jednak my skupimy się na samym odczycie.

Jak wybrnąć z tego problemu? Użyć Optional. To było proste. Zasady też są proste. Jeżeli dojdziemy do końca pliku to zwracamy Absent inaczej Present. Do odczytu plików tekstowych linia po linii posłuży nam stary dobry BufferedReader. WIemy zatem jak będzie wyglądał “core” naszej aplikacji

Listing 2. Metoda get naszego readera

public class FileReaderViaSupplier implements Supplier<Optional<String>> {

	private BufferedReader reader;

	@Override
	public Optional<String> get() {
		try {
			String reference = reader.readLine(); // 1
			return Optional.fromNullable(reference).or(Optional.<String>absent()); // 2
		} catch (IOException e) {
			return Optional.absent(); // 3
		}
	}
}

Na początku odczytujemy pojedynczą linię (1), a następnie na jej bazie tworzymy obiekt Optional, który będzie istniał o ile tylko odczytaliśmy coś co nie jest null-em. W przeciwnym wypadku zostanie zwrócony Absent. Absent zostanie zwrócone też w przypadku błędu.

Jak to zainicjować

Mamy co prawda reader, ale nadal nie mamy kodu odpowiedzialnego za jego inicjalizację. Przedstawię tylko jeden konstruktor. Można go potraktować jako ostatni w ścieżce delegacji pomiędzy różnymi wersjami (bo jak zwykle operując na plikach mamy od cholery konstruktorów).

Listing 3. Konstruktor naszego readera

public FileReaderViaSupplier(File file, Charset charset) {
	checkNotNull(file);
	checkNotNull(charset);
	checkArgument(file.exists(), "File %s does not exist", file.getAbsolutePath());
	try {
		reader = Files.asCharSource(file, charset).openBufferedStream();
	} catch (IOException e) {                                                                    
		checkState(false, e.getMessage());
	}
}

W pierwszych trzech liniach sprawdzamy czy w ogóle możemy sobie pozwolić na utworzenie readera. Wykorzystuję tu Preconditions, które opisywałem pewien czas temu. Następnie próbujemy utworzyć BufferedReader. Jeżeli to się nie uda to walimy kolejnym wyjątkiem.

W przeciwieństwie do odczytu gdzie błąd oznaczał tylko zakończenie działania tu przyjąłem trochę inną strategię. Proces odczytu jest leniwy. Zatem możemy zabezpieczyć się przed warunkami zewnętrznymi inaczej niż w przypadku zachłannego procesu tworzenia obiektu. Tu chcemy od razu powiedzieć “nie wiem, nie znam się, zarobiony jestem, przyjdź pan jurto”. Natomiast w przypadku odczytu po prostu mówimy “nic więcej nie mogę odczytać”. Nie ważne jest czy wynika to z problemów z plikiem czy też jest po prostu koniec pliku.

Podsumowanie

Mamy zatem podstawowy element pozwalający na leniwe odczytywanie plików. W dodatku napisaliśmy to w sposób pozwalający na wykorzystanie razem z innymi elementami Guavy.

O tym jak dobrać rozwiązanie do problemu i czy opłaca się pisać rozwiązania uogólnione będę mówił w trakcie warsztatów “Beginning Functional Programming in Java world” na Warsjawie już 26-27 września.

Na koniec mała prośba jeżeli spodobał ci się ten wpis udostępnij go w mediach społecznościowych korzystając z przycisków poniżej. Jak masz pytania zadaj je w komentarzu. Postaram się zaspokoić twoją ciekawość.