2013. július 29., hétfő

Két OOM Design Pattern

Van pár dolog, amiért nem szól se a checkstyle, se a findbugs, de egyébként nagyon egyszerű megtalálni és csillió van belőle, legalábbis melóban.

Az egyik az, amikor deklarálsz egy HashMap-et és úgy hívod, hogy cache, vagy odakommentezed, hogy ez egy cache. Ez sajnos nem igazán cache lesz, sajnos nagyon gyakran inkább egy OOM. Tipikusan amikor vagy egy singletonban találod, vagy eleve a "cache" statikus. Ilyenkor általában nem gondol az ember azokra a dolgokra, amik megkülönböztetnek egy igazi cache-t a HashMap-től: weak reference, TTL, méret korlátok, stb.

A másik ilyen tipikus gebasz, amivel találkozni szoktam forráskódban, az az amikor valaki felfertőzi a finalize metódust (amikor ilyet találok, mindig elkezdem keresni hogy erre vajon mi oka lehet) és odakommenteli rá, hogy "destructor". A finalize metódus nem destruktor. Ha nem olvastad a javadoc-ot, akkor erre akkor jössz rá, amikor a finallize metódusba valami lassú műveletet pakolt az elkövető. Szerintem ilyenkor leginkáb a HIV vírushoz hasonlít a hatása, lelassítja annyira a GC-t, hogy ne tudjon takarítani és természetesen OOM lesz a vége.

Ez ilyen könnyű győzelem, amennyiben megengedik hogy kijavítsd.

"Ennyi volt a Design Pattern mára,
fiatalember vigyázzon, rádzsael a paprikára!"

2013. július 24., szerda

Master Bean Design Pattern

Master Bean, a google szerint
A Master Bean pattern az, amikor akár EJB, akár spring, akár valami custom házitechnológia bevetése esetén van egy központi ojjektum, ebben található hivatkozás minden DAO, manager, service satöbbi objektumra és minden egyéb kód, a DAO, manager, service satöbbi objektumokat is beleértve ebből az objektumból keresi meg amire szüksége van.
Láttam különböző implementációkat, ezt a Master Bean-t van amikor injektálják, van amikor ősi singleton patternként getInstance()-elik és van olyan is amikor valami izgalmas módszerrel lookup()-olják.

Egyéb elnevezések és hasonló koncepciók: God Object, registry

A Facade nem keverendő a Master Bean-nel, mert a Facade a hívásokat delegálja általában több service objektum több metódusának, a Master Bean pedig csak visszaad egy hivatkozást magára a service objektumra.

Ennyi lenne a design pattern mára. Légkondi megy?

többnejű programming

Egyik nap ebéd közben azt mondtam a munkatársaimnak, hogy szerintem ahhoz hogy valamiből igazán jó legyél, ahhoz erősen fókuszálni kell arra a területre. Emiatt pedig csak 1 dologból lehetsz igazán jó, a többiből csak tűrhető. Például Albert Einstein fantasztikusan jó volt fizikából, emellett még egész tűrhetően hegedült. Ha több dologból is igazán jó akarsz lenni, akkor több dologra is fókuszálnod kellene, ez viszont ütközik a fókusz definíciójával. Milyen fókusz az, hogy fókuszálsz a ruby, a python, a linux kernel és a java technológiákra?

Nos az eredmény az volt, hogy leüvöltöttek. Mint amikor gimiben megkérdeztem hogy a kereszténység miért egyistenhit, amikor van egy rakás szent, angyal, ördög, satöbbi, teljesen kiakadt tőlem a tanár.
Azt mondják az egész csak idő-management kérdése. Ezt én nem értem, megfelelő idő-managementtel ki lehet bővíteni még 8 órával a napot?
Ez a dolog a red hat-nél valószinűleg azért van, mert a java programozónak is egész jelentős bash és linux teszten kell keresztülmenni felvételikor, ellenben szerintem a vizsgáztatók elég keveset tudnak kérdezni java témakörben. A legtöbben tehát a bash rémes szintaxisán és a python követhetetlen csomagrendszerén véreznek el, nem pedig a JPAQL részletkérdésein.

Elhiszem, hogy tűrhető python programozó lesz valaki, míg java programozásban igazán jó, de nem lehet valaki Rambó és Batman egyidejűleg. Még ha agymunkával bírná is, nem fér bele a napba.

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.

2013. május 17., péntek

Google Compute Engine árak

A Google Compute Engine-n ha csinálsz egy 1 TB-os merevlemezt, akkor az a mai árazás szerint az havi 102 USD-be fog kerülni. 102 USD az ma 23.000 forint vagy úgy 2.000 korona. Ebben még nincs benne az ÁFA - ami Magyarországon a legkevésbé sem elhanyagolható tényező.
Ezért az árért a sarki hardver boltban alkudozás nélkül kapsz egy 1 TB-os merevlemezt 2 év garanciával, ebben már benne van az ÁFA is.

A GCE minden I/O műveletet kiszámláz. A bevásárolt merevlemez ilyet nem csinál, viszont áramot zabál.

Sebesség: Egy GCE gépemen kipróbátam egy dd paranccsal felszívni egy 20 GB-os lemez tartalmát a /dev/null-ba. Elsőre 90 MB/sec sebesség jött ki, de aztán egy másik diskről próbáltam ugyanezt és azzal csak 30 MB/sec jött. Az írási sebességben voltak hasonló eltérések, de az persze egy kategóriával lassabb volt. A Compute Engine SLA egy szóval nem említi, hogy mennyivel kellene jönnie. Bízzuk a szerencsére.
Ugyanez egy sima merevlemeznél mondjuk elég egyszerű, egy sima bolti SATA vincsitől számíthatsz 100 MB/sec sustained read, és úgy 80-90 MB/sec sustained write sebességre.

Ha már GCE SLA: Jól értem hogy 5% unplanned downtime esetén visszakapom az ár felét? Több mint egy nap havonta és csak a fele? Ez nem hangzik jól, annyinál már az egészet hagynám a fenébe. És havi fél óra downtime belefér? Nem tűnik úgy, hogy nagy megbízhatóság lett az árba belekalkulálva.

A GCE csak egy példa. Sokkal olcsóbban is lehet virtuális szervert szerezni a sufni webappjainknak, de szerintem még sokat kell hogy alakuljon a publikus felhők árazása.

2013. április 19., péntek

code review (anti)patterns

Egyik nap néhány munkatársammal beszélgettünk arról, hogy hogyan haladunk és egyetértettünk abban, hogy ahogyan a code review történik, az nem csak hogy nem segít a minőség javításában, de néha teljesen hülye hibákoz is vezet. Én a hiba okát abban látom, hogy a reviewer soha nem tesztel. Túl sok dolga van. A reviewer minnél hamarabb túl akar lenni az egészen, ezért megkeresi az első hibát, lefikázza és otthagy. Ez általában a commit comment, amit átírsz és majd a későbbi patchek során hetekkel később kiderül hogy mégse volt az olyan rossz.
Mindenesetre a patch írói az első verziót szokták tisztességesen letesztelni. A második verziót talán. Mindegy, X idő és Y review után már a tökük televan ezzel a patch-el, szánják-bánják hogy hozzákezdtek és a végül elfogadott patch-en könnyen lehet hogy a kutya se futtatott teszteket, ha ugyan vannak még benne. A manuális tesztekről inkáb ne is beszéljünk :) Az nyilvánvalóan csak az első pár patch-nél történt és a véglegesnél nagy valószinűséggel nem. Gyakran van az, hogy a végleges verziót már marhaságnak tartom, de mindegy, csak menjen már.
(Szakirodalom: Boris Vian: Venyigeszú és a plankton)

Szóval erre halmoztunk fel pár zavaró megoldást amit felváltva és kombinálva használunk. Ezek nagyban növelik a káoszt, de kicsit javítják a teljesítményt, minket persze az utóbbi érdekel.

  1. Küldj patchet akkor, amikor a csapat meetingen van. Tréfi, de ez van. Szükséged van valakire nyilván aki elfogadja neked gyorsan, de a legjobb ha nem adsz időt a trolloknak, meg a hatszáz rebaselést is elkerülöd.
  2. Spameld a reviewereidet.

    A legegyszerűbb kommentbe írogatni hogy "ping". Rossz esetben blokkolva leszel, ekkor változtass e-mail címet. (gúgliban a gipsz.jakab+1@gmail.com pl műxik) Naponta vagy másnaponta egy email nekem elegendő középútnak tűnik egy kultúrált úriember és egy nigériai tábornok között, de persze volt már aki teljesen kiakadt és sikítozni kezdett. Nem lettem érte lecseszve, a CÉG majomként kezeli a szoftverfejlesztőket. Ez szerintem sem áll távol a valóságtól.
  3. Ha csinálsz junit teszteket, soha ne pakold ugyanabba a patchbe, mint amibe a kódot. A patch-sor végén elég lesz. Ha eljutsz odáig, akkor bekerül, ha nem akkor meg nem tart fel. De tipikusan egy olyan tényező, ami csak feltart. Az egyik oka annak, hogy nem igazán vannak junit tesztjeink az az, hogy mindig az kerül utoljára hogy legalább valamennyire haladjunk.
  4. Racionalizáj: dobd ki a reviewereket egy adott létszám felett! Az inkatívakat mindenképpen, mert rájuk csak várnak. Az akadékoskodókat csak ha lehet.

    Próbáld ki, írj egy közös akármit (levelet a nagymamának, főnöködnek, a köztársasági elnöknek vagy a halál pöcsének) úgy hogy 8 embernek egyet kell értenie minden szavával és senki nem akar még hozzátenni valamit. Amit valaki hozzá akar tenni, azt más majd el akarja venni. 8 ember nem tud egyetérteni valamiben. (Szakirodalom: 12 dühös ember)
  5. Újra ugyanazt

    Teljesen működő megoldás mégegyszer más címen vagy akár csak más ID-val elküldeni ugyanazt mégegyszer és esetleg valaki mást kérni review-re. Lebukás-veszély persze van, de szerencsére úgyse tudják megjegyezni a nevemet.
  6. Szép dolog maintainernek lenni, de haszontalan

    Ez megint egy érdekes csavar a történeten, de egy rémegyszerű dolgot nem sikerült sehogy sem átverekednem a többi maintaineren, senki sem merte bevállalni. Egy idő után eldobtam a patch-et, úgy gondoltam elég időt pazaroltam rá. Pár hónappal később egy új kolléga küldte el tejesen ugyanazt a változtatást. Csak leellenőriztem és be is lett mergelve.
  7. Dobd ki az ablakon.

    Ezt sajnos gyakran csinálom, de ha 2-3 hétig a noszogatás ellenére se csinál senki semmit, akkor kidobom a patchet. Ez a legtöbb reviewernek nem probléma. Néhányan szoktak csak felháborodni hogy "de hát jó volt". Lehet hogy jó volt, de sehova se haladtunk vele. Rémesen sok időt elvesztegettünk rá és végül sehova se jutottunk, de még mennyi időt elvesztegethettünk volna arra, hogy sehova se jutunk a végén? Egy újraírás talán csak 5 perc. Teszttel együtt egy óra :D De ez semmi ahhoz képest hogy mennyi baszakodás lesz vele.

Szóval a rendszer elég egyszerű lenne, de valahogyan mindig kisebb-nagyobb csalásokra kényszerül az ember. Nem egzakt tudomány, inkáb számvitel és politikatudomány mint matek és fizika. Valami ilyen lehet földhivatalban dolgozni.

Tudom kurvára utáltok amiért képtelen vagyok a marketinglófaszt elénekelni nektek, de gondoltam ez valamivel hasznosabb lehet :)

2013. április 1., hétfő

Atom / RSS feed test tool

Van a w3c feed validátor, ami király, de a leghétköznapibb RSS feedre is azt mondja, hogy törött. Sajnos igaza van, de nem állhatunk meg tökölni amikor kiderül hogy az internet fele sz*r, hanem megtanuljuk szépen tolerálni a hülyeséget. Másrészt a technikai minőségéről semmit nem mond, csak a formátumáról.


Szóval csináltam egy saját feed test eszközt, amivel a legutóbbi teszt szintén elég szomorú (de legalább szines) eredményeit hoztam ki. Tessék ehun van e. A kis edit boxba kell bedobni az RSS/Atom feed-ed címét és kidobja az eredményt. Nem túl felhasználóbarát felület. Ha gondolod próbáld ki a saját feed-jeiden és szólj vissza ha valamivel nem értessz egyet!