Blog Day 2014

August 31st, 2014

W tym roku będzie trochę “prywaty”

Paragraf na kozetce – blog poświęcony prawu i psychologii w procesie postępowania sądowego (oraz około sądowego).
Simply Home About – dla tych co remontują i urządzają… bo to kolejny raz w tym roku przerabiałem
Subiektywnie o finansach – chyba najlepszy polski blog dziennikarski o finansach.
Czas Dżentelmenów – trochę męskiej, klasycznej mody, trochę historii, troch ciekawostek. Generalnie warto poczytać ponieważ niektóre informacje są bezcenne.
Ciekawostki historyczne – świetne czytadło historyczne dla tych, co chcą posiąść wiedzę nietypową.

Predykaty z Guavy i enumy, czyli praktyki dwa łyki

August 31st, 2014

Mamy sobie taki sprytny inaczej system uruchamiania raportów w innym systemie, gdzie z jednej strony mamy status raportu jako enum, a z drugiej jako String. Klasyczny przypadek prowadzący do “potworkowania” kodu takimi oto ifami:

Listing 1. If-potworek

for (ReportRunHistory reportRunHistory : reportRunsHistory) {                     
	LOG.info(reportRunHistory.toString());                                        
	if (reportRunHistory.status.equals(CANCELED.getStatusText())                                  
			|| reportRunHistory.status.equals(FAILED.getStatusText())                             
			|| reportRunHistory.status.equals(COMPLETED.getStatusText())){
        // ...
        }                                       
}

Tomek Nurkiewicz na Confiturze w 2012 roku opowiadał o tym jak pozbywać się Ifów z kodu. Ten kod podpada pod “jest prosto nie trzeba upraszczać”. Mnie jednak osobiści drażni takie coś. Można to naprawdę sprowadzić do czegoś co będzie wyglądać dobrze i co najważniejsze będzie łatwe do przeczytania. Jak używamy Guavy rzecz staje się jeszcze prostsza.

Do czasu…

Pierwszy problem każdego korpo

Trochę się po korpo nie informatycznych włóczyłem i zaobserwowałem, że istnieje w nich pewna wspólna cecha dotycząca kodu. Można by ją opisać, jako mieszankę niechęci do zmian z silną separacją zespołów. Wyobraźmy sobie, że nasz system raportowy ma klienta, który jest napisany w Javie i dostarczony nam przez zespół zajmujący się apką raportową. Rzecz w tym, że jak znajdziemy jakiś błąd to procedura wdrożenia poprawki jest drogą przez mękę. W praktyce napisanie własnego lokalnego haka na bibliotekę jest prostsze…
Inaczej mówiąc w korpo jak dostajesz coś zapaczkowane w jara, to choć by zespół odpowiedzialny za ten kod siedział po sąsiedzku to uzyskanie poprawki jest długotrwałe.
A co w przypadku gdy chcesz uzyskać nową funkcjonalność? Zapomnij.

Miej więcej taki problem mamy z naszym systemem raportowym. Choć klient mógłby zwracać enum to zwraca String, a my musimy robić brzydkie haki w naszych enumach w rodzaju:

Listing 2. “Hakowany” enum

public enum RunReportStatusEnum {

	QUEUED("queued"), RUNNING("running"), COMPLETED("completed"), FAILED("failed"), CANCELED("canceled");

	private final String statusText;

	private RunReportStatusEnum(String statusText) {
		this.statusText = statusText;
	}

	public String getStatusText() {
		return statusText;
	}

}

String w konstruktorze enuma, który mapuje nasz kod na zasadzie enum-String. Można to rozwiązać mapą, ale… nadal zostaje ten pieprzony If z Listingu 1 gdzie jakoś musimy w pewnym momencie przefiltrować sobie to co przychodzi na nasze enumy.

No ale mamy Guavę

A Guava ma predykaty. Pisałem już o predykatach i funkcjach, a teraz chcę pokazać jedno z ciekawszych zastosowań, moim zdaniem oczywiście.

Krok 1. Enum – predykat

Pierwszym krokiem refaktoryzacji jest zauważenie, że w IFie kod składa się z trzech identycznych pod względem konstrukcji warunków. Można je zgeneralizować w następujący sposób:

Listing 3. Metoda uogólniająca dla Ifa

boolean is(ReportRunHistory reportRunHistory, RunReportStatusEnum e){
	return reportRunHistory.status.equals(e.getStatusText());
}

Co w samo w sobie jest może i ładne, ale użycie tego w kodzie nadal paskudne. Zatem w zamiast czegoś takiego można napisać własny enum implementujący Predicate:

Listing 4. Enum – predykat

public enum RunReportStatusEnumPredicate implements Predicate<String> {
	IS_QUEUED(QUEUED), 
	IS_RUNNING(RUNNING), 
	IS_COMPLETED(COMPLETED), 
	IS_FAILED(FAILED), 
	IS_CANCELED(CANCELED);

	private final RunReportStatusEnum statusEnum;

	private RunReportStatusEnumPredicate(RunReportStatusEnum statusEnum) {
		this.statusEnum = statusEnum;
	}

	@Override
	public boolean apply(String input) {
		return statusEnum.getStatusText().equals(input);
	}
}

W praktyce nie wychodzi to poza to co na listingu 3. Główna różnica polega na tym, że całość można sprawnie przetestować (banalne) oraz mamy zapewniony interfejs zdatny do użycia z Guavą.

Krok 2. Składamy predykat

Kto czytał tekst o predykatach ten wie, że można składać predykaty wykorzystując metodę Predicates.or. Złóżmy zatem nasz predykat:

Listing 5. Enum – predykat

or(IS_CANCELED, IS_FAILED, IS_COMPLETED)

LOL… jakie to proste… nasz wyjebany w kosmos IF zamienił się w jednolinijkowca… Nope…

Krok 3. Transformata

Jak przyjrzycie się interfejsowi naszego predykatu to przyjmuje on typ String, a w pętli mamy do czynienia z ReportRunHistory. Jak zatem wtłoczyć do naszego kodu inny typ? Tu z pomocą przychodzi kolejna metoda Predicates.compose, która przyjmuje predykat i funkcję, która zwraca typ zgodny z typem wejściowym predykatu.

Listing 6. Funkcja konwertująca

public class ReportRunHistoryStatusAsStringFunction implements Function {
	public static final ReportRunHistoryStatusAsStringFunction REPORT_RUN_HISTORY_STATUS_AS_STRING_FUNCTION
			= new ReportRunHistoryStatusAsStringFunction();
	
	private ReportRunHistoryStatusAsStringFunction(){}

	@Override
	public String apply(ReportRunHistory input) {
		return input.status;
	}
}

W efekcie nasz kod można przepisać do:

Listing 7. Funkcja i enum

compose(
		or(IS_CANCELED, IS_FAILED, IS_COMPLETED),
		REPORT_RUN_HISTORY_STATUS_AS_STRING_FUNCTION
)

Co zwraca predykat przyjmujący ReportRunHistory i odpalający warunek z predykatu gdzie potrzeba String.

Pułapka

Kod zaczął się trochę “rozwlekać”. Można mu zarzucić, że stworzyłem wiele małych klas, których powtórne użycie jest wątpliwe, a trzeba je jakoś utrzymywać. Powiem tak, jeżeli boisz się tworzyć nowe klasy “na masę” to idź pisać w pascalu gdzieś indziej. Kluczem do sukcesu w tym przypadku jest duża granulacja kodu. W praktyce ( i w rozwiązaniu z korpo) z pojedynczej konstrukcji for-if-for-if-logika można wygenerować nawet 10-12 klas, a każda z nich będzie odpowiadać, za jakąś pojedynczą funkcjonalność. Choćby była to obsługa ifa.
Ten przykład jest niekompletny, ponieważ if znajduje się w pętli to nie do końca widać siłę tej refaktoryzacji. Ale o tym następnym razem, bo nie o tym tu chciałem teraz napisać.

Duża granulacja kodu to też pewna pułapka. Z jednej strony bardzo łatwo jest taki kod przetestować, ale z drugiej strony kto będzie pisał testy dla getterów (nasza funkcja to opakowanie gettera). tym samym może okazać się, że po większej refaktoryacji, gdzie dodaliśmy dużo nowych małych klas bez testów, nagle nasze pokrycie testami spada i wywala buildy. Bywa… choć testowanie małych klas wydaje się zawracaniem dupy to należy się zmusić i to robić.
Można też ułatwić sobie życie testując trochę większe kawałki kodu. Tu dobrym kandydatem na napisanie testu jest nie funkcja i enum, ale predykat powstały z ich kompozycji. Choć nadal duża część testu to sprawdzenie “czy guava działa” to jednak jest to już test, który już napisaliśmy. Kiedy? Gdy przystępowaliśmy do refaktoryzacji i mieliśmy pokrycie testami dla całego Ifa. Pamiętajcie, że nadal testujemy jakiś większy kawałek kodu – serwis czy coś w ten deseń, gdzie w środku w wyniku refaktoryzacji udało się wyciągnąć ileś tam małych klas.

Podsumowanie

Przedstawiona tu technika radzenia sobie z ifem jest dobrym punktem zaczepienia jeżeli chcecie wprowadzać elementy programowania funkcyjnego do swojego kodu. Nie jest to oczywiście programowanie funkcyjne jako takie, ale ma jego naturę (funkcja i predykat są bezstanowe, nie zmieniają stanu obiektu itp.). To już dużo. Znacznie więcej niż można sobie wyobrazić gdy widzimy przeciętny kod korpo-potworka i chcemy się w nim rozeznać.

Jest to oczywiście fragment większej refaktoryzacji, a kolejnym ciekawym jej elementem jest to jak wywołać logger z pierwszej linii pętli.

O tym między innymi 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ść.

Clean services, albo mikro architektura…

August 24th, 2014

Jak cholerę zwał tak zwał. Generalnie ostatnie spotkania Wrocławskiego JUGa dały mi trochę do myślenia.

Pierwsze z Wujkiem Bobem było poświęcone Clean Architecture. Wcześniej Andrzej Bednarz opowiadał nam o swoich doświadczeniach z tym rozwiązaniem, ale tu mieliśmy okazję “u żródła”.
Drugie poświęcone architekturze mikroserwisów poprowadzone przez Roberta Firka było swoinstym dopełnieniem.

O co chodzi?

Clean Architecture jest koncepcją takiego tworzenia funkcjonalności by były one jak najbardziej odseparowane od świata zewnętrznego. Interaktor (ciężko mi znaleźć polskojęzyczny odpowiednik) ma swój interfejs komunikacyjny i korzysta z pewnych obiektów – encji domenowych (wspólnych dla wielu aplikacji nie tylko dla tej konkretnej). Gdy potrzebuje dostać się do danych korzysta z interfejsu dostępowego, ale nie DAO lecz czegoś w rodzaju gateway-a. Co jest za nim… who cares. Po prostu dostajemy dane w pewnym określonym formacie i czy będzie pod spodem baza danych, czy jakiś sawant… W efekcie dostajemy aplikację, która ma charakter kontenera pluginów. Jest sobie jakiś core biznesowy reprezentujący use casy, a reszta to tylko łatwo wymienialne pluginy.

Mikroserwisy są znowuż podejściem gdzie stawiamy duży nacisk na separację poszczególnych funkcjonalności i ich niezależność. W tym podejściu liczy się przede wszystkim duża granulacja kodu, tak by zmiana nie trwała tygodniami, a raczej godzinami. Poszczególne fragmenty komunikują się ze sobą i każde wywołanie powinno nieść ze sobą wszelką wiedzę i informacje potrzebną do wykonania danej operacji. Mikroserwisy mogą powstawać w różnych technologiach i nie mogą współdzielić zasobów.

Widzicie na czym polega myk?

Mikro architektura, czyli clean services

Projektowanie zaczynamy zgodnie z Clean Architecture. Naszą bazą mentalną jest konkretny use case. Reprezentuje on jeden niezależny scenariusz w aplikacji. W tym momencie projektujemy kod, spisując kolejne kroki i korzystając z bazy pojęć CA. Mamy więc interaktora, boundaries, entyties, gateways.
Następnie zaczynamy kod pisać i na poziomie pojedynczego use casa nadal trzymamy się CA.
Gdy jednak dokładamy realizację elementów “plugowalnych” chociażby jakiś testowy gateway to staje się on mikroserwisem. Staramy się tak zaprojektować interfejs by wywołanie jakiegoś pluginu realizowane było w oparciu o MiS.

Co to nam daje?

Dwa słowa podsumowania. CA i MiS są to dwa podejścia, które kładą nacisk na dwa inne elementy architektury. W CA staramy się modularyzować kod tak by reprezentował on poszczególne zagadnienia biznesowe. Każdy niezależny element w kodzie ma odbicie w use caseie. MiS kładzie znowuż nacisk na to jak poszczególne moduły ze sobą współpracują oraz na to by awaria jednego z nich nie wywaliła nam aplikacji.
Moim zdaniem połączenie tych dwóch podejść pozwala na stworzenie z jednej strony aplikacji, która będzie dość odporna na awarie. Jednocześnie każda pojedyncza jednostka organizacyjna będzie miała jasno określony zakres odpowiedzialności biznesowej.
Ponad to, jako że w każdej aplikacji istnieją pewne byty konieczne z punktu widzenia prawidłowego działania, ale nie niezbędne biznesowo (administracja uprawnieniami, składowanie danych, audyt), będzie można tak zorganizować kod by ich istnienie miało jak najmniejszy wpływ na logikę biznesową.

Typy prymitywne z logiką biznesową wstęp do dobrego kodu

July 13th, 2014

Większość aplikacji obiektowych, które są tworzone jak świat długi i szeroki nie ma za dużo wspólnego z OOP. Przynajmniej na poziomie modelu. Ten został w czasach proceduralno-strukturalnych. Mamy zatem klasy, które w rzeczywistości są strukturami znanymi z C tyle tylko, że wyposażonymi w gettry i settery.
Te klasy są trochę jak aktorki w filmach porno. Patrzysz na nie i niby mają na sobie fatałaszki (metody), ale jak zaczniesz z taką zabawę to dość szybko okaże się, że nie ma ona nic do ukrycia. O ile w porno jest to OK, to w programowaniu obiektowym nie do końca. Klasa, która ujawnia zbyt dużo może szybko stać się źródłem problemów. W dodatku sama w sobie ma tendencję do obrastania dodatkowymi klasami narzędziowymi, bez których nie za bardzo może żyć.

Friendzone

Jest to pewien antywzorzec będący bezpośrednim następstwem anemicznego modelu. Można powiedzieć, że klasa “awansowała” do friendzone jeżeli w stosunku do innej klasy pełni rolę służebną nie otrzymując nic w zamian. Klasa taka musi spełniać pewne wymagania:

  • Musi być częścią publicznego API systemu.
  • Jej usunięcie nie ma wpływu na logikę działania systemu.
  • Jej usunięcie ma wpływ na zachowanie systemu.

Założenia te spełnia większość klas typu “utilsy do czegoś tam”. Szczególnie zaś najprzeróżniejsze parsery informacji z GUIa, serwisów zewnętrznych.

Przypadek specjalnej troski

Specyficznym przypadkiem jest użycie typów podstawowych (prymitywnych i String) jako pełnoprawnych członków modelu. To zły pomysł. Jak dopuścisz prymitywów do dyskusji to zaczną odpierdalać nietoperza, osrają wszystko dookoła, a na koniec dadzą w mordę przypadkowym gościom. Jeszcze gorzej jest gdy typ prymitywny niesie w sobie pewną logikę biznesową. W takim wypadku trzeba z nim jakoś żyć. Niestety wielu programistów idzie po linii najmniejszego oporu i zamiast opakować typ prymitywny “friendzonuje” grupę klas by tylko się nie narobić. A to błąd…

Karmimy model

By jakoś wyrwać się z okowów anemicznego modelu należy przeprowadzić refaktoryzację. Zazwyczaj pierwszy krok takiej refaktoryzacji polega na wydzieleniu klasy opakowującej. Niestety wiele osób na tym kończy. W najlepszym wypadku dostajemy takiego potworka jak poniżej

Listing 1. Ta klasa też jest anemiczna

public class Pesel {

	private final String pesel;

	public Pesel(String pesel){
		this.pesel = pesel;
	}

	@Override
	public String toString() {
		return pesel;
	}
	public void accept(Validator validator){
		validator.validate(this.pesel);	
	}

}

Niby wszystko jest OK. Nawet jakaś walidacja jest… taka to wali wyjątkami… Ale jednak trochę do dupy… trochę bardzo.

Klasa nie niesie ze sobą żadnej wartości. Jak ją przerobić na coś co ma wartość? Wszystko zależy od tego jaką informację biznesową niesie ze sobą określony typ prymitywny. W przypadku numeru PESEL ilość informacji jest stosunkowo duża jak na tak krótki numer. Zatem można wygenerować dość bogatą klasę opakowującą. W dodatku ze względu na specyfikę logiki numeru PESEL można tu naprawdę dużo upchnąć.

Pierwszym krokiem przy dokarmianiu modelu jest decyzja jak “bogaty” ma być. Ja postaram się to zrobić na full wypas. Zatem klasa będzie niosła ze sobą całą logikę zawartą w numerze PESEL oraz dodatkowo będzie kompensować jego niedociągnięcia.

Listing 2. Pesel na bogato pierwsze kroki

public class RitchPesel {

	private final String dateOfBirth;
	private final String serialNumber;
	private final int sexDigit;
	private final int controlDigit;

	private final boolean isCorrect;
	private final boolean isValid;

	private RitchPesel(String dateOfBirth, String serialNumber,
	                   int sexDigit, int controlDigit,
	                   boolean isCorrect, boolean isValid) {
		this.dateOfBirth = dateOfBirth;
		this.serialNumber = serialNumber;
		this.sexDigit = sexDigit;
		this.controlDigit = controlDigit;
		this.isCorrect = isCorrect;
		this.isValid = isValid;
	}

	public Sex sex() {
		return Sex.byDigit(sexDigit);
	}

	public LocalDate birthDate() {
		return PeselBirthDateParser.parse(dateOfBirth);
	}

	public boolean isCorrect() {
		return isCorrect;
	}

	public boolean isValid() {
		return isValid && isCorrect;
	}

	@Override
	public String toString() {
		return dateOfBirth + serialNumber + sexDigit + controlDigit;
	}

}

Zatem mamy coś takiego. Klasa zawiera pewną logikę. Na podstawie numeru PESEL możemy określić datę urodzenia oraz płeć. Na uwagę zasługuje tu rozdzielenie pól isValid i isCorrect. Wynika ono z uwarunkowania historycznego numeru PESEL. Nie każdy prawidłowy numer jest poprawny. Pierwsze pole przechowuje informację o poprawności numeru w sensie wyliczenia sumy kontrolnej. Drugie przechowuje informację o prawidłowości numeru w odniesieniu do rejestru. Oznacza to tyle, że może istnieć numer nie spełniający zasad wyliczania sumy kontrolnej, z nieprawidłową datą bądź nieprawidłowym oznaczeniem płci i będzie on prawidłowy.
O takich sytuacjach zapominają ludzie implementujący obsługę numeru i później jest jazda gdy przychodzi klient, podaje dowód osobisty, a system się burzy.
Kolejna ważna rzecz w tym konkretnym przypadku to prywatny konstruktor. Po co on nam? W końcu można by było stworzyć konstruktor, który przyjmował by numer PESEL jako String i robił odpowiednią magię. Rzecz w tym, że tu znowu daje znać o sobie sprawa poprawności i prawidłowości numeru. Można co prawda dodać kolejny parametr w konstruktorze, który będzie opisywał jak ścisła ma być walidacja, ale to nadal nie rozwiązuje problemu. Taki kod choć krótki nie niesie ze sobą informacji co tak naprawdę tam się w środku dzieje.
Kolejna sprawa, i kolejny parametr w konstruktorze, to walidacji płci. Po samym numerze nie rozpoznamy czy zawarta w nim płeć jest poprawna. Trzeba dorzucić parametr informujący czy mamy do czynienia z mężczyzną czy z kobietą. Podobnie ma się sprawa z datą urodzenia. Tu mamy dwa przypadki. Pierwszy jak w przy płci weryfikacja w źródle zewnętrznym, a drugi to weryfikacja dat w rodzaju 31 listopada. Zatem kolejny parametr, który jest opcjonalny (bo przy wyłączonej ścisłej walidacji można go olać). I tak oto otrzymujemy całkiem sporą grupę konstruktorów, które będą dość zagmatwane w swojej naturze.
Rozwiązaniem problemu jest oczywiście stworzenie budowniczego dla naszej klasy. Na tym etapie możemy zagrać sobie na typach i stworzyć kod w oparciu o dziedziczenie. UWAGA! Co co chcę tu przekazać to dobry przykład poprawnego użycia dziedziczenia. Jeżeli ktoś mówi wam, że dziedziczenie w stylu Figura > Prostokąt > Kwadrat jest ok, to mu nie wierzcie. To jest dobry przykład na implementację interfejsu, ale nie dziedziczenie!
Na początek dodajmy do naszej klasy dwie metody statyczne zwracające nam odpowiednich budowniczych

Listing 3. Dwóch różnych budowniczych

public static Builder getStricBuilder(String pesel){
	return new StrictBuilder(pesel);
}

public static Builder getTolerantBuilder(String pesel){
	return new TolerantBuilder(pesel);
}

To już dużo wyjaśnia. Metody te pomimo swojej prostoty są bardzo ekspresyjne. Zarówno osoba czytająca kod w jak i to używająca nie będzie miała problemu ze zrozumieniem co tu się dzieje. Sama klasa Builder jest klasą wewnętrzną i abstrakcyjną. Nie jest interfejsem ponieważ chcemy w niej przechowywać numer w postaci ciągu znaków. Poza tym będzie ona zawierać wspólną logikę dla obu typów budowniczych.
Kolejnym krokiem jest implementacja budowniczych w oparciu o przekazywane parametry i ustawiane flagi.
Ostatni krok to posprzątanie kodu wedle własnych potrzeb.

Oczywiście należy pamiętać o testach.

Podsumowanie

Samo obudowanie typu prymitywnego w mającą biznesowe uzasadnienie klasę jest stosunkowo proste. Jednak dopiero wzbogacenie takiej encji o logikę biznesową, która jest z nią bezpośrednio powiązana pozwala na tworzenie dobrego kodu. Kod taki będzie pozbawiony publicznych klas, które “wpadły w friendzone”. Zostaną one zamknięte w ramach klasy, którą wspierają.
Kod taki pozwala też na napisanie lepszych testów jednostkowych. Testy takie będą rzeczywiście sprawdzać zachowania, a nie powtarzać logikę biznesową. Warto tu jednak zwrócić uwagę na ilość kodu zamkniętego w encji. Jeżeli będzie go za dużo to testowanie może okazać się mordęgą. Szczególnie jeżeli cały kod będzie w ramach klas wewnętrznych BEZ możliwości dobrania się do nich.
W takim wypadku należy pójść na pewien kompromis. Na pewno część kodu (zazwyczaj pewne klasy narzędziowe) będzie miała dużą wartość też poza klasą, w której została zdefiniowana. Warto zatem upublicznić ich API, a w skrajnym przypadku przenieść poza encje. Świetnym przykładem tego typu klas są walidatory. Jeżeli tylko napiszemy je w miarę ogólnie, na przykład przyjmując, że na wejściu otrzymują dane w formie typów prymitywnych, to nic nie stoi na przeszkodzie by wydzielić je do osobnego pakietu. W takim wypadku, walidator może pracować z różnymi encjami biznesowymi reprezentującymi ten sam byt (bo chyba nie wierzycie w bajki o spójnych encjach biznesowych w projektach integracyjnych).

I już po Confiturze

July 9th, 2014

Jak od ośmiu lat początek wakacji stanął pod znakiem Confitury. Po raz trzeci spotkaliśmy się na terenie kampusu głównego UW. I było wesoło…

Java performance tricks and traps – Michał Warecki

Generalnie nastawiłem się na coś co można nazwać “performance track” i się w sumie nie zawiodłem. Prezentacja Michała dotyczyła wszystkich poziomów tego co nazywamy wydajnością. Począwszy od wysoko poziomowej zabawy z konfiguracją po niskopoziomowe zagadnienia bliskie krzemu. Bardzo fajne. Było też trochę o tym jak badać wydajność swojego kodu.

Archeologia kodu źródłowego – Paweł Ślusarz

Poszedłem na tą prezentację z dwóch powodów. Trochę interesuję się “starym kodem” i tym jak się w nim powinno grzebać. To raz, a dwa zaciekawił mnie opis ponieważ wynikało z niego, że będzie to nie tylko teoria.
Sama prezentacja była świetna. Paweł opowiedział, choć pobieżnie, o pewnych prostych lecz nieoczywistych metrykach pozwalających na wyszukanie elementów kodu, które mogą sprawić prawdziwe problemy. Zaprezentował to na żywym projekcie, który był rzeczywiście duży.

Twórz i Rządź, czyli jak developer może pobawić się hardwarem – iBeacony, RaspberryPi, druk 3D itd. – Tomasz Szymanski, Jarosław Kijanowski

Fajna “hakierska” prezentacja. Jednak moim zdaniem chłopaki chcieli pokazać dużo różnych rzeczy i wyszło trochę to takie nieforemne (jak z drukarki 3d). Była zatem mowa i o RaspberryPi i o druku 3D i o iBeaconach. Myślą przewodnią spinającą całość był system oceniania prezentacji na Confiturze oraz aplikacja wspomagająca imprezę. Tyle tylko, że jakoś mnie to nie do końca przekonało. Fajnie na luzie i rzeczowo, ale trochę z kwiatka na kwiatek i bez systematycznego planu.

JVM and Application Bottlenecks Troubleshooting with Simple Tools – Daniel Witkowski

Tu było zabawnie. Daniel zademonstrował na przykładzie naprawdę paskudnego kodu jak nasza niefrasobliwość może wpływać na wydajność dostarczanych rozwiązań. Choć osobiście uważam, że refaktoryzowany fragment by mocno “przedobrzony” w swej chujowatości, to jednak dobrze zbierał różne częste potknięcia.
Mam nadzieję, że kod wraz z video będzie szybko dostępny, bo moim zdaniem była to najbardziej wartościowa prezentacja w tej edycji.

Java in low latency world – Andrzej Michałowski

Temat ciekawy i choć można z niego dużo wycisnąć, to nie lubię gdy prezentujący odwołuje się do innych prezentacji z założeniem, że nie będzie o czymś opowiadać, bo już było. Bi nie było. Nie ważne jednak. Prezentacja o trochę innej tematyce niż to co mówił Daniel i wcześniej Michał. Niby to samo, GC, tuning i strojenie maszyny, ale czegoś mi tu zabrakło. Serio, serio.

Nie koduj, pisz prozę – lingwistyczne techniki wychodzące daleko poza Clean Code – Sławomir Sobótka

Może nie tyle sam temat, bo Sławek nie powiedział nic nowego czy odkrywczego, ale sposób przedstawienia problemu zrobił na mnie wrażenie. Trochę śmieszno, trochę straszno, ale bardzo merytorycznie i rzeczowo. Lubię słuchać Sławka, bo to jeden z tych ludzi, którzy mają dar do prowadzenia prezentacji i szkoleń.

Podsumowanie

Później była Spoina i co działo się na Spoinie niech pozostanie na Spoinie. Generalnie w tym roku było na granicy możliwości organizatorów. Przynajmniej mam takie wrażenie. Z jednej strony błyskawiczne zamknięcie rejestracji. Z drugiej około 1400 uczestników, którzy rzeczywiście się zjawili! To spowodowało lekki zator przy rejestracji. W tym roku impreza rozproszyła się też na dwa budynki aulimaks i stary BUW. Na całe szczęście nie było aż tak upalnie jak rok temu.

Dzięki wszystkim za przybycie, fajne rozmowy i dobrą zabawę.

UPC Free – sposób ataku wymyślony w tramwaju

June 27th, 2014

Nowa usługa UPC jest cholernie niebezpieczna. IMO, niebezpieczniejsza niż zwykłe otwarte hotspoty w knajpach. Te ostatnie jak by nie patrzeć mają jakieś sensowne nazwy i zazwyczaj dają się przypisać do konkretnej firmy/lokalu. Hotspoty UPC emitują tylko nic nieznaczące nazwy.

Sposób ataku w przypadku korzystających z tego typu sieci jest banalnie prosty.

  • Przygotowujemy sobie router z nazwą sieci pasującą do modelu nazw UPC
  • Preparujemy lokalnego DNSa tak by strona logowania kierowała do naszego skryptu z adresem wyglądającym na poprawny. Zbieramy PESELe i numery klientów
  • Najtrudniejsza część – udawany SSL. Czyli tworzymy konfigurację, w której nawiązanie połączenia po SSLu z np. pocztą oznacza, że użytkownik łączy się z naszym komputerem po “naszym” SSLu, my rozpakowujemy jego dane i przepakowujemy dalej do zwykłego SSLa z serwerem docelowym łącząc się niejako “W imieniu klienta”.
  • Rozbijamy obóz w jakiś ruchliwym miejscu i czekamy

Może nie uda się wysniffować danych o kontach bankowych, ale już hasło do googla już tak. W efekcie dostaniemy dostęp do danych wrażliwych i może nawet do ksera dowodu… a to już bardzo dużo.

Dlaczego klasy anonimowe to zło – wydajność

June 19th, 2014

Przy okazji jednego z ostatnich code review natrafiłem na kawałek kodu w stylu:

Listing 1. Przykładowy kod z cr

     Collections2.transform(bussinessObjects, new Function<BussinessObject, SomeProperty>(){
        
          public SomeProperty apply(BussinessObject bo){
              return bo.getSomeProperty();
          }
        }
     );

Bardzo częsty obrazek w kodzie. Ogólna logika jest tu taka, że z listy obiektów pewnej klasy chcemy uzyskać listę obiektów z jednego z ich pól i dalej bawić się z tylko z tymi polami. Ma to sens. Kod tego typu jest czytelny i intuicyjny. W dodatku bardzo ładnie mapuje się na specyfikację “…ze zbioru BO wyciągamy wartości pola X dla każdego BO i następnie…”.

Pytanie brzmi czy powyższe rozwiązanie jest ok?

Klasa anonimowa to zło

Szczególnie w Javie, w której przez lata klasa anonimowa była protezą dla brakujących domknięć/miksinów. Jest to też pokłosie szybkiego kodowania prostych rzeczy tak jak przedstawiona powyżej. Wiemy, że można by to zrobić w pętli. Wiemy, że będzie też ok. Dlatego wybieramy prostszy i szybszy zapis z wykorzystaniem transformat z Guavy. W dodatku kod funkcji jest mocno jednorazowy zatem nie wyciągamy go nigdzie na zewnątrz do np. zmiennej.
Oczywiście pozostaje sprawa powtórzeń w kodzie, ale przy ogarniętym procesie budowania w razie czego otrzymamy informację z narzędzi śledzących takie rzeczy. Dochodzą tu jeszcze rzeczy związane z “drabinkowaniem” kodu i jego czytelnością. To jednak insza inszość.

Jako, że jest to proteza to i nie ma w Javie dobrych mechanizmów pozwalających na optymalizację takiego kodu przez JIT. Zauważyć należy, że funkcja taka jest bezstanowa lub jej stan jest silnie powiązany ze stanem obiektu, w którym została utworzona. Zatem można by przenieść ją do pola na poziomie obiektu. Odpowiednio statycznego dla funkcji bezstanowych i niestatycznego dla funkcji związanych z obiektem. Pytanie brzmi o ile szybciej będzie wykonywał się kod po takim przeniesieniu. Rzeczą oczywistą jest to, że usunięcie z kodu inicjalizacji obiektu przyspiesza go. Oczywiste jest też to, że im więcej wywołań metody w której oryginalnie inicjujemy obiekt funkcji tym różnica jest większa.

Sprawdźmy to!

Zadanie

By stworzyć w teście warunki w miarę zbliżone do takich jakie mogą panować na serwerze test będzie miał następującą konstrukcję:

  • Będziemy pracować na stosunkowo dużym zbiorze danych tak by zapchać pamięć.
  • Operacja wykonywana w funkcji powinna być “JITowalna” i łatwa w optymalizacji na poziomie kompilatora.
  • Operacja powinna być “na zdrowy chłopski rozum” dość długa.

Pierwsze dwa punkty wydają się oczywiste. Serwery są zazwyczaj obciążone zarówno jeśli chodzi o pamięć jak i procesor. Duża ilość danych pozwoli nam na zapchanie pamięci. W dodatku sama operacja “biznesowa” powinna być tak skonstruowana by JIT był ją wstanie zoptymalizować. Ostatni punkt pozwoli nam na sprawdzenie czy takie przeniesienie ma sens jeżeli operacja wewnątrz funkcji jest przynajmniej w teorii dość powolna. Innymi słowy czy czas inicjalizacji obiektu będzie mały w stosunku do czasu operacji.

Nasze zadanie zatem brzmi. Policzy N razy n! dla wszystkich liczb n ze zbioru [0, N-1]. Czyli jeżeli N=5 to odpalamy pięć razy pętle w której liczymy silnie dla liczb od 0 do 4. Całość ma sens jeżeli używamy BigInteger.

Listing 2. Kod “biznesowy”

public class Silnia {

	public BigInteger oblicz(BigInteger n) {
		return silnia(BigInteger.ONE, n);
	}


	private BigInteger tailRec(BigInteger acc, BigInteger n) {
		if (n.equals(BigInteger.ZERO))
			return acc;
		return tailRec(acc.multiply(n), n.subtract(BigInteger.ONE));
	}

}

Tu uwaga Java nie wspiera rekurencji ogonkowej. Po prostu. Wynika to z modelu bezpieczeństwa przyjętego przy projektowaniu języka i tego jak będzie on współpracował ze stosem. Do poczytania tu. Zatem powyższy kod to tylko sztuka dla sztuki i podanie wystarczająco dużej liczby na wejściu spowoduje StackOverflowException wynikający ze zbyt dużej liczby wywołań.

Nasze testowe funkcje będą wołać metodę oblicz. Teraz czas na naszych bohaterów:

Listing 3. Klasy inicjujące funkcje na różne sposoby

class FunctionAlwaysNew {

	public Collection obliczSilnie(List input) {

		return Collections2.transform(input, new Function() {
			@Override
			public BigInteger apply(BigInteger n) {
				return App.silnia.oblicz(n);
			}
		});
	}
}

//...
class FunctionAsStatic {

	private static final Function FUNCTION = new Function() {
		@Override
		public BigInteger apply(BigInteger n) {
			return App.silnia.oblicz(n);
		}
	};

	public Collection obliczSilnie(List input) {
		return Collections2.transform(input, FUNCTION);
	}
}

Ilość danych na wejściu 17,5mln liczb. Parametr -Xmx2g:

Wprowadź dużą liczbę całkowitą.
17500000
Tworzę listę z danymi
Dane gotowe. Naciśnij enter by zacząć test
Rozpoczynam test dla przypadku z użyciem pola statycznego.
Test zakończony. Zajął 21ms

Rozpoczynam test dla przypadku z użyciem new.
Test zakończony. Zajął 1512ms

i to samo dla parametrów -Xmx2g -server:

Wprowadź dużą liczbę całkowitą.
17500000
Tworzę listę z danymi
Dane gotowe. Naciśnij enter by zacząć test
Rozpoczynam test dla przypadku z użyciem pola statycznego.
Test zakończony. Zajął 622ms

Rozpoczynam test dla przypadku z użyciem new.
Test zakończony. Zajął 6878ms

Zatem widać, że inicjalizacja statyczna jest jakieś dwa rzędy wielkości szybsza, a w przypadku użycia trybu serwera różnica jest rzędu wielkości.

No cześć maleńka… chcesz zobaczyć moją lambdę

Ok teraz kod z pomocą lambd i pytanie na ile będzie szybszy. Przy czym nie używam tu Stream API ponieważ wersja wielowątkowa to insza inszość i temat na inny tekst. Chcąc użyć lambd mamy do wyboru trzy opcje. Pierwsza to “inline”, druga to lambda przypisana do pola, a trzecia to method ref. Kod interesujących nas klas poniżej:

Listing 4. Wykorzystanie lambd

class FunctionLambdaInline {

	public Collection obliczSilnie(List input) {

		return Collections2.transform(input, n -> App.silnia.oblicz(n));
	}
}

//..

class FunctionLambdaStatic {

	public static final Function FUNCTION = n -> App.silnia.oblicz(n);

	public Collection obliczSilnie(List input) {

		return Collections2.transform(input, FUNCTION);
	}
}

//...

class FunctionLambdaRef {

	public Collection obliczSilnie(List input) {

		return Collections2.transform(input, App.silnia::oblicz);
	}
}

I wyniki dla wersji z -Xmx2g:

Wprowadź dużą liczbę całkowitą.
17500000
Tworzę listę z danymi
Dane gotowe. Naciśnij enter by zacząć test
Rozpoczynam test dla przypadku z użyciem pola statycznego.
Test zakończony. Zajął 30ms

Rozpoczynam test dla przypadku z użyciem new.
Test zakończony. Zajął 2162ms

Rozpoczynam test dla przypadku z użyciem lambdy inline.
Test zakończony. Zajął 576ms

Rozpoczynam test dla przypadku z użyciem lambdy method ref.
Test zakończony. Zajął 6358ms

Rozpoczynam test dla przypadku z użyciem lambdy statycznej.
Test zakończony. Zajął 19ms

i z -Xmx2g -server:

Wprowadź dużą liczbę całkowitą.
17500000
Tworzę listę z danymi
Dane gotowe. Naciśnij enter by zacząć test
Rozpoczynam test dla przypadku z użyciem pola statycznego.
Test zakończony. Zajął 29ms

Rozpoczynam test dla przypadku z użyciem new.
Test zakończony. Zajął 3137ms

Rozpoczynam test dla przypadku z użyciem lambdy inline.
Test zakończony. Zajął 37ms

Rozpoczynam test dla przypadku z użyciem lambdy method ref.
Test zakończony. Zajął 6540ms

Rozpoczynam test dla przypadku z użyciem lambdy statycznej.
Test zakończony. Zajął 24ms

Podsumowanie

Oczywiście metodyka testów jest mocno chałupnicza i wyniki są tylko poglądowe. Dotyczą też javy “od suna” czyli maszyny hotspot.
Wyniki pozwalają jednak wnioskować, że inicjalizacja statyczna będzie dużo szybsza niż każdorazowe wołanie new. Ponad to jeżeli mamy okazję użyć javy 8 to należy wystrzegać się method ref i w zamian używać lambd. Przy czym w wersji serwerowej nie ma większego znaczenia jak będzie ona tworzona.

Interfejsy z implementacją w Javie 8

June 16th, 2014

Zastanawialiście się kiedyś po co w Javie 8 wprowadzono interfejsy z (domyślną) implementacją? Oczywiście można powiedzieć, że dzięki temu mamy miksiny/domknięcia/traity czy jak to tam zwał w zależności od punktu odniesienia.
Ale czy taka konstrukcja nie jest przez przypadek rozwiązaniem znacznie poważniejszego problemu projektowego?

Jak zrobić API?

API, czyli po ludzku interfejs aplikacji/biblioteki/narzędzia itp. Java udostępnia dwa w miarę rozsądne rozwiązania pozwalające na tworzenie takich interfejsów.
Pierwsze to oczywiście interfejsy. Zawierają w sobie tylko definicje, sygnatury, metod. Całkowicie abstrakcyjne, niezwiązane z konkretną implementacją ani z określonym podejściem. Fajne są. Generalnie współcześnie w produkcji kodu kładzie się nacisk na programowanie z wykorzystaniem właśnie interfejsów. Dzięki temu zachowujemy elastyczność. O tym za chwilę.
Drugim rozwiązaniem są klasy abstrakcyjne. Sprawdzają się gdy wiemy iż implementacja, jej główny koncept, nie zmieni się w znaczący sposób, a użytkownik powinien zdefiniować szczegóły. To podejście pozwala na tworzenie rozwiązań, które mają mniej punktów swobody, ale jednocześnie już “odwalają” za nas część pracy. Dobry pomysł, gdy wiemy iż wszystkie możliwe, i zdroworozsądkowe, implementacje interfejsu będą powtarzać pewne schematy. Zresztą bardzo często jest tak iż klasa abstrakcyjna implementuje interfejs tak by użytkownik musiał już tylko dopisać niewielki kawałek. Sparametryzować kod.

Elastyczność API

To co napisałem dotychczas jest oczywiste do tego stopnia iż pytanie o różnicę pomiędzy interfejsem i klasą abstrakcyjną zadają już nawet panny z HRu na rozmowie. Na takie pytanie oczywiście pada odpowiedź o tym, że klasa abstrakcyjna to tak naprawdę zwykła klasa, że można tylko dziedziczyć po jednej z nich, a interfejsy to panie kochany implementujemy ile chcemy.
Ok, dobra odpowiedź. Przy czym nie o to chodzi :D

Główna różnica polega na elastyczności w rozumieniu zarówno zmiany implementacji jak zmiany samego interfejsu. Interfejs jest po opublikowaniu praktycznie niezmienny. Jego implementacje mogą być najróżniejsze. Wyobraźmy sobie taki oto interfejs:

Listing 1. Prosty interfejs

interface Sort<T extends Comparable<T>>{

	Collection<T> sort(Collection<T> c);

}

Ilość implementacji jest naprawdę duża. Zresztą, znajomy z forum 4programmers rzeźbi ciekawy projekt na ten temat. Se weźcie poczytajcie. Ad rem, wyobraźmy sobie, że wydaliśmy naszą bibliotekę z tym interfejsem i ludzie z niej korzystają. Względnie wykorzystaliśmy ją w dużym projekcie i wirus naszego interfejsu rozlał się na całą zdrową tkankę kodu. Teraz chcemy dodać kolejną metodę i dupa…
Interfejsy po publikacji są mało elastyczne. Zmiana w interfejsie pociąga za sobą konieczność zmiany we wszystkich implementacjach.
Trochę inaczej ma się sprawa z klasami abstrakcyjnymi.

Listing 2. Prosta klasa abstrakcyjna

abstract class AbstractSort<T extends Comparable<T>>{

	abstract Collection<T> sort(Collection<T> c);

}

Tu dodanie kolejnej metody jest banalnie proste. Jeżeli nie będzie abstrakcyjna to nie wpływa na poszczególne podklasy. Pojawia się i już. Wadą tego rozwiązania jest oczywiście utrata elastyczności w budowaniu hierarchii klas. Klasy muszą dziedziczyć z naszej klasy abstrakcyjnej i tym samym wykluczają się z innych hierarchii.

Rozwiązanie pośrednie

Rozwiązaniem pośrednim tego problemu jest wielopoziomowy interfejs. Po prostu jeżeli zachodzi konieczność dodania nowej metody do interfejsu to tworzymy podinterfejs.

Listing 3. Hierarchia interfejsów

interface FreeSort<E> extends Sort{

	Collection<E> sort(Collection<E> c, Comparator<E> comp);

}

Teraz tam gdzie potrzebujemy zmieniamy implementowany interfejs. Mało zabawne.

Rozwiązanie w oparciu o Javę 8

Po tym dość długim wstępie czas na prezentację tego co dają interfejsy z domyślną implementacją w Javie 8. Otóż domyślna implementacja daje nam naprawdę dużo. Z jednej strony zachowujemy swobodę jaką dają interfejsy. Z drugiej otrzymujemy możliwość bezinwazyjnego dodawania metod tak jak w przypadku klas abstrakcyjnych.
Nasz interfejs po zmianie nie będzie miał już podinterfejsu. Otrzyma dodatkową metodę, a jej dodanie nie wpłynie na istniejące implementacje

Listing 4. Interfejs z dodatkową metodą

interface Sort<T extends Comparable<T>>{

	Collection<T> sort(Collection<T> c);

	default <E> Collection<E> sort(Collection<E> c, Comparator<E> comp ){
		throw new UnsupportedOperationException("Default impl");
	};
}

Podsumowanie

Domyślna implementacja w interfejsach wprowadzona w Javie 8 to nie tylko namiastka wielodziedziczenia czy też “coś na wzór scalowych traitów”. To rozwiązanie poważnego problemu projektowego, który bardzo często wpływa na kształt naszego kodu.
Co więcej dzięki temu rozwiązaniu można zrezygnować ze sztucznej hierarchii interfejs + klasa abstrakcyjna, z której wszystko dziedziczy. Takie uproszczenie pozwala na tworzenie API elastycznego zarówno pod względem dowolności implementacji jak i łatwego w rozszerzaniu o nowe możliwości.

Hello IT, please turn off and turn on computer….

June 13th, 2014

Ok jako arystokrata pozwolę sobie na chwilę plebejskiej rozrywki w postaci popełnienia wpisu na bloga…

Sprawa tekstu Tomasza Molgi o “IT-Arsystokracji” jest powszechnie znana. Tydzień zaczęliśmy z grubej rury i czas na podsumowanie. Pozwolę zatem sobie na popełnienie wpisu. Oczywiście by nie być w całkowitym oderwaniu od rzeczy trzy linki:

Każdy z tych tekstów gdy potraktujemy go jako coś samodzielnego nie ma sensu. Nawet po dodaniu kontekstu całej sprawy nadal nie jest dobrze. Jednak jeżeli przyjrzymy się na chłodno tym trzem tekstom na raz to można zobaczyć całkiem ciekawy obraz nie tylko polskiego IT, ale i tzw. pokolenia przemian ustrojowych.

Po kolei jednak…

Tekst 1

Ból dupy. W sumie to idealnie podsumowuje ten tekst. Tyle tylko, że nie do końca wiadomo skąd się wziął. Proste wytłumaczenie, zawiść o kasę, nie wytrzymuje starcia z rzeczywistością. Moim zdaniem dupa redaktora boli o coś trochę innego.
Otóż zapewne z okazji n-lecia matury albo innej okazji okazało się, że klasowa łamaga, osobnik będący pośmiewiskiem i obiektem różnych wrednych żartów (notabene dziś podpadających pod zwykłe znęcanie się) przytoczył się własnym, wypaśnym samochodem (może było to Camaro ;) ), a przy okazji różnych dyskusji okazało się, że kredyt mieszkaniowy już dawno się spłacił i stu metrowy apartament jest “mój i tylko mój”.
Jakże to, żeby taki jebany kuc, co piłki prosto kopnąć na wf-ie nie potrafił. Kujon pierdolony zarabiał lepiej niż ja – klasowa “elytka”. Cóż worek maści na ból dupy dla pana redaktora.
Ale tego nikt oficjalnie nie powie, bo przecież my, pokolenie urodzone gdzieś tam w okolicach stanu wojennego, zawistni nie jesteśmy. I to niezależnie czy prawaki czy lewaki :)

W tekście zaszyte jest jeszcze coś. Swoista wisienka na gówno-torcie. Otóż wypowiedź Filipiaka. Jak to źle, że mu “chłopaków” podkupywali. Tego samego Filipiaka, co to rzucił iż

Każdego wykwalifikowanego programistę da się zastąpić skończoną liczbą studentów

I w którymś z kolejnych wywiadów dorzucił iż liczba ta to “zazwyczaj jeden”. Jeżeli ktoś traktuje wysoko wykwalifikowanych specjalistów jak roboli od łopaty to niech się nie dziwi iż mu uciekają. Ludzie mają swoją godność i nie będą przed byle prezesiątkiem tańczyć jak im zagra.

Mówiąc prościej i tak by nasza biznesklasa zrozumiała. Jeżeli traktujecie programistów i ogólniej dział IT jak roboli to spierdalajcie na drzewo. Krzyż wam w dupę i chuj w plecy.

Tekst 2

Wielki powrót. Tekst chyba miał na celu pokazanie, że programiści rzeczywiście są zepsuci. Pokazał jednak, że Polska to “dziki kraj”. Kraj w którym nie płacenie faktur jest OK, że olewanie ludzi też jest OK. Zatem w cenę trzeba wliczyć swoiste ubezpieczenie od niezapłaconych faktur.
Mamy tu jednak jeszcze kilka innych fajnych aspektów. Pierwsza to “odkrycie” iż IT to biznes globalny. Dosłownie globalny. Ze względu na swój charakter nie ma znaczenia czy pracownik siedzi w Polsce, Bangalore, Singapurze czy też w Nowym Jorku. Dla klienta liczy się dostarczony produkt. W mniejszym stopniu to czy telekonferencja będzie zrobiona rano czy wieczorem. Oczywiście są pewne granice przyzwoitości jeśli chodzi o odległość liczoną w strefach czasowych. Choć i to można zazwyczaj jakoś ogarnąć.
Z globalizacji wychodzi też kolejna rzecz. Zarobki. Skoro programista w Palo Alto może krzyknąć 100 dolarów za godzinę to czemu ja we Wrocławiu nie mogę? Korzystam z tego i mam bonus w postaci niskich kosztów życia w porównaniu z USA. Zatem moje zarobki są jeszcze wyższe (szczególnie gdy porównamy je na zasadzie jeden do jeden z np. zarobkami pismaka). Oczywiście są też programiści za 8 dolców za godzinę…
… bo programistom płaci się za wiedzę, doświadczenie i umiejętności. Nie tylko za bycie zajebistym.
Ostatnia rzecz o której wspomnę w odniesieniu do tego tekstu, a która już została poruszona to sposób pracy i rozliczeń. Pomimo, że statystyki pokazują iż w IT “zatrudnia się na etat”, to tak naprawdę ogromna ilość programistów rozlicza się w oparciu o umowy cywilnoprawne lub fakturę. Tym samym nasza “arystokracja” należy do grona mikroprzedsiębiorców tak kochanych w naszym państwie i pracowników “na śmieciówkach” (tu kolejny tekst z Filipiaka – on też pracuje na śmieciówce). Etaty w IT są zarezerwowane dla specyficznej grupy pracowników.

Tekst 3

Dobry, ale szkoda iż wyglądał jak pierdololo działu HR. Serio, serio. Lecz i tu mamy kilka smaczków. Smaczek pierwszy to etaty. Występują przede wszystkim tam gdzie klientowi zależy na tworzeniu własnych szytych na miarę rozwiązań, czyli w korpo. Pracowników kontraktowych zatrudnia się na zasadzie ludzi od brudnej roboty. Ekspertów od babrania się w gównie. Względnie do wykonania bardzo konkretnych zadań, które pozwalają polepszyć jakość produktów, a nie wymagają stałej pracy np. w celu przeprowadzenia specyficznych prac optymalizacyjnych.
Trochę ten świat etatowego programisty poznałem i wiem, że to tak musi działać. Wiedza kluczowa dla organizacji musi zostać w jej ramach. UoP jest tu świetnym rozwiązaniem. Pracownik w zamian za stabilność i całkiem niezłą kasę dostaje prikaz by gromadzić i przekazywać wiedzę o produktach kolejnym pokoleniom. Ma też możliwość awansu w strukturach firmy w przeciwieństwie do kontraktora. Tym by osłodzić życie “wiecznego robola” płaci się jeszcze więcej :) Jednocześnie jak wspomniałem dostają do robienia rzeczy, których pracownicy wewnętrzni nie mają ochoty ruszać.
Kolejna sprawa to olewanie działów IT na każdym etapie. Począwszy od rekrutacji, poprzez niesłuchanie opinii IT o możliwościach rozwoju oprogramowania i jego ulepszania, a kończąc na zwalaniu przez biznes na IT wszelkich swoich niepowodzeń.
Jest też w tym tekście mowa o starych technologiach. Tu rzecz ma się trochę inaczej. Mateusz Kurleto nie ma racji pisząc, że biznesowi nie zależy na “nowoczesności”.

Proponuję zastanowić się nad innowacyjnością technologii, które wykorzystywane są lata po tym jak producenci wycofują wsparcie a migracje na nowe wersje (nie wspominając o następcach) są niemożliwe do wywalczenia.

Wiesz z czego to wynika? Ano z tego, że technologie te są stabilne. Nikt, w żadnym banku, domu maklerskim czy instytucji ubezpieczeniowej nie pozwoli sobie na wprowadzenie czegoś co nie jest stabilne. Dlatego też do wyliczania obciążeń inżynierowie nadal używają FORTRANa, dlatego w bankach na zachodzie hula COBOL. Kod się nie zużywa. Po 20 latach można założyć iż naprawiono w nim wszystkie bugi, a te które pominięto są znane i uwzględnione w procesie.
Motywacja do zmiany w przypadku tego typu organizacji jest jedna – specjaliści idą na zasłużone emerytury.

Moje zdanie

IT to bardzo specyficzna branża. Szczególnie współczesne, które wyrwało się z okowów informatyki-nauki. Dziś programistą może zostać każdy. Masz komputer to możesz programować. Nie trzeba kończyć studiów ani zdawać państwowego egzaminu. Po prostu musisz się trochę pouczyć…

… no właśnie nie takie trochę. Programiści to specyficzni ludzie. Ci, który trafiają to naszego grona tylko ze względu na kasę bardzo szybko są eliminowani. W sumie to sami się eliminują, bo być programistą to stan umysłu. Mało kto z osób nie związanych z tym fachem zdaje sobie sprawę ile poświęcenia wymaga ten zawód. Tu nie liczy się przebojowość ani uroda. Tu liczy się ciężka praca. Praca nad sobą. Ta wymaga samodyscypliny, “ogarnięcia”, pokory. Tu trzeba po porostu zapierdalać.
Jak rozmawiam ze znajomymi z IT to przez wiele lat głównym problemem w życiu było to jak magazynować książki. Później pojawiły się czytniki. To ułatwiło nam życie.
Programiści są chyba jedyną poza lekarzami grupą zawodową, która musi stale się uczyć. Nie mówię tu o czytaniu i poszerzaniu wiedzy dla przyjemności. Tylko o zwykłej nauce. Dziennikarz może położyć lachę na książki wraz z odebraniem dyplomu. Inżynier może całe życie projektować silniki bez potrzeby sięgania po literaturę fachową. Programista do końca swojego zawodowego życia musi się uczyć.
Pracowałem z ludźmi, którzy do emerytury mieli bliżej niż ja stażu. Nadal się uczyli. Nadal chodzili z nami na szkolenia i nadal czytali różne książki z zakresu IT. Ciągle poszerzali swoją wiedzę. Wyobraźcie sobie gościa lat sześćdziesiąt kilka, który jak uczniak siedzi w ławie, słucha wykładu i robi notatki. Później jak wróci do domu to grzecznie przerabia jeszcze raz cały materiał. Inaczej się nie da.
Wysokie zarobki są nie tyle co nagrodą co po prostu rynkową wyceną zgromadzonej przez nas wiedzy. Bardzo często nie tylko o komputerach, ale też o różnych innych dziedzinach życia. Programista poza wiedzą fachową zdobywa też wiedzę “biznesową”. Bez tego nie będzie wstanie pisać dobrego kodu. Bez tego też nie spełni wymagań klienta. Programowanie komputerów to naprawdę ciężki fach i jeżeli ktoś mówi, że programistom się w dupach poprzewracało to niech po prostu odwoła się do słów Lecha Wałęsy

Sprzątaczce należy się więcej niż dyrektorowi, bo ona więcej potu daje.

Ale by przytoczyć te słowa trzeba wcześniej przeczytać trochę więcej niż to co polecił przeczytać profesor przed kolokwium.

Najpopularniejszy język świata…

June 5th, 2014

… to COBOL. Zdziwieni? Jak wam powiem, że 80% kodu napisanego na świecie jeszcze kilka lat temu było napisane w COBOLu to będziecie jeszcze bardziej zdziwieni :)

Ok, ale nie o tym chciałem. Otóż łapię się ostatnio, że niektóre rzeczy łatwiej jest mi napisać w COBOLu niż w Javie. Nie jest ich dużo, ale mają pewną swoją specyfikę i idealnie wpasowują się w COBOLa.

By nie być gołosłownym mały przykład.

Jaś został deportowany z USA z powodu pracy na czarno. Przybył nad Wisłę mając w kieszeni 5 dolarów. Jako, że za kilka dni wyrusza na truskawki do Hiszpanii postanowił je wymienić na euro. Po drodze chce jeszcze coś zjeść w kraju więc musi dokonać przeliczenia USD>PLN>EUR. Pomóżmy Jasiowi policzyć ile będzie miał na każdym etapie operacji.
Kursy (dzisiejsze)
1 EUR 4,1215
1 USD 3,0275

Program w COBOLu będzie wyglądał tak:

Listing 1. Przelicznik walut w COBOLu

IDENTIFICATION DIVISION.
PROGRAM-ID. PRZELICZNIK-WALUT.
DATA DIVISION.
WORKING-STORAGE SECTION.
    01 kEUR PIC 9V9999 VALUE 4.1215.
    01 kUSD PIC 9V9999 VALUE 3.0275.
    01 PLN PIC 99V99 VALUE ZERO.
    01 EUR PIC 99V99 VALUE ZERO.
    01 USD PIC 99V99 VALUE 5.
PROCEDURE DIVISION.
    DISPLAY "--- Przeliczam USD na PLN".
    MULTIPLY USD BY kUSD GIVING PLN ROUNDED.
    DISPLAY "Po przeliczeniu " USD " mam " PLN "PLN".

    DISPLAY "--- Przeliczam PLN na EUR".
    DIVIDE PLN BY kEUR GIVING EUR ROUNDED.
    DISPLAY "Po przeliczeniu " PLN "PLN mam " EUR "EUR".
STOP RUN.

A teraz zadanie dla was drogie misie. Napiszcie tak elegancko samo dokumentujący się kod w Javie.