ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
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 160
Abonamente

Studiu comparativ: Quarkus vs. Spring Boot în microserviciile de AI

Alexandru Diniș
Unit Head Cluster Engineering @ BMW TechWorks Romania



PROGRAMARE

În ultimii ani, inteligența artificială a trecut de la un subiect "la modă", rezervat doar unora dintre noi, la un adevărat sistem inovator aplicabil în aproape orice domeniu: de la servicii, unde aplicațiile de suport clienți pot răspunde la întrebări în limbaj natural, până la industria auto, cu sisteme care analizează date în timp real pentru a sprijini luarea deciziilor. Dacă nu demult modelele lingvistice mari păreau inaccesibile din cauza resurselor necesare, astăzi provocarea nu mai este doar antrenarea lor, ci integrarea lor fără fricțiuni în aplicațiile enterprise și în viața de zi cu zi.

Acest scenariu ridică o întrebare-cheie: cum expunem interfețele AI într-un mod scalabil, rapid și ușor de întreținut? în ultima vreme, în comunitățile tehnice online prinde tot mai mult contur un subiect: va exista o migrare completă a aplicațiilor scrise în Python către Java în viitor? Va reuși Python să facă față uriașei provocări data de scalare milioanelor de cazuri de utilizare pe care le va aduce în continuare revoluția AI?

În continuare, în lumea Java, două nume domină scena: Spring Boot, frameworkul cunoscut pentru longevitate și ecosistemul masiv, și Quarkus, frameworkul mai nou, care promite pornire rapidă, consum redus de memorie și o potrivire naturală cu ecosistemele cloud, având totodată unul dintre cele mai rapide ritmuri de adopție timpurie ca framework Java.

Când vorbim despre microservicii în sfera AI, timpii de răspuns și costurile de infrastructură pot face diferența dintre un demo "cool" și un produs gata de livrat în producție. Comparația dintre cele două frameworkuri devine cu atât mai interesantă cu cât comportamentul la execuție poate fi semnificativ diferit. De precizat că, în unele situații, codul pentru a implementa un endpoint al unei interfețe AI poate arăta aproape identic.

În acest studiu, vom construi un microserviciu AI simplu pentru clasificare de text, folosind Hugging Face și DJL, pe care îl vom expune printr-un endpoint REST, /api/classify. Ideea este să implementăm exact același microserviciu atât în Quarkus, cât și în Spring Boot, cu dependințe și condiții identice, pentru o comparație corectă. Vom arunca, de asemenea, o privire asupra modelului arhitectural BCE (Boundary-Control-Entity), care se potrivește acestui tip de aplicație.

Vom parcurge de asemenea și experiența de dezvoltare software, de la modul ușor de dezvoltare și hot reload din Quarkus, până la sistemul de "starters" și integrări din Spring Boot. După ce finalizăm implementarea, vom crea câteva benchmarkuri, măsurând timpul de pornire (atât pe JVM, cât și ca imagine nativă), consumul de memorie în stare idle și sub sarcină, latența răspunsului la scalare, și chiar dimensiunea imaginilor Docker. Așadar, să vedem cine va câștiga bătălia frameworkurilor.

Descrierea microserviciului

Așa cum am stabilit, voi implementa același microserviciu atât în Quarkus, cât și în Spring Boot: un endpoint de clasificare de text, care apelează Hugging Face Inference API. Interfața Hugging Face (HF Inference) a fost aleasă deoarece elimină dependența locală de hardware a modelului și ne permite să măsurăm frameworkul în sine și nu capacitatea hardware-ului de a rula modelul. La nivel de interfață, vom avea următoarele:

Endpoint: 'POST /api/classify'

Payload: '{"inputs":"Alex absolutely loves Quarkus! It exceeded all his expectations."}'

Response: '{"label":"POSITIVE","score":0.999}'

Implementare

După ce am stabilit specificațiile, este momentul să trecem la implementare. Ca referință, voi folosi Quarkus 3.28.2 și Spring Boot 3.2.5. Pentru crearea aplicațiilor, atât Quarkus, cât și Spring oferă mai multe opțiuni de "quickstart". În zona Spring există bine-cunoscutul Spring Initializer, unde proiectul și dependințele pot fi configurate dintr-o interfață web, dar și un Spring CLI mai puțin cunoscut. Interesant este că și pentru Quarkus există un initializer web, de aceasta dată mai puțin cunoscut. Pe lângă acesta, aplicațiile Quarkus pot fi pornite rapid în diverse moduri: folosind CLI-ul sau direct folosind Maven. Odată instalat, CLI-ul îți permite să introduci direct extensiile necesare pentru a porni rapid o aplicație. Pentru aplicația noastră, voi folosi PowerShell pentru a inițializa ambele proiecte folosind CLI-ul. Din perspectiva de development, faptul că totul este disponibil în terminal este foarte comod, deoarece pot fi utilizați diverși asistenți AI disponibili tot în terminal. După ce aplicațiile sunt pregătite, putem începe cu prima măsurătoare din benchmark: vom vedea cât durează să inițializăm proiectele cu dependențele necesare. Cu alte cuvinte, voi măsura timpul de "init" și de pornire pentru un proiect de tip "hello-world", deoarece ambele instanțe inițiale vin cu așa ceva predefinit.

Quarkus init ~ 2.5 seconds

Spring init ~ 2.3 seconds

După cum se poate observa, timpul de execuție este similar (~2,3 secunde pentru Spring, ~2,5 secunde pentru Quarkus). Ceea ce este vizibil de la început este că sintaxa Spring CLI este mult mai stufoasă prin comparație cu Quarkus. Asta reflectă perspectiva generală a Quarkus, unde simplitatea este esențială.

După ce aplicațiile sunt inițializate, putem face un mic test de pornire pe o aplicație tip "hello-world". Voi urma abordarea clasică: rulez comanda mvn package, apoi execut fișierul .jar obținut.

După cum se vede în imaginile de mai sus, timpul de pornire al aplicației Quarkus este de 1,23 secunde, iar pentru Spring avem 3,25 secunde. Motivul este că Quarkus mută o mare parte din munca frameworkului în etapa de build. În loc să treacă prin etapa de beans discovery, să scaneze adnotări și să "lege" componentele la startup, Quarkus realizează toate aceste operații la build, dar și generează bytecode pentru Dependency Injection și pentru componentele și link-uri. Rezultatul: mai puțină reflecție, mai puține căutări dinamice, o suprafață de rulare mai mică, pornire mai rapidă și consum de memorie mai redus față de alte frameworkuri.

Un alt beneficiu major legat de procesul de development este că, datorită reducerii reflecției și a căutărilor dinamice, Quarkus oferă hot reload. Astfel, modificările se văd în sub o secundă, creând un flux "save & refresh" foarte apropiat de limbajele interpretate, nu de cele compilate.

Următorul pas este să adăugăm dependințele Maven necesare. Nu am putut să le includ la init, deoarece ambele frameworkuri permit adăugarea doar a dependențelor "proprii" în faza de inițializare. Voi folosi dependența Maven ai.djl pentru ambele proiecte. Implementarea în Quarkus va urma specificațiile Jakarta EE și MicroProfile, astfel încât codul să fie portabil către orice alt framework bazat pe Jakarta (Micronaut, Helidon). Ca stil arhitectural voi folosi BCE (Boundary-Control-Entity), pe care îl consider auto-explicativ și foarte ușor de testat și înțeles.

Ca parte a implementării BCE, am început prin a proiecta structura de date și interfețele de servicii astfel încât să fie agnostice față de frameworkul de dedesubt. Modelul BCE are avantajul separării clare între stratul de API (Boundary), logica de business (Control) și structurile de date (Entity). Astfel, codul devine modular, iar fiecare strat poate fi testat independent. De asemenea, convențiile de denumire din BCE, de la pachete la clase, apropie partea de business de soluția tehnică.

Pentru implementarea în Quarkus am folosit adnotări care aparțin Jakarta REST (JAX-RS) pentru API-ul REST și MicroProfile REST Client pentru apelurile HTTP externe către Hugging Face. Configurația — endpointul Hugging Face, modelul și tokenul — este transmisă în application.properties, ceea ce face ușoară schimbarea modelului fără modificări de cod.

Aceeași abordare poate fi reflectată în Spring Boot folosind Spring Web pentru API-ul REST și RestTemplate sau WebClient pentru apelurile externe. Dacă se dorește o abordare mai declarativă, putem folosi artifactul spring-cloud-starter-openfeign. Ca diferență de stil, Quarkus are avantajul că permite o implementare nativă pe specificațiile Jakarta EE; astfel, migrarea codului către un alt framework este nu doar posibilă, ci și ușoară, iar codul nu devine dependent de un framework anume. În schimb, în Spring codul ajunge strâns legat de framework, ceea ce face portarea dificilă sau imposibilă. Implementarea Quarkus poate fi găsită aici: https://github.com/alexandrudinis/sentiment-analyzer#.

Măsurători

Acum că ambele aplicații sunt create și gata de pornire, să înceapă "bătălia". Voi măsura diferite scenarii și cazuri de utilizare, păstrând aceeași arhitectură, același cod și același hardware. La finalul acestui capitol voi putea formula o concluzie pertinentă și documentată, bazată pe mai multe măsurători, precum:

Timpul de pornire într-un caz real de utilizare pe JVM

Cu ambele aplicații pornite, este momentul pentru încă un test de viteză la start. În scenariul simplu "hello-world", Quarkus s-a dovedit deja aproape de trei ori mai rapid. Dar se mai păstrează această diferență după ce adăugăm cod real? Surprinzător, Quarkus nu doar că a rămas mai rapid, ci diferența chiar a crescut considerabil. Timpul de pornire pentru Quarkus a rămas aproape identic cu use-case-ul "hello-world", în jur de 1,3 secunde, în timp ce Spring a avut nevoie de aproximativ 5,6 secunde.

Nu este vorba doar de cifre — viteza de pornire are implicații reale. În medii cloud-native, unde aplicațiile scalează constant în ambele sensuri, fiecare secundă în plus la start poate întârzia răspunsul considerabil. Știm deja că elasticitatea este un factor-cheie în ecosistemul cloud, iar aici impactul este direct. În scenarii serverless, această întârziere apare ca "cold start latency", afectând direct experiența utilizatorului final mai mult decât în alte medii.

Și mai interesantă este consistența Quarkus. Adăugarea logicii reale peste baseline-ul "hello-world" abia i-a modificat timpul de pornire, semn că optimizările lui rezistă sub sarcinile generate de scenarii de utilizare reale. Spring Boot, pe de altă parte, are un overhead mai mare din cauza auto-configurărilor extinse. Chiar dacă diferența poate fi considerată un compromis justificat în multe sisteme enterprise, pentru microservicii devine un dezavantaj clar.

Pentru a pune lucrurile și în context vizual, să privim diagrama de mai jos. Diferența pare și mai mare când o vizualizăm grafic, nu-i așa?

Timpul de pornire într-un caz real de utilizare folosind imagini native

O altă măsurătoare interesantă este să vedem cum se schimbă timpul de pornire după ce construiesc aplicațiile ca imagini native. Compilarea cu GraalVM elimină mare parte din scanarea classpathului, deci ne așteptăm la timpi de boot mult mai buni față de folosirea JVM. În cazul Quarkus, aici se vede cu adevărat forța frameworkului: datorită optimizărilor făcute la build, poate porni adesea în câteva zeci de milisecunde, practic instant din perspectiva utilizatorului. Recunosc, prima dată când am văzut asta am crezut că instanța Quarkus încă rula dintr-o pornire anterioară, atât de incredibilă părea viteza.

Totuși, și Spring Boot, prin suportul nativ introdus în versiunea 3, beneficiază de îmbunătățiri semnificative, deși amprenta rămâne firesc puțin mai mare din cauza modelului de auto-configurare. Chiar și așa, reducerea timpului de pornire de la câteva secunde la câteva sute de milisecunde este un câștig major, mai ales în contexte cloud-native în care containerele sunt scalate frecvent.

Pornind imaginile native de mai multe ori, diferența a crescut până la aproape de 10x (Quarkus fiind de zece ori mai rapid la startup). Am decis să rulez trei teste diferite ca să văd dacă diferența se menține. După cum se vede în diagramă, diferența este consistentă și rămâne aproape 10x în favoarea Quarkus la fiecare dintre cele trei rulări.

Măsurători pentru aplicația containerizată — consum de memorie în repaus și sub sarcină, latența răspunsului la scalare, dimensiunea imaginilor Docker

Pentru a trece dincolo de măsurătorile locale simple, trebuie să pun ambele aplicații într-un mediu care reflectă modul real de rulare în sistemele de producție. Alegerea firească este containerizarea și rularea lor cu Docker. Containerizarea ne oferă un set-up curat și reproductibil, în care serviciile Quarkus și Spring Boot pot fi testate în aceleași condiții, fără interferențe de la hardware-ul sistemelor locale.

Rulând aplicațiile în Docker, câștigăm posibilitatea de a măsura metricile care contează cel mai mult în contextul cloud-native: dimensiunea imaginilor finale, consumul de memorie în repaus și sub sarcină susținută, precum și latența răspunsului atunci când traficul crește. Acești factori influențează direct viteza de deploy, costurile de infrastructură și experiența utilizatorului final.

Dimensiunea imaginilor Docker

Prima comparație o voi face la nivelul dimensiunii imaginilor Docker. Aceasta măsurătoare, deși simpla, are consecințe practice: imagini mai mici înseamnă pulluri mai rapide în pipeline-urile CI/CD, porniri mai rapide în Kubernetes și un consum mai mic de lățime de bandă între medii. Cu ambele imagini construite, putem vedea acum cum se compară Quarkus și Spring Boot la acest aspect fundamental. Pentru testul nostru, ambele aplicații au fost containerizate folosind aceeași imagine de bază (eclipse-temurin:21-jre) și au fost construite în aceleași condiții. Rezultatele sunt prezentate mai jos:

Așa cum era de așteptat, imaginea Quarkus tinde să fie mai "ușoară" datorită modului optimizat de packaging, în timp ce imaginile Spring Boot includ de obicei un set de dependențe mai voluminos. Deși diferența poate să nu pară dramatică într-un mediu local, în medii la scară mare, unde zeci sau sute de servicii sunt deployate, aceste diferențe se adună și se transformă în costuri operaționale palpabile.

Consumul de memorie în repaus

Odată ce containerele sunt construite și rulează, următorul aspect de analizat este amprenta de memorie în repaus (idle). Consumului de memorie în repaus îi corespunde costul de bază al menținerii unui serviciu "în viață", adică simpla rulare, fără a procesa cereri. În mediile cloud, acest prag este deosebit de important, deoarece definește resursele minime care trebuie alocate permanent unui serviciu, având impact direct asupra prețului. Un consum mai mic la idle se traduce prin densitate mai bună pe nodurile Kubernetes și costuri de infrastructură reduse. Pentru a măsura memoria la idle, am pornit ambele aplicații în Docker în aceleași condiții, le-am acordat o scurtă perioadă de "warm-up" (30 de secunde), apoi le-am observat folosind instrumentele de monitorizare integrate în Docker. Procesul este direct, bazat pe comportamentul implicit al Docker.

Chiar dacă la dimensiunea imaginilor Docker diferențele nu au fost mari, la resursele de memorie ele sunt mai evidente. La CPU, Quarkus folosește cu 3% mai puține resurse. La memorie, vedem că Quarkus consumă de trei ori mai puțină memorie în idle. Când multiplicăm acest lucru pe mai multe noduri Kubernetes, economia obținută prin utilizarea Quarkus poate deveni semnificativă.

Deși măsurătorile în repaus ne oferă consumul de bază, testul "adevărat" vine când aplicațiile sunt puse sub trafic susținut. Consumului de memorie sub sarcină îi corespunde nu doar eficiența runtime-ului fiecărui framework, ci și felul în care gestionează resursele când procesează concurent multiple cereri. Aceasta măsurătoare este direct legat de scalabilitate: cu cât creșterea memoriei este mai stabilă și previzibilă, cu atât putem avea mai multă încredere că sistemul va face față în cazul unor sarcini susținute.

Pentru evaluare, containerele Quarkus și Spring Boot au fost supuse unui test de încărcare controlat, în timp ce consumul de memorie a fost monitorizat. Procedura a fost următoarea: folosind Virtual Threads, după ce aplicațiile au fost pornite în Docker pe două porturi diferite (8081 și 8082), am generat un număr crescător de requesturi pentru fiecare aplicație și am monitorizat rezultatele. Am repetat execuția de mai multe ori pentru a observa o tendință, pornind de la 100 de cereri paralele și ajungând până la 400 de cereri paralele.

În general, Quarkus tinde să prezinte o creștere mai stabilă a memoriei sub sarcină, deoarece minimizează reflecția și crearea de proxy-uri la runtime, lăsând un overhead mai mic per cerere. Spring Boot, deși mai "flămând" la memorie, beneficiază adesea de optimizările JVM, precum object pooling și o colectare eficientă a memoriei (garbage collection), ceea ce înseamnă că, deși baza este mai mare, poate susține throughputul fără degradări mari. Totuși, în configurații cloud, un comportament predictibil precum cel observat la Quarkus este dezirabil.

Diferențele sunt mai ales relevante în medii cu concurență ridicată. Un profil de memorie mai "slim" înseamnă că un număr mai mare de instanțe Quarkus pot fi împachetate pe același nod Kubernetes, în timp ce Spring Boot poate necesita mai multe resurse per pod. Ca o comparație finală, la nivel de CPU, chiar dacă pornim de la același consum pentru 100 de cereri, se observă o tendință de creștere pe măsură ce numărul de cereri crește; per total, Quarkus are un consum mai mic de CPU. La nivel de memorie, diferența este mai mare încă de la început și continuă să crească pe măsură ce crește numărul de cereri. Acest lucru reflectă același comportament observat și în testul de idle.

Latența de răspuns la scalare

Pentru a surprinde comportamentul fiecărui framework sub trafic real, am scris un mic instrument de măsurători în Java care profită din nou de existența Virtual Threads. Scriptul îmi permite să specific atât numărul de workeri concurenți, cât și numărul de requesturi pe care fiecare worker trebuie să le trimită. Fiecare thread trimite în buclă apeluri HTTP POST către endpointul /api/classify, măsurând timpul pentru fiecare request în parte. După finalizarea tuturor requesturilor, scriptul agregă rezultatele și calculează statistici-cheie: latența medie, precum și percentilele p95 și p99[^6]. Acest set-up oferă o perspectivă mai realistă asupra timpilor de răspuns la scară: nu doar cazul mediu, ci și cât de des și cât de sever apar vârfuri de latență pe măsură ce crește concurența. Rulând scriptul atât pe aplicația Quarkus, cât și a Spring Boot cu parametri identici, am putut obține o comparație corectă a reactivității sub sarcină. Rezultatele pot fi văzute mai jos:

Analizând măsurătorile de latență, ambele aplicații au procesat cu succes toate cele 5.000 de cereri fără erori, ceea ce confirmă că serviciile rămân stabile sub sarcină. Comparând mediile, Spring Boot a ieșit în față, cu un timp mediu de răspuns de aproximativ 411 ms, față de Quarkus cu circa 629 ms. Aceeași tendință se vede și la p95, unde 95% dintre cererile Spring s-au încheiat sub 741 ms, în timp ce Quarkus a ajuns la 895 ms.

Totuși, imaginea se schimbă la extremitatea distribuției. La percentila p99 — cele mai lente 1% dintre cereri — Quarkus a rămas sub două secunde, în timp ce Spring Boot a generat câteva valori extreme care au depășit patru secunde. Asta indică faptul că Spring, deși mai rapid în medie, poate suferi ocazional vârfuri severe de latență la concurență ridicată, pe când Quarkus a oferit timpi de răspuns mai previzibili pe toată distribuția.

În practică, asta înseamnă că un serviciu bazat pe Spring poate părea uneori mai rapid în regim stabil, dar Quarkus oferă mai multă consistență atunci când vorbim despre "worst-case"-urile care pot afecta experiența utilizatorului în medii sensibile la latență.

Concluzie

Compararea Quarkus și Spring Boot prin prisma implementării unui microserviciu legat de AI arată că cele două frameworkuri reflectă filozofii foarte diferite.

Spring Boot are un avantaj prin ecosistemul său bogat. Este în continuare o alegere excelentă pentru echipele unde nivelul de cunoștințe deja investite în stackul Spring este ridicat, mai ales acolo unde productivitatea dezvoltatorilor și integrarea cu sistemele existente sunt prioritare.

Quarkus, pe de altă parte, a demonstrat constant avantaje la viteza de pornire, eficiența memoriei și predictibilitatea sub sarcină. Designul său "slim" se traduce în consum redus în repaus și performanță mai stabilă la scară, ceea ce reduce direct costurile de infrastructură și îmbunătățește densitatea în medii containerizate și pe Kubernetes. În toate măsurătorile, Quarkus a arătat profilul unui framework mai ușor, mai "cloud-native". Timpul de start-up a rămas în jur de 1,3 secunde chiar și cu logică de business reală, față de 5,6 secunde la Spring Boot. În medii containerizate, imaginile Quarkus au fost mai mici și au cerut de trei ori mai puțină memorie în repaus— un avantaj clar pentru deploymenturile pe Kubernetes, unde costul contează. Sub sarcină, Quarkus a menținut o amprentă de memorie mai stabilă și a consumat mai puțin CPU pe măsură ce a crescut concurența, în timp ce Spring Boot a devenit mai "greu". În fine, deși Spring Boot a fost puțin mai rapid la latența medie (411 ms vs. 629 ms), Quarkus s-a dovedit mult mai previzibil la scară: cererile "worst-case" p99 au rămas sub două secunde, în timp ce la Spring au sărit peste patru secunde.

Privite împreună, aceste rezultate explică de ce Quarkus câștigă comparația: oferă pornire mai rapidă, consum mai mic de resurse și performanță mai stabilă sub presiune — exact calitățile necesare pentru microservicii AI în mediile cloud moderne și elastice.

LANSAREA NUMĂRULUI 160

Automotive în mișcare

Joi, 23 Octombrie, ora 18:00

sediul P3 Romania

Facebook LinkedIn StreamEvent YouTube

Conferință TSM

NUMĂRUL 159 - Industria Automotive

Sponsori

  • BT Code Crafters
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • P3 group
  • Ing Hubs
  • Cognizant Softvision
  • GlobalLogic
  • BMW TechWorks Romania

INTERVIU