Znowu mamy całkiem wypełnioną edycje – dzisiaj mniej newsów, a więcej trochę głębszych treści. Mam nadzieje, że się spodoba.
1. Poważna sekcja o poważnych tematach – czyli nowości w obsłudze kryptografii
Zaczniemy sobie od tematów związanych z bezpieczeństwem, bo w zeszłym tygodniu dostaliśmy ciekawe ogłoszenie od samego Oracle.
JCA, czyli Java Cryptography Architecture, to zestaw interfejsów (wprowadzony w JDK 1.1 w 1997), umożliwiających integrację i dostęp do różnorodnych operacji kryptograficznych, takich jak szyfrowanie, podpisywanie czy generowanie kluczy. Jipher JCE to rozwiązanie od Oracle, zaprojektowane jako implementacja JCA i integruje ono wstępnie skonfigurowaną i zgodną z FIPS wersję OpenSSL 3.0, specjalnie dostosowaną do obsługi algorytmów dozwolonych przez standardy FIPS. Podczas KubeCon North America 2023 Oracle ogłosiło, że rozwiązanie (będące wcześniej komponentem ich chmury) zostanie oddane społeczności.
No to teraz trochę o FIPS. Jest to skrót od Federal Information Processing Standards, publicznie ogłaszanych standardów, opracowanych przez National Institute of Standards and Technology (NIST) w Stanach Zjednoczonych. Te są stosowane w rządowych systemach komputerowych (z wyjątkiem systemów związanych z obronnością), aby zapewnić ich bezpieczeństwo i interoperacyjność. Obejmuje to właśnie wspomniany moduł FIPS OpenSSL 3.0.
Słowem klucz ogłoszenia jest więc szeroko rozumiany „compliance”, aczkolwiek to co wyróżnia Jipher JCE to również wydajność – całość zbudowana została bowiem w oparciu o Project Panama, co daje jej przewagę nad starszą konkurencją typu Bouncy Castle… podobno, bo na razie dostaliśmy dopiero zapowiedź wprowadzenia rozwiązania do OpenJDK.
To jednak nie wszystko. Oracle ogłosił chęć większego zaangażowania w prace Cloud Native Computing Foundation (CNCF). Zaangażowanie to obejmuje zaś 3 miliony dolarów w kredytach na infrastrukturę w ramach mocy obliczeniowej Ampere Arm w Oracle Cloud Infrastructure. Wszystkie zapowiedzi znajdziecie tutaj.
A jak już jesteśmy przy bezpieczeństwie, to jeszcze w sierpniu swoją premierę miała biblioteka Java Dilithium, która jest „hobbystyczną” implementacją biblioteki Dilithium z C. Dilithium, będący częścią zestawu algorytmów CRYSTALS, został zalecony przez wspomniany już NIST jako główny algorytm dla kryptografii postkwantowej. Opiera się on na algebraicznych kratownicach (algebraic lattices), oferując kilka rozwiązań z różnymi poziomami bezpieczeństwa oraz obsługująca deterministyczne schematy sygnatur. Jak ktoś lubi kryptografie, to główne mięsko znajdziecie zaś w tej klasie.
Chociaż ta implementacja, zaprojektowana dla satysfakcji autora i nie przeznaczona do produkcji, przechodzi wszystkie dostępne testy i obejmuje funkcje takie jak serializacja i deserializacja. Jest to jednak projekt stworzony „dla zabawy”, warto jednak mu się przyjrzeć, bo obrazuje trend w ewolucji standardów kryptograficznych oraz trwające poszukiwania algorytmów w obliczu postępów w dziedzinie komputerów kwantowych.
Zainstaluj teraz i czytaj tylko dobre teksty!
2. Projekt Amper – Gradle definiowany za pomocą YAML
Przyzwyczajenia programistów się zmieniają – w ostatnich latach (teraz to już pewnie dekadzie) dostaliśmy wysyp rozwiązań CI/CD, pozawalających w łatwy sposób definiować kolejne kroki procesu, deklaratywnie konfigurowanych za pomocą plików YAML – żeby wymienić tu tylko Github Actions czy TravisCI. Jak się nad tym zastanowić, to między skryptami do budowania (zwłaszcza prostszymi), a pipelanami Continouse Integration nie ma aż tak wielkiej koncepcyjnej różnicy. Trend „yamlizacji” nie przeniknął jakoś mocno do świata build tooli, przynajmniej w szerokim ekosystemie Javy. Mamy co prawda deklaratywnego Mavena, ale ze swoim mało czytelnym XML-em, filozofia skupienia na „zarządzania projektami” (POM to w końcu Project Object Model), ale też mała elastyczność sprawiły, że wielu programistów zaczęło patrzeć na łatwiej rozszerzalnego Gradle. Rozszerzalność zaś prowadzić zaczęła do nadmiernie skomplikowanych skryptów, w których łatwo się pogubić.
Boli to zwłaszcza JetBrains, którym wdrożenie Kotlin Multiplatform szczególnie uwidoczniło złożoność Gradle, z jego mocno imperatywnym podejściem. Utrzymując równocześnie aplikacje na klika platform, programiści spędzać muszą bowiem sporo czasu z powodu ciągłych zmian w modułach, zależnościach oraz potrzebie kompatybilności między platformami. Idąc w sukurs tym wyzwaniom, JetBrains rozpoczęło we współpracy z Gradle eksperymentalny projekt o nazwie Amper. Narzędzie to ma na celu uproszczenie konfiguracji projektów i poprawę doświadczeń użytkownika w środowiskach IDE, szczególnie dla osób pracujących z Javą i Kotlinem. Zaimplementowany jako wtyczka do Gradle, Amper używa formatu YAML do konfiguracji projektów. Całość wygląda tak:
product:
type: lib
platforms: [jvm, android, iosArm64, iosSimulatorArm64, iosX64]
# Shared Compose dependencies:
dependencies:
- org.jetbrains.compose.foundation:foundation:1.5.0-rc01: exported
- org.jetbrains.compose.material3:material3:1.5.0-rc01: exported
# Android-only dependencies
dependencies@android:
# integration compose with activities
- androidx.activity:activity-compose:1.7.2: exported
- androidx.appcompat:appcompat:1.6.1: exported
# iOS-only dependencies with a dependency on a CocoaPod
dependencies@ios:
- pod: 'FirebaseCore'
version: '~> 6.6'
settings:
# Enable Kotlin serialization
kotlin:
serialization: json
# Enable Compose Multiplatform framework
compose: enabled
Nikt tu się nawet nie próbuje kryć ze źródłem inspiracji
Chociaż obecnie obsługuje tylko Kotlin i Kotlin Multiplatform, Amper obiecuje także wsparcie dla Javy i Swifta.
Dodając deklaratywną warstwę konfiguracji opartą na YAML nad Gradle, Ampera oferuje prostsze i potencjalnie mniej podatne na błędy podejście do konfiguracji projektów. Inicjatywa ta ma na celu uczynienie Gradle bardziej dostępnym i przyjaznym dla użytkownika, szczególnie dla programistów, którzy mogą być przytłoczeni jego złożonością.
Przyznam szczerze, że jestem w temacie tego rozwiązania nieco rozdarty. Z jednej strony, widzę wyraźną potrzebę uproszczenia procesu definiowania buildów w Gradle, na kształt Mavena ale z bardziej intuicyjnym zarządzaniem zależnościami i wtyczkami. Użycie deklaratywnego syntaxu podobnego do tego używanego w popularnych narzędziach CI, takich jak GitHub Actions, też wydaje się być pozytywnym krokiem. Jednak moim zdaniem, powinniśmy podchodzić do tego z ostrożnością. Istnieje ryzyko, że uproszczenie może ograniczyć zdolności systemu do obsługi mniej standardowych wymagań – a to był właśnie powód, dla którego tak wiele osób zaczęło migrować się z Mavena. Ogólnie rzecz biorąc, jestem ostrożnie optymistyczny co do potencjalnych korzyści płynących z Ampera, ale mam nadzieje, że wraz z jego adopcją nie zginie gdzieś po drodze elastyczność cechująca Gradle.
3. Czy wiesz czym jest i jak działa Invoke Dynamic?
Co za dużo newsów to nie zdrowo, prawda? Dlatego dzisiaj mam dla Was „powrót do korzeni”, czyli świetny tekst dotyczący jednej z ciekawszych fragmentów JVM, sprzedający wiedzę w mój ulubiony, przystępny sposób.
Invoke dynamic, często skracane jako indy
, to instrukcja na poziomie bajtkodu wprowadzona w Java 7 jako część Java Virtual Machine. Głównym jej celem jest ułatwienie implementacji na JVM, obok statycznie typowanych języków (takich jak Java) również języków dynamicznie typowanych (takich jak Python czy Ruby). W skrócie, instrukcja oferuje elastyczny i wydajny sposób obsługi wywołań metod w scenariuszach, gdy typ metody nie jest znany do momentu uruchomienia.
Ale oczywiście wiąże się z nią masa niuansów, dlatego chciałem się dzisiaj podzielić z Wami tekstem The Hidden Dynamic Life of Java autorstwa Natali Dziubenko. Tekst umożliwia bowiem jasne zrozumienie różnic między językami statycznie i dynamicznie typowanymi oraz tego, jak te różnice wpływają na funkcjonalność samego JVM. Następnie omówione są różne instrukcje wywołania metod w JVM, takie jak invokevirtual
i invokestatic
, oraz to jak invokedynamic
różni się od nich. Ponadto artykuł dostarcza praktycznych, prostszych do zrozumienia przykładów wykorzystania invokedynamic
w Javie mp. do konkatenacji łańcuchów znaków, Pattern Matchingu czy lambd. Całość dotyka także wyzwań związanych z dynamicznym zachowaniem w kompilacji Ahead-Of-Time (AOT) oraz tego, jak invokedynamic
wpisuje się w ten krajobraz, szczególnie w technologiach takich jak GraalVM.
Ogólnie Medium Natalii to taki mały „hidden gem”, który w tym tygodniu odkryłem i nie wiem jak do tej pory się przede mną ukrywał, bo teksty jej autorstwa oferują bogate przegląd mniej znanych aspektów Javy. Jestem pewien, że jej Medium będzie świetnym miejscem dla każdego, kto chce pogłębić swoją wiedzę o JVM. U mnie to był instafollow 😃
Zainstaluj teraz i czytaj tylko dobre teksty!
4. A na koniec, filozoficznie o wyjątkach i teorii typów.
Ogólne nastawienie społeczności programistycznej do Checked Exceptions w Javie jest (w najlepszym razie) mieszane – znacząca część programistów uważa je za uciążliwe i ograniczające. Wymagają one, aby metody deklarowały wyjątki, które mogą w nich wystąpić, a wywołujący te metody muszą obsługiwać te wyjątki lub wymuszać to na swoich odbiorcach. Ten aspekt Javy ma sens na papierze (w końcu dobrze wiedzieć, co może pójść nie tak) jednak jest często postrzegany jako nadmiernie rozwlekły i może prowadzić do skomplikowanego kodu, szczególnie w przypadkach, gdy konieczne jest przechwytywanie lub propagowanie wielu różnych wyjątków.
Tekst Why Checked Exceptions Failed autorstwa Fernando Borrettiego dostarcza przemyślanej krytyki Checked Exceptions w Javie, kwestionując ich praktyczność i integrację z resztą funkcji języka. Wskazuje na to, że chociaż Java dodała te dodatkowe informacje do sygnatur metod, nie zintegrowała w pełni tego koncepcji z innymi funkcjami języka, co prowadzi do braku czegoś, co autor nazywa „polimorfizmem rzucania wyjątków”.
Tekst jest wart przeczytania, ponieważ bada głębsze implikacje decyzji projektowych Javy dotyczących wyjątków. Wyjaśnia przyczyny znanych z praktycznego użycia ograniczeń nałożonych przez wyjątki kontrolowane, takie jak trudności w ich stosowaniu w parze z interfejsami i typami generycznymi, i kontrastuje to z podejściem języków programowania funkcyjnego, które używają typów takich jak Option i Result do obsługi błędów. Autor argumentuje też, dlaczego to podejście bardziej naturalnie wpisuje się w istniejące systemy typów tych języków.
Ponadto, artykuł może służyć jako przypomnienie o tym, jak złożonym problemem jest projektowanie języków programowania. Ilustruje, jak dodanie lub modyfikacja jednego fragmentu syntaxu może mieć szerokie implikacje, wymagające starannego rozważenia i integracji z całością języka.