Koniec Eldorado II

Maj 6th, 2016

Jakieś dwa lata temu brałem udział w dyskusji na liście warszawskiego JUGa. Po niej zacząłem popełniać tekst „Koniec Eldorado”, dlatego ten ma II w tytule. Tekstu nigdy nie dokończyłem, ale nie szkoda mi tego. Wtedy brakowało mi dobrych przykładów, które potwierdziły by moje przypuszczenia.

Niestety przykłady znalazły się szybciej niż sądziłem. Zastanawiam się czy to zalinkować, bo już raz przerabiałem temat świnek morskich. Z drugiej strony sprawa nie tyczy się tak mocno relacji między gatunkowych w branży… a tam… macie (leci przez t.co, bo bezpośrednio tego nie zalinkuję).

Jeżeli uważacie, że tekst jest za długi to wam go skrócę:

Biorąc pod uwagę oszczędność czasu (5 lat studiów a miesiąc) oraz skuteczność nauki (studiowanie informatyki nie jest równoznaczne z umiejętnością programowania), pieniądze zwracają się bardzo szybko.

Zatem po miesięcznym szkoleniu mamy oto gotowego programistę, którego wykop nazywa „programistą za 15k miesięcznie”, serio mamy taki tag. Przerażająca jest ta pewność siebie bijąca od tego typu ludzi. Trochę przypomina to:

Pewność siebie a doświadczenie

przy czym nie ma tu żadnego wypłaszczenia. Zostało ono zasypane pieniędzmi. Serio. Zarobki na pozycji juniorskiej to mniej więcej średnia krajowa. W kraju, gdzie mało kto dobija do średniej już w pierwszej pracy można dostać, w sumie górę mamuta.

Czytają takie teksty jak ten podlinkowany zastanawiam się, gdzie popełniłem błąd, bo po ponad 10 latach pracy w zawodzie, 15 latach usystematyzowanej nauki i jakiś 25 latach od momentu gdy napisałem pierwszy, prosty program nie mam nawet połowy tej pewności siebie… i nadal pozostaje pytanie o stawkę, ale to już inna sprawa. To jest jednak objaw zupełnie innej choroby.

To nie jest kraj dla konsultantów

Serio. Polski rynek IT stoi outsourcingiem. Jesteśmy tanią siłą roboczą. Oczywiście można powiedzieć, że Hindusi są tańsi, ale lepiej zapłacić trochę więcej za Polaka czy Ukraińca i mieć ten sam kod kulturowy niż płacić za Hindusa i jebać się z problemami komunikacyjnymi. Przy czym mała uwaga, są też i Hindusi, którzy są naprawdę dobrzy w te klocki. Tyle tylko, że oni dawno już przyjęli zachodni styl pracy i co za tym idzie zachodnie stawki. Jest też ich niewielu. W Polsce w praktyce nie ma za to rynku konsultantów. Próbujcie zatrudnić się w np. banku jako konsultant. Nie na zasadzie poprowadzę trzy czy cztery szkolenia w przeciągu miesiąca lub dwóch, ale właśnie jako konsultant. Osoba najęta do rozwiązania konkretnego problemu lub wsparcia konkretnych zespołów w ich zadaniach. To jest w praktyce niewykonalne. Jednocześnie te same instytucje zatrudniają w samym Wrocławiu kilka tysięcy programistów na zasadach outsourcingu. Tak, dobrze przeczytaliście, kilka tysięcy.

Firmy outsourcingowe to w ogóle ciekawy temat. Weź swoją stawkę dodaj do niej od 30 do 60%. Tyle firma kasuje za twoje usługi korporację. Przy czym te firmy zazwyczaj nie wytwarzają żadnych własnych produktów. Projekty własne ograniczone są do minimum i zazwyczaj związane z wewnętrznym zapotrzebowaniem na konkretne rozwiązania w rodzaju CRMy, CMSy, systemy HRowe. W efekcie firmy te wysysają z rynku programistów i przekierowują ich do lokalnych mordorów. A w mordorze oczywiście jest loteria, są projekty ciekawe, w których można się dużo nauczyć, a są i takie których nie ruszą nawet elbończycy. Zastanawiałeś się kiedyś skąd wzięła się nazwa ork? Od orki na ugorze w miejscowym mordorze. Rzecz w tym, ze tych ciekawych projektów jest naprawdę niewiele, a i większość z nich dostępna jest tylko dla „swoich”, a nie outsorcingu.

Dlaczego firmy decydują się na outsourcing?

Oczywiście dlatego, że jest to tanie rozwiązanie. Jeżeli jeszcze do tego dorzucimy niskie koszty pracy w takiej Polsce to okazuje się, że opłacalność tego procederu jest bardzo, ale to bardzo wysoka. Dodatkowo nie trzeba użerać się z konsultantami, czyli inaczej mówiąc nie zamiast stu, czy dwustu mamy jedną fakturę z kilkuset pozycjami. Dodatkowym atutem jest wyrzucenie procesu rekrutacji na zewnątrz. Czego efektem ubocznym są stanowiska seniorskie, na które wymagane są dwa, trzy lata doświadczenia.

Jest duże zapotrzebowanie, nie zbiedniejemy

To jest dobry argument. Można powiedzieć, że skoro w Polsce brakuje jakieś 50 tys. programistów, to bieda nam nie grozi. Dziś nie. Jutro też zapewne nie, ale biednienia już się zaczął i przypadki opisane na początku tylko go przyspieszą. Proces obniżania stawek już się zaczął i choć na razie nie jest jeszcze aż tak widoczny i bolesny, to się to dzieje.

Ja tu ciągle o kasie, ale w praktyce będzie to tylko wynik spadku jakości. Jakoś nie mogę się przekonać, że jak usadzę koło siebie osobę po miesięcznym kursie i świerzaka po studiach, przy założeniu, że oboje potrafią klepać kod na podobnym poziomie, zadam im typowe zadanie to osoba po kursie zrobi to lepiej. Jednak studia to nie tylko nauka programowania, bo z tym bywa różnie, ale przede wszystkim nauka myślenia w specyficzny sposób. Sama biegłość w klepaniu kodu to nie wszystko.

BTW, dopiero od niedawna zaczyna mi się przydawać znajomość matematyki ze studiów przy opisywaniu problemów i rozwiązań. Umiejętność przełożenia problemu na formalny język to jedna z tych rzeczy, które można wynieść ze studiów, bo tylko tam uczą tego języka. Na miesięcznym kursie klepania kodu nie powiedzą ci czym jest algebra ani nie wytłumaczą jak działa tranzystor czy bramka logiczna. Czy ta wiedza jest przydatna? Czasami jest. I to czasami zazwyczaj objawia się silną presją czasu oraz dużą ilością bluzgów.

Oczywiście spadek jakości będzie niezauważalny dla klienta. Kod ma to do siebie, że jest pewną abstrakcją. Nie można patrząc na działającą aplikację powiedzieć nic o samym kodzie. Nie określimy czy jest on dobry, czy zły. Klient zobaczy produkt, który zdaje się spełniać wymogi. Jednak czy w środku mamy materiał wysokiej jakości czy też szpachlowany paździerz? Kto wie… Do czasu, gdy nie trzeba będzie czegoś dopisać, poprawić, czy zmienić. Wtedy zacznie się bal. Koszty zaczną rosnąć, a jakość zacznie spadać w sposób widoczny dla samego klienta. Tyle tylko, że wtedy będzie już za późno na ratunek. By zatrudnić profesjonalistę, który to ogarnie będzie stać tylko duże i bogate firmy. Te mniejsze i dysponujące skromniejszymi budżetami będą ratować się za pomocą doraźnych napraw. W efekcie będziemy mieli coraz więcej coraz gorszego kodu.

Tu wrócę na chwilę do prezentacji Grzegorza Godlewskiego z tegorocznego DevCrowda. Jako przykład naprawdę złego kodu pokazał nam stronę pewnego producenta mebli. Stronę, która przy naprawdę solidnym łączu ładowała się minutę. Jak zaczynałem pracę wiele lat temu, to zakładaliśmy, że strona z dużą ilością grafiki nie może ładować się dłużej niż kilka sekund i to przy łączach w rodzaju 256kbit…

Te, Kasandara…

Możecie mi zarzucić, że pesymistycznie patrzę na problem. Rzecz w tym, że porównałem naszą sytuację z sytuacją innych zawodów, które przeszły już przez podobny proces.

Programowanie ma to do siebie, że jedynym progiem wejścia jest tak na prawdę kasa. Wystarczy, że masz komputer, najlepiej maca, bo drogi, i zapłacisz za miesięczny kurs programowania. Pieniądze nie są problemem, bo mamy dotacje.

Przeczytaj powyższy ustęp i zamień programowanie na grafikę komputerową albo fotografię. Łapiesz? W Latach 90-tych zapotrzebowanie na profesjonalnych grafików i fotografów było ogromne. Rynek reklamy był wstanie wchłonąć w praktyce dowolną ilość specjalistów z tych dziedzin. Podobnie rzecz miała się z tzw. copywriterami, czyli osobami odpowiedzialnymi za hasła reklamowe (w ogromnym uproszczeniu). Stąd też w czasach gdy chodziłem do liceum na co drugim słupie wisiały ogłoszenia szkół fotografii i grafiki komputerowej. Później już nawet nie trzeba było robić kursu, bo prasa i internet zapewniały odpowiednie materiały w postaci tutoriali oraz pirackiego photoshopa. Jak to się skończyło? Ano skończyło się tak jak opisano tutaj. Nieszczególnie dobrze. Oczywiście są firmy i osoby dobre, a nawet bardzo dobre, ale takich jest naprawdę niewiele.

Co więcej tego typu proces dotyka nie tylko zawody o niskim progu wejścia (kasę możemy wziąć z dotacji, pamiętajcie). Jeszcze kilkanaście lat temu prawnik po aplikacji był w stanie w przeciągu 3 do 5 lat odłożyć pieniądze na zakup mieszkania… za gotówkę. Dziś bezrobotny prawnik nie jest niczym szczególnym. Stawki spadły drastycznie, a przecież ilość pracy, podobnie jak w IT, nie zmniejszyła się. Wręcz przeciwnie. Zauważmy, że mówimy o zawodzie, w którym mamy wysoki próg wejścia. 5 lat studiów, 3 lata aplikacji albo doktoratu (tu nie jestem pewien) by uzyskać uprawnienia. Ogromna ilość wiedzy do przyswojenia. W sumie gigantyczna inwestycja, która nie zwraca się. Co więcej pracę prawnika klient jest wstanie ocenić. Zarówno w prost – wygrane sprawy, minimalizacja kosztów spraw przegranych jak i pośrednio choćby poprzez ilość wyprodukowanego papieru.

Podsumowanie

Obawiam się nie tyle co partaczy, co ich produktów. Oczywiście bycie wykształconym programistą nie daje gwarancji, że nie popełnimy błędów. Jednak proces kształcenia jest dobrą lekcją pokory. W przeciągu miesięcznego kursu nie uświadomimy sobie jak niewiele potrafimy. Jeżeli do tego dodamy stosunkowo duże, w proporcji do średniej, pieniądze, to efekt będzie opłakany.

Nie twierdzę, że ten proces będzie szybki. Takie rzeczy nie dzieją się z dnia na dzień, ani z miesiąca na miesiąc. Choć patrząc na prawników cały proces zajął niewiele ponad cztery lata. Nie twierdzę też, że potrzeba jakiegoś procesu regulacji w dostępie do zawodu. Nie ma większego sensu, ponieważ charakter pracy jest taki iż nie będzie można tego wyegzekwować. Zresztą samo środowisko przez lata potrafiło bronić się przed tego typu działaniami, bo nawet systemy certyfikacji nie są uznawane za miarodajne.

Jedyne co pozostaje to nadzieja, że to wszystko przynajmniej jakoś widowiskowo jebnie.

Dobry, zły i brzydki, czyli kolejna wersja retro

Maj 5th, 2016

Retrospektywa na koniec sprintu to punkt obowiązkowy, każdego porządnego zespołu korpoagilowego. Czym jest zespół korpoagilowy?

KorpoAgile

Takie zespoły działają zazwyczaj w ekstremalnie nieprzyjaznym środowisku. Jeżeli dodatkowo są tylko częścią większego projektu prowadzonego według starego dobrego waterfalla to muszą radzić sobie z problemami, które w normalnej sytuacji nie istnieją. Dlatego, też uważam, że typowe „retro” nie jest dla nich odpowiednim podejściem. Przez typowe rozumiem takie retro, które opiera się na trzech pytaniach dotyczących omawianego przedziały (sprint, release, itp.) w kontekście zespołu:

  • Co było dobre?
  • Co było złe?
  • Co możemy poprawić, zmodyfikować by było lepiej?

W przyjętym przeze mnie podejściu ogólna metoda działania jest bardzo podobna, ale skupia się na elementach pochodzących z zewnątrz. Dlatego też nie powinno ono być stosowane za każdym razem. Raczej jak warstwa korpogówienka będzie już widoczna, ale jeszcze nie zastygnie, by być trudną do usunięcia. Zanim przejdziemy do szczegółów jeszcze jedna uwaga. Może zdarzyć się tak, że po spotkaniu będziemy mieli bardzo negatywne i jednocześnie agresywne nastawienie do otoczenia. To nie jest nic złego. Nic nie wkurwia bardziej niż procedurki, papierki, tabeleczki, raporciki i podobne zdrobnienia. BTW, wiecie, że osoby chore na raka bardzo często wiedzą, jaka jest diagnoza, zanim zobaczą papiery, ponieważ personel medyczny zaczyna używać zdrobnień w stosunku do dokumentacji i procedur? Taki myk.

Nie należy jednak dawać po sobie, jako zespole, poznać, że najchętniej byśmy całe korpo potraktowali napalmem. Zemsta najlepsza jest na zimno, a jeszcze lepsza, gdy dokonamy jej narzędziami samej korporacji.

Przygotowania

Oczywiście do retro należy się przygotować. Poza bezpośrednimi przygotowaniami warto przez pewien czas zbierać „haki” na otoczenie zespołu. Nie działają wirtualki – ticket w Jirze + dokładne trackowanie czasu przestoju. Nieaktualna biblioteka powoduje problem, ale procedura nie pozwala na aktualizację – ticket + podpinanie do niego wszystkich powiązanych problemów. Poganiacz ma jakieś chore pomysły – mail z kulturalną informacją, do czego doprowadzi jego niedojebanie mózgowe.
Działa to też w drugą stronę. Należy stworzyć listę spraw rozwiązanych i załatwionych.

Dobry

Zaczynamy od miłych rzeczy. Lista spraw, które udało nam się rozwiązać albo załatwić. Najistotniejszym elementem tej części jest omówienie, JAK zostało to osiągnięte. Dobrze by efektem było pojawienie się krótkiej listy procedur, które były nam pomocne. Każda korporacja ma swoje procedury. Dużo procedur i nie sposób znać je wszystkie. Zatem warto dzielić się odkryciami w tym zakresie. Przykład z życia – kilku nowych pracowników miało nieprawidłowe adresy email. Pomylone imiona, nazwiska itp. Okazało się, że można to naprawić za pomocą procedury „ślubnej”, bo ta dotyczyła aktualizacji danych w związku z ich zmianą po ślubie. Odkrycia tego dokonał zespół dopiero po tym, jak jedna z koleżanek wzięła ślub, a w geście rozpaczy jeden z „nowych” napisał do kadr z pytaniem, czy jak on weźmie ślub, to też mu poprawią dane.

Zły

Złe rzeczy przytrafiają się każdemu. My jednak chcemy odszukać i jak najszybciej wyeliminować te zmiany, które nastąpiły w otoczeniu i mają bezpośredni wpływ na nasz projekt. W tej części ważne jest określenie natury problemu. Niektórych rzeczy nie przeskoczymy. Jeżeli zmiana jest na wysokim szczeblu i dotyka całego ustroju firmy, to trudno będzie z tym walczyć. Można jednak skupić się na wszystkich tych elementach, które w jakiś sposób bezpośrednio nas dotykają. Moim ulubionym przykładem jest tu hasło idące od PM ze strony klienta „wrzućcie to na produkcję, to jest polecenie służbowe”. Do tego worka trafią też wszystkie inne rzeczy, które były jawnym złamaniem ustalonych zasad. Na koniec tworzymy listę rzeczy, które trzeba koniecznie naprawić.
W niektórych przypadkach naprawa oznacza napisanie dupokrytki, a w innych zmianę procedur wewnątrz zespołu tak by tego typu „atak” można było łatwiej odeprzeć. Warto też wydzielić zdarzenia, które powodowały, iż pojawiały się opóźnienia. Następnie tworzymy listę uporządkowaną według pilności. To są rzeczy do zrobienia na już.

Brzydki

W tej kategorii lądują wydarzenia systemowe, ale też wszelkie propozycje, które mogą mieć zły wpływ na projekt, a nie są jeszcze pewne. W ich przypadku należy przedyskutować zagrożenia i wypracować wspólne stanowisko. Ważne jest ,by dobrać też odpowiednie metryki, które w razie czego pozwolą na negocjację, a w ostateczności na wykazanie, że nie my zjebaliśmy.
Oddzielną grupę stanowią usprawnienia. Czasami mamy możliwość dokonania pewnych zmian na styku zespół-korporacja. Takie rzeczy też powinny znaleźć się na tej liście. Oczywiście wyposażone w odpowiednie metryki i uzasadnienie.

Podsumowanie

Tego typu retrospektywa dobrze sprawdza się, gdy chcemy w jakiś sposób ustalić „interfejsy” pomiędzy zespołem a otoczeniem. Zespoły IT mają już to do siebie, że nie za dobrze wpisują się w sztywne ramy korporacyjnych procedur. Dodatkowo jakość ich pracy w ogromnym stopniu zależy od czasu, w jakim pojawia się informacja zwrotna. Istotną różnicą jest też abstrakcyjność pracy, która w połączeniu z ponadprzeciętnymi zarobkami, jest polem do popisu dla różnego typu niedojebanych PM średniego szczebla. Szczególnie wtedy, gdy trzeba zrzucić na kogoś odpowiedzialność.

Mając w zanadrzu odpowiednie argumenty, które zespół przygotował wcześniej, może on obronić się przed tego typu atakami. Z agile jak z ciążą albo jest w całej organizacji, albo go nie ma. Pojedyncze zespoły prowadzone w ten sposób, szczególnie w firmach nie technologicznych, zawsze będą musiały bronić swojego podejścia.

Idąc przez Kotlinę w doborowej kompanii

Maj 4th, 2016

Czyli o obiektach towarzyszących w Kotlinie sobie dziś porozmawiamy. Nie od dziś wiadomo, że jak mamy jakiś problem z Javą to rozwiązaniem jest stworzenie ProblemFactory, która będzie zawierać statyczną metodę create. Kończymy z całą dzielnicą przemysłową w naszym kodzie. Nie to, żeby fabryki były złe. One są dobre, a nawet powiem więcej, one są bardzo sensowne, jeżeli tylko korzystamy z DDD w naszym projekcie. Dlaczego i po co to już osobna kwestia i dziś nie będę tego omawiać.

Trochę innym zagadnieniem są klasy narzędziowe, które posiadają całe litanie metod statycznych. Rzecz w tym, że w Kotlinie nie ma metod statycznych. Ich rolę przejmują właśnie obiekty towarzyszące… tak, wiem „taka debilna scala i po co nam to”…

Definiowanie

By zdefiniować obiekt towarzyszący, musimy umieścić go w klasie, której ma towarzyszyć oraz użyć słowa kluczowego companion:

Listing 1. Obiekt towarzyszący

class MyService{

    private constructor()

    companion object {

        fun create(): MyService = MyService()
    }
}

W ten sposób zdefiniowaliśmy najprostszy obiekt towarzyszący. Ma on domyślną nazwę Companion, ale oczywiście możemy używać własnych nazw. Tylko po co skoro rzadko będziemy odwoływać się do niej bezpośrednio z kodu?

Użycie

Jak już o użyciu to w trakcie kompilacji zostaną wygenerowane odpowiednie metody, które zostaną dołączone do naszej klasy. Zatem można napisać:

Listing 2. Użycie obiektów towarzyszących

fun main(args: Array<String>) {
    MyService.create();
}

I będzie to działać poprawnie. Rzecz w tym, że nie z poziomu javy nie będą one widoczne. Technicznie klasa MyService będzie mieć tylko pole Companion, za pomocą którego będziemy odwoływać się do metody create. Niby ok, ale można by to jakoś uprościć. W tym celu należy dodać adnotację @JvmStatic do metody, która zostanie wygenerowana w klasie serwisowej:

Listing 3. Obiekt towarzyszący z delegacją

class MyService{

    private constructor()

    companion object {

        @JvmStatic
        fun create(): MyService = MyService()
    }
}

Oczywiście obiekt towarzyszący to nadal normalna klasa, a zatem możne ona implementować interfejsy:

Listing 4. Obiekt towarzyszący implementujący interfejs Factory

interface Factory<T>{

    fun create():T
}

class MyService{

    private constructor()

    companion object :Factory<MyService>{

        override fun create(): MyService = MyService()
    }
}

Kod jest poglądowy i nie należy w ten sposób robić fabryk, ale chodzi tu o samą mechanikę związaną z implementacją.

Podsumowanie

Obiekty towarzyszące są w pewien sposób lepszym podejściem do kwestii statycznej zawartości w klasie. W Kotlinie ich implementacja jest bardzo prosta i intuicyjna. Bez większych przeszkód można ich używać. Zapewnienie współpracy z kodem w Javie też nie jest uciążliwe. Same plusy.

Jak napisać takeWhile w Javie 8

Maj 3rd, 2016

W Javie 9 będzie to dostępne od ręki, ale w ósemce trzeba się trochę nagimnastykować. O co dokładnie chodzi? Przyjrzyjmy się prostemu programowi:

Listing 1. Przykładowy program

public class App {

	public static void main(String[] args) {
		Scanner console = new Scanner(System.in);
		Stream.generate(() -> console.nextLine())
				.limit(10)
		.forEach(System.out::println);
	}
}

Czytamy wartość z konsoli i wypisujemy ją na konsolę. Typowe zadanie z ćwiczeń na wielu uczelniach… ciekawe czy takie rozwiązanie by przeszło 😉 Problem polega na tym, że w tym przypadku liczba wczytanych wartości jest równa 10. W ogólniejszej wersji chcielibyśmy, aby wczytywane było kontynuowane do momentu podania konkretnej wartości w rodzaju exit, czy pustej linii. Inaczej mówiąc:

Listing 2. Przykładowy program II

public class App {

	public static void main(String[] args) {
		Scanner console = new Scanner(System.in);
		Stream.generate(() -> console.nextLine())
				.takeWhile(s-> !s.isEmpty())
		.forEach(System.out::println);
	}
}

Powyższy kod zaskoczy w Javie 9, ale w Javie 8 (bez dodatkowych bibliotek) już nie. Nie za bardzo możemy też bez większego paprania się z AspectJ dodać taką metodę do interfejsu Stream. Pozostaje nam stara dobra klasa narzędziowa/interfejs narzędziowy. To co chcemy uzyskać to kod w postaci:

Listing 3. Program z takeWhile

public class App {

	public static void main(String[] args) {
		Scanner console = new Scanner(System.in);
		takeWhile(
				Stream.generate(() -> console.nextLine())
				, s -> !s.isEmpty()
		)
				.forEach(System.out::println);
	}
}

Czyli mamy metodę takeWhile, która przyjmuje jakiś Stream i predykat, który będzie go ograniczać. Przystąpmy więc do implementacji:

Listing 4. Implementacja takeWhile

class TakeWhile {

	public static <T> Stream<T> takeWhile(Stream<T> in, Predicate<T> condition) {
		Spliterator<T> inSplit = in.spliterator();
		return StreamSupport.stream(
					new Spliterators.AbstractSpliterator(inSplit.estimateSize(), 0) {
						private boolean isGoing = true;

						@Override
						public boolean tryAdvance(Consumer action) {
							if (isGoing) {
								boolean next = inSplit.tryAdvance(e -> {
									if (condition.test(e))
										action.accept(e);
									else
										isGoing = false;
									});
								return next && isGoing;
							}
							return false;
						}
					}
					, false
			);
    }
}

Na początek z naszego wejściowego strumienia bierzemy Spliterator. Na jego podstawie tworzymy nowy strumień. I teraz cała zabawa dzieje się w metodzie tryAdvice. Jeżeli isGoing jest prawdziwa, czyli strumień zawiera kolejny element, to wywołujemy tryAdvice na wejściowym strumieniu (za pośrednictwem spliteratora), przekazując specyficznie przygotowanego Consumera. Najpierw sprawdza on warunek i jeżeli ten pasuje to wywołuje oryginalną akcję. Jeżeli nie, to oznacza iż osiągnęliśmy kres naszego strumienia – warunek nie jest spełniony i ustawiamy isGoing na false. Następnie zwracamy sumę z wywołania tryAdvice na wejściowym strumieniu i isGoing. Suma ta pokrywa przypadek gdy wejściowy strumień nie ma już elementów, ale nasz warunek jest spełniony. W razie czego zwracamy false, ale to nie powinno się zdarzyć i praktycznie jest informacją dla obsługujących strumień, że nie ma w nim już żadnych elementów.

Kod co prawda nie jest piękny, ale spełnia swoje zadanie. Kolejne kroki mogą polegać na wyciągnięciu fragmentów tego algorytmu do mniejszych klas, dodaniu zabezpieczeń na przypadek uruchomienia w wielu wątkach itp. Jednak na chwilę obecną wystarczy.

Klasy zapieczętowane w Kotlinie

Maj 2nd, 2016

Strasznie skaczę po tematach jeśli chodzi o Kotlina, ale lepiej jest wybrać kilka fajnych rzeczy i je opisać niż lecieć materiał w postaci „35 część tutoriala”. Dziś na tapecie klasy zapieczętowane, czyli oznaczone jako sealed.

Definicja takiej klasy jest prosta:

Listing 1. Klasa zapieczętowana

sealed class Expr

Zabawa zaczyna się jednak w momencie gdy przyjrzymy się znaczeniu słówka sealed. Domyślnie w Kotlinie wszystkie klasy są finalne. Nie można ich rozszerzać. Podobnie ma są sprawa z klasami zapieczętowanymi z tą różnicą, że rozszerzanie jest dopuszczalne tylko wtedy gdy klasa dziedzicząca jest klasą wewnętrzną:

Listing 2. Rozszerzanie klasy zapieczętowanej

sealed class Expr{
   class Const(val number:Double) : Expr()
   class Sum(val l:Expr, val r:Expr) : Expr()
}

class Mult(val l:Expr, val r:Expr) : Expr() // to się wywali

I tradycyjnie już tego typu konstrukcje mają zastosowanie we wszelkiego rodzaju parserach i interpreterach:

Listing 3. Użycie klasy zapieczętowanej

fun eval(expr: Expr) :Double = when(expr){
    is Expr.Const -> expr.number
    is Expr.Sum -> eval(expr.l) + eval(expr.r)
}

fun main(args: Array) {

    println (eval(Expr.Sum(Expr.Const(1.0), Expr.Const(1.0))))
}

Oczywiście Kotlin w tym konkretnym przypadku nie zrobi magicznej sztuczki i przy długim wyrażeniu zabraknie mu stosu, ale cóż…

Podsumowując. Klasy zapieczętowane w Kotlinie pokrywają część zagadnień związanych z programowaniem w oparciu o typy. Jest weekend majowy więc nie bardzo mi się chce, ale mam do dokończenia większy tekst o tego typu pisaniu kodu w Javie. W każdym razie…

Jak zacząć zabawę z TDD od strony praktycznej

Maj 1st, 2016

TDD, czyli programowanie sterowane testami jest jedną z tzw. zwinnych praktyk programowania. Zazwyczaj, niesłusznie, ogranicza się testy do testów jednostkowych. Samo TDD nie definiuje z jakimi dokładnie testami pracujemy. Jednakże testy jednostkowe jako najprostsze do ogarnięcia są też uznawane za kwintesencję TDD.

Dziś chciałbym przedstawić wam pewien sposób pracy, który pozwala na lepsze przyswojenie sobie praktyki „test first”. Inaczej mówiąc jeżeli problemem jest dla ciebie pisanie najpierw testu potem kodu, to tu znajdziesz pomoc. Choć za rezultaty nie ręczę 🙂

Moja smutna historia

Gdy po raz pierwszy przedstawiono mi ideę TDD wydawał mi się banalnie prosta. Piszemy test, uruchamiamy go i mamy czerwono. Następnie piszemy kod do momentu, aż będzie zielono. Wtedy też piszemy kolejny test, który się zaczerwieni i dopisujemy kolejny „zieleniący” kawałek kodu. Zapętlamy. Po kilku obrotach dokładamy cegiełkę refaktoryzacji, by uprzątnąć plac budowy. Proste? Przynajmniej jak się to czyta. Takie podejście zwane „test first” jest bardzo dobre, bo pozwala na bieżąco kontrolować kod i wychwytywać co grubsze babole.

Problem z jakim się zetknąłem był jednak dość specyficzny, acz popularny. Java jako język statycznie typowany słabo znosi brak metod. W efekcie bardzo szybko zamiast pisania testu i skupieni się na tym co chcę wyrazić zaczynałem pisać metody. Jak zacząłem pisać metody, to wpadałem we „flow”, który powodował, że zaniedbywałem testy. Jak zaniedbałem testy, to później je dopisywałem tak by były ok. Z test first (TF) robiło się code first (CF). Najprostszym i najszybszym rozwiązaniem jest pisanie w parach. Dwa samce/samice zamknięte na małej przestrzeni (biurko) i zmuszone do współdzielenia zasobów (klawiatura) zaczną rywalizować. Jako, że jesteśmy ludźmi cywilizowanymi i do tego programistami, to nasza rywalizacja przeniesie się na poziom porównywania naszych umiejętności. W takim układzie oba samce/samice będą na wzajem się pilnować by robić dobrze kodowi, a każda okazja do wbicia szpili będzie bezwzględnie wykorzystywana. Jeżeli zamienimy parę na różnopłciową to zadziała mechanizm „jak ci mała pokażę jak to się robi” kontra „nie jestem taka durna chuju”. Efekt będzie taki sam.

Podejście kodowania w parach sprawdziłem w różnych konfiguracjach. Zazwyczaj działało. Jedynym warunkiem jest brak dużej różnicy umiejętności. W takim wypadku ze współpracy idziemy w kierunku nauczania, a to choć wartościowe dla obu stron, nie rozwiązuje problemu.

Co w przypadku gdy nie mamy możliwości kodowania w parze? Jak w tedy walczyć z problemem odchodzenia od test first? Po kilku latach zmagań z tym problemem mogę powiedzieć, że mam całkiem dobre rozwiązanie. W dodatku kompiluje się, działa i ma testy. Sprawdziłem je też w sytuacjach kryzysowych i wiem, że nawet osoba, która nie ma dużej wprawy w pisaniu testów spokojnie je będzie wstanie wdrożyć. Kluczem do sukcesu jest odpowiednia konfiguracja IDE.

Kod i testy – wygląd

Można powiedzieć, że jeżeli dobrze znamy swoje IDE to potrafimy od ręki rozwiązać połowę problemów, z którymi będziemy się mierzyć. W moim podejściu kluczem do sukcesu jest znajomość IDE i odpowiednie jego używanie. Gdy zacząłem analizować problem „dryfu z TF do CF”, to jedną z pierwszych rzeczy jakie zauważyłem była irytacja wynikająca z przeskakiwania pomiędzy testem, a kodem. Na początek należy zatem ograniczyć ilość tego typu skoków. Jednak same skoki nie są tak irytujące jak „wtrącenia”, czyli przejście do pliku, którego aktualnie nie używamy.

Po pierwsze zmniejsz masę

Jak piszesz kod i testy jednostkowe do niego (upraszczam, ale później uogólnimy), to zamknij wszystkie inne pliki w IDE. Jeżeli pozwala, to zamknij też inne okna. Niech nie będzie widoczne nic poza kodem. IntelliJ Idea i pochodne posiadają tryb pełnoekranowy:

TDD1

oraz „distraction free mode” (DFM):

TDD2

Jeżeli masz za małe literki powiększ je albo zamiast DFM użyj trybu prezentacji. Dzięki temu pozbędziesz się rozpraszaczy. Wadą DFM jest utrata powiększenia liter po zmianie pliku. Dlatego też osobiście preferuję tryb pełnoekranowy.

Po drugie poznaj IDE

W praktyce poznaj skróty klawiaturowe, które służą do nawigowania pomiędzy kodem i testami:

  • ctrl+shift+t – tworzy nową klasę testową albo pozwala przejść do testu z kodu. Jeżeli jesteś w klasie testowej i masz co najmniej jedną metodę testową to skacze do klasy testowanej.
  • ctrl+e – działa podobnie do alt+tab, ale nawiguje pomiędzy ostatnio otwartymi plikami.
Po trzecie wykorzystaj monitor(y)

IntelliJ Idea posiada takie magiczne coś jak podział ekranu pomiędzy dwa edytory. Najprościej zrobić to klikając PPM na tytule zakładki i następnie wybrać opcję Split Vertically:

TDD3

W ten sposób na jednym ekranie mamy na raz i testy i nasz kod. Ogranicza to uciążliwość skoków pomiędzy plikami. Jednocześnie lepiej wykorzystujemy powierzchnię ekranu. Dodatkowo „jakoś samo się tak dzieje”, że dbamy o to by nasze linie były krótkie. U mnie limit to 120 znaków z czego widoczne jest około 110. Standardem jest 80 znaków, ale już nie bądźmy tacy ortodoksyjni.

Kod i testy – działanie

Kolejna rzecz to uruchamianie testów. Jest to zazwyczaj możliwe jednym przyciskiem. Jeszcze lepiej jeżeli można to zrobić jednym skrótem klawiaturowym:

  • ctrl+shift+F10 – uruchamia testy z bieżącego pliku. Poprzedzony ctrl+shift+t w pliku z kodem pozwala na uruchomienie testów z poziomu kodu.
  • ctrl+F5 – powtarza ostatnie uruchomienie. Przydatne do powtórnego uruchamiania testów.

Jak już uruchomimy testy to nie zamykamy okna z wynikami. To ważne ponieważ, znowu, ogranicza to ilość gwałtownych zmian w wyglądzie obszaru roboczego. Ekran można jeszcze oczyścić w menu View (alt+v) wyłączając wszystkie paski narzędzi, nawigacji czy statusu (ten sobie zostawiam, bo lubię patrzeć na zajęty RAM):

TDD4

Podsumowanie

Na początku każdej większej zmiany najbardziej przeszkadzają drobnostki. Jesteśmy gotowi na „duże” problemy, ale to duperele nas wkurzają i zniechęcają. Dlatego też warto zacząć od eliminacji choć części z nich. Takie małe sukcesy pomagają nam też w kontynuacji pracy, bo czujemy, że coś zrobiliśmy.

Skończyły mi się wifecoiny, bo poszedłem na Code Forward

Kwiecień 30th, 2016

Na konferencje Code Forward poszedłem trochę pod wpływem impulsu. Raz, że znałem organizatorów, a dwa w środę kolega „namówił mnie” na warsztaty z Martinem Thompsonem, co poskutkowało masą pytań. Czas na ich zadanie był na afterpraty, które caluteńkie przegadaliśmy z Martinem jako jego groupies.

Co innego się działo?

Na dzień dobry Alister Cockburn „zjebał” świat za popsucie idei stojącej za Agile Manifesto. To co warto było zapamiętać z jego prezentacji to przypowieść o tym jak został trenerem Agile i w ramach przysposobienia do tej roli otrzymał listę podstawowych pojęć, które miał przedstawić… 180 sztuk. Do tego sam podział na Shu-Ha-Ri z dodatkiem Kokoro. Wytłumaczone tutaj.
Potem Dino Esposito w bardzo fajny sposób podsumował ideę DDD. Jeżeli przychodzi do ciebie BA i mówi, że kolejną historyjka do implementacji to „Klient kupił produkt” to w praktyce masz już API. Ważną rzeczą, którą ciężko ogarnąć w DDD jest to, iż model dla ORMa jest czymś innym niż model biznesowy. Dlatego też ważna jest warstwa pośrednia.
Po obiadku Cameron Fletcher opowiadał nam o Even Sourcingu i CQRS. Jakoś po prezentacji Grega Younga z przed kilku miesięcy ta nie zrobiła ma mnie jakiegoś dużego wrażenia. Następną rundę odpuściłem, a w praktyce zamieniłem na kawę na zimno w G Coffe Company. Polecamy tego pana. Na sam koniec oczywiście wykład Martina Thompsona o wysoko wydajnych aplikacjach w Javie. Ciekawe uzupełnienie warsztatów z czwartku.

I tyle. Na konferencji tradycyjnie już ubrałem się i doposażyłem mieszkanie – termokubeczeków i t-shirtów nigdy za wiele.

FaaS, czyli jak nisko możemy zejść z delegacją kodu

Kwiecień 29th, 2016

FaaS – Function As A Service, nie mylić z FAZW tudzież z FASW jest to usługa w ramach, której umieszczamy w chmurze nasz kod w postaci bezstanowych, czystych funkcji. Następnie karmimy je danymi i na wyjściu otrzymujemy wyniki. Możemy tworzyć małe funkcje w rodzaju f(A):B, f(B):C i następnie z poziomu interfejsu webowego budować potoki g(A):C = (f(A)→f(B)).

Warunkiem jest jedynie brak efektów ubocznych w naszym kodzie. W ten sposób można bardzo precyzyjnie skalować aplikacje i płacić jedynie za rzeczywistą moc obliczeniową, którą przepaliliśmy. Poza tym zyskujemy odcięcie od problemów związanych z koordynacją kodu, współbieżnością, synchronizacją. Jest sobie AWS Lambda, które zapewnia tego typu usługę. Jednak dostrzegam duże pole dla tych wszystkich organizacji, gdzie współdzieli się dużo kodu pomiędzy projektami. Dziś są to biblioteki. Może jutro będą to po prostu usługi?

W przyjaźni z maszyną – podsumowanie warsztatów z Martinem Thompsonem

Kwiecień 28th, 2016

Dawno nie dane mi było uczestniczyć w warsztatach, które były by tak wymagające. Miejsce na warsztatach z Martinem Thompsonem, autorem bloga Mechanical Sympathy udało mi się zarezerwować w ostatnim momencie. Wydałem na nie masę wifecoinów, ale było warto.

Nie będę rozwodził się nad przykładami, bo te bez solidnego wprowadzenia teoretycznego nie będą wiele warte. Wprowadzenie takie to w sumie całe warsztaty, a te trwały prawie 10 godzin. Chciałbym jednak napisać kilka słów o filozoficznej części spotkania.

Po pierwsze, jak piszemy kod nawet w Javie, która jest mocno odseparowana od krzemu, to warto przemyśleć to jak będzie on działać na poziomie procesora. Dobrze widać czemu musimy to zrobić na poziomie rozwiązywania konfliktu ArrayList kontra LinkedList. Obie te kolekcje mają swoją filozofię i przeznaczenie. Tak samo jest z hardwarem. Procesory są projektowane pod konkretne zastosowania. Nawet jak są to rozwiązania w rodzaju x86, które mają spełniać zachcianki różnego rodzaju klientów to twórcy, kierując się względami marketingowymi, będą preferować pewnego rodzaju kod. W przypadku x86 będzie to kod „liczący”, bo taki najczęściej jest spotykany w grach, a jak wiadomo głównymi odbiorcami topowego sprzętu są gracze.

Po drugie, wiele elementów w normalnej pracy programisty podlega tym samym zasadom co kod współbieżny. Jeżeli będziemy potrafili zastosować te zasady w naszej pracy to ułatwimy sobie życie. Nawet najprostsza praca z narzędziami typu git, jeżeli jest zorganizowana tak jak bylibyśmy osobnymi wątkami będzie wydajniejsza niż radosny chaos obecny w wielu zespołach.

Po trzecie warto na warsztatach wymieniać się wiedzą z innymi uczestnikami. Dzięki temu odkryłem narzędzie i7z, które na spółkę z htop świetnie się uzupełniają w temacie śledzenia tego co dzieje się w krzemie.

Podsumowując. Jutro konferencyjna część CodeForward, która też zapowiada się całkiem zacnie.

Znaki magiczne w kodzie elixirowym

Kwiecień 27th, 2016

Mała odskocznia od tematów JVMowych. Dziś przyjrzymy się mechanizmowi sigiliW w elixirze.

Czym jest sigil?

Wikipedia mówi, że jest to symbol utworzony do celów magicznych. I ta definicja całkiem ładnie wpisuje się w to co robią. Swoim zachowaniem przypominają interpolatory ze scali jednak są pomiędzy nimi drobne różnice, które jednak nie będą dla nas istotne (trochę inna składnia i duperele wynikające z różnic w języku). To co odróżnia sigile w elixirze od interpolatorów w scali to sposób w jaki obrabiany jest argument. Na przykładzie:

Listing 1. Interpretacja ciągu znaków

iex(3)> ~S"Napis #{1+1}"
"Napis \#{1+1}"
iex(4)> ~s"Napis #{1+1}"
"Napis 2"

Sigil, zapisany jako ~S lub ~s (ogólna konwencja ~ZNAK), będzie miał przekazany argument w zależności od wielkości znaku. Jeżeli zapiszemy go wielką literą, to string przekazany w argumencie nie będzie interpretowany. Jeżeli zapiszemy małą to sigil otrzyma już „wyliczony” argument.

Własne sigile

Tworzenie własnych sigili jest stosunkowo proste. By zachować porządek w kodzie warto wydzielić je do osobnego modułu:

Listing 2. Moduł z sigilami

defmodule SigilsExample do
  @moduledoc false

  import DateToString

  def sigil_m(string, []), do: Stream.zip(String.split(string, "@"), [:name, :domain]) |> Enum.to_list

  def sigil_l(string, []), do: IO.puts(string)

  def sigil_l(string, [t]), do: IO.puts( DateToString.date_to_string(:os.timestamp |>:calendar.now_to_datetime) <> "# " <> string)

end

zasada jest prosta funkcja, która jest ukryta pod sigilem nazywa się sigil_ZNAK. Elixir już samodzielnie dokona rozkminy potrzebnej do rozróżniania wielkości liter. Drugim argumentem jest lista dodatkowych parametrów. Pozwala to na sterowanie sposobem działania funkcji. Na powyższym przykładzie sigiel logujący ~l może dodawać aktualny czas gdy dodamy parametr t.

Użycie

To co przypadło mi do gustu w przypadku elixira to poza możliwością tworzenia własnych sigili to duża elastyczność w wykorzystaniu ograniczników dla ciągu znaków. Wszystkie poniższe zapisy są poprawne:

Listing 3. Różne zapisy sigili

defmodule LearnElixir do
    import SigilsExample

    def main() do
      ~l"log"t
      ~l'log't
      ~l/log/t
      ~l|log|t
      ~l<log>t
      ~l{log}t
      ~l[log]t
      ~l(log)t
    end
end

Pozwala to na wytworzenie pewnych konwencji tak jak w przypadku zapisu wyrażeń regularnych z użyciem slashy r/WYRAŻENIE/ig.

Elixir generalnie jest całkiem fajnym językiem, który daje dużo możliwości i pozwala „uciec” z JVMki.


Translate »