AdatbazisokUjratervezese02.qxd
4/21/2009
9:54 AM
Page 11
2 Adatbázis-újratervezés Amint befagyasztunk egy tervet, elavulttá válik. – Fred Brooks
Ez a fejezet az adatbázis-újratervezés alapelveit tekinti át: elmagyarázza, mi is az adatbázis-újratervezés, hogyan illeszkedik a fejlesztés folyamatába, és miért bizonyul gyakran nehéznek sikeresen végrehajtani. Az ezt követõ fejezetekben aztán részletesen leírjuk az adatbázisséma újratervezésének tényleges folyamatát is.
2.1 Kódújratervezés Refactoring (1999; magyarul Refactoring – Kódjavítás újratervezéssel, 2006, Kiskapu) címû könyvében Martin Fowler az újratervezésnek (refactoring) nevezett programozási eljárást ismerteti, amely a kód szerkezetének fegyelmezett, kis lépésekben történõ módosítását jelenti. Az újratervezés révén lehetõvé válik, hogy a kódot lassan, fokozatosan fejlesszük tovább, vagyis hogy a programozás során fokozatos (ismétlõdõ és egymásra épülõ lépésekbõl álló) megközelítést alkalmazzunk. Az újratervezés lényeges jellemzõje, hogy megtartja a kód viselkedési jelentését: újratervezéskor nem bõvítjük új képességekkel a programot, és nem is veszünk el belõle szolgáltatásokat. Az újratervezés csupán a kód felépítésén javít, se többet, se kevesebbet nem tesz. A 2.1. ábrán például a Függvény lejjebb helyezése nevû újratervezési megoldást alkalmazzuk, hogy a calculateTotal() mûveletet az Offering osztályból annak Invoice alosztályába helyezzük. Ez a módosítás a felszínen egyszerûnek tûnhet, csakhogy a mûveletet meghívó kódot is meg kell változtatnunk, hogy Offering objektumok helyett Invoice objektumokkal dolgozzon. Csak akkor mondhatjuk el, hogy valóban újraterveztük a kódot, miután végrehajtottuk ezeket a változtatásokat is, mert a kód csak ekkor fog ugyanúgy mûködni, mint korábban.
AdatbazisokUjratervezese02.qxd
12
4/21/2009
9:54 AM
Page 12
Refactoring – Adatbázisok újratervezése
Világos, hogy a kód újratervezését rendszerezett módon kell végrehajtani, és ehhez megfelelõ eszközökre és eljárásokra van szükség. A mai egyesített fejlesztõkörnyezetek (integrated development environment, IDE) többsége már támogatja valamilyen mértékig a kódújratervezést, ami jó kezdet. Ahhoz azonban, hogy az újratervezés a gyakorlatban is mûködjön, egy naprakész visszirányú tesztcsomagot is ki kell dolgoznunk, amely ellenõrzi, hogy a kód továbbra is mûködik-e. Addig nem vághatunk bele bizalommal az újratervezésbe, amíg megfelelõen meg nem tudunk bizonyosodni róla, hogy a kódot nem tesszük mûködésképtelenné.
2.1. ábra Függvény lejjebb helyezése egy alosztályba
Az agilis megközelítést és különösen az extrém programozási (XP) módszereket alkalmazó fejlesztõk közül sokan elsõdleges fejlesztési eljárásnak tekintik az újratervezést. Számukra egy kódrészt újratervezni ugyanolyan alapmûvelet, mint bevezetni egy if utasítást vagy egy ciklust. A kódot könyörtelenül újra kell tervezni, mert a munkánk akkor a leghatékonyabb, és akkor vagyunk a legtermékenyebbek, ha magas színvonalú forrráskóddal dolgozunk. Ha új képességgel kell bõvítenünk a kódot, elõször ezt a kérdést kell feltennünk magunknak: „A lehetõ legjobb felépítésû a kód ahhoz, hogy ezzel az új szolgáltatással bõvíthetõ legyen?” Amennyiben a válasz igen, hozzáadhatjuk az új képességet. Ha azonban nemmel felelünk, akkor elõször újra kell terveznünk a kódot, hogy az a lehetõ legjobb felépítésû legyen, és csak ez után láthatunk neki a bõvítésnek. Elsõ pillantásra ez rengeteg munkának tûnhet, a gyakorlatban azonban ha magas színvonalú forráskód áll rendelkezésre, amelyet újratervezünk, hogy a minõségét megtartsuk, rájövünk majd, hogy ez a fajta megközelítés kitûnõen mûködik.
2.2. Adatbázis-újratervezés Az adatbázis-újratervezés (Ambler 2003) az adatbázissémán végrehajtott olyan apró módosítást jelent, amely javít a séma felépítésén, miközben megtartja annak viselkedési és információs jelentését – más szavakkal, nem adhatunk új képességeket hozzá, és nem is tehetünk mûködésképtelenné meglevõ szolgáltatásokat, valamint nem vehetünk fel új adatokat, és nem változtathatjuk meg a meglevõ adatok jelentését sem. A mi szempontunkból az adatbázissémának vannak szerkezeti jellemzõi, például a tábla- és nézettáblameghatározások, illetve mûködésbeli jellemzõi, például a tárolt eljárások és a kioldók
AdatbazisokUjratervezese02.qxd
4/21/2009
9:54 AM
Page 13
2. fejezet • Adatbázis-újratervezés
(trigger). Innen kezdve a kódújratervezés kifejezést használjuk, ha a Martin Fowler által leírt hagyományos újratervezésrõl beszélünk, míg adatbázis-újratervezés alatt az adatbázissémák újratervezését értjük. Az adatbázis-újratervezés folyamata, amelyet a 3. fejezetben tárgyalunk részletesen, azt a tevékenységet jelenti, amelynek során ezeket az apró módosításokat végrehajtjuk egy adatbázissémán. Az adatbázis-újratervezés elméletileg bonyolultabb, mint a kódújratervezés: a kódújratervezés során csak a viselkedési jelentést kell megõriznünk, míg az adatbázis-újratervezésnél az információs jelentést is meg kell tartanunk. Ezen kívül az adatbázis-újratervezést az adatbázis architekturájából eredõ csatolások mennyisége is bonyolítja (lásd a 2.2. ábrát). A csatolás (coupling) két elem egymástól való függõségének mértékét jelenti: minél szorosabb a csatolás két dolog között, annál nagyobb az esélye, hogy az egyiken végrehajtott változtatás a másik dolog módosítását is szükségessé teszi. A legegyszerûbb esetet az egyalkalmazásos adatbázis-architektúrák jelentik: az adatbázissal ekkor csak a mi alkalmazásunk áll kapcsolatban, ami lehetõvé teszi a kettõ párhuzamos újratervezését és egyidejû telepítését. Ilyesmi nem csupán elméletben létezik: az ilyen rendszereket hívják gyakran önálló alkalmazásoknak vagy „stovepipe” rendszereknek. A másik alkalmazott architektúra sokkal összettebb: az adatbázissal számos külsõ program érintkezik, amelyek némelyike felett egyáltalán nem rendelkezünk befolyással. Ilyen esetben nem tételezhetjük fel, hogy az összes külsõ programot egyszerre telepítik, ezért egy átmeneti idõszakkal (más néven elavulási idõszakkal) kell számolnunk, amikor is a régi és az új sémát párhuzamosan egyaránt támogatnunk kell. (Errõl késõbb bõvebben is beszélünk.)
2.2. ábra Az adatbázis-architektúrák két fajtája
13
AdatbazisokUjratervezese02.qxd
14
4/21/2009
9:54 AM
Page 14
Refactoring – Adatbázisok újratervezése
Bár a könyvben szót ejtünk az egyalkalmazásos környezetekrõl is, nagyobb hangsúlyt fektetünk a többalkalmazásos környezetekre, amelyekben az adatbázisunkhoz számos, általunk csak kis mértékben vagy egyáltalán nem vezérelhetõ külsõ program fér hozzá. Aggódnunk azonban nem kell; a 3. fejezetben ismertetjük azokat a stratégiákat, amelyeket az ilyen helyzetek kezeléséhez követhetünk. Most azonban nézzünk végig gyorsan egy példát, hogy az adatbázis-újratervezést az összefüggéseiben is lássuk. Tegyük fel, hogy néhány hete egy banki alkalmazáson dolgozunk, amikor felfedezünk valami furcsaságot a 2.3. ábrán látható Customer (Ügyfél) és Account (Számla) táblákkal kapcsolatban. Valóban ésszerû, hogy a Balance (Egyenleg) oszlop a Customer tábla része legyen? Nos, nem, ezért az Oszlop áthelyezése újratervezési megoldással javítunk az adatbázis felépítésén.
2.3. ábra A Customer és Account táblák kezdeti adatbázissémája
2.2.1. Egyalkalmazásos adatbázis-környezetek Az elsõ lépés tehát az, hogy a példa-adatbázisunkban áthelyezünk egy oszlopot egy táblából egy másikba, egy egyalkalmazásos adatbázis-környezetben. Ennél egyszerûbb helyzettel nem fogunk találkozni: mind az adatbázisséma, mind az ahhoz hozzáférõ alkalmazás kódja teljesen a mi irányításunk alatt áll. Ebbõl következõen egyidejûleg mind a kettõt újratervezhetjük – nem kell párhuzamosan támogatnunk az eredeti és az új adatbázissémát, mert a mi alkalmazásunk az egyetlen, amelyik mûveleteket végez az adatbázison. Ennél a forgatókönyvnél azt ajánljuk, hogy ketten dolgozzanak párban: az egyikük rendelkezzen alkalmazásprogramozási készségekkel, míg a másik adatbázis-fejlesztési tapasztalatokkal – az ideális persze az lenne, ha mindketten jártasak lennének mindkét területen. A párnak elsõ lépésként meg kell határoznia, hogy az adatbázissémát újra kell-e tervezni. Elõfordulhat ugyanis, hogy a programozó téved a séma továbbfejlesztésének szükségességét illetõen vagy abban, hogy miként célszerû végrehajtani az újratervezést. Az újratervezési megoldás kidolgozásának és tesztelésének elõször a fejlesztõ homokózójában kell történnie. A munka végeztével aztán a fejlesztõ a módosításokat közzéteszi a projektegyesítõ környezetben, végül pedig a rendszert igény szerint újraépítik, tesztelik és javítják.
AdatbazisokUjratervezese02.qxd
4/21/2009
9:54 AM
Page 15
2. fejezet • Adatbázis-újratervezés
Az Oszlop áthelyezése újratervezési megoldás alkalmazásának elsõ lépése a fejlesztési homokozóban, hogy a pár lefuttatja az összes tesztet, hogy meggyõzõdjön róla, hogy sikerrel lefutnak. Ezt követõen egy új tesztet írnak, mivel a tesztvezérelt fejlesztés (TDD) megközelítését követik. Megfelelõ teszt lehet például egy olyan, amely az Account.Balance oszlopban próbál elérni egy értéket. Miután ezt a tesztet is lefuttatták, és az meghiúsult, bevezetik az Account.Balance oszlopot, ahogy azt a 2.4. ábrán láthatjuk. A következõ lépés a tesztek újrafuttatása, amelyeknek ezúttal sikerrel kell járniuk. Ez után azoknak a már meglevõ teszteknek az újratervezése következik, amelyek megerõsítik, hogy az ügyfélbetétek (deposit) a Customer.Balance helyett megfelelõen mûködnek az Account.Balance oszloppal. Ezek a tesztek meghiúsulnak, ezért a betéti mûveleteket át kell dolgozni, hogy mûködjenek az Account.Balance oszloppal. A tesztcsomagon és az alkalmazáson belül azokat az egyéb kódrészeket – például a kivéti mûveletek logikáját – is hasonlóan módosítani kell, amelyek jelenleg a Customer.Balance oszlopra támaszkodnak.
2.4. ábra A Customer és Account táblák végsõ adatbázissémája
Ha az alkalmazás ismét mûködõképes, a Customer.Balance oszlopban található adatokról biztonsági másolatot kell készíteni, majd az adatokat ebbõl az oszlopból az Account.Balance megfelelõ sorába másolni. Ezt követõen a tesztek újbóli lefuttatása következik, hogy a pár meggyõzõdjön róla, hogy az adatok áttelepítése biztonságosan megtörtént. A séma módosításának utolsó lépéseként törlik a Customer.Balance oszlopot, majd ismét lefuttatják az összes tesztet, és ha szükséges, kijavítják az esetleges hibákat. Amikor mindezzel végeztek, a módosításokat a korábban ismertetett módon közzéteszik a projektegyesítõ környezetben.
2.2.2. Többalkalmazásos adatbázis-környezetek A többalkalmazásos adatbázis-környezetekben nehezebb dolgunk van, mivel az egyes alkalmazásoknak új változatai jelenhetnek meg, amelyeket más-más idõpontban telepítenek (példánkban egy másfél éves idõszakot veszünk alapul). A fenti adatbázis-újratervezési megoldás megvalósításához egy ilyen környezetben ugyanazokat a lépéseket kell elvégeznünk, mint az egyalkalmazásos adatbázis-környezetben, azzal a különbséggel, hogy egyelõre nem töröljük a Customer.Balance oszlopot. Ehelyett egy legalább másfél évig tartó „átmeneti idõszakban” párhuzamosan fenntartjuk mindkét oszlopot, hogy a fejlesztõcsapatoknak
15
AdatbazisokUjratervezese02.qxd
16
4/21/2009
9:54 AM
Page 16
Refactoring – Adatbázisok újratervezése
elég idejük legyen minden alkalmazás frissítésére és újratelepítésére. Az adatbázissémának ezt a részét az átmeneti idõszakban a 2.5. ábrán láthatjuk. Megfigyelhetjük, hogy az átmeneti idõszakban két kioldómûvelet, a SynchronizeCustomerBalance és a SynchronizeAccountBalance futtatásával gondoskodunk róla, hogy a két oszlop összhangban legyen.
2.5. ábra Az adatbázisséma az átmeneti idõszakban
Miért tart ilyen sokáig az átmeneti idõszak? Nos, ennek az az oka, hogy lehet, hogy egyes alkalmazásokon jelenleg nem dolgoznak, míg más alkalmazások a hagyományos fejlesztési életciklust követik, és csak évente jelenik meg belõlük új változat. Az átmeneti idõszaknak tehát egyaránt számolnia kell a gyors és a lassú fejlesztõcsapatokkal. Ezenkívül nem támaszkodhatunk arra sem, hogy az egyes alkalmazások mindkét oszlopot frissítik, ezért valamilyen módon – például kioldókkal – gondoskodnunk kell a két oszlop értékeinek összehangolásáról. (Elképzelhetõ más megoldás is, például használhatunk nézettáblákat, vagy végrehajthatjuk az összehangolást a módosítás után, de amint az 5. fejezetbõl majd kiderül, tapasztalataink szerint a kioldók mûködnek a legjobban.) Az átmeneti idõszak letelte után eltávolítjuk az eredeti oszlopot, valamint a kioldót vagy kioldókat, ami a 2.4. ábrán látható végsõ adatbázissémát eredményezi. Az eltávolítást csak akkor szabad végrehajtani, ha megfelelõ teszteléssel meggyõzõdtünk róla, hogy a mûvelet biztonságosan elvégezhetõ. Az újratervezés ekkor válik teljessé. A példa megvalósítását a 3. fejezetben részletesen is bemutatjuk.
2.2.3. A jelentés megõrzése Amikor újratervezünk egy adatbázissémát, annak mind az információs, mind a viselkedési jelentését meg kell õriznünk – tehát nem adhatunk hozzá és nem is vehetünk el belõle semmit. Az információs jelentés az adatbázisban tárolt információk jelentésére vonatkozik, azok felhasználóinak szemszögébõl. Az információs jelentés megõrzése alatt azt értjük, hogy ha megváltoztatjuk egy oszlop értékeit, akkor a változásnak nem szabad hatással lennie az adatok felhasználóira. Tegyük fel például, hogy egy karakter típusú, telefonszámokat tároló oszlop adatait alakítjuk át az Egységes formátum bevezetése nevû adatbázis-újratervezési
AdatbazisokUjratervezese02.qxd
4/21/2009
9:54 AM
Page 17
2. fejezet • Adatbázis-újratervezés
megoldással, hogy az olyan számokból, mint a (416) 555-1234 és a 905.555.1212, 4165551234 és 9055551212 legyen. Bár a formátumon ezzel javítunk, hiszen így egyszerûbb kód szükséges az adatok kezeléséhez, gyakorlati szempontból az információtartalom nem változik, mert a telefonszámokat továbbra is (XXX) XXX-XXXX formában kell megjelenítenünk – csupán az információ tárolásának módját változtatjuk meg. A gyakorlati használhatóság létfontosságú az adatbázisok újratervezésénél. Martin Fowler a kódújratervezéssel kapcsolatban gyakran említi a „megfigyelhetõ viselkedés” fogalmát, rámutatva, hogy sok újratervezési-megoldásnál nem lehetünk teljesen biztosak benne, hogy nem változtatjuk meg valamilyen apró mértékben a jelentést, és legfeljebb annyit tehetünk, hogy reménykedünk, hogy a lehetõ legalaposabban végiggondoltuk a kérdést és megfelelõ teszteket írtunk, majd futtatjuk ezeket a teszteket, hogy ellenõrizzük, hogy nem változott-e meg a jelentés. Tapasztalataink szerint az adatbázissémák újratervezésekor is ez a helyzet az információs jelentés megõrzését illetõen. A (416) 555-1234 4165551234-re módosítása elképzelhetõ, hogy valamelyik alkalmazásban a tudtunk nélkül kissé megváltoztatta az információ jelentését – például létezhet egy olyan kimutatás, amely csak azokat az adatsorokat veszi figyelembe, amelyekben a telefonszám (XXX) XXX-XXXX formában szerepel, vagyis a kimutatás erre a formátumra támaszkodik. Az is lehet, hogy bár gyakorlati szempontból továbbra is ugyanazt az információt küldjük a kimenetre, a kimutatás az újratervezés után XXXXXXXXXX formában írja ki a számokat, amelyek így nehezebben olvashatók lesznek. Miután felfedeztük a problémát, a kimutatás frissítésére lehet szükség, hogy az tükrözze az új formátumot. A viselkedési jelentés vonatkozásában is az a cél, hogy a „fekete doboz” mûködése változatlan maradjon: minden forráskódot, amely az adatbázisséma módosított részein végez mûveleteket, át kell dolgozni, hogy ugyanazt a mûködést érjük el, mint korábban. Például ha a Számítófüggvény bevezetése újratervezési megoldást alkalmazzuk, más tárolt eljárások átdolgozására is szükség lehet, hogy az új függvényt hívják meg a számítási logika megvalósítása helyett. Kívülrõl nézve az adatbázis ugyanazt a logikát valósítja meg, csak éppen a számítási logika most már csak egyetlen helyen szerepel. Fontos tudnunk, hogy az adatbázis-újratervezés az adatbázis-transzformációk részhalmaza, de míg egy adatbázis-transzformáció megváltoztathatja a jelentést, az adatbázis-újratervezés nem. A 11. fejezetben több szokványos adatbázis-transzformációt is bemutatunk, mert egyrészt lényeges, hogy megértsük a mibenlétüket, másrészt ezek a transzformációk gyakran szükséges lépések egy-egy adatbázis-újratervezési megoldáson belül. Például amikor fentebb az Oszlop áthelyezése újratervezési megoldást alkalmaztuk, hogy a Balance oszlopot a Customer táblából az Account táblába helyezzük át, az egyik lépés az Oszlop bevezetése transzformáció alkalmazása volt. Felületesen szemlélve az Oszlop bevezetése tökéletesen kielégíti az újratervezési megoldások követelményeit: egy üres oszlop hozzáadása egy táblához nem változtatja meg a tábla jelentését, amíg egy új alkalmazáskód használni nem kezdi az oszlopot. Azért tekintjük
17
AdatbazisokUjratervezese02.qxd
18
4/21/2009
9:54 AM
Page 18
Refactoring – Adatbázisok újratervezése
mégis transzformációnak (és nem újratervezésnek), mert a szándékunktól függetlenül megváltoztathatja egy alkalmazás viselkedését. Például ha az oszlopot a tábla közepére szúrjuk be, minden olyan programkód, amely a helyük szerint éri el az adatokat (tehát például a 17. oszlopra hivatkozik az oszlop neve helyett), mûködésképtelenné válik. Ezenkívül a DB2 típusú táblákhoz kapcsolt COBOL kódok akkor sem fognak mûködni, ha nem kötjük õket az új sémához, ha az oszlopot a tábla végére vesszük fel. Végeredményben mindig a gyakorlati használhatóság kell, hogy az iránytûnk legyen. Az, ha az Oszlop bevezetése eljárást újratervezésnek (vagy akár „subidubidúnak”) minõsítjük, még nem befolyásolja azt, ahogy használjuk (legalábbis reméljük).
Miért ne véglegesítsünk már az elején? Az adatszakértõk gyakran hangoztatják, hogy a valódi megoldást az jelenti, ha mindent elõre modellezünk, mert így nincs szükség az adatbázisséma késõbbi újratervezésére. Ez érdekes elképzelés, és némely esetben mûködhet is, de három évtized tapasztalataival a hátunk mögött kijelenthetjük, hogy általánosságban nem bizonyult a gyakorlatban jól mûködõ programozói megközelítésnek. Az adatmodellezés hagyományos megközelítése nem tükrözi sem az olyan modern eljárások, mint az RUP vagy az extrém programozás fokozatos megközelítését, sem azt a tényt, hogy az üzleti megrendelõk egyre gyorsuló ütemben igényelnek új szolgáltatásokat, illetve a meglevõk módosítását, és a régi módszerek egyszerûen nem kielégítõek többé. Szerintünk az 1. fejezetben ismertetett agilis modellvezérelt fejlesztés (Agile ModelDriven Development, AMDD) megközelítését célszerû követni, amely szerint kezdetben csak magasszintû modellezést végzünk, hogy elkészítsük a rendszer átfogó „térképét”, majd igény szerint, modellrohamok során dolgozzuk ki a részleteket. A modellezés elõnyeit így anélkül használjuk ki, hogy viselnünk kellene a túlmodellezés és a túldokumentálás költségeit, illetve a túl sok alkotóelem naprakészen tartásával és összehangolásával járó bürokratikus terheket. Az alkalmazáskód és az adatbázisséma aszerint fejleszthetõ tovább, ahogy egyre jobban megértjük a problématartományt, és a minõséget a kettõ újratervezésével biztosíthatjuk.
2.3. Az adatbázis-újratervezési megoldások fajtái Az adatbázis-újratervezési megoldásoknak hat csoportját különböztetjük meg; ezeket a 2.1. táblázatban soroltuk fel. A csoportosítást ennek a könyvnek a rendszerezése érdekében vezettük be, de reméljük, hogy a jövõben megalkotandó adatbázis-újratervezési eszközök rendszerezésében is segíteni fog. A csoportosítási módszerünk persze nem biztos, hogy tökéletes: a Függvény helyettesítése nézettáblával például az architekturális és a függvény-újratervezési megoldások közé is sorolható, mert mindkettõ alátámasztható érvekkel. (Mi az architekturális újratervezés kategóriájába helyeztük.)
AdatbazisokUjratervezese02.qxd
4/21/2009
9:54 AM
Page 19
2. fejezet • Adatbázis-újratervezés 2.1. táblázat
Az adatbázis-újratervezési megoldások fajtái
Adatbázis-újratervezési kategória Leírás Szerkezeti újratervezés Egy vagy több tábla (6. fejezet) vagynézettábla meghatározásának módosítása. Adatminõségi újratervezés Olyan módosítás, (7. fejezet) amely az adatbázisban tárolt információ minõségén javít.
Hivatkozási épségi újratervezés (8. fejezet)
Architekturális újratervezés (9. fejezet)
Függvény-újratervezés (10. fejezet)
Nem újratervezõ átalakítás (11. fejezet)
Példák Oszlop áthelyezése egy táblából egy másikba; vagy egy többcélú oszlop több önálló, egy-egy szerepet betöltõ oszlopra bontása. Oszlop nem nullázhatóvá tétele annak biztosítása érdekében, hogy az oszlop mindig tartalmazzon valamilyen értéket; vagy egységes formátum alkalmazása egy oszlopra a következetesség biztosítása érdekében. Olyan módosítás, Kioldó felvétele, amely lépcsõzeamely azt biztosítja, tes törlést tesz lehetõvé két egyed hogy egy hivatkozott között, szükségtelenné téve egy sor létezzen egy másik korábban az adatbázison kívül táblában, illetve hogy megvalósított kódot. egy feleslegessé vált sor törlése megfelelõen történjen. Olyan módosítás, Egy megosztott kódkönyvtárban amely a külsõ progra- található létezõ Java-mûvelet mok és az adatbázis cseréje egy az adatbázisban levõ együttmûködését álta- tárolt eljárásra, amelyet így a nem lánosságban javítja. Java nyelvû alkalmazások is elérhetnek. Tagfüggvény (tárolt Egy tárolt eljárás átnevezése, hogy eljárás, tárolt függvény a szerepe könnyebben vagy kioldómûvelet) értelmezhetõ legyen. olyan módosítása, amely a tagfüggvény minõségén javít. Az adatbázis-tagfüggvényekre számos kódújratervezési megoldás alkalmazható. Az adatbázisséma olyan Új oszlop hozzáadása egy létezõ módosítása, amely táblához. megváltoztatja a séma jelentését.
19
AdatbazisokUjratervezese02.qxd
20
4/21/2009
9:54 AM
Page 20
Refactoring – Adatbázisok újratervezése
2.4. Adatbázisszag ok A „kódszag” fogalmát Fowler (1997) vezette be: ez a kifejezés egy olyan általános problémacsoportra utal, amely azt jelzi, hogy újratervezésre lehet szükség. A leggyakrabban elõforduló kódszagok („gyanús szagú kódok”) közé tartoznak a switch utasítások, a hosszú függvények, a többször ismétlõdõ azonos kódrészletek (megkettõzött kódok), illetve a szolgáltatások elirigylése. Ehhez hasonlóan léteznek adatbázisszagok is, amelyek szintén az újratervezés szükségességét jelezhetik (Ambler 2003). Ezek közé a következõk tartoznak: • Többcélú oszlop. Ha egy oszlop több szerepet is betölt, akkor valószínû, hogy külön kódra van szükség a forrásadatok „megfelelõ” használatának biztosítása érdekében. Ez a kód többnyire egy vagy több másik oszlop értékeit ellenõrzi. Lehet például egy olyan oszlopunk, amely valakinek a születésnapját tárolja, amennyiben az illetõ egy vásárló, de a munkába állás idõpontját, ha a személy egy alkalmazott. Ennél is rosszabb, hogy ez valószínûleg korlátozza a lehetõségeinket – hogyan tárolhatjuk például egy alkalmazott születésnapját? • Többcélú tábla. A fentihez hasonlóan elõfordulhat, hogy egy táblát használunk többféle elem tárolására, ami szintén tervezési hibára utal. Ennek példája lehet egy olyan általános Customer (Ügyfelek) tábla, amely emberekrõl és cégekrõl egyaránt tárol információt. Ezzel a megközelítéssel az a gond, hogy a kettõ más-más adatszerkezetet igényel, az embereknek ugyanis kereszt- és vezetékneve is van (és esetleg középsõ nevük is), míg a cégeknek csak egy hivatalos nevük. Egy általános Customer táblában tehát olyan oszlopok is lehetnek, amelyek bizonyos ügyfelek esetében üresek, míg más ügyfeleknél nem. • Felesleges adat. A felesleges (redundáns) adatok komoly problémát jelentenek a mûveleti adatbázisokban, mivel ha az adatokat több helyen tároljuk, azok következetlenné válhatnak. Nagyon gyakori például, hogy az ügyfélinformációkat több helyen is tárolják a vállalat rendszerében, és emiatt sok cég képtelen pontos listát készíteni arról, hogy valójában kik is az ügyfeleik. A gondot az okozza, hogy elõfordulhat, hogy az egyik táblában John Smith a 123 Main Street alatt lakik, míg egy másik táblában a lakcíme a 456 Elm Street. Valójában persze ugyanarról a személyrõl van szó, aki korábban a 123 Main Street címen lakott, de egy éve elköltözött, és sajnos nem két lakcímváltozás-bejelentõ ûrlapot nyújtott be a cégünkhöz (egyet-egyet a róla tudomással bíró két alkalmazás számára). • Túl sok oszlopot tartalmazó tábla. Ha egy tábla túl sok oszlopot tartalmaz, az arra utal, hogy a tábla nem egységes szerkezetû, vagyis többféle elemet próbál egyetlen helyen tárolni. A Customer táblánkban például lehetnek olyan oszlopok, amelyek különbözõ címeket (szállítási, számlázási és ideiglenes) vagy telefonszámokat (otthoni, munkahelyi, mobil stb.) tárolnak. Ilyen esetben valószínûleg a szerkezet normalizálására van szükség egy Address (Cím) és egy PhoneNumber (Telefonszám) tábla bevezetésével.
AdatbazisokUjratervezese02.qxd
4/21/2009
9:54 AM
Page 21
2. fejezet • Adatbázis-újratervezés
• Túl sok sort tartalmazó tábla. A nagy táblák teljesítményproblémákat okozhatnak; egy több millió sorból álló táblában például nagyon sokáig tarthat a keresés. Ilyenkor érdemes lehet egyes oszlopok másik táblába helyezésével „függõlegesen”, vagy sorok áthelyezésével „vízszintesen” felbontani a táblát. Mindkét megoldás csökkenti a tábla méretét, ami javíthat a teljesítményen. • „Okos oszlop”. Az „okos oszlop” olyan oszlop, amelyben az adatértékek egyes részei más-más fogalmaknak felelnek meg. Ha egy ügyfélazonosító elsõ négy számjegye például az ügyfélcég egy-egy irodáját jelöli, akkor az ügyfélazonosító oszlop „okos oszlop”, mert a feldolgozásával aprólékosabb információkhoz (például a központi iroda azonosítójához) juthatunk. Egy másik példa lehet egy olyan szöveges oszlop, amely XML-adatszerkezeteket tárol: világos ugyanis, hogy az XML-adatszerkezetek kisebb adatmezõkre bonthatók. Az okos oszlopokat általában célszerû valamikor a fejlesztés során az alkotóelemeket tároló adatmezõkre felbontani, hogy az adatbázis egyszerûen kezelhesse azokat önálló elemekként. • Félelem a változtatástól. Ha nem merjük megváltoztatni az adatbázissémát, mert attól tartunk, hogy elrontunk valamit, ami korábban mûködött – például azt az ötven alkalmazást, amely olvas az adatbázisból –, az a legbiztosabb jele annak, hogy a sémát újra kell terveznünk. A félelem a változtatástól egyértelmûen jelzi, hogy komoly kockázat áll fenn, ami idõvel csak növekedni fog. Fontos, hogy megértsük, hogy csak azért, mert valaminek erõs szaga van, még nem biztos, hogy rossz – egyes sajtoknak például kifejezetten erõteljes illatuk van, pedig nagyon finomak. Ha viszont a tej áraszt rossz szagot, akkor tudhatjuk, hogy valami nincs rendben vele. Tehát ha szagot érzékelünk, elõször nézzük meg, honnan ered, gondoljuk végig a kérdést, és csak akkor hajtsunk végre újratervezést, ha az ésszerû.
2.5. Az adatbázis-újratervezés helye a fejlesztési folyamatban A modern szoftverfejlesztési eljárások – beleértve a Rational egyesített eljárást (Rational Unified Process, RUP), az extrém programozást (XP), az agilis egyesített eljárást (Agile Unified Process, AUP), a Scrumot és a dinamikus rendszerfejlesztési módszert (Dynamic System Development Method, DSDM) – kivétel nélkül fokozatos jellegûek. Craig Larman (2004) összefoglalta a kutatások eredményét, amelyek a fokozatosságra épülõ fejlesztés elõnyeit támasztják alá, és rámutatott, hogy az informatikusok közösségének szellemi vezetõi túlnyomó többségben ezt a megközelítést támogatják. Az adatközpontú eljárások többsége azonban sajnos soros jellegû, és a szakértõk által végrehajtott viszonylag szûk körû feladatokra, például a logikai vagy a fizikai adatmodellezésre támaszkodik. Ebben rejlik a probléma – a két csoportnak együtt kell mûködnie, de mindkettõ másképp képzeli el a feladatok végrehajtását. A mi álláspontunk az, hogy az adatprogramozók ugyanúgy hasznot húzhatnak a modern, fokozatosságra épülõ eljárások átvételébõl, mint a programfejlesztõk, és az adatbázis-újratervezés egyike azoknak a fontos készségeknek, amelyeket az adatprogramozóknak el
21
AdatbazisokUjratervezese02.qxd
22
4/21/2009
9:54 AM
Page 22
Refactoring – Adatbázisok újratervezése
kell sajátítaniuk. Sajnos az adatokkal foglalkozók közössége lemaradt az 1990-es évek objektumforradalmáról, és kihagyta azt a lehetõséget, hogy megtanulja azokat a fokozatos eljárásokat, amelyeket az alkalmazásprogramozók ma már rutinszerûen alkalmaznak. Bizonyos szempontból ehhez hasonlóan hagyják figyelmen kívül most az agilis megközelítés forradalmát, amely egy lépéssel továbbmegy a fokozatos fejlesztésnél, és a minél szorosabb együttmûködést helyezi a középpontba. Az adatbázis-újratervezés egy adatbázis-megvalósítási módszer, ugyanúgy, ahogy a kódújratervezés egy alkalmazás-megvalósítási eljárás. Az adatbázisséma újratervezésének célja az, hogy megkönnyítsük az adatbázis késõbbi bõvítését. Gyakran elõfordul, hogy egy adatbázist új képességgel kell kiegészítenünk, például egy új oszlopot vagy tárolt eljárást kell adnunk hozzá, de a meglevõ felépítés nem a legalkalmasabb erre. A bõvítés elsõ lépéseként ezért újra kell terveznünk az adatbázissémát, hogy megkönnyítsük a bõvítést, és az újratervezési megoldás sikeres alkalmazása után vehetjük fel az új szolgáltatást. Ennek a megközelítésnek az az elõnye, hogy lassan, de folyamatosan javítunk az adatbázis felépítésének minõségén. Ez az eljárás nem csak könnyebben értelmezhetõvé és használhatóbbá teszi az adatbázist, hanem a késõbbi bõvítést is egyszerûbbé teszi – más szavakkal, a fejlesztés általános hatékonyságát is javítja.
2.6. ábra Egy fokozatos fejlesztésû projekt lehetséges fejlesztési tevékenységei
A 2.6. ábrán annak a magasszintû áttekintését láthatjuk, hogy milyen létfontosságú tevékenységeket kell végrehajtani egy olyan modern projektben, amely egyaránt támaszkodik objektumokra és relációs adatbázisokra. Figyeljük meg, hogy minden nyíl kétirányú
AdatbazisokUjratervezese02.qxd
4/21/2009
9:54 AM
Page 23
2. fejezet • Adatbázis-újratervezés
kapcsolatot jelez, vagyis a tevékenységek között oda-vissza váltunk, szükség szerint. Azt is vegyük észre, hogy nincs sem meghatározott kezdõpont, sem meghatározott végpont, ami világosan mutatja, hogy nem hagyományos, soros megközelítésrõl van szó. Az adatbázis-újratervezés csak egy része a fokozatos adatbázis-fejlesztésnek. A fokozatos, illetve agilis megközelítést az adatmodellezésre is alkalmazzuk, az adatbázissémát továbbra is tesztelni kell, és gondoskodni kell az alkotóelemek változásainak nyomon követésérõl, valamint az adatbázis megfelelõ hangolásáról is – ezeket a témaköröket azonban meghagyjuk más könyveknek.
2.6. Az adatbázisséma újratervezésének megkönnyítése Minél szorosabb csatolás áll fenn, annál nehezebb újratervezni valamit. Ez igaz a kódújratervezésre és természetesen az adatbázis-újratervezésre is. A tapasztalatunk az, hogy a csatolás akkor válik komoly kérdéssé, amikor a mûveleti kérdéseket (programkódokat) kezdjük vizsgálni – számos adatbázisokkal foglalkozó könyv elkerüli ezt a témát. A legegyszerûbb helyzetet nyilvánvalóan az egyalkalmazásos adatbázisok jelentik, mivel ezek esetében az adatbázisséma csak önmagával és az alkalmazásunkkal áll kapcsolatban. Egy a 2.7. ábrán láthatóhoz hasonló többalkalmazásos adatbázis-architektúrában azonban csatolás állhat fenn az adatbázisséma és több alkalmazás forráskódja, tárolóelérési keretrendszerek, objektumrelációs leképezõ (ORM) eszközök, (többszörözésen, adatkiolvasáson- és betöltésen stb. keresztül) más adatbázisok, adatfájlsémák és tesztkódok között, sõt magán az adatbázissémán belül is.
2.7. ábra Az adatbázisok szoros kapcsolatban állnak külsõ programokkal
Az adatbázis vonatkozásában fennálló csatolás lazításának hatékony módja az adatbázis elérésének betokozása. Ezt úgy érhetjük el, hogy a külsõ programokat arra kényszerítjük, hogy az adatbázishoz tárolóelérési rétegeken keresztül férjenek hozzá (lásd a 2.8. ábrát).
23
AdatbazisokUjratervezese02.qxd
24
4/21/2009
9:54 AM
Page 24
Refactoring – Adatbázisok újratervezése
Tárolóelérési réteget többféleképpen is megvalósíthatunk: adatelérési objektumokkal (data access object, DAO), amelyek megvalósítják a szükséges SQL-kódot; keretrendszerekkel; tárolt eljárásokkal; sõt webszolgáltatásokon keresztül is. Ahogy az ábrából is kiderül, a csatolás soha nem csökkenthetõ nullára, de mindenképpen kezelhetõ mértékûre szorítható.
2.8. ábra A csatolás lazítása a hozzáférés betokozásán keresztül
2.7. Összefoglalás A kódújratervezés egy programkód fegyelmezett, kis lépésekben történõ módosítása a kód felépítésének javítása érdekében. A kódújratervezés megõrzi a kód viselkedési jelentését, tehát nem bõvíti új képességekkel a kódot, és nem is vesz el belõle képességeket. Ehhez hasonlóan az adatbázis-újratervezés az adatbázissémán végrehajtott olyan apró módosítást jelent, amely javít a séma felépítésén, miközben megtartja annak viselkedési és információs jelentését. Amint megtanultuk, az adatbázis-újratervezés az egyik legfontosabb eljárás, amely lehetõvé teszi az adatprogramozók számára, hogy az adatbázisok fejlesztésében fokozatos megközelítést alkalmazzanak; ezen kívül láttuk, hogy minél szorosabb csatolás áll fenn az adatbázis és az adatbázist elérõ más elemek között, annál nehezebb az adatbázis újratervezése.