2011. augusztus 24., szerda

Gyárlátogatás: konfiguráció

A következő dolog, amit mindenki totál máshogy csinál a java/j2ee/jee környezetben az a szoftver konfigurációja. A téma sajnos nem annyira "egyszerű" mint az a képesség, hogy a verziószámot meg tudjad mondani, így hát igen szép számban van rá megoldás. Ezek a megoldások még csak nem is diszjunktak, simán átfedik egymást. Egészen biztos, hogy nincsen két ugyanúgy konfigurálható java szoftver. Illetve csak ha pont ugyanaz az ember írta mondjuk 1 héten belül. Szóval oltári buhera zajlik a téren. Mint mindig.

Elvárások a konfigurációval kapcsolatban

Ha én lennék az admin, most így fejből ezeket várnám el az appoktól és fejlesztőiktől:

  1. Legalább az minor release-k között őrizze meg integrítását. Azaz a 1.0-hoz bütykölt konfig had menjen már el a 1.0.1-gyel is.
  2. Ne az alkalmazásba legyen belebuherálva (WEB-INF/classes, satöbbi), hogy amikor az upgrade során rm -rf paranccsal kezeled a régi verziót (ja, backup, csókolom!) ne vesszen el a régi bugokkal együt a konfiguráció is. Legalább a környezet-specifikus konfiguráció ne az appban legyen!

Mint fejlesztő, nagyon szeretem azt, ha nem kell a fél életemet a fejlesztői környezet összebuherálásával töltenem. Értelmes alapértékek (akár pl egy beágyazott DB), könnyű felülcsűrhetőség.
Illetve ezt csak nagyon szeretném, baromi ritka az ilyen. Remélem nem úgy képzelitek el a halálcsillag építését, hogy kiszedik a dobozból, bekapcsolják és működik.

Plain Property file-ok

A property fileok ősi java feature és a legtöbb rendszer még mindig felhasználja a konfiguráció tárolására. Ezzel persze nem rossz dolog. Máig ez a legtöbb konfigurációs megoldás alapja, de persze a tiszta és legalapabb formája az, amikor pl a konstruktorban megkapod a Properties ojjektumot magát és bányásszad ke belőle azt, ami köll. Volt egy ennél kicsit szofisztikáltabb megoldás, ami csak a teljes konfig egy részét passzolta oda... lényegtelen. Ezek tipikusan az IoC-nélküli rendszerek.

Á igen, IoC

Az IoC egy olyan ötlet volt, amiért jópárszor leégettem magam azzal hogy próbáltam megmagyarázni a főnökeimnek valamikor régen, és néha még mostanában is. Ötlet: "Do not call me, I will call you!" Azaz az IoC konténer majd beállítja neked a konfigot, összekapcsolja az ojjektumaidat, elindítja az appod ha kész, illetve elhasal ha nem sikerült (ez esetben az jó, hogy hülyeséggel nem indult el). Ebből eleinte még két faj létezett, az intrusive (pl Avalon) és a non-intrusive, tipikusan POJO jellegű. Az elöbbit mára csak CVS-múzumokban találod. Az utóbbiból se a spring volt persze az első, csak a legnépszerűbb. Volt még elötte picocontainer, nanocontainer, és már a fene se emlékszik mik. Ma Spring, Guice, és az EJB is sok inspirációt kölcsönzött a téren ezektől a projectektől. Vitatkozhatnánk róla, hogy eleget-e vagy sem, de igazából nem érdekelne.

Még itt szeretném megemlíteni azokat a böszme nagy XML fileokat amiket írunk az IoC frameworknek és együt jönnek az appal szinte minden verzióban kicsit úthuzalozva és átkombinálva. Szerintem ne akarjátok, hogy az admin ebben matasson! Az merge-hell! Sírás-rívás, jajjveszék, rollback, cancel, és hasonló kulcsszavak jutnak róla eszembe. (Egy külsős fejlesztő szívatott ilyennel éveken át)

Spring, PropertyOverrideConfigurer és PropertyPlaceholderConfigurer

Ezt a két dolgot igazából nagyon szerettem a spring-ben. Ez megoldás arra, hogy az appcontext-ben összeállított konfigurációt felülcsűrd egy property file tartalmával. Tehát ide lehet tenni az X-et ennek én nagy rajongója vagyok még most is. A különbség a két dolog lehetőség között, hogy az override configurerrel mindent felül lehet csapni (söt, olyat is ami az appcontextben nem is volt benne), míg a placeholder configurer csak a placeholdereket helyettesíti be. Azért gyanús, hogy az előre kigondoltakon kívül jól jöhet, ha időnként más beállításokat is megváltoztathatsz. Természetesen az a placeholder configurerben viszont szimpatikus, hogy az éles rendszerektől megköveteli az előre definiált placeholderek értékének beállítását, különben nem indul el. Ugyanakkor még mindig jobban szeretem, ha a rendszer értelmes defaultokkal jön, és bármít felül lehet benne csapni.

Mindkettőnek van némi hiányossága. Pl listákat és map-eket nem kezelnek. Na erre mindenkitől láttam valami saját szintaxist és saját megoldást.

Jó, de hova?

Azt a kérdést, hogy hova tegye a rendszergizda a konfig fileokat, illetve az app hol keresse, az izlés és hitviták tárgya. Volt egy melóhelyem, ahol a unix filerendszerhez kellett igazítani a struktúrát. A konfig az etc-be, a program kód meg a usr-be (usr-be?!?!?!), felhasználókkal kapcsolatos dolgok talán a home-ba, adatok a var-ba. Igen, még mindig java szoftverfejlesztésről van szó. Vicces volt egész addig amíg rá nem jöttem hogy komolyan gondolják. Utánna már nem :-D

Mindenesetre a legtöbb program egyszerűen csak a classpath-on keresi a konfigját, többnyire {appnév}.properties alatt. Ez talán a legértelmesebb dolog, de minden appszerveren máshova kell dobni, hogy a classpath alatt legyen. Had sírjon aki migrálni merészel!

JMX!

A JMX még belerúg ebbe a témába kicsit. JMX-en keresztül beállíthatod az alkalmazásod konfigurációját, meghívhatsz rajta maintenance metódusokat, stb. A JMX király dolog, de arról nem gondoskodik, hogy a container újraindítása utánra is megmaradjanak ezek a beállítások. Az az app gondja. Valószinúleg ez lehet az oka annak, hogy hibakeresés közben láttam csak JMX-et, konfiguráció beállításhoz soha. Nevezhették volna inkább java debugging extensionnak.

JNDI?

Ha már a container szolgáltatásainál tartunk. Sokat tűnődtem rajta, hogy a JNDI miért csak annyi lett, amennyi lett. Semmi mást nem csinálsz vele, csak java.sql.Datasource és java.mail.Session objektumot halászol ki belőle, többnyire hardcode-olt címről. Az innen kihalászott objektumok előre fel vannak konfigolva a környezet beállításaival: hol az adatbázis, milyen adatbázis, hány kapcsolatot nyithatok rá, satöbbi, hasonlóan az smtp szerverrel. Na jó, még arra is használjuk néha, hogy a LDAP szervereken kurkásszunk valamit. Ennyi?
Tehát akkor az adatbázis és SMTP eléréssel kapcsolatos infókat akkor ott tartjuk. A többit miért nem? És ha a többit nem ott, akkor azt miért? Nem lenne jobb egybe tartani?
Kipróbáltam pár appszervert, a GUI/web-es felületeken keresztül egyik sem volt hajlandó a fenti kettőtől eltérő ojjektumot elhelyezni a JNDI fában. Kézzel be lehet haxolni.

Adatbázis

Remélem mindenki érzi, hogy egy komoly robosztus ACID-compliant replikált és backupolt nagy teljesítményű, 24/7 365 felügyelt RDBMS a legrojszrojszabb hely a világon, ahova a konfigját az ember berakhatja. Szóval legkevésbé sem ritka, hogy az appok az adatbázisban tartják a konfigjukat. Akkor már csak az a kérdés, hogyan éred el az adatbázist, de ezt többnyire a JNDI megválaszolja.

Én nem érzem a késztetést :-) Csupán technikai oldalról, nem értem mi haszna van az ACID viselkedésnek akkor, amikor olyan adatokról van szó, ami csak akkor változik, amikor éppen bütyküljük a rendszert. Sokkal hasznosabb ha gyorsan és egyszerűen hozzá lehet férni, mindig. Továbbá nagyon nagyon szép ha pl valami verziókövetőben tárolhatjuk, hogy tudjuk ki buherált rajta és mit, mikor hogy nézett ki. Egy text-file sokkal szimpatikusabb. Na ezt talán inkáb oda kellett volna írnom a propertyfile-hoz. Na mindegy, úgyis elcsesztem már pár helyen ezt a cikket.