Përshëndetje të gjithëve në këtë blog, dhe ja postimi i katërt në serinë mbi Quarkus!

ishte për mënyrën se si Quarkus bashkon MicroProfile dhe Spring. Kujtojmë që pozicionohet si «Java subatomike super të shpejtë», po ashtu si «stoku Java i orientuar ndaj Kubernetes, i projektuar për GraalVM dhe OpenJDK HotSpot dhe i ndërtuar nga bibliotekat dhe standardet më të mira». Sot do të tregojmë se si të modernizoni aplikacionet Java ekzistuese, duke shfrytëzuar mundësitë e Quarkus, me shembullin e , i cili përdor teknologjitë e mbështetura nga Quarkus, CDI dhe Servlet 3.
Këtu është e rëndësishme të theksohet se si Quarkus ashtu edhe JBoss EAP përqendrohen në përdorimin e mjeteve, sa më shumë të jetë e mundur, të ndërtuara mbi standardet. A nuk keni një aplikacion që funksionon në JBoss EAP? Nuk ka problem, mund të migrohet lehtësisht nga serveri aktual i aplikacioneve në JBoss EAP duke përdorur . Pas kësaj, versioni përfundimtar dhe punues i kodit të modernizuar do të jetë i disponueshëm në depoja , në modul .
Gjatë shkruarjes së këtij postimi u përdorën , kryesisht dhe Building a .
TĂ« pajisim kodin
Së pari do të krijojmë një klon lokal të depozites :
$ git clone https://github.com/jboss-developer/jboss-eap-quickstarts.git
Cloning into 'jboss-eap-quickstarts'...
remote: Enumerating objects: 148133, done.
remote: Total 148133 (delta 0), reused 0 (delta 0), pack-reused 148133
Receiving objects: 100% (148133/148133), 59.90 MiB | 7.62 MiB/s, done.
Resolving deltas: 100% (66476/66476), done.
$ cd jboss-eap-quickstarts/helloworld/
Shikojmë se si funksionon helloworld origjinal
Në thelb, thelbi i këtij aplikacioni është i qartë nga emri, por ne do ta përmirësojmë kodin e tij në një mënyrë strikte shkencore. Prandaj, për fillim, le të shohim këtë aplikacion në formën e tij origjinale.
Shkarkojmë helloworld
1. Hapim terminalin dhe kalojmë në rrënjën e folderit JBoss EAP (mund ta shkarkoni ), që do të thotë në folderin EAP_HOME.
2. Aktivizojmë serverin JBoss EAP me profilin e parazgjedhur:
$ EAP_HOME/bin/standalone.sh
Shënim: në Windows për aktivizimin përdoret skripti EAP_HOMEbinstandalone.bat.
Pas disa sekondash, logu duhet të shfaqë diçka si kjo:
[org.jboss.as] (Controller Boot Thread) WFLYSRV0025: JBoss EAP 7.2.0.GA (WildFly Core 6.0.11.Final-redhat-00001) nisur në 3315ms - Nisi 306 nga 527 shërbime (321 shërbime janë lenë, pasive ose sipas kërkesës)
3. Hapim në shfletuesin :8080 dhe shohim këtë:

Fig. 1. Home page e JBoss EAP.
4. Ndjekim udhëzimet në manualin : hapim helloworld dhe ekzekutojmë komun dhe ndjekim komandën e mëposhtme:
$ mvn clean install wildfly:deploy
Pas përfundimit të suksesshëm të kësaj komande, do të shohim diçka të tillë në log:
[INFO] ------------------------------------------------------------------------
[INFO] NDĂRTIM I SUKSESHĂM
[INFO] ------------------------------------------------------------------------
[INFO] Koha totale: 8.224 s
Pra, përfaqësimi i parë i aplikacionit helloworld në JBoss EAP zuri pak më shumë se 8 sekonda.
Testojmë helloworld
Duke vepruar në përputhje me udhëzimet , hapim në shfletuesin :8080/helloworld dhe shohim këtë:

Fig. 2. Hello World origjinal nga JBoss EAP.
Bëjmë ndryshime
Ndryshojmë parametrin hyrës createHelloMessage(String name) nga World në Marco:
writer.println("<h1>" + helloService.createHelloMessage("Marco") + "</h1>");
Përsëri ekzekutojmë komandën e mëposhtme:
$ mvn clean install wildfly:deploy
Pastaj rifreskojmë faqen në shfletues dhe shohim që teksti është ndryshuar:

Fig. 3. Hello Marco në JBoss EAP.
Kthejmë prapa përfaqësimin e helloworld dhe përfundojmë punën e JBoss EAP
Kjo nuk është e detyrueshme, por nëse doni të anulloni përfaqësimin, mund ta bëni me komandën e mëposhtme:
$ mvn clean install wildfly:undeploy
Për të përfunduar instancën e JBoss EAP, thjesht shtypni Ctrl+C në dritaren e terminalit.
Modernizojmë helloworld
Tani do të merremi me modernizimin e aplikacionit origjinal helloworld.
Krijojmë një degë të re
Krijojmë një degë të re punë pas përfundimit të projektit quickstart:
$ git checkout -b quarkus 7.2.0.GA
Modifikojmë skedarin pom.xml
Ne do të fillojmë të modifikojmë aplikacionin nga skedari pom.xml. Që Quarkus të mund të shtojë blloqe XML, do të ekzekutojmë komandën e mëposhtme në dosjen helloworld:
$ mvn io.quarkus:quarkus-maven-plugin:0.23.2:create
Për shk writing që u përdor versioni 0.23.2 për këtë artikull. Quarkus shpesh lëshon versione të reja, dhe mund të kontrolloni se cila version është më e fundit në faqen .
Komanda e mësipërme do të shtojë në pom.xml elementet e mëposhtme:
- Prona , që përcakton versionin e Quarkus që do të përdoret.
- Blloku për të importuar Quarkus BOM (bill of materials), në mënyrë që të mos shtohet versioni për secilën varësi Quarkus.
- Përmirësimi quarkus-maven-plugin, që është përgjegjës për paketimin e aplikacionit dhe ofron modalitetin e zhvillimit.
- Profili native për të krijuar skedarë ekzekutues të aplikacionit.
Përveç kësaj, ne do të bëjmë ndryshime të caktuara në pom.xml:
- Nxjerrim etiketën nga blloku dhe e vendosim mbi etiketën . Pasi në hapin tjetër do të heqim bllokun , duhet të ruajmë .
- Pohoqim bllokun pasi, në mënyrë që ky aplikacioni të mos ketë më nevojë për pomin prindër nga JBoss gjatë punës me Quarkus.
- Shtojmë etiketën dhe e vendosim atë nën etiketën . Mund të tregoni numrin e versionit që dëshironi.
- Pohoqim etiketën pasi ky aplikacion nuk është më WAR, por një JAR i zakonshëm.
- Modifikojmë varësitë e mëposhtme:
- Ndryshojmë varësinë javax.enterprise:cdi-api në io.quarkus:quarkus-arc, duke hequr provided pasi (sipas dokumentacionit) ky është një zgjatje e Quarkus që siguron injektimin e varësive CDI.
- Ndryshojmë varësinë org.jboss.spec.javax.servlet:jboss-servlet-api_4.0_spec në io.quarkus:quarkus-undertow, duke hequr provided pasi (sipas dokumentacionit) kjo zgjatje e Quarkus mbështet servletët.
- Pohoqim varësinë org.jboss.spec.javax.annotation:jboss-annotations-api_1.3_spec pasi ato vijnë me varësitë që sapo kemi ndryshuar.
Versioni i skedarit pom.xml me të gjitha ndryshimet është në adresën .
Vini re se komandë mvn io.quarkus:quarkus-maven-plugin:0.23.2:create jo vetëm që ndryshon skedarin pom.xml, por gjithashtu shton një sërë komponentësh në projekt, përkatësisht, skedarët dhe dosjet e mëposhtme:
- Skedha mvnw dhe mvnw.cmd dhe dosjen .mvn: Maven Wrapper lejon që të ekzekutoni projekte Maven me një version të caktuar të Maven pa e instaluar atë version.
- Dosja docker (në katalogun src/main/): këtu ndodhen shembuj të skedhave Dockerfile për modet native dhe jvm (bashkë me skedhën .dockerignore).
- Dosja resources (në katalogun src/main/): këtu ndodhet një skedhë e zbrazët application.properties dhe një shembull i faqes fillestare Quarkus index.html (shiko më shumë te Run the modernized helloworld).
Kemi nisur helloworld
Për të testuar aplikacionin, përdorim quarkus:dev, i cili nis Quarkus në modalitetin e zhvillimit (shiko më shumë në këtë seksion në udhëzuesin për ).
Shënim: këtë hap do të thotë, pritshmërisht, të sjellë një gabim, pasi nuk kemi bërë të gjitha ndryshimet e nevojshme.
Tani ekzekutojmë komandën për të kontrolluar si do të funksionojë:
$ ./mvnw compile quarkus:dev
[INFO] Skanning për projekte...
[INFO]
[INFO] --------------------------------
[INFO] Ndërtimi i Quickstart: helloworld quarkus
[INFO] -------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ helloworld ---
[INFO] Duke përdorur kodimin 'UTF-8' për të kopjuar burimet e filtruar.
[INFO] Kopjimi i 2 burimeve
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ helloworld ---
[INFO] Asgjë për të ndërtuar - të gjitha klasat janë në gjendje të përditësuar
[INFO]
[INFO] --- quarkus-maven-plugin:0.23.2:dev (default-cli) @ helloworld ---
Duke dëgjuar për transport dt_socket në adresë: 5005
INFO [io.qua.dep.QuarkusAugmentor] Duke filluar augmentimin quarkus
INFO [org.jbo.threads] JBoss Threads version 3.0.0.Final
ERROR [io.qua.dev.DevModeMain] Dështoi për të nisur quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Dështim ndërtimi: Dështimi ndërtimit për shkak të gabimeve
[error]: Hapi ndërtimi io.quarkus.arc.deployment.ArcProcessor#validate hodhi një përjashtim: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Varësia e pavlefshme për tipin org.jboss.as.quickstarts.helloworld.HelloService dhe kvalifikatorët [@Default]
- anëtari java: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService
- e deklaruar në bean-in e klasës [tipet=[javax.servlet.ServletConfig, java.io.Serializable, org.jboss.as.quickstarts.helloworld.HelloWorldServlet, javax.servlet.GenericServlet, javax.servlet.Servlet, java.lang.Object, javax.servlet.http.HttpServlet], kvalifikatorët=[@Default, @Any], target=org.jboss.as.quickstarts.helloworld.HelloWorldServlet]
atë io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:841)
atë io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:214)
atë io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:106)
atë io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:249)
atë sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
atë sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethod)
atë sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
atë java.lang.reflect.Method.invoke(Method.java:498)
atë io.quarkus.deployment.ExtensionLoader$1.execute(ExtensionLoader.java:780)
atë io.quarkus.builder.BuildContext.run(BuildContext.java:415)
atë org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
atë org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
atë org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
atë org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1426)
atë java.lang.Thread.run(Thread.java:748)
atë org.jboss.threads.JBossThread.run(JBossThread.java:479)
Cauza: javax.enterprise.inject.UnsatisfiedResolutionException: Varësia e pavlefshme për tipin org.jboss.as.quickstarts.helloworld.HelloService dhe kvalifikatorët [@Default]
- anëtari java: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService
- e deklaruar në bean-in e klasës [tipet=[javax.servlet.ServletConfig, java.io.Serializable, org.jboss.as.quickstarts.helloworld.HelloWorldServlet, javax.servlet.GenericServlet, javax.servlet.Servlet, java.lang.Object, javax.servlet.http.HttpServlet], kvalifikatorët=[@Default, @Any], target=org.jboss.as.quickstarts.helloworld.HelloWorldServlet]
atë io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:428)
atë io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:371)
atë io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:206)
... 14 më shumë
Pra nuk funksionon... Pse?
Përjashtimi UnsatisfiedResolutionException tregon për klasën HelloService, e cila është një anëtar i klasës HelloWorldServlet (java member: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService). Problemi është se HelloWorldServlet ka nevojë për një instancë të injektuar të HelloService, dhe kjo nuk mund të gjendet (ndonëse këto dy klasa janë në të njëjtën paketë).
ĂshtĂ« koha pĂ«r t'u rikthyer nĂ« dhe tĂ« lexoni se si funksionon nĂ« Quarkus , dhe nĂ« pĂ«rfundim, (CDI). Prandaj, hapim manualin e Konteksteve dhe Injektimit tĂ« VarĂ«sive dhe nĂ« seksionin lexojmĂ«: «Bean-klasa, e cila nuk ka njĂ« annotim bean pĂ«rcaktues, nuk do tĂ« kĂ«rkohet».
Shikojmë klasën HelloService - me të vërtetë nuk ka një annotim të tillë. Prandaj, duhet ta shtojmë, në mënyrë që Quarkus të mund të kërkojë dhe të gjejë bean. Dhe duke qenë se është një objekt stateless, ne mund ta shtojmë annotimin @ApplicationScoped kështu:
@ApplicationScoped
public class HelloService {
Shënim: këtu mjedisi i zhvillimit mund të kërkojë të shtoni paketën e nevojshme (shih rreshtin më poshtë), dhe do të duhet ta bëni këtë manualisht, kështu:
import javax.enterprise.context.ApplicationScoped;
Nëse keni dyshime se cila fushë scope duhet të përdoret kur për bean-in burimor ajo nuk është e caktuar fare, lexoni dokumentacionin. .
Tani, le të provojmë përsëri të nisni aplikacionin me komandën ./mvnw compile quarkus:dev:
$ ./mvnw compile quarkus:dev
[INFO] Skanohet për projekte...
[INFO]
[INFO] --------------------------------
[INFO] Duke ndërtuar Quickstart: helloworld quarkus
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ helloworld ---
[INFO] Duke përdorur kodimin 'UTF-8' për të kopjuar burimet e filtruar.
[INFO] Po kopjoj 2 burime
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ helloworld ---
[INFO] Ndryshimet u zbuluan - po ri-komponohet moduli!
[INFO] Po kompiloj 2 skeduj burimesh në /home/mrizzi/git/forked/jboss-eap-quickstarts/helloworld/target/classes
[INFO]
[INFO] --- quarkus-maven-plugin:0.23.2:dev (default-cli) @ helloworld ---
Dëgjoni për transportin dt_socket në adresën: 5005
INFO [io.qua.dep.QuarkusAugmentor] (main) Duke filluar augmentimin e quarkus
INFO [io.qua.dep.QuarkusAugmentor] (main) Augmentimi i quarkus përfundoi në 576ms
INFO [io.quarkus] (main) Quarkus 0.23.2 u nisi në 1.083s. Dëgjoj në: http://0.0.0.0:8080
INFO [io.quarkus] (main) Profili dev aktivizuar. Kodimi në kohë realeaktivizuar.
INFO [io.quarkus] (main) Funksionalitetet e instaluara: [cdi]
Tani gjithçka kalon pa gabime.
Po nisim helloworld të modernizuar.
Siç është shkruar në log, hapim në shfletues. :8080 (faqja e fillimit e Quarkus me parazgjedhje) dhe shohim këtë:

Fig. 4. Faqja fillestare e Quarkus dev.
Në annotimin WebServlet të kësaj aplikacioni është përcaktuar si vijon konteksti:
@WebServlet("/HelloWorld")
public class HelloWorldServlet extends HttpServlet {
Prandaj, hapim në shfletues: :8080/HelloWorld dhe shohim si vijon:

Fig. 5: Faqja The Quarkus dev për aplikacionin Hello World.
Ja, tani gjithçka funksionon.
Tani do tĂ« bĂ«jmĂ« ndryshime nĂ« kod. Vini re se komanda ./mvnw compile quarkus:dev akoma funksionon dhe ne nuk kemi ndĂ«rmend ta ndalim. Tani do tĂ« provojmĂ« tĂ« aplikojmĂ« tĂ« njĂ«jtat â ndryshime shumĂ« tĂ« thjeshta â nĂ« kodin e vet dhe do tĂ« shohim se si Quarkus lehtĂ«son jetĂ«n e zhvilluesit:
writer.println("<h1>" + helloService.createHelloMessage("Marco") + "</h1>");
Ruajmë skedarin dhe më pas refresh-uam faqen në internet për të parë shkrimin Hello Marco, siç është treguar në ekranin më poshtë:

Fig. 6. Faqja Hello Marco në Quarkus dev.
Tani do të kontrollojmë daljen në terminal:
INFO [io.qua.dev] (vert.x-worker-thread-3) U zbulua ndryshimet në skedarët e burimit, po rimekEmbloj [/home/mrizzi/git/forked/jboss-eap-quickstarts/helloworld/src/main/java/org/jboss/as/quickstarts/helloworld/HelloWorldServlet.java]
INFO [io.quarkus] (vert.x-worker-thread-3) Quarkus u ndal në 0.003s
INFO [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Duke filluar augmentimin e quarkus
INFO [io.qua.dep.QuarkusAug Mentor] (vert.x-worker-thread-3) Augmentimi i quarkus u përfundua në 232ms
INFO [io.quarkus] (vert.x-worker-thread-3) Quarkus 0.23.2 filloi në 0.257s. Dëgjon në: http://0.0.0.0:8080
INFO [io.quarkus] (vert.x-worker-thread-3) Profilin dev është aktivizuar. Programimi i drejtpërdrejtë është aktivizuar.
INFO [io.quarkus] (vert.x-worker-thread-3) Karakteristikat e instaluara: [cdi]
INFO [io.qua.dev] (vert.x-worker-thread-3) Koha e zëvendësimit të nxehtë totale: 0.371s
Risia e faqes aktivizoi detektimin e ndryshimeve nĂ« kodin burimor, dhe Quarkus аĐČŃĐŸĐŒĐ°Ńikisht ŃДалŃĐ·ŃĐČаĐČ procedurĂ«n "ndalo-fill". Dhe e gjitha u krye pĂ«r vetĂ«m 0.371 sekonda (ja ajo, java "super mĂ« e shpejtĂ« subatomike").
Duke krijuar helloworld në paketën JAR
Tani që kodi punon siç duhet, do ta paketojmë me komandën e mëposhtme:
$ ./mvnw clean package
Kjo komandĂ« krijon dy skedarĂ« JAR nĂ« dosjen /target: skedari helloworld-.jar, i cili pĂ«rfaqĂ«son artikullin standard tĂ« krijuar nga ekipi Maven sĂ« bashku me klasat dhe burimet e projektit. Dhe skedari helloworldârunner.jar, qĂ« pĂ«rfaqĂ«son njĂ« JAR ekzekutiv.
Kujdes: kyçoni që ky nuk është një uber-jar, pasi të gjitha varësitë janë kopjuar thjesht në dosjen /target/lib (e jo të paketuar në skedarin JAR). Prandaj, për të ekzekutuar këtë JAR nga një dosje tjetër ose në një host tjetër, duhet të kopjoni si skedarin JAR ashtu edhe dosjen /lib, duke marrë parasysh se elementi Class-Path në skedarin MANIFEST.MF brenda paketës JAR përmban një përmbledhje eksplicite të JAR-eve nga dosja lib.
Për të mësuar se si të krijoni aplikacione uber-jar, referohuni udhëzuesit. .
Ekzekutojmë helloworld, i paketuar në JAR
Tani mund ta ekzekutojmë JAR-in tonë duke përdorur komandën standarde java:
$ java -jar ./target/helloworld-<version>-runner.jar
INFO [io.quarkus] (main) Quarkus 0.23.2 nisi në 0.673s. Duke pritur në: http://0.0.0.0:8080
INFO [io.quarkus] (main) Profili prod aktivizuar.
INFO [io.quarkus] (main) Karakteristikat e instaluara: [cdi]
Pasi të ketë përfunduar kjo, hapni shfletuesin në :8080 dhe kontrolloni se gjithçka funksionon siç duhet.
Krijojmë helloworld si një skedar ekzekutues natyror
Pra, helloworld-i ynë funksionon si një aplikacion standalone Java, duke përdorur varësitë Quarkus. Por mund të shkojmë më tej dhe ta kthejmë atë në një skedar ekzekutues natyror.
Instalojmë GraalVM
Së pari, është e nevojshme të instaloni mjetet e nevojshme:
1. Shkarkoni GraalVM 19.2.0.1 nga .
2. Zbërthemi arkivën e ngarkuar:
$ tar xvzf graalvm-ce-linux-amd64-19.2.0.1.tar.gz
3. Shkoni në folderin e zbërthyer.
4. Aktivizoni komandën e mëposhtme për të shkarkuar dhe shtuar imazhin native:
$ ./bin/gu install native-image
5. Caktoni folderin e krijuar në hapin 2 në variablën e mjedisit GRAALVM_HOME:
$ export GRAALVM_HOME={untar-folder}/graalvm-ce-19.2.0.1)
Informacione dhe udhëzime të tjera për instalimin në sisteme të tjera operative mund të gjenden në manual .
Krijojmë helloworld në një skedër ekzekutiv native
Lexoni manualin : «Tani le të krijojmë një skedë ekzekutive native për aplikacionin tonë, për të shkurtuar kohën e nisjes dhe madhësinë në disk. Skeda ekzekutive do të ketë gjithçka të nevojshme për të nisur aplikacionin, duke përfshirë makinën JVM (në të vërtetë, versionin e saj të reduktuar, që përmban vetëm atë që kërkohet për të ekzekutuar aplikacionin) dhe aplikacionin tonë vetë».
Për të krijuar një skedë ekzekutive native, duhet të aktivizoni profilin native në Maven:
$ ./mvnw package -Pnative
NdĂ«rtimi ynĂ« zgjati njĂ« minutĂ« e 10 sekonda, dhe skeda pĂ«rfundimtare helloworldârunner f u krijua nĂ« folderin /target.
Aktivizoni skedën ekzekutive native helloworld
NĂ« hapin e mĂ«parshĂ«m morĂ«m skedarin ekzekutues /target/helloworldârunner. Tani ta lansojmĂ« atĂ«:
$ ./target/helloworld-<version>-runner
INFO [io.quarkus] (main) Quarkus 0.23.2 u nis në 0.006s. Dëgjon në: http://0.0.0.0:8080
INFO [io.quarkus] (main) Profil prod u aktivizua.
INFO [io.quarkus] (main) Veçoritë e instaluara: [cdi]
Përsëri hapim në shfletuesin :8080 dhe kontrollojmë nëse gjithçka funksionon siç duhet.
Vazhdon!
Ne besojmë se metoda e diskutuar në këtë postim (edhe pse me një shembull shumë të thjeshtë) për modernizimin e aplikacioneve Java duke përdorur mundësitë e Quarkus duhet të aplikohet aktivisht në jetën reale. Ndërkohë, ndoshta do të përballeni me një sërë problemesh, zgjidhja e të cilave ne do të diskutojmë pjesërisht në postimin e ardhshëm, ku do të flasim për mënyrën se si të masim konsumimin e memorjes për të vlerësuar përmirësimin e performancës, një pjesë e rëndësishme e gjithë procesit të modernizimit të aplikacioneve.
Burimi: habr.com
