MASARYKOVA UNIVERZITA FAKULTA INFORMATIKY
Domain-Driven Design BAKALÁŘSKÁ PRÁCE
David Ševčík
Brno, jaro 2009
ZADÁNÍ BAKALÁŘSKÉ PRÁCE
2
PROHLÁŠENÍ Prohlašuji, že tato práce je mým původním autorským dílem, které jsem vypracoval samostatně. Všechny zdroje, prameny a literaturu, které jsem při vypracování používal nebo z nich čerpal, v práci řádně cituji s uvedením úplného odkazu na příslušný zdroj.
Vedoucí práce: RNDr. Jaroslav Ráček, Ph.D. 3
SHRNUTÍ Domain-driven design je agilní přístup k analýze a návrhu softwaru, který byl vyvinut na základě zkušeností vývojářů s rozsáhlými softwarovými projekty. Klade důraz na pečlivou analýzu problémové domény a na komunikaci získaných znalostí napříč vývojovým týmem. Cílem této práce je představit nejdůležitější aspekty Domain-driven designu a prakticky jej předvést na případové studii návrhu jednoduchého CRM systému.
KLÍČOVÁ SLOVA analýza a návrh softwaru, agilní metodiky vývoje softwaru, Domain-driven design, Modeldriven design, refaktoring, Design by contract, domain-specific languages, doménově specifické jazyky
4
PODĚKOVÁNÍ Děkuji RNDr. Jaroslavu Ráčkovi, Ph.D. za poskytnutí dostatečného prostoru pro realizaci této práce a za cenné připomínky.
5
OBSAH Zadání bakalářské práce ............................................................................................................................................ 2 Prohlášení .......................................................................................................................................................................... 3 Shrnutí ................................................................................................................................................................................. 4 Klíčová slova ..................................................................................................................................................................... 4 Poděkování ........................................................................................................................................................................ 5 1
2
Úvod...................................................................................................................................................................8 1.1
Účel softwaru ....................................................................................................................................... 8
1.2
Vývoj softwaru..................................................................................................................................... 8
1.3
Cíl bakalářské práce ....................................................................................................................... 10
1.4
Poznámka k překladu termínů .................................................................................................. 10
Co je to Domain-driven design ............................................................................................................ 11 2.1
3
Efektivní komunikace.............................................................................................................................. 13 3.1
4
5
Doména a její model ....................................................................................................................... 11 Všímprostupující jazyk (Ubiquitous language) .................................................................. 13
Model-driven Design ............................................................................................................................... 15 4.1
Architektura vrstev ........................................................................................................................ 15
4.2
Objekty v MDD .................................................................................................................................. 16
4.2.1
Entity........................................................................................................................................... 16
4.2.2
Objekty reprezentující hodnotu (Value Objects) ...................................................... 16
4.2.3
Služby (Services).................................................................................................................... 17
4.2.4
Moduly ....................................................................................................................................... 17
4.2.5
Agregáty (Agregates) ........................................................................................................... 18
4.2.6
Továrny (Factories) .............................................................................................................. 18
4.2.7
Skladiště (Repositories)...................................................................................................... 19
Refaktoring modelu ................................................................................................................................. 20 5.1
Rozhraní vypovídající o záměru................................................................................................ 20
5.2
Metody bez vedlejších efektů ..................................................................................................... 21
5.3
Design podle kontraktu (Design by Contract)..................................................................... 22
5.4
Konceptuální kontury domény .................................................................................................. 23
5.5
Nezávislost objektů ........................................................................................................................ 24
5.6
Uzávěr operací .................................................................................................................................. 25
5.7
Deklarativní design......................................................................................................................... 25
5.7.1
Funkcionální a logické programovací jazyky ............................................................. 26 6
6
5.7.2
Externí doménově specifické jazyky ............................................................................. 26
5.7.3
Interní doménově specifické jazyky .............................................................................. 26
Případová studie – jednoduchý CRM systém ................................................................................ 28 6.1
Zadání problému ............................................................................................................................. 28
6.2
První verze sdíleného slovníku ................................................................................................. 28
6.3
Průzkum již hotových řešení ...................................................................................................... 29
6.4
Úvodní model .................................................................................................................................... 29
6.5
Modelovaní vazeb ........................................................................................................................... 32
6.6
Vize domény (Domain vision statement) .............................................................................. 34
6.7
Revize sdíleného slovníku ........................................................................................................... 34
6.8
Refaktoring modelu ........................................................................................................................ 36
6.9
Změněná vize domény .................................................................................................................. 38
6.10
Revize sdíleného slovníku ........................................................................................................... 40
6.11
Zhodnocení modelu ........................................................................................................................ 40
7
Závěr............................................................................................................................................................... 41
8
Použité zdroje ............................................................................................................................................. 42
7
1 ÚVOD 1.1 ÚČEL SOFTWARU Software je obvykle vyvíjen za účelem automatizace procesů nebo řešení úloh existujících v reálném světě. Měl by podpořit a zjednodušit práci jeho uživatelů. Pokud jsou uživatelské potřeby jednoduché a vývojový tým tvoří jeden nebo několik málo vývojářů, je cesta k funkční aplikace relativně přímočará a není třeba ji komplikovat sofistikovanými metodologiemi vývoje softwaru. Se vzrůstajícími požadavky a velikostí týmu se však cesta k výsledku začíná klikatit a šance, že uživatel dostane to, co opravdu potřebuje, klesá. Je tedy třeba nasadit techniky, které nám pomohou celý proces uřídit.
1.2 VÝVOJ SOFTWARU Cestu k funkčnímu softwaru můžeme vidět jako propojenou soustavu těchto kroků: 1. 2. 3. 4. 5.
sběr požadavků analýza a návrh implementace testovaní nasazení
O nezbytnosti těchto kroků není pochyb, je ale třeba promítnout tyto abstraktní pojmy do reálného světa. Od sedmdesátých let 20. století vznikají různé metodologie zabývající se tímto problémem. Každou metodologii můžeme vidět zjednodušeně jako soubor doporučení, jak výše zmíněné kroky propojit, jak nastavit priority v procesu vývoje a jak práci rozdělit časově a mezi jednotlivé členy týmu. Většina těchto metodologií je postavena na dvou základních modelech životního cyklu: vodopád a iterativní vývoj. Model vodopád jednoduše řadí jednotlivé kroky za sebe. Když je jedna fáze hotová, přistoupí se k následující. Výhodou je jeho jednoduchost, můžeme naplánovat budoucí kroky a v každé okamžiku víme, kde v procesu vývoje softwaru se právě nacházíme. Tento přístup ale není vhodný pro rozsáhlejší a dlouhodobější projekty, jelikož nereflektuje skutečnost, že v průběhu vývoje často dochází ke změnám nebo zpřesňování požadavků a některé skutečnosti se projeví až během pozdějších fází. V závislosti na tom, jak se nová skutečnost odchyluje od původních předpokladů, je někdy potřeba vrátit se až na začátek k analýze a zrevidovat všechny následující fáze.
8
OBRÁZEK 1.1: MODEL VODOPÁD
Model iterativního vývoje byl navržen, aby problémy modelu vodopád odstranil. Softwarový projekt je v rámci počátečního návrhu rozdělen na jednotlivé funkční celky a každý je poté vyvíjen odděleně v rámci jedné nebo více iterací. Problémy skryté za pozdějšími fázemi vývoje se tedy projeví dříve a můžeme na ně dříve reagovat. Objem nutných změn se tím zmenšuje a zkušenosti z vývoje jedné části aplikace můžeme následně aplikovat na části další. Nevýhodou tohoto modelu jsou vyšší nároky na řízení integrace jednotlivých částí, je tedy vhodné se více zaměřit na testování. Většina v současnosti využívaných metodologií vychází z tohoto modelu.
OBRÁZEK 1.2: MODEL ITERATIVNÍHO VÝVOJE
Můžeme se také setkat s modelem inkrementálního vývoje. Tento model je z velké části totožný s modelem iterativním, pouze počítá s kratšími vývojovými cykly a zdůrazňuje nutnost pravidelné integrace již hotových částí. Pojem metodologie, tak jak jsem ho použil v předchozích odstavcích, se vztahuje k procesu vývoje jako celku. Realita vývoje softwaru je ale bohatší, nalezneme zde metodologie, které řídí proces vývoje od začátku až do konce jako např. Unified Software Development Process, jiné se ale zabývají pouze některými vývojovými fázemi a mohou být kombinovány 9
s jinými metodikami jak např. Test-driven development. Některé jsou spíše abstraktními popisy, sloužící jako základ pro jiné metodologie jako např. Agile software development a z něj vycházejíci Extreme Programming. A některé se dokonce vyhýbají pojmu metodologie, jako i Domain-driven design, který sám sebe označuje jako soubor přístupů a doporučení. Je zaměřen primárně na analýzu a návrh, ale zároveň zdůrazňuje nutnost propojení této fáze se všemi ostatními.
1.3 CÍL BAKALÁŘSKÉ PRÁCE Cílem této práce je prakticky představit Domain-driven design přístup k vývoji softwaru a předvést jej na případové studii návrhu jednoduchého CRM systému. Pro příklady budu požívat upravených UML diagramů a kódu v jazyce Java.
1.4 POZNÁMKA K PŘEKLADU TERMÍNŮ Protože v době psaní této práce existuje k tématu Domain-driven design velmi malé množství materiálů v českém jazyce a česká terminologie není ustálená, přeložil jsem technické termíny z anglicky psaných zdrojů podle vlastního uvážení a anglické termíny uvádím při prvním použití v závorce. V případech, kdy český překlad zní uměle a znepřehledňuje okolní text, jsem se rozhodl ponechat anglický originál.
10
2 CO JE TO DOMAIN-DRIVEN DESIGN
OBRÁZEK 2.1: CO VŠE POJEM DOMAIN-DRIVEN DESIGN ZAHRNUJE
V roce 2003 vyšla na toto téma první kniha od Erica Evanse pod názvem Domain-Driven Design: Tackling Complexity in the Heart of Software. V jejím úvodu se můžeme dočíst, že Domain-driven design (dále jen DDD) je přístup k návrhu softwaru, který se postupně vyvinul v rámci komunity vývojářů používajících objektové technologie. Autor probírá tyto širokou komunitou prověřené postupy a připojuje vlastní zkušenosti z praxe. Slovy Erica Evanse je tedy DDD způsob myšlení a nastavení priorit, obojí zaměřené na zefektivnění vývoje softwarových projektů řešících komplikované domény. V kontextu vývojových fází softwaru je hlavní zaměření DDD na část analýzy a návrhu, ale zároveň zasahuje do fází sběru požadavků a implementace. Propojení těchto fází je podle DDD nutností k dosažení efektivního vývojového procesu, protože každá může odhalit detaily o doméně z jiné perspektivy. (1) avizuje, že DDD není svázáno s žádnou konkrétní metodologií, ale nejvíce můžeme z těchto přístupů vytěžit v rámci agilních metodologií vývoje. Pro aplikovatelnost DDD uvádí dvě podmínky: 1. iterativní přístup k vývoji 2. zapojení doménových expertů do procesu vývoje
2.1 DOMÉNA A JEJÍ MODEL Pod pojmem doména rozumíme oblast, kterou daný software řeší, např. bankovnictví, řízení letového provozu atd. Účelem softwaru je zefektivnit práci v této doméně. Aby toho bylo dosaženo, musí být software odrazem domény. To znamená, že musí být vybudován na hlavních konceptech a prvcích domény a vztazích mezi nimi. Doména ale existuje v reálném světě, takže ji není možné přímo přeložit do programového kódu. Proto potřebujeme vytvořit abstrakci domény – její model. Model domény nechápe DDD jako nějaký diagram, ale jako znalost o doméně, která je v tomto diagramu obsažena. Tato znalost může mít mnoho reprezentací: funkční specifi11
kace, UML diagramy, kód programu nebo testy. Z tohoto úhlu pohledu, lze podle (1) DDD chápat jako pět doporučení jak efektivně modelovat doménu: 1. Provázání modelu a implementace. Model bez možnosti implementace je v oblasti komerčního softwaru zbytečný a implementace, která není založena na modelu, snadno sklouzne k řešení problémů, které jsou mimo obor domény a opomenutí těch skutečně důležitých. 2. Model reflektuje jazyk doménových expertů. Aby model během celého vývoje odrážel skutečnosti dané domény, je třeba používat ve všech jeho reprezentacích shodný jazyk, který vychází z jazyka doménových expertů. 3. Model zachycuje znalosti. Objekty modelu nejsou pouze datových schématem, v modelu musíme zachytit také chování objektů a pravidla domény. 4. Destilace modelu. Model se během vývoje stále mění, integrujeme do něj nově objevené koncepty domény a odstraňuje nebo modifikujeme ty, které se ukážou jako irelevantní. 5. Komunikace a experimentování. Model je předmětem komunikace mezi doménovými experty a dalšími vývojáři. Tím, jak se jej snažíme popsat větami, se často objeví dosud skryté souvislosti. Prostřednictvím diskuzí a brainstormingů můžeme rychle procházet a posuzovat jeho různé variace.
12
3 EFEKTIVNÍ KOMUNIKACE Je třeba zajistit, aby se model a jeho změny v průběhu vývoje promítly do celého procesu, tedy aby se ke všem členům týmu dostaly informace, které potřebují. Efektivní komunikace je nástrojem, který může nasměrovat celý tým k požadovanému výsledku. Čím větší je vývojový tým, tím se stává tento nástroj důležitější. Členy týmu můžeme rozdělit na doménové experty, systémové analytiky a vývojáře. Zejména ve velkých vývojářských firmách je časté, že komunikace mezi skupinami probíhá pouze shora dolů bez zpětné vazby. To může být zdrojem problémů, např. analytici dodají přesný popis domény, osahující vazby, které ale není možné v nezměněné podobě reprezentovat pomocí daných softwarových nástrojů. Vývojáři je proto model upraven, aby bylo možné jej implementovat. Protože ale nekomunikují změnu zpátky analytikům, může se tímto zásahem do modelu ztratit nebo pozměnit část znalosti o doméně a výsledný produkt se odchýlí od úvodních požadavků. Na klíčových rozhodnutích by se podle DDD měly podílet všechny skupiny v rámci vývojového procesu. To znamená neoddělovat striktně vývojáře od systémových analytiků a doménových expertů. Ať už je dokument se závěry analýzy proveden sebelépe, vždy budou existovat detaily, které není možné srozumitelně vyjádřit pomocí diagramů nebo textu. Tyto detaily se vyjasní jenom díky diskuzi a spolupráci skupin na klíčových částech modelu.
3.1 VŠÍMPROSTUPUJÍCÍ JAZYK (UBIQUITOUS LANGUAGE) Každá z výše zmíněných skupin používá pro komunikaci uvnitř této skupiny svůj vlastní slovník. Rozdílné skupiny často používají stejných výrazů pro popis odlišných věcí a různých výrazů pro popis stejných věcí. To je vážným problémem v komunikaci napříč celým týmem. Zvláště markantní je to v komunikaci mezi doménovými experty a ostatními skupinami. Doménoví experti ve většině případů nejsou informatici, ale např. bankéři pokud vyvíjíme bankovní systém. DDD proto zavádí pojem všímprostupující jazyk (ubiquitous language) jako prostředek, který prováže jednotlivé reprezentace modelu a umožní model komunikovat mezi všemi skupinami. Všímprostupující jazyk můžeme chápat jako sdílený slovník, který obsahující všechny termíny vztahující se doméně, pro kterou je vyvíjený software určen. DDD neříká nic o tom, jakou formu by tento slovník měl mít, ponechává na vývojářích, jestli má být slovník zachycen v písemné formě, nebo jestli postačí ústní dohoda. Termíny a jejich definice jsou záležitostí konsenzu mezi jednotlivými skupinami. Jejich zdrojem jsou nejčastěji doménoví experti nebo odborná literatura z oboru domény. Úlohou analytiků a vývojářů je slovník upravit do podoby, která bude srozumitelná všem a bude rámcově implementovatelná. Všechny úpravy je třeba dělat společně s doménovými experty, nebo si je alespoň nechat odsouhlasit. Doménoví experti tedy garantují, že představa o doméně odpovídá realitě, zatímco analytici a vývojáři garantují její proveditelnost. 13
Sdílený slovník se vyvíjí iterativně spolu s modelem a měl by s ním korespondovat. Pokud nějaký výraz často používají doménoví experti, ale v modelu se nevyskytuje, je to signál, že v modelu možná chybí nebo je skrytá důležitá vlastnost domény. Naopak, pokud se v modelu vyskytuje nějaký termín, který se neobjevuje ve sdíleném slovníku, měl by být jeho význam pro doménu prodiskutován s doménovými experty. Nejlepším podkladem pro diskuzi o modelu jsou jednoduché diagramy. DDD se snaží vyvrátit široce přijímanou domněnku, že doménoví experti diagramům nerozumí. Pravdou je, že doménoví experti nerozumí komplexním UML diagramům. Řešením je tedy abstrakce klíčových objektů, které tvoří hlavní doménu řešeného problému a jejich prezentace pomocí jednoduchých neformálních diagramů spolu s komentářem. Sdílený slovník by měl být reflektován také v kódu a dokumentaci a naopak. Tím je zajištěna konzistence jednotlivých reprezentací modelu. Pokud je z implementačního důvodů nutné změnit nebo vnést do kódu nový termín, který není čistě technického rázu, ale reprezentuje element domény, je třeba jej zohlednit v modelu a také ve sdíleném slovníku.
14
4 MODEL-DRIVEN DESIGN Model-driven design (dále jen MDD) je soubor doporučení a vzorů, které umožňují model vzniklý v hlavách členů vývojového týmu formalizovat. Umožňuje tak pohled na model z vyšší úrovně a podporuje další diskuzi. Účelem vzorů je zabezpečit, aby bylo možné model domény jednoduše přeložit z jedné reprezentace do jiné, zejména tedy do programového kódu. Pro zachycení modelu obvykle používáme textové popisy, diagramy, samotný programový kód a testy. Všechny reprezentace jsou více či méně abstraktní pohledy na model domény, každý z nich nám může pomoci nalézt doposud skrytou vlastnost domény, nebo vyjasnit již známou vlastnost, které ale nebyla pochopena správně. Dohromady poskytují celkový obrázek o problémové doméně. Změny v jedné reprezentaci je nutné promítnout do všech ostatních, jinak vzniknou dva oddělené modely a tím pádem potenciál pro špatné pochopení mezi jednotlivými členy týmu. Přehledně napsaný programový kód a testy jsou nejvíce konkrétní a nejobsáhlejší reprezentací modelu, není tedy třeba suplovat jejich roli pomocí komplexních UML diagramů. MDD používá UML diagramů1 hlavně jako prostředku pro komunikaci znalostí o doméně mezi členy vývojového týmu. UML diagramy by měli být tak jednoduché, aby bylo možné nad nimi diskutovat také s doménovými experty.
4.1 ARCHITEKTURA VRSTEV Rozdělení aplikace do vrstev nám zajistí lepší přehled nad řešeným problémem a usnadní změny. Obvykle můžeme rozdělit aplikaci na tyto vrstvy: 1. Prezentační vrstva (uživatelské rozhraní) Prezentuje informace uživateli a interpretuje jeho povely. 2. Aplikační vrstva Koordinuje činnosti aplikace. Neobsahuje business logiku a neudržuje stav business objektů. Může ale držet stav úkolů na úrovni aplikace. 3. Doménová vrstva Obsahuje znalost o doméně ve formě objektů a jejich stavů Nejdůležitější vrstva aplikace, na níž se celý DDD soustředí. Nestará se o perzistenci objektů. 4. Vrstva infrastruktury Funguje jako podpora pro ostatní vrstvy. Poskytuje prostředky pro komunikaci mezi vrstvami a perzistenci business objektů. Každá vrstva může přímo komunikovat pouze s vrstvami nižšími. Komunikace opačným směrem může být řešena např. pomocí zpětného volání. Pokud chceme využívat tento přístup, musíme zvolit vhodné vývojové prostředky. Především není možné jej kombinovat s tzv. Smart UI, kdy používáme vizuálního návrháře užiZdroje, ze kterých čerpám, používají v příkladech převážně UML diagramy tříd, v několika případech také stavové a sekvenční diagramy 1
15
vatelského rozhraní a přiřazujeme jednotlivým ovládacím prvkům chování v závislosti na událostech. Tím je doménový model rozeset napříč celou aplikací a to znesnadňuje provádění změn jak v modelu, tak v uživatelském rozraní. Striktní rozdělení do vrstev sice ze začátku vyžaduje větší úsilí, ale poskytne nám základní strukturu aplikace, v rámci které můžeme budovat doménový model.
4.2 OBJEKTY V MDD Když se během analýzy a návrhu vynořují nové objekty doménové vrstvy je užitečné je nějakým způsobem kategorizovat. MDD proto poskytuje sadu vzorů, které do jisté míry určují chování objektů a způsob zacházení s nimi. Tento proces je iterativní, s prohlubováním znalostí o doméně objekty rozdělujeme, slučujeme, přeskupujeme a spolu s tím měníme také vzory, které na ně aplikujeme. V příkladech používám UML přizpůsobeného pro účel MDD pomocí stereotypů.
4.2.1 ENTITY Entitou je každý objekt, u něhož je důležitější jeho identita než jeho vlastnosti. Jsou to takové objekty, které chceme jednoznačně identifikovat bez ohledu na, to v jaké stavu se zrovna nacházejí, např. osoba, konto, projekt. Práce s entitami je náročnější jak po stránce návrhové, tak po stránce technické, takže je výhodné navrhovat objekty jako entity jenom pokud je to nezbytně nutné a na ostatní objekty aplikovat následující vzory.
OBRÁZEK 4.1: PŘÍKLAD ENTITY
4.2.2 OBJEKTY REPREZENTUJÍCÍ HODNOTU (VALUE OBJECTS) V kontrastu k entitám jsou objekty reprezentující hodnotu takové objekty, u kterých nás zajímají jejich vlastnosti, nezajímá nás jejich identita ani stav. Mohou být libovolně vytvářeny a rušeny bez nutnosti o tom informovat zbytek systému. MDD důrazně doporučuje, aby hodnotové objekty byly neměnné, tj. vytvořili se na základě argumentů konstruktoru a pokud je potřeba je změnit, objekt se jednoduše zahodí a vytvoří se nový. Na úrovni infrastruktury to umožňuje sdílení těchto objektů.
OBRÁZEK 4.2: PŘÍKLAD OBJEKTU REPREZENTUJÍCÍHO HODNOTU
16
4.2.3 SLUŽBY (SERVICES) Služby jsou rozhranní poskytující operace. Tyto operace můžeme identifikovat jako slovesa ve sdíleném slovníku, která se nedají jednoznačně přiřadit k žádnému podstatnému jménu a není tedy vhodné je modelovat jako metody entity nebo hodnotového objektu. Provádějí často operace nad více objekty různých typů a jsou bezstavové. Pro službu bychom se měli snažit najít pojmenování ve všímprostupujícím jazyce. U služeb je třeba se vždy zamyslet, jestli opravdu patří do doménové vrstvy nebo by měly být spíše ve vrstvě aplikační nebo infrastruktury, a naopak, jestli některé služby v těchto vrstvách jsou pevně spjaty s řešenou doménou a neměly by tedy být přesunuty do doménové vrstvy.
OBRÁZEK 4.3: PŘÍKLAD SLUŽBY
4.2.4 MODULY Moduly složí k organizaci objektů takovým způsobem, aby to vedlo k snížení komplexity problému a zvýšení koheze modelu. Kohezi můžeme rozdělit na komunikační a funkcionální. Komunikační koheze znamená, že části modulu operují nad stejnými daty a je mezi nimi tedy silná provázanost. Funkcionální koheze znamená, že všechny části modulu spolupracují na řešení dobře definovaného úkolu. Funkcionální koheze je lepší, protože nám umožňuje explicitně vyjádřit účel domény a o to jde v DDD především. Proces vedoucí k dosažení tohoto typu koheze nás nutí k hlubšímu pochopení problémové domény. Pojmenování modulu by mělo být zvoleno tak, aby jasně vyjadřovalo jeho účel. Pokud to jde, snažíme se pojmenování najít ve všímprostupujícím jazyce.
OBRÁZEK 4.4: PŘIKLAD MODULŮ
17
4.2.5 AGREGÁTY (AGREGATES) Účelem agregátu je snížit počet vazeb mezi objekty. Agregát je skupina asociovaných objektů, na které se můžeme dívat jako na jednu jednotku. Jeden objekt v agregátu je kořenem, který je jediným rozhraním pro komunikaci s agregátem zvenčí. Objektu uvnitř agregátu mohou mít libovolné vzájemné vazby, ale nemohou mít žádnou vazbu s objekty mimo agregát. Přístup k těmto objektům je možný pouze prostřednictvím metod kořenového objektu, mimo agregát by se měly předávat pouze kopie těchto objektů. Pokud jsou objekty entity, je jejich identita lokální v rámci agregátu. Tento rozdělení nám umožní lepší kontrolu nad invarianty, protože povinnost za jejich dodržení leží pouze na kořenu.
OBRÁZEK 4.5: PŘÍKLAD AGREGÁTU
4.2.6 TOVÁRNY (FACTORIES) Továrny zapouzdřují proces konstrukce jiného objektu. Používá se v případech, kdy konstrukce objektu přesahuje obor odpovědnosti objektu samotného, tj. když je ke konstrukci třeba přístupu k dalším zdrojům, nebo se současně vytváří více objektů, nejčastěji v agregátu. Jako továrna může sloužit metoda nějakého objektu (odpovídá návrhovému vzoru Method Factory2), nejčastěji kořene agregátu, který má zodpovědnost za konstrukci objektů uvnitř agregátu. Tato metoda může vracet kopii vytvořeného objektu.
OBRÁZEK 4.6: PŘÍKLAD TOVÁRNY JAKO METODA KOŘENE AGREGÁTU
Pokud jde o tvorbu objektu mimo agregát, nebo je konstrukční metoda příliš složitá, je vhodné použití továrny jako samostatného objektu.
2
Popis na adrese
18
OBRÁZEK 4.7: PŘÍKLAD TOVÁRNY JAKO SAMOSTATNÉHO OBJEKTU
Při rozhodování, jestli odpovědnost za konstrukci objektu přesuneme na továrnu, bychom měli taky vzít na vědomí fakt, že tím obvykle porušujeme zapouzdřenou daného objektu, protože továrna potřebuje přístup k jeho privátním proměnným.
4.2.7 SKLADIŠTĚ (REPOSITORIES) Skladiště zapouzdřují logiku nutnou k získání reference na objekt. Nejčastěji se používá jako rozhraní k nějakému perzistentnímu úložišti. Stará se o přidávání, aktualizaci, mazání a vyhledávání entit. Odstiňuje tak doménovou vrstvu od vrstvy infrastruktury. Často modelujeme skladiště jako nadstavbu ORM3 frameworku.
OBRÁZEK 4.8: PŘIKLAD SKLADIŠTĚ
3
Object-relational mapping – mapování dat z relační databáze na atributy objektů
19
5 REFAKTORING MODELU Pokud již máme hotový základní model podle vzoru MDD, můžeme přistoupit k jeho refaktoringu, který dále provází celý vývojový proces. DDD zavádí sadu doporučení co a jak refaktorovat. Refaktoring modelu můžeme chápat jako nadřazený technickému refaktoringu kódu (tedy tomu, co je obecně pod pojmem refaktoring chápáno), ačkoliv se s ním často překrývá a zahrnuje také změny v kódu, jeho použití vychází ze znalostí domény a má vyústit v hlubší vhled do její problematiky. Doporučení pro tento druh refaktoringu jsou obtížněji formálně definovatelná než ta pro technický refaktoring. Následující vzory podle (1) ilustrují obecný styl designu a cestu jak o něm uvažovat. Mají učinit software pochopitelnější, předvídatelnější a komunikativnější, a prostřednictvím toho také zefektivnit abstrakci a zapouzdření. Nepřinášejí univerzálně použitelná řešení, ale spíše směřují naši pozornost na případy, které se mohou při vývoji modelu vyskytnout. Při hledání konkrétních řešení nám nejlépe poslouží zkušenosti s podobnými projekty a často také principy abstrahované z konkrétnějších pravidel technického refaktoringu. Myšlenkou skrytou za všemi doporučenými postupy je snížit informační zahlcení vývojářů a odrýt doposud skryté souvislosti tím, že izolují klíčové prvky domény do snadno pochopitelných struktur. Model je díky tomu jednodušeji implementovatelný a výsledný software lépe udržovatelný a rozšířitelný. Pokud již mámě hotový nějaký kód, reflektujeme výsledky refaktoringu přímo v něm s příslušnými úpravami v diagramech. Pokud dané části systému zatím nejsou implementovány, jsou nejlepší způsobem pro zachycení podrobností jednoduché UML digramy popisující výřez systému spolu s příklady kódu a komentáři. DDD nedoporučuje snažit se vše zachytit jedním UML diagramem tříd, který by se tak stal nepřehledný a obtížně udržovatelný. Následuje popis jednotlivých doporučení.
5.1 ROZHRANÍ VYPOVÍDAJÍCÍ O ZÁMĚRU Názvy modul, tříd a rozhraní metod by měli vystihovat jejich záměr. Tak, aby je další vývojáři mohli použít ve svém kódu, aniž by museli procházet jejich implementaci. Zároveň to usnadní refaktoring daných objektů. Jako praktický přístup jak rozhraní vypovídajících o záměru dosáhnout doporučuje DDD simulovat použití objektů v rámci jednotkových a integračních testů ještě předtím, než jsou objekty samy vytvořeny.4 Příklad: Jako přiklad použijeme následující třídu. Její význam nemusí být pro vývojáře, který toto rozhraní vidí poprvé ihned jasný.
Tento přístup se nazývá Test-driven development, více informací na . Na tomto přístupu dále staví Benaviordriven development, který umožňuje explicitněji popsat požadované budoucí chování rozhraní, více na . 4
20
class AccountTools { List transactionHistory(Account account, Date from, Date to) { // implementation } }
Při refaktoringu přejmenujeme jak třídu, tak její metodu a zjednodušíme její vstupní parametry. class TransactionRepository { List findTransactions(TransactionCriteria criteria) { // implementation } } class TransactionCriteria { void setAccount(Account account) { ... } void setFromDate(Date date) { ... } void setToDate(Date date) { ... } }
Rozhraní po refaktoringu jasně vyjadřují svůj význam a jsou navíc snadno rozšířitelné.
5.2 METODY BEZ VEDLEJŠÍCH EFEKTŮ Nejen že z rozhraní metody a její dokumentace by mělo být zřejmé, jaké chování od ní můžeme očekávat, ale zároveň by metoda neměla dělat nic navíc. Metody tříd můžeme rozdělit na funkce, které vracejí hodnotu a procedury které mění stav aplikace. DDD doporučuje držet se striktně tohoto rozdělení, tak aby žádné funkce neměnili stav aplikace a aby procedury nevracely žádné hodnoty. Maximum logiky aplikace bychom se měli snažit vyjádřit pomocí funkcí a zbylé procedury by měly zůstat co nejjednodušší. Dalším krokem je přesunutí funkcí s komplexní logikou z entit do objektů reprezentujících hodnotu. Tato izolace se pozitivně projeví při testování a odhalování chyb. Můžeme testovat logiku aplikace bez toho, abychom museli simulovat stavy aplikace. Počet metod entit i jejich komplexnost se sníží a umožní tak jednodušší inspekci. Příklad: Představme si, že bankovní systém v rámci správy účtů poskytuje funkcionalitu na výpočet poplatku za vedení účtu, jehož výše se odvíjí od služeb, které má zákazník aktivovány. Tato funkcionalita může být implementována v rámci třídy účet:
21
class Account { Money balance; Set services; ... void addService(AccountService service) { ... } void removeService(AccountService service) { ... } ... void subtractFee() { // spočítej poplatky za každou službu a odečti celkovou sumu z účtu } ... }
Při refaktoringu delegujeme správu služeb a výpočet poplatku na neměnný objekt reprezentující hodnotu AccountServiceSet. class AccountServiceSet { Set services; ... AccountServiceSet addService(AccountService) { ... } AccountServiceSet removeService(AccountService) { ... } Money totalFee() { // vypočítej poplatek za všechny služby } }
To vede ke zjednodušení metod třídy Account které mění stav objektu. Na příkladu je to patrné hlavně u metody subtractFee. class Account { Money balance; AccountServiceSet serviceSet; ... void addService(AccountService) { serviceSet = serviceSet.addService(service); } void removeService(AccountService) { serviceSet = serviceSet.removeService(service) } ... void subtractFee() { balance = balance.subtract(serviceSet.totalFee()); } ... }
5.3 DESIGN PODLE KONTRAKTU (DESIGN BY CONTRACT) Design by Contract (dále jen DbC) umožňuje formálně definovat spolupráci mezi jednotlivými komponentami softwaru. Toto doporučení můžeme chápat jako jakousi nadstavbu prvního doporučení - rozhraní vypovídající o záměru. Podle (2) je DbC přístup k návrhu softwarového systému založený na metafoře z obchodního prostředí, kde se klient a dodavatel shodnou na kontraktu, který definuje, jaké služby a za jakých podmínek dodavatel klientovi poskytne. Samotné formulování 22
podmínek vede vývojáře ke kvalitnějšímu a robustnějšímu kódu. Zároveň jim poskytne dostatek informací o rozhraních již implementovaných částí systému bez toho, aby museli studovat jejich implementaci. Rozhraní komponenty poskytující službu deklaruje: 1. vstupní podmínky – datové typy vstupních proměnných a omezující podmínky na jejich hodnoty 2. invarianty – podmínky, které musí být splněné v rámci daného rozsahu (metoda, třída, modul atd.) 3. výstupní podmínky – definují datový typ výstupních proměnným a omezující podmínky na jejich hodnoty Tento přístup byl zaveden s programovacím jazykem Eiffel, kde tvoří integrální součást samotného jazyka. Pro většinu dnes rozšířených jazyků existují knihovny, které umožňují DbC použít. Podmínky DbC jsou za běhu programu kontrolovány a pokud dojde k jejich porušení je program přerušen. Příklad: Použití nástroje Contract4J5 pro jazyk Java. Podmínky zde zapisujeme pomocí anotací a exportují se do generované dokumentace. Příklad převzat z dokumentace ke Contract4J (3). @Contract public class MyClass { @Invar ("name != null") private String name; @Pre ("n != null") public void setName (String n) { name = n; } @Post ("$return != null") public String getName () { return name; } @Pre ("n > 10 && s != null") @Post ("$return != null") public String doIt (int n, String s) { ... } ... }
Při rozhodování zda použít formální DbC nebo vystačit s méně formálními doporučeními, jako rozhraní vypovídající o záměru bychom měli vzít v úvahu velikost projektu, počet vývojářů a nároky na kvalitu.
5.4 KONCEPTUÁLNÍ KONTURY DOMÉNY Objekty modelu (třídy, moduly atd.) by měly kopírovat konceptuální kontury domény. Během vývoje bychom si měli stále klást otázku, jestli tomu tak je. Každá doména je ale odlišná a proto je nemožné sestavit konkrétní doporučení, podle kterého bychom mohli postupovat. Nejvíce nám v této oblasti mohou pomoci zkušenosti s podobnými projekty.
55
Dostupný na adrese .
23
Antipříklad: Rozdělení domény na moduly, které nereflektují konceptuální kontury domény, ale spíše použitý framework.
OBRÁZEK 5.1: PŘÍKLAD NEKONCEPTUÁLNÍHO ROZDĚLENÍ DOMÉNY DO MODULŮ
5.5 NEZÁVISLOST OBJEKTŮ Objekty reprezentující fundamentální principy domény by měly mít minimální počet závislostí na dalších objektech, ideálně žádnou. DDD chápe závislost z pohledu vývojáře používající daný objekt ve svém kódu. Pokud je jeden objekt (třída, modul atd.) závislý na jiné objektu, musí vývojář, který jej chce použít, pochopit chování jak daného objektu, tak objektu na kterém tento objekt závisí. Závislost vzniká použitím objektu v rámci vstupů a výstupů funkcí a dědičnosti. Nevzniká, pokud je použití objektu závislosti kompletně zapouzdřeno a neprojevuje se na rozhraní. To je odlišnost od technického refaktoringu kódu, který se nesoustředí na pohled programátora zvenčí.6 Čím delší je řetězec závislostí, tím větší část systému je třeba prostudovat předtím, než jej lze použít. Příklad: Entita Customer drží reference na všechny entity Account reprezentující účty zákazníka, je tedy na objektu Account závislá.
OBRÁZEK 5.2: ENTITA CUSTOMER ZÁVISÍ NA ENTITĚ ACCOUNT
Odstranění závislosti mezi entitami provedeme aplikací vzoru MDD skladiště.
V rámci technického refaktoringu se závislosti mezi objekty nazývají coupling. Více o tomto tématu lze nalézt na . 6
24
OBRÁZEK 5.3: ZÁVISLOST MEZI ENTITAMI BYLA ODSTRANĚNA
5.6 UZÁVĚR OPERACÍ Tento koncept je vypůjčený z matematiky a říká nám, že typ vstupních proměnných funkce je shodný s typem výstupní proměnné. To je výhodné při návrhu objektů domény, protože díky tomu snížíme počet závislostí na jiných objektech a zmenšuje se tak informační zahlcenost vývojáře. Tento přístup je nejčastěji aplikovatelný na objekty reprezentující hodnotu, kde se nemusíme zabývat jejich stavem a jednoduše vrátíme jako výsledek metody tohoto objektu nový objekt reprezentující hodnotu. Pokud není možné splnit všechny podmínky uzávěru, snažíme se alespoň navrhnout metodu objektu tak, aby vracela objekt stejného typu a její argumenty byly primitivních typů (integer, string atd.), nebo naopak. Primitivní typy totiž nevnášejí do modelu nové závislosti. Příklad: Ideálním příkladem uzávěru operací je návrhový vzor CompositeSpecification podle (4). public interface CompositeSpecification { boolean isSatisfiedBy(Object candidate); CompositeSpecification and(CompositeSpecification spec); CompositeSpecification or(CompositeSpecification spec); CompositeSpecification not(); }
Tento vzor slouží pro definování složitých podmínek business logiky. Jeho metody and a or kombinují podmínky definované samotným objektem s podmínkami objektu předaného jako argument a vrací nový objekt CompositeSpecification. Not vrací negaci dané specifikace.
5.7 DEKLARATIVNÍ DESIGN Deklarativní design znamená psát program jako formu spustitelné specifikace. Popisujeme tedy, co od softwaru očekáváme a ne sled kroků, jak toho dosáhnout. V ideálním případě se tak vyhneme psaní množství obslužného kódu, který nemá přímou souvislost s řešením problému domény. Podle (1) je toto zlatým grálem DDD, kterého je těžké plně dosáhnout, můžeme se mu ale přiblížit. K tomu využíváme buď mechanismů programovacího jazyka, nebo generátorů kódu. S generátory kódu bývají obvykle problémy při inte-
25
graci s ručně napsaným kódem, pokud se nespokojíme se základními konstrukcemi, které generátor vytváří. Pokud se rozhodneme pro deklarativní design za pomocí některého programovacího jazyku, máme zde široké pole možností. Z toho úhlu můžeme rozdělit jazyky na (zde vycházím z (5) a (6)): 1. funkcionální a logické programovací jazyky 2. externí doménově specifické jazyky 3. interní doménově specifické jazyky
5.7.1 FUNKCIONÁLNÍ A LOGICKÉ PROGRAMOVACÍ JAZYKY Tyto jazyky můžeme použít, pokud problémová doména nebo její podstatná část odpovídá charakteru jejich paradigmat. Tedy pokud řešíme matematické problémy (vyhodnocování grafů, trajektorií, statistické výpočty atd.) nebo domény založené na vyhodnocování složitých podmínek (znalostní systémy, AI atd.). Jejich výhodami je vysoká vyjadřovací schopnost v rámci těchto typů domén a formálnost výsledných programů. Důležitými aspekty při rozhodování, zda je použít jsou náklady na zavedení jazyka (školení týmu atd.), případně pracnost propojení s částmi systému napsaných v jiném jazyku. Příklady těchto jazyků jsou Erlang, Caml, Haskell, Prolog atd.
5.7.2 EXTERNÍ DOMÉNOVĚ SPECIFICKÉ JAZYKY Externí doménově specifický jazyk (dále jen EDSJ) je např. konfigurační soubor, SQL SELECT příkaz nebo regulární výraz. Mají obvykle velmi omezené pole působnosti a řeší specifické úkoly v rámci většího systému. Pro své spuštěni potřebují softwarovou komponentu, která slouží jako jejich interpret. Vytvoření vlastního EDSJ tedy spočívá v návrhu syntaxe a sémantiky, a naprogramování interpretu. Nejjednodušší je založit takový jazyk na XML, protože existuje mnoho nástrojů pro jeho zpracování. Nevýhodou XML může být jeho „upovídanost“, která snižuje přehlednost a znepříjemňuje ruční editaci. Jelikož je funkčnost EDSJ omezená, nenese s sebou velké náklady na školení vývojářů a umožňuje tak delegovat tvorbu v rámci nich na týmy, které se zabývají např. konfigurací a nasazováním softwaru.
5.7.3 INTERNÍ DOMÉNOVĚ SPECIFICKÉ JAZYKY Interní doménově specifický jazyk (dále jen IDSJ) je vytvořen v obecném programovacím jazyku a používá jeho konstrukce. Je tedy sám vykonatelný a nepotřebuje interpretovat, jako to bylo v případě EDSJ. Obecně se dá říct, že IDSJ je možné vytvořit v jakémkoliv programovacím jazyku podporujícím reflexi. Podle (7) je reflexe vlastnost jazyku, díky níž může program zjistit a změnit svou strukturu a chování. Tuto vlastnost má většina dnes rozšířených jazyků jako Java, C#, Perl, Python, Ruby, Groovy, atd. Rozdíl je ale v náročnosti tvorby a přehlednosti výsledného IDSJ. V tomto mají výhodu jazyky, které mají volnější syntaxi, bez statické typového systému s prvky funkcionálních jazyků, např. Ruby nebo Groovy.
26
Přiklad: Reálným příkladem použití IDSJ v jazyce Ruby je framework pro Behaviourdriven development - RSpec7, který slouží k popisu chování programových tříd napsaných v Ruby. describe Account do it "should raise OutOfMoneyException when tried to withdraw over the \ current ballance” do account = Account.new(:ballance => 500) lambda {account.withdraw(600)}.should raise_error(OutOfMoneyException) end end
7
Dostupný na adrese .
27
6 PŘÍPADOVÁ STUDIE – JEDNODUCHÝ CRM SYSTÉM V této případové studii se snažím zachytit iterativní průběh návrhu jednoduchého CRM systému s aplikací přístupu DDD.
6.1 ZADÁNÍ PROBLÉMU Navrhnout model CRM pro fiktivní firmu ThermoRex která se zabývá energetickými službami, zejména projekcí a dodávkou systému vytápění a izolace průmyslových hal. Požadavky na CRM jsou následující:
umožnit centrální správu kontaktů sloužit jako e-mailový klient sloužit jako plánovací kalendář a úkolovník sloužit jako centrální úložiště smluv a dalších dokumentů evidovat obchodní příležitosti a nabídky služeb zákazníkům evidovat průběh komunikace se zákazníkem (e-maily, záznamy telefonátů, výsledky schůzek)
6.2 PRVNÍ VERZE SDÍLENÉHO SLOVNÍKU Ve funkčních požadavcích jsem identifikoval termíny, které budou součástí sdíleného slovníku. V první fázi jsem se soustředil pouze na podstatná jména.
kontakt e-mailový klient kalendář úkol smlouva dokument příležitost nabídka služba zákazník komunikace e-mail telefonát schůzka
Ze seznamu jsem vyřadil ty termíny, které jsou za hranicemi problémové domény a které vytvářený software nebude řešit. Zde je to termín služba.
28
6.3 PRŮZKUM JIŽ HOTOVÝCH ŘEŠENÍ Pro získání lepší představy o problematice CRM systému jsem vyzkoušel dva produkty, které poskytují zkušební verzi zdarma: Salesforce.com8 a Microsoft Dynamic CRM9. Obě tyto řešení fungují jako webové aplikace. Doplnil jsem sdílený slovník o výrazy, které se v těchto produktech vyskytují a které potencionálně popisují potřeby zákazníka, ale nejsou uvedené v úvodních požadavcích. Zároveň jsem doplnil anglické překlady těchto termínů. V modelu a v kódu budu déle používat tyto anglické ekvivalenty.
kontakt (contact) e-mailový klient (e-mail client) kalendář (calendar) úkol (task) smlouva (contract) dokument (document) příležitost (opportunity) nabídka (quote) zákazník (customer) komunikace (communication) e-mail telefonát (phone call) schůzka (meeting) objednávka (order) faktura (invoice) fax dopis (letter) uživatel (user) obchodní vztah (account) zájemce (lead) dodavatel (supplier) konkurent (competitor)
Přidané termíny jsem probral se zadavatelem. Ten je odsouhlasil jako relevantní pro problémovou doménu s výjimkou termínu konkurent, protože nemá potřebu jejich evidence.
6.4 ÚVODNÍ MODEL Termíny ze sdíleného slovníku jsem převedl do formy doménových objektů. Objekty jsem rozdělil na ty, které patří do hlavní poddomény (anglicky označované jako core) a ty, které patří do generických poddomén, viz Obrázek 6.1.
Informace a zařízení zkušebního konta . Informace o produktu naleznete na , zkušební konto lze zařídit na . 8 9
29
OBRÁZEK 6.1: ROZDĚLENÍ OBJEKTŮ DO PODDOMÉN
Generické poddomény nejsou specifické pro doménu CRM systému a mohou být řešeny pomocí již existujících komponent nebo spravovány externím systémem. V této práci se těmito poddoménami nebudu dál zabývat, vypustil jsem je proto i ze sdíleného slovníku. Výjimkou je objekt User, který se objevuje často ve vztahu k dalším objektům, proto jej ve slovníku zachovám. Zároveň doplním k termínům jejich definice. V každé definici se snažím popsat proč je daný objekt v systému evidován. Pokud je toto odůvodnění obtížné, je to signál, že daný objekt je možná mimo hranice domény.
Objekt kontakt (contact) reprezentuje soubor informací o osobě která je nebo může být účastníkem aktivit evidovaných systémem, evidovaný za účelem navázání komunikace s danou osobou. Objekt obchodní vztah (account) reprezentuje soubor informací o subjektu který je nebo může být účastníkem aktivit evidovaných systémem, uchovávaný za účelem navázání komunikace s danou osobou. Objekt zájemce (lead) reprezentuje soubor informací o subjektu, který má potenciál být účastníkem aktivit evidovaných systémem, ale informace o něm nemusí být kompletní nebo ověřené, evidovaný za účelem navázání komunikace s daným subjektem. Objekt zákazník (customer) reprezentuje soubor informací o subjektu který je nebo může být zákazníkem subjektu používajícího tento systém, evidovaný za účelem navázání komunikace s daným subjektem. 30
Objekt dodavatel (supplier) reprezentuje soubor informací o subjektu který je nebo může být dodavatelem služeb nebo zboží potřebným pro podnikání, evidovaný za účelem navázání komunikace s daným subjektem. Objekt úkol (task) reprezentuje záznam o naplánovaném, zpracovávaném nebo dokončeném úkolu, který souvisí s chodem podniku, evidovaný za účelem zefektivnění plánování. Objekt smlouva (contract) reprezentuje záznam o plánované nebo uzavřené dohodě mezi zákazníkem a subjektem užívajícím tento systém o provedení služby, evidovaný za účelem zlepšení přehledu o zjednaných smlouvách. Objekt dokument (document) reprezentuje datový soubor pocházející z externích zdrojů který může být přiložený k záznamu v systému za účelem poskytnutí dalších informací. Objekt příležitost (opportunity) reprezentuje záznam o možnosti zahájení komunikace se zákazníkem, evidovaný za účelem zefektivnění správy obchodních příležitostí. Objekt nabídka (quote) reprezentuje záznam o potencionální nebo uskutečněné nabídce služeb nebo zboží mezi účastníky komunikace, evidovaný za účelem zefektivnění správy nabídek. Objekt objednávka (order) reprezentuje záznam o potencionální nebo uskutečněné nabídce služeb nebo zboží mezi účastníky komunikace, evidovaný za účelem zefektivnění správy objednávek. Objekt faktura (invoice) reprezentuje záznam o potencionální, odeslané nebo přijaté faktuře mezi účastníky komunikace, evidovaný za účelem zefektivnění správy objednávek. Objekt komunikace (communication) reprezentuje uspořádanou množinu e-mailů, telefonátů, faxů, a dopisů zachycující průběh komunikace mezi uživatelem systému a účastníkem obchodní komunikace, evidovaná za účelem plánování a dohledatelnosti předchozích bodů komunikace a navázání na ně. Objekt e-mail reprezentuje rozepsanou, odeslananou nebo přijatou zprávu mezi účastníky komunikace, evidovanou za účelem plánování a dohledatelnosti předchozích e-mailu a navázání na ně. Objekt telefonát (phone call) reprezentuje záznam o plánovaném nebo uskutečněném telefoním hovoru mezi účastníky komunikace, evidovaný za účelem plánování a dohledatelnosti výsledků předchozích telefonátů a navázání na ně. Objekt schůzka (meeting) reprezentuje záznam o plánované nebo uskutečněné schůzce mezi účastníky komunikace, evidovaný za účelem plánování a dohledatelnosti výsledků předchozích schůzek a navázání na ně. Objekt fax reprezentuje záznam o plánované, přijaté nebo odeslané faxové zprávě mezi účastníky komunikace evidovaný, za účelem plánování a dohledatelnosti předchozích faxových zpráv a navázání na ně. Objekt dopis (letter) reprezentuje záznam o plánovaném, přijatém nebo odeslaném dopisu mezi účastníky komunikace, evidovaný za účelem plánování a dohledatelnosti předchozích dopisů a navázání na ně. Objekt uživatel (user) reprezentuje osobu, která má práva na to, aby spravovala záznamy evidované systémem za účelem rozvíjení podniku nebo servisu systému. 31
U ostatních doménových objektů je vždy uvedena osoba, která je za daný objekt zodpovědná. Rád bych poznamenal, že tyto definice nebyly vytvořeny na první pokus, ale byly několikrát přepsány tak, aby byl výsledek dostatečně konzistentní. Již samotné vytváření definic je tedy procesem, ve kterém dojde k vyjasnění mnoha nejasností. Slovník jsem opět konzultoval se zadavatelem a nechal si ho odsouhlasit.
6.5 MODELOVANÍ VAZEB V definicích jsem hledal často se objevující obraty, které jsou specifické pro doménu. Zde je to obrat účastník komunikace, doplním jej tedy do slovníku.
Objekt účastník komunikace (communication participant) reprezentuje kontakt, obchodní vztah, zájemce, zákazníka nebo dodavatele, evidované za účelem zobecnění subjektu se kterým uživatel systému komunikuje.
Formulace účelu napovídá, že půjde o abstraktní objekt, který definuje chování jiných konkrétních objektů. Dále jsem hledal vzory, které mi pomohou při modelování vazeb mezi objekty. Zde si můžeme všimnout podobností definic obchodní vztah, zájemce, zákazník a dodavatel. Nejprve jsem uvažoval o obchodním vztahu jako o nadřazeném pojmu a tedy o vztahu dědičnosti s rodičovskou třídou Account. Po delším přemýšlení jsem se ale rozhodl modelovat vazbu tak, že obchodní vztah může mít různé role (zákazník, dodavatel…). Tento přístup podle mého názoru lépe odpovídá realitě, umožňuje jednodušší přidání dalších rolí a také umožňuje, aby obchodní vztah měl přiřazeno více rolí najednou. Zájemce jsem se rozhodl podle zkušeností z konkurenčních CRM systému nespojovat pevnou vazbou s obchodním vztahem. Objekt zájemce má sloužit pro potřeby rychlého poznamenání kontaktů z vizitek, případně může být automaticky vytvářen prostřednictvím kontaktního formuláře na firemních stránkách. Informace, které obsahuje, mohou být méně strukturované. Věřím, že toto rozdělení zvýší přehlednost obchodních vztahů, tím že zmenší počet nekompletních záznamů, které v budoucnu již nebudou použity. Nyní již mohu vytvořit první diagram tříd s vazbami, viz Obrázek 6.2.
32
OBRÁZEK 6.2: DIAGRAM TŘÍD S VAZBAMI
OBRÁZEK 6.2: DIAGRAM TŘÍD S VAZBAMI
33
Během vytváření diagramu jsem odkryl hlavní principy, na kterých je tato doména založena. To nám umožňuje sepsat tzv. domain vision statement, který slouží všem účastníkům vývojového procesu jako vstupní bod pro studium domény.
6.6 VIZE DOMÉNY (DOMAIN VISION STATEMENT) Model core domény CRM systému reprezentuje komunikace (Communication) vedené za účelem souvisejícím s oborem podnikání zadavatele (např. oslovení potencionálních zákazníků, dohoda o nové smlouvě atd.). Každá komunikace je uspořádaný seznam komunikačních kroků (CommunicationStep). Každý krok komunikace reprezentuje výměnu informací o objektu komunikace (CommunicationObject) mezi účastníky komunikace (CommunicationParticipant) prostřednictvím komunikačního média (CommunicationMedium). Komunikační krok může nabývat stavu plánovaný, uskutečněný, nebo zrušený, viz Obrázek 6.3.
OBRÁZEK 6.3: STAVOVÝ DIAGRAM KOMUNIKAČNÍHO KROKU
6.7 REVIZE SDÍLENÉHO SLOVNÍKU Během tvorby diagramu tříd jsem do modelu přidal další objekty, které je nutné zavést také do sdíleného slovníku. Jelikož DDD nespecifikuje podobu definic, rozhodl jsem se je v této fázi upravit do méně formální podoby, která usnadní jejich pochopení. Zároveň pomocí odsazení znázorním konceptuální podřazenost a nadřazenost objektů. Vypustím definice termínů tam, kde je jejich význam obecně zřejmý.
Objekt komunikace (Communication) reprezentuje uspořádaný seznam komunikačních kroku. Objekt komunikační krok (CommunicationStep) reprezentuje jednotku komunikace která vypovídá o tom co (objekt komunikace) má být, bylo, nebo mělo být komunikováno mezi kým (účastník komunikace) prostřednictvím jakého komunikačního prostředku. Může zaujímat stavy plánovaný, uskutečněný nebo zrušený. o Objekt objekt komunikace (CommunicationObject) reprezentuje soubor informací o objektu komunikace, relevantní pro obor podnikání zadavatele. Je to souhrnný název pro: Objekt nabídka (Quote) Objekt smlouva (Contract) 34
Objekt objednávka (Order) Objekt faktura (Invoice) Objekt obecná informace (GenericInfo) reprezentuje objekt komunikace, který nelze charakterizovat žádným z výše uvedených výrazů. o Objekt účastník komunikace (CommunicationParticipant) reprezentuje soubor informací o účastníkovi komunikace, relevantní pro obor podnikání zadavatele. Je to souhrnný název pro: Objekt obchodní vztah (Account) reprezentuje společnost, sdružení nebo oddělení společnosti. Může obsahovat kontakty. Objekt role obchodního vztahu (AccountRole) reprezentuje roli, kterou daný obchodní vztah hraje v rámci předmětu podnikání zadavatele. Konkrétně jde o: o Objekt zákazník (Customer) o Objekt dodavatel (Supplier) o Objekt vlastník (Owner) reprezentuje samotného zadavatele a provozovatele podnikání. Objekt kontakt (Contact) reprezentuje osobu se kterou chceme komunikovat. Objekt zájemce (Lead) reprezentuje subjekt nebo osobu, která má nebo by mohla mít zájem o služby zadavatele. Informace o zájemci nemusí být kompletní. Pokud již s daným zájemcem navážeme komunikaci, zakládáme pro něj nový obchodní vztah nebo kontakt, všechny vazby na zájemce se přesouvají na nově vytvořený objekt a objekt zájemce se zruší. o Objekt prostředek komunikace (CommunicationMedium) reprezentuje soubor informací o prostředku komunikace, relevantní pro obor podnikání zadavatele. Je to souhrnný název pro: Objekt e-mail (Email) reprezentuje rozepsaný, odeslaný nebo přijatý e-mail. Objekt telefonát (PhoneCall) reprezentuje soubor informací o plánovaném nebo uskutečněném telefonátu. Objekt fax (Fax) reprezentuje rozepsaný, odeslaný nebo přijatý fax. Objekt dopis (Letter) reprezentuje rozepsaný, odeslaný nebo přijatý dopis (v elektronické podobě po naskenování). Objekt schůzka (Meeting) reprezentuje soubor informací o plánované nebo uskutečněné schůzce. Objekt úkol (Task) reprezentuje naplánovaný, zpracovávaný nebo dokončený úkol, souvisejícím s předmětem podnikání zadavatele. Objekt dokument (Document) reprezentuje datový soubor pocházející z externích zdrojů, který může být přiložený k záznamu v systému za účelem poskytnutí dalších informací. Objekt příležitost (Opportunity) reprezentuje soubor informací o možnosti zahájení obchodní komunikace. Objekt uživatel (User) reprezentuje osobu, která má práva na to aby spravovala záznamy evidované systémem. U ostatních doménových objektů je vždy evidován uživatel, který je za daný objekt zodpovědný.
35
6.8 REFAKTORING MODELU Následovala konzultace modelu se zákazníkem na základě vytvořeného diagramu tříd, sdělení vize o doméně a sdíleného slovníku. Při tom se objevila nová skutečnost, která předtím nebyla zřejmá. To je obvyklý případ - zákazník dokáže obtížně navrhnout model, ale mnohem jednodušeji je schopen poznat pokud model neodpovídá realitě. V tomto případě se ukázalo, že jsou pro zákazníka mnohem důležitější výsledky komunikace (nabídky, objednávky, smlouvy atd.) a nezajímá se příliš o přesný průběh této komunikace. Proto jsem vypustil explicitní koncept komunikace a komunikačních kroků a koncentroval se více na subjekty, které jsou zainteresovány v podnikání zadavatele a skutečnosti (výsledky komunikace) které o nich chce v systému evidovat. Postup kroků komunikace lze ale nadále v systému vysledovat, pokud by to bylo v budoucnu třeba. Dále jsem objevil, že v modelu není explicitně vyjádřen důležitý koncept kontaktních údajů, které náleží subjektům podnikání. Proto jsem do modelu přidal objekt Contact, který tuto skutečnost zachycuje. Díky tomu, ale došlo ke kolizi jmen, protože objekt pojmenovaný Contact již byl v modelu použit pro reprezentaci kontaktní osoby. Tuto kolizi jsem vyřešil přejmenování původního objektu Contact na Person. Na základě předchozích poznatků jsem tedy model pozměnil, viz Obrázek 6.4.
36
OBRÁZEK 6.4: DIAGRAM TŘÍD PO REFAKTORINGU
37
Objekt Task jsem přesunul do generické poddomény společně s objektem Calendar a nazval ji PlanningTools. Tyto objekty nejsou fundamentální pro core doménu CRM, pro jejich řešení mohou být použity již existující nástroje nebo může být jejich vývoj delegován na jiný tým. Úlohu objektu AccountRole jsem nahradil pomocí konceptu tzv. štítkování (objekty Taggable a Tag). K tomu jsem přistoupil kvůli univerzálnosti tohoto řešení, a protože se osvědčilo v mých předchozích projektech. Vlastnost „tagovatelnosti“ mohou jednoduše využít také další objekty modelu u kterých to má smysl, zde BusinessItem.
6.9 ZMĚNĚNÁ VIZE DOMÉNY Model core domény CRM systému reprezentuje subjekty zainteresované v podnikání zadavatele (BusinessSubject) společně s business aktivitami a záznamy ve kterých hrají tyto subjekty nějakou roli a které se vztahují k podnikání zadavatele (BusinessItem). O každém BusinessSubject mohou být uchovávány kontaktní informace. Každý BusinessItem se nachází v daný čas v nějakém stavu (např. naplánovaný, uskutečněný, zrušený). Možné stavy závisí na konkrétní specializaci. Tato nová vize domény vede k dalšímu refaktoringu. To, že se ve vizi domény neobjevily některé objekty, vede k zamyšlení, jestli jsou tyto objekty fundamentální pro core doménu, anebo mohou být také přesunuty do generických poddomén. Pro odebrání z core domény jsem se rozhodl u objetu Attachable a jeho podobjektů a také u objektu Taggable, který jsem se rozhodl zaměnit za obecnější poddoménu Taxonomy, která má na starost kategorizaci objektů. Další změnou je použití vzoru MDD - agregát na vztah mezi BusinessSubject a Contact. BusinessSubject se tak stane kořenem agregátu a Contact jeho interním prvkem a zároveň objektem reprezentujícím hodnotu (vzor MDD - Value Object). Změny můžete vidět na Obrázku 6.5
38
OBRÁZEK 6.5: DIAGRAM TŘÍD PO DALŠÍM REFAKTORINGU NA ZÁKLADĚ VIZE DOMÉNY
39
6.10 REVIZE SDÍLENÉHO SLOVNÍKU Provedený refaktoring modelu se odrazí také na slovníku.
Objekt obchodní subjekt (BusinessSubject) reprezentuje subjekt, který se účastní, účastnil nebo může účastnit aktivit a/nebo o kterém zadavatel vede, nebo může vést záznamy. Objekt uchovává informace potřebné pro navázání komunikace (e-mailové a korespondenční adresy a telefonní čísla). Je to souhrnný název pro: o Objekt obchodní vztah (Account) reprezentuje organizace nebo její část. o Objekt kontaktní osoba (Person). Může být součástí obchodního vztahu, nebo vystupovat samostatně. o Objekt zájemce (Lead) reprezentuje subjekt, který má nebo by mohl mít zájem o služby zadavatele. Informace o subjektu nemusí být kompletní. Pokud již s daným zájemcem navážeme komunikaci, zakládáme pro něj nový obchodní vztah nebo kontaktní osobu, všechny vazby na zájemce se přesouvají na nově vytvořený objekt a objekt zájemce se zruší. Objekt obchodní položka (BusinessItem) reprezentuje skutečnost, které se vztahuje k obchodním subjektům a kterou má cenu evidovat za účelem plánování dalších akcí. Je to souhrnný název pro: o Objekt záznam (Record) reprezentuje záznam o skutečnosti, která je, byla, nebo může být předmětem nebo výsledkem komunikace mezi obchodními subjekty. Objekt nabídka (Quote) Objekt smlouva (Contract) Objekt objednávka (Order) Objekt faktura (Invoice) Objekt příležitost (Opportunity) o Objekt aktivita (Activity) reprezentuje aktivitu vyvolanou nebo plánovanou za účelem komunikace mezi obchodními subjekty. Je to souhrnný název pro: Objekt e-mail reprezentuje rozepsaný, odeslaný nebo přijatý e-mail. Objekt telefonát (PhoneCall) reprezentuje soubor informací o plánovaném nebo uskutečněném telefonátu. Objekt fax reprezentuje rozepsaný, odeslaný nebo přijatý fax. Objekt dopis (Letter) reprezentuje rozepsaný, odeslaný nebo přijatý dopis (v elektronické podobě po naskenování). Objekt schůzka (Meeting) reprezentuje soubor informací o plánované nebo uskutečněné schůzce. Objekt uživatel (user) reprezentuje osobu, která má práva na to, aby spravovala záznamy evidované sytémem. U ostatních doménových objektů je vždy evidován uživatel, který je za daný objekt zodpovědný.
6.11 ZHODNOCENÍ MODELU Model CRM systému byl v této podobě odsouhlasen zákazníkem jako odpovídající jeho potřebám. Zároveň je, díky použití MDD a doporučení k refaktoringu modelu, bez zásadních změn vhodný pro implementaci. 40
7 ZÁVĚR V průběhu historie tvorby softwaru se ukázala fáze analýzy a návrhu jako klíčová. Technické nedostatky softwaru, které vznikly pochybením při implementaci, se dají opravit daleko snadněji v porovnání s chybami v analýze a návrhu. Zároveň je nutné, aby nástroje pro analýzu a návrh reflektovali technologická omezení a dokázali se rychle přizpůsobit změnám v průběhu vývoje. Domain-driven design je jedním z přístupů který na tyto fakty klade důraz. Poskytuje nám soubor nástrojů a doporučení jak zefektivnit etapy analýzy a návrhu, a jak je včlenit do celkového procesu tvorby softwaru. Zároveň nám dává dostatek volnosti, abychom jej mohli libovolně kombinovat s jinými (především agilními) metodikami. Po přečtení této práce byste měli získat přehled o jeho nejdůležitějších součástech a způsobech jak je využít. Mne samotnému přineslo její psaní hlubší vhled do problematiky návrhu softwaru a motivovalo mě k dalšímu zájmu o přístupy jako Design by Cotract a doménově specifické jazyky.
41
8 POUŽITÉ ZDROJE 1. EVANS, Eric. Domain-driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley Professional, 2003. 0321125215. 2. Wikipedia contributors. Design by contract. Wikipedia, The Free Encyclopedia. [Online] [Citace: 10. duben 2009.] 3. WAMPLER, Dean. README for Contract4J5: Contracts Using Java 5 Annotations. Aspect Research Associates. [Online] [Citace: 3. květen 2009.] 4. EVANS, Eric - FOWLER, Martin. Specifications. [Online] [Citace: 29. duben 2009.] 5. Wikipedia contributors. Declarative programming. Wikipedia, The Free Encyclopedia. [Online] [Citace: 10. květen 2009.] 6. FOWLER, Martin. Introduction to Domain Specific Languages. InfoQ.com. [Online] 31. říjen 2006. 7. Wikipedia contributors. Reflection (computer science). Wikipedia, The Free Encyclopedia. [Online] [Citace: 10. květen 2009.] 8. AVRAM, Abel - MARINESCU, Floyd. Domain-Dirven Design Quickly. C4Media, 2006. 978-1-4116-0925-9. 9. CHMELINSKY, David - HELLESOY, Aslak. RSpec Documentation. [Online] [Citace: 15. duben 2009.] 10. PENCHIKALA, Srini. Domain Driven Design and Development In Practice. InfoQ.com. [Online] [Citace: 16. květen 2009.]
42