A kódom (véletlenül) egy olajfúró torony vezérlőszoftverébe került. Ezt a 6 dolgot tanultam belőle.

2010-ben az első fejlesztője voltam az egyik legfejlettebb Windows-os charting könyvtárnak, a Visiblox-nak. A komponenst eredetileg azért fejlesztettük, hogy azt pénzügyi cégek (bankok és alapok) integrálják az alkalmazásaikba. Aztán a kiadása után pár hónappal teljesen váratlanul ért a hír, hogy a világ egyik egyik legnagyobb olajfúrótornyán a kritikus folyamatok a monitorozására ezt a komponenst használják. Amely komponens kódjának a legnagyobb részét én írtam.

De mielőtt túlságosan előreszaladnék, kezdjük inkább az elejéről.

Túl sok adatpont és túl lassú diagramok

2009-ben a BME elvégzése után a Scott Logic pénzügyi tanácsadó cégnél dolgoztam Edinburghban. Itt egy csomó banknak és pénzügyi cégnek fejlesztettünk változatos dolgokat - és észrevettük, hogy a legtöbbjük mind panaszkodik a charting komponenseikre. Mindannyian több tízezer (vagy százezer) adatpontot akartak megjeleníteni az alkalmazásaikban. Ugyanakkor az akkori Windows-os charting könyvtárak (mint Telerik, DevExpress, Ingragistics) mind nagyon mutatósak voltak... csak éppen pár száz pontnál több rajzolásakor elkezdtek akadozni és a gyakorlatban használhatatlanná válni.

Ez a felismerés adta az ötletet: fejlesszünk egy hatékonyabb diagram komponenst, ami több millió adatpontot is meg tud jeleníteni, illetve villámgyorsan tud ki- és bezoomolni. És ha már így nekiálltunk, fejlesszük baromi kiterjeszthetőre is: például tetszőleges számú X vagy Y tengelyt is lehessen hozzáadni a komponenshez (néhány nagyon spéci alkalmazásban több Y tengelyre szükség lehet).

Összeraktunk egy prototípust egy hónap alatt, gyorsan szereztünk visszajelzést az ügyfeleinktől, majd 6 hónap után kiadtuk az első verziót. A banki ügyfeleinknek bejött az új könyvtár, illetve pár másik cég is megvette a szoftverünket. Az ügyfeleink változatos projektekre használták a diagramokat, tőzsdei adatok vizualizásától egészen versenyautók fordulatszámának a valós idejű megjelenítéséig.

Én pedig begyűjtöttem a pacsikat a kollégáktól, s a jól végzett munka tudatával hátradőltem a széken, azzal a tudattal, hogy a pénzügyi világ diagram rajzolási gondjait Windowson egyszer s mindenkorra (de pár évre biztosan) megoldottuk.

Visiblox diagramok

Aztán egy áprilisi reggelen megcsörrent a telefon, és hirtelen egyáltalán nem voltam biztos benne, hogy jól mértük fel, hogy ki is fogja használni ezeket a diagramokat.

A Telefonhívás Texasból

Pár hónappal az első verzió kiadása után egy telefonhívás futott be valahonnan Texasból. Egy csapat, aki megvette a szoftverünket, segítséget kért annak integrálásához. A fejlesztők egyszerre több X tengelyt akartak különböző mértékegységekkel és színekkel megjeleníteni.

A diagram komponensünk támogatta ezt a forgatókönyvet, habár én személy szerint nem találkoztam senkivel, akinek valóban szüksége lett volna ilyen felhasználásra. Így aztán elkezdett érdekelni, mi az, amihez több X tengely kellhet, ők pedig készséggel elmagyarázták, hogy durván egy ilyen diagramot akartak megjeleníteni:

A texasi csapat projektje, amihez több X tengely megjelenítésére volt szükségük

Az eddig nem különösebben izgalmas beszélgetés hirtelen nagyon is érdekes kezdett lenni. Fúrás mélysége? Fordulatszám? Rezgés mértéke? Mit fejleszt ez a csapat tulajdonképpen és hol fog ez futni? Ők meg nemcsak elmondták, de meg is mutatták, hogy az egyik monitoron fog futni, ebben a helységben:

A monitor, ahol az alkalmazás futni fog

Ami mellesleg a vezérlőterem a világ egyik legnagyobb olajfúró tornyán:

A világ egyik legnagyobb olajfúrótornya

És ez volt az a pillanat, amikor leesett: basszus, amíg én itt egy kis irodában dolgozok, addig, a kód, amit írtam, a világ másik felén nagyon durva dolgokat művel!.

Hat dolog, amit az olajfúrón dolgozó fejlesztőktől tanultam

A következő néhány héten sokat segítettem az olajfúrótorony fejlesztőinek az integráció befejezésével, mielőtt élesítették volna azt (egyébként tudtommal a mai napig ugyanez a komponens fut a vezérlőegységen). Itt a legfontosabb 6 dolog, amit ebből az esetből megtanultam.

1. Egy telített piacon a sikerhez a terméked 10x jobb kell, hogy legyen, mint a konkurenciádé

Az egész fejlesztési ötletet az adta, hogy több ügyféltől hallottuk, hogy panaszkodnak a meglévő chart SDK-kra. Mielőtt bármibe belevágtunk volna, leteszteltük az összes jelentős komponenst (a későbbi versenytársainkat), hogy megnézzük az erősségeiket és a gyengeségeiket.

Tudtuk, hogy senki se fektet időt egy új eszköz megismerésébe és integrációjába, ha csak egy kicsivel jobb, mint a meglevőek. Ha egy létező és érett piacon akarsz egy új terméket bevezetni, annak legalább 10x olyan jónak kell lennie több területen, mint a meglevő alternatívák.

Amikor elkezdtük a fejlesztést, több, mint 20 charting könyvtár létezett WPF-en, amiket már 5-6 éve fejlesztettek. Mi a piaci lehetőséget ott láttuk meg, hogy semelyikük sem tudott normális teljesítménnyel több, mint 500 adatpontot megjeleníteni, mi pedig azt tűztük ki célul, hogy 1M pontot is akadozás nélkül kirajzolunk. Vagyis 2000x több adatpontot támogatunk, mint bármely versenytársunk, és emellett extra funkciókat is kínálunk (mint ki- és bezoomolás és tetszőleges mennyiségű X és Y tengely).

2. Minél hardcore-abb eszközöket készítesz fejlesztőknek, ők még annál is durvább alkalmazásokat fognak összerakni

A diagram komponenst egy WPF SDK-ként készítettük, kizárólag fejlesztőknek szánva, hogy mindenféle alkalmazásba integrálhassák. Mielőtt nekiláttunk a fejlesztésnek, összeraktunk egy listát pár lehetséges hardcore használati lehetőségről, például több Y tengely használatára több százezer pontot rendelve mindegyikhez és egy csomó pénzügyi szektorban használatos sok adatpontos megjelenítési formáról.

Tudtuk, hogy úgy se fogjuk tudni lefedni az összes lehetséges esetet, úgyhogy igyekeztünk minél kiterjeszthetőbbé tenni a komponenst - például tetszőleges számú és megjelenésű X és Y tengelyt engedtünk definiálni, alosztályokon keresztül pedig szinte minden rajzolási logikát meg lehet változtatni. Emellett azért pár őrült, a valóságtól teljesen elrugaszkodott diagramot is összeraktunk, csak hogy rendesen sztressz teszteljük az SDK-t.

Ugyanakkor a legváratlanabb dolgok a való világbeli felhasználásokból jönnek. A mai napig nem láttam olyan összetett - és abszolút valós igényű - diagramot több X tengellyel, mint amit az olajfúró toronyhoz raktak össze. Azt meg külön ötletesnek - és kifejezőnek - találtam, hogy az Y tengelyt a fúró mélységének a megjelenítésére használták.

3. A legkritikusabb rendszerek sem építenek mindent a nulláról

Az olajfúrón dolgozó fejlesztők egy meglévő, saját fejlesztésű diagram komponenst akartak lecserélni a mienkre. Eleinte kénytelenek voltak saját maguk írni egyet, mert nem találtak semmit, az igényeiknek megfelelt volna. Ugyanakkor nem voltak elégedettek se a teljesítményével, se azzal, hogy egy csomó időt kellett hibajavításokkal tölteniük, és idővel egyre nehezebb lett karbantartani a kódjuknak ezt a részét.

Időben és pénzben is sokkal jobban megérte nekik egy meglévő komponenst integrálni - és nem szóraknozni a diagram rajzolás hogyanjával, amit mi jobban megoldottunk, mint ők bármikor. A diagram UI-ja ugyan nagyon fontos része volt a rendszerüknek - ha pl a fúró hőmérséklete átment pirosba, manuálisan visszavettek a mérnökök a fúró teljesítményéből -, de még így is jobban megérte nekik egy külső, megbízható komponenst használni saját írása helyett.

Ha egy megbízható eszközt fejlesztetsz, ami jelentősen megkönnyíti a fejlesztők munkáját, akkor a fejlesztők iparágtól és kritikusságtól függetlenül is használni fogják az eszközödet. (Megjegyzés: nyilván pragmatikusan fognak hozzáállni: minél kritikusabb a komponens, annál nagyobb értéket kell az eszköznek hozzáadnia, hogy ne sajátot fejlesszenek).

4. A nagy teljesítményű szoftverek messzemenően kihasználják a nyelv, keretrendszer és platform lehetőségeit

Amikor elkezdtük a fejlesztést, nem egyből kódolással indítottunk, átgondoltuk és felmértük a gyakorlati korlátainkat, prototípusokat építettünk és ezeket mértük, hogy eldöntsük, milyen megvalósításokat választunk.

Hány adatpont a maximum, amit memóriában tárolhatunk? Mekkora memória áll rendelkezésünkre és mekkora helyet foglal egy adatpont tárolása? Használjunk class-okat egy 8-12 byte-os extra memóriafoglalásért cserébe pontonként, vagy inkább maradjunk struct-oknál? Ha struct-okat használunk, akkor csak a stack méretéig nőhet a memória használatunk, vagy a heap-et is használhatják?

Mi a leggyorsabb módja a sok pont rajzolásának a WPF keretrendszeren belül? Érdemes bitmapekre rajzolni, vagy használjatjuk a Canvast vagy van más módszer is? Hogyan működnek a különböző megoldások zoomolással? Mielőtt letettük volna a voksunkat bármelyik megoldás mellett, több napig prototípusokat építettünk, mértük a sebességüket és memórihasználatukat, majd ez alapján választottunk [1].

Az alapos előkészületek után a komponenst összerakni sokkal egyszerűbb volt, mint azt vártam: egy első, elég jól működő verziót kb egy hónap alatt felépítettünk. Ehhez az egyszerűséghez és teljesítményhez ugyanakkor az kellett, hogy ismerjük - és kihasználjuk - a programozási nyelv, a keretrendszer és platform határait.

5. Az adatstruktúrák, és algoritmusok és best practice-ek elengedhetetlenek a hardcore fejlesztéshez

Amikor az algoritmuselméletet használom

Ahhoz, hogy legalább 10x gyorsabb komponenst tudjuk fejleszteni, mint a meglevőek, a problémánkhoz legjobban illő adatstruktúrákat és kellően hatékony algoritmusokat kellett használnunk.

A szoftveres karrierem során nem sokszor fordult elő, hogy az adatstruktúrák és algoritmusok futásidejéről és memóriaigényéről annyit tanácskozzunk, mint ezen a projekten. Nem hiszem, hogy valaha teljes mértékben ki fogok aknázni a BME-n az algel tárgyon tanult mélységet, viszont ebben a projektben rengeteget segített, hogy pontosan tudtam, hogy O(logn)-nél gyorsabb futásidejű sorting algoritmusra nem lesz szükségünk. Meg hogy nem csak a futásidő, de a konstans memóriahasználat is legalább annyira fontos - főleg, ha sok pontról beszélünk.

Egy legalább annyira fontos tanulság volt, hogy a design patternek és best practice-ek gyakorlatban alkalmazása tényleg megkönnyíti a fejlesztést. Sokat vitatkoztunk arról, hogy 1M pontot kizoomolva hogyan is rendeljünk egy 500px szélességű diagramon. Nyilván nincs értelme 500 pontnál többet kirajzolni, ergo filtereznünk kell. De milyen algoritmus alapján tegyük ezt?

Ehhez a problémához - adott bemenetként 1M pont, kimenetként 500 pontot várunk - egyből adja magát a Strategy design pattern. Miért definiáljunk egy megoldást, ha többet is implementálhatunk - pl max érték, min érték, mértani közép, vagy medián? A diagram egyik változójaként egy saját IFilterStrategy interrface-t definiáltunk és ezzel egyben lehetőséget biztosítottunk egyedi, a mienktől eltérő filterezési stratégiák implementálására. Vagyis: ha nem tetszik, amit mi csináltunk: simán csinálhatsz jobbat magadnak.

6. A memory leak-ek megengedhetetlenek a kritikus rendszerekben

Amikor az olajfúrótorony fejlesztői elkezdték integrálni a diagramjainkat, az első méréseik mind a memóriahasználatra irányultak és azt nézték, hogy nem szivárog-e memória. És ez teljesen érthető is: amikor egy olyan rendszert építesz, aminek hónapokig kell folyamatosan futnia, akkor nagyon fontos, hogy a futási sebesség ne kezdjen el romlani. Még ennél is fontosabb, hogy ne fusson ki memóriából az alkalmazás.

És mint azt megtanultam, a memory leak-ek és futási sebesség lassulása különbség között nagyon is erős összefüggés van. Ha memory leak van a kódodban, ez szinte biztosan a futási sebesség lassulását fogja eredményezni. És nem mellesleg, egy idő után az alkalmazás ki fog futni a memóriából és összeomlik.

A projektünkön rengeteg időt és energiát szenteltünk a memória szivárgások megkeresésére és megszüntetésére - ami nem igazán triviális vagy élvezetes feladat. Emellett rendszeresen mértünk különböző teszteseteket, hogy biztosítsuk, hogy nem került be egy újabb memory leak a kódba. Persze a futási teljesítmény a memory leak-eken kívül még számtalan más ok miatt is visszaeshet, de amikor hosszú futásidejű appokat fejlesztesz, akkor mindig ellenőrizd, hogy az app nem szivárogtat memóriát.

A kódod segíteni fog más fejlesztőknek - de csak akkor, ha elérhetővé teszed

Durván jó érzés volt, hogy több ezer kilométer távolságból, anélkül, hogy bármit is tudnék az olajfúrókról - így is segítettem az egyikük vezérlőrendszerét jobbá tenni (vagy legalábbis a diagramokat szebbé tenni).

A nem fogyasztóknak szánt dolgok fejlesztése sokszor nem tűnik túl szexinek. A barátaim például a Visiblox diagramokon végzett munkámat sokkal kevésbé értékelik, mint a koktélos appomat, ami a telefonjukon fut. De azért én a Visiblox projektet ugyanannyira élveztem és többet tanultam belőle, mint sok másik, látszólag szexibb app készítésével.

De nem csak SDK-k vagy könyvtárak kódolásával segíthetsz más fejlesztőknek valami még klasszabb készítéséhez. A legegyszerűbb módja, hogy más fejlesztőknek egy segítő kezet nyújtsál - és hasonlóan meglepődj, mint ahogy én tettem - az az, ha publikálod a forráskódodat, hogy mások is használhassák, például a GitHub-on. Én például egyre több saját projektem kódját teszem fel ide - ennek a blognak a skinjét is szabadon hozzáférhetővé tettem.

Jegyzetek

[1] - Egy Canvas-os megoldást készítettünk, ahol a Point adatstruktúrákat cacheltünk és újrahasználtuk - a méréseink alapján nagyon rontotta volna a teljesítményt és memóriahasználatot, ha a Canvas-hoz hozzáadtunk, illetve töröltünk pontokat[. A bitmapos megoldás sokkal gyorsabb lett volna, de a zoomolást Canvassal jóval egyszerűbb volt lefejleszteni.

(A cikk angol változata itt található.)

Orosz Gergely

Csapatvezető az Ubernél. Korábban a mobil és full stack mérnök a Skyscannernél és JP Morgannél, a Skype-nál pedig az XBox One csapat alapító tagja volt.

Rendszeresen új, inspiráló és érdekes sztorival jelentkezünk a szoftverfejlesztés világából.
Következik: 4 évet dolgoztam a Facebooknál. Ezt a 4 fontos dolgot tanultam itt meg.
Iratkozz fel a hírlevélünkre - és elsőként értesítünk az új szorikról.
A kommenteket a Disqus jeleníti meg