Dane oryginału

Copyright © 2020 O’Reilly Media, Inc. All rights reserved. Title of English-language original: 97 Things Every Java Programmer Should Know, by Kevlin Henney and Trisha Gee, ISBN 978-1-491-95269-6, published by O’Reilly Media, Inc. Polish-language edition copyright © 2021 by Polish Scientific Publishers PWN Wydawnictwo Naukowe PWN Spółka Akcyjna. All rights reserved.

This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls all rights to publish and sell the same.

Przekład Magdalena Rogulska i Mariusz Rogulski na zlecenie WITKOM Witold Sikorski

Projekt okładki polskiego wydania INT-MEDIA Dawid Mazur na podstawie oryginału

Wydawca Wioleta Szczygielska-Dybciak

Redaktor prowadzący Jolanta Kowalczuk

Redaktor Małgorzata Dąbkowska-Kowalik

Koordynator produkcji Anna Bączkowska

Skład wersji elektronicznej na zlecenie Wydawnictwo Naukowe PWN Michał Latusek

Konsultant merytoryczny

Piotr Prądzyński

Zastrzeżonych nazw firm i produktów użyto w książce wyłącznie w celu identyfikacji.

Copyright © for the Polish edition by Wydawnictwo Naukowe PWN SA

Warszawa 2021

ISBN 978-83-01-21730-3

eBook został przygotowany na podstawie wydania papierowego z 2021r. (Wydanie I)

Warszawa 2021

Wydawnictwo Naukowe PWN SA

02-460 Warszawa, ul. Gottlieba Daimlera 2

tel. 22 69 54 321, faks 22 69 54 288

infolinia 801 33 33 88

e-mail: pwn@pwn.com.pl, reklama@pwn.pl
www.pwn.pl

Bezpłatny fragment

Wstęp

Wszystko, czego potrzebujesz, to Java
Anders Noras

Testowanie zatwierdzające
Emily Bache

Rozszerzenie Javadoc przez AsciiDoc
James Elliott

Uważaj na otoczenie swojego kontenera
David Delabassee

Zachowanie jest „łatwe”, a stan jest trudny
Edson Yanaga

Benchmarking jest trudny – pomaga w nim JMH
Michael Hunger

Korzyści z kodyfikowania i zapewniania jakości architektonicznej
Daniel Bryant

Podziel problemy i zadania na małe kawałki
Jeanne Boyarsky

Buduj zróżnicowane zespoły
Ixchel Ruiz

Procesy budowania nie muszą być powolne ani zawodne
Jenn Strater

„Ale u mnie to działa!”
Benjamin Muschko

Argumenty przeciw fat JAR-om
Daniel Bryant

Restaurator kodu
Abraham Marin-Perez

Współbieżność w JVM
Mario Fusco

CountDownLatch – przyjaciel czy wróg?
Alexey Soshin

Wyrażenia deklaratywne drogą do równoległości
Russel Winder

Dostarczaj szybciej lepsze oprogramowanie
Burk Hufnagel

Czy wiesz, która jest godzina?
Christin Gorman

Nie ukrywaj swoich narzędzi
Gail Ollis

Nie zmieniaj swoich zmiennych
Steve Freeman

Przyjmij myślenie z SQL-a
Dean Wampler

Zdarzenia między komponentami Javy
A. Mahdy AbdelAziz

Pętle informacji zwrotnych
Liz Keogh

Praca na najwyższych obrotach
Michael Hunger

Postępuj zgodnie z nudnymi standardami
Adam Bien

Częste wydania zmniejszają ryzyko
Chris O’Dell

Od łamigłówek do produktów
Jessica Kerr

„Full-stack developer” to sposób myślenia
Maciej Walkowiak

Odśmiecanie pamięci jest twoim przyjacielem
Holly Cummins

Popraw nazywanie rzeczy
Peter Hilton

Hej Fred, możesz mi przekazać HashMap?
Kirk Pepperdine

Jak unikać null
Carlos Obregón

Jak spowodować awarię swojej JVM
Thomas Ronzon

Poprawa powtarzalności i audytowalności dzięki ciągłemu dostarczaniu
Billy Korando

W wojnach językowych Java nie daje za wygraną
Jennifer Reif

Myślenie wkomponowane
Patricia Aas

Interoperacyjność z Kotlinem
Sebastiano Poggi

Jest ukończone, ale...
Jeanne Boyarsky

Certyfikacja w Javie: kamień probierczy technologii
Mala Gupta

Java to dziecko lat dziewięćdziesiątych
Ben Evans

Programowanie w Javie z perspektywy wydajności JVM
Monica Beckwith

Java powinna być przyjemna
Holly Cummins

Nieoznaczone typy Javy
Ben Evans

JVM jest platformą wieloparadygmatową: wykorzystaj to, aby ulepszyć swoje programowanie
Russel Winder

Trzymaj rękę na pulsie
Trisha Gee

Rodzaje komentarzy
Nicolai Parlog

Poznaj twą flatMap
Daniel Hinojosa

Poznaj swoje kolekcje
Nikhil Nanivadekar

Kotlin to jest coś
Mike Dunn

Poznaj idiomy Javy i umieść je pamięci podręcznej swojego umysłu
Jeanne Boyarsky

Nauka kata i kata do nauki
Donald Raab

Naucz się kochać swój stary kod
Uberto Barbini

Naucz się korzystać z nowych funkcji Javy
Gail C. Anderson

Naucz się swojego IDE, aby zmniejszać obciążenie poznawcze
Trisha Gee

Zawrzyjmy umowę: sztuka projektowania API w Javie
Mario Fusco

Uczyń kod prostym i czytelnym
Emily Jiang

Uczyń swoją Javę jeszcze bardziej odlotową
Ken Kousen

Minimalne konstruktory
Steve Freeman

Nazwij datę
Kevlin Henney

Potrzeba stosowania technologii przemysłowych
Paul W. Homer

Zbuduj tylko te fragmenty, które się zmieniają, a resztę wykorzystuj ponownie
Jenn Strater

Projekty open source nie są magiczne
Jenn Strater

Optional to monada łamiąca reguły, ale i dobry typ
Nicolai Parlog

Pakiet na funkcjonalność z domyślnym modyfikatorem dostępu
Marco Beelen

Produkcja to najszczęśliwsze miejsce na Ziemi
Josh Long

Program z dobrymi testami jednostkowymi
Kevlin Henney

Czytaj OpenJDK codziennie
Heinz M. Kabutz

Warto zajrzeć pod maskę
Rafael Benevides

Odrodzenie Javy
Sander Mak

Odkryj JVM na nowo dzięki Clojure
James Elliott

Refaktoryzuj wartości logiczne na wyliczenia
Peter Hilton

Refaktoryzacja w kierunku szybkiego czytania
Benjamin Muskalla

Proste obiekty wartości
Steve Freeman

Dbaj o swoje deklaracje modułów
Nicolai Parlog

Dbaj o swoje zależności
Brian Vermeer

Potraktuj poważnie „separację zagadnień”
Dave Farley

Techniczne rozmowy kwalifikacyjne to umiejętność, którą warto rozwijać
Trisha Gee

Programowanie sterowane testami
Dave Farley

W twoim katalogu bin/ są świetne narzędzia
Rod Hilton

Wyjdź poza piaskownicę Javy
Ian F. Darwin

Myślenie w koprocedurach
Dawn Griffiths i David Griffiths

Wątki to infrastruktura i tak je traktuj
Russel Winder

Trzy cechy naprawdę, naprawdę dobrych programistów
Jannah Patchay

Kompromisy w architekturze mikroserwisowej
Kenny Bastani

Nie kontroluj swoich wyjątków
Kevlin Henney

Odblokowywanie ukrytego potencjału testowania integracyjnego przy użyciu kontenerów
Kevin Wittek

Nieuzasadniona skuteczność fuzz testingu
Nat Pryce

Użyj pokrycia, aby ulepszyć swoje testy jednostkowe
Emily Bache

Swobodnie używaj niestandardowych adnotacji tożsamościowych
Mark Richards

Użyj testowania, aby szybciej tworzyć lepsze oprogramowanie
Marit van Dijk

Używanie zasad obiektowych w kodzie testów
Angie Jones

Wykorzystywanie mocy społeczności do rozwijania swojej kariery
Sam Hepburn

Czym jest program JCP i jak w nim uczestniczyć
Heather VanCura

Dlaczego nie traktuję certyfikatów poważnie
Colin Vipurs

Pisz jednozdaniowe komentarze
Peter Hilton

Napisz „czytelny kod”
Dave Farley

Młoda, stara i odśmiecacz
Maria Arias de Reyna

O autorach i redaktorach

Przypisy

Wstęp

Umysł nie jest naczyniem, które trzeba napełnić, lecz ogniem, który należy rozniecić

Plutarch

Co powinien wiedzieć każdy programista Javy? To zależy. Zależy od tego, kogo pytasz, dlaczego pytasz i kiedy pytasz. Sugestii jest co najmniej tyle, ile punktów widzenia. W zakresie języka, platformy, ekosystemu i społeczności, która wpływa na oprogramowanie oraz życie tak wielu ludzi. I dzieje się tak od stulecia do stulecia, od jednego do wielu rdzeni, od megabajtów do gigabajtów. Jest to szersze, niż można byłoby się spodziewać, że zostanie ujęte w jednej książce przez jednego autora.

Natomiast w tej książce wykorzystamy niektóre z tych wielu punktów widzenia, aby stworzyć razem pewien przekrój i przedstawić sposób myślenia w technologii Java. To nie będzie jedynym słusznym podejściem, ale 97 spojrzeniami 73 autorów. Cytując przedmowę książki 97 Things Every Programmer Should Know (O’Reilly):

Jest tak wiele rzeczy do poznania i do zrobienia i tak wiele na to sposobów, że żadna osoba ani żaden byt nie może rościć sobie praw do „jedynej słusznej drogi”. Poszczególne spojrzenia nie muszą zazębiać się jak części pewnego modułu – może być nawet odwrotnie. Wartość każdego spojrzenia wynika z jego odrębności. Wartość kolekcji wynika z tego, jak poszczególne elementy uzupełniają się, potwierdzają, a nawet zaprzeczają sobie nawzajem. Nie ma nadrzędnej narracji: to Ty poszukujesz odpowiedzi, zastanawiasz się i łączysz to, co czytasz, porównując z własnym kontekstem, wiedzą i doświadczeniem.

Co powinien wiedzieć każdy programista Javy? 97 rzeczy, które będziemy poruszać, obejmują język, JVM, techniki testowania, JDK, społeczność, historię, zwinne myślenie, wiedzę wdrożeniową, profesjonalizm, styl, treść, paradygmaty programowania, programistów jako ludzi, architekturę oprogramowania, umiejętności wykraczające poza kod, narzędzia, mechanikę GC, języki JVM inne niż Java... i nie tylko.

Własność intelektualna

Zgodnie z duchem pierwszej książki 97 Things, każde spojrzenie na pewne zagadnienie w tej publikacji jest zgodne z nieograniczonym modelem open source. Każde jest też objęte licencją Creative Commons Attribution 4.0. Wiele z nich pojawiło się po raz pierwszy na platformie Medium 97 Things.

Wszystkie one są paliwem i ogniem dla twoich myśli i twojego kodu.

O’Reilly – wiedza online

Od ponad 40 lat O’Reilly Media oferuje szkolenia, wiedzę i wgląd w zakresie technologii i biznesu, pomagające firmom odnieść sukces.

Nasza wyjątkowa sieć ekspertów i innowatorów dzieli się swoją wiedzą i doświadczeniem przez książki, artykuły i naszą internetową platformę edukacyjną. Platforma edukacyjna O’Reilly zapewnia dostęp na żądanie do szkoleń prowadzonych na żywo, rozbudowanych ścieżek edukacyjnych, interaktywnych środowisk kodowania oraz ogromnej kolekcji tekstów i materiałów wideo pochodzących od O’Reilly i ponad 200 innych wydawców. Aby uzyskać więcej informacji, odwiedź http://oreilly.com

Kontakt z nami

Komentarze i pytania dotyczące tej książki prosimy kierować do wydawcy:

O’Reilly Media, Inc.

1005 Gravenstein Highway North

Sebastopol, CA 95472

800-998-9938 (w Stanach Zjednoczonych i Kanadzie)

707-829-0515 (międzynarodowy i lokalny)

707-829-0104 (fax)

Dla tej książki prowadzimy dedykowaną stronę internetową, na której zamieszczamy erratę, przykłady i wszelkie dodatkowe informacje. Dostęp do tej strony można uzyskać pod adresem https://oreil.ly/97Tejpsk.

Aby skomentować lub zadać pytania techniczne dotyczące tej książki, wyślij e-mail na adres bookquestions@oreilly.com.

Odwiedź http://oreilly.com, aby zapoznać się z wiadomościami i informacjami o naszych książkach i kursach.

Znajdź nas na Facebooku: http://facebook.com/oreilly.

Śledź nas na Twitterze pod adresem http://twitter.com/oreillymedia, a także sprawdzaj http://twitter.com/97_Things.

Oglądaj nas na YouTubie: http://youtube.com/oreillymedia

Podziękowania

W projekcie 97 Things Every Java Programmer Should Know wiele osób poświęciło swój czas i podzieliło się spostrzeżeniami, zarówno bezpośrednio, jak i pośrednio. Wszyscy oni zasługują na uznanie.

Chcielibyśmy podziękować wszystkim, którzy poświęcili czas i wysiłek, aby przyczynić się do powstania tej książki. Jesteśmy również wdzięczni za dodatkowe opinie, komentarze i sugestie przekazane przez Briana Goetza.

Dziękuję wydawnictwu O’Reilly za wsparcie, które zapewnili dla tego projektu, w szczególności Zanowi McQuade’owi i Corbinowi Collinsowi za ich wskazówki i opiekę nad naszymi współpracownikami oraz zawartością książki, oraz Rachel Roumeliotis, Susan Conant i Mike’owi Loukidesowi za ich wkład w tę podróż.

Kevlin chciałby również podziękować swojej żonie Carolyn za nadanie sensu temu, co było go pozbawione, a synom Stefanowi i Yannickowi za nadanie rodzicom sensu życia.

Trisha chciałaby podziękować swojemu mężowi Isrze, za pomoc w dostrzeżeniu, że zamartwianie się tym, że robi wciąż zbyt mało, nie pomaga jej w czymkolwiek, a swoim córkom, Evie i Amy, za bezgraniczną miłość i przytulania.

Mamy nadzieję, że ta książka będzie źródłem informacji i że uznacie ją za odkrywczą i inspirującą.

Miłej lektury!

Wszystko, czego potrzebujesz, to Java

Anders Noras

Pracując nad pierwszą dużą wersją programu Visual Studio, zespół firmy Microsoft przedstawił światu trzy postacie programistów: Morta, Elvisa i Einsteina.

Mort był oportunistycznym deweloperem, robiącym szybkie poprawki, wymyślającym rozwiązania i idącym dalej. Elvis był pragmatycznym programistą budującym rozwiązania na lata, uczącym się w pracy. Einstein natomiast uchodził za paranoicznego programistę, mającego obsesję na punkcie projektowania najbardziej wydajnego rozwiązania i sprawdzania wszystkich możliwości przed napisaniem swojego kodu.

Będąc po stronie Javy – biorąc pod uwagę religijny podział języków programowania – śmialiśmy się z Mortów i chcieliśmy być Einsteinami budującymi frameworki, które zapewnią, że Elvisowie napiszą swój kod we „właściwy sposób”.

To był początek ery frameworków i jeśli nie byłeś biegły w najnowszym i najlepszym narzędziu do mapowania obiektowo-relacyjnego i frameworku z odwróconym sterowaniem, to nie byłeś dobrym programistą Javy. Biblioteki rozrosły się we frameworki o określonej architekturze. A ponieważ te ostatnie stały się technologicznymi ekosystemami, wielu z nas zapomniało o prostym języku, który był na początku – o Javie.

Java to wspaniały język, a jego biblioteka klas zawiera coś na każdą okazję. Potrzebujesz pracować z plikami? java.nio zapewni ci wsparcie. Bazy danych? java.sql to miejsce, do którego należy się udać. Prawie każda dystrybucja Javy zawiera nawet pełnowartościowy serwer HTTP, chociaż nie znajdziemy go w pakiecie java, a w com.sun.net.httpserver.

Teraz, gdy nasze aplikacje przechodzą w kierunku architektur bezserwerowych, w których jednostki wdrożeniowe mogą być pojedynczymi funkcjami, korzyści, jakie uzyskujemy z frameworków aplikacji, maleją. Dzieje się tak, ponieważ zapewne spędzamy mniej czasu na rozwiązywaniu problemów technicznych i infrastrukturalnych, skupiając nasze wysiłki programistyczne na założeniach biznesowych realizowanych przez nasze programy.

Jak to ujął Bruce Joyce:

Od czasu do czasu musimy wymyślać koło na nowo, nie dlatego, że potrzebujemy wielu kół, ale dlatego, że potrzeba nam wielu wynalazców.

Wielu próbowało zbudować ogólne frameworki dla logiki biznesowej, aby zmaksymalizować ich ponowne wykorzystanie. Większość z nich nie spełniła oczekiwań, gdyż tak naprawdę nie ma żadnych ogólnych problemów biznesowych. Robienie czegoś wyjątkowego w określony sposób jest tym, co odróżnia jeden biznes od innego. Dlatego mamy gwarancję, że będziemy pisać odrębną logikę biznesową w prawie każdym projekcie. W imię wymyślenia czegoś ogólnego i do wielokrotnego wykorzystania można by pokusić się o stworzenia silnika reguł lub czegoś podobnego. Ostatecznie skonfigurowanie silnika reguł byłoby programowaniem, często w języku gorszym od Javy. Dlaczego zatem nie spróbować po prostu użyć Javy? Będziesz zaskoczony, że wynik końcowy będzie łatwy do analizy, co z kolei sprawi, że kod będzie łatwy w utrzymaniu – nawet dla programistów spoza języka Java.

Dość często zauważysz, że biblioteka klas Javy jest trochę ograniczona i możesz potrzebować czegoś, co sprawi, że praca z datami, sieciami lub czymś innym będzie wygodniejsza. W porządku. Skorzystaj z innej biblioteki. Różnica polega na tym, że będziesz teraz używać tej biblioteki, ponieważ wystąpiła konkretna potrzeba, a nie dlatego, że była częścią stosu, z którego zawsze korzystałeś.

Następnym razem, gdy przyjdzie ci do głowy pomysł na mały program, odśwież swoją wiedzę o bibliotece klas Javy, zamiast sięgać po generator kodu JHipster. Hipsterstwo jest passe; proste życie jest tam, gdzie właśnie jesteśmy. Założę się, że Mort kochał proste życie.

Testowanie zatwierdzające

Emily Bache

Czy kiedykolwiek zdarzyło ci się napisać twierdzenie testowe z błędną lub pustą wartością? Coś takiego:

assertEquals("", functionCall())

Wtedy functionCall zwraca łańcuch, a ty nie jesteś pewien, jaki dokładnie powinien on być, ale będziesz wiedział, że jest właściwy, gdy go zobaczysz. Oczywiście po pierwszym uruchomieniu testu kończy się on niepowodzeniem, ponieważ functionCall zwraca łańcuch, który nie jest pusty. (Być może trzeba wykonać kilka prób, aż zwracana wartość będzie wyglądać poprawnie.) Następnie wklejasz tę wartość zamiast pustego łańcucha w assertEquals. Teraz test powinien zakończyć się pomyślnie. Sukces! To właśnie nazwałabym testem zatwierdzającym.

Decydującym krokiem jest tutaj podjęcie decyzji, który wynik jest poprawny i użycie go jako wartości oczekiwanej. Wynik „zatwierdzamy” – jest na tyle dobry, że można go przyjąć. Spodziewam się, że robiłeś coś takiego, nawet nie myśląc o tym. Być może nadasz temu inną nazwę: określa się to również testowaniem migawkowym lub testowaniem golden master. Z mojego doświadczenia wynika, że jeśli masz platformę testową zaprojektowaną specjalnie do tego typu testów, wszystko dobrze się składa i testowanie w ten sposób staje się łatwiejsze.

W przypadku klasycznego frameworka dla testów jednostkowych, takiego jak JUnit, aktualizacja takich oczekiwanych łańcuchów, gdy się zmieniają, może być nieco żmudna. Kończy się to wklejaniem różnych rzeczy bezpośrednio w kodzie źródłowym. W przypadku narzędzia do testów zatwierdzających, tego typu łańcuch zostanie za to zapisany w pliku. To od razu otwiera nowe możliwości. Możesz użyć odpowiedniego narzędzia do porównywania, aby przejść przez zmiany i scalić je jedna po drugiej. Możesz mieć możliwość podświetlania składni dla łańcuchów JSON i tym podobnych. Możesz wyszukiwać i zamieniać aktualizacje między testami w różnych klasach.

Jakie są więc dobre sytuacje dla testów zatwierdzających? Oto kilka:

Kod bez testów jednostkowych, który trzeba zmienić

Jeśli kod jest w produkcji, to wszystko, co robi, jest domyślnie uważane za poprawne i może zostać zatwierdzone. Wymagająca część tworzenia testów zamienia się w problem ze znalezieniem powiązań i wyłuskaniem elementów logiki, które zwracają coś interesującego, co można zatwierdzić.

REST API i funkcje, które zwracają JSON lub XML

Jeśli wynikiem jest dłuższy łańcuch, to przechowywanie go poza kodem źródłowym jest dobrym wyborem. JSON i XML mogą być formatowane przy użyciu białych znaków, dzięki czemu można je łatwo porównać z oczekiwaną wartością. Jeśli w formacie JSON lub XML istnieją wartości, które są innego typu – na przykład daty i godziny – może być konieczne sprawdzenie ich oddzielnie przed zastąpieniem ich ustalonym łańcuchem i zatwierdzeniem pozostałej części.

Logika biznesowa, która buduje i zwraca złożony obiekt

Zacznij od napisania klasy Printer, która może przyjąć zwracany obiekt złożony i sformatować go jako łańcuch. Pomyśl o Receipt, Prescription lub Order. Każda z tych klas może być przedstawiona jako wielowierszowy łańcuch czytelny dla człowieka. Twoja klasa Printer może wyświetlać tylko podsumowanie – przejście przez graf obiektu, aby wyciągnąć odpowiednie szczegóły. Twoje testy będą następnie wykorzystywać różne reguły biznesowe i używać Printer w celu utworzenia łańcucha do zatwierdzenia. Jeśli masz właściciela produktu lub analityka biznesowego, którzy nie są programistami, mogą oni nawet przeczytać wyniki testów i sprawdzić, czy są poprawne.

Jeśli dysponujesz już testami, z których wynika, że będą istnieć łańcuchy dłuższe niż jeden wiersz, polecam dowiedzieć się więcej o testowaniu zatwierdzającym i zacząć używać narzędzia, które je obsługuje.

Rozszerzenie Javadoc przez AsciiDoc

James Elliott

Programiści Java znają już Javadoc. Ci, którzy są w temacie już od dłuższego czasu, pamiętają, jaka była to istotna zmiana, ponieważ Java stała się pierwszym popularnym językiem, który zintegrował generator dokumentacji bezpośrednio z kompilatorem i standardowym zestawem narzędzi. Wynikająca z tego eksplozja dokumentacji API (nawet jeśli nie zawsze była ona świetna lub dopracowana) przyniosła nam wszystkim ogromne korzyści, a trend rozprzestrzenił się na wiele innych języków. Jak donosił James Gosling, Javadoc był początkowo kontrowersyjny, ponieważ „dobry redaktor dokumentacji technicznej mógłby zrobić to o wiele lepiej” – natomiast istnieje znacznie więcej API niż redaktorów dokumentacji technicznej, a zaleta posiadania czegoś powszechnie dostępnego została dobrze sprawdzona.

Czasami jednak potrzebujesz czegoś więcej niż tylko dokumentacji API – znacznie więcej, niż możesz zmieścić na stronach opisu pakietów i projektów, które oferuje Javadoc. Skupione na końcowym użytkowniku przewodniki i instrukcje, teoria i szczegółowe informacje o architekturze, wyjaśnienia dotyczące łączenia ze sobą wielu komponentów... żadne z nich nie pasuje do Javadoc.

Czego możemy zatem użyć, aby zaspokoić te potrzeby? Odpowiedzi zmieniały się na przestrzeni czasu. W latach 80. ubiegłego wieku przełomowym, wieloplatformowym narzędziem do tworzenia dokumentów technicznych, wyposażonym w GUI był FrameMaker. Do generowania atrakcyjnej drukowanej dokumentacji API za pomocą FrameMakera, Javadoc zawierał nawet MIF Doclet – z czego pozostała tylko szczątkowa wersja dla systemu Windows. DocBook XML oferuje podobne możliwości związane ze strukturą i łączeniem, wraz z otwartą specyfikacją i wieloplatformowym zestawem narzędzi, ale bezpośrednia praca z jego surowym formatem XML jest niepraktyczna. Nadążanie za jego narzędziami do edycji stało się kosztowne i uciążliwe, a nawet te dobre spośród nich stały się toporne i utrudniały pisanie.

Jestem podekscytowany, gdyż znalazłem lepszą odpowiedź: AsciiDoc – oferujący całą siłę DocBooka w łatwym do napisania (i odczytania) formacie tekstowym, w którym robienie prostych rzeczy jest trywialne, a wykonywanie złożonych jest możliwe. Większość konstrukcji AsciiDoc jest tak samo czytelna i dostępna jak w innych, lekkich formatach znacznikowych, takich jak Markdown, które stały się popularne na internetowych forach dyskusyjnych. A kiedy potrzebujesz czegoś bardziej wyrafinowanego, możesz dołączyć złożone równania przy użyciu formatów MathML lub LaTeX, sformatowane listingi kodów źródłowych z ponumerowanymi i dołączonymi objaśnieniami w akapitach tekstu, różnego rodzaju specjalne bloki i nie tylko.

AsciiDoc został wprowadzony wraz z implementacją Pythona w 2002 roku. Obecną oficjalną implementacją (i najważniejszą w zakresie tego języka) jest Asciidoctor, wydany w 2013 roku. Jego kod, napisany w Ruby można również uruchomić w JVM przez AsciidoctorJ (z wykorzystaniem wtyczek do Mavena, czy Gradle’a) lub transponować do JavaScriptu – wszystko to działa dobrze w środowiskach bazujących na ciągłej integracji. Gdy na bazie powiązanej dokumentacji (nawet z różnych repozytoriów) musisz zbudować całą witrynę, narzędzia takie jak Antora sprawiają, że jest to szokująco łatwe. Społeczność jest przyjazna i wspierająca, a obserwowanie jej rozwoju i postępów w ciągu ostatniego roku było inspirujące. A jeśli ma to dla ciebie znaczenie, to proces formalnej standaryzacji specyfikacji AsciiDoc jest w toku.

Lubię tworzyć bogatą, atrakcyjną dokumentację do projektów, które udostępniam. AsciiDoc znacznie mi to ułatwiło i wprowadziło tak szybkie cykle pracy, że szlifowanie i doskonalenie dokumentacji stało się zabawą. Mam nadzieję, że w twoim przypadku będzie tak samo. I, zataczając koło, jeśli zdecydujesz się postawić wszystko na AsciiDoc, przekonasz się, że istnieje nawet Doclet o nazwie Asciidoclet, który pozwala pisać Javadoc za pomocą AsciiDoc!

Uważaj na otoczenie swojego kontenera

David Delabassee

Istnieje niebezpieczeństwo związane z konteneryzacją starszych aplikacji Java w takiej postaci, w jakiej są, wraz z ich starszymi wersjami wirtualnych maszyn Javy (JVM), ponieważ ergonomia tych starszych maszyn będzie zaburzana podczas uruchamiania w kontenerach Dockera.

Kontenery stały się de facto mechanizmem opakowania środowiska uruchomieniowego. Zapewniają wiele korzyści: pewien poziom izolacji, lepsze wykorzystanie zasobów, możliwość wdrażania aplikacji w różnych środowiskach i nie tylko. Kontenery pomagają również zmniejszyć powiązania między aplikacją a platformą znajdującą się poniżej, ponieważ dana aplikacja może być spakowana w przenośny kontener. Ta technika jest czasami używana do modernizacji starszych aplikacji. W przypadku języka Java taki kontener zawiera starszą aplikację Javy wraz z jej zależnościami, w tym starszą wersję maszyny JVM używanej przez tę aplikację.

Praktyka polegająca na konteneryzowaniu starszych aplikacji Javy wraz z ich środowiskami z pewnością może pomóc w utrzymaniu starszych aplikacji działających w nowoczesnej infrastrukturze, przez oddzielenie jej od starszej, nieobsługiwanej infrastruktury. Jednak potencjalne korzyści płynące z takiej praktyki wiążą się z nowym zestawem zagrożeń wynikających z mechanizmów ergonomii JVM.

Mechanizmy ergonomii JVM umożliwiają wirtualnym maszynom Javy dostrojenie się na podstawie dwóch kluczowych wskaźników środowiskowych: liczby procesorów i dostępnej pamięci. Dzięki tym metrykom JVM określa ważne parametry, takie jak używana metoda odśmiecania pamięci, sposób jej konfiguracji, rozmiar sterty, rozmiar puli wątków i tak dalej.

Obsługa kontenerów Dockera z systemem Linux, dodana w 191 aktualizacji JDK 8, umożliwia maszynie JVM wykorzystywanie funkcji cgroups Linuksa w celu uzyskania metryk zasobów przydzielonych do kontenera, w którym działa. Każda maszyna JVM starsza niż ta nie będzie świadoma, że działa w kontenerze i uzyska dostęp do metryk z systemu operacyjnego hosta, a nie z samego kontenera. W większości przypadków kontener jest skonfigurowany tak, aby używał tylko podzbioru zasobów hosta, dlatego w celu dostrojenia się, maszyna JVM będzie bazować na nieprawidłowych metrykach. To szybko doprowadzi do niestabilnej sytuacji, w której kontener prawdopodobnie zostanie zabity przez hosta, gdy spróbuje zużyć więcej zasobów, niż jest dostępnych.

Poniższe polecenie pokazuje, które parametry maszyny JVM są konfigurowane przez mechanizmy ergonomii JVM:

java -XX:+PrintFlagsFinal -version | grep ergonomic

Obsługa kontenerów JVM jest domyślnie włączona, ale można ją wyłączyć za pomocą flagi JVM -XX: -UseContainerSupport. Użycie tej flagi w kontenerze z ograniczonymi zasobami (procesor i pamięć) pozwala obserwować i badać wpływ mechanizmów ergonomii JVM z włączoną lub wyłączoną obsługą kontenerów.

Uruchamianie starszych JVM w kontenerach Dockera nie jest zalecane. Ale jeśli jest to jedyna możliwość, taka wersja JVM powinna być przynajmniej skonfigurowana tak, aby nie przekraczała zasobów przydzielonych do kontenera, w którym działa. Idealnym, oczywistym rozwiązaniem jest użycie nowoczesnej, wspieranej wersji JVM (na przykład JDK 11 lub nowszej), która nie tylko domyślnie obsługuje kontenery, ale także zapewnia aktualne i bezpieczne środowisko uruchomieniowe.

Zachowanie jest „łatwe”, a stan jest trudny

Edson Yanaga

Gdy poznawałem programowanie obiektowe, jednymi z pierwszych nauczanych pojęć była trójka: polimorfizm, dziedziczenie i hermetyzacja[1]. Szczerze mówiąc, spędziliśmy trochę czasu, próbując je zrozumieć i wykorzystać w kodzie. Ale, przynajmniej w moim przypadku, zbyt duży nacisk położono na pierwsze dwa pojęcia, a bardzo mało na trzecie i najważniejsze: hermetyzację.

Hermetyzacja pozwala nam okiełznać rozrastający się stan i złożoność, które są czymś typowym w dziedzinie tworzenia oprogramowania. Pomysł, że możemy ukrywać stan m.in. przed innymi komponentami i opakować jego dowolne zmiany starannie zaprojektowanym API, jest podstawą projektowania i kodowania złożonych systemów informatycznych.

Jednak, przynajmniej w świecie Javy, nie udało się rozpowszechnić niektórych dobrych praktyk dotyczących budowy dobrze hermetyzowanych systemów. Właściwości JavaBean w anemicznych klasach, które po prostu ujawniają stan wewnętrzny przez gettery i settery, są powszechne, a dzięki architekturom Java Enterprise została spopularyzowana koncepcja, że większość – jeśli nie całość – logiki biznesowej powinna być zaimplementowana w serwisach. W ich wnętrzu używamy getterów do pobrania informacji, przetworzenia ich w celu uzyskania wyniku, a następnie jego wstawienia z powrotem do naszych obiektów za pomocą setterów.

A kiedy pojawiają się błędy, przekopujemy się przez logi, używamy debugerów i próbujemy dowiedzieć się, co dzieje się z naszym kodem w środowisku produkcyjnym. Dość „łatwo” jest wykryć błędy spowodowane problemami z zachowaniem: fragmenty kodu robią coś, czego nie powinny. Z drugiej strony, gdy wydaje się, że nasz kod działa właściwie, a my nadal mamy błędy, sprawa staje się znacznie bardziej skomplikowana. Z mojego doświadczenia wynika, że najtrudniejsze do rozwiązania są błędy spowodowane niespójnym stanem. Pewnie osiągnąłeś w swoim systemie stan, który nie powinien się wydarzyć, ale jednak wystąpił – wyjątek NullPointerException dla właściwości, która nigdy nie miała być null, czy wartość ujemną, która powinna być tylko dodatnia i tak dalej.

Szanse na znalezienie kroków, które doprowadziły do takiego niespójnego stanu, są nikłe. Nasze klasy mają otoczki, które zbyt łatwo zmienić i są zbyt łatwo dostępne: każdy fragment kodu, w dowolnym miejscu w systemie, może zmienić nasz stan bez żadnego sprawdzenia czy wyważenia.

Możemy oczyścić dane wejściowe wprowadzone przez użytkownika za pomocą mechanizmów walidacji, ale taki „niewinny” setter nadal istnieje i pozwala każdemu fragmentowi kodu go wywołać. Nie będę nawet omawiał prawdopodobieństwa, że ktoś użyje instrukcji UPDATE bezpośrednio w bazie danych, aby zmienić niektóre kolumny, które są mapowane w encjach na podstawie bazy danych.

Jak możemy rozwiązać ten problem? Jedną z możliwych odpowiedzi jest niezmienność (niemutowalność). Jeśli możemy zagwarantować, że nasze obiekty są niezmienne, a spójność stanu jest sprawdzana podczas tworzenia obiektów, nigdy nie będziemy mieć niespójnego stanu w naszym systemie. Ale musimy wziąć pod uwagę, że większość frameworków Javy nie radzi sobie zbyt dobrze z niezmiennością, zatem powinniśmy przynajmniej dążyć do zminimalizowania zmienności. Posiadanie odpowiednio zakodowanych metod wytwórczych i konstruktorów może również pomóc nam osiągnąć ten stan minimalnej zmienności.

Dlatego nie generuj setterów automatycznie. Zastanów się nad tym. Czy naprawdę potrzebujesz tego settera w swoim kodzie? A jeśli zdecydujesz, że tak, być może z powodu pewnych wymagań frameworka, rozważ użycie warstwy antydegradacyjnej (anti-corruption layer) w celu ochrony i weryfikacji stanu wewnętrznego po interakcjach spowodowanych setterami.

Przypisy

[1] Inaczej: enkapsulacja (encapsulation) (przyp. red.).