CQRS i Event Sourcing – oczami architekta biznesowego

Wprowadzenie

Jednym z naj­czę­ściej sto­so­wa­nych wzor­ców pro­jek­to­wych w war­stwie dzie­dzi­no­wej jest wzo­rzec CQRS (Command Query Responsibility Segregation) oraz czę­sto wyko­rzy­sty­wa­ny razem z nim Event Sourcing. 

W 2012 roku pisa­łem o tym wzor­cu w kon­tek­ście opty­ma­li­za­cji wydajnosci:

Idea tego pomy­słu na tym, by nie opty­ma­li­zo­wać wydaj­no­ści sys­te­mu meto­dą, nie raz zgni­łe­go, kom­pro­mi­su, a podejść do pro­ble­mu dzie­ląc go na dwa pro­ble­my: zgod­ność mode­lu z rze­czy­wi­sto­ścią i wydaj­ność całe­go sys­te­mu. Pierwszy pro­blem roz­wią­zu­je­my two­rząc wier­ny model struk­tu­ry opi­su­ją­cej pro­duk­ty, dru­gi pro­blem ? wydaj­no­ści ? roz­wią­zu­je­my two­rząc dru­gi uprosz­czo­ny model pro­duk­tów, do celów szyb­kiej reali­za­cji kil­ku waż­nych ??zapy­tań? (np. publi­ka­cja on line uprosz­czo­nej posta­ci cen­ni­ka). ( CQRS czy­li kto, co i jak zama­wia i dostar­cza – Jarosław Żeliński IT-Consulting).

Rok póź­niej (2013), w toku prac nad kolej­nym pro­jek­tem, powsta­ła wątpliwość:

i to jest ten moment, w któ­rym ja chy­ba cze­goś nie zro­zu­mia­łem u Fowlera (i nie tyl­ko u nie­go) (CQRS czy­li jak osią­gnąć wydaj­ność c.d. – Jarosław Żeliński IT-Consulting)

Najczęściej CQRS opi­sy­wa­ny jest przez deve­lo­pe­rów, języ­kiem deve­lo­pe­ra, i moim zda­niem, z per­spek­ty­wy deve­lo­pe­ra oraz domyśl­ne­go uży­cia rela­cyj­ne­go mode­lu danych. M.Fowler poka­zu­je to tak:

(źr. M.Fowler)

Co ozna­cza, że sepa­ra­cja jest reali­zo­wa­na wyłącz­nie w posta­ci odręb­nych zesta­wów pole­ceń SQL, jed­nak do tej samej rela­cyj­nej bazy danych (na powyż­szym dia­gra­mie po lewej, czy­li tej samej ich struk­tu­ry) przy­kry­tej jej abs­trak­cją (środ­ko­wa część powyż­sze­go dia­gra­mu), uży­wa­na na uży­tek jed­no­li­te­go dostę­pu do niej. Warto pamię­tać, że ta abs­trak­cyj­na war­stwa to mapo­wa­nie obiek­to­wo-rela­cyj­ne (ORM, ang. Object Relational Mapping), rzecz w tym, że takie podej­ście owszem sepa­ru­je ele­men­ty imple­men­ta­cji logi­ki apli­ka­cji, ale nadal nie uwal­nia nas od zło­żo­no­ści zapy­tań SQL do rela­cyj­nej bazy danych. Przykładem może być ten (zresz­tą, uwa­żam bar­dzo dobry) opis: 

Dobrze, przejdź­my więc do gra­ficz­nej [rys. powy­żej] repre­zen­ta­cji wzor­ca, któ­ra powin­na pomóc nam zro­zu­mieć z czym tak na praw­dę mamy do czy­nie­nia… (CQRS i Event Sourcing – czy­li łatwa dro­ga do ska­lo­wal­no­ści naszych)

Należy tu zwró­cić uwa­gę na fakt, że CQRS to wzo­rzec archi­tek­to­nicz­ny czy­li dobra prak­ty­ka, a Event Sourcing to czę­sto mecha­nizm wbu­do­wa­ny w sys­tem zarzą­dza­nia rela­cyj­ną bazą danych. 

Separacja

Opiszę wer­sję PIM obu ww. wzor­ców, abs­tra­hu­jąc cał­ko­wi­cie od war­stwy tech­no­lo­gicz­nej, czy­li pomi­nę kwe­stię hen­dle­rów”, szyn bus” itp. To mam nadzie­ję oczy­ści opis z tego co nie jest isto­tą idei jaka, moim zda­niem, stoi a tymi wzor­ca­mi: opty­ma­li­za­cja zarzą­dza­nia prze­cho­wy­wa­ną informacją.

Niedawno, pod­su­mo­wu­jąc opis baz doku­men­to­wych i przy­kła­do­we­go pro­jek­tu, pisa­łem, że:

Dokumentowe bazy danych mają wie­le zalet (np. wydaj­ność) ale zale­tą, któ­ra czy­ni jest na praw­dę ??hitem? jest moż­li­wość cał­ko­wi­tej rezy­gna­cji z mode­lu rela­cyj­ne­go i języ­ka SQL, co w efek­cie daje ogrom­ne uprosz­cze­nie imple­men­ta­cji. ??Wyciągnięcie? z repo­zy­to­rium nawet bar­dzo skom­pli­ko­wa­ne­go struk­tu­ral­nie doku­men­tu, reali­zu­je­my tu jed­nym bar­dzo pro­stym pole­ce­niem. Identyczna ope­ra­cja w mode­lu rela­cyj­nym będzie wyma­ga­ła nie raz mon­stru­al­ne­go, trud­ne­go do testo­wa­nia, zapy­ta­nia SQL .Bazy doku­men­to­we ??nie boją się redun­dan­cji? (Projekt apli­ka­cji czy­li bazy doku­men­to­we – Jarosław Żeliński IT-Consulting).

Warto też nie zapo­mi­nać, że wzor­ce pro­jek­to­we są po to by roz­wią­zać pro­blem (speł­nie­nie wyma­gań) a nie po to by jest zasto­so­wać bo tak. 

Przyjmuje się, że CQRS to zasa­da, któ­ra mówi że każ­da meto­da w sys­te­mie powin­na być zakla­sy­fi­ko­wa­na do jed­nej z dwóch grup: 1. Command – są to meto­dy, któ­re zmie­nia­ją stan apli­ka­cji i nic nie zwra­ca­ją, 2. Query – są to meto­dy, któ­re coś zwra­ca­ją, ale nie zmie­nia­ją sta­nu apli­ka­cji. Autor ww. arty­ku­łu przywołuje: 

Dlaczego doko­nu­je­my podzia­łu jedy­nie metod na te, któ­re pobie­ra­ją dane oraz na te, któ­re zmie­nia­ją stan naszej apli­ka­cji? Możemy prze­cież zapro­jek­to­wać nasz sys­tem tak, aby tymi zada­nia­mi zaj­mo­wa­ły się osob­ne kla­sy. To jest głów­na róż­ni­ca mię­dzy dwo­ma podej­ścia­mi. ?Mówiąc o CQS myśli­my o meto­dach. Mówiąc o CQRS myśli­my o obiektach.?

I tu widzę pro­blem, bo bazy rela­cyj­ne cechu­ją się tym, że doku­men­ty (okre­ślo­ne struk­tu­ry danych mają­ce postać struk­tu­ral­ną lub nie) w nich nie ist­nie­ją, same tabe­le rela­cyj­ne zawie­ra­ją dane, ale nie nio­są żad­nej uży­tecz­nej infor­ma­cji. Niezależnie od tego czy chce­my zapi­sać doku­ment (zmie­nio­ny lub nowy) czy też do odczy­tać, musi­my wyko­nać, nie raz bar­dzo skom­pli­ko­wa­ny, kod zapy­ta­nia w języ­ku SQL. Separacja zapi­sów danych nowych (zmie­nio­ne też są nowe”) i ich odczy­ty­wa­nia, ma tu sens bo czy­ta­nie nie wyma­ga żad­nej kon­tro­li (nie sta­no­wi ryzy­ka dla sys­te­mu), zapis jest zawsze obło­żo­ny restryk­cja­mi bo stwa­rza ryzy­ko spo­wo­do­wa­nia błę­dów cało­ści struk­tu­ry danych. Po dru­gie czę­sto odczyt, jest w takiej bazie rozu­mia­ny jako raport czy­li treść two­rzo­na na pod­sta­wie wie­lu doku­men­tów, co dodat­ko­wo kom­pli­ku­je treść zapy­ta­nia SQL. 

O wzor­cu Event Sourcing nie będę się roz­pi­sy­wał, roz­wią­zu­je pro­blem zarzą­dza­nia histo­rią zmian danych w rela­cyj­nym mode­lu, przy jed­no­cze­snym usu­wa­niu redun­dan­cji danych, a jego opi­sy są łatwo dostęp­ne. Tu sku­piam sie jedy­nie na opi­sie wzor­ca na pozio­mie biz­ne­so­wym dzie­dzi­ny problemu.

Struktura komponentu Archiwum

Struktura Archiwum (opr. własne)

Powyższy dia­gram obra­zu­je archi­tek­tu­rę Archiwum Dokumentów (odpo­wia­da za zacho­wa­nie doku­men­tów i dostęp do ich tre­ści). Opis od prawej.

Dokument jako agre­gat, jest to ciąg zna­ków, któ­ry może mieć nada­ną mu struk­tu­rę . Podstawowa struk­tu­ra to nazwa oraz począ­tek i koniec doku­men­tu. Treść może mieć wewnętrz­ną struk­tu­rę :

(patrz Dokument…)

Podstawowym ele­men­tem Archiwum jest zbiór obiek­tów kasy Zachowany Dokument. Obiekty tej kla­sy są nośni­ka­mi doku­men­tów (cią­gów zna­ków jak wyżej), każ­dy ma okre­ślo­ną toż­sa­mość (iden­ty­fi­ka­tor doku­men­tu). Każda ope­ra­cja zapi­sa­nia lub przy­wo­ła­nia doku­men­tu to wywo­ła­nie wła­ści­we­go obiek­tu: przy­wo­łaj doku­ment (iden­ty­fi­ka­tor doku­men­tu). Zapis doku­men­tu wyglą­da ana­lo­gicz­nie, co ozna­cza, że ewen­tu­al­ny zapis pobra­ne­go wcze­śniej doku­men­tu o zmie­nio­nej tre­ści nad­pi­sze jest sta­rą wer­sję”. Jest wie­le sytu­acji gdy nie sta­no­wi to pro­ble­mu. Te przy­pad­ki, gdy chce­my mieć doku­ment jako draft” (edy­to­wal­ny) i wer­sję final­ną (nie­edy­to­wal­ny) reali­zu­je­my doda­ją obiek­to­wy atry­but sta­tus doku­men­tu” (draft|final). Jednak jest wie­le sytu­acji gdy histo­ria zmian jest potrzebna. 

Pierwsza rzecz: za histo­rię powi­nien odpo­wia­dać inny obiekt więc two­rzy­my dodat­ko­wą Klasę obiek­tów Zmiany. Separowanie histo­rii obiek­tów od nich samych ma dwie korzy­ści: nie prze­cią­ża­my Obiektów kla­sy Zachowany Dokument oraz może­my tę histo­rię (mecha­nizm) dodać póź­niej, gdy oka­że się że fak­tycz­nie jest potrzeb­ny. Po trze­cie, co jest tu bar­dzo waż­ne: w kla­sie Zachowany Dokument toż­sa­mość ma doku­ment, zaś w kla­sie Zmiany toż­sa­mość ma wer­sja doku­men­tu. Biorąc pod uwa­gę, że bar­dzo czę­sto żąda­my dostę­pu do doku­men­tów i bar­dzo rzad­ko do histo­rii ich zmian, pozwa­la to utrzy­mać mini­mal­ną wyma­ga­na licz­bę obiek­tów kla­sy Zachowany Dokument (a mogą to milio­ny). Praktyka poka­zu­je, że kom­fort pra­cy jest oce­nia­ny na pod­sta­wie czyn­no­ści wyko­ny­wa­nych czę­sto na co dzień, rzad­ko wyko­ny­wa­ne czyn­no­ści (odtwa­rza­nie histo­rii) to te, na któ­re czę­sto mamy znacz­nie wię­cej czasu.

Tu waż­na infor­ma­cja: doku­ment może być opi­sem fak­tu lub obiek­tu (czy­taj wię­cej o Separacja kon­tek­stu…). Ma to ogrom­ne zna­cze­nie, bo Archiwum (kasa Zachowany doku­ment) wca­le nie musi prze­cho­wy­wać doku­men­tów o iden­tycz­nej struk­tu­rze. Zaletą tego wzor­ca jest to, że nie muszą czy­li np. może­my w jed­nym jed­nym Archiwum trzy­mać doku­men­ty mimo tego, że ich struk­tu­ra ewo­lu­uje z cza­sem, co nie wyma­ga żad­nej refak­to­ry­za­cji bazy i jej migra­cji. Klasyfikacji tre­ści doku­men­tów może­my doko­nać z pomo­cą spe­cjal­nej struk­tu­ry iden­ty­fi­ka­to­ra doku­men­tu (sys­tem ten sta­le funk­cjo­nu­je w archi­wi­sty­ce: każ­dy doku­ment ma uni­kal­ną sygna­tu­rę, zawie­ra­ją­cą tak­że kla­sy­fi­ka­cję doku­men­tu). Można też dodać do każ­de­go doku­men­tu opi­su­ją­ce go meta­da­ne i użyć ich jako dodat­ko­wych atry­bu­tów kla­sy Zachowany doku­ment, ale lep­sze roz­wią­za­nie w dal­szej części. 

Trzeci ele­ment to kla­sa Hurtownia Danych. Najczęściej jest to inter­fejs do dedy­ko­wa­ne­go sys­te­mu rapor­to­wa­nia np. hur­tow­ni danych, sys­te­mu BI itp.. 

Przed resz­tą świa­ta” cała struk­tu­ra jest ukry­ta” (her­me­ty­za­cja) za obiek­tem kla­sy Menedżer Repozytorium. Tu jest cała logi­ka kon­tro­li dostę­pu do Archiwum oraz logi­ka adre­so­wa­na zapy­tań: pyta­nie o doku­ment będzie kie­ro­wa­ne do obiek­tów kla­sy Zachowany Dokument, pyta­nie o histo­rie okre­ślo­ne­go doku­men­tu do obiek­tów kla­sy Zmiany, wszel­kie żąda­nia danych zbior­czych i prze­li­cza­nych, do Hurtowni Danych. kom­po­nen­ty korzy­sta­ją­ce z tych usług nie zna­ją archi­tek­tu­ry tego zaple­cza”, dzię­ki cze­mu jakie­kol­wiek zmia­ny w tym zaple­czy” w żad­nym stop­niu nie będą doty­czy­ły resz­ty systemu. 

Po lewej stro­nie mamy (tu dwa) cie­ka­we obiek­ty. Są to dzie­dzi­no­we spi­sy doku­men­tów. Wyżej pisa­łem, że moż­na też dodać do każ­de­go doku­men­tu opi­su­ją­ce go meta­da­ne i użyć ich jako dodat­ko­wych atry­bu­tów kla­sy Zachowany Dokument, jed­nak to spo­wo­du­je, że przy­szła potrze­ba wpro­wa­dze­nia nowej kla­sy­fi­ka­cji spo­wo­du­je koniecz­ność refak­to­ry­za­cji obiek­tów kla­sy Zachowany Dokument (doda­nie kolej­ne­go atry­bu­tu). Aby tego unik­nąć, obiek­ty kla­sy Zachowany Dokument powin­ny odpo­wia­dać wyłącz­nie za zacho­wa­nie doku­men­tu (każ­dy ma toż­sa­mość w atry­bu­cie iden­ty­fi­ka­tor doku­men­tu). Jeżeli potrzeb­ne jest nam ope­ro­wa­nie doku­men­ta­mi na pod­sta­wie więk­szej ilo­ści jego cech (daty, war­to­ści pie­nięż­ne, oso­by pod­pi­su­ją­ce itp., tema­ty­ka tre­ści, inne) udo­stęp­nia­my akto­rom nie Menedżera Repozytorium (Aktor A) a Dziedzinowe Rejestry (Aktor B). Uzyskujemy dwie klu­czo­we korzy­ści: kon­tro­le dostę­pu do tre­ści (aktor może mieć dostęp tyl­ko do obiek­tów kla­sy Dziedzinowy Rejestr X) oraz moż­li­wość doda­wa­nia kolej­nych dzie­dzi­no­wych reje­strów bez koniecz­no­ści refak­to­ry­za­cji wła­ści­we­go Archiwum. Tak funk­cjo­nu­ją reper­to­ria w urzę­dach i sądach. 

Podsumowanie

Opisana archi­tek­tu­ra pozwa­la na sepa­ra­cję kon­tek­stów (aktu­ali­za­cja tre­ści i jej pobie­ra­nie). Pozwala na nie­za­leż­ne zarzą­dza­nie histo­rią doku­men­tów. Spełnia zasa­dę OOP (ang. Open Close Principia) czy­li archi­tek­tu­ra jest zamknię­ta na zmia­ny i otwar­ta na roz­sze­rze­nia. Oparta jest na idei wzor­ców powszech­nie zna­nych jako CQRS i Event Sourcing. 

Praca z poje­dyn­czym doku­men­tem (w szcze­gól­no­ści jego stwo­rze­nie i aktu­ali­za­cja) jest pro­sta wyma­ga tyl­ko (i aż) zna­jo­mo­ści jego iden­ty­fi­ka­to­ra. Tu mamy do czy­nie­nia ze zmia­ną tre­ści (sta­nu) w sys­te­mie (CQRS).

Szybkie wyszu­ka­nie doku­men­tu na bazie wyra­fi­no­wa­nych zapy­tań da nam hur­tow­nia danych (tu zastrze­żo­na dla Aktora A), któ­ra w tabli­cy fak­tów zawie­ra iden­ty­fi­ka­tor doku­men­tu, z któ­re­go pobra­no dane (tu osob­ny temat to hur­tow­nie danych i wie­lo­wy­mia­ro­we mode­le danych do obli­czeń i rapor­to­wa­nia). Jest to czy­ta­nie, ope­ra­cja nie zmie­nia­ją­ca sta­nu sys­te­mu (CQRS). Dotyczy to tak­że zmie­nio­nych, histo­rycz­nych wer­sji dokumentów. 

Obu tych ope­ra­cji moż­na doko­nać tak­że za pośred­nic­twem Dziedzinowego Rejestru (Aktor B).

Opisana tu kon­struk­cja zosta­ła wyko­rzy­sta­na w sys­te­mie Generator Ofert dla Biura Polonijnego Kancelarii Senatu oraz w ?System Wspierania Realizacji Zadań ŻW? dla Oddziału Zabezpieczenia Żandarmerii Wojskowej. W obu przy­pad­kach jed­nym z klu­czo­wych wyma­gań był czas wyko­na­nia imple­men­ta­cji, dzie­dzi­no­wa kon­tro­la dostę­pu do doku­men­tów, oraz moż­li­wość pra­cy z for­mu­la­rza­mi o czę­sto zmie­nia­nej struk­tu­rze i for­mu­la­rza­mi nowy­mi, bez koniecz­no­ści inge­ren­cji developera. 

Bibliografia

Papamarkos, G., Zamboulis, L., & Poulovassilis, A. (2015). Xml Databases. School of Computer Science and Information Systems, Birkbeck College, University of London. http://www.dcs.bbk.ac.uk/~sven/adm08/xmlDBs.pdf
Pacheco, V. F. (2018). Microservice Patterns and Best Practices: Explore pat­terns like CQRS and event sour­cing to cre­ate sca­la­ble, main­ta­ina­ble, and testa­ble micro­se­rvi­ces. Packt Publishing Ltd.
Šilingas, D., & Butleris, R. (2009). Towards imple­men­ting a fra­me­work for mode­ling softwa­re requ­ire­ments in MagicDraw UML. Information Technology and Control, 38(2).

Projekt aplikacji – przykład

Wstęp

Napisałem o orien­ta­cji na doku­men­ty w toku analiz:

Często jestem i ja pyta­ny o to ??Jak wyja­śnić zło­żo­ne roz­wią­za­nie tech­nicz­ne inte­re­sa­riu­szom nie­tech­nicz­nym?? Jak wie­lu mi podob­nych odpo­wia­dam: roz­ma­wiaj doku­men­ta­mi. Sponsor pro­jek­tu, przy­szli użyt­kow­ni­cy, postrze­ga­ją swo­ją pra­cę poprzez doku­men­ty: ich treść i układ. (Wymagania na for­mu­la­rze czy­li dia­gra­my struk­tur zło­żo­nych i XML)

Dzisiaj pój­dzie­my dalej, omó­wi­my to gdzie i jak zacho­wać tę infor­ma­cję. Posłużę się pro­stym przy­kła­dem przy­chod­ni wete­ry­na­ryj­nej. Artykuł będzie opi­sem meto­dy podej­ścia do ana­li­zy zorien­to­wa­nej na pro­ce­sy i dokumenty. 

Tekst ma dwie czę­ści: pierw­sza jest opi­sem dro­gi jaka pro­wa­dzi nas do zde­fi­nio­wa­nia tego jakie doku­men­ty, jaką mają (mieć) zawar­tość i struk­tu­rę. Praktycznie jest to opis ana­li­zy i pro­jek­to­wa­nia. Druga – krót­ka – to przy­kła­do­wa archi­tek­tu­ra logi­ki reali­za­cji apli­ka­cji, poka­zu­ją­ca miej­sce doku­men­to­wej bazy danych w archi­tek­tu­rze i pro­jek­cie, czy­li tak­że projektowanie. 

Celem tego wpi­su jest poka­za­nie czym może być ana­li­za oraz jej pro­dukt jakim jest Techniczny Projekt Oprogramowania.

Czytaj dalej… Projekt apli­ka­cji – przy­kład”

CQRS czyli jak osiągnąć wydajność c.d.

Rok temu pisa­łem o wzor­cu CQRS, tam­ten wpis bazo­wał głów­nie na arty­ku­le M.Fowlera i sta­no­wił raczej zajaw­kę tema­tu. Teraz mam trosz­kę wła­snych doświad­czeń, tak­że w dys­ku­sjach z pro­gra­mi­sta­mi, i przy­to­czę tu moja kon­klu­zję, nie­co chy­ba odbie­ga­ją­cą od opi­su M.Fowlera, któ­re­go albo nie zro­zu­mia­łem ale on upro­ścił swój wpis (dzię­ki cze­mu ja wte­dy nie zrozumiałem).

Mamy pro­blem pole­ga­ją­cy na tym, że fir­ma ma ogrom­ną ofer­tę pew­nych bar­dzo zło­żo­nych pod­ze­spo­łów, żeby nie psuć ich opi­su i moż­li­wo­ści roz­bu­do­wy, model dzie­dzi­ny odwzo­ro­wu­je struk­tu­rę tych czę­ści. Jednak bar­dzo duża licz­ba użyt­kow­ni­ków skle­pu inter­ne­to­we­go regu­lar­nie przy­wo­łu­je na ekran listę pod­ze­spo­łów w posta­ci cen­ni­ka, peł­ne­go, stro­ni­co­wa­ne­go, sor­to­wa­ne­go alfa­be­tycz­nie lub ceną.

Rozwiązanie: repo­zy­to­rium prze­trzy­mu­je dwa kom­ple­ty tych danych: jeden jako peł­ny kata­log danych o pro­duk­tach dru­gi jako pła­ski cen­nik. bar­dzo czę­sto spo­ty­kam się z opi­nia (imple­men­ta­cją), w któ­rej (np. za pomo­cą ORM) mapu­je się model (pro­jekt) logicz­ny na bazę danych w spo­sób jak poniżej:

CQRS 1

Prawdopodobnie dla­te­go, że na stro­nie http://​mar​tin​fow​ler​.com/​b​l​i​k​i​/​C​Q​R​S​.​h​tml mamy taki oto dia­gram opi­su­ją­cy wzo­rzec CQRS:

cqrs

i to jest ten moment, w któ­rym ja chy­ba cze­goś nie zro­zu­mia­łem u Fowlera (i nie tyl­ko u nie­go). W moim mnie­ma­niu (i w mojej wer­sji w pro­jek­tach) wyglą­da to jed­nak tak:

CQRS 2

Czyli z zewnątrz” mamy RepozytoriumPodzespołów (jeden inter­fejs) a logi­ka jest taka: na bazie kolek­cji agre­ga­tów powsta­je rów­no­le­gle (jest aktu­ali­zo­wa­na okre­so­wo) nie­za­leż­na pła­ska lista. Korzystający z tego kom­po­nen­tu – wyko­nu­jąc ope­ra­cje podajCennik() – nie wie, czy cen­nik jest gene­ro­wa­ny wprost z agre­ga­tów czy z pła­skiej tabli­cy, bo to jest ukry­te za inter­fej­sem. Jednak, jak nie trud­no się domy­śleć, odpo­wiedź z kolek­cji ProstyopisPodzespołów będzie o nie­bo” szyb­sza niż ad-hoc zapy­ta­nie do kolek­cji bar­dzo zło­żo­nych agre­ga­tów. Agregaty prak­tycz­nie wyłącz­nie obsłu­gu­ją ope­ra­cje CRUD. Warunkiem uzy­ska­nia dużej wydaj­no­sci ope­ra­cji podajCennik() jest, pro­jek­tu­jąc utrwa­la­nie, zbu­do­wa­nie dwóch odręb­nych zesta­wów tablic dla agre­ga­tów i dla pła­skiej kolekcji.

Dom bez planów

CQRS czyli kto, co i jak zamawia i dostarcza

Poprzedni arty­kuł koń­czy­ły słowa:

Tak więc jest to moim zda­niem dro­ga do mode­lo­wa­nia wyma­gań meto­dą ?tak to ma dzia­łać? a nie tyl­ko ?tak to ma wyglą­dać?, bo to dru­gie jest przy­czy­ną wie­lu problemów?

Wielu deve­lo­pe­rów zacie­kle bro­ni się przed tezą, że wyma­ga­nia to tak­że ?żąda­na reali­za­cja logi­ki biz­ne­so­wej?, ocze­ku­ją wyłącz­nie zesta­wu wyma­gań funk­cjo­nal­nych i poza-funk­cjo­nal­nych. Jest to moim zda­niem źró­dło dwóch ryzyk:

  • jeże­li zamó­wie­nie jest opi­sem czar­nej skrzyn­ki tak na praw­dę nie wie­my do dosta­nie­my jako jej realizację,
  • jeże­li auto­rem reali­za­cji jest dostaw­ca, pozo­sta­je mu nie­zby­wal­ne pra­wo do pro­jek­tu tej realizacji.

Dlatego war­to, jako wyma­ga­nie prze­ka­zać pro­jekt tak zwa­nej ?bia­łej skrzyn­ki?, bo zabez­pie­cza to nas przed powyż­szy­mi ryzy­ka­mi. (Wzorzec ana­li­tycz­ny Boundary Control Entity).

Czemu tak bro­nię tej tezy? Zarzuty deve­lo­pe­rów wobec mnie to: wymu­szasz imple­men­ta­cję a to rola pro­jek­tan­ta”. Jest to nie praw­da, bo pro­jek­ty wyma­gań zawie­ra­ją­ce wewnętrz­ną logi­kę to jesz­cze nie imple­men­ta­cja, ale na pew­no jest to ocze­ki­wa­nie kupu­ją­ce­go opro­gra­mo­wa­nie. Gdybym kupo­wał samo­chód nie chciał bym, by mi ktoś powie­dział, że wol­no mi powie­dzieć tyl­ko jak będę do nie­go wsia­dał, wysia­dał i po co, że będę zgod­nie z ogól­ny­mi zasa­da­mi naci­skał peda­ły i mani­pu­lo­wał drąż­kiem zmia­ny bie­gów. Nie! Mam pra­wo i ocho­tą okre­ślić typ sil­ni­ka, żądać ABS i wie­le innych rze­czy. Jeżeli ja nie znam się aż tak na samo­cho­dach popro­szę o pomoc kogoś kto się zna. Jest ryzy­ko? Jest, ale to ja o nim decy­du­ję a nie sprze­daw­ca samochodów!

Jeden z wielu powodów takiego podejścia

Przytłaczająca więk­szość deve­lo­pe­rów, z któ­ry­mi się spo­tka­łem, roz­wią­zu­je pro­blem wydaj­no­ści np. pra­cy z listą pro­duk­tów, podej­mu­jąc kom­pro­mis pomię­dzy szcze­gó­ło­wo­ścią i wier­no­ścią opi­su pro­duk­tu” a wydaj­no­ścią (czas odpo­wie­dzi sys­te­mu) np. pod­czas pre­zen­ta­cji (gene­ro­wa­nia) uprosz­czo­ne­go cen­ni­ka. Większość zna­nych mi deve­lo­pe­rów nie­ste­ty pre­zen­tu­je coś co nazy­wam struk­tu­ral­ny model pro­jek­to­wa­nia opro­gra­mo­wa­nia opar­ty na ane­micz­nym mode­lu dzie­dzi­ny”. Z regu­ły roz­wią­zu­ją oni opi­sa­ny wyżej pro­blem cen­ni­ka, uprasz­cza­jąc opis pro­duk­tu (psu­ją model!), umiesz­cza­ją uprosz­czo­ne dane o pro­duk­cie w mode­lu rela­cyj­nym wraz z resz­tą danych i wal­czą z opty­ma­li­za­cją zapy­tań do tej rela­cyj­nej bazy (uprasz­cza­nie i denormalizacja).

Nie raz pro­wa­dzi to do sytu­acji, w któ­rej opro­gra­mo­wa­nie jest szyb­kie i nieprzydatne”. 

< – jeże­li nie jesteś ana­li­ty­kiem przejdź na koniec artykułu – >

Wygląda to wte­dy np. tak (źr. Fowler CQRS):

Od pra­wej: inter­fejs użyt­kow­ni­ka, model dzie­dzi­ny, baza danych (pod­sys­tem utrwalania).

CQRS

Nie od dzi­siaj zna­ny jest wzo­rzec pro­jek­to­wy, któ­ry radzi sobie z tym pro­ble­mem. Nazywa się CQRS, i tak jest opi­sy­wa­ny przez guru” ana­li­zy i pro­jek­to­wa­nia :), Martina Fowlera:

CQRS stands for Command Query Responsibility Segregation. It’s a pat­tern that I first heard descri­bed by Greg Young. At its heart is a sim­ple notion that you can use a dif­fe­rent model to upda­te infor­ma­tion than the model you use to read infor­ma­tion. This sim­ple notion leads to some pro­fo­und con­se­qu­en­ces for the design of infor­ma­tion sys­tems. (źr. CQRS).

Idea tego pomy­słu na tym, by nie opty­ma­li­zo­wać wydaj­no­ści sys­te­mu meto­dą, nie raz zgni­łe­go, kom­pro­mi­su, a podejść do pro­ble­mu dzie­ląc go na dwa pro­ble­my: zgod­ność mode­lu z rze­czy­wi­sto­ścią i wydaj­ność całe­go sys­te­mu. Pierwszy pro­blem roz­wią­zu­je­my two­rząc wier­ny model struk­tu­ry opi­su­ją­cej pro­duk­ty, dru­gi pro­blem – wydaj­no­ści – roz­wią­zu­je­my two­rząc dru­gi uprosz­czo­ny model pro­duk­tów, do celów szyb­kiej reali­za­cji kil­ku waż­nych zapy­tań” (np. publi­ka­cja on line uprosz­czo­nej posta­ci cennika).

Powyższy dia­gram poka­zu­je: UI (inter­fejs użyt­kow­ni­ka), poka­zu­je menu zgod­ne z opi­sem z przy­pad­ków uży­cia (wyma­ga­nia funk­cjo­nal­ne). Model dzie­dzi­ny (część środ­ko­wa) poka­zu­je ocze­ki­wa­ne roz­wią­za­nie (takie­go żądam w wyma­ga­niach). Polega ono wła­śnie na zapro­jek­to­wa­niu w czę­ści dzie­dzi­no­wej odręb­ne­go mode­lu do zarzą­dza­nia poje­dyn­czy­mi pro­duk­ta­mi i odręb­ne­go do wydaj­ne­go zarzą­dza­nia ich kolek­cją. Owszem, model się nie­co skom­pli­ko­wał (jest nie­co kosz­tow­niej­szy w imple­men­ta­cji), ale jako zama­wia­ją­cy mam to cze­go potrze­bu­ję: wydaj­ny i uży­tecz­ny system.

< – jeże­li nie jesteś ana­li­ty­kiem tu zacznij czy­tać dalej – >

Opisując wyma­ga­nia wyłącz­nie jako czar­ną skrzyn­kę” nie wiem co dosta­nę. Większość deve­lo­pe­rów będzie dąży­ło do uprosz­cze­nia imple­men­ta­cji (ich koszt, nie raz brak wie­dzy) by zaspo­ko­ić na mini­mal­nym pozio­mie wyma­ga­nia opi­sa­ne przy­pad­ka­mi uży­cia. Nie raz klient sły­szy tu musi­my to upro­ścić bo tak się nie da”, a zama­wia­ją­cy, nie mając kom­pe­ten­cji by pole­mi­zo­wać z taką opi­nią, zga­dza się i dostar­czo­ny w efek­cie sys­tem sta­je się zgni­łym kom­pro­mi­sem opar­tym wła­śnie na czar­nej skrzyn­ce” jako spe­cy­fi­ka­cji zamó­wień: dosta­li­śmy dokład­nie to co zamó­wi­li­śmy ale zupeł­nie nie to cze­go napraw­dę potrzebujemy”. 

Tak więc,

nie ma zna­cze­nia fakt, że na pew­no są na ryn­ku deve­lo­pe­rzy zna­ją­cy pro­blem, któ­ry opi­sa­łem i sto­su­ją­cy opi­sa­ne tu roz­wią­za­nie takich pro­ble­mów. Jednak nawet cień ryzy­ka (a jest ono na praw­dę duże), że dosta­nie­my bubla, daje zama­wia­ją­ce­mu pra­wo do szcze­gó­ło­we­go defi­nio­wa­nia wyma­gań jako bia­łej skrzyn­ki”, bo dzię­ki temu zama­wia­ją­cy dosta­nie to cze­go potrze­bu­je a nie tyl­ko to co zamó­wił”.

Dla zain­te­re­so­wa­nych tak­że do pobra­nia książ­ka z MSDN:

The CQRS pat­tern and event sour­cing are not mere sim­pli­stic solu­tions to the pro­blems asso­cia­ted with lar­ge-sca­le, distri­bu­ted sys­tems. By pro­vi­ding you with both a wor­king appli­ca­tion and writ­ten guidan­ce, we expect you’ll be well pre­pa­red to embark on your own CQRS jour­ney. (za CQRS Journey).

Wzorzec analityczny Boundary Control Entity i ICONIX a także MVC i MVVM

Opisywałem ostat­nio wzo­rzec DDD jako narzę­dzie doku­men­to­wa­nia ana­li­zy i two­rze­nia mode­li ana­li­tycz­nych. Faktycznie, czy­tel­ni­cy mają wie­le racji twier­dząc, że czę­sto jest on zbyt bli­ski imple­men­ta­cji (zbyt szcze­gó­ło­wy a więc trud­ny dla nie­pro­gra­mi­stów). Niejednokrotnie lep­szym pomy­słem” jest opis logi­ki sys­te­mu na nie­co wyż­szym pozio­mie abs­trak­cji, pozo­sta­wia­jąc tym samym wię­cej swo­bo­dy developerowi.

Od cza­su do cza­su uży­wam wzor­ca BCE (Boundary, Control Entity) do mode­lo­wa­nia logi­ki biz­ne­so­wej. Jego rodo­wód się­ga chy­ba jesz­cze cza­sów począt­ków [[meto­dy­ki RUP]]. Pierwotnie był trak­to­wa­ny jako wzo­rzec ana­li­tycz­ny do mode­lo­wa­nia archi­tek­tu­ry kom­pa­ty­bil­nej z MVC, w swej ory­gi­nal­nej posta­ci nawią­zu­je do EJB/DAO ([[Enterprise JavaBeans/Data Access Object]]). Przykładowe stan­dar­do­we uży­cia (źr. wiki):

Wzorzec BCE koja­rzo­ny jest głów­nie z archi­tek­tu­rą EJB ([[Enterprise Java Beans]]). Od tam­tej pory EJB jed­nak nie­co ode­szło w nie­pa­mięć”, nie mamy już J2EE a JEE. Wzorzec MVC docze­kał się sen­sow­nej moim muta­cji do wer­sji [[MVVMC]], [[Model-View-ViewModel Contoler]], [[MVP]] (i kil­ku innych odmian). Diagram w tej kon­wen­cji jest tak­że nazy­wa­ny „[[robust­ness dia­gram]]” i koja­rzo­ny jest z meto­dy­ką ICONIX, jed­nak oso­bi­ście pole­cam sto­so­wa­nie zasad UML i uży­wa­nie dia­gra­mu klas zgod­nie z jego zasa­da­mi” czy­li uży­wa­nie związ­ków uży­cia (linia prze­ry­wa­na z gro­tem a nie cią­gła) i uzna­nie, że robust­ness dia­gram to po pro­stu dia­gram klas.

Podstawowa pier­wot­na wer­sja inter­pre­ta­cji wzor­ca BCE opi­sa­na jest zwięź­le tutaj:

This pat­tern is simi­lar to the Model View Controller pat­tern (descri­bed here [BUS96] and here [WIKP-MVC] among other pla­ces), but the Entity Control Boundary pat­tern is not sole­ly appro­pria­te for dealing with user inter­fa­ces and it gives the con­trol­ler a sli­gh­tly dif­fe­rent role to play. (za Entity-Control-Boundary Pattern).

Stosuję go jed­nak w nie­co zmie­nio­nej” formie.

Boundary, Control, Entity

Jak widać na powyż­szym, BCE nawią­zu­je bez­po­śred­nio do wzor­ca MVC, kla­sy boun­da­ry są w tej wer­sji już ele­men­ta­mi kom­po­nen­tu View. Starając się oddzie­lić (her­me­ty­zo­wać) logi­kę biz­ne­so­wą od czę­ści nie­biz­ne­so­wej” kodu, będą­cej w więk­szo­ści przy­pad­ków ele­men­ta­mi śro­do­wi­ska ([[fra­me­work]]) aplikacji.

Nieco inne podej­ście, to któ­re sto­su­ję obec­nie, opi­su­ję poni­żej. Zachowując pod­sta­wo­we zna­cze­nia tych trzech klas (BCE), nawią­za­łem do wzor­ca MVVM. Powstaje więc kon­struk­cja, w któ­rej Model ma struk­tu­rę M‑VM, pozo­sta­łe ele­men­ty View i Controler mają kon­kret­ne zadania:

  • M‑VM to struk­tu­ra czę­ści dzie­dzi­no­wej (Model-ViewModel),
  • View – tra­dy­cyj­nie odpo­wia­da za prezentację,
  • Controler – tra­dy­cyj­nie odpo­wia­da za zarzą­dza­nie cało­ścią, w tym poza-funk­cjo­nal­ne wyma­ga­nia (np. kodo­wa­nie trans­fe­ru danych nie jest ele­men­tem dzie­dzi­ny sys­te­mu, itp.)

Pewna cie­ka­wost­ką jest w tym wzor­cu wła­śnie ele­ment VM (ViewModel). Jego idea pole­ga na umiesz­cze­niu w obsza­rze dzie­dzi­ny dodat­ko­wej wie­dzy (logi­ki), ste­ru­ją­cej tym jakie (cho­dzi o ich bogac­two”) infor­ma­cje są poda­wa­ne na urzą­dze­nia pre­zen­tu­ją­ce o róż­nych moż­li­wo­ściach np. mały lub duży ekran, roz­dziel­czość czy wręcz komu­ni­ka­cja z pomo­cą SMS.

Powyższy dia­gram poka­zu­je sche­mat budo­wa­nia mode­lu na bazie tego wzor­ca. Jak widać ele­ment dzie­dzi­ny Model zacho­wu­je się zawsze tak samo, repre­zen­tu­je wie­dzę i logi­kę dzie­dzi­no­wą (np. kom­plet infor­ma­cji o oso­bie), Dziedzina (Model) jest dodat­ko­wo wypo­sa­żo­na w wie­dzę o moż­li­wo­ściach pre­zen­to­wa­nia peł­nej lub okro­jo­nej wer­sji wie­dzy publi­ko­wa­nej przez obiekt dzie­dzi­no­wy (kla­sy ViewModel). Dzięki temu View nie zawie­ra żad­nej logi­ki np. fil­tro­wa­nia peł­nej infor­ma­cji, dosta­je tyl­ko pro­sty przy­go­to­wa­ny zestaw danych do pre­zen­ta­cji poza samą pre­zen­ta­cją (dla uprosz­cze­nia pomię­to kom­po­nent Controller).

Jest to o tyle wygod­ne i waż­ne, że sto­so­wa­nie wzor­ca BCE wyłącz­nie do mode­lo­wa­nia logi­ki biz­ne­so­wej wyma­ga zacho­wa­nia her­me­ty­za­cji kom­po­nen­tu Model. Spotkać się moż­na z dia­gra­ma­mi, w któ­rych boun­da­ry będzie ele­men­tem kom­po­nen­tu Model (jako ViewModel). Jego rola to stwo­rze­nie dedy­ko­wa­ne­go inter­fej­su np. pomię­dzy kom­po­nen­tem View (lub Controller) a Model. Dzięki temu moż­li­we jest np. stwo­rze­nie odręb­ne­go inter­fej­su dla View na duży ekran i odręb­ne­go dla View na np. małych ekra­nach smart­fo­nów. Takie podej­ście wyglą­da tak:

Znaczenie (seman­ty­ka) stereotypów:

Boundary to kla­sa ozna­czo­na ste­reo­ty­pem «boun­da­ry», na dia­gra­mach repre­zen­to­wa­na może być iko­ną jak po lewej. Odpowiedzialność klas boun­da­ry to sepa­ra­cja mode­lu dzie­dzi­ny od innych kom­po­nen­tów (to czę­sto adap­ter, fasa­da, inter­fejs). Dzięki temu ewen­tu­al­ne zmia­ny Modelu nie prze­nio­są się na kom­po­nen­ty View i Controller oraz może­my zbu­do­wać np. róż­ne dedy­ko­wa­ne i bez­piecz­ne dzie­dzi­no­we adap­te­ry dostę­po­we do Modelu (np. w sys­te­mie nawi­ga­cyj­nym boun­da­ry dostar­czy Modelowi koor­dy­na­ty geo­gra­ficz­ne, View pozwo­li wpro­wa­dzić je z kla­wia­tu­ry a Controller z odbior­ni­ka – inter­fejs – GPS, Model sta­je nie­czu­ły na źró­dło tych koordynatów).

Control. Klasy ozna­czo­ne ste­reo­ty­pem «con­trol» lub iko­ną jak po lewej. Są to kla­sy odpo­wie­dzial­ne za wewnętrz­ne usłu­gi spe­cy­ficz­ne dla dzie­dzi­ny, umie­jęt­no­ści”. Nie są to kla­sy utrwa­la­ne. Ta kla­sa będzie obli­cza­ła np. czas prze­jaz­du na bazie wyty­czo­nej w sys­te­mie nawi­ga­cji strasy.

Entity. Najbardziej kon­tro­wer­syj­na kla­sa, w pier­wot­nej wer­sji inter­pre­ta­cji wzor­ca BCE (EJB) ozna­cza­ła tyl­ko dane utrwa­la­ne, nawią­zu­jąc do EJB sta­no­wi­ła mate­riał” na tak zwa­ny [[antyw­zo­rzec obiek­to­wy o nazwie ane­micz­ny model dzie­dzi­ny]]. Klas ozna­czo­nych ste­reo­ty­pem «enti­ty» uży­wa­my do mode­lo­wa­nia wie­dzy, czy­li zgro­ma­dzo­nych danych, nie są to jed­nak ane­micz­ne kla­sy bez ope­ra­cji. Będą to np. punk­ty na mapie cyfrowej.

Trzy powyż­sze typy klas są tu ele­men­ta­mi kom­po­nen­tu Model. Syntaktyka odwo­łań ele­men­tów wzor­ca BCE:

Obrazowo wyglą­da to tak:

Przejście na poziom DDD, dro­gę w kie­run­ku imple­men­ta­cji tego mode­lu przy powyż­szych zało­że­niach, moż­na reali­zo­wać np. tak:

Interpretacja ta pozwa­la zacho­wać głów­ny cel czy­li roz­ło­że­nie logi­ki Modelu na pro­stą” mapę trzech ele­men­tów: kon­tak­tu z oto­cze­niem (boun­da­ry), reali­za­cji logi­ki i reguł (con­trol) oraz zacho­wy­wa­nia bier­nych” obiek­tów biz­ne­so­wych (enti­ty). Mała adap­ta­cja kon­wen­cji do wzor­ca MVVM-V‑C pozwa­la uzy­skać kom­fort cał­ko­wi­tej sepa­ra­cji tak mode­lo­wa­ne­go Modelu od jego otoczenia.

Tak więc jest to moim zda­niem dro­ga do mode­lo­wa­nia wyma­gań meto­dą tak to ma dzia­łać” a nie tyl­ko tak to ma wyglą­dać”, bo to dru­gie jest przy­czy­ną wie­lu problemów…

Wielu deve­lo­pe­rów zacie­kle bro­ni się przed tezą, że wyma­ga­nia to tak­że żąda­na reali­za­cja logi­ki biz­ne­so­wej”, ocze­ku­ją wyłącz­nie zesta­wu: wyma­ga­nia funk­cjo­nal­ne i poza-funk­cjo­nal­ne. Jest to moim zda­niem źró­dło dwóch ryzyk:

  • jeże­li zamó­wie­nie jest opi­sem czar­nej skrzyn­ki tak na praw­dę nie wie­my do dosta­nie­my jako jej realizację,
  • jeże­li auto­rem reali­za­cji jest dostaw­ca pozo­sta­je mu nie­zby­wal­ne autor­skie pra­wo oso­bi­ste do pro­jek­tu tej reali­za­cji (mająt­ko­we­go nie musi wydać).

Dlatego war­to, jako wyma­ga­nie prze­ka­zać pro­jekt tak zwa­nej bia­łej skrzyn­ki”, bo zabez­pie­cza to nas przed powyż­szy­mi ryzykami. 

Literatura

Polecam cie­ka­wy arty­kuł na podob­ny temat:

As we have seen, the fun­da­men­tal idea of MVC is a sepa­ra­tion of the doma­in logic and the GUI objects into the Model and the View. These two are lin­ked indi­rec­tly by using the Publish-Subscribe mecha­nism known as the Observer pat­tern. Another ele­ment of this design is a Controller that imple­ments a par­ti­cu­lar stra­te­gy for the View. (Model View Controller, Model View Presenter, and Model View ViewModel Design Patterns – CodeProject).

Oraz (apro­po MVVM iMVC):

Warto pisać apli­ka­cje w taki spo­sób, żeby moż­na było je w cało­ści obsłu­gi­wać za pomo­cą testów jed­nost­ko­wych. Jak nale­ży to rozu­mieć? Budując apli­ka­cję w taki spo­sób, że cała jej funk­cjo­nal­ność dostęp­na jest bez inter­fej­su użyt­kow­ni­ka, możesz każ­dy jej aspekt opi­sać za pomo­cą testów jed­nost­ko­wych. To pozwa­la na wstęp­ne testo­wa­nie zgod­no­ści apli­ka­cji z wyma­ga­nia­mi wstęp­ne, bo cały czas nale­ży pamię­tać, że testy jed­nost­ko­we to narzę­dzie, wspie­ra­ją­ce pro­gra­mi­stów, a nie teste­rów i jako takie nie może zastą­pić testów apli­ka­cji. (Wykorzystanie TDD wraz ze wzor­cem MVVM).

Kiedy i po co robimy te modele?

Tu nawią­żę do MDA (tu co nie­co o Model Driven Architecture). W łań­cu­chu mode­li MDA mamy trzy mode­le: CIM->PIM->PSM. Analiza biz­ne­so­wa na pierw­szym eta­pie to two­rze­nie mode­lu orga­ni­za­cji pomi­ja­ją­ce­go ist­nie­nie jakie­go­kol­wiek opro­gra­mo­wa­na (CIM – [[Computation Independent Model]]), celem jest peł­ne zro­zu­mie­nie i opi­sa­nie funk­cjo­no­wa­nia organizacji.

Kolejny etap to opra­co­wa­nie mode­lu dzie­dzi­ny pro­jek­to­wa­ne­go (wyma­ga­ne­go) opro­gra­mo­wa­nia. To model PIM ([[Platform Independent Model]]). Jego celem jest udo­ku­men­to­wa­nie logi­ki opro­gra­mo­wa­nia, wyma­ga­nia poza funk­cjo­nal­ne są reali­zo­wa­ne nie­za­leż­nie od tej logi­ki. Tak więc model PIM do coś co nazy­wa­ne bywa: wyma­ga­nia dzie­dzi­no­we”. Wymagania funk­cjo­nal­ne nie opi­su­ją w ogó­le logi­ki biz­ne­so­wej, same przy­pad­ki uży­cia nie są wystar­cza­ją­ce do napi­sa­nia opro­gra­mo­wa­nia, potrzeb­na jest wie­dza o logi­ce biz­ne­so­wej. Funkcjonalność sys­tem sprze­da­ży auto­ma­tycz­nie uwzględ­nia upu­sty dla klien­tów” nic nie mówi. Ale gdzie defi­ni­cja logi­ki udzie­la­nia tych upu­stów? Gdzie jest wie­dza o upu­stach a gdzie o towa­rach? Przy klien­cie czy przy towa­rze? Nie wia­do­mo, trze­ba to jakoś zro­zu­mieć i udo­ku­men­to­wać, w spo­sób pozwa­la­ją­cy na imple­men­ta­cją czy­li jed­no­znacz­nie. I po to się two­rzy mode­le PIM.

Tu jed­nak nale­ży się mała uwa­ga (bo nigdy nie mów nigdy): bywa, że ogra­ni­cze­nie o tre­ści mak­sy­mal­ny czas ocze­ki­wa­nia na ofer­tę nie może prze­kro­czyć pro­gu cier­pli­wo­ści 80% klien­tów”. Pozostaje zba­da­nie pro­gu cier­pli­wo­ści”, ten para­metr nie jest ele­men­tem regu­ły biz­ne­so­wej gdyż jest wła­śnie para­me­trem” a nie zasa­dą” (regu­ły biz­ne­so­we to zasa­dy postę­po­wa­nia a nie regu­ły podej­mo­wa­nia decy­zji czy mier­ni­ki). Ta regu­ła może stać się ele­men­tem dzie­dzi­ny pro­jek­to­wa­ne­go sys­te­mu jeże­li np. jej speł­nie­nie jest ele­men­tem budo­wy prze­wa­gi ryn­ko­wej. Co to zna­czy? Że nie nale­ży opty­ma­li­zo­wać obec­ne­go mode­lu dzie­dzi­ny (np. pod­no­sze­nie wydaj­no­ści poprzez uprosz­cze­nie struk­tu­ry opi­su pro­duk­tów) a dodać do dzie­dzi­ny struk­tu­rę pozwa­la­ją­cą na wyko­ny­wa­nie pew­nych wybra­nych czyn­no­ści pro­ściej i szyb­ciej. To jed­nak temat o wzor­cu pro­jek­to­wym CQRS ale to temat na inny arty­kuł.

(inne źró­dła:

basic rules apply: Actors can only talk to boun­da­ry objects.Figure 3. Robustness Analysis RulesBoth boun­da­ry objects and enti­ty objects are nouns, and con­trol­lers are verbs. Nouns can’t talk to other nouns, but verbs can talk to either nouns or verbs. Boundary objects can only talk to con­trol­lers and actors. Entity objects can only talk to con­trol­lers. Controllers can talk to boun­da­ry objects and enti­ty objects, and to other con­trol­lers, but not to actors

źr. Memorandum).