Czas Mavena minął

Aż ciężko uwierzyć, jak mocno ludzie potrafią trzymać się rozwiązań, które kiedyś podbijały rynek i ułatwiały życie, a obecnie są już tylko groteskowym reliktem przeszłości i hamulcem rozwoju. Japończycy cały czas używają faksów, Amerykanie czeków, a programiści Javy — Mavena. Od razu trochę sprostuję, żeby nie być niesprawiedliwym w ocenach: przywiązanie do czeków może nie być takie złe, bo zapewne nie pozwala na społeczne wykluczenie ludzi, którzy mają kłopoty z nauczeniem się korzystania z komputerów lub są zbyt biedni, żeby z łatwo z nich korzystać. Skupmy się jednak na programowaniu.

Czytaj dalej Czas Mavena minął

Funkcyjna obsługa błędów w Kotlinie i Javie

Czasem obsługa błędów jest prosta, „zerojedynkowa”: albo operacja się powiedzie, albo rzuci wyjątkiem. Mamy jednak też sytuacje, gdy od strony biznesowej podejście „wszystko albo nic” nie ma sensu i oczekiwane jest działanie w trybie „best effort”. Na wejściu jest zestaw danych, wykonujemy na nich operacje, jeśli w trakcie pojawiają się błędy, to po prostu idziemy dalej i próbujemy doprowadzić do końca tak wiele, jak się da, nie wycofując się z niczego. Nie mówimy o beztroskim ignorowaniu błędów: nawet jeśli zgadzamy się na częściowe niepowodzenie, dobrze jest wiedzieć, które z danych były przetworzone pomyślnie, a które z błędem. Jak zaprogramować takie podejście w sposób czytelny i jasno przekazujący intencję?

Imperatywne podejście (try-catch) w naturalny sposób modeluje sytuację zerojedynkową. Żeby zamodelować wersję „best effort” musimy myśleć w sposób bardziej funkcyjny, potraktować zarówno operację do wykonania jak i błąd jako byty na równi z danymi. Będziemy „kolekcjonować” błędy, żeby móc później zanalizować, ile ich było.

Języki nastawione na programowanie funkcyjne ułatwiają tu sprawę, ponieważ mają sprawdzone i dobrze opisane rozwiązania. Przykładowo Scala ma w bibliotece standardowej typ Try. Kotlin i Java nie są językami tradycyjnie wykorzystywanymi w sposób funkcyjny — nie oznacza to, że nie da się działać w nich w analogiczny sposób, jedynie to, że może być trudno znaleźć odpowiedź, jak do tego podejść.

Czytaj dalej Funkcyjna obsługa błędów w Kotlinie i Javie

Praca ze schowkiem z linii komend

Efektywna praca ze schowkiem systemowym to nie tylko umiejętność szybkiego wciskania Ctrl+C i Ctrl+V — przydatna jest też na przykład wiedza, jak korzystać ze schowka w terminalu.

Warto oglądać dobrych programistów przy pracy, pozwala to nauczyć się rzeczy, o których istnieniu po prostu nie wiemy. Ostatnio uderzyło mnie to przy słuchaniu prezentacji twórców Springa — w pewnym momencie Rob Winch potrzebuje zakodować hasło, a potem wkleić je w jedno pole w IDE (patrz 30-sekundowy fragment nagrania). Do tej pory gdy miałem zrobić coś podobnego, uruchamiałem komendę wypisującą coś w terminalu, zaznaczałem tekst myszą i kopiowałem. Upierdliwa rzecz, trzeba oderwać ręce od klawiatury, można kliknąć w złym miejscu, a z dala od biurka, na przykład na chodzącym jak spróchniała deska touchpadzie Lenovo, taka prosta czynność staje się utrapieniem. Natomiast Rob wykonał po prostu w terminalu:

spring encodepassword password | copy

Jak możemy uzyskać coś takiego na naszej maszynie? Sprawa jest nieco skomplikowana, bo nie ma jednej metody dla wszystkich systemów.

Czytaj dalej Praca ze schowkiem z linii komend

Dzielenie się testowymi klasami pomocniczymi w Gradle’u

Czasem mamy przypadek, że piszemy test jednostkowy jakiejś klasy i okazuje się, że część kodu testowego może być przydatna w innych częściach naszego projektu. Jak udostępnić ten kod, żeby był widoczny zarówno w testach aktualnego projektu, jak i w testach projektów od niego zależnych? Gradle od wersji 5.6 udostępnia dla tego celu plugin java-test-fixtures.

Czytaj dalej Dzielenie się testowymi klasami pomocniczymi w Gradle’u

Importy nieprzerywające pracy w IntelliJ

Do niedawna nienawidziłem przeklejania kodu do IDE. Nie dlatego, żebym uważał, że prawdziwemu programiście nie wypada robić copy-paste ze Stack Overflow (to bzdura). Cierpiałem na samą myśl, że będę musiał dodać importy do wszystkich użytych w tym fragmencie klas, ponieważ normalnie w IntelliJ jest to niewygodne. Dobra wiadomość: istnieje wbudowana opcja, która pozwala ułatwić sobie życie — ale domyślnie jest wyłączona. W dalszej części pokażę, jak ustawić swoje IDE do wydajnej pracy z importami. Na samym końcu będzie krótka dygresja o modelach mentalnych dla programistów.

Czytaj dalej Importy nieprzerywające pracy w IntelliJ

Poprawny Git commit message w IntelliJ

Pisanie commitów Gita wymaga zachowania pewnego savoir-vivre’u. Nie jest to powszechna wiedza, ale od czego mamy IDE? Oprócz wyłapywania potencjalnych błędów w kodzie mogłoby też kontrolować tekst wpisywany przy commicie. IntelliJ Idea (oraz WebStorm itp.) potrafi takie rzeczy — ale musimy włączyć odpowiednią opcję.

Czytaj dalej Poprawny Git commit message w IntelliJ

3 najbardziej pouczające materiały z 2019

Styczeń to na różnych stronach i blogach okres publikowania podsumowań minionego roku. Miałem zamiar napisać artykuł w stylu „3 najlepsze książki programistyczne, jakie przeczytałem w 2019”, ale okazało się, że nie zbiorę trzech: musiałbym albo zaproponować rzeczy, z których nie byłem w pełni zadowolony, albo książki niezwiązane ściśle z branżą IT. Zamiast tego mogę zaproponować 3 rzeczy związane z programowaniem, ale niekoniecznie wydrukowane na papierze: jedną książkę, jedną publikację w sieci i jedno nagranie wideo.

Czytaj dalej 3 najbardziej pouczające materiały z 2019

Niebezpieczny isEmpty() z utili Springa

Wyobraźmy sobie, że znajdujemy w projekcie taki kod w Javie (lub prawie identyczny — w Kotlinie):

public void assertNoViolations(Collection<ConstraintViolation> violations) {
    if (!isEmpty(violations)) {
        throw new IllegalStateException("violates constraints: " + violations);
    }
}

Na oko — kod jak kod, robi co trzeba, nuda. Co może pójść nie tak?

Metoda zgodnie z oczekiwaniami bezproblemowo akceptuje nulla. Rzuca wyjątkiem, gdy przekażemy jej listę zawierającą contraint violations. Jest jeden szkopuł:

assertNoViolations(emptyList());
java.lang.IllegalStateException: violates constraints: []

Jak to jest możliwe?

Czytaj dalej Niebezpieczny isEmpty() z utili Springa