Álláskeresési tanácsok szoftverfejlesztőknek (és másoknak)

Egy levélben az alábbi kérést kaptam:

Arra szeretnélek még megkérni amennyiben időd engedi, hogy pár sorban összefoglalnád-e mivel foglalkozol a jelenlegi munkahelyeden és milyen elvárásoknak kell megfelelned. Azért érdekel, mert ha hasonló területen/pozícióban helyezkednék el, akkor mire számíthatnék, milyen szakmai vagy egyéb kihívásoknak kellene megfelelnem. Röviden mi a jó és rossz oldala annak az állásnak amelyet betöltesz.

Azt hiszem nem én vagyok a legmegfelelőbb ember, aki erre a kérdésre választ tud adni (és éppenséggel időm sincs valami sok), de gondoltam ha már válaszolok megosztom mindenkivel, elvégre egyre több ember próbál elhelyezkedni ezen a területen, nem árt ha tudják mire számítanak.

Ha pár évvel ezelőtt tették volna fel nekem ezt a kérdést egyszerű választ adtam volna. Ismerni kell a megfelelő technológiákat, trendeket, gyorsan jól kell dolgozni.

Lehet tényleg a korral jár, de azóta sokkal többrétűnek látom ezt a problémát. Ezért nem is a konkrét kérdésekre fogok válaszolni (nem hiszem, hogy a válaszaim bárkinek is segítenének elhelyezkedni) inkább azokat a dolgokat írom le, amit én fontosnak tartok a témával kapcsolatban.

Tehát:

1. Mit várnak el manapság egy szoftverfejlesztőtől?

Amikor döntenek valakiről (felvegyük/ne vegyük)  több szempontot értékelnek. Hogy pontosan miket és milyen súllyal az változhat, de jó eséllyel a lentiek mindig benne lesznek:

Szakmai elvárások: Legyen kielégítő szakmai tudása. Tegyük fel ha java fejlesztőről beszélünk, akkor ismerje a java nyelvet (öröklődés, generikus típusok, objektumok és natív típusok közötti különbségek, stb.), tudjon kódot értelmezni, és legyen (legalább) áttekintő képe a fontosabb technológiákról (ha nem is mindenről de: spring, hibernate, soap, xml/xsd, servlet, jsp, svn, stb.). Jó kérdés, hogy mi minősül fontosabb technológiának. Erre a válasz az, hogy amelyek beleillenek a trendekbe, megfelelő támogatottságuk van, stb. Nincs konkrét recept, de ha valaki megfelelő fórumokat/listákat olvas, vagy megkérdez egy szakmabelit biztos fog egy listát kapni, ami kiindulásnak tökéletes.

Management elvárások: A szoftverfejlesztés (vagy bármi más) nem csak a szoftverfejlesztésről szól. Fontos, hogy a jelentkező képben legyen a saját korlátaival, képességeivel, be tudja határolni mi az elvárása/célja, és tudja ezeket megfelelően kommunikálni. Ha valaki kezdő fejlesztő persze nem nagyon tudja megállapítani saját korlátait (mert nincs viszonyítási alapja) de még mindig szerencsésebb ezt mondani, mint bármi mást. Képzeljük el az alábbi helyzetet. Jelentkezik valaki fejlesztőnek, és beáll azok közé, akik x éve fejlesztenek, napi x órában. Ha úgy állnak az új emberhez, hogy ő tapasztalt, joggal elvárhatják, hogy a feladat ismeretében határozza meg, mennyi ideig fog tartani a megvalósítás. Ez egy egyszerű kérdés, emiatt többen alul is becsülik ennek a súlyát. A kérdés egyszerűsége ellenére a választ nagy ritkán sikerül még napra pontosan is megmondani. Rutinnal és sok gyakorlással jól lehet tippelni (feltéve ha az ember odafigyel erre, és tanul a hibáiból). Egy pályakezdő 90%-ban rossz választ fog adni, és ha mégsem, az is inkább a szerencse miatt van. Vagy nagyon felülbecsüli, ami kiveri a biztosítékot a vezetőknél, és elmagyarázzák neki, hogy na ez itt ám nem az a hely, vagy alul és jó esetben napi 12 órákat dolgozik mire behozza a lemaradást. Rossz esetben valaki másnak kell átvenni tőle a feladatot ami nem biztos, hogy elősegíti a további jó munkahelyi kapcsolatok kialakulását (pl. ha az új kolléga miatt kell valakinek hétvégézni, miközben egész héten 1x órákat volt bent 🙂 ). A “becsüljük meg mennyi idő lesz” probléma minden fejlesztőnél létezik, sajnos ezt csak gyakorlással lehet fejleszteni (pl. megkérünk valakit vagy keresünk a neten egy fejlesztési feladatot, megbecsüljük, megcsináljuk, megnézzük mennyit tévedtünk, elemezzük mit becsültünk alul, felül, stb.), de nagyban megkönnyíti az életünket ha ebben jók vagyunk (akkor is ha nem mi szabjuk meg a határidőket, mert legalább tudunk sípolni időben ha valami nem kerek azzal amit nekünk mondtak).

Emberi elvárások: A szoftverfejlesztés (főleg ha nagy projekt) olyan mint egy sokszereplős társasjáték. Az emberek azért dolgoznak, hogy beérjenek a célba (elkészüljön az amit csinálnak, és még jó is legyen). Csak itt a játékosok nem egymás ellen, hanem egymással játszanak. Szép dolog (és igen jó érzés) ha ez működik. Ha valaki elkapkod valamit, nem gondolkozik, hajlamos félvállról venni dolgokat az felér azzal, mint amikor azt mondják a társasjátékban a többi játékosnak, hogy 2 körből kimaradsz. Ha valaki nem lát meg egy problémát előre előfordul. Ha valaki meglátja, és nem érdekli, az a probléma. Tehát az alaposság, következetesség, és kommunikáció kiemelten fontos (nem csak IT területen, de itt sokkal több a kevésbé kommunikatív ember, ami a reál tudományágaknál egy ismert tendencia). Szintén érdemes gyakorolni az önmegtartóztatást. A fejlesztések során a projekt méretével a tévedések száma valamint mérete is nőni szokott. Például nem túl szerencsés fennhangon anyázni egy kódrészletet mert: lehet valaki tévedett, lehet, hogy amikor megcsinálta még jó volt, csak tudtán kívül átalakult körülötte a kód többi része, vagy csak fáradt volt mert 1x órája dolgozott. Ezt soha nem tudhatjuk (persze van amikor mérgelődünk kicsit konszolidáltan, de azt hiszem ettől vagyunk emberek  😉 )

2. Milyen egy szoftverfejlesztő élete

Társaság: Ha egy jó csapatba/cégbe csöppen az ember, akkor nagyon jó. Nekem személyes tapasztalatom az, hogy az emberek sokkal fontosabbak mint a projektek. Ez az a szakma ahol mindig meglehet találni a feladatok szépségét, vagy egy semmitmondó feladatot is meg lehet oldani érdekesen, oly módon, hogy tanulni is lehessen belőle (persze itt is kiemelten fontos az önismeret, bukott el nem egy nagy projekt a túlcizellált megoldásokon).

Szabadidő: Természetesen a szoftverfejlesztés nem kevéssé időigényes feladat, és ha valaki egy új cég életébe csökken, az első napok/hetek/hónapok biztos nagyon húzósak lesznek (túlórák, rengeteg új dolog, érthetetlen összefüggések). Ezek ismert dolgok, nem szabad megijedni, szépen lassan tisztul a kép, és utána megtérül a sok befektetett idő és energia.Természetesen ezek után sem áll meg az élet, folyamatosan jönnek az újabb trendek, mérföldkövek, verziók, hibajegyek, stb.

Pénz: A szoftverfejlesztésben van pénz. Vannak fizetések is (bár ez cégtől függ 😉 ). Kevés szoftverfejlesztőt láttam porsche-val munkába járni (én egy időbe szerettem volna, de nem jött össze 🙂 ), de szerintem a legtöbben megtalálják a számításaikat.

GWT rpc servlet Vs Apache proxy

A gwt alkalmazások (egyik) legnagyobb előnye a perfect cache kezelés. Ahhoz, hogy ez hatékony legyen érdemes minden statikus tartalmat egy apache-ra rakni, és csak az RPC hívásokat átfűzni egy proxy-n az alkalmazás szerver felé. Ennek hatására viszont előállhat az a furcsa helyzet, hogy az RPC szolgáltatásokat kezelő szervlet context-root-ja eltér a statikus fájlok context-root-jától.

Ezt a GWT rpc kezelő servlete nem szereti valami nagyon és mindenkit megjutalmaz az alábbi hibaüzenettel:

[10/28/10 12:50:44:383 CEST] 00000041 webapp        I com.ibm.ws.webcontainer.webapp.WebApp log SRVE0296E: [app_war#app.war][/app/services][Servlet.LOG]:.PartnerServiceServlet: ERROR: The module path requested, /app/, is not in the same web application as this servlet, /app/services.  Your module may not be properly configured or your client and server code maybe out of date.:.null

Ez önmagában nem baj, csak csúnya, de amikor komplex osztályokat küldünk fel a szerverre, ennél komolyabb hibák is jelentkeznek (cannot load serialization policy).

Ennek oka, hogy az RPC üzenetek hordozzák magukban, hol keletkeztek, és a szerver oldal ellenőrzi, hogy az egyezik e a context rootjával.

Ha megfigyeljük az RPC hívások tartalmát látszik, hogy az url a verziók után utazik, pl:

verziók|hívó|ser policy fájl|hívás névtér|szolgáltatás, stb…

A valóságban valami ilyesmi:

5|0|9|http://server/app/|D0C8380096848CC179C5488360839537|hu.aftershock.client.services.gwtrpc.modules.common.ICommonService|getCommonCodes

A probléma a 4 résznél van, amit cserélni kell (ha az alkalmazás context rootja nem /app hanem /app/services). Ezt oly módon tudjuk megtenni, hogy leszármazunk a RemoteServiceServlet osztályból, és felülírjuk a processcall funkciót (ezt egyébként is érdemes megtenni, ide lehet mindenféle hasznos dolgot mint profiling, audit, security implementálni).

@Override

public String processCall(String paydload) throws SerializationException {

paydload=mainUrlFix(paydload);

A mainUrlFix implementáció az alábbi módon néz ki:

private String mainUrlFix(String payload) {

int tokenNum=0;

String prefixString=””, mainUrl=””, postfixString=””;

for (int i=0, il=payload.length(); i<il; i++ ) {

if (payload.charAt(i)== AbstractSerializationStream.RPC_SEPARATOR_CHAR) {

tokenNum++;

if (tokenNum==3) {

prefixString=payload.substring(0,i);

} else if (tokenNum==4) {

mainUrl=payload.substring(prefixString.length(),i);

postfixString=payload.substring(i);

break;

}

}

}

if (!mainUrl.endsWith(“services/”)) {

mainUrl+=”services/”;

}

return prefixString+mainUrl+postfixString;

}

Levélküldés tesztelése

Manapság már nem nagy dolog olyan alkalmazást fejleszteni ami emailt tud küldeni. Ellenben fejlesztés alatt egyáltalán nem biztos, hogy szerencsés, ha a valódi felhasználók a fejlesztők viccesebbnél viccesebb tárgyú leveleit kapják kézhez (pl. szerződését díjrendezettség hiányában töröltük, stb). Ezt elkerülendő lehet mindenféle if-eket írni a kódba, de ez sajnos megváltoztatja a program működését, és ezzel a metódussal elég sok potenciális hibaforrást elrejthetünk a kódban. Célszerűbb csinálni egy saját smtp szervert, ami e leveleket fogadja, de nem küldi ki, hanem lementi egy könyvtárba.

Erre a legegyszerűbb megoldás linux alatt a fakemail nevű program, ami a phytonnal együtt jön.

Tehát a telepítés

sudo apt-get install python

Az indítás (pl. init.d-ből)

sudo su -c ‘fakemail.py –host=voji.hu –port=10025 –path=/var/samba/servers/smtp –background’ voji

A lényeg a ‘ ‘ jelek közötti rész, a su -c csak azért felel, hogy voji userként fusson a szerver.

A paraméterek:

  • host – a cím, ahol a szerver fut
  • port – port ahol hallgatózik majd az smtp szerverünk
  • path – könyvtár ahova a leveleket lementi amit a szerveren keresztül küldenek.
  • background – háttérben fusson, ne a konzolon

Spring

Manapság divatos szó a Spring. Ha már csak megjelenik a szövegkörnyezetben, rögtön betölti a levegőt a misztikum, és mindenki érzi, hogy itt valami nagyon komoly, és jó dologról van szó.
Valószínű azért, mert már önmagában a szó jelentése is tavasz, rugalmasság, tehát csupa jó dolog egy olyan világban, ahol a legtöbb dolgot már csak 3 betűs rövidítésekkel illetik (igen kreatív módon, mint pl esb, ejb, ear, stb. 🙂

Programozóknak a spring szó már önmagában olyan, mint az átlagembernek egy üveg Chteau Latour Pauillac. Nem tudja mi az, de jól hangzik, biztos jó lesz valamire.

A fentiek miatt, manapság már szinte nem is találkozni olyan dokumentummal amiben ne szerepelne ez a misztikus szó, ami önmagában örvendetes, és ugyanakkor elszomorító is.
Elszomorító, mert az esetek nagyrészében nagyon kevés ember tudja elmondani, hogy miért és legfőképp mire is használja a springet.

Hogy ezt tisztába tegyük, röviden mire is jó a Spring:
– Az alkalmazások Spring alkalmazás környezetben futnak, ami független lehet az alkalmazásszerver gyártójától, és egyéb megkötésektől. Ezáltal könnyen mozhatható az alkalmazás különböző alkalmazásszerver vendor-ok között, vagy használható az alkalamzás akár alkalmazás szerver nélkül is.

– Megvalósítja azt jól, ami az ejb-nek nem sikerült valami fényesen: alkalmazásobjektumok kezelését, és azok automatikus egymásba ágyazását, működésének meghatározását az alkalmazástól „független” konfiguráció alapján

– Segítségével könnyedén lehet integrálni sok más divatos szóval jelölt technológiát (hibernate. quartz, stb.)

Hirtelen ennyi gondolatébresztőnek, nemsokára várható pár érdekesség a témában 🙂

GWT – kliens szerver határán

Lassan 1 éve foglalkozok GWT-vel. Gondoltam eljött az idő, hogy röviden számotvessek magammal, milyen is volt ez az 1 év…
A maga a koncepció, ahogy a megvalósították, hogy java-ban hozhatunk létre böngészőfüggetlen javascriptet, a szabad forráskódú fejlesztés, hogy a rendszer minden részének működését forráskód szinten látjuk, hogy módosíthatók (vagy utánozhatóak) az alap implementációk, és még sorolhatnám. Ez kétségtelenül megérdemel egy + jelet 🙂

Persze az ismerkedés nem volt egyszerű, néhány fejlesztési alapvetést, és nézetet adaptálni kellett, tehát aki gwt-re adja a fejét (szerintem ez ajax-ra, sőt minden asszinkron működésű programra vonatkozik) kénytelen picit „másképp gondolkodni”.
A tapasztalataim részletekbe menő ismertetését most sajnos nem írom le, de néhány gondolatot azért igen.

Nem, nem bántam meg, hogy gwt-be fejlesztek, és ha újra kellene választanom, én ismét ezt választanám. (bár ilyen téren mindegy miben kell fejleszteni, ha valaki elég eltökélt, bármivel tud nagyszerű dolgokat készíteni, max sok idő, és áldozat árán 😉 )

A GWT alkalmazásokban gondolkozik, és ezért „nagy alkalmazás” fejlesztése során felmerülnek problémák (pl. a memória használat, kódok mérete). Ha viszont egy picit tovább gondoljuk a dolgot, minden nagy alkalmazás nem más mint kis alkalmazások összessége, amik viszont játszi könnyedséggel integrálhatóak egy nagy alkalmazásba (ez a megközelítés egyébként is rengeteg előnnyel jár, mint pl. az egymástól független verziókezelés, stb).

Kliens és szerver oldali kódok az RPC hívások miatti duplikálása (ami sajnos mostanában elég bevett szokás), egy hibás koncepció. Rengeteg fejlesztő duplikálja a DAO kódokat (pl. egy tábla leíró osztály), hogy a gwt számára a böngészőbe át tudja adni a benne lévő adatot. Erre nincs szükség. Amikor a gwt fordít, akkor a gwt fordító fordít, amiből javascript lesz. Amikor a java fordít abból pedig szerver oldali java class fájlok. A két folyamat eltéréséből adódik, hogy megtehető az, hogy a gwt fordítás alatt az ember picit más class-okat használ fel, mint a java fordítás alatt.
Egy életből vett példa, hogy érthető legyen:

Tegyük fel, hibernate-t használunk, és csinálunk egy partner osztályt:

@Entity
@Table(name = "Partner")
public class Partner {

@Id
@GeneratedValue
@Column(name = "PARTNER_ID")
public long getId() {
return this.id;
}



Ha ezt gwt oldalon el szeretnénk érni két általános dolgot kell tennünk:
– levinni a kódot a kliens oldalra
– implementálni az IsSerializable típust

A második dolog viszonylag egyszerű, ellenben amikor a kliens oldalra mozgatjuk az osztályt, akkor a gwt fordító kedvesen figyelmeztet, hogy kliens oldalon nem lehet szerver oldali komponenseket használni (mint a hibernate notáció).

Persze azért mondja ezt, mert nem tudja, hogy mi ezeket a kódokat kliens oldalon nem is akarjuk használni. A megoldás kézenfekvő, és egyszerű. A hibernate forrásából ki kell szedni azokat a fájlokat amiket kliens oldalon is használunk. A forrásban használt függvényeket meghagyuk, de az implementációs részt töröljük. Fordítunk belőlle egy olyan jar-t amiben benne van a forrás is, és a fordított funkció nélküli class fájlok, megmondjuk a gwt fordítónak, hogy tessék ezt használni.

A kód lefordul, a javascript a hibernate notációval ellátott, de funkcióval nem rendelkező osztályokat használja, ellenben amikor ez az adat felkerül szerver oldalra, ott már a hibernate funkcionalitás is elérhetővé vállik, nincs szükség az osztályok duplikálására.

Ugyanez az elv használható a validációk során is, a jól megírt validációt végző keretrendszer minden esetben használható mind kliens mind szerver oldalon (optimális esetben notációkkal, pl. a hibernate által használt dao osztályban… ).

Részemről a geek hajlamok ezzel letudva a hétvégére 🙂

Gwt memory leak

Ezer éve nem volt módom (és időm) írni, de most sikerült, megtaláltam, és megengedek magamnak ekkora pihenőt. Jó ideje egy GWT alapú alkalmazás készülget, és eddig szinte minden „simán” ment a fejlesztés során, volt néhány kisebb trükk, pár gwt-s osztályt át kellett írni, de összességében szerintem a GWT keretrendszer jól teljesített, sőt felül is múlta az elvárásaimat.
Egészen tegnapig, amikor is azt jelezték, hogy az alkalmazás sok memóriát fogyaszt. Ilyenkor az ember hajlamos azt mondani, hogy persze, hiszen nagy alkalmazás, de a C++-hoz szokott énem rögtön kétségbe esett, ez bizony memory leak. Gyors mérések után a tünetek egyértelműek voltak. Az alkalmazás leak-el, menüpontonként pár megát. Az látszott, hogy nem a javascript memóriahasználata nő (google chrome kiírja), hanem a böngésző memória használata. Ekkor kezdtem gyanakodni, hogy ezt pedig mi rontottuk el, és a végén igazolódott is ez az állítás. A hibát csak a tanúsága miatt megosztom mindenkivel.

Az eredeti kód:


private void setLoadingVisible(boolean pVisible) {
if (pVisible) {
waitingPopup=new APopupWaiting(msgs.main_waitingmessage(), Window.getClientWidth(),Window.getClientHeight());
waitingPopup.center();
}
if (!pVisible && waitingPopup.isVisible()) {
waitingPopup.hide();
}

Ez a szolgáltatás arra szolgál, hogy ha tölteni kell, akkor kirak egy töltés dialógust. Első látásra minden rendben van, létrehoz egy újat, megjeleníti, vagy elrejti a megadott paraméter alapján. Az implementáció hibás, az már érdekesebb kérdés miért. Normál esetben maximum egy nem optimális implementáció lenne, hiszen miért hozunk mindig létre valamit, ami már egyszer létre lett hozva, ráadásul sohasem változik. Sokkal nagyobb probléma, hogy ez javascriptben fut, és a GWT a változót (és a hozzá javascript által generált HTML dom-ot) csak akkor szabadítja fel, ha már nincs rá referencia. Ellenben a PopupDialogra igen is lesz referencia, és nem a DOM-on keresztül, hanem azon eseménykezelők miatt, amikre működéséből fakadóan feliratkozott. Tehát az objektum lóg a levegőben, és fogyasztja a memóriát.

Egy lehetséges megoldás:


private void setLoadingVisible(boolean pVisible) {
if (pVisible) {
if (waitingPopup==null) {
waitingPopup=new APopupWaiting(msgs.main_waitingmessage(),
Window.getClientWidth(),Window.getClientHeight());
waitingPopup.center();
} else {
waitingPopup.center();
}
}
if (!pVisible && waitingPopup!=null) {
waitingPopup.hide();
}
}

Végezetül egy kis olvasmány (de az ellen nem véd ;):
http://code.google.com/p/google-web-toolkit/wiki/DomEventsAndMemoryLeaks