Ahoj,
porušení normální formy databáze by nemělo být dogma - už kolikrát jsem
musel volit nutné zlo v podobě redundance dat místo toho, abych omezoval
uživatele zbytečně pomalou službou. Každopádně díky za moc cenné
zkušenosti a dobré vodítko pro naši další práci!
David Mach
Dne 2.9.2010 7:29, Ing. Jan Novotný napsal(a):
Ahoj,
my jedeme na modulárním systému asi 2 roky (s tím rozdílem, že
nemáme OSGI, ale jen zřetězené aplikační konexty Springu na stejné
classpath - nicméně už to k zavedení modulárnosti stačí). Řešili jsme
stejný problém a obávám se, že neexistuje ideální řešení. Základní
pravidlo spočívá ve správném "řezu" modulů - každý by měl mít
jednoznačnou odpovědnost a funkci. Moduly by se měly vzájemně
doplňovat spíš než ve funkcionalitách překrývat. Prostě příliš malé
moduly nejsou dobré, protože mají potom mnoho závislostí ven, velké
moduly také nejsou dobré, protože se tím zase snižuje jejich
použitelnost. Na správném řezu funkcionalitou prostě záleží hodně.
Pokud by jeden modul sahal do dat jiného modulu přímo a nikoliv
přes jeho API povede toto porušení zapouzdřenosti k: svázanosti
(couplingu) těchto dvou modulů, zhoršení testovatelnosti, problém se
samostatným rozvojem modulů (vždy se na ně bude muset pohlížet jako na
nějaký provázaný celek).
My jsme došli ke dvěma možným technikám v těchto případech
(naštěstí těch případů není zase až tak moc).
1) obětování výkonu - tj. každý modul udržuje pouze svá data a pokud z
nějakého důvodu potřebuje vrátit či pracovat s daty jiného modulu, jde
přes jeho API - tím se ale samozřejmě nedá využít JOINů a platíme
výkonem. Tyto mezimodulové "dotazy" se alespoň snažíme optimalizovat
na metodách API tím, že tam máme metody pro hromadné načítání dat -
např. List<Data> getDataById(Integer... id), která může všechna
potřebná data načít jednorázově přes WHERE id in (...)
2) porušením normální formy db - kromě přímého volání mezi moduly na
úrovni API máme ještě jednu formu komunikace postavenou na "observer
patternu", která vychází ze Springu, tj. moduly v důležitých
okamžicích své funkcionality publikují tzv. eventy do systému, na
které pak mohou reagovat listenery v jiných modulech. Tímto způsobem
je možné distribuovat některá důležitá (i agregovaná) data do zbytku
systému. Uvedu příklad - máme tzv. hodnotící modul, který umožňuje
hodnotit libovolný obsah kdekoliv (např. ve formě hvězdiček na nějaké
škále), tento modul samozřejmě o obsahu samotném nic neví - naopak
jiný modul, který spravuje daný obsah (třeba články) chce při vracení
článku vracet aktuální hodnotu průměrného hodnocení. Hodnotící modul
vždy po přepočtení aktuálního hodnotícího čísla po daný obsah vyhodí
událost do systému, na kterou může kterýkoliv jiný modul naslouchat.
Modul starající se o články tuto událost odchytí a k článku si uloží
dodatečný údaj o aktuálním hodnocení (již vypočtený, hotový k
zobrazení). Tímto způsobem je porušena normální forma - jeden údaj je
v DB uložen 2x, nicméně data jsou potom již hezky po ruce (bez
výkonnostní penalizace) a nedochází k narušení zapouzdřenosti modulů -
jeden může bez problému fungovat bez druhého, pokud běží oba -
spolupracují.
Pokud existuje ještě nějaký jiný způsob komunikace rád se jej
dozvím. Jak říkám, ani jedna z výše uvedených praktik není úplně
ideální, ale na nic lepšího jsme za ty roky nepřišli :(.
Honza
--
--------------------------------------------------------------
Ing. Jan Novotný
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
http://blog.novoj.net
Myšlenky dne otce Fura
--------------------------------------------------------------
2010/9/1 David Mach <[email protected] <mailto:[email protected]>>
Zdravím všechny!
V naší firmě jsme doposud vyvíjeli klasické aplikace na jedné
classpath (typu "vidím vše, volám vše, využívám vše", čili občas
pěkná prasárna). Nyní vyvíjíme novou modulární aplikaci postavenou
na OSGi, přičemž naše původní vize byla ta, že jednotlivé moduly
mezi sebou budou komunikovat výhradně prostřednictvím API. To by
ale například znamenalo, že pro získání dat z modulu A (která
potřebuji pro SQL dotaz v modulu B) budu muset nejprve volat
nějakou metodu z API modulu A, získat ta data a teprve posléze
budu moci složit SQL dotaz v modulu B. Z této představy ovšem
vstávají některým kolegům hrůzou vlasy na hlavě a horují pro to,
abychom se drželi klasické cesty, kdy data z tabulek náležejících
k modulu A budeme získávat pomocí JOINů.
Chci se tedy zeptat přítomných zkušenějších vývojářů na to, zda je
původní vize správná a také na zkušenosti z implementace. Zajímá
mě také rozdíl ve výkonu aplikace při použití API vs JOIN...
Vřelé díky předem!
David Mach