Jedna z velmi častých a závažných chyb při návrhu IS aneb jak vznikají tzv. „molochální systémy“ Část druhá autor RNDr. Ilja Kraval, http://www.objects.cz červenec 2006 (pozn.: článek navazuje na první část také volně ke stažení) Ve školeních OOP a UML věnujeme velmi velkou pozornost jednomu ze základních pojmů v návrhu IS - principu úrovní abstrakce: jaké poslání mají analýza, design a kód. Prakticky se jedná o návod, jak správně navrhnout analytický modelu, jak od něj odvodit technologický návrh a kód. Přitom probíráme několik ukázkových příkladů z praxe, mezi nimi řešíme jako příklad analytický model a technologický návrh evidence hypotetické firmy, která dodává na trh výrobky z porcelánu. Druhy výrobků této firmy jsou členěny tak, že některé jsou základní, jsou dále nedělitelné a jediná možnost, jak jej rozdělit, je rozbít výrobek (…ale pak jsou již neprodejné ☺). Výrobky určitých druhů jsou oproti tomu složené z jiných výrobků (složeniny). Toto skládání nemusí být pouze jednoúrovňové. Například firma dodává na trh „šálek A“, dále „konvici B“ (oba druhy patří do nedělitelných druhů), dodává také „servis C“, který je složen z jedné „konvice B“ a šesti „šálku A“, a také dodává „servis D“, který je složen ze dvou „servisů C“ atd. Úkolem cvičení na úrovně abstrakce je předložit analytický model tříd evidence dodávaných druhů výrobků a provést následný technologický návrh. Smyslem příkladu je ukázat, jak uvažuje analytik a jak uvažuje designér, tj. jak spolu souvisí analytický model a následný model designu.
© Ilja Kraval, 2006, http://www.objects.cz
Existuje několik možných řešení tohoto příkladu (o všech známých je podáno ve výkladu ve cvičení), což pro tento článek není až tak důležité. My se pro účely článku soustředíme na jedno z řešení, viz následující model:
Základní Element +element rozkladu
- název: string 1
Složený Element
+položky
Položka Elementu
* - počet: int
obrázek 1 Jedno z možných řešení evidence skládaných výrobků - Kusovník Princip evidence je poměrně jednoduchý: Existují dvě konkrétní třídy evidující druhy výrobků: Třída Základní Element pro nedělitelné druhy a třída Složený Element pro prvky dále složené. Prvky z třídy Složený Element mají navíc tzv. položky, které udávají „kolik a z čeho“ je prvek složen. Je třeba zdůraznit, že na konci asociace v roli „element rozkladu“ může být jak prvek ze třídy Základní Element, tak prvek ze třídy Složený Element. (Poznámka: Někdy se podobné evidenci také říká Kusovník). Ještě jednou upozorňuji, že existují velmi blízká, ale odlišná řešení, například „čistější řešení“, které zavádí horní abstraktní třídu Element a teprve ta má dva dědice - konkrétní třídy Základní Element a Složený Element. V tom případě je řešení velmi podobné jako vzor COMPOSITE s tím rozdílem, že u Kusovníku dochází ke skládání složeniny přes položky obsahující počet prvků („grupování“ přes počet). Všimněme si, že již zde na několika málo třídách může vzniknout „molochální“ systém díky chybě nečistoty analytického návrhu. Pokračujme v tomto příkladu stejně jako ve cvičení, kdy je předloženo další zadání: „Příklad pokračuje: Uživatel si přeje evidovat také množství výrobků na skladě. Navrhněte řešení, zaveďte evidenci množství výrobků daného druhu na skladě!“ Tady je malý logický háček (malý chyták), který nesouvisí ani tak s UML, ale s logickým myšlením analytika. Pokud budoucí uživatel vznese takovýto požadavek s evidencí výrobků na skladě, musí logicky následovat proti-dotaz od analytika: „Jak jsou výrobky uskladněny? Jsou složené výrobky na skladě již složeny anebo se skládají až při vyskladnění?“ Povaha skládání výrobků metodou „přímo na skladě“
strana 2
© Ilja Kraval, 2006, http://www.objects.cz
nebo metodou „až po vyskladnění“ totiž předurčuje algoritmus evidence množství na skladě. Odpověď budoucího uživatele zní: „Na skladě jsou pouze nedělitelné výrobky, nikoliv složené. Složené výrobky se skládají až po vyskladnění. Ale přejeme si, abychom vždy věděli, kolik se dá čeho složit.“ Je zřejmé, že tímto musíme nejprve zavést evidenci základních elementů (nikoliv složených), následně evidence množství složených výrobků bude dáno jako „virtuální výpočet“ udávající kolik se dá z dané skutečně fyzické evidence složit. Jako příklad je zřejmé, že pokud budeme mít v evidenci základních elementů tisíc „šálků A“ a jednu „konvici B“, složíme pouze jeden „servis C“ a nesložíme ani jeden „servis D“. Soustřeďme se tedy nejprve pouze na evidenci množství u prvků typu Základní element. A nyní přichází „jádro pudla“ našeho výkladu: „Kam toto množství prvků na skladě u základních Elementů vlastně umístit?“ Školsky řečeno, tady se může udělat opravdu vážná hrubka. Někteří účastníci školení navrhovali umístit množství prvků Základních elementů přímo do třídy Základní element jako atribut takto:
Základní Element - množství na skladě: int - název: string
obrázek 2 Jedno z možných řešení množství na skladě V prvé řadě je třeba poznamenat, že toto řešení je funkční, ale chybné (…jak záludné!), protože tímto řešením máme zaděláno na problém… Všimneme si nejprve jedné teoretické záležitosti: Prvek Základní Element již není pouze označením „druhu výrobku“, ale nese také současně informaci o množství na skladě daného druhu. Došlo ke „smíchání dvou pojmů“, druh a množství na skladě jsou v jedné entitě. To se negativně projeví ve vazbách: Cokoliv, co se týká množství se projeví také v druhu. A nutno poznamenat, že znakem „molocha“ je, že u něj opravdu vše souvisí se vším. Takto navrženým řešením je položen první základní kámen „molochálního“ systému. Záludnost této chyby spočívá v tom, že toto řešení splňuje zadání a dokonce funguje dobře. Jaké je tedy „dobré řešení“? Správně má být množství na skladě daného druhu v použití obráceně, tj. množství má použít prvek Základní Element a tím se udává, jakého druhu je dané množství, např. takto:
strana 3
© Ilja Kraval, 2006, http://www.objects.cz
modul druhy výrobku
Množství ZE
- množství: int
Základní Element
1 - název: string
Složený Element
+element rozkladu 1
+položky
Položka Elementu
* - počet: int
obrázek 3 Lepší řešení pro množství prvků na skladě Jednoduchým argumentem, který osvětluje, proč je toto řešení lepší, vystihuje vyznačená hranice pro „modul druhů výrobku“. Tento modul (nebo obecně oblast řešení) stojí samostatně, do něj již problém skladu nezasahuje, do něj se pouze „ukazuje“, tj. tato oblast je v použití a sama nepoužívá. Vidíme, že „sklad používá druhy“ a nikoliv naopak. Dovedu si představit, že skupina tříd v zeleném poli bude umístěna do jednoho prvku Package v UML (např. CONTROL PACKAGE v EA) a následně po mapování do designu do jedné komponenty (resp. skupiny komponent), v datech do jedné skupiny tabulek. Uveďme si jednoduchý a názorný příklad, který okamžitě osvětlí, proč je toto řešení správnější než předešlé chybné „molochální“. Nechť uživatel přijde časem s novým požadavkem: „Nemáme již pouze jeden sklad, ale zavedli jsme N skladů…“ A ihned vidíme problém s naším atributem! Budeme nuceni překopávat modul druhů, pokud jsme množství umístili jako jednoduchý atribut do druhů výrobků (a to určitě nevede k příjemnému pocitu…). Jednoduchou větu ve smyslu „co se stane s entitou Y, pokud se změní entita X …“ použijte vždy, pokud máte pochybnosti o čistotě pojmů v modelu. Uvedená jednoduchá věta totiž odhaluje směr závislosti (Dependency) mezi entitami, což je právě pro chybu zavlečení nečistoty charakteristické. Pomocí této jednoduché věty je tato chyba snadno viditelná. Jak by vypadal analytický model pro zadání „zaveďte N skladů“ v případě odčlenění skladu od druhu, tj. při správném „nemolochálním“ řešení? Jednoduše rozvineme myšlenku skladu nezávisle na druzích výrobků např. takto: strana 4
© Ilja Kraval, 2006, http://www.objects.cz
modul sklad
Sklad
modul druhy výrobku
* Množství ZE
- množství: int
Základní Element
1
+element rozkladu
- název: string
1
Složený Element
+položky
Položka Elementu
* - počet: int
obrázek 4 Rozvíjení problému skladu - modul druhů je na něm nezávislý Mohu z vlastní několikaleté zkušenosti na mnoha projektech potvrdit, že chyba nečistoty pojmů a následný moloch patří k nejčastějším chybám při návrhu systému a mívá katastrofické následky už pro jenom malinko větší systémy (řádově od 50 entit výše, o stovkách entit ani nemluvě!). Při konzultacích a školeních jsem měl možnost vidět přímo extravagantní ukázkové molochy, například vzpomínám na jeden systém, kde všechny business třídy byly umístěny do jedné obrovské komponenty. A přitom bylo použito pro použití komponentní technologie velmi prostředí JAVA (!), které přímo vybízí k „rozsekání“ systému na menší části (totéž platí i pro .NET)… Jako další klasické příklad zavedení „molocha“ nečistotou pojmů mohu uvést velmi častou chybu nesprávného použití modulu Osob (tj. modul pro Fyzické a Právnické osoby apod.). Vážnou chybou je, pokud se do těchto entit evidujících osoby počnou „cpát“ všechny možné údaje, které správně patří jinam, například údaje dodavatele a odběratele, údaje o živnosti, údaje čtenáře, pacienta atd. Přitom je evidentní, že směr použití je přesně naopak: Uvedené entity (tj. dodavatel, živnostník, čtenář apod.) „obalují“ jádro – osoby a používají jej.
strana 5
© Ilja Kraval, 2006, http://www.objects.cz
Není bez zajímavosti, že této chyby se nejčastěji dopouštějí tzv. „dataři“, kteří bez analytického modelu rovnou navrhují tabulky. Mnohem méně se této chyby dopouštějí vývojáři, kteří používají objektové technologie a objektové programování. Osobně se domnívám, že důvod tohoto rozdílu spočívá v tom, že vývojáři znalí OOP mnohem více dbají na směrovost vazeb, tj. sledují „kdo koho má ve svém držení a použití“. Objekty k tomuto náhledu více nabádají díky své přesné definici vnitřních struktur včetně vazeb, u kterých je ihned vidět „nežádoucí“ vnitřní strukturu. Bráno čistě teoreticky, chyba nečistoty pojmů spočívá v zanedbávání vztahu závislostí v asociacích, konkrétně v zanedbání vlastnosti „IsNavigable“ na koncích asociací. Tam je totiž schováno jádro pudla: Slangově řečeno, je vždy důležité vědět, kdo koho „vidí“, řečeno odborněji, je dobré znát, který typ (třída) musí použít který jiný typ (třídu) v jakém směru. V relačních databázích je udávání směru vazby bezpředmětné a proto se chybně zanedbává. V samotném programu je však směrovost velmi důležitá, ať už je program napsán objektově anebo nikoliv. V souvislosti s tímto postřehem se musíme zmínit o jednom drobném technickém detailu. Mnohdy se při školeních vysloví otázka: „Pokud však zavedeme takovouto směrovou vazbu (viz předešlý obrázek), tak mi není jasné, jak potom můžeme dostat odpovídající prvek množství na skladě při zadaném, vybraném, „fečnutém“ druhu výrobku? Druh výrobků přece o množství neví, a tedy z druhu výrobku se k množství nedostaneme, protože v tomto směru není viditelnost, není tam směr použití.“ Tato úvaha v sobě obsahuje malý chyták: Funkcionalita nalezení daného množství na skladě při zadaném druhu výrobku není vlastností (není funkcionalitou) druhu výrobku, a je zřejmé, že při správném rozvrstvení aplikace ani být nesmí (všimněte si chybného směru vazby při takto zavedeném řešení). Pokud se podíváme na předešlý obrázek, tak funkcionalita „Dej množství na skladě pro vybraný druh“ (tj. v designu funkce nebo metoda objektu) musí být umístěna do modulu vlevo, tj. do modulu skladu a nikoliv do modulu druhu. Přitom údaj vybraný druh výrobku se stává vstupním parametrem takového výběru. Vyhledává se takový prvek z množství na skladě, který má vazbu na vybraný prvek druh výrobku … Bohužel mohu z několikaleté zkušeností konzultanta a školitele potvrdit, že zavlečení nečistoty pojmů s následnými „nerozvrstvenými aplikacemi molochálního typu“ je při návrhu IS až příliš častou chybou. Povahou se jedná o stále stejnou chybu: Nečistotou pojmů vznikají „dále od sebe neodseknutelné a nedělitelné celky“ (kočkopsi a nikoliv psi a kočky), systém následně vykazuje vlastnost totálního provázání všeho se vším. Zdánlivě ušetřený počet entit (tabulek) vede k nežádoucímu propletení informací mezi sebou. V takto navrženém systému vznikají enormně velká „kusiska kódu“, která principielně nelze rozdělit na menší části. Jak vidět, jedná se o cestu přesně proti modernímu trendu komponentní technologie, který zní: „Rozděl kód na menší části a linkuj je. Tímto postupem ‚rozděl a panuj‘ máš vládu nad libovolně rozsáhlým projektem.“ Jenomže pokud chceme dodržovat toto rozumné pravidlo, je třeba velmi přesně dbát na směry vazeb mezi částmi kódu, jinak je toto pravidlo nepoužitelné… --- konec článku --strana 6