A következő címkéjű bejegyzések mutatása: kotlin. Összes bejegyzés megjelenítése
A következő címkéjű bejegyzések mutatása: kotlin. Összes bejegyzés megjelenítése

2019. január 22., kedd

Kotlin null-biztonság

A kotlin mellett még mindig a szuper-barátságos null-safety a legjobb érvem. Aki esetleg nem ismerné a kotlin nyelvet, Annak röviden:
A kotlin fordítási időben ellenőrzi a változók és értékek típusát.
Azaz mindent úgy kell deklarálnod (a kotlin erősen típusos nyelv) hogy lehet-e null vagy sem.

Például:

var neverNull : String = "bla bla bla"
var maybeNull : String? = null // hoppá alapból pont null

Lehet próbálni a széllel szembe pisilni:

var amISmarterThanTheCompiler : String = null // compiler error

A compiler pedig kikényszeríti a null értékek tiszteletét, azaz mindig kell valami null-ellenőrzést beiktatni. Lehet old-school if(blah!=null) a kotlin elvis-operátorával, vagy a null-safe navigációval, pl

person.taxId?.startsWith("1234") ?: false

A legeslegesleg szeretetre-méltóbb dolog az, hogy ezt adatreprezentációban, a kotlin data osztályokban.

data class Person (
  val firstName : String,
  val lastName: String, 
  val taxId : String?
)

Millió órányi NullPointerException-kergetés után könnyes szemekkel hüppögve kérdezhetjük:

Akkor most meg vagyunk mentve?

És a korrekt válasz: lófaszt. Illetve már majdnem, csak még nem.

Persze azzal kezdtem, hogy fordítási időben ellenőrzi a null-biztonságot. Ebből következően bármi ami nem kotlinból jön, hanem java, groovy, akármi, az megsértheti ezt a szabályt és egy ideig ez ki sem derül.


1. számú gyanúsított: Serialization

A legnyilvánvalóbb tréfát serializationnel lehet elkövetni.

data class Person (
  val firstName : String,
  val lastName: String, 
  @Transient val name = "$firstName $lastname"
)

Tessék kérem serializálni, deserializálni, majd

person.name.startsWith("Meglepi") // bang

2. számú gyanúsított: Jackson 

A jackson egyébként az evidens esetekben kedvesen szól, hogy nem lehet null valami...

data class Person (
  val firstName : String,
  val lastName: String
)

objectMapper.readValue(""" 
 {
   "firstName":"Kakukk",
   "lastName": null
 }
""", Person::class.java)

És itt a jackson felháborodik, amitől mindenki megnyugszik, hogy tessék, biztonságban vagyunk. Igen, majdnem...

data class Person (
  val firstName : String,
  val lastName: String,
  val titles : List
)

val person = objectMapper.readValue(""" 
 {
   "firstName":"Eugene",
   "lastName": "Cuckoo",
   "titles" : ["dr",null,"sir"]
 }
""", Person::class.java)         // nahát, működött...
person.titles.forEach(::println) // bang

Erre többször nyitottak bugot a jackson-kotlin modul bugtrackerében, összegyűlt tekintélyes mennyiségű szavazat. Minden alkalommal a fejlesztő pár hónap után lezárta ugyanazzal a kommenttel: wont fix. A jackson egy java komponens, nem érdekli a kotlin nullsafety.

Egyébként egyre népszerűbbek az egyéb JSON libraryk, mint a moshi... meglátjuk, van időm. Inkáb egy jól ismert lókötő, mint egy civilizált idegen, nem?

3. számú gyanúsított: mindenki

De legyen elég mára ennyi a paranoiából, mert végülis csak annyit akartam mondani, hogy
  1. Semmi baj, túl lehet élni, csak figyelni kell rá.
  2. Mindent addig kell kínozni, amig a kívánt vallomást meg nem teszi.
  3. Oké elég, takarodó

2015. november 9., hétfő

kotlin 1.0-majdnem

A kotlin programnyelv közelít az 1.0 kiadáshoz és érezhetően nő az érdeklődés körülötte, gondoltam pár további tapsztalatot megosztanék arról, hogy hogyan alakult a történet az utóbbi hónapokban.

Kezdjük mondjuk azzal, hogy a fejlesztők néha felvetettek egy-egy kérdést fórumra blogra és így az aktív felhasználói közösség részt vehetett a kotlin nyelv alakításában. Ez szimpi.

Ennek keretében szinte utolsó elötti húzásként kötelezővé tették az annotációk elötti kukacot. Lehetett mindent telekukacolni. Szintén viszonylag nemrég kicsit lazítottak a nullpointer védelmen és már nem kell mindenhova !!-t meg ?-t írni, ha java kódot hív az ember.

Főleg az utóbbi pár hónapban a fejlesztők kidobtak egy csomó deprecated funkciót és jópár másikat pedig átneveztek. Ennek következtében elég sok időt rá kellett szánni a migrációkra. Erre számítnia kell annak, aki 1.0 elötti programnyelvet használ.

A compiler nem igazán lett gyorsabb, de végre feltalálták az inkrementális fordítót és az ideába integráltak egy fordító démont, ez kicsit segít a problémán.

Szerintem továbbra is elég kedvetlenül támogatják a maven felhasználókat, a gradle-t sokkal inkáb. A maven compiler például annyira kevéssel gyorsul a második fordítás során, hogy az simán lehet mérési hiba, szerintem egyszerűen csak nem működik az incremental compiler mavenben és kész. Az is ide tartozik például, hogy a régi dokumentációs eszköz, a kdoc soha nem kapott működő maven plugint, az új dokumentációs eszköz a dokka pedig még mindig nem elérhető a maven centralból. Na jó, szóval a másik kevésbé-siker-sztori a dokumentáció generálás.

A bytecode idáig minden release körül változott. Ez azt jelenti, hogy a kotlin 0.11-el lefordított library nem működött kotlin 0.12-vel. Ennek ellenére léteznek kifejezetten kotlin-hoz írt libraryk:
  • A jackson-hoz van egy kotlin modul, ami a kotlin data osztályait segít JSON-ba és vissza alakítani.
  • A kovenant egy kotlin framework Future ojjektumok köré
  • Quasar - actor és satöbbi library kotlinhoz. Olyan mint az akka scala-hoz.
Szóval legalább ez a néhány népszerű fejlesztő csapat rendszeresen adott ki frissítést a kotlin verziók megjelenése utáni napokban vagy általában inkáb órákban. Szép tőlük.

Elvileg a legutóbbi beta kiadással lezárták a módosításokat és mostantól kezdve igyekeznek majd kompatibilisek lenni.

Az IDE támogatás mint az egy IDE fejlesztő cégtől elvárható, elég kellemes volt idáig. Mondjuk nem érzem magam másodosztályú IDEA felhasználónak egy java fejlesztőhöz képest. Engem kicsit bosszantott, hogy minden új kotlin release-hez egy új IDEA verziót is be kell szereznem, mert a régivel már nem műxik a plugin. Nagyon sok időt nem kellett ezen elszúrnom, de minden alkalommal egy fél óra nekem az már sok. Az új IDEA-ba már alapból benne van a kotlin, remélem így kényelmesebb lesz.
Határozottan örülök neki, hogy lassan szobatisztává válik a kotlin, egy egész használható dolgot kapunk, de azért még van egy hosszú listám arról, hogy mit szeretnék kapni. Jön a karácsony :)
  • Valami olyasmi, mint a PMD java-ban igazán hasznos lenne kotlin-hoz
  • Sonar plugint!
  • gyorsabb compilert
  • több valamit, kevesebb semmit

2014. augusztus 19., kedd

kotlin helyzet

Csak egy gyors véleményösszegzés arról, hogy hol tarhat most a kotlin programnyelv fejlesztése. A project célkitűzésein végigfutva:
  • Legalább olyan gyors compiler legyen, mint a javac
    Ezt jelenleg alulmúlja a kotlin. Állítólag hónapokon belül érkezik az incremental compiler, de még nem jött meg. Nyomai persze már vannak a forráskódban. Szerintem jelenleg elég lassú. (fordítás közben az ember végigvizslatja az I7-es processzorral szállított laptopok árait)
  • Java kompatibilis
    Ezen a téren viszont egészen jó, teljesen normálisan használható a kotlin kód java kódból és fordítva. Az extension funkciók szerintem jól eltalált dolog, a null protection is transzparens a java felől nézve.
  • Biztonságos
    A designt nézve elég biztonságos, de nekem hiányoznak az olyan eszközök, mint a findbugs, amivel gyorsan automatikusan végig lehet túrni a kódot tipikus hibák után. Fejben már elkezdtem összeszedni egy listát azokról a dolgokról, hogy hogyan lehet magadat lábon lőni kotlinban egész könnyen.
  • Kifejező
    Ez passzol. Közel sem olyan cifra, mint a scala, de az egyszerűségével nekem tetszik.
  • Milyen főbb lépések vannak hátra
    Ezt megkérdeztem a fejlesztőktől és válaszoltak. Igen pont abból a párbeszédből kiderül, hogy visszafelé nem kompatibilis. Ezért library jellegű dolgot írni kotlinra még kissé bosszantó. Le is mondtam az egyébként csinos spek BDD toolról a jbehave javára.

Hát ennyi. Kérem kapcsolja ki.

2013. június 9., vasárnap

MongoDB - pár tapasztalat

Mostanában szabadidőmben MongoDB-re írogatok mindenfélét, gondoltam írok egy kicsit alaposabb beszámolót arról hogy milyen marhaságokat csináltam eddig vele. A legutóbbi régen volt és nagyon felületes.

Bosszantó apróságok


Nyugodtan kezdhetjük a rossz hírekkel, nem lesznek nagyon rosszak, inkább csak bosszantó apróságok.

Az egyik ilyen az, hogy 32-bites rendszeren a mongodb behúzza a kéziféket és max 2 GB méretű adatbázist enged. Ez lófüffy, fogalmazzuk talán inkáb úgy, hogy 32-bites rendszereken a mongodb röpképtelen.

A másik apróság, amibe belefutottam még az elején, az az hogy a OpenVZ virtuális gépeken valami okból memóriaszivárgás van a MongoDB szerverben és ettől teljesen használhatatlan. Bevallom nem néztem igazán utánna, de itt került fel az OpenVZ a ganajlistára. Miféle virtualizációs technológia az, amivel egy adott szoftver a vendég operációs rendszerben behal? Gubancos, gondolom.

Sokkal inkáb bosszantó a MongoDB hanyag viselkedése a tárhellyel. Az alapbeállításokkal  folyamatosan logolja az összes adatmódosítást, ami rettenetes méretű logokat eredményez nálam. Kicsit kellett keresgetnem hogy hogyan lehet kikapcsolni.

A másik tárhely-kellemetlenség 3 GB-os journal, amit az adatbázis inicializálásakor létrehoz. Bár a memóriafogyasztása egyébként nagyon frankó lenne, ez a 3 GB journal kicsi adatbázisokhoz nagyjábol diszkvalifikálja. Ki lehet kapcsolni, akkor kicsit visszavesz a sebességből és egy esetleges crash teljesen hazavágja. Akkor most gondolkozzunk el rajta hogy mit szeretnénk inkáb.

Klassz dolgok


Szóval az egyik klassz dolog amit igazán kedvelek a MongoDB-ben, az UPSERT, ami az "insert or update"-re egy rövidítés. Ez pl log feldolgozáskor marha gyors tud lenni és az alkalmazáson is nagyon sokat egyszerűsíthet. Az upsert egyszerűen úgy működik, hogy megmondod a keresőfeltételt és egy dokumentumot. Ha talál a keresőfeltételnek megfelelő dokumentumot, akkor ahhoz hozzávágja az új dokumentumot, tehát azokat a kulcsokat, amik a régiben voltak, azokat felülírja (itt lehet trükközni), ha nincs ilyen kulcs, akkor hozzáteszi a dokumentumhoz. Amennyiben nem talált ilyen dokumentumot, akkor csinál egyet, ami megfelel ennek a keresésnek, azaz benne lesz a keresett kulcs és a bedobott dokumentum.

Nézzük a fent említett okosítást: például nekem hasznos az, hogy egy dokumentumban egy tömbhöz fűzök hozzá értékeket illetve érték párokat. Erre jó a PUSH, amivel a régi doksiban nem írja felül a régi értéket, hanem csak hozzáappendel. Ez upsert esetében is teljesen jól muzsikál.

Az marha sokat segít, hogy nem kell csekkolni, hogy egy dokumentum létezik-e már a feldolgozás során.

A sebesség a másik baró dolog. Eleinte voltak olyan tévhiteim, hogy az adatmennyiséggel egy beágyazott derby is el fog boldogulni. A derby hozta is a formáját az első pár órában, amikor azonban a memória méreténél nagyobbra nött az adatbázis mérete, beleállt a földbe a teljesítménye.

Trükkök


Relációs adatbázishoz szokott barátaim: egy pár dolgot át kell gondoljunk, amikor mongodb országba települünk.

Például relációs adatbázisokban nagyjából magánügy, hogy hogy nevezed a tábláidat és az oszlopokat, a teljesítményre aligha van hatással, mert nem kerül bele minden rekordba, legfeljebb amikor lekérdezést küldünk az adatbáziszervernek akkor kicsit több byte-ot küldünk. Nem nagy ár, ezért inkáb érthetőre próbáljuk faragni a relációs sémát szép oszlopnevekkel. A különbség egy dokumentum-alapú, séma-nélküli adatbázisnál az, hogy minden dokumentumban benne vannak a kulcs-nevek, így a rövidebbet jobb sebességgel jutalmazza az adatbázis szerver.
Én pofátlanul mindent egy-két betűsre rövidítettem. Ezt a dolgot ha valaki átvenné tőlem, nagyon gyűlölne.

Ezzel kapcsolatban jut eszembe az _id kérdése. A mongoDB minden dokumentumba beletesz egy _id nek nevezett, 12-byte hosszú azonosítót, amiben a szerver azonosítója, egy random szám, valami sorszám, a heti lottó nyerőszámok és ilyesmi tlálható. Az én alkalmazásomhoz nem volt igazán hasznos, de egy databig nem jöttem rá erre:
A dokumentumodnak amúgy is kell valami, ami amolyan elsődleges kulcs. Egyszerűen ezt a dolgot hívd _id-nak. Még akkor is, ha az "id", az "azon", és a "customerid" elsőre jobban tetszik. Az _id ugyanis nem kell, hogy a fenti szám legyen. Lehet szöveg, szám, akármi. Értelmesnek tűnik saját ID-t csinálni.

Emellett persze az _id az a dolog, ami mindig indexelve van, nem is kell kérni és nem is lehet kikapcsolni.

Indexek: meg tudom erősíteni, hogy amit nem indexelsz, arra a lekérdezés egészen lassú lesz. Ezt gondolom gondoltad :) Az indexek viszont rendesen meglendítik a memóriahasználatot, szóval okosan azzal az indexel.

Még egy trükk, amiért lehet hogy máglyára küldenétek. Olyanra is volt szükségem, hogy egy dátumokhoz számértékeket rendeljek. Eleinte így csináltam:
[{k: Date(), v: 1}, {k: Date(), v: 3}, {k: Date(), v: 4}]

Ez kicsit terjengős dolog, úgyhogy azt találtam ki, hogy a dátumot szöveggé alakítom, mégpedig egy nagyon tömör szöveggé (amire összeütöttem egy 75 vagy 76 digitből álló számrendszert, az még könnyen olvasható) és az így adott dátumokhoz simán csak a számot rendelem. Ilyen lett:

[{"8V3": 1}, {"8V4": 3}, {"8V5": 4}]

Ennél én sajnos nem tudok tovább egyszerűsíteni, de ha egy dátum csak egyszer fordulhat elő, akkor csinálhatnám így is:

{"8V3": 1, "8V4": 3, "8V5": 4}

Ez ocsmány trükknek tűnhet, de nagyon sokat segített az adatbázis  méretének redukálásában. Illetve vehetek nagyobb gépet is persze. Vagy kérhetek karácsonyra.

DAO kérdések


No utolsó beteg design patternem következik így vasárnap este...

Relációs adatbázisoknál a resultset-eket tipikusan egy listává alakították át a DAO-k, ehhez az egész resultsetet elösször végigolvasták és objektumokká formálták. Na ez nagy adathalmazokhoz soha nem volt jó ötlet, de olyan ritkán kellett ilyesmit csinálni. És most mintha mást se kellene.

Szóval én meg akartam tartani a listát mert olyan egyszerűen lehet vele bánni, viszont eszem ágában sem volta teljes eredményhalmazt berángatni a memóriába. Szóval a megoldás egy olyan lista lett, ami Closable is. Így viszont a DAO metódosukat hívó kódnak be kell zárnia a listát. Ez a része szokatlan és kicsit bizonytalan vagyok a kérdésben. A problémát azért megoldotta.


Kotlin nyelven azért egészen egyszerű a dolog a (szerényen dokumentált) use funkció segítségével.

dao.getBlaList().use { it.each{ ... } }



Ezt nyugodtan fikázzátok le, nem garantálom hogy átírom de garntáltan érdekel a véleményetek! No ennyi mára, boldog hétfőt!

Tartozom még egy beszámolóval a linux konferenciáról, nem éppen java de volt java is.