Váltás Javáról Kotlinra

Ritkán esik szó itt programozásról, a Kotlinról meg főleg. Az utóbbi pár hétben beletanultam, és nagyon tetszik. Írok róla egy kicsit kedvcsinálónak.

Legfőképpen azt kell tudni a Kotlinról, hogy a Javához hasonlóan JVM-re fordul. Ebből rögtön pár pozitív dolog következik.

Az első a fordítás. Külön fordító és class library van hozzá, de jó esetben minden létező fejlesztési folyamathoz van már hozzá támogatás. Én konkrétan IntelliJ-ben kódolok és Bazellel fordítok, itt a Javával megegyezően működik minden (IJ néha belassul mindkettőnél). A második a futtatás. JAR file készül a kódból, tehát pont ugyanúgy lehet futtatni, mint egyéb Javás cuccokat. Ezen szempontok szerint kevés plusz munka van vele, ha valaki ki akarja próbálni.

A harmadik a szintaxis. Ez kicsit félrevezető, de alapvetően a JVM bytecode jellege miatt Java és Kotlin között oda-vissza lehet fordítani, és nagyjából 1:1 megfeleltetés van a két szintaxis között. Az IJ konkrétan azt tudja, hogy egy Java fájlt automatikusan (közepes minőségű) Kotlin fájllá konvertál. Ezen van mit reszelni, de kezdésnek nagyon jó. A visszafelé konvertálás a Kotlin fejlettsége miatt azért közel sem ilyen szép. Az is konkrétan specifikálva van, hogy Kotlin és Java nyelven írt kódok között hogyan működik az interop. Ez azért nagyon jó, mert nem kell az egész kódbázist újraírni, lehet fájlonként. Pl. pár új modult Kotlinban írsz meg, vagy épp csak a teszteket, bemelegítésnek.

És akkor jön az, hogy a Kotlin a konverzió és interop lehetősége ellenére nem egy Java klón, hanem egy önálló nyelv. Persze van sok dolog, amit az ember Kotlinban Javához (vagy bármi más nyelvhez) hasonlóan csinál, és ha pl. Guice frameworköt használunk, az is ugyanúgy fog menni. De pl. osztályok tervezésekor új döntések előtt állunk, hogy pl. sima classt, data classt, vagy objectet írunk-e. Konstruktorok, builder DSL-ek, extension methodok nagyon jó lehetőségeket kínálnak. Én a Java előtt régen C#-oztam, ehhez képest a Java nagy visszalépés volt, és most a Kotlin megadja mindazt, ami a Javából hiányzott. Megoldották a nullable típusok kezelését (viszlát Optional), nincsenek unboxed primitív típusok, van operator overloading, stb.

Némi negatívum, hogy a Kotlin szintaxis egy kicsit érdekes tud lenni (pl. a return utasítás hova fog kiugrani), vagy túl sok a syntactical sugar. Pár hét gyakorlat után még nem érzem, mi az a szint, amitől kezdve a kód idiomatikusnak tekinthető, de még nem visszük túlzásba a szintaxis adta lehetőségeket és nem válik nehezen olvashatóvá a kód. Nálunk divat, hogy a framework Java osztályokhoz Kotlin-specifikus kiegészítéseket írnak, hogy odaát szebb legyen a kód, és ezek szerintem nagyon hasznosak. Kifejezetten tetszik, hogy a protobuf compiler milyen builder DSL-t generál. Aki dolgozott már protobuffal, tudja, hogy Javában mennyit kell gépelni egy nagyobb üzenethez.

Mutatok két példát. Itt áll két egyenértékű metódus, a második az ún. single expression function.

fun hello(s: String): String { return s + "world" }

fun hello(s: String) = s + "world"

Itt pedig pár lambda látható. Mind ugyanazt tudja, kivéve, hogy a negyedik ki is ír valamit. Ha egy metódushívás utolsó paramétere lambda, ki lehet emelni. Egyparaméteres lambda esetén implicite használható az it paraméter. Return utasítás nincs, simán az utolsó kifejezés a visszatérési érték, ami egy kicsit azért furcsa tud lenni, mintha a levegőben lógna valami.

list.filter({ x -> x.field > 42 })

list.filter({ it.field > 42 })

list.filter { it.field > 42 }

list.filter {
  println("valami")
  it.field > 42
}

Ami leginkább tetszik Kotlinban, az az aszinkron programozás. Javában nincs a nyelvbe építve aszinkron programozási lehetőség. JRE-ben létezik pl. a Future osztály, amit a Guava jelentősen feljavított a ListenableFuture osztállyal, de még akkor is kézzel kell összelapátolni, hogy mi mi után fusson. Még a tök egyszerű lineárisan futó aszinkron kód is tök csúnyán néz ki leírva (mondjuk ezen a JEP-425 sokat fog dobni). Ezt a Kotlin coroutine-okkal váltja ki. Egy lineárisan futó aszinkron kód Kotlinban is tök lineáris. A színfalak mögött nagyon durva dolgok fordulnak belőle, hogy a JVM megegye, de evvel nekünk nem kell foglalkozni. Persze a nem lineáris dolgok is szépen néznek ki, async/await mód az egyik lehetőség. Amúgy van még benne rengeteg finomság, de az alapokhoz nem kell sokat tanulni.

A Java egyik nagy hibája (szerintem) a type erasure. A Kotlin sajnos ezt sem tudta teljesen megoldani, mert JVM-ben van a hiányosság. Azért van némi fejlődés: egy inline function tud reified generic type parametert deklarálni, és az már majdnem olyan.

Hát ennyi. Én azt mondom, mindenki nyugodtan váltson át Kotlinra, mert az jó.

Hozzászólások

Köszönöm, ez érdekes volt! Még az is lehet, hogy valamikor kipróbálom.

Nagyon szeretem a Java-t, érdekes módon amikor C#-oznom kell, én meg azt érzem visszaesésnek. Vannak jól kitalált dolgok benne, de például hatalmas arcraesés volt amikor rá kellett jönnöm, hogy nincsenek beépített fa megoldások benne. Nagy mellénnyel mentem optimalizálni, hogy csak ezt kell átírni fára, és már jó is lesz... Ahha, csakhogy nincsen készen elérhető fa implementáció. Legalábbis valami új függőséget kellett volna túrni hozzá.

A Kotlin a kollekciókban is újítást hozott, ezt kihagytam. A JRE-ben alapból van sok jó típus, ehhez a Guava hozzátett még sokat (Immutable* típusok, Multimap, Table). A Kotlinban (tudtommal) 3x2 típus van: {List, Set, Map} x {mutable, immutable}. Kicsit fapados a felhozatal, de ezek szintaxissal jól meg vannak támogatva, ráadásul végre a List és MutableList két külön típus. Ami ebből hiányzik, arra továbbra is ott a Guava.

A .NET-tel talán az a baj, hogy a Microsoft nagyon nagy class libraryt kínál gyárilag, de ami abból hiányzik, arra sokszor nincs olyan jól bevált és elterjedt megoldás, mint Javában a Guava. Biztos van tree típus, csak mondjuk tízféle random kicsi Nuget csomag formájában.

> Biztos van tree típus, csak mondjuk tízféle random kicsi Nuget csomag formájában.

Nyilván van, ha meg nincsen, akkor lehet csinálni, csak abban a projektben nem én döntöttem a függőségekről, csak okos akartam lenni és mutatni egy optimalizációt, ami így nem jött össze.

Köszi. Ez nagyon tetszett! Szakmai és jól érthető is egyben.

Amikor utoljára átnéztem, akkor arra a következtetésre jutottam, hogy nagyobb rendszereknél nem állnék át. Gondolok bármely pénzügyi rendszerre. Tévedtem volna a konklúziómmal?

Nem hiszem, hogy a mérethez lenne köze. Mint írtam, a tooling és az interop miatt nincsenek komoly rizikói, kiforrott már a dolog. A tesztekre is igaz, lehet Kotlint Javával tesztelni és fordítva. Baj esetleg akkor van, ha egy cégben még nincs know how, és 1-2 tapasztalatlan ember kezd el béna Kotlin kódot írogatni.

Ez mikor volt? Pár éve Kotlin konferencián meséltek 1-2 esetet amikor backendet írtak át Kotlinra... Ott azért volt fejvakarás... azóta viszont sokat fejlődött...

 

Mit értünk pénzügyi rendszeren és most miben van megírva? Gondolom nem egy bank/biztosító CORE rendszerére gondolsz... AS/400 PL1/Cobol témában... :)

Random PHP alkalmazást minden gondolkodás nélkül...

Azért a Kotlin sokmindenben sokkal szigorúbb - alapból minden immutable, a null-safety a type system része, stb.

Szerintem a know-how hiány miatt tud veszélyes lenni - én sokáig azt hittem, bármelyik java fejlesztő megért egy kotlinban felépített DSL-t, vagy kotlin kódot, aztán egyszer szembejött, hogy nem. És a lambdákat, meg extension functionöket kellett magyarázni, ahelyett, hogy fejlesztettünk volna.

Tapasztalatom szerint a Java-féle szigor nem véd a túlbonyolított és összebarmolt kódok ellen: ugyanúgy lehet szar rendszert készíteni, mint bármi más nyelven. (Ld: bármilyen nyelvben lehet Fortran-ban programozni...)

Az egyik problémás eleme a checked exception. Az elv jó, de egy nagy rendszer közepére ha egy gyenge képességű fejlesztőnek exception kezelést kell írnia, néha bizony a catch ág ott lesz, de a kezelése nem... Kedvencem mikor catch (Exception e) kódokat írnak s népek EJB környezetben, aztán néz nagyokat sz üzemeltetés, hogy miért lett rollback-elve a tranzakció magától... Tapasztalatom szerint több problémát okoz, mint amit megold.

Az interfész nácizmus problémás tud lenni, rettenetesen olvashatatlanná tud tenni nagyobb kódokat.

Tiszta szerencse, hogy a 14-es Java óta van már végre record class, mert a property még mindig nem nyelvi elem (kb sz összes többi nyelvben van ilyen, csak a Java-ban nincs), és igazán kellemetlen volt szarakodni data classokkal így. Persze Lombok meg egyebek léteznek már nagyon régóta, de bakker!

Nem rossz nyelv a Java, de évekkel le van maradva használhatóságban (és olvashatóságban!) a konkurencia mögött. A lambda megvalósítás és az egész stream fw kimondottan fos lett. Az nem érv, hogy a jvm platform korlátokat hoz, mert az összes többi JVM alapú nyelvben jobbak a lambdák, pl Kotlinban is, és mégis kompatibilis marad.

Külön mókás, hogyan lehet pl iterátor implementációt készíteni Kotlinban (és C#-ban is): imperatívan megírod a ciklus blokkot, és kész, nem kell szarakodni az interfész implementációval és az állapottal. Pár sor kód egy komplett class helyett, és még olvashatóbb is.

Ha csak tehetem, Kotlint használok Java helyett, akárt keverten id (pár class Java, pár pedig Kotlin).

Valójában sokszor az is sokat segítene, ha a programózó delikvens elolvasná és értelmezné az IDE warning-jait... Amelyik projektben nincs kikényszerítve a warning-mentesítés, ott a fejlesztők nagy része látványosan leszarja. Utánuk meg nem győzöm a sok NullPointerException-t meg hasonlókat kigyomlálni.

Más: vajon egy refernecia-alapú, GC memóriakezelésű nyelvben miért NullPointerException a neve? Nincsenek is pointerek. C#-ban NullReferenceException a neve :)

Egyelőre csak pár dolgot említek, ami állandóan idegesít:

  • SAM interfész nélkül nincs definíció (változó típus, függvény paraméter)
  • checked exceptions. Lehet kézzel wrappelgetni RuntimeException-be.
  • stream terminálás stream.collect(Collectors.toList()). Szép, kompakt, olvasható! Ja nem. Szerencsére Java 16-tól már van stream.toList(). Csak 7 évet kellett rá várni.

Lehet magyarázni, hogy a stream terminálás azért ilyen, hogy jobban el lehessen különíteni a pipeline építést és a végrehajtást, csakhogy rohadtul kényelmetlen, főleg mikor kisebb collection-ökön kell szűrögetni és leválogatni. És ha már ennyire szabályszeretőek vagyunk, akkor lássuk: Map<K, V>.get(Object key). A kulcs Object típus, nem K. Miért is? Ja tudom, visszafelé kompatibilitás. Az tök mindegy, hogy a legacy kód bugos, csak forduljon! Ennyit az elméletekről.

Szeretem a Java-t, nem rossz nyelv, csak C# és Kotlin után mindig kicsit fáj, hogy rengeteg boilerplace szart kell csinálni (oké, az IDE jó részét elintézi). Az újabb verziók sokat ledolgoztak a hátrányokból (type inference, record classes, switch expression, stb), de nekem pár dolog nagyon hiányzik, pl property, főleg azért, mert a Kotlin-osok meg tudták csinálni, és 100% Java kompatibilis maradt...

Mindenhol található egy-két ember, akiknek valamiféle programozási nyelv fétise van, és próbálja meggyőzni a környezetét, hogy milyen jó lenne ha az általa preferált nagyon új és nagyon fancy nyelvet használják, de ők nem nézik távolabbról a dolgokat. 

Java -> Kotlin migrációra én nem látom milyen valid érvek létezhetnek. Elsődlegesen nem a nyelven fog múlni (ebben az esetben), hogy milyen minőségben készülnek el a funkciók. Az átírás költsége általában nem térül meg. Az átállás egy hosszú folyamat és egy jó ideig két nyelven írt kód lesz a monolit, ami vezethet újabb problémákhoz. Ha architektúrálisan támogatod meg az átállást, és az új funkciók különálló szolgáltatásokba kerülnek, akkor is fenn kell tartanod a nyelvi kompetenciát párhuzamosan. Ha egy halott nyelvről lenne szó, akkor megérteném a motivációt, de még mindig a 3. legnépszerűbb nyelv (TIOBE index szerint). 

A piacon elérhető Kotlinhoz értő fejlesztők nagyrészt Android vonalon mozognak, szóval eléggé megnehezíti az új emberek felvételét, ha egy ilyen egzotikus terepre tévedsz. 

Félreértés ne essék, nem ellentmondani akarok, hanem inkább ellenpontozni. Az általad írt pontok sok esetben valid problémák lehetnek bizonyos esetekben, bizonyos cégeknél.

Elsődlegesen nem a nyelven fog múlni (ebben az esetben), hogy milyen minőségben készülnek el a funkciók.

Nagyban hozzájárul az is.

Az átírás költsége általában nem térül meg.

Erről is szól a poszt, hogy nem kell átírni, lehet hozzáfejleszteni, vagy csak a kritikus részeket átírni.

Egyáltalán nem új nyelvről van szó, idestova 11 éves. Jó fejlesztőket sok esetben könnyebben találsz olyan nyelvekhez, amik korszerűek és/vagy nagy potenciállal rendelkeznek a jövőt illetően.

Nagyban hozzájárul az is.

Programozási paradigmák tudják befolyásolni komolyabb mértékben a rendszer komplexitását, de ez a fejlesztőkön múlik hogyan használják rosszul vagy jól. 

 

Erről is szól a poszt, hogy nem kell átírni, lehet hozzáfejleszteni, vagy csak a kritikus részeket átírni.

Persze, lehet ilyet csinálni, ahogy írtam is, de ez növeli a karbantartás és fejlesztés költségét. Egy polyglot kódbázishoz minden azon dolgozó fejlesztőnek fel kell vennie az új tudást. Ez hatással van a tanulási görbére, és behoz egy állandó problémát az új fejlesztések esetén. Az új igények miatt refaktorálni kellene a régi kódot, felmerül a kérdés, hogy akkor írjuk át az egészet az új nyelvre, vagy fektessünk energiát a régibe?

Az automatikus kódtranszformációtól engem egy picit ráz a hideg, hogy az emberileg mennyire marad majd karbantartható, de biztos van az a kiindulási állapot, amikor ez már nem oszt vagy szoroz. 

Egyáltalán nem új nyelvről van szó, idestova 11 éves.

Érdemi népszerűségre 2017-ben tett szert, mikor Androidon támogatott nyelv lett. Java-s léptékben a Kotlin még fiatalnak számít.

 

Jó fejlesztőket sok esetben könnyebben találsz olyan nyelvekhez, amik korszerűek és/vagy nagy potenciállal rendelkeznek a jövőt illetően.

Nekem nem ez a tapasztalatom. Go (vagy Rust) fejlesztőket is baromi nehéz találni, és ezek még mainstreamnek számítanak. Az egyéb képességek ezen a ponton még képbe sem jöttek. Biztos vannak olyan nyelvek, amik determinálják a potenciális jelentkezők képességeit és/vagy korábbi tapasztalatait (Haskell, Clojure, Erlang, stb), de általánosságban nem érzem úgy, hogy ez jellemző lenne. 

Egy polyglot kódbázishoz minden azon dolgozó fejlesztőnek fel kell vennie az új tudást.

Miért kellene?
Nálunk a legnagyobb projekteken, mindenki csak egy-egy kis részterületen dolgozik. Pontosan elég azt ismernie.

Nekem nem ez a tapasztalatom. Go (vagy Rust) fejlesztőket is baromi nehéz találni, és ezek még mainstreamnek számítanak.

Tapasztaltakat igen, de kérdezd meg a jelenlegi vagy a felveendő programozókat, hogy lenne-e kedvük Go, Rust, Kotlin, Scala, ...-ben dolgozni. Épp azért nincs sok, mert nem adunk esélyt, még kisebb projekteken sem, ezen nyelveknek.

Miért kellene?
Nálunk a legnagyobb projekteken, mindenki csak egy-egy kis részterületen dolgozik. Pontosan elég azt ismernie.

Termék- és szervezetfüggő. Komponens csapatoknak is megvan az előnye, de ez megnehezíti az átszervezéseket meg erőforrás újraelosztásokat.    

Tapasztaltakat igen, de kérdezd meg a jelenlegi vagy a felveendő programozókat, hogy lenne-e kedvük Go, Rust, Kotlin, Scala, ...-ben dolgozni. Épp azért nincs sok, mert nem adunk esélyt, még kisebb projekteken sem, ezen nyelveknek.

Volt, hogy teljesen autonóm módon rendelkezhettek a használt techstack felett a csapatok, de elég rövidtávon visszaütött. A fluktuáció és átszervezések miatt meg kellett húzni egy vonalat. Jelenleg 3 nyelven készülnek microservicek. Ez is sok... Állandó probléma, hogy az egyik csapat x nyelvet használ, a másik csapat y nyelven. Így mikor egy microservice valamiért másik csapathoz kerül, akkor átírják a saját techstackjükre. Kis szerencsével ez pár hétnél nem tarthat tovább, de nem tartom hatékonynak. Letámogatni is nehezebb a különböző csapatok fejlesztését. Biztos vannak olyan helyek ahol bőven van erőforrás, de egyre inkább okoz problémát, hogy baromi sok idő és energia új embereket találni.

Szerintem jól gondolod, de ennek főleg az az oka, hogy nagy monolitokat nem szokás egyik nyelvből a másikra átírni. Itt van a gépemen egy ilyen, a Git working copy 2-3 giga - azt sem tudom, hogy kellene nekiállni egy Java->Kotlin váltásnak. Oké, az automatikus IntelliJ konverterrel csinálok "közepesen jó" Kotlin kódot, és utána? Felveszek a 600 fejlesztő mellé még 600 Kotlin devet, aki a közepesen jóból elég jót csinál? :)

Szerintem nagy kódbázis konverziójának nincs sok értelme, legalábbis olyan minőségű konverziót még nem láttam, ahol a humán hozzányúlás elhanyagolható lenne. Figyelembe kell venni, hogy van-e annyi előnye.

Nyugodtan lehet Javában hagyni a nagy részét. Kis részeket át lehet írni gyakorlásnak, vagy akkor, amikor épp amúgy is hozzá akarsz nyúlni. Esetleg konkrétan kereshetsz olyan részeket, ahol pl. coroutine-októl sokat javulna a teljesítmény, vagy sokat javulna a class design/átláthatóság/bármi. De pusztán azért átírni, hogy utána ugyanazzá forduljon, az időpazarlás.

nem kompatibilis a lentebbi kommenttel, miszerint "nincs elvi akadálya, hogy holnap egy teljesen új területre kell belenyúlnod"

Ez most azért megvalósítható, mert minden érintett fejlesztő kb. ugyanazon a tech stacken dolgozik. A domain ismeret (hiánya) miatt nyilván nem jellemző, persze.

Én meg az üzleti PM oldal azon hozzáállását nem értem, amikor véresre fossák a nacit a refaktor szótól is... Illetve az időszakos karbantartás keretében újraírástól dettó... Mert az nem termel pénzt!!44!!44!

Aztán jó pár éves kódbázison ahol összesen 20+ különböző ember tette már le a kézjegyét, azt várják el, hogy a beadott ticket tegnapra legyen meg...minden is max 2 óra alatt. Aztán a reális becslés mondjuk 6-8 óra... akkor meg kb értetlenkednek, hogy mi kerül ezen ennyibe... Derick és Harry csak egy mező c. klasszikusának egy specializált változata az előbbi eset... 

Nem vagyok PM. Csak példának írtam. 

Saját munkámat rendszeresen refaktorálom több okból is. Köztük olyanból, hogy a korábbi kódomat ma már magam előtt is szégyellem, vagy érthetőbb legyen, etc. 

Ettől függetlenül, ha PM vagy ügyfél lennék és elkezdenék fragmentálni a rendszerem plusz nyelvekkel, akkor kiborulnék. Vagy menjen ez tervezetten, és idővel álljunk át, vagy sehogy. Az is tervezett, hogy a monolitot el kezdjük szétkapni microservioce-kre és eközben használunk más nyelvet, de csak egyet.

Az ügyfél rendszere nem az önmegvalósítás terepe, se nem tanműhely. Van egy szó amit ebben a  témában hallottam: "intellektuális maszturbálás"  <- ennek tekintem az ilyen kísérletezzünk és tanuljunk valami újat az ügyfél költségén című mutatványt. Az ilyen kísérletezésekkel, és ezt írjuk valami másban lesz az igazi bloatware és hányás legacy rendszer. Idővel sehol nem fognak hozzá találni céget, aki babrálja és emiatt kell majd valamilyen nyelven újraírni az egészet. Ez simán csődbe is vihet egy céget, mert nem lesz ideje/pénze emiatt megújulni. Itt már nem csak az app lefejlesztése a költség, hanem a menet közben keletkezett üzleti veszteség is, amit a vállalat lelassult reakció ideje okoz.

Nem ismerek olyan céget aki 20 éve optimista, de olyan 100 éves céget igen, aki azóta pesszimista. :)
Nekem tulajdonosként/befektetőként a pesszimizmusom adja az optimizmusomat! :P

Szóval:
Optimistán tervezni vállalati jövőt? Nem készülni a veszélyekre? Nem elemezni kockázatot?
Hol is olvastam ezekről? Ja!  Csődjelentésekben. :)

Jelenleg ebben a helyzetben torzítja az éles látásod a pozíciód... Az nem egy általános helyzet, hogy a cégvezető/tulajdonos fejleszt egy rendszert... Nincs fölötted PO/PM... Neked a refaktorálás pl nincs időhöz kötve...Sőt! Eleve magadnak eldöntöd, hogy most ezt csinálod. Sok esetben elég keményen meg kell indokolni, hogy egy refaktorálás jóváhagyásra kerüljön... és akkor már általában eléggé nyakig ér a barna pont az ügyfél portáján...mert utolsó utáni percig szokták húzni.

Én a magam részéről azt szoktam javasolni, hogy adott feladat keretein belül 10-20% extra időt rá lehet szánni ha van olyan kódrész azon a területen amire a feladat szól, amit lehet refaktorálni... Ezért tartom a hátam ha PM/ügyfél oldalon felmerül a kérdés miért lett az több... 

 

Bocs, hogy ezt mondom, de ez közel sem ennyire transzparens. Az ügyfél nem tudja ezt megítélni, mert szakmailag nem kompetens a témában... Plusz most nagyon ráfeszültél a Java/Kotlin hibrid kódra. Elmondom, hogy ez nem egy PHP/ C++ szintű vegyítés... Utóbbira ugyanazt mondom mint te. Előbbi nem jelent megrázkódtatást...inkább a két nyelv közelsége biztosítja, hogy biztonsággal meg lehet lépni egy ilyen átírást...

Jogos az észrevétel ami a személyemről szól. Valóban én döntök róla, mit tartok hasznosabbnak az adott ponton. Mondjuk nálam ez úgy néz ki, hogy kell egy ficsőr, akkor biztosan refaktor előzi meg akaratlanul is. Amíg újra képbe kerülök az adott résszel ez ugyanis megtörténik.

Java vs. Kotlin
Nekem a Java-ban az tetszik, hogy ránézek és értem, nem kell az egeret rávinnem valamire, hogy tudjam mi az.
Kotlinban meg az tetszik, hogy ha mélységében egyszerűbb az alkalmazás, akkor gyorsabban megérthető a kód.

Ez alapján gondolom azt, hogy monolit=>java, micorservice=>kotlin. 

 

ps.: Ne feledjük, mérsékelt a tapasztalatom, egyedül fejlesztek és én vagyok a mindenes is.

"nem kell az egeret rávinnem valamire, hogy tudjam mi az"

Mit értünk ez alatt?

Osztályokat, mezőket ugyanúgy tudod dokumentálni mindkét nyelvben (Javadoc vs KDoc), ugyanaz az elnevezési konvenció.

Változók típusait mindkét nyelvben lehet inferenciára bízni (var/val) vagy teljesen kiírni (a Kotlin inferenciája jobb amúgy).

Nekem a Java-ban az tetszik, hogy ránézek és értem

A Java nyelv tervezésekor ez szempont volt. Sajnos ez nem akadályozza meg a fejlesztőket abban, hogy hülyeséget csináljanak. Számtalanszor találkoztam nagyobb (monolitikus:)) projektekben olyan Java kóddal, amit nem hogy ránézésre nem lehetett érteni, de napokig tartott kideríteni, hogy valójában mi a szerepe, és hol van elrontva.

Kevésbé bonyolult kódnál jól jön, ha a nyelv kompakt és könnyen érthető. Bonyolult kódnál mindegy milyen nyelvben készül, ugyanúgy el lehet rontani PL/1-ben is, mint Java-ban vagy Kotlinban, és egyiket sem lesz könnyű kibogozni. Munkám számottevő része áll ilyesmiből, és tapasztalataim szerint nem könnyebb a Java rendszerben a hibákat megtalálni. Na jó, a PL/1-hez képest talán igen :)

A Java nyelv tervezésekor ez szempont volt.

Igen, abban az időben még korszerűnek is számított, de azóta nagyon eljárt felette az idő és nem igazán tudják, akarják jó irányba fordítani.

Felesleges komplexitásra nagyon jó példa a "Hello World!" alkalmazás:

public class Simple{  
    public static void main(String args[]){  
        System.out.println("Hello World!");  
    }  
}  

vs

println("Hello World!")

Nagyon nehéz megbecsülni, hogy egy hatékonyabb, de kevésbé begyakorlott nyelven mennyivel változik a fejlesztési idő.

Van projektünk (nem csak egy), ahol eleve Kotlin-al indultunk úgy, hogy a fejlesztők is ezen a projekten tanulták (senior Java fejlesztők). Nem volt gond a nyelvvel, utólag visszatekintve (eredetileg is ezt becsültük) nem volt lassabb a haladás és nagyobb kockázat, mintha Java-ban csináltuk volna, sőt! Az egyetlen komoly nehézség a korutinok és az aszinkronitás elsajátítása volt, főleg, hogy még nem volt stabil az API, mikor elkezdtük :), de ez sem vetette vissza a projektet, mert ha más technológiával kellett volna megoldani, az sem lett volna egyszerűbb.

A fejlesztők egy része örült neki, hogy van lehetősége egy új nyelvet élesben tanulni. Másik (kisebb) részük ágált ellene, de hamar beleszoktak. Vannak fejlesztők, akiknek a programozás csak ugyanolyan munka, mint a futószalag mellett állni, nekik mindegy a nyelv, de biztosan ellenkezni fognak, ha változás jön. Mások szeretik élvezni, amit csinálnak, és szívesen kipróbálnak új és érdekes szerszámokat.

Nagyon sokat hallom, hogy "nem az ügyfél kontójára tanulunk!". Bocsi, de ha sosem tanulsz, lemaradsz. Ha nem ügyfél-projekten tanulsz, akkor mikor keresel pénzt, ha ebből élsz? El kell találni az egészséges arányt, másrészt nagyon fontosnak tartom, hogy legyen megfelelő tapasztalt szakember("kemény mag"), akik vezetni tudják a többieket, és minimálisra szorítani a kockázatot. Az ilyen embereknek viszont sokszor fontos az "intellektuális maszturbáció", jelentős motiváló tényező tud lenni, és ennek már bizony üzletileg is kimutatható eredménye lesz.

A Kotlin hatalmas előnye az, hogy csak a nyelv más, de a teljes ökoszisztéma ugyanaz marad, ráadásul 100%-ban kompatibilis Java-val. Olyannyira, hogy Kotlin-ban írt libek-classok simán használjatóak Java classokból, sőt, több projetet is láttam (és csináltam is), ahol vegyesen használják a két nyelvet. Más platformra (pl node.js-re) átírni az alkalmazást (vagy beletanulni egy új projektben) tényleg nagy rizikó, de a Java->Kotlin út sokkal zökkenőmentesebb.

Akkor sok projekt instant faszerdő... Már csak erőforrások kezelése miatt eleve van egy kompetencia kombináció. Egy projekten vannak a frontend és a backend fejlesztők. Az előbbi csapat patent a JavaScript/Typescript nyelvekben és a kapcsolódó VueJS/Angular keretrendszerben...az utóbbi meg a Javaban és a Springben vagy JEE-ben... Persze, vannak a fullstack fejlesztők...de nem akarok kinyitni egy második Pandóra szelencéjét...

Viszont az előzmények tükrében felmerül a kérdés, hogy nálatok hogy állnak össze az IT vonatkozású szoftver és hardver beszerzések... ezek üzemeltetése...stb...?

Kinézel egy részt, ami átdolgozásra szorul, vagy ami újat hozzá kell tenni a rendszerhez, és az Kotlinban csinálod meg. Többször leírták a többiek, hogy teljes az együttműködés a "sima" Java-val, tehát meg lehet tenni.

Pont Kotlint én még nem használtam, de hasonlót egyszer kipróbáltunk, és ami nekem egyedül ellenszenves volt, az az volt, hogy az a tool nagyon belassította a fejlesztést, mert egyáltalán nem volt annyira optimalizálva mint a sima Java toolchain.

(joco01-nek is írhattam volna)

Szerintem nem ugyanazt értjük "nagy monolit" alatt. :) A hatszáz fejlesztőt nem hasraütésre írtam, valós példa. Ha csak az új dolgokat kezdenénk Kotlinban írni, már akkor is belefutnánk olyan problémába, hogy a 600 fejlesztőből mondjuk mennyi ismeri a Kotlint legalább középszinten? Ötven?

Milyen szempontból?

* Java fejlesztő meghívja Kotlin fejlesztő kódját -> nem lesz probléma (hacsak nem suspend functionről van szó, de ez a Kotlin fejlesztő dolga, hogy tudja, a hívója mit vár el tőle)

* Java fejlesztő review-zza Kotlin fejlesztő kódját -> ha a Kotlin fejlesztő ért hozzá, és hihető, hogy szép Kotlin kódot írt, akkor nincs probléma, a Java fejlesztő fogja tudni olvasni (különben meg vak vezet világtalant)

* Java fejlesztőnek kell Kotlin fejlesztő kódjába belenyúlni -> itt már lehetnek gondok, amit vagy oktatással vagy megfelelő feladatbeosztással lehet orvosolni

Nincsen Kotlin fejlesztő. Az első lépés, hogy legyen, ehhez viszont kell egy business case, hogy mit fog nyerni a cég a váltással. 

Nyilván a 600 fejlesztő csapatokra van osztva, nem mindenki mindent kódol, viszont monolitikus projekt lévén nincs elvi akadálya, hogy holnap egy teljesen új területre kell belenyúlnod. Ha esetleg egy nagyon jól szeparálható, zöldmezős modult kellene csinálni, ott már lehet értelme kotlinos embereket keresni, viszont ha ennyire független alrendszerről van szó, akkor már eleve nem biztos, hogy a monolit részeként kell megcsinálni.

Nálunk az async a fő selling point, amire nagyon sok erőforrást tudunk szánni, mert fényévekkel jobb az alternatíváktól. A Java async kód csúnya, és csúnya bugokat tud szülni, a nem async kód meg teljesítmény szempontból szar. Hogy Kotlinban kevesebbet kell írni, meg szebb a kód, az egy nice to have, de sok fejlesztőt ez már önmagában meggyőz arról, hogy érdemes beletanulni akár önszorgalomból is.

Nagy monolitokat úgy írunk át, ha egyáltalán átírunk, hogy modularizáljuk.
Egy-egy modult aztán átírhatunk másik nyelvre.
Attól függően, hogy mekkora része van átírva, annyi Kotlin fejlesztő kell, és elvileg legalább annyival kevesebb Java fejlesztő.
A modularizáció önmagában is csökkentheti a szükséges fejlesztők számát.

Tehát kezdetben felveszel pl. 10 Kotlin fejlesztőt, akik készítenek és karbantartanak egy modult, majd ha lesz plusz kapacitásuk akkor újabb részeket is átírhatnak. Ha ez jónak tűnik és a piacról tudsz felvenni újabb Kotlin fejlesztőket, akkor bővülhet a Kotlin csapat és csökkenthető a Java csapat.

Én pl. írtam olyan template kezelő library-t (modult), amit könnyedén lehet Javas (spring) projektekben használni, kiváltva a Javas template library-kat.

"felveszel pl. 10 Kotlin fejlesztőt"

Többnyire inkább csak tanulni kellene. Én a jelenlegi cégnél sok év C# és 0 Java fejlesztési tapasztalat alapján lettem Java fejlesztő. Most meg önállóan eldöntöttem, hogy Kotlinozni fogunk, mert TL vagyok és megtehetem és tetszik is a nyelv és a jobb async támogatásra szükségünk van (már nagyon régóta fennálló űrt tölt be). Szerencsére vannak céges doksik az átállást megkönnyítendő, és lehet Kotlin szakértőktől plusz code reviewt kérni, ami felgyorsítja a tanulást. (Nagyszabású átírás egyelőre nincs tervben.)

Ha template, akkor a mai napig semmi sem éri utól az rtemplate-et, amit viszont én írtam: lényegében JSP vagy PHP-szerű az alapja, de két irányú a hozzárendelés, akár a Java, akár a template kódot is szerkeszthetjük, mindkettő működik és áttranszformálódik a másik nézetre egy pillanat alatt. Nincsenek saját konstrukciói, viszont a Java minden konstrukciója elérhető a template alatt is. Emiatt a tanulási görbéje nagyon alacsony, mert az eredeti nyelvet elegendő ismerni. Link: https://github.com/qgears/rtemplate#rtemplate

Az alap ötlet abból a frusztrációból keletkezett az alapötlet még az egyetemen, hogy a JSP-ből generált java kódot nehéz volt kitúrni amikor az egyetemen JSP-zni kellett, és akkor arra gondoltam, hogy miért kell ezt elrejteni a fejlesztő elől?

A kétirányú transzformáció ötlete pedig abból keletkezett, hogy minek valósítanám meg a Java editor összes jóságát a template nyelvben is, mikor már az eredeti nyelvben működik és rendkívül hatékonyan tudom használni. Így a template-ekre is működik az összes refaktor, szemantikus keresés, névkiegészítés satöbbi, ami a kód többi részére is.

A futási teljesítménye a legjobb ami az adott nyelven elérhető.

Nem csak Java-val működik, hanem bármivel, aminek a string eszképelés szabályai egyeznek (de legalább kompatibilis ami kell). Csináltam már vele mikrovezérlőn futó C programot is, illetve C# template-et is.

Gratulálok hozzá!

A futási teljesítménye a legjobb ami az adott nyelven elérhető.

Ennek igazolásához kellene egy benchmark is a legnépszerűbb és leggyorsabb template rendszerekkel. ;-)

Egyébként én nem szeretem keverni az adatot és a kódot, így a template rendszerekből is a legminimalistábbakat szeretem. A template az önmagában is egy helyes, jól megjelenő formátum legyen, pl. , ha html template, akkor a böngészőben is megnézhető legyen, html szerkesztővel szerkeszthető legyen, ... Az adat, az pedig csak adat legyen, amiben benne van minden, amit a template-be be kell rakni.

Benchmark: annó csináltunk valam ilyesmit, de szinte értelmetlen volt, mert az rtemplate-nek semmi overheadje nincsen, amivel meg összehasonlítottuk az elég gagyi volt, ha jól emlékszem reflectiönnel vette ki az adatokat az objektumokból, ami élből több nagyságrenddel lassabb, mint egy sima adattag elérés.

De ha tudsz kihívóról - ami azt állítja magáról, hogy sebességre van optimalizálva - akkor csinálhatok benchmarkot. (Java-ban és C-ben is akár) Eddig nem nagyon találtam olyat, amivel egyáltalán lehetne értelme összehasonlítani.

 

> A template az önmagában is egy helyes, jól megjelenő formátum legyen, pl. , ha html template, akkor a böngészőben is megnézhető legyen, html szerkesztővel szerkeszthető legyen

Igen, az az egy hátránya van az rtemplate-nek, hogy ezt sajnos nem tudja. Amikor még régen próbálkoztam standard HTML template-ekkel, akkor még nagyon nehézkesen működtek ezek a kombinált editorok, amik egyszerre HTML és template editorok voltak, pláne ha volt benne például iterálás, vagy elágazás is nem csak sima behelyettesítés. Általában úgy dolgozok vele, hogy a fordítás, oldalújratöltés kör nagyon gyors legyen és a példaadatokkal kitöltött template kimenetet nézem meg böngészőből visszacsatolásként.

Az enyémben ott a benchmark projekt linkje.

Oda bekonfigolod a saját libedet, majd MR után már része is lehet a projektnek.

Az sem mindegy melyik benchmark programmal méred a futást. A spring-comparing-template-engines projekt az ab programot használta és a JSP lett a legjobb, én a wrk programot (lásd az Ickenham projektben), aminél a Mustache lett a legjobb, a JSP "csak" kb. olyan gyors, mint az enyém.

Azt sem igazán értem hogyan lettek azon projektben ilyen lassúak, pl. a leggyorsabb is 25000 kérést 11,22 mp alatt teljesítette, miközben az én sok éves laptopomon másodpercenként 26500 tud az enyém is, a Mustache meg 34500-at, miközben az elvi határ (üres oldal visszaadása) 40.000 másodpercenként.

> sok éves laptopomon másodpercenként 26500 tud az enyém is, a Mustache meg 34500-at

 > miközben az elvi határ (üres oldal visszaadása) 40.000 másodpercenként.

Még nem nézegettem végig, de ha valami web keretrendszerbe van ágyazva a template, akkor simán lehet, hogy a web keretrendszert mérjük, nem a template-et. Ha már ennyire megközelítjük a lehetőségeket, akkor ez nem túl jó benchmark a template nyelvre. Ha a darabszámot az üres oldalhoz képest nem felezi a template, akkor az azt jelenti, hogy konkrétan az időnek több mint a felét a HTTP szerver viszi el, nem?

Mi annó fájlokat generáltunk, úgy benchmarkoltunk, de még úgy is összemérhető a template futásideje a kerettel.

Szerk.: Az eredmény a gépemen: https://github.com/rizsi/spring-comparing-template-engines/commit/73e35…

$ ./runtests.sh localhost
jsp Time taken for tests: 0.681 seconds
velocity Time taken for tests: 0.295 seconds
freemarker Time taken for tests: 0.246 seconds
thymeleaf Time taken for tests: 0.574 seconds
mustache Time taken for tests: 0.116 seconds
jade Time taken for tests: 23.003 seconds
pebble Time taken for tests: 0.189 seconds
handlebars Time taken for tests: 0.627 seconds
scalate Time taken for tests: 2.457 seconds
httl Time taken for tests: 0.249 seconds
chunk Time taken for tests: 0.272 seconds
htmlFlow Time taken for tests: 0.098 seconds
trimou Time taken for tests: 0.098 seconds
rocker Time taken for tests: 0.104 seconds
ickenham Time taken for tests: 0.217 seconds
rythm Time taken for tests: 1.048 seconds
groovy Time taken for tests: 39.990 seconds
liqp Time taken for tests: 0.531 seconds
rtemplate Time taken for tests: 0.066 seconds

Természetesen a web keretrendszert is méred, de az minden esetben ugyanaz.

X idő a keretrendszer és Y idő a template generálás. A fenti példa esetén 1/40000 mp a keretrendszer. A leglassabb háromszor lassabb, mint a keretrendszer, a leggyorsabb meg sokkal gyorsabb, mint a keretrendszer.

Megmértem, hogy ha csak annyit ír az oldal a writer-be, hogy hello, akkor: Time taken for tests: 0.059 seconds

Látszik tehát, hogy ezen az eredményen a Java nyelven belül már nem nagyon lehet javítani. Persze még volnának ötleteim, de előbb állnék neki Webszervert optimalizálni, mint a template nyelvemet :-). Még nem találkoztam olyan feladattal, ahol ez lett volna a szűk keresztmetszet.

Én a nyers Jetty API-kra szoktam építeni a programjaimat, nem Springre. Megmértem a nyers oldallekérést (hello) abban a keretben amit használni szoktam: benchmark Time taken for tests: 0.090 seconds (Sokadik futásra, elsőre még több is, ugye be kell melegedni a JVM-nek). A Spring azért tud valamit, hogy jobb. Meg is lepődtem, majd rámozdulok és optimalizálok a Jetty-n :-). (Nem, nem állok neki, csak kevés felhasználós oldalakat szoktam csinálni és bőven jó amit tud. De mégis egy kicsit idegesít, hogy mitől lassabb.)

Egyébként nem is a sebessége a legfontosabb előnye az rtemplate-nek, hanem az hogy ami lehet, az direkt Java elérésen keresztül megy, nem reflektíven, és így statikusan ellenőrizve vannak a típusok a template alatt is, illetve működik az összes refaktor is rá. Van olyan kód, amit 10 éves nagyságrendben tartunk karban vele és ahogy halad előre az idő csak egyre elégedettebb vagyok.

 

Szerk.: ha adsz példát a wrk használatára, akkor megmérem, vagy a linkelt forkot megmérheted magad is. Tettem bele plusz két HTML eszképelést, amitől egy icipicit lassabb lett, de még mindig a leggyorsabb. Elég nagy a szórás a mérésekben a template futásidejéhez képest. Mivel jórészt a keretrendszert mérjük, a JVM bemelegedés, vagy hogy épp mikor fut a GC nagyon számít már.

A rocker binárisra alakított változatával, mindháromra bemelegítés után másodszorra futtatva másoltam be az eredményeket:

$ wrk -c 100 -d 10 -t 10 http://localhost:8080/rocker
Running 10s test @ http://localhost:8080/rocker
  10 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.96ms    3.07ms  32.58ms   84.65%
    Req/Sec     4.32k   741.00     7.43k    69.10%
  430650 requests in 10.03s, 3.53GB read
Requests/sec:  42915.62
Transfer/sec:    360.01MB
$ wrk -c 100 -d 10 -t 10 http://localhost:8080/rtemplate
Running 10s test @ http://localhost:8080/rtemplate
  10 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.53ms    3.92ms  43.14ms   84.78%
    Req/Sec     4.00k   835.03     6.53k    68.40%
  399543 requests in 10.04s, 3.23GB read
Requests/sec:  39782.86
Transfer/sec:    329.18MB
$ wrk -c 100 -d 10 -t 10 http://localhost:8080/trimou
Running 10s test @ http://localhost:8080/trimou
  10 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.68ms    3.48ms  40.27ms   85.29%
    Req/Sec     3.19k   627.66     6.55k    69.80%
  318567 requests in 10.05s, 2.96GB read
Requests/sec:  31699.01
Transfer/sec:    302.07MB

A stringek bináris optimalizációja legyőzhetetlen.

Rácsavarodtam a témára, csináltam bináris cache-t a template fix részeihez, és a változókhoz optimalizált UTF-8 konverziót:

$ wrk -c 100 -d 10 -t 10 http://localhost:8080/rtemplate
Running 10s test @ http://localhost:8080/rtemplate
  10 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.77ms    2.90ms  30.56ms   84.98%
    Req/Sec     4.67k     0.87k    8.36k    67.90%
  465705 requests in 10.04s, 3.76GB read
Requests/sec:  46382.70
Transfer/sec:    383.78MB

Ennek a kódja nincsen rendesen végigcsinálva, éppen csak működik, érdekességnek jó, projektet nem építenék rá ebben a formában: https://github.com/jreijn/spring-comparing-template-engines/commit/d7e7…

$ wrk -c 100 -d 10 -t 10 http://localhost:8080/empty
Running 10s test @ http://localhost:8080/empty
  10 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.36ms    2.54ms  47.68ms   84.91%
    Req/Sec     5.63k     0.87k    9.06k    69.50%
  560744 requests in 10.03s, 73.36MB read
Requests/sec:  55929.48
Transfer/sec:      7.32MB
$ wrk -c 100 -d 10 -t 10 http://localhost:8080/ickenham
Running 10s test @ http://localhost:8080/ickenham
  10 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    18.73ms   29.73ms 319.35ms   87.59%
    Req/Sec     1.34k   283.01     2.36k    68.40%
  133268 requests in 10.02s, 1.08GB read
Requests/sec:  13302.56
Transfer/sec:    110.14MB

Itt vannak a legfrissebb számok. A legfrissebb kommit itt van: https://github.com/rizsi/spring-comparing-template-engines

Az igazságosság jegyében újrafuttattam úgy, hogy a jsp legyen az utolsó - "bemelegedjen" addigra a JVM - ráadásul a második mérést írom csak ide, mert a JSP tudtommal első használatkor lefordítja a kódot és dinamikusan betölti osztályként a template-t, tehát bemelegítés nélkül ezt az overheadet is belemérjük:

velocity Time taken for tests: 0.175 seconds
freemarker Time taken for tests: 0.081 seconds
thymeleaf Time taken for tests: 0.185 seconds
mustache Time taken for tests: 0.104 seconds
jade Time taken for tests: 23.788 seconds
pebble Time taken for tests: 0.129 seconds
handlebars Time taken for tests: 0.610 seconds
scalate Time taken for tests: 0.110 seconds
httl Time taken for tests: 0.226 seconds
chunk Time taken for tests: 0.320 seconds
htmlFlow Time taken for tests: 0.071 seconds
trimou Time taken for tests: 0.078 seconds
rocker Time taken for tests: 0.067 seconds
ickenham Time taken for tests: 0.151 seconds
rythm Time taken for tests: 0.104 seconds
groovy Time taken for tests: 37.480 seconds
liqp Time taken for tests: 0.342 seconds
rtemplate Time taken for tests: 0.084 seconds
jsp Time taken for tests: 0.093 seconds

Látható, hogy a mérés körülményein nagyon sok múlik, és a JSP valójában igen jól teljesít. A htmlFlow pedig legyőzte az rtemplate-et! Ajjaj!

Azzal a céllal, hogy összemérjem az rtemplate-t és a htmlFlow-t, mértem 100000 lekéréssel csak ezt a kettőt:

htmlFlow Time taken for tests: 7.056 seconds
rtemplate Time taken for tests: 6.766 seconds
htmlFlow Time taken for tests: 7.176 seconds
rtemplate Time taken for tests: 6.653 seconds
htmlFlow Time taken for tests: 7.254 seconds
apr_socket_recv: Connection reset by peer (104)
rtemplate
htmlFlow Time taken for tests: 8.599 seconds
rtemplate Time taken for tests: 7.047 seconds
htmlFlow Time taken for tests: 7.170 seconds
rtemplate Time taken for tests: 6.759 seconds
apr_socket_recv: Connection reset by peer (104)
htmlFlow
rtemplate Time taken for tests: 6.611 seconds
htmlFlow Time taken for tests: 7.142 seconds
rtemplate Time taken for tests: 6.846 seconds

Látható, hogy több méréssel kisebb az ingadozás az eredményekben, és az rtemplate természetesen stabilan jobban teljesít. Sajnos volt néhány túlterhelésből adódó hiba, amit nem fejtettem meg, hogy hogyan lehetne javítani, de nyilvánvalóan az OS-tesztprogram-HTTP szerver háromság valamelyike a ludas, nem a template nyelv, úgyhogy ezt most megoldatlanul hagyhatjuk.

Hopp, észre sem vettem, hogy ezek is gyorsabbak lettek.

A rockerben ez a feature a killer teljesítmény szempontból szerintem: https://github.com/fizzed/rocker#near-zero-copy-rendering A konstans template stringek újrakódolása UTF-8-ba minden kérésre az ami talán a legtöbb CPU-t viszi és tökéletesen felesleges munka, minden alkalommal garantáltan ugyanazt az eredményt kell adnia.

Az rtemplate logikáján belül nem lehet megcsinálni, az egyszerűséget fel kellene áldozni ennek az oltárán, és az már egy másik eszköz volna, ha beletenném ezt a feature-t. Pont ez az egyik feature, amire azt írtam, hogy vannak még ötleteim hogy hogyan lehet Java-n belül gyorsabbat csinálni... Most nincs nálam a másik gépem amin mértem, de majd lefuttatok erre is több mérést kontra rtemplate, mert kiváncsi vagyok.

Ha már nekiállnék egy új template nyelvnek, akkor eleve olyanra csinálnám meg, hogy korutinként is futtatható legyen a template runtime, mert egyébként a nagyteljesítményű webszerverek problémája már sokkal inkább a sok kontextusváltás, mint bármi más, és NIO szerverrel CPU magonként 1 szálon lehetne a leghatékonyabb kiszolgálást megvalósítani. Még az is lehet, hogy erre a projektre saját HTTP szervert is írni kellene... De sajnos még sosem jött szembe olyan feladat, ahol ennek értelme volna, úgyhogy eddig csak álmodoztam ilyenről.

 

A trimou sajnos annyira nem jól dokumentált, hogy ránézésre meg lehetne mondani, hogy mitől tud gyorsabb lenni, bele kellene ásnom magam, és arra is kellene több mérést futtatnom.

 

Szerk.: Ismételt futtatások 100.000 ismétléssel, még mindig az rtemplate a nyerő:

$ ./runtests.sh localhost
rocker Time taken for tests: 6.350 seconds
rtemplate Time taken for tests: 5.938 seconds
trimou Time taken for tests: 6.522 seconds
rocker Time taken for tests: 6.384 seconds
rtemplate Time taken for tests: 5.946 seconds
trimou Time taken for tests: 6.504 seconds
rocker Time taken for tests: 6.382 seconds
rtemplate Time taken for tests: 6.035 seconds
trimou Time taken for tests: 6.716 seconds
apr_socket_recv: Connection reset by peer (104)
rocker
rtemplate Time taken for tests: 5.984 seconds
trimou Time taken for tests: 6.650 seconds
rocker Time taken for tests: 6.360 seconds
rtemplate Time taken for tests: 5.984 seconds
trimou Time taken for tests: 6.833 seconds

De! Belenéztem a benchmark kódokba, és a rocker példakódja nagyon gyengén van implementálva, mert ugye a rocker nyilván csak bináris kimenet esetén tudja a linkelt killer optimalizációját, a beillesztése pedig nem úgy van megvalósítva sajnos. Ezt javítani kellene, hogy igazságos legyen az összehasonlítás.

Javítottam a rocker benchmark példát, hogy a bináris kimenetét használja. Így már egészen fej fej mellett van az rtemplate-tel: https://github.com/jreijn/spring-comparing-template-engines/commit/d17a…

$ ./runtests.sh localhost
rocker Time taken for tests: 6.102 seconds
rtemplate Time taken for tests: 5.882 seconds
trimou Time taken for tests: 6.544 seconds
rocker Time taken for tests: 5.797 seconds
rtemplate Time taken for tests: 5.894 seconds
trimou Time taken for tests: 6.517 seconds
rocker Time taken for tests: 5.889 seconds
rtemplate Time taken for tests: 6.083 seconds
trimou Time taken for tests: 6.656 seconds
rocker Time taken for tests: 6.016 seconds
rtemplate Time taken for tests: 5.877 seconds
trimou Time taken for tests: 6.481 seconds
rocker Time taken for tests: 5.810 seconds
rtemplate Time taken for tests: 5.878 seconds
trimou Time taken for tests: 6.580 seconds

Jó volna mélyebben belelátni, hogy lehet-e még valamit javítani a Rocker konfigurációján, de már így is túl sokat foglalkoztam a kérdéssel.

Köszi! Jó kis írás!

Igen, sokkal jobban használható a Kotlin, mint a Java.

/ A Scala még a Kotlinnál is jobb szerintem, de a támogatottsága a Kotlinnak nagyobb. A fentiek nagy része egyébként a Scalara is áll. /

Megoldották a nullable típusok kezelését

Remek dolog!

(viszlát Optional)

Attól még a legtöbb esetben jobb az Option(al), egyáltalán nem kell kidobni. ;-)

Lásd pl. itt és itt.