Az infokukac blog 2010. márciusában átköltözött. Átirányítás folyamatban...

Az átirányítás automatikus. Ha mégsem sikerülne, látogasd meg az új oldalt a http://infokukac.com címen, és frissítsd a könyvjelzőidet!

2009. augusztus 19., szerda

A visszajelzések

A szoftverprojektek szállítása egy komplex feladat, komplex rendszerként viselkedik. Ennek a rendszernek rengeteg összetevője van: maga a rendszer, a fejlesztők, tesztelők, az üzleti környezet, a futtató hardver, az infrastruktúra, a folyamatos bizonytalanság, a kockázatok stb. Hogyan biztosítható az (vagy hogyan csökkenthetőek a kockázatok), hogy egy fejlesztés alatt lévő komplex rendszer egy olyan irányba fejlődjön, hogy végül azt alkalmazni lehessen?

Az agilis szoftverfejlesztésben alkalmazott mérnöki(?) gyakorlatok egyik célja az, hogy minél korábbi visszajelzéseket kapjunk a munkánkról. Az agilis módszertanok egyszerűen "üdvözlik" a folyamat során bekövetkező hibákat, kudarcokat, mert fel vannak készülve arra, hogy ezek egy projektnek természetes velejárójuk.

Először egy korai előfeltevésből indulunk, utána pedig fel kell ismernünk, hogy hol hibáztunk. Egyszerűen tanulunk és javítunk

Mik azok a módszerek, és hogyan járulnak hozzá ahhoz, hogy a komplex szoftvert végül kifejleszthessük, és az sikeres legyen? Ebben a cikkben megkísérlek áttekintést adni az általam megismert technikákról. Az egyes technikáknak az alkalmazása több előnnyel is szolgálhat, most csak a visszacsatolások szemszögéből jellemzem őket.

Prioritás alapú fejlesztés

Amikor egy szoftver elkészítése a fejlesztési szakaszába ér, folyamatos probléma az, hogy milyen funkciók kifejlesztése mentén haladjunk a cél felé. Sok esetben projekt ütemtervet készítenek. Mi is számtalanszor próbálkoztunk ezzel, de a következő problémákkal szembesültünk:

  • Lehetetlen előre jól megbecsülni a feladatokra fordítandó időt, ez hatványozottan jelentkezik az időben egyre távolabb lévő taszkokra.
  • Lehetetlen előre lebontani a projektet taszkokra, ennek több oka is van: az elején nem látjuk a lefejlesztendő rendszer képességeit, tudását, nem ismerjük az üzleti problémát, a követelmények(?) pedig állandóak változnak.
    • A projektterv figyelembe veszi az erőforrásokat is, mivel sem a feladatokra szánt időt nem tudjuk megbecsülni, sem a feladatokat magukat nem tudjuk megfogalmazni, az erőforrások figyelembevételével történő projekttervezés extrém bonyolítságúvá teszi az amúgy is bizonytalan projekttervet.
    • Az így felállított ütemterv általában pár hét alatt szétesik, és már képtelenség követni, annak megfelelni.
        
    A Scrum szerint a lefejlesztendő funkciókat üzleti szempontból kell megfogalmazni, ezeket üzleti szempontból is kell priorizálni, és mindig a legnagyobb prioritású (azaz legfontosabb) sztorikkal haladni. A kérdés mindig az: ha az üzleti felhasználó szemével tekintjük a hátralévő funkciókat, akkor ezek közül melyik az, amelyik a legnagyobb hasznot hozza? Ha ezt kiválasztottuk, jöhet a következő sztori. Miért jó ez?

    • A megrendelőnek már igen korán visszacsatolási lehetősége nyílik, és az alapján korrigálhatunk.
    • A legfontosabb funkciók meghatározzák a szoftver alapvető működését, a felhasználói felületeket, a domain model-t, ezáltal a fejlesztő is a lehető legkorábban megtanulhatja az üzleti tudást, és megismerheti a fejlesztés alatt lévő rendszerének a lehetőségeit, képességeit. Tehát a fejlesztő számára a prioritás alapú fejlesztés a tanulásban jelent hatékony visszacsatolást.

    Egyszer megrendelői oldalon ültem, és három szállítóval is tárgyaltunk. Mindegyik felvázolta a rendszerrel kapcsolatos elképzeléseit, a fejlesztési módszertanát. Az egyik szállító cég így kezdte: "először megcsináljuk az adminisztrációs felületeket". Tipikus hiba. Az adminisztrációs felületek az ügyfélnek (legalábbis az üzleti megrendelőnek) kevés hozzáadott értéket képviselnek, ez csak egy "szükséges rossz" a programban. Ha elkészül az admin felület, semmit nem tudunk levonni a szoftver tényleges működésével kapcsolatban, a hozzáadott üzleti értékéről, nincs lehetőség a minél korábbi visszacsatolásra. (Ráadásul - megítélésem szerint - egy jó admin felületet csak akkor lehet megcsinálni, ha már a szoftverben "a dolgok a helyükre kerültek", és tudjuk, hogy mit kell pontosan adminisztrálni.)

    Pair programming

    A páros programozás az XP módszertan részre. A lényege, hogy ketten ülnek a gép előtt, az egyik gépel, a másik figyeli. Az előnye, hogy a gépelő azonnali visszajelzést kap az őt figyelőtől. Ha valamit elront, azt azonnal lehet javítani. Ha egy junior fejlesztő ül a gépnél, és egy senior nézi, a junior fejlesztő a kapott visszacsatolások alapján gyorsabban is fejlődik.

    Code review

    A code review célja, hogy a fejlesztői csapat által készített kódokat a fejlesztői csapat közösen áttekinti, ellenőrzi. (Ezt sokféleképpen lehet megtenni, pl. mielőtt/miután update-elünk, megnézzük, hogy milyen változások történtek a szoftverben, vagy a vezető fejlesztő nézi át minden nap a commit-okat, vagy ha patch-et adunk ki egy élesben lévő rendszerhez, akkor mindig valaki más is megnézi, hogy milyen változások történtek a programban, és ezek okozhatnak-e újabb hibákat.)

    A code review-k segítenek a hibák idő előtti megtalálásában, és az új kódbázisnak a csapattudásba történő hatékonyabb integrálásában.

    Folyamatos integráció

    Ha a kódunkhoz automatizált teszteseteket írunk, és ezen automatizált teszteseteket egy Continuous Integration (CI) szerveren minden commit után automatikusan lefuttatjuk, azonnali visszajelzést kapunk arról, hogy a kódbázisban történt változtatások nem okoznak-e hibákat a kód egyéb részeiben.

    Ez hatalmas segítséget nyújt a hibák mihamarabbi megtalálásában. Ha új funkciót fejlesztünk vagy egy hibát javítunk, biztosíthatjuk, hogy nem (vagy minimális) hiba került a rendszerbe. Ha egy csapat ezzel a módszerrel dolgozik, véleményem szerint soha nem akarja ezt már kihagyni.

    On-site customer

    Ha a szoftverfejlesztői csapat részévé válik az üzleti szakértő, akkor ő nagyban hozzájárulhat ahhoz, hogy a fejlesztendő szoftver sikeres legyen. Az ügyfél folyamatosan velünk dolgozik, megismerjük a gondolkozását, az üzleti terület nyelvezetét, működését.

    Mielőtt neki állunk egy új funkciót fejleszteni, van kitől kérdezni: hogy működjön, hogy fogják használni, milyen legyen a felhasználói felület? Az éppen a kezünk közül kiesett felhasználói felületeket, programrészek működését, azonnal ellenőriztethetjük az on-site customerrel

    Sztori alapú fejlesztés

    A fejlesztendő funkciókat célszerű üzleti oldalról megközelítve megfogalmazni. Amikor egy sztorit fejlesztünk, írjunk hozzá egy forgatókönyvet konkrét példával, amin keresztül bemutatható az adott sztori (how-to-demo forgatókönyv). A forgatókönyv elkészítését mi a fejlesztőre bízzuk azért, hogy kikényszerítsük tőle az üzleti probléma megértését. Ha a forgatókönyvet meg tudja írni, tudja, hogy mit kell megcsinálnia. Általában az a jellemző, hogy nem tudja magától megírni (és ez nagyon jó!), ezért segítséget kell kérnie az üzleti szakértőtől, esetleg a csapattal közösen találják ki a részleteket.

    A sztori alapú fejlesztés azonnal kikényszeríti a tanulást, a problémák azonnali felvetésével. Ha nem írunk ilyen forgatókönyvet, annak az eredménye az, hogy a fejlesztő elkezdi valahogy csinálni az adott funkciót, időnként kérdez (vagy nem), és az eredmény sokszor egy nem jól megvalósított funkció. (Nem előnyös felhasználói felület, üzletileg nem jól működő program.)

    Daily stand-ups

    A napi 10-15p-esre tervezett stand-up-ok lényege, hogy a teljes csapat egyénenként beszámoljon arról, hogy mit csinált előző nap, mit tervez az adott napra. Ha valami akadály merül fel, egyből orvosolható. A probléma nem csupán a szoftverrel kapcsolatos lehet, lehet külső tényező is. Pl. kapcsolódhat a szoftverfejlesztő cég belső szervezeti problémáihoz (pl. az embert ide-oda ráncigálják projektek között). A napi stand-up-ok alapján felfedhetők a résztvevők motivációs problémái is. (Ennek megoldása nem a stand-up-ok feladata.)

    Iteratív fejlesztés

    Az iteratív fejlesztés célja, hogy tanuljunk belőle, miközben csináljuk. Az iterációk után az ügyfélnek tartott demók, a demók utáni csapatmegbeszélések (retrospectives) mind azt a célt szolgálják, hogy a szoftverfejlesztésben résztvevők kinyilváníthassák véleményüket, felfedjék a (lehetséges) problémákat. Ezen problémák felismerése, a rájuk történő ellenlépések kidolgozása annak a folyamatnak a részei, amelyben a projekt - mint egy komplex rendszer - megtanulja önmagát kezelni.

    Inkrementális fejlesztés

    Az inkrementális fejlesztés célja, hogy az egyre növekvő rendszert szándékosan kitegyük a valós környezeti hatásoknak. A valós környezet (felhasználók, üzleti környezet, hardver, infrastruktúra) egy olyan tényleges visszajelzést juttat a projektbe, amely a tanulást és az adaptációt ténylegesen kikényszeríti. Ha rövidebbre vesszük a release-ciklusokat, az inkrementális fejlesztésből adódó visszajelzésekre még időben tudunk reagálni. (Nem 1 év múlva derül ki, hogy alapjaiban rossz a rendszer.) Az agilis módszertanok sürgetik a release-eket. 




    2009. augusztus 18., kedd

    Kommentek a kódban

    Sokat hallani másoktól, hogy írjunk kommentet a kódba. A fő érv a javaslók körében az, hogy ezáltal a programkódot érthetőbbé tehetjük. Az idők során megtanultam azonban azt, hogy a kommentek sok esetben nemhogy hasznosak, de kifejezetten károsak is tudnak lenni.

    Milyen célból használunk kommentezést?

    • programrészletek átmeneti kikommentezésére, mert valamit ki szeretnénk próbálni (nyomkövetés céljából),
    • egy alternatív implementációt próbálunk létrehozni, és meghagyjuk az eredeti kódot,
    • hogy elmagyarázzuk, éppen mit csinál egy kódrészlet (pl. osztály, metódus, metóduson belüli részkód), vagy mit jelentenek egyes programstruktúrák (pl. változók, mezők),
    • hogy elmagyarázzuk, hogyan működik a kód, 
    • hogy elmagyarázzuk, miért implementáltunk valamit úgy, ahogy,
    • TODO-k.

    Ottfelejtett kódrészletek

    Ha egy kódrészletet újra akarunk írni, gyakran tesszük azt, hogy az eredeti kódrészletet kikommentezzük, és az alapján - mintegy emlékeztetőt használva - írjuk meg az új kódot. Az így ottfelejtett kódrészleteknek megvan az a veszélye, hogy a valódi kód olvasásakor, áttekintésekor állandóan ezt a kódot fogjuk kerülgetni, és ezáltal fókuszunkat vesztjük. Lehet, hogy az amúgy egy képernyőn elférő metódus sem látszik már, mert tele van tűzdelve mindenféle régi szeméttel. Vannak gyűjtögető életmódot folytató emberek, akik egyszerűen úgy gondolják, hogy "jó az, ha megvan". Valóban jó? Ha ott hagyunk egy kódrészletet, és helyette írunk egy másikat, fogjuk-e még hasznát venni az eredetinek? Csak egy kis időnek kell eltelnie, és már semmi haszna nem lesz, csak gátol minket az olvasásban.

    Az otthagyott, kikommentezett kódnak megvan az a további veszélye is, hogy az arra tévelyedő fejlesztőtársaink elkezdik elemezni, értelmezni. Kérdéseket vet fel, kétségéket ébreszt bennük, elgondolkodtatja őket. Ez ritkán produktív. Ha meglátok egy ilyet, azonnal törlöm. (A source control-ban úgyis megvan.)

    Mit csinál a kód?

    Ha valaki elkezd a kódba egy kisregényt írni, hogy az adott rész épp mit csinál, az általában nem veszi a fáradtságot arra, hogy a kódot tisztességesen megírja. Miért? Ha a változóink, metódusaink, osztályaink elnevezése megfelelő ("beszédes"), akkor nem feltétlenül kell leírni azt, hogy mit csinál a kód. Például metódusaink elnevezésekor törekedni kell arra, hogy a metódus neve felfedje azt, hogy az mit csinál (nem tudom eléggé hangsúlyozni a mit szócskát). (Ha nem tudunk nevet adni neki, az alkalmasint azt jelenti, hogy épp rossz úton haladunk.)

    Egy hosszú metóduson belül sem kell kommenteznünk az egyes részeket, mert ha azokat megfelelően emeljük ki külön metódusba, máris tudunk nekik külön nevet adni. (Refaktorálás: Extract Method).

    API-k esetében kötelező a szabványos kommentezés (pl. legalább metódus szinten), ld. pl. Javadoc, vagy .NET XML comments.

    Hogyan működik a kód?

    Nem maga a kód írja le önmaga működését? Ha a kód jól struktúrált, és a metódusainknak, változóinknak tudunk értelmes(!) nevet adni, szükség van-e arra, hogy leírjuk hogyan működik a kód? Úgy gondolom, általában nincs rá szükség. 

    Miért?

    Ha azt szeretnénk fejlesztőtársainknak kommunikálni, hogy valamit miért éppen úgy valósítottunk meg ahogy, akkor azt kifejezetten hasznos kommentekben leírnunk. Kiváló példa erre a workaround-ok esete: valamilyen technológiát alkalmazunk, aminek van egy általunk ismert hibája. Hogy összességében elérjük a célunkat, ezt valahogyan körbe kell programoznunk, és a megoldás sokszor nem triviális. Ilyenkor teljesen természetes, hogy jelezzük, miért csináltunk meg valamit úgy, ahogy.

    TODO-k

    A TODO-k nagyon hasznosak. Ha valamit nem implementálunk teljesen, akkor oda írjuk a kódban a megfelelő helyre, hogy azt még meg kell csinálni (pl. TODO: A 24 számjegynél hosszabb hitelkártyaszámok kezelése). Minden modern fejlesztőkörnyezet képes a forráskódban elhelyezett TODO-k kigyűjtésére, és ezáltal ezekkel utólag is foglalkozhatunk.

    A TODO-kkal csak egyetlen gond van: ha egy kicsit nem figyelünk, elszaporodnak, és csak kerülgetni fogjuk őket. Eleinte frusztrációt okoznak, de rövid időn belül immunissá válunk rájuk, és a TODO-k mögötti valódi problémák rejtve is maradnak. Tapasztalatom szerint a produkciós környezetbe simán megy ki úgy kód, hogy tele van TODO-kkal. Miért jók akkor, ha nem kezdünk velük semmit? 

    Ezeket is irtani kell. De hogyan?

    • Előfordul, hogy egy üzleti probléma húzódik meg a háttérben. Ezt próbáljuk minél hamarabb tisztázni, és kezeljük új sztoriként (funkcióként), amit egyszer majd lefejlesztünk. (Ha kell majd egyáltalán.)
    • Ha a kód túltervezett, sokszor belebukunk abba, hogy az "általános" megoldást nem jut időnk befejezni. Egyszerűsítsük a kódot azonnal.
    • Ha tudjuk, hogy hibásan működik a kódrészlet, akkor - ha lehet - azonnal javítsuk ki. Ha nem lehetséges, vigyük fel a hibát a hibakövető rendszerbe (a reprodukálás módjával). Ezzel elősegítjük a tesztelőket abban, hogy ők is részt vegyenek a hiba elemzésében, ellenőrzésében, és egységes rendszerben kezeljük a hibákat.
    • Valamibe belekezdünk, de valami miatt úgy döntünk, hogy még nem fejezzük be, mert más dolgunk akadt, vagy máshol simogatjuk a programkódot. Ezekben az esetekben inkább használjunk exception-öket (pl. UnsupportedOperationException). Ez segít nem elfelejteni, hogy valamivel még adósok vagyunk. Felesleges a TODO, a tesztek miatt nagyon hamar kibukik, hogy hol az elfeledett kódrészlet.

    Komment = dokumentáció

    A komment egyfajta dokumentáció, ezáltal megvan az a hátulütője is, hogy könnyedén elavulttá válik. Míg egy programkódot (a kommenteket nem beleértve) könnyedén tudunk alakítani, refaktorálni, addig a természetes nyelven megírt kommentek ugyanúgy maradnak, ahogy eredetileg megírtuk őket. Még egy érv amellett, hogy a kommunikáció ne a kommenteken, hanem a működő kódon keresztül történjen.

    Konklúzió - kulcs gondolatok

    A kommentekkel általában a következők a problémák:

    • a fejlesztő nincs rákényszerítve arra, hogy "rendes" kódot írjon, ehelyett odarak pár kommentet a kódjához: a későbbiekben, ha változtatni kell (új funkció, hibajavítás) nehezebb a dolgunk,
    • széttagolják a kódot, ezáltal rontják az olvashatóságot (kerülgetni kell őket),
    • könnyedén elavulnak.

    Nem azt akarom kifejezni, hogy a kommentekre nincs szükség, vagy hogy arra törekedjünk, hogy minél kevesebb komment legyen a kódunkban. Inkább azt javaslom, hogy a cél az legyen, hogy olyan kódot írjunk, amelyhez nem szükséges vagy minimálisan kell csak kommentet írni

    Legyünk tudatosak, következetesek az elnevezésekben! Semmi ne maradjon rejtve, tegyük explicitté, adjunk nevet neki. (Tudok-e nevet adni neki egyáltalán? Ha nem, akkor valami gond van.)

    Valóban azt fejezi ki az osztály, mező, metódus, változó neve, amire használjuk? 

    Ha egy hibát keresünk, és ránézünk egy metódusra, megértjük-e a működését? Én meg fogom-e érteni később? Mások vajon megértik-e? Hogyan tudom refaktorálni, hogy tényleg érthető legyen?

    Nem lehet tökéletes receptet megfogalmazni. A cél viszont egyértelmű: legyen olvasható és karbantartható a kódbázis!

    2009. augusztus 13., csütörtök

    Folyamatos integráció

    [Update, 2009. 08. 14. A konkrét neveket kiszedtem a cikkből, nehogy problémát okozzon.]
    Immáron két és fél éve éneklek egy budapesti kamarakórusban basszistaként. A tavalyi évben felkérést kaptunk egy másik kórustól, hogy közösen adjunk elő egy 20. századi darabot.

    A darab egy másfél-kétórás oratórium. Az oratóriumok egyik közös jellemzője, hogy nagylétszámú zenekarra és kórusra íródtak, és résztvesz bennük jópár szólista énekes is. Kórus szempontból a zeneirodalom egyik legnehezebben tanulható művei közé tartozik a darab: jócskán tartalmaz atonális részeket; ha kocka akarok lenni, azt mondanám, hogy a hangok random követik egymást. Az egyszerre, a különböző teljesen független szólamok által megszólaltatott hangok egyfajta fanyar harmóniát alkotva mégis képesek megfesteni a drámai hatású bibliai jelenéseket.

    Számomra az egyik érdekes dolog a darabban az volt, ahogyan megtanultuk azt. A másik kórus, akiktől a felkérést kaptuk, az első pár hónapban tőlünk függetlenül tanulta a darabot. Az ő módszerük az volt, hogy a kórusból minden egyes szólam külön-külön próbált, ún. szólampróbákat tartott, mivel nagyon nehéz a darab. Minden szólam tanulja meg először rendesen a saját hangjait, és majd a végén összepróbálják az egészet.

    A mi módszerünk más volt. Az egyes próbák elején mi is szólampróbákat tartottunk, mert a darab megkívánta. A próbák második felében viszont a teljes kórus ún. tutti próbát tartott: összeénekeltük, amit a próba első felében a szólampróbán tanultunk. Sokat szenvedtünk és izzadtunk: próbáltuk a saját szólamunkat tartani, miközben a többi szólam énekelte a sajátját. Nagyon meredek volt, csak kapaszkodtunk, de egyre jobban ment.


    Amikor pár hónap múltán a két kórus találkozott a különbség döbbenetes volt. A másik kórus utálta a darabot, mi megszerettük. Ők nem tudták, mi tudtuk (kis túlzással persze, mert még tanuló fázisban voltunk). A hatalmas különbség oka egyszerűen az volt, hogy mi folyamatosan integráltuk a próbák első felén megszerzett szólamismeretet a teljes kórustudásba. A kusza, független szólamok hirtelen harmóniává alakultak, és ezáltal képesek voltunk magunknak megteremteni egy kontextust, amelyhez tudtunk alkalmazkodni, amelyben ésszerűen tudtunk dolgozni.

    A részek összegéből alkotott egész megismeréséből a következő próbára mindig új próbakoncepció alakult ki. A lényeg nem az volt, hogy egy-egy ember tökéletesen énekelte-e azt, ami a kottában le volt írva, hanem hogy együtt a csapat milyen hatást tudott kiváltani. Ha volt egy rész, ami nagyon gyengén szólt, azt a következő próbán elővettük, és azt csiszoltuk. Nem foglalkoztunk a nüansznyi dolgokkal. És ahogy így próbáltuk a darabot, mindig a legfontosabb részekre koncentrálva, a nüansznyi dolgok is beolajozódtak, eltűntek.

    Persze, emelett, hogy biztosan végezzünk a darabbal, szigorú időbeosztásunk volt. Megvolt, hogy hétről hétre milyen részekkel kell végezni, hogy a végére mindent megtanuljunk. A fennmaradó időket pedig az adott időszak anyagában a leggyengébben megszólaló részek finomítására áldoztuk.

    A másik kórusnak erre a felismerésre esélye sem volt. Tudom, mert néhány szólampróbájukon én is ott voltam. Egyszerűen utáltam, hogy hangról hangra kellett tökéletesen énekelni, és ha elcsesztünk valamit, kezdhettük előlről. Nem lehetett érezni, hogy hová tartunk, vagy hogy egyáltalán mit akarunk elénekelni. Beragadtunk. Nem volt ritmusa a próbának, nem volt iránya sem lokálisan, sem globálisan.

    Végül több, mint fél évig tanultuk a darabot. A két koncertet Ausztriában tartottuk, és nagyon jól sikerültek. Azóta volt egy másik koncertünk is idehaza. Mindenki a kórust dícsérte. Na, meg persze Csabát, a kórusvezetőnket...

    2009. augusztus 10., hétfő

    Domain Driven Design - 2. rész

    A cikksorozat első része egy rövid bevezetőt tartalmazott a DDD hátteréről, és arról mit várhatunk a DDD alkalmazásától. 

    Hogyan képzeljük el?

    Eric Evans könyve remek elméleti összefoglaló ugyan - rengeteg valós esettanulmánnyal és példával -, azonban mégis kevés konkrét kódrészletet és technológiai ajánlást ad. Igaz, ez a könyvet időtállóvá is teszi: nem avul el egykönnyen amiatt, hogy újabb és újabb technológiák jelennek meg. Mégis ahhoz, hogy elkezdjünk a DDD szellemében dolgozni, kézzelfogható dolgokhoz kell nyúlnunk.

    Az elmúlt évtizedekben egészen a mai napig is a relációs adatbáziskezelők (Relational Database Management System-ek, azaz RDBMS-ek) a legelterjedtebbek. Amikor egy RDBMS-ben tároljuk az adatainkat, az üzleti logikát többféleképpen is megírhatjuk:

    • A felhasználói felület közvetlenül az adatbázisba ír: egyszerű alkalmazásoknál ez a legkézenfekvőbb és legegyszerűbb módja az adatok tárolásának. Az általában nem túl képzett PHP-s "szakemberek" által gyártott szoftverektől kezdve, a Delphi-ben megírt sufni alkalmazásokon át még akár a .NET-es platformon megírt programokban is találkozhatunk ezzel a megvalósítási móddal (kulcsszó pl.: data binding). Az űrlapon beviszik az adatokat, az űrlap elvégez egy-két számítást, az eredményeket pedig közvetlenül vagy közvetve beírja az adatbázisba. A kereső felületek önmaguk tartalmazzák vagy állítják össze a lekérdezéshez használt SQL-t is.
    • Az üzleti logika az adatbázisban kerül megvalósításra: definiálják a táblákat, annak oszlopait, és tárolt eljárások hívásával valósítják meg az üzleti logikát. A tárolt eljárások végzik az adatok beszúrását, módósítását, törlését és lekérdezését, valamint a különféle számítási algoritmusokat is ezek tartalmazzák. Előnyük, hogy nagyon gyorsak (SQL-re optimalizáltak), hátrányuk viszont, hogy kevéssé rugalmasak: nincs vagy minimális a refaktorálás támogatása, a megvalósítás erősen kötődik az előre definiált 2D-s táblaszerkezetekhez, az IDE támogatás sem erős, és nehezen lehet bennük automatizált teszteseteket írni.
    • Az üzleti logika (a felhasználói felülettől leválasztva) teljes egészében objektum-orientáltan kerül megvalósításra (pl. JAVA-ban, .NET-ben), az RDBMS-t csupán adattárolónak használják. Hatalmas előnye tud lenni ennek a megközelítésnek, hogy a teljes üzleti logika egy platformon elérhető, a refaktorálás és az automatizált tesztesetek megírása könnyedén megvalósítható.

    A DDD alkalmazásához leginkább a harmadik megoldás passzol, azonban egy objektum-orientált kódban is többféleképpen valósítható meg az üzleti logika. A Martin Fowler által beazonosított minták a következők lehetnek:

    • Table Data Gateway: egy adatbázis táblához egy osztály tartozik a kódban (minden osztálynak csak egyetlen példánya van). Ennek az objektumnak a feladata az adott táblába a rekordok beszúrása, módosítása, törlése és lekérdezése (CRUD-műveletek, azaz: creates, reads, updates and deletes). Az objektum tartalmazza mindazon SQL-utasításokat, amelyek ezen műveletek végrehajtásához szükségesek. Pl. az ADO.NET data set-jei.
    • Row Data Gateway: itt egy adatbázis tábla egy konkrét rekordjához egy objektum tartozik, amelynek a feladata a CRUD műveletek biztosítása.
    • Active Record: itt is egy rekord egy objektum, viszont az objektum már üzleti logikát is megvalósít. Az objektum felelőssége önmagának a lementése, visszatöltése. Fowler szerint egyszerűbb domain model-lek esetén az Active Record még egy jó választás lehet, ahól jórészt csak CRUD-műveletek (creates, reads, updates and deletes) történnek. A gond vele, hogy túlságosan kötődik az adatbázistáblák szerkezetéhez.
    • Data Mapper: az objektumok perzisztálása az adatbázisban kvázi automatikusan történhet, amelyről egy object/relational mapper (vagy O/R mapper, pl. Hibernate) gondoskodik. Ez a DDD valódi technológiai támasza, ugyanis a komplex üzleti logikát megvalósító komplex objektumhierarchia (a domain model) könnyedén fejleszthető pl. Javaban, és mögötte az RDBMS-ek által "nyújtott" rugalmatlanság kevéssé korlátozó tényező. A hátránya a dolognak, hogy teljesítményben az így megírt rendszerek (még) alulmaradnak a hagyományos SQL-ben megírt üzleti logika rétegtől, valamint számos új problémával is szemben találjuk magunkat az elején (és közben is :)). Ha ilyenbe kezdenénk, akkor mindenképpen legyen a csapatban egy olyan ember, aki már írt alkalmazást O/R mapper segítségével.

    A domain model, az "alkalmazás szíve"

    A DDD szellemében megírt alkalmazások központi része a domain model. Csupán technológiailag tekintve a domain model nem más, mint az üzleti probléma objektum modellje, amely egyesíti mind a működést mind az adatokat, összekötött objektumok hálója (Fowler). Ha bonyolultak és állandóan változóak az üzleti szabályok (validáció, számítások, fogalmi rendszer), mindenképpen ezt a megközelítést célszerű alkalmazni (ha adottak ehhez a megfelelő technológiai feltételek is).

    Egy domain model esetében kiemelten fontos, hogy a működést az objektumok önmagukban valósítsák meg. A régi EJB 2-s világban alkalmazott módszer az volt, hogy az adatbázis séma alapján elkészítik az osztályokat, amik az adatokat tárolják (entitások), ezeket ellátják egy csomó set-terrel, get-terrel, és magát az üzleti logikát kívül ún. session bean-ekben írják meg (amik az entitások attribútumait lekérdezik, majd visszaírják a kívánt adatokat). Az ilyen "domain model"-t anemic (vérszegény) domain model-nek nevezték el, az üzleti logikát megvalósító állapotmentes metódusokat (EJB2-ben a session bean-ek metódusait) pedig Transaction Script-eknek hívják. Ennek az anti-mintának a hátránya az, hogy az üzleti logika procedurálisan készül el, és nem használja ki az objektum-orientált programozás előnyeit (egységbezárás, felelősség stb). 1 évvel ezelőtt egy microsoftos szakértő szájából is hallanom kellett olyat, hogy az "adatbázisból legeneráljuk az osztályokat"...

    Véleményem szerint a domain model azonban több objektumok hálójánál. Ez testesíti meg az üzleti problémáról szerzett ismereteinket, rendszerezi gondolatainkat és egy egységes modellbe foglalja. A modell színtiszta objektum-orientált kód, amely lehetővé teszi a modell egyszerű áttekintését, folyamatos formálását, ahogy egy agyagszobrász formálja a mesterművét. 

    (folyt.köv.)

    U.i. ...és ami kimaradt :)

    Köszönet Kristófnak, hogy 2 évvel ezelőtt megismertette velünk a DDD-t, és segített minket az elindulásban :)