ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 168
Numărul 167 Numărul 166 Numărul 165 Numărul 164 Numărul 163 Numărul 162 Numărul 161 Numărul 160 Numărul 159 Numărul 158 Numărul 157 Numărul 156 Numărul 155 Numărul 154 Numărul 153 Numărul 152 Numărul 151 Numărul 150 Numărul 149 Numărul 148 Numărul 147 Numărul 146 Numărul 145 Numărul 144 Numărul 143 Numărul 142 Numărul 141 Numărul 140 Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 168
Abonamente

De ce 13 devine 3? Fascinanta lume a actualizărilor Java

Sebastian Luca
Senior Software Engineer @ Cognizant



PROGRAMARE

Ai primit vreodată un User Story de migrare Java estimat la 13 puncte Fibonacci — pentru 20-30 de servicii? Știm cu toții cum se termină: zile de erori de compilare, forumuri din anii '90 și promisiunea că "celelalte vor fi copy-paste". În 2026, avem o veste bună: acele 13 puncte pot deveni 3, iar tu poți urmări totul servind o cafea gustoasă.

O zi din viața unui programator Java

Dați-ne voie să facem o presupunere: cu siguranță asta nu a fost cea mai plăcută experiență a ta ca programator! A face actualizări de versiuni majore — care vin în mod obișnuit cu actualizări ale altor dependențe secundare și terțiare pe care poate chiar nu le cunoști — nu este cea mai interesantă sarcină. Probabil că ai stat mai mult de două zile pe un singur serviciu, încercând să rezolvi toate acele erori de compilare, efect al deprecierii anumitor API-uri. Apoi, când în sfârșit codul compilează și nu mai ai niciun pic de roșu (preferabil nici galben...), dai drumul aplicației pe local și aceasta îți crapă cu o eroare pe care nu știi de unde să începi să o citești sau cum să o interpretezi. Și atunci începi și cauți ca tot omul pe StackOverflow, dar, nimic. Apoi intri la căutarea avansată pe Google și cauți: Reddit, Medium, Dev.to ș.a.m.d. Când în final nu găsești nimic, după ce ai modificat textul de căutare de câteva ori, după ce ai făcut o pauză de cafea și ai întrebat colegii din birou sau chiar ai dat un @all pe canalul cu toți developerii de Java pe Slack și nu ai primit niciun răspuns favorabil, ajungi la capătul tuturor ideilor. Și atunci zici că mai încerci pentru ultima dată să modifici termenii de căutare, să pui ceva clasă între ghilimele sau să te axezi pe prima eroare care a fost înfășurată în alte excepții de 5-6 ori... Și după ce ai ajuns la capătul internetului (ultima pagină din Google), ajungi pe un forum dubios cu grafică din '90 și acolo cineva spune că a rezolvat problema făcând upgrade la o singură versiune minoră, sau schimbând 1-2 litere dintr-o proprietate. Și o încerci și tu și... VICTORIE, aplicația pornește în sfârșit!!

Ești bucuros. Mâine la daily poți, în sfârșit, să nu mai spui că lucrezi tot pe upgrade-ul de Java la primul serviciu, ci că ai trecut mai departe. Totuși, înainte de a face commit te gândești să rulezi o dată testele pe local. Și ce să vezi? — jumătate din teste crapă, toate cu aceeași eroare că o clasă nu poate fi găsită în classpath, o clasă dintr-un pachet de care de asemenea nu ai auzit niciodată.

Toate acestea sunt la primul serviciu. Unul dintre "doar" 30 de alte servicii pe care tu trebuie să le migrezi la versiunea nouă în două sprinturi. Că doar e o sarcină ușoară: deoarece ai de modificat doar niște numere (versiuni) într-un singur fișier așa cum a zis "X" din echipa cealaltă, User Story-ul tău a primit doar 13 puncte Fibonacci (împărțit în două de 8 puncte fiecare, unul pe fiecare sprint) cu indulgență (adică după ce a fost pus "din burtă" extra ca să acopere orice incertitudine la estimare). Iar tu, la a patra zi din sprint, lucrând la testele primului serviciu, și dându-te de ceasul morții că nu vei reuși să faci la timp, știind că managerul tău care e liniștit acum nu are dreptate când spune că odată ce faci primul, celelalte vor fi copy-paste.

O situație familiară

Îți sună puțin cunoscută situația de mai sus? Te râcâie puțin când povestesc? Am reușit să atingem măcar o coardă sensibilă?

Dați-ne voie să răspundem noi: "DA!". Nu credem că vreun developer mid/senior nu s-a întâlnit cu câte ceva asemănător pe parcursul carierei. Da, poate că am exagerat puțin anumite aspecte, ca să facem povestea mai intensă și să aprindem un mic "foc" citind aceste rânduri.

Soluția din 2026: agenții IA

Dar acum venim cu o veste bună! În această zi minunată din 2026 avem toate uneltele necesare pentru a nu mai fi nevoiți să trecem prin tot acel stres. Nu va mai fi nevoie să mergem low level încercând să descoperim ce versiuni ale dependenței "X" merg cu framework-ul "Y", sau care e configurația corectă după migrarea de la un API depreciat la înlocuitorul său. Oare la ce ne referim? Credem că știți cu toții — agenții de inteligență artificială (IA) sau, mai tehnic spus: modelele mari de limbaj (LLM).

Vibe coding sau planificare structurată?

Poate că acum urmează să spuneți: "Lasă că am auzit noi de vibe coding și că vin oamenii non-tehnici și fac ei aplicații și că ne iau locurile de muncă. Dar noi știm care este curba de eficiență când faci vibe coding și că va ajunge codul (sau dependențele în situația actuală) de neîntreținut și în final vom pierde mai multe resurse decât dacă facem noi migrarea de mână". Nu am putea decât să vă dăm dreptate: vibe codingul a fost demonstrat că pe termen lung face ravagii și e foarte costisitor la proiecte mari și de lungă durată. Acum vine întrebarea: unde am spus vreodată noi vibe coding? Într-adevăr, vibe coding este o unealtă disponibilă agenților IA, dar nu este singura! Astăzi vrem să explorăm o altă unealtă, și anume: planificarea și executarea folosind agenți specializați, care comunică între ei, fiind coordonați de un agent principal. Sună complicat, nu? Însă odată înțelese aceste aspecte, nu va mai părea atât de dificil.

De ce ultimul Java LTS?

Dar acum vine și întrebarea: "De ce am vrea să ne batem capul să mergem la ultima versiune de Java LTS (25 la momentul scrierii acestui articol)?" Cel mai bun lucru ar fi să ne uităm la beneficiile aduse de această nouă versiune, plecând de la premisa că suntem cu o versiune LTS în urmă (Java 21). Având acestea în vedere, am dori să punem accentul doar pe câteva dintre noile funcții aduse de Java 25 care ne pot aduce beneficii în mediul enterprise:

Agenți AI coordonând migrarea Java

Planificarea: fundamentul abordării

Să o luăm cu începutul: planificarea. Ce înseamnă aceasta oare?

Prin planificare ne referim la faptul că nu vom folosi agenții pentru a modifica direct codul, făcând vreo modificare, ci vom lucra împreună cu agentul ca să scriem un plan foarte bine definit și pus la punct. Acest plan trebuie să explice fiecare modificare pe care dorim să o realizăm, să evidențieze aspectele esențiale și să precizeze ce trebuie realizat la fiecare pas. În final, planul va fi folosit de agent (și de subagenții săi) pentru a implementa toate modificările într-un singur proces.

Care e avantajul acestei abordări? Simplu: faptul că fiecare agent specializat va trece și modifica codul o singură dată asigură că nu vor apărea bucăți de cod uitate, sau aruncate, sau duplicate, ci totul va fi scris da capo al fine având același context. Asta va asigura calitatea finală a codului, corectitudinea rulării și siguranța că la final vom comite ceva complet funcțional și cu șanse minuscule de regresii introduse prin această migrare.

Construim planul împreună cu agentul

Cerințele de migrare

Știm în acest moment că doar abilitățile de programator expert Java nu sunt suficiente, așa că trebuie să apelăm la înțelepciunea internetului, care ne învață despre noua arie din tehnologie: prompt engineering. După cum s-a observat că dă cele mai bune roade, începem cu o cerință generală care descrie ce ne dorim ca agentul IA să scrie în plan. Mai întâi, însă, trebuie să îi transmitem că este un expert care le știe pe toate și că este mai mult decât capabil să facă ceea ce noi cerem:

De acum încolo vei acționa ca un inginer software expert, având aria de expertiză în Java, Spring și alte tehnologii aferente, fiind expert în versiunile cele mai moderne.
Vreau să începi să faci un plan despre ce presupune exact să fac actualizarea acestui serviciu la ultima versiune de Java LTS, și anume Java 25. Vreau să actualizezi absolut toate dependențele din proiect așa încât să aibă compatibilitate 100% cu versiunea de Java și Spring Boot. Vreau să folosești BOM-uri acolo unde este necesar și recomandat, având cel puțin două dependențe care beneficiază de acel BOM.
Dacă există dependențe care s-au mutat în alt pachet, cel curent fiind la capătul vieții, vreau să faci actualizarea la versiunea din noul pachet compatibilă cu codul meu.
De asemenea, vreau să extragi dependențele de teste într-un bloc nou `dependencies {}` și să te asiguri că sunt definite corect, fără să mă bazez în cod pe dependențe tranzitive, ci totul să fie specificat corect în `testImplementation / testRuntimeOnly`.
Te rog nu uita că și versiunea de `gradle wrapper` trebuie actualizată la cea mai nouă versiune potrivită cu versiunea de Java la care migrăm. Totodată, orice imagine Docker ce există trebuie parcursă, așa încât să te asiguri că are versiunea de bază și toate comenzile necesare ca să poată fi construită cu noua versiune de Java.
Nu în ultimul rând, vreau ca toate dependențele să fie verificate în baza de date CVE. Dacă dependențele mele directe sunt vulnerabile, vreau să alegi versiunea recomandată care rezolvă acea vulnerabilitate. Dacă vreuna din dependențele tranzitive ale proiectului sunt vulnerabile, vreau să actualizezi dependența părinte. Dacă acest lucru nu este posibil (vulnerabilitatea nu a fost fixată încă public), vreau ca într-un bloc separat `dependencies {}` să treci versiunea care fixează acea vulnerabilitate a dependenței tranzitive, într-un bloc `implementation {}` în care specifici versiunea strictă ce rezolvă acea problemă și totodată motivul (regula CVE) pentru acea implementare.

Validăm acoperirea testelor

Văzând că planul este generat și arată bine, putem trece la următorul pas: să ne asigurăm că tot codul este funcțional în local atât înainte, cât și după, iar testele rulează corect:

Vreau să pornești aplicația în local și să rulezi testele înainte de migrare. După migrare trebuie să te asiguri că aceleași teste rulează corect, iar aplicația pornește și funcționează corect.
Înainte de migrare vreau să verifici dacă testele acoperă majoritatea codului meu, atât ca acoperire a codului, cât și ca testare logică și funcțională a codului atingând majoritatea cazurilor limită. Dacă testele nu acoperă așa cum am cerut, vreau o statistică și un plan de adăugare de noi teste așa încât să respecte cerința mea.

Coordonăm un roi de agenți specializați

În timp ce agentul procesează, scanează codul și pregătește planul, un gând îmi vine în minte: dacă tot lucrăm cu mai mulți agenți care pot fi specializați, oare nu ar fi mai bine să gândim un proces în care diferiți specialiști să ia unul de la celălalt codul și să facă partea lor specială de îmbunătățire și auditare? De exemplu, am putea să ne axăm pe următoarele dimensiuni:

În special, ultimul punct îl considerăm foarte util, pentru că atunci când echipele fac migrarea la o nouă versiune, nimeni nu are timp să treacă peste tot codul așa încât să elimine toate părțile deprecated și să folosească ultimele funcționalități (de exemplu, a converti un String lung de tot, scris pe multe rânduri cu concatenare la un multiline string, sau a folosi .toList() la final de stream în loc de a scrie întreg colectorul).

Urmând aceste idei și bazându-ne pe un set deja existent de agenți (de ex: @ruvnet/ruflo) putem să îi cerem următoarele agentului:

Doresc ca planul pe care îl facem să fie rulat cu un roi de agenți, fiecare specializat pe domeniul său de activitate și coordonat de către tine. Incluzând pașii descriși mai sus, vreau să faci în ordine următoarele:
1. Testarea completă și rularea aplicației în local
2. Actualizarea versiunii de Java și aducerea tuturor celorlalte dependențe la versiunea cea mai nouă care respectă dependențele versiunii de Java și a celorlalte dependențe majore (ca și Spring Boot de exemplu)
3. Pornirea în local a codului și rularea testelor; rezolvarea oricărei probleme apărute datorită migrării.
4. Rularea uneltelor de analiză a versiunilor pentru a descoperi orice vulnerabilitate „CVE" și rezolvarea acestor vulnerabilități
5. Rularea uneltelor de analiză SAST și a celor de securitate, urmată de rezolvarea problemelor descoperite.
6. Pornirea aplicației în local și rularea testelor încă o dată, urmată de rezolvarea oricărei probleme descoperite. Totodată, pe baza logurilor, rezolvarea tuturor notificărilor de depreciere sau a avertizărilor apărute la pornirea aplicației.
7. Scanarea întregului cod și aducerea lui la nivelul nou de Java. În acest pas, agentul expert în Java va trebui să modifice părțile de cod care sunt depreciate, sau care au o variantă mai bună și modernă de scriere, față de cum a fost scris codul original. Ca exemple aici îți pot da conversia de la string-uri concatenate pe multe linii, la a folosi `"""`, transformarea din `.collect(Collectors.toList())` la `.toList()`, folosirea noilor variante de switch-case etc. Nu te limita doar la exemplele date aici, ci ia în considerare toate posibilitățile, așa încât după acest pas, codul să fie la un nivel complet modern.
8. Rularea testelor și pornirea aplicației, urmărirea logurilor și rezolvarea oricăror probleme posibile apărute.
9. Comiterea tuturor modificărilor (aceasta trebuie făcută la fiecare dintre pașii de mai sus), împingerea spre repo folosind un branch nou, finalizată cu deschiderea unui nou pull-request și anunțarea userului despre finalitate.

Declanșăm execuția

În acest moment, considerând că am atins toate aspectele necesare producerii unei migrări corecte și elegante, putem da drumul agentului să genereze varianta finală a planului. Odată finalizat, recomandarea noastră este să fie parcurs o dată pentru siguranță și ajustat dacă este nevoie.

Odată ce am ales modelul de LLM cel mai competent, pentru a ne asigura că lucrează corect, îi putem spune pur și simplu:

Lucrând ca un inginer software cu specializare în Java și Spring și bazându-te pe planul pe care l-am conceput împreună, începe să rulezi agenții specializați urmând toate instrucțiunile din plan. La final, vreau o explicație cu tot ce s-a făcut, rezultatul final, și un set extins de statistici.

De la plan la skill reutilizabil

Și cu asta ar trebui să avem aplicația migrată așa cum niciun programator nu ar avea timpul și răbdarea de a o face. Totuși, cu bune, cu rele, ca să ajungem la acest punct a trebuit să lucrăm câteva ore. Nu a fost tocmai un simplu migrează-mi aplicația asta la Java 21. Oare trebuie să trecem prin acești pași la fiecare aplicație pe care o migrăm? Sau trebuie să facem mereu copiere și lipire la toată această descriere lungă?

Nicidecum! Soluția este simplă — definirea unui skill global și reutilizarea sa. Tot ce trebuie să facem este să creăm un skill care are toate cerințele noastre de mai sus puse la un loc, iar noi va trebui doar să îi spunem folosind skill-ul tău de migrare Java, fă o migrare la Java 21 pentru această aplicație, începând cu planificarea și finalizând cu execuția sa. Partea frumoasă este că un astfel de skill poate fi urcat de către noi în GitHub cu licență MIT, după care mii de alți programatori vor putea face o migrare foarte simplă a codului lor, fără să treacă prin toți pașii noștri de mai sus.

Concluzie

Finalul tuturor lucrurilor este o aplicație migrată elegant și eficient, ocolind stresul unui developer care trebuie să facă o astfel de migrare de câteva ori în carieră. Ba mai mult — un singur developer poate rula mai multe migrări în același timp, lăsând agenții să lucreze în paralel, producând astfel o eficientizare maximă, posibil scurtând acele "13 puncte" inițiale la doar 5 sau poate chiar 3.

Actualizarea versiunilor Java a devenit dintr-odată mai accesibilă, mai interesantă și mai fascinantă. Parcă orizonturile s-au deschis, oferind un mai simplu proces de actualizare. Acum, ca stăpâni ai codului, ne va fi mult mai simplu să fim la zi cu toate versiunile noi de Java care apar mai nou "ca pâinea caldă". Așadar, nu mai suntem nevoiți să așteptăm să apară încă două LTS-uri până să ne luăm inima în dinți și să facem și noi odată actualizarea repede-repede până nu ajunge versiunea noastră în End of Life (EoL).

LANSAREA NUMĂRULUI 168

De la Vibe Coding la Production Engineering

Marți, 30 iunie, ora 18:00

Cognizant (Timișoara)

Facebook Meetup StreamEvent YouTube

NUMĂRUL 166 - AI for Programmers

Sponsori

  • Banca Transilvania
  • Betfair
  • MHP
  • .msg systems
  • P3 group
  • Cognizant Softvision
  • BMW TechWorks Romania

INTERVIURI