System rezerwacji sal – część 0 – co chcę zrobić

January 25th, 2015

Mam pomysł na apkę z serii “do poćwiczenia”. Będzie to system rezerwowania sal w firmie. Jest to przymiarka do trochę innego zadania, które obecnie nazywam “głównym projektem”.

Architektura – zarys

Mamy dwa główne elementy z których chcemy korzystać. Pierwszy to baza (jakaś, nie koniecznie baza danych) użytkowników, którzy pracują sobie w biurach. Drugi to informacja o salach w poszczególnych lokalizacjach. To spinamy w ramach komponentu zwanego “rezerwacje”. UMLa nie będzie, bo nie chce mi się szukać pluginu do rysowania w WP.
Komponenty mają dobrze zdefiniowane interfejsy i generalnie potrafią się “dogadać” za pomocą REST-WS. I to w praktyce jest jedyne ograniczenie projektowe – jak coś robisz to musi to gadać z resztą po restach i w jsonie. Nie ważne jest czy będzie to pod spodem Java, Railsy, Go, Erlang czy pociąg hindusów. Sposób komunikacji jest jasny i precyzyjny.
Oznacza to, że komponenty będą wobec siebie niezależne na poziomie platformy. Zależności biznesowych się nie pozbędziemy.

Architektura – pomysł na implementację

Skoro całość ma być wzajemnie niezależna to rozsądnym wydaje się wykorzystanie mikroserwisów. Spełniają one warunek wzajemnej niezależności oraz pozwalają na wymuszenie określonej formy komunikacji. Żadnych RMI, żadnych SOAP-ów, a jedynie REST. To nawet COBOL potrafi obsłużyć.
Zatem każdy z modułów będzie sobie śmigał jako niezależny serwis. Oczywiście na poziomie biznesowym będą one zależne, ale awaria jednego z serwisów nie powinna wpłynąć na inne. Co najwyżej wyłączy część funkcjonalności (w myśl zasady, że na pochyłe drzewo i salmonella nie naleje).

Przeprowadźmy zatem krótką analizę zależności na poziomie biznesowym oraz wpływu awarii na poszczególne komponenty.

Użytkownicy (i Sale)

Komponent niezależny. Awaria innych komponentów nie ma na niego wpływu. Ma ukrytą zależność na poziomie implementacji w postaci “jakiegoś” elementu zapisującego dane (baza relacyjna, plik, proviler). Awaria tego elementu spowoduje awarię komponentu.

Rezerwacje

Komponent zależy od dwóch powyższych. Awaria jednego z nich spowoduje ograniczenie możliwości komponentu. Tworzenie i zmiana rezerwacji będzie niemożliwe ponieważ nie będzie można odczytać informacji o salach i użytkownikach. Usuwanie rezerwacji będzie możliwe. Odczyt części informacji o rezerwacji będzie niemożliwy (szczegóły użytkownika/sali).
Komponent ma zależność używaną do składowania danych. Awaria w tym miejscu wyłącza komponent z użycia.

Jak zatem widać współpraca komponentów może oznaczać, że wraz z awarią jednego z nich inne będą miały ograniczone możliwości.

Podsumowanie

Ideę znamy można by to zaimplementować…

Chamberconf 2015 okiem organizatora

January 22nd, 2015

No i się porobiło… na początku gdy luźno sobie z Pawłem, Marcinami i Mateuszem gadaliśmy o zrobieniu wypadu gdzieś za miasto by napić się piwa i pokodować nie sądziłem, że przerodzi się to w konferencję.

Nie sądziłem też, że będę jej współwinnym… znaczy się będę jednym z organizatorów.

Jako uczestnik

Z tej perspektywy mogę powiedzieć tylko tyle, że konferencja się udała. Zarówno prezentacje pierwszego dnia, unconference, integracja jak i dzień drugi były na niezłym poziomie. Największy udział mieli w tym prelegenci i trenerzy, bo to oni przede wszystkim “dają poziom”.
Co mnie osobiście irytowało to rozjechanie się drugiego dnia w ścieżkach. Prezentacje już dawno się skończyły, a warsztaty jeszcze trwały. Cóż… bywa, ale nie sądziłem, że będzie to aż na taką skalę.

Jako organizator

Dużo się nauczyłem o pracy w grupie w przypadku “miękkiego” zadania. Chyba niezłym pomysłem było niezapraszanie sponsorów i zrobienie płatnej konferencji. Dzięki temu mieliśmy pełną swobodę co do organizacji. Nie wiem jak was, ale mnie coraz bardziej zaczynają irytować stoiska firm outsourcingowych. Mam jakieś takie wrażenie, że działa tu deal bezpłatna konferencja za duszę. Może to błędne podejście lecz mam wrażenie, że to wszystko podąża w jakimś złym kierunku. To jednak osobny temat.

Podsumowanie

Chciałbym wszystkim uczestnikom podziękować za te dwa dni dobrej zabawy. Do zobaczenia za rok.

Chamberconf 2015 – rejestracja

January 7th, 2015

Na naszym wrocławsko jugowym meetupie ruszyła rejestracja na Chamberconf 2015.

Zapraszam w imieniu organizatorów :)

Czy twój bitewniak jest zrównoważony?

January 7th, 2015

Poza tym, że rzeźbię sobie kod lubię czasami pograć w gry bitewne. Teraz mam już na to bardzo mało czasu, ale kiedyś było tego więcej. Obecnie z hobby pozostało tylko malowanie ludzików, a i to nie za często.
Niemniej jednak nadal staram się śledzić co dzieje się w świecie. Oznacza to też czytanie blogów. Ostatnio trafiłem na wpis na blogu MX Site poświęcony Prawu Kwadratów Lanchestera (PKL). Jest to chyba najprostszy model pola walki jaki istnieje. Oczywiście na poziomie intuicyjnym. Matematyka to inna inszość… co i jak w oryginalnym poście.

Mnie jednak zastanowiło czy można za pomocą tego prawa w jakiś sposób określić zrównoważenie gry bitewnej. Wszystko w dużym uproszczeniu.

Wprowadzenie teoretyczne do gry

By sprawdzić czy gra jest dobrze zrównoważona za pomocą PKL należy tak dobrać walczące strony by miały równą siłę ognia i liczebność…
Rozpatrzmy walkę dwóch oddziałów Space Marines po 10 żołnierzy w każdym. Nazwijmy je siłami Alfa i Beta. Walkę będziemy rozpatrywać na bazie reguł szóstej edycji W40k (nie mam podręcznika do 7).
Mechanika gry jest oparta o tzw. rzuty kaskadowe. Inaczej mówiąc o rezultacie starcia decyduje seria rzutów tu są to:

  • Rzut na trafienie – reprezentuje umiejętności strzelającego.
  • Rzut na zranienie – reprezentuje siłę ognia broni.
  • Rzut na pancerz – reprezentuje poziom ochrony obrońcy.

W tym modelu by rozstrzygnąć starcie atakujący wykonuje dwa rzuty, a obrońca jeden. Przykładowo Alfa strzela 10k6 (10 kości 6-ściennych), trafia 5 (na pięciu kościach uzyskał wynik większy bądź równy oczekiwanemu). Następnie rzuca na zranienie 5k6 i rani 3 (3 kości >= oczekiwany). Obrońca rzuca 3k6 na pancerz i jeden rzut jest nieudany (wyrzucił mniej oczek niż oczekiwana). Jeden model jest zdejmowany z pola bitwy.

Następnie strony zamieniają się rolami.

Innym rodzajem mechaniki jest mechanika oparta o rzuty przeciwstawne. W jej przypadku każda ze stron wykonuje jeden rzut i modyfikuje go cechami modelu. Takie rozwiązanie wymaga wprowadzenia innego niż równomierny rozkładu prawdopodobieństwa dla wyników rzutu.

Chwila analizy

Już na pierwszy rzut oka widać, że gra nie będzie zrównoważona. Strona broniąca się poniesie straty w pierwszej turze rzutów i jak stanie się stroną atakującą to będzie “na dzień dobry” miała mniejszą siłę ognia.
Dlatego PKL jest tu dobrym narzędziem :) Ponieważ pozwala na porównanie czy nasz system turowy zbliża się do “świata rzeczywistego” gdzie oddziały walczą symultanicznie (wszyscy na raz strzelają).

Rezultaty

Kod możecie sobie pobrać z Githuba. Nas interesuje to rezultat końcowy.

Ogólnie przeprowadziłem 1000000 (milion) symulacji walki. Strona Alfa to atakujący, a Beta broniący. Obie strony to 10 osobowe oddziały SM. Walkę prowadzimy do ostatniego żołnierza.

PKL: ALPHA wins 566 658 times
PKL: BETA wins 433 342 times

Co oznacza, że w około 43% przypadków strona broniąca się ma szansę na zwycięstwo. W40k jest nieźle zrównoważonym systemem… no dobra, zmieńmy trochę liczebność oddziałów. Pytanie brzmi co stanie się gdy zwiększymy liczbę obrońców o 2.

Walka 10:12

PKL: ALPHA wins 277 896 times
PKL: BETA wins 722 104 times

Zatem nie opłaca się atakować przeciwnika silniejszego raptem o 20%. Kolejnym testem jest określenie jak wyposażenie wpływa na wynik walki. W tym celu wyposażę jednego z obrońców w ciężki bolter.

PKL: ALPHA wins 558 199 times
PKL: BETA wins 441 801 times

Dużo to nie dało. Jednak zawsze coś. Po dodaniu kolejnego ciężkiego boltera:

PKL: ALPHA wins 536 463 times
PKL: BETA wins 463 537 times

Co już pozwala na kombinowanie. Nie wiem jakie są obecnie limity broni ciężkiej w oddziale, ale jak podejrzewam można tu trochę ugrać. Szczególnie, że model nie uwzględnia modyfikatorów.

Wnioski

Gra okazuje się całkiem nieźle zrównoważona. Co prawda intuicja podpowiada, że strona atakująca powinna mieć znaczą przewagę, ale w praktyce okazuje się, że kaskadowe rzuty niwelują ją do rozsądnych granic. Jeżeli zatem w trakcie gry okazuje się, że wybitnie ci nie idzie… zmień kostki ;)

Nowe wideo o lambdach i testowaniu

December 8th, 2014

Zapraszam do obejrzenia

Powinno już być lepiej z dźwiękiem i obrazem :)

Gdzie Diabeł nie może tam Wrapper pośle

December 1st, 2014

All problems in computer science can be solved by another level of indirection

– David Wheeler

I tego się trzymajmy. Jednak nie byłbym sobą, gdybym nie pokazał zastosowania tej reguły na przykłądzie z życia wziętym.

Problem

Mamy niezmienialną (w sensie – nie możemy zmienić kodu) klasę reprezentującą jakąś informację. W naszym przypadku była to encja reprezentująca naruszenie spójności dla instrumentu finansowego. Otrzymywaliśmy listę tego typu encji, a naszym zadaniem było jej przefiltrowanie pod kątem unikalności wpisów. Wpis był unikalny, czyli encje były równe, jak ich atrybuty były równe. Rzecz w tym, że hashCode i equlas nie były zaimplementowane więc encje zawsze były różne niezależnie od tego co miały w bebechach. Wykluczało to zastosowanie najprostszej metody na redukcję za pomocą Seta.

Listing 1. Redukcja za pomocą Set

public Collection<MyEntity> reduceToUnique(Collection<MyEntity> notUnique){
   return new HashSet<MyEntity>(notUnique);
}

Jak by sobie z tym można było poradzić…

Wprowadzamy Wrapper

Uwaga, kod już jest generyczny. W moim przypadku pierwsza wersja była niegeneryczna i przygotowana pod konkretna encję. Omówię ją w dużym skrócie, ale jest ona przykładem implementacji “starupowej” – byle jak byle działało.

By rozwiązać ten problem wprowadziłem dodatkową warstwę pomiędzy obiektami otrzymywanymi z zewnątrz, a naszą logiką. Jego zadanie polega na dostarczeniu naszej własnej implementacji dla metod hashCode i equlas. W tym miejscu natknąłem się na pewien problem w implementacji, który spowodował, że pierwsze, niegeneryczne, podejście do implementacji choć zakończyło się sukcesem to zdecydowałem się na powtórą implementację całego rozwiązania.

W takim niegenerycznym przypadku tworzymy jedeną klasę wrappera na każdą klasę, którą chcemy obudować. Powoduje to, że pojawia się masa zduplikowanego kodu. Przykładowo dla kasy Person z biblioteki JFairy, która to klasa zachowuje się jak nasza encja, będziemy mieli:

Listing 2. Niegeneryczny Wrapper

class PersonWrapper{
    private final Person person;

    public PersonWrapper(Person person) {
        this.person = person;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof PersonWrapper)) {
            return false;
        }

        PersonWrapper that = (PersonWrapper) o;

        if (person != null ? !person.firstName().equals(that.person.firstName()) : that.person != null) {
            return false;
        }

        return true;
    }

    @Override
    public int hashCode() {
        return person != null ? person.firstName().hashCode() : 0;
    }
}

Dodatkowo jeżeli chcemy zmienić implementację warunków to musimy stworzyć nową klasę. Czyli jest źle. Znaczy się jeżeli chcemy to zrobić punktowo dla jakiejś jednej klasy i zestawu warunków to będzie ok. Jednak jeżeli będziemy tego używać w wielu miejscach to warto zaimplementować to porządnie.

Jak widać w niegenerycznej wersji problemem było sztywne zaszycie w kodzie klasy zarunków równości. By wyciągnąć je na zewnątrz będziemy potrzebować dwóch interfejsów. Po jednym na każdą metodę. Dlaczego dwóch? Ponieważ dzięki temu możemy zaimplementować je później jako lambdy.

Listing 3. Generyczny Wrapper i dodatkowe interfejsy

class Wrapper<T> {

    public final T bean;
    private final Eq<T> eq;
    private final Hc<T> hc;

    Wrapper(T bean, Eq<T> eq, Hc<T> hc) {
        this.bean = bean;
        this.eq = eq;
        this.hc = hc;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof Wrapper)) {
            return false;
        }

        Wrapper wrapper = (Wrapper) o;

        Object right = wrapper.bean;
        if (right != null && right.getClass().isAssignableFrom(bean.getClass()))
            return eq.eq(this.bean, (T) right);

        return false;
    }

    @Override
    public int hashCode() {
        return bean != null ? hc.hashCode(bean) : 0;
    }

}
interface Eq<T> {

    boolean eq(T left, T right);
}

interface Hc<T> {

    int hashCode(T t);
}

Jak łatwo zauważyć zarówno hashCode jak i equals zostały zaimplementowane w ten sposób by po dokonaniu wstępnej weryfikacji obudowanego obiektu oddelegować konkretne wyliczenia do implementacji interfejsów.

Czas na przykłado wykorzystania. W tym celu stworzymy losową listę obiektów Person i wyciągniemy unikalny zestaw. Warunkiem równości będzie płeć (jest to warunek w miarę rozsądny, bo zbiór wartości jest ograniczony, a możliwość wylosowania tylko osób o takiej samej płci przy dużej liczbie losowań jest znikoma).

Listing 4. Program przykładowy

public class WrapperExample {

    public static void main(String[] args) {
        Fairy fairy = Fairy.create(Locale.forLanguageTag("PL"));
        List<Person> persons = IntStream.range(0, 1000)
                .collect(ArrayList::new, (c, i) -> c.add(i), ArrayList::addAll)
                .stream()
                .map(i -> fairy.person())
                .collect(Collectors.toList());
        System.out.println("Raw data " + persons.size());

        Set<Person> personSet = persons.stream().collect(Collectors.toSet());
        System.out.println("Set default " + personSet.size());

        List<Person> personWrappersSex = persons.stream()
                .map(p -> new Wrapper<Person>(p,
                        (left, right) -> (left.isMale() && right.isMale()) || (left.isFemale() && right.isFemale()),
                        g -> g.isMale() ? 1 : 0
        )).collect(Collectors.toSet()).stream()
                .map(w -> w.bean).collect(Collectors.toList());
        System.out.println("Set from wrapper sex " + personWrappersSex.size());
    }

}

Najpierw tworzymy listę tysiąca osób. Następnie próbujemy wrzucić je do Seta i otrzymujemy zbiór o tej samej wielkości. W kolejnym kroku najpierw mapujemy wszystkie obiekty na Wrapper z odpowiednimi warunkami równości. Następnie zbieramy to do Seta, co powoduje wywołanie logiki z interfejsów Eq i Hc po czym znowu mapujemy wyłuskując Person i zbieramy do listy.

Podsumowanie

Jak widać po wprowadzeniu dodatkowej warstwy problem stał się trywialny i ograniczył się do napisania implementacji dla odpowiednich metod.

Nasza oryginalna implementacja jest jeszcze troche inna ponieważ mamy Javę 1.6 i Guavę co powoduje, że kod jest bardziej rozwlekły w wykorzystaniu.

Procrastination short story

November 25th, 2014

For people who wouldn’t like to read long posts.

Why?

1. Because all articles how to beat procrastination are to long for people who would do this.
2. Because I know what I write. Procrastination is my personal daemon everyday for years.

How?

1. Define “The Big Thing” that you want to achieve. It is to big to one bite. For me is to buy this toy.
2. Define milestones and write it on paper. I have my pr0-note. Don’t write it on computer. Paper is real and nad you can touch it. Computer note is abstract. You can’t create “mental link” with that abstract thing.
3. Milestones are to big, still. But they are easier to achieve, easier to manage and less abstract. My milestones e.g.:
– Save first 3K
– Save first 10k
– Save 30K
– Find source of passive income – up to 1k/per month
– Find source of passive income – up to 3k/per month
4. Split each milestone to tasks and ideas. Some of them will be duplicated in milestones
– Tasks – what I can do without any additional planing or need only small research e.g. start charge back program account in my bank, find and start good investment.
– Ideas – need more work or additional planing e.g. find clients form my apps. Technically they are set of depended tasks.
5. Set deadlines for tasks and planing session dates for ideas. Still use paper :)
6. Realise task. One by one. Remember to mark task as done. You could realise task from different milestones. Sometimes you could realise sub-tasks from ideas.

When win

1. Write short summary – what was good and help you. Just 5-6 words.
2. When achieve milestone – get small prize. Remember it should be really small. My favorite is bottle of “craft beer”.

When fail

1. Write short summary – what should be done better. Just 5-6 words. DO NOT TRY TO FIND REASON! Because You will write “I Suck” and demotivate yourself.
2. Define new deadline.
3. If you fail second time in the same task. Re define. It is to big.

Congratulation! You read this post. Now go to next task.

Typy nieprymitywne w tabelach Vaadin

November 22nd, 2014

Powrót do konwerterów, ale tym razem w kontekście tabeli.

Problem

Mamy sobie tabelkę wyświetlającą jakieś tam dane. W jednej z kolumn chcemy wyświetlić informację o polu obiektu, które to pole nie jest prymitywne/boxowane/stringiem (jeżeli jest to vaadinowy komponent GUI to zostanie osadzony w komórce, ale to jest wyjątek). Przykładowo:

Listing 1. definicja tabeli

Table table = new Table("Informacje o oddziałach");
table.addContainerProperty("id", Long.class, null);
table.addContainerProperty("name", String.class, "");
table.addContainerProperty("address", Address.class, null);
table.setColumnHeaders("id", "Nazwa", "Adres");

Jak widać w ostatniej kolumnie chcemy umieścić adres oddziału. Niby nic, ale jeżeli przekażemy obiekt bezpośrednio to zostanie na nim wywołana metoda toString i dostaniemy jakieś syfne dane. Oczywiście można pokusić się o napisanie tej metody tak by zwracała dane sformatowane w jakiś domyślny sposób. Można też użyć konwertera.

Konwerter i tabela

Do każdej kolumny w tabeli można podpiąć konwerter w następujący sposób:

Listing 2. dodawanie konwertera

table.setConverter("address", new AddressConverter());

Sam konwerter jest już prosty do napisania. Wystarczy, że zaimplementujemy interfejs Converter<CEL, ŹRÓDŁO>:

Listing 3. implementacja konwertera

private class AddressConverter implements Converter<String, Address> {
	@Override
	public Address convertToModel(String value, 
		Class<? extends Address> targetType,
		Locale locale) throws ConversionException {
		return addressDao.fromString(value);
	}

	@Override
	public String convertToPresentation(Address value, 
		Class<? extends String> targetType, 
		Locale locale) throws ConversionException {
		return value == null ? "" : value.street()+"/"+value.city();
	}

	@Override
	public Class<Address> getModelType() {
		return Address.class;
	}

	@Override
	public Class<String> getPresentationType() {
		return String.class;
	}
}

I w sumie było by to na tyle… interfejs jest paskudny i trochę dużo zbędnego kodu tu, ale inaczej się nie da…

Ale jak masz Javę 8

Można się pokusić o napisanie tego wszystkiego lambdami, co trochę ułatwi życie i może wprowadzić Sajgon w kodzie jak radośnie nazwiecie zmienne, co też zademonstruję.

Na początek potrzebujemy funkcję przyjmująca trzy argumenty:

Listing 4. funkcja o trzech argumentach

@FunctionalInterface
public interface TriFunction<T, U, V, R> {

	R apply(T t, U u, V v);
}

Następnie potrzebujemy fabrykę, która będzie nam produkować nasze konwertery na podstawie lambd:

Listing 5. fabryka konwerterów

public class ConverterFactory {

	public static <T, S> Converter<T, S> get(
		TriFunction<T, Class<? extends S>, Locale, S> toModel,
	        TriFunction<S, Class<? extends T>, Locale, T> toPresentation,
	        Class<S> modelType, 
		Class<T> presentationType) {
		
		return new Converter<T, S>() {
			@Override
			public S convertToModel(T value, 
			                        Class<? extends S> targetType, 
			                        Locale locale) throws ConversionException {
				return toModel.apply(value, targetType, locale);
			}

			@Override
			public T convertToPresentation(S value, 
			                               Class<? extends T> targetType, 
			                               Locale locale) throws ConversionException {
				return toPresentation.apply(value, targetType, locale);
			}

			@Override
			public Class<S> getModelType() {
				return modelType;
			}

			@Override
			public Class<T> getPresentationType() {
				return presentationType;
			}
		};
	}
}

niezłe prawda? To tutaj to są funkcje wyższego rzędu w praktyce. Bardzo przydatne zastosowanie teorii (w językach bardziej funkcyjnych można to zrobić ładniej).

I teraz nasz konwerter można zapisać tak:

Listing 6. konwerter z lambd

table.setConverter("address", 
	new ConverterFactory().get((a, b, c) -> addressDao.fromString(a),
			(a, b, c) -> a == null ? "" : a.street()+"/"+a.city(),
			Role.class,
			String.class));

Elegancko. No prawie ;) Popatrzcie na nazwy zmiennych w lambdach i zapamiętajcie, że nie należy takich rzeczy robić w kodzie produkcyjnym. Niestety Java nie udostępnia mechanizmu parametru domyślnego jak Scala reprezentowanego znakiem _, czy też parametru ignorowanego jak Erlang (ten sam znaczek). Ja wypracowałem sobie konwencję, że jeżeli jakiś parametr jest nieużywany to nazywam go $ jeżeli mam kilka takich parametrów, to liczba znaków $ rośnie. Jak będzie ich więcej niż dwa to oznacza, że trzeba refaktorować.

Dziękuję za to, ze dotrwałeś do końca. Jeżeli spodobał ci się ten wpis to podziel się nim ze znajomymi korzystając z przycisków poniżej. Do tego one służą.

VLOG 1. Leniwa ewaluacja

November 20th, 2014

Robię mały eksperyment.

Jak się podoba? Jest zapewne dużo rzeczy do poprawienia i ulepszenia, ale na początek chyba nie jest źle?

Szybkie tworzenie list z pomocą edytorów w Vaadin

November 18th, 2014

Kolejny wpis z serii jak to zrobić w Vaadin by nie bolało.

Załóżmy, że chcemy sobie spiąć pole naszego bean-a z ComboBox-em. Oczywiście coś w rodzaju:

Listing 1. To nie zabangla

ComboBox listofSth = fieldGroup.buildAndBind("Lista wyboru", "oneOfMany", ComboBox.class);

Walnie nam wyjątkiem com.vaadin.data.fieldgroup.FieldGroup$BindException i nie ma w tym nic dziwnego ponieważ skąd framework ma wiedzieć czy spinana wartość ma sens w kontekście potencjalnej zawartości listy czy też nie.

Rozwiązanie jest proste. Wystarczy użyć metody bind:

Listing 2. A to już tak

ComboBox listOfSth = new ComboBox("Lista wyboru");
fieldGroup.bind(listOfSth, "oneOfMany");

Takie coś ku pamięci…


Translate »