Wprowadzenie

W arty­ku­le o apli­ka­cjach webo­wych, ponad rok temu, pisałem:

Generalnie klu­czo­wą cechą micro-ser­wi­­sów, czy­nią­cą z nich tak zwa­ną zwin­ną archi­tek­tu­rę, jest cał­ko­wi­ta wza­jem­na nie­za­leż­ność imple­men­ta­cji poszcze­gól­nych usług apli­ka­cyj­nych. (źr.: Aplikacje webo­we i mikro­ser­wi­sy czy­li archi­tek­tu­ra sys­te­mów webo­wych).

Przy innej oka­zji pisa­łem o wzorcach:

Wzorce pro­jek­to­we to bar­dzo waż­na część ??zawo­du? ana­li­ty­ka i archi­tek­ta opro­gra­mo­wa­nia. […] Generalnie wzor­ce są to ska­ta­lo­go­wa­ne stan­dar­dy i dobre prak­ty­ki . (Obiektowe wzor­ce projektowe ) 

Szkolenia dla ana­li­ty­ków poprze­dzam ankie­ta­mi przed szko­le­nio­wy­mi, jak do tej pory żad­na nie zawie­ra­ła pytań o wzor­ce pro­jek­to­we: ani tego że są uży­wa­ne ani tego, że są celem szko­le­nia, nie­mal­że każ­dy dekla­ru­je albo, że uży­wa UML lub, że chce zacząć uży­wać UML, nawet gdy są to pro­gra­mi­ści. Zauważyłem, że wzor­ce pro­jek­to­we w świa­do­mo­ści ana­li­zy biz­ne­so­wej i pro­jek­to­wa­nia (OOAD) nie ist­nie­ją”. Wśród pro­gra­mi­stów, jeże­li jest spo­ty­ka­na, to wie­dza o wzor­cach przy­dat­nych w two­rze­niu biblio­tek i narzę­dzi, czę­sto też powie­la­ne są wyuczo­ne sta­re i złe prak­ty­ki pro­gra­mi­stycz­ne rodem z lat 60-tych (np. prak­ty­ki SmallTalk, patrz dalej). 

Z dru­giej stro­ny od wie­lu lat zna­ne są tech­ni­ki MDA (Model Driven Architecture) czy MBSE (Model Based System Engineering), któ­re w róż­nych for­mach, ale jed­nak wska­zu­ją, że naj­sku­tecz­niej­sza for­ma wyra­ża­nia wyma­gań wobec roz­wią­za­nia to pro­jekt archi­tek­tu­ry i logi­ki dzie­dzi­no­wej (model) dzia­ła­nia apli­ka­cji . O pro­jek­to­wa­niu poprze­dza­ją­cym imple­men­ta­cję pisze sie od dość daw­na, meto­dy obiek­to­we i dobre prak­ty­ki zna­ne są od lat .

Autorzy BABoK prak­tycz­nie od począt­ku ist­nie­nia tego wydaw­nic­twa, zwra­ca­ją uwa­gę na tak zwa­ną bia­łą skrzyn­kę”, czy­li wyma­ga­nia wyra­żo­ne w posta­ci wewnętrz­nej struk­tu­ry pro­duk­tu, wska­zu­jąc, że to znacz­nie sku­tecz­niej­sza meto­da defi­nio­wa­nia wyma­gań wobec roz­wią­za­nia, niż tak zwa­na czar­na skrzyn­ka”, czy­li tra­dy­cyj­ne, i jed­nak mniej sku­tecz­ne, wyma­ga­nia wyra­żo­ne tyl­ko jako cechy funk­cjo­nal­ne i poza-funk­cjo­nal­ne. Pamiętajmy, że adre­sa­tem wyma­gań jest zawsze dostaw­ca produktu!

Kluczowe definicje

Architektura opro­gra­mo­wa­nia to pod­sta­wo­wa orga­ni­za­cja sys­te­mu wraz z jego kom­po­nen­ta­mi, wza­jem­ny­mi powią­za­nia­mi, śro­do­wi­skiem pra­cy i regu­ła­mi usta­na­wia­ją­cy­mi spo­sób jej budo­wy i rozwoju[IEEE Std 1471 – 2000, 2007]. Opis archi­tek­tu­ry opro­gra­mo­wa­nia (ang. Software Architecture Description) postrze­ga­ny jest jako plat­for­ma poro­zu­mie­wa­nia się wszyst­kich osób zaan­ga­żo­wa­nych w pro­ces wytwór­czy sys­te­mów informatycznych.

Generalnie wzo­rzec pro­jek­to­wy (ang. design pat­tern) w inży­nie­rii jest powszech­nie defi­nio­wa­ny jako: uni­wer­sal­ne, spraw­dzo­ne w prak­ty­ce roz­wią­za­nie. Kolejnym waż­nym poję­ciem jest poli­ty­ka. Z per­spek­ty­wy spo­so­bu postę­po­wa­nia, słow­nik języ­ka pol­skie­go defi­niu­je poli­ty­kę jako: zręcz­ne i układ­ne dzia­ła­nie w celu osią­gnię­cia okre­ślo­nych zamierzeń”. 

Polityka (poli­ty­ki) to poję­cie ogól­niej­sze niż wzo­rzec. Wyraża ona gene­ral­ne zasa­dy, te zaś dopie­ro impli­ku­ją sto­so­wa­nie okre­ślo­nych wzor­ców. Pozostaje ostat­nie już waż­ne poję­cie: para­dyg­mat: jest to przy­ję­ty spo­sób widze­nia rze­czy­wi­sto­ści w danej dzie­dzi­nie, dok­try­nie itp. Np. poli­ty­ką jest umo­wa (wyma­ga­nie), że sto­su­je­my wzor­ce a para­dyg­ma­tem to, że dowol­ną archi­tek­tu­rę budu­je­my z nie­za­leż­nych i samo­dziel­nych mniej­szych, współ­pra­cu­ją­cych elementów. 

Paradygmat obiek­to­wy pro­jek­to­wa­nia opro­gra­mo­wa­nia to przy­ję­cie zało­że­nia, że opro­gra­mo­wa­nie to współ­pra­cu­ją­ce obiek­ty (kom­po­nen­ty). Kluczową cechą obiek­tu jest to, że nie ujaw­nia on swo­jej wewnętrz­nej budo­wy (her­me­ty­za­cja) a jedy­ną for­mą współ­pra­cy obiek­tów jest ich reago­wa­nie na wza­jem­nie prze­ka­zy­wa­ne bodź­ce (wywo­ła­nia, obiekt ma okre­ślo­ne zacho­wa­nia, wię­cej w arty­ku­le: para­dyg­mat obiek­to­wy). Reakcja na bodziec i wynik tej reak­cji zale­ży od obiek­tu a nie od bodź­ca (poli­mor­fizm: np. szy­ba i dzwon ina­czej reagu­ją na iden­tycz­ne ude­rze­nie młotkiem). 

Definicja para­dyg­ma­tu obiek­to­we­go jest prak­tycz­nie toż­sa­ma z ogól­niej­szą defi­ni­cją, jaką jest defi­ni­cja poję­cia «sys­tem»: zespół logicz­nie powią­za­nych, współ­pra­cu­ją­cych ele­men­tów . Wielu auto­rów doda­je do tej defi­ni­cji w okre­ślo­nym celu”, co uwa­żam za nad­uży­cie, gdyż poję­cie cel ozna­cza czy­jeś świa­do­me dzia­ła­nie, zaś to, że ota­cza­ją­cy nas świat moż­na opi­sać (model) jako sys­tem, nie wyni­ka z tego, że ktoś go celo­wo tak stworzył.

Na koniec defi­ni­cja poję­cia pryn­cy­pium: naj­waż­niej­sza dla kogoś lub dla cze­goś zasa­da albo wartość. 

Wzorce projektowe czy polityki tworzenia architektury?

Podstawową, moim zda­niem, zasa­dą świa­do­me­go zacho­wa­nia jest jego celo­wość. Jeżeli więc sto­su­je­my (jakieś) wzor­ce pro­jek­to­we to nale­ży okre­ślić cel ich stosowania.

Nie ma sen­su sto­so­wa­nie jakich­kol­wiek wzor­ców dla same­go fak­tu ich sto­so­wa­nia, ale ich świa­do­me sto­so­wa­nie obni­ża ryzy­ko pro­jek­tu i popra­wia jego jakość.

Podstawowym celem inży­nie­rii jest pro­jek­to­wa­nie roz­wią­zań, a ich klu­czo­wą, poza-fun­cjo­nal­ną, cechą są kosz­ty utrzy­ma­nia i rozwoju. 

Wzorce pro­jek­to­we to przede wszyst­kim dobre prak­ty­ki obni­ża­ją­ce kosz­ty utrzy­ma­nia i rozwoju.

Postaram się poka­zać (posta­wić tezę), że gene­ral­nie cho­dzi o pew­ne okre­ślo­ne poli­ty­ki pro­jek­to­wa­nia archi­tek­tu­ry opro­gra­mo­wa­nia, a sku­pię się na spe­cy­fi­ce mode­li PIM .

Wzorce w literaturze

Literatura na temat wzor­ców pro­jek­to­wych jest bar­dzo boga­ta, myślę że czy­tel­nik łatwo do niej dotrze (patrz mój arty­kuł cyto­wa­ny na począt­ku). W tym tek­ście sku­pię się na bar­dzo waż­nym aspek­cie tych wzor­ców, jakim jest model dzie­dzi­ny sys­te­mu jako obszar ich stosowania. 

Znakomita więk­szość wzor­ców pro­jek­to­wych opi­sy­wa­nych w lite­ra­tu­rze, doty­czy obsza­ru Control i View archi­tek­tu­ry MVC. Stosowanie ich w obsza­rze Model jest bar­dzo czę­stym zja­wi­skiem wśród pro­gra­mi­stów. Powielanie prak­tyk zna­nych z zale­ceń C++ czy SmallTalk jest wręcz złym pomy­słem (patrz pod­su­mo­wa­nie). Czego więc powin­ni nauczyć się ana­li­ty­cy-pro­jek­tan­ci? Tylko tego co wpły­wa na kosz­ty utrzy­ma­nia i roz­wo­ju funk­cjo­nal­no­ści systemu. 

Środowiska wyko­naw­cze (biblio­te­ki, fra­me­wor­ki) zmie­nia­ją się dość wol­no. Upgrade śro­do­wi­ska ma miej­sce co kil­ka lat. Zmiany w funk­cjo­nal­no­ści opro­gra­mo­wa­nia wspie­ra­ją­ce­go zarza­dza­nie zacho­dzą w takt zmian pra­wa i ryn­ku: nawet kil­ka razy w cią­gu roku. Dlatego wła­śnie decy­zje o zasto­so­wa­niu tech­nik i wzor­ców pro­jek­to­wych nale­ży podej­mo­wać w kon­tek­ście tego czy pro­jek­tu­je­my: imple­men­ta­cję logi­ki biz­ne­so­wej czy śro­do­wi­sko apli­ka­cji. To dru­gie sta­wia wyłącz­nie wyma­ga­nia takie jak wydaj­ność i nie­za­wod­ność oraz kompatybilność.

Oprogramowanie biz­ne­so­we (mecha­nizm reali­za­cji logi­ki biz­ne­so­wej) ma nie tyl­ko dłu­gi cykl życia ale i bar­dzo burzliwy.

Dlatego do reali­za­cji Modelu Dziedziny (kom­po­nent reali­zu­ją­cy logi­kę biz­ne­so­wą) wyma­ga­ne jest inne podej­ście niż do reali­za­cji wyma­gań poza-funkcjonalnych. 

OCP jako miernik jakości architektury

Jedną z klu­czo­wych cech archi­tek­tu­ry speł­nia­ją­cej powyż­sze, eko­no­micz­ne, wyma­ga­nia jest zasa­da OCP (Open-Closed Principle): opro­gra­mo­wa­nie jest otwar­te na roz­sze­rze­nia, ale zamknię­te na zmia­ny. Oznacza to, że pro­jek­tant będzie mógł (powi­nien móc) doda­wać kolej­ne funk­cjo­nal­no­ści do kla­sy (kom­po­nen­tu, sys­te­mu), ale nie będzie edy­to­wał obec­nych już funk­cji w spo­sób, któ­ry wpły­wa na ist­nie­ją­cy pozo­sta­ły kod, któ­ry z nie­go korzy­sta. Zasada ta jest czę­ścią zesta­wu zasad zwa­nych SOLID, są wśród nich tak­że: zasa­da poje­dyn­czej odpo­wie­dzial­no­ści klas (ozna­cza jeden kon­tekst a nie jed­ną ope­ra­cję), zasa­da segre­ga­cji inter­fej­sów (to kon­se­kwen­cja poprzed­niej zasa­dy) . Autor tej publi­ka­cji, na pod­sta­wie swo­ich badań, pisze: 

Zgodnie z moimi bada­nia­mi i punk­ta­mi, któ­re omó­wi­li­śmy powy­żej, wnio­sek jest taki, że nie ma [nie są sto­so­wa­ne] żad­ne kon­kret­ne zasa­dy i regu­la­cje w pro­jek­to­wa­niu opro­gra­mo­wa­nia. Warto zauwa­żyć, że pro­jek­to­wa­nie jest sty­lem, jed­nak nie wszyst­kie sty­le prze­ba­da­łem. Zaobserwowałem, że pro­jek­tan­ci sto­su­ją róż­ne podej­ścia, np. ta sama agen­cja Narodów Zjednoczonych raz sto­su­je opi­sa­ne zasa­dy a raz nie. Nadal nie ma żad­nych zasad ani wska­zó­wek, któ­re sto­so­wa­ne były by we wszyst­kich przy­pad­kach, cho­ciaż, są pró­by sfor­ma­li­zo­wa­nia dąże­nia doskonałości”. 

Moje wie­lo­let­nie obser­wa­cje potwier­dza­ją powyż­sze spo­strze­że­nia: wzor­ce i meto­dy są od lat zna­ne, jed­nak rzad­ko są sto­so­wa­ne. Warto tu zwró­cić uwa­gę na fakt, że mamy rok 2021 a o wzor­cach mówi­my od począt­ków metod obiek­to­wych. Pozostaje pyta­nie: nie są powszech­nie sto­so­wa­ne bo nie są dobre, czy nie są sto­so­wa­ne bo wie­dza o nich jest nadal mało roz­po­wszech­nio­na. A może są inne powo­dy? Moim zda­niem wie­dza ta jest powszech­nie dostęp­na, ale nie jest popu­lar­na. Po dru­gie pro­mo­wa­nie zwin­no­ści (czy­li dro­ga na skró­ty) skut­ku­je tak­że ogra­ni­cza­niem prac ana­li­tycz­nych i pro­jek­to­wych w począt­ko­wym eta­pie pro­ce­su two­rze­nia opro­gra­mo­wa­nia, i tu upa­tru­ję głów­ne­go powo­du małej popu­lar­no­ści wzor­ców: wyma­ga­ją eta­pu ana­li­zy i pro­jek­to­wa­nia. Analiza i pro­jek­to­wa­nie pod­no­si pla­no­wa­ne kosz­ty wytwo­rze­nia, ale prak­ty­ka oka­zu­je nie jest praw­dą, że wydłu­ża czas do pierw­sze­go uru­cho­mie­nia. Nie jest tajem­ni­cą, że pierw­szy etap (jego koszt) czę­sto decy­du­je o wybo­rze dostaw­cy, jed­nak mści się to wie­lo­krot­nie na eta­pie utrzy­ma­nia i rozwoju.

Jaką war­tość wno­si sto­so­wa­nie wzor­ców? Pojawia się nastę­pu­ją­cy tok uza­sad­nie­nia ich użycia:

  1. wyznacz­ni­kiem jako­ści opro­gra­mo­wa­nia są kosz­ty w całym jego cyklu życia, a nie tyl­ko na eta­pie wytwa­rza­nia i wdrażania,
  2. klu­czem sta­je więc zasa­da OCP: opro­gra­mo­wa­nie jest otwar­te dla roz­sze­rze­nia, ale zamknię­te na zmia­ny, co w kon­se­kwen­cji pozwa­la na uzy­ska­nie linio­we­go (zamiast wykład­ni­cze­go) wzro­stu łącz­ne­go kosz­tu roz­wo­ju apli­ka­cji: pono­si­my koszt reali­za­cji nowej potrze­by, bez dodat­ko­we­go kosz­tu aktu­ali­za­cji (refak­to­ry­za­cja) już używanego,
  3. w kon­se­kwen­cji zamiast mono­li­tu, sto­su­je­my archi­tek­tu­rę kom­po­nen­to­wą (np. mikro ser­wi­sy, micro aplikacje),
  4. pod­sta­wo­wą jed­nost­ką pro­jek­to­wa­nia i roz­wo­ju sta­je się Usługa Aplikacji mode­lo­wa­na w UML jako Przypadek Użycia (np. patrz Use Case 2.0),
  5. z uwa­gi więc na to, że każ­dy przy­pa­dek uży­cia to odręb­ny, sepa­ro­wa­ny kom­po­nent, mają­cy swój wła­sny cykl życia, wyma­ga­ją­cy tak­że utrzy­ma­nia i roz­wo­ju, wymie­nio­ne zasa­dy (wzor­ce pro­jek­to­we) sto­su­je­my tak­że do pro­jek­to­wa­nia jego wewnętrz­nej architektury.

System to jego archi­tek­tu­ra oraz zacho­wa­nie (struk­tu­ra i reak­cja cało­ści na bodź­ce). Dlatego mówiąc o wzor­cach pro­jek­to­wych, mówi­my o wzor­cach archi­tek­to­nicz­nych i o wzor­cach zacho­wa­nia. W tym opra­co­wa­niu sku­pię się głów­nie na wzor­cach archi­tek­to­nicz­nych, o wzor­cach (zasa­dach) zacho­wa­nia wspomnę. 

Architektura oparta na wzorcach – po kolei

Umowa na zakres czyli jakie usługi – Orientacja na Przypadki Użycia

Na tym eta­pie podej­mu­je­my decy­zję «Co i dla kogo apli­ka­cja ma robić» (a nie JAK). 

Zakres pro­jek­tu pro­jek­to­wa­nia opro­gra­mo­wa­nia wyra­żo­ny w posta­ci usług apli­ka­cji (przy­pad­ki uży­cia sys­te­mu w nota­cji UML)

Diagram Przypadków Użycia to dia­gram pomoc­ni­czy w UML . Celem jego two­rze­nia jest zawar­cie umo­wy na to co ma powstać (usłu­gi) i dla kogo (aktor), czy­li komu i do cze­go ten sys­tem ma służyć. 

Bardzo waż­ne: tu wyma­ga­niem biz­ne­so­wym (usłu­ga apli­ka­cyj­na) jest to CO chce uzy­skać Aktor Systemu a nie to JAK to będzie reali­zo­wa­ne. Decyzja JAK jest decy­zją pro­jek­tan­ta roz­wią­za­nia, decy­zja CO jest usta­le­niem celu two­rze­nia opro­gra­mo­wa­nia. Usługa z per­spek­ty­wy Aktora, to opis reak­cji Systemu (sku­tek).

Zachowanie bar­dzo czę­sto doku­men­tu­je­my, począt­ko­wo nie­for­mal­nie, w posta­ci pro­ce­du­ry tek­sto­wej (np. wypunk­to­wa­na lista kolej­nych kro­ków). Kolejny etap to ite­ra­cyj­no-przy­ro­sto­wa for­ma­li­za­cja opi­su zacho­wa­nia z pomo­cą dia­gra­mu aktyw­no­ści lub sekwen­cji .

Diagram aktyw­no­ści to począt­ko­wo idea wza­jem­nej komu­ni­ka­cji kom­po­nen­tów, potem algo­ryt­my i mecha­ni­zmy. Diagram sekwen­cji poka­zu­je już wza­jem­ną komu­ni­ka­cję kom­po­nen­tów w posta­ci wywo­ły­wa­nych ope­ra­cji inter­fej­sów (na dia­gra­mach aktyw­no­ści tak­że moż­na to poka­zać, jed­nak dia­gram sekwen­cji jest tu znacz­nie łatwiej­szy do percepcji). 

Prostokąt Aplikacja” na powyż­szym sche­ma­cie, to czar­na skrzyn­ka” repre­zen­tu­ją­ca tę apli­ka­cję czy­li opro­gra­mo­wa­nie, któ­re ma powstać. Czy repre­zen­tu­je cały przy­szły kod? Nie, na tym eta­pie pro­jek­to­wa­nia mówi­my wyłącz­nie o logi­ce dzie­dzi­no­wej .

Architektura hexagonalna i wzorzec Model View Controler (MVC)

Podstawowym zało­że­niem jest tu sepa­ra­cja dzie­dzi­no­we­go mecha­ni­zmu dzia­ła­nia Aplikacji od śro­do­wi­ska w jakim dzia­ła . Mozna to zobra­zo­wać tak:

Środowisko wyko­naw­cze apli­ka­cji sta­je się coraz bar­dziej wyra­fi­no­wa­ne, obec­nie moż­na je zobra­zo­wać np. tak:

źr.: https://​her​ber​to​gra​ca​.com/​2​0​1​7​/​1​1​/​1​6​/​e​x​p​l​i​c​i​t​-​a​r​c​h​i​t​e​c​t​u​r​e​-​0​1​-​d​d​d​-​h​e​x​a​g​o​n​a​l​-​o​n​i​o​n​-​c​l​e​a​n​-​c​q​r​s​-​h​o​w​-​i​-​p​u​t​-​i​t​-​a​l​l​-​t​o​g​e​t​h​er/

Na dia­gra­mie powy­żej wyróż­nio­no trzy obszary:

  1. Application Core (cen­tral­ny obszar oto­czo­ny czer­wo­nym wielokątem).
  2. User Interface (obszar po lewej stro­nie ozna­czo­ny kolo­rem zielonym).
  3. Infrastructure (obszar po pra­wej stro­nie ozna­czo­ny kolo­rem pomarańczowym).

Powyższe odpo­wia­da wzor­co­wi MVC, odpo­wied­nio: Model, View, Controller. Projekt, w któ­rym ma powstać apli­ka­cja to tyl­ko” obszar ozna­czo­ny czer­wo­nym wie­lo­ką­tem, to co jest poza nim ist­nie­je” już jako sys­te­my ope­ra­cyj­ne, ste­row­ni­ki, biblio­te­ki, inne sys­te­my dzie­dzi­no­we. Dlatego jed­nym z naj­bar­dziej fał­szy­wych opi­sów MVC jest ten mówią­cy, że Model to (tyl­ko) model danych”, a Controller to (tyl­ko) regu­ły biznesowe”. 

Idąc tro­pem pro­ce­su MDA w dal­szej czę­ści opi­sa­na zosta­nie archi­tek­tu­ra Modelu czy­li mecha­ni­zmu dzia­ła­nia aplikacji. 

Architektura wysokiego poziomu” aplikacji 

Tak zwa­ną archi­tek­tu­rę wyso­kie­go pozio­mu (ang. HLD, High Level Design) budu­je­my już na bazie wzor­ca mówią­ce­go, że usłu­gi apli­ka­cji imple­men­tu­je­my jako odręb­ne kom­po­nen­ty, sepa­ru­je­my je tak­że od resz­ty oto­cze­nia. Idea ta nosi nazwę mikro­ser­wi­sów i jest zna­na od dość daw­na, jeden z naj­po­pu­lar­niej­szych chy­ba, zna­nych mi, sche­ma­tów blo­ko­wych poka­zu­je to tak:

About Microservices | Bee Travels
Monolit vs. mikroserwisy

Warto tu pod­kre­ślić, że kom­po­nen­ty reali­zu­ją­ce usłu­gi apli­ka­cje nie komu­ni­ku­ją się mię­dzy sobą. Więc nasza Aplikacja powin­na mieć np. taką wewnętrz­ną architekturę:

Architektura wyso­kie­go pozio­mu” sys­te­mu, wyra­żo­na jako dia­gram kom­po­nen­tów UML.

Komponenty reali­zu­ją­ce Usługi Aplikacji są inte­gro­wa­ne z uży­ciem API Koordynatora, zaś zewnętrz­ne usłu­gi są z zasa­dy izo­lo­wa­ne Adapterem. Na tym pozio­mie pro­sta sytu­acja może wyglą­dać tak:

Diagram sekwen­cji opi­su­ją­cy pro­sty dialog. 

Mamy tu pro­sty przy­pa­dek, gdy usłu­ga apli­ka­cji nie wyma­ga żad­nej wymia­ny danych mię­dzy kom­po­nen­ta­mi dziedzinowymi. 

Jednak może się zda­rzyć, że reali­za­cja jakiejś usłu­gi będzie wyma­ga­ła wymia­ny danych mię­dzy tymi kom­po­nen­ta­mi. Wtedy taki dia­log może wyglą­dać np. tak:

Realizacja usłu­gi wyma­ga­ją­cej inte­gra­cji wewnętrznej.

Powyższy dia­gram obra­zu­je dwa wzor­ce: SAGA, czy­li cała sekwen­cja inte­gra­cji, jako sce­na­riusz, jest ste­ro­wa­na z jed­ne­go dedy­ko­wa­ne­go do tego kom­po­nen­tu . Dzięki temu poszcze­gól­ne kom­po­nen­ty nie muszą wie­dzieć” nicze­go o sobie na wzajem. 

Komponent Adapter to bra­ma sepa­ru­ją­ca apli­ka­cję od jej oto­cze­nia. Zewnętrzne apli­ka­cje (np. inte­gro­wa­ne, świad­czą­ce usłu­gi itp.) mają API usta­lo­ne przez ich pro­du­cen­ta, mogą sie też zmie­niać w cza­sie, na co nie mamy żad­ne­go wpły­wu. Z tego powo­du auto­rzy czę­sto sto­su­ją tu zamien­nie lub łącz­nie nazwę tego wzor­ca: adapter/gateway.

Dlatego dobrą prak­ty­ką jest:

  1. sepa­ro­wa­nie ich od lokal­nej naszej logi­ki apli­ka­cji (her­me­ty­za­cja nasze­go kodu), 
  2. trans­for­ma­cja wywo­łań cudze­go API i zwra­ca­nych wyni­ków, to posta­ci opty­mal­nej z nasze­go punk­tu widzenia,
  3. poli­mor­fizm czy­li wywo­ły­wa­nie kom­po­nen­tów, tak że wynik zale­ży nie od nazwy pole­ce­nia a od tego jaki kom­po­nen­to zosta­nie wywołany.

Korzyści z tego podejścia:

  1. kupio­ne na ryn­ku kom­po­nen­ty goto­we (COTS, ang. com­mer­cial off the shelf) łatwo włą­czyć bo mają tyl­ko jeden styk z aplikacją,
  2. wymia­na kom­po­nen­tu na inny to tak­że tyl­ko inge­ren­cja w API lub napi­sa­nie adaptera,
  3. inte­gra­cja z zewnętrz­ny­mi apli­ka­cja­mi nie wyma­ga inge­ren­cji w pozo­sta­łe kom­po­nen­ty, wyma­ga co naj­wy­żej adaptera.

Wewnętrzna architektura komponentu realizującego usługę aplikacji

Jest to tak zwa­na archi­tek­tu­ra niskie­go pozio­mu (LLD, ang. Low Level Design). Na tym pozio­mie pro­jek­tu­je­my logi­kę reali­za­cji usługi. 

BCE

Już w latach 90-tych powstał wzo­rzec BCE (ang. Boundary, Control, Entity). Był wyko­rzy­sty­wa­ny w ramach dość cięż­kiej meto­dy­ki RUP (Rational Unified Process) oraz lek­kiej, zwin­nej, zwa­nej ICONIX . To były począt­ki orien­ta­cji na kom­po­nen­ty i przy­pad­ki uży­cia . Podział na kom­po­nen­ty oraz wzo­rzec (zasa­da) pro­jek­to­wa­nia zorien­to­wa­ny na odpo­wie­dzial­ność klas/komponentów, były kolej­nym zesta­wem dobrych prak­tyk .

Poniżej ilu­stra­cja z książ­ki Scotta Amblera (sygna­ta­riusz Agile Manifesto):

Nazwa Robustness dia­gram, to coś co moż­na tłu­ma­czyć jako bazo­wy model archi­tek­tu­ry” do dal­szych prac pro­jek­to­wych (rodzaj fun­da­men­tu na tym pozio­mie pro­jek­to­wa­nia). Wzorzec ten to umo­wa, że dowol­ny kom­po­nent (kla­sa) może reali­zo­wać: albo funk­cję inter­fej­su (boun­da­ry), albo reali­zo­wać okre­ślo­ną logi­kę dzie­dzi­no­wą (con­trol), albo reali­zo­wać funk­cję utrwa­la­nia dzie­dzi­no­wych danych (enti­ty). Dla uła­twie­nia szki­co­wa­nia, przy­ję­to że każ­dy z tych typów odpo­wie­dzial­no­ści będzie miał dedy­ko­wa­ny sym­bol, iko­nę (jak na rysun­ku powy­żej). Istotne jest tak­że to, że sym­bo­le te nie prze­wi­du­ją poka­zy­wa­nia atry­bu­tów, a jedy­nie ope­ra­cje. Obecne narzę­dzia CASE pozwa­la­ją na poka­za­nie atry­bu­tów, ale w począt­ko­wych eta­pach ana­liz i pro­jek­to­wa­nia nie ma takiej potrze­by, np. istot­ne jest to, że ist­nie­je taki byt jak fak­tu­ra, ale abso­lut­nie nie jest istot­ne to ile ma on atry­bu­tów i jakie one są. Liczy się jedy­nie to, że fak­tu­ra to treść opi­su­ją­ca trans­ak­cję kupna-sprzedaży). 

Łańcuch odpowiedzialności

Powyższy dia­gram to tak­że pre­zen­ta­cja wzor­ca Łańcuch odpo­wie­dzial­no­ści” . Wzorzec ten bazu­je na zasa­dzie poje­dyn­czej odpo­wie­dzial­no­ści oraz zało­że­niu, że nie pomi­ja­my żad­nej z nich. Efektem jest kaska­da (łań­cuch) odpo­wie­dzial­no­ści: kom­po­nent Boundary odpo­wia­da wyłącz­nie za dia­log z Aktorem (inter­fejs), kom­po­nent Control odpo­wia­da wyłącz­nie za reali­za­cję logi­ki biz­ne­so­wej (ste­ro­wa­nie), kom­po­nent Entity odpo­wia­da wyłącz­nie za utrwa­la­nie danych (pier­wot­nie były to obiek­ty DAO: ang. Data Access Object, sta­no­wią­ce sobą zapy­ta­nia SQL do rela­cyj­nych baz danych).

Repozytorium

Jest to model pro­jek­to­wa­nia, zakła­da­ją­cy, że dane nie wie­dzą komu wol­no je czy­tać” co ogrom­nie uprasz­cza ich struk­tu­rę. Schematycznie, korzy­sta­jąc z wzor­ca BCE, moż­na to przed­sta­wić tak:

Repozytorium

Komponent nazwa­ny Kontrola dostę­pu do doku­men­tów” to Repozytorium. To kom­po­nent, któ­ry sepa­ru­je dane od resz­ty apli­ka­cji, i jako jedy­ny zawie­ra tak­że regu­ły dostę­pu do nich. Ten kom­po­nent to tak­że jedy­ny inter­fejs do danych, więc dodat­ko­wo peł­ni rolę adap­te­ra: zmia­na miej­sca prze­cho­wy­wa­nia danych wyma­ga jedy­nie zmia­ny adre­sa­cji w tym komponencie. 

Ważne: repo­zy­to­rium nie two­rzy nowych obiek­tów, a jedy­nie je prze­cho­wu­je (patrz dalej: fabry­ki). Komunikacja mię­dzy Kontrola dostę­pu a Dokument zacho­wa­ny odby­wa się na bazie wzor­ca publish/subscribe .

Envelope – koperta

Zachowany doku­ment może być dowol­nym komu­ni­ka­tem XML, JSON itp. Jak poka­za­no w czę­ści opi­su­ją­cej archi­tek­tu­rę hek­sa­go­nal­ną, nie inte­re­su­je nas na tym eta­pie pro­jek­to­wa­nia fizycz­ny model danych. Wiemy jed­nak, że mogą one mieć nie­try­wial­ną struk­tu­rę. Zakładamy tak­że, że komu­ni­ka­cja mię­dzy kom­po­nen­ta­mi pole­ga na wymia­nie (tych) komu­ni­ka­tów, któ­re mogą być dowol­ną pacz­ką danych”, któ­rą to pacz­kę (np. jako ciąg zna­ków XML lub JSON) moż­na zacho­wać w cało­ści jako war­tość atry­bu­tu kom­po­nen­tu Entity .

Obiekt enti­ty jako kon­te­ner na komunikat

Obiekty Entity z zasa­dy nie reali­zu­ją żad­nej logi­ki biz­ne­so­wej, zacho­wu­ją jedy­nie dane, mają wyłącz­nie ope­ra­cje zapisz/przywołaj, two­rzo­ne i usu­wa­ne są przez poprze­dza­ją­ce je kom­po­nen­ty reali­zu­ją­ce logi­kę usłu­gi lub przez dodat­ko­wą usłu­gę, gdy zaj­dzie taka potrze­ba. Ewentualne dodat­ko­we atry­bu­ty słu­żą tu wyłącz­nie do indek­so­wa­nia .

Fabryki i metody wytwórcze

Tworzenie nowych obiek­tów to temat wie­lu dys­ku­sji. Jednak naj­czę­ściej poja­wia teza mówią­ca, że obiekt jed­nak nie two­rzy się sam. Druga teza to: repo­zy­to­rium (patrz wyżej) nie two­rzy obiek­tów, któ­re jedy­nie prze­cho­wu­je. One powsta­ją poza nim. Więc gdzie? Jedynym miej­scem, w jakim znaj­dzie­my kom­pe­ten­cje do two­rze­nia nowych obiek­tów, jest miej­sce w któ­rem jest wie­dza o tym czy są popraw­ne. Po trze­cie: czym jest komu­ni­kat (treść)? Może być obiek­tem okre­ślo­nej kla­sy, ale czy musi? Czy np. fak­tu­ra powin­na być obiek­tem okre­ślo­nej kla­sy, czy może jed­nak wystar­czy, że jako treść (bo to jest okre­ślo­na treść) umie­ści­my ją w koper­cie”?

Poniżej sce­na­riusz two­rze­nia nowe­go dokumentu:

Nowy doku­ment

Tu widać wszyst­kie zale­ty opi­sa­nych wzorców:

  1. logi­ka two­rze­nia i wali­da­cji tre­ści jest w jed­nym miejscu,
  2. repo­zy­to­rium dosta­je popraw­ne doku­men­ty i nie prze­cho­wu­je żad­nej logi­ki ich two­rze­nia ani sprawdzania,
  3. repo­zy­to­rium nie two­rzy doku­men­tów a jedy­nie miej­sce do ich prze­cho­wa­nia, dla­te­go może być imple­men­to­wa­ne dowol­nie, nawet jako sys­tem plików, 
  4. bez uszczerb­ku dla logi­ki apli­ka­cji dane mogą być w dowol­nym momen­cie wynie­sio­ne do chmu­ry”.

Architektura reali­zu­ją­ca powyż­sze wyglą­da tak:

Architektura LLD usługi

Agregat jako model danych

Agregat to drze­wia­sta struktura. 

Naturalną for­mą zarzą­dza­nia infor­ma­cją są doku­men­ty a nie rela­cyj­ne bazy danych”. 

Relacyjny model danych opra­co­wał Edgar Codd w 1970 roku, jego celem i klu­czo­wą zale­tą jest mecha­nizm spój­no­ści i trans­ak­cyj­no­ści zbio­ru danych (ACID). Model ten nie­ste­ty jest bar­dzo nie­na­tu­ral­ny z per­spek­ty­wy doku­men­tów: w mode­lu rela­cyj­nym ich po pro­stu nie ma. Warto pamię­tać, że:

Information Science inc­lu­des two fun­da­men­tal­ly dif­fe­rent tra­di­tions: a docu­ment” tra­di­tion con­cer­ned with signi­fy­ing objects and the­ir use; and a com­pu­ta­tio­nal” tra­di­tion of apply­ing algo­ri­th­mic, logi­cal, mathe­ma­ti­cal, and mecha­ni­cal tech­ni­qu­es to infor­ma­tion mana­ge­ment. Both tra­di­tions have been deeply influ­en­ced by tech­no­lo­gi­cal moder­nism: Technology, stan­dards, sys­tems and effi­cien­cy ena­ble pro­gress. Both tra­di­tions are needed. Information Science is rooted in part in huma­ni­ties and quali­ta­ti­ve social scien­ces. The land­sca­pe of Information scien­ce is com­plex. An ecu­me­ni­cal view is needed.” [Nauka o infor­ma­cji obej­mu­je dwie zasad­ni­czo róż­ne tra­dy­cje: tra­dy­cję doku­men­to­wą”, zaj­mu­ją­cą się opi­sy­wa­niem obiek­tów i ich wyko­rzy­sta­niem, oraz tra­dy­cję obli­cze­nio­wą”, pole­ga­ją­cą na zasto­so­wa­niu tech­nik algo­ryt­micz­nych, logicz­nych, mate­ma­tycz­nych i mecha­nicz­nych do zarzą­dza­nia infor­ma­cją. Obie tra­dy­cje zna­la­zły się pod głę­bo­kim wpły­wem moder­ni­zmu tech­no­lo­gicz­ne­go: Technologia, stan­dar­dy, sys­te­my i wydaj­ność umoż­li­wia­ją postęp. Obie tra­dy­cje są potrzeb­ne. Nauka o infor­ma­cji jest czę­ścio­wo zako­rze­nio­na w naukach huma­ni­stycz­nych i jako­ścio­wych naukach spo­łecz­nych. Krajobraz nauki o infor­ma­cji jest zło­żo­ny. Potrzebne jest spoj­rze­nie ekumeniczne.]

Dlatego są obsza­ry, w któ­rych model rela­cyj­ny spraw­dza sie dosko­na­le (obli­cze­nia) i obsza­ry, w któ­rych nie spraw­dza się wca­le (doku­men­ty). Poniżej struk­tu­ra hipo­te­tycz­ne­go doku­men­tu. Poziom zagnież­dżeń tre­ści może tu być dowolny:

Dokumentowa struk­tu­ra danych wyra­żo­na w posta­ci Diagramu Struktur Złożonych UML (źr. I jak to wszyst­kim poka­zać żeby było czy­tel­ne?)

Jeżeli zało­ży­my, że powyż­sze to struk­tu­ra pli­ku XML/JSON to jej zło­żo­ność nie ma zna­cze­nia, bo zawsze jest to pła­ski tekst (string). Powyższa struk­tu­ra wyra­żo­na jako pro­sty dia­gram klas w UML wyglą­da tak:

Drzewiasta struk­tu­ra doku­men­tu w posta­ci pro­ste­go dia­gra­mu klas UML

Powyższe jest typo­wym agre­ga­tem: toż­sa­mość nie­sie korzeń tej struk­tu­ry, pozo­sta­łe jej ele­men­ty nie muszą mieć toż­sa­mo­ści, gdyż moż­na do nich dotrzeć bez pro­ble­mu zna­jąc toż­sa­mość agre­ga­tu. Agregat sam dla sie­bie jest prze­strze­nią poję­cio­wą, podob­nie jak wewnętrz­ne sek­cje. Dlatego atry­bu­ty w róż­nych sek­cji mogą mieć takie same nazwy.

Zaletą korzy­sta­nia z agre­ga­tów jest łatwość mani­pu­lo­wa­nia nimi i zarzą­dza­nia ich cyklem życia. Dane nigdy nie są roz­sia­ne”. Bardzo dużym błę­dem jest ich mapo­wa­nie na rela­cyj­ne struk­tu­ry tabe­la­rycz­ne, gdyż to prak­tycz­nie nisz­czy wszyst­kie korzy­ści z ich sto­so­wa­nia (patrz: The One Question To Haunt Everyone: What is a DDD Aggregate? – Thomas Ploch – DDD Europe 2022).

Agregat i jego stan vs. status

To kolej­ny temat budzą­cy wie­le emo­cji. generalnie:

…stan obiek­tu to jego cecha, sta­tus obiek­tu to opis nie­bę­dą­cy cechą tego obiektu.

źr.: Kiedy maszy­na sta­no­wa a kie­dy jed­nak status?

Innymi sło­wy stan obiek­tu, jako jego cecha, jest zapi­sa­ny jako war­tość jed­ne­go z jego atry­bu­tów. Status obiek­tu, jako infor­ma­cja o nim, musi być zapi­sa­ny poza nim. Np. kolor ele­wa­cji budyn­ku to jego cecha, to będzie war­tość atry­bu­tu opi­su­ją­ce­go ten budy­nek. Jednak zadłu­żo­na hipo­te­ka tego budyn­ku nie jest jego cechą, jest osob­ną infor­ma­cją doty­czą­cą tego budyn­ku. Faktura od momen­tu jej utwo­rze­nia, jest nie­za­mie­nial­ną tre­ścią. Np. sal­do jej opła­ce­nia nie może być cechą fak­tu­ry, to stan kon­ta księ­go­we­go, prze­cho­wu­ją­ce­go sal­do tej faktury. 

Agregat to mniej lub bar­dziej zło­żo­ny opis fak­tu lub obiek­tu, ale nie nośnik jakiej­kol­wiek logi­ki opi­su­ją­cej ten obiekt lub fakt. Powyższe wzor­ce wła­śnie to reali­zu­ją: logi­ka biz­ne­so­wa jest poza repo­zy­to­rium prze­cho­wu­ją­cym agre­ga­ty w koper­tach”. Agregat to treść prze­cho­wu­ją­ca opis, koper­ta to miej­sce na zapi­sa­nie aktu­al­ne­go sta­tu­su tego co opi­su­je agre­gat umiesz­czo­ny w tej kopercie.

A co z Domain Driven Design (DDD)?

No wła­śnie, co z DDD? W swo­jej książ­ce z 2003 roku Evans opi­su­je pew­ne podej­ście do archi­tek­tu­ry. Opisał je sche­ma­tycz­nie tak:

Evans dekla­ru­je tu:

  1. przy­wią­za­nie do pro­jek­to­wa­nia opar­te­go na mode­lo­wa­niu (ang. Model Driven Design, MDD), ale to prak­tycz­nie to samo co MDA rodem z OMG​.org i UML. 
  2. izo­la­cje dzie­dzi­no­wej czę­ści od resz­ty (iso­la­te doma­in), ale to nic inne­go jak opi­sa­na archi­tek­tu­ra heksagonalna, 
  3. Smart UI – ale to nic inne­go jak wydzie­le­nie View w MVC,
  4. Services – ale to ele­men­ty logi­ki Control w opi­sa­nej BCE,
  5. Entities – ale to nośni­ki toż­sa­mo­ści w BCE o tej samej nazwie,
  6. Repositories – ale to opi­sa­ny wyżej zna­ny z innych źró­deł wzo­rzec, to tak­że ele­ment logi­ki Control w opi­sa­nej BCE,
  7. Agregates – ale to wzo­rzec opi­sa­ny wcze­śniej ,
  8. Value Object – ale to pozba­wio­ny toż­sa­mo­ści obiekt kla­sy Value opi­sa­ny wcze­śniej w UML,
  9. Factory – ale to kolej­na usłu­ga (Control w BCE), mają­ca jedy­nie okre­ślo­ny kon­tekst, niczym innym się nie wyróżnia. 

Niewątpliwym wkła­dem Evansa jest zwró­ce­nie uwa­gi na to co nazwał Ubiquitous language”:

Używając języ­ka opar­te­go na tym wzor­cu, zbli­ża­my się do mode­lu, któ­ry jest kom­plet­ny i zro­zu­mia­ły, skła­da­ją­cy się z pro­stych ele­men­tów, któ­re łączą się w celu wyra­że­nia zło­żo­nych pomy­słów.

Eksperci dzie­dzi­no­wi powin­ni sprze­ci­wiać się uży­wa­niu w pro­jek­cie pojęć, któ­re są nie­zgod­ne ze słow­nic­twem danej dzie­dzi­ny, zaś pro­gra­mi­ści powin­ni to usza­no­wać by nie powo­do­wać nie­jed­no­znacz­no­ści lub nie­spój­no­ści, któ­re pro­wa­dza do nieporozumień. 

E.Evans

NoSQL i dokumenty

Prawie 20 lat temu poja­wi­ły się bazy danych zwa­ne NoSQL (Not only SQL). Porównania poka­zu­ją też, że bazy NoSQL (np. doku­men­to­we) ofe­ru­ją znacz­nie szyb­szy dostęp do danych . Porównania poka­zu­ją, że czas zapi­su i dostę­pu do zło­żo­nych doku­men­tów w bazach NoSQL jest nawet o trzy rzę­dy (tysiąc­krot­nie!) krót­szy niż w bazach SQL .

Model rela­cyj­ny to sztyw­na struk­tu­ra i po utwo­rze­niu jest prak­tycz­nie nie­zmien­ny. Niestety w obec­nych cza­sach sta­bil­na na wie­le lat struk­tu­ra danych to prak­tycz­nie fik­cja. Po dru­gie udział danych struk­tu­ral­nych w ogól­nej ilo­ści zbie­ra­nych danych sta­le spa­da, oce­nia się, że obec­nie dane struk­tu­ral­ne to <10% ogó­łu zebra­nych danych (wie­dzy). Dokumenty biz­ne­so­we, ich struk­tu­ra, zmie­nia­ją sie wraz ze zmia­na­mi pra­wa i mode­li biz­ne­so­wych, czy­li nie raz nawet czę­ściej niż raz w roku. Dlatego opar­cie się na doku­men­to­wych wzor­cach jest obec­nie znacz­nie sku­tecz­niej­sze, mikro­ser­wi­sy zresz­tą z zasa­dy wyklu­cza­ją mono­li­tycz­ne rela­cyj­ne bazy danych (inte­gra­cja poprzez współ­dzie­le­nie danych).

Rezygnacja z mode­li rela­cyj­nych zna­ko­mi­cie uprasz­cza etap ana­li­zy i pro­jek­to­wa­nia, co widać np. w opi­sie archi­tek­tu­ry hek­sa­go­nal­nej jako wzor­ca (moto­ry baz danych są czę­ścią infra­struk­tu­ry a nie dzie­dzi­ny systemu). 

Notacja UML od lat dosko­na­le wspie­ra nie­esqe­lo­we” meto­dy pro­jek­to­wa­nia opro­gra­mo­wa­nia, w tym doku­men­to­we (w szcze­gól­no­ści XML) struk­tu­ry danych . Warto zazna­czyć, że UML nie słu­ży do mode­lo­wa­nia danych w mode­lu relacyjnym!

Dane, biz­ne­so­we w szcze­gól­no­ści, są orga­ni­zo­wa­ne w struk­tu­ry doku­men­to­we, jak wska­za­no powy­żej, jest to ich natu­ral­na postać (wię­cej na ten temat w arty­ku­le Struktury for­mu­la­rzy jako for­ma wyra­ża­nia wyma­gań).

Jak widać dane i ich struk­tu­ry (doku­men­ty) są cał­ko­wi­cie oddzie­lo­ne od metod ich two­rze­nia, korzy­ści z takie­go podej­ścia opi­su­je Evans w DDD, reko­men­da­cje takie moż­na zna­leźć u wie­lu innych auto­rów .

Projekt apli­ka­cji nie wyma­ga żad­ne­go SQL i rela­cyj­ne­go mode­lu. Na eta­pie pro­jek­to­wa­nia na pew­no nie, a na eta­pie imple­men­ta­cji obec­nie coraz czę­ściej tak­że już nie. 

Architektura usłu­gi to dość pro­sta struk­tu­ra. Każdy kon­kret­ny przy­pa­dek uży­cia (usłu­ga apli­ka­cji) może być nie­co inny, ale ogól­na idea zasto­so­wa­nia zasad: łań­cuch odpo­wie­dzial­no­ści (nie pomi­ja­my żad­ne­go kom­po­nen­tu w dro­dze od akto­ra do doku­men­tu), repo­zy­to­rium (inter­fejs do kolek­cji obiek­tów biz­ne­so­wych), i nowe zacho­wa­nia, to nowe a nie zmie­nio­ne, kom­po­nen­ty zorien­to­wa­ne na role. Całość daje bar­dzo przy­dat­ny zestaw tyl­ko kil­ku wzor­ców na eta­pie ana­li­zy i pro­jek­to­wa­nia mode­lu dzie­dzi­ny sys­te­mu (kom­po­nent reali­zu­ją­cy logi­kę biz­ne­so­wą, czy­li wyma­ga­nia funk­cjo­nal­ne, to Model Dziedziny Systemu) .

W real­nym pro­jek­cie każ­da kla­sa mia­ła­by oczy­wi­ście ope­ra­cje. Tu tego nie poka­zy­wa­łem by nie kom­pli­ko­wać dia­gra­mów. Przykład real­ne­go pro­jek­tu wyko­na­ne­go wg. powyż­szych reguł opi­sa­łem w arty­ku­le Inżynieria opro­gra­mo­wa­nia z uży­ciem narzę­dzia CASE ? przy­kła­do­wy pro­jekt. Szczegóły oma­wiam na szko­le­niach: Analiza obiek­to­wa i pro­jek­to­wa­nie logi­ki opro­gra­mo­wa­nia z uży­ciem nota­cji UML.

Podsumowanie

To co opi­sa­no to archi­tek­tu­ra kom­po­nen­to­wa zna­na od ponad 20 lat . Orientacja na odpo­wie­dzial­ność klas zna­na od 2003 roku, książ­ka Rebeki Wirfs-Brock jest cyklicz­nie wzna­wia­na . Także w 2003 roku, w duchu powyż­szych zasad, Eric Evans opi­sał wzo­rzec Domain Driven Design .

Problemem jaki dostrze­gam, jest uprosz­czo­na edu­ka­cja na stu­diach, zrów­nu­ją­ca pro­jek­to­wa­nie obiek­to­we z pro­gra­mo­wa­niem z uży­ciem języ­ków obiek­to­wych. To co nazy­wa­my pro­gra­mo­wa­niem obiek­to­wym (OOP) jest czę­sto defi­nio­wa­ne na bazie cech języ­ka C++: 

  1. Wszystko jest obiektem
  2. Każdy obiekt jest instan­cją klasy
  3. Każda kla­sa ma kla­sę nadrzędną
  4. Wszystko dzie­je się przez wysy­ła­nie wiadomości
  5. Wyszukiwanie metod uży­wa łań­cu­cha dziedziczenia

I to nie­ste­ty jest klu­czo­we źró­dło wie­lu pro­ble­mów. Punkt 3. jest jed­ną z naj­gor­szych i naj­kosz­tow­niej­szych prak­tyk w obsza­rze mode­lu dzie­dzi­ny, uza­leż­nia­ją­cych defi­ni­cje klas od sie­bie (łama­nie klu­czo­wej zasa­dy jaką jest her­me­ty­za­cja). Punkt 5 jest w zasa­dzie mar­twy, bo meto­dy albo są zna­ne bo wyma­ga­ne inter­fej­sem, albo nie wie­my, że są (kosz­tow­ne, osie­ro­co­ne ele­men­ty kodu w wie­lu sys­te­mach). Dziedziczenie z zasa­dy łamie her­me­ty­za­cję (współ­dzie­le­nie ele­men­tów kodu, przy­po­mi­nam, że dzie­dzi­cze­nie usu­nię­to z UML w 2015 roku). 

Tak więc para­dyg­mat obiek­to­wy to po pro­stu komu­ni­ku­ją­ce się, her­me­tycz­ne, obiek­ty i tak pro­jek­tu­je­my. Klasy to wyłącz­nie defi­ni­cje obiek­tów w kodzie źró­dło­wym, i tak kodu­je­my (UWAGA! Kod pro­gra­mu wyra­żo­ny w języ­ku obiek­to­wym to meta­mo­del dzia­ła­ją­ce­go programu!). 

Typowymi popu­lar­ny­mi i zły­mi prak­ty­ka­mi są umiesz­cza­nie metod kre­acyj­nych w ich kla­sach bazo­wych czy pobie­ra­nie i zapi­sy­wa­nie war­to­ści atry­bu­tów pole­ce­nia­mi get/set-atry­but. Szkodliwość tej dru­giej prak­ty­ki opi­sał Fowler w DTO . Fowler jest auto­rem jed­nej z naj­po­pu­lar­niej­szych na świe­cie pozy­cji o wzor­cach pro­jek­to­wych, mają­cej już kil­ka wzno­wień i aktu­ali­za­cji .

Jak poka­za­no, ana­li­za i pro­jek­to­wa­nie DOSKONALE oby­wa się bez SQL i rela­cyj­nych mode­li danych (nie uży­wam ich na eta­pie ana­li­zy i pro­jek­to­wa­nia od ponad 15 lat i nie jestem w tym osa­mot­nio­ny na świe­cie). Problem jaki stwa­rza­ją usil­nie pro­jek­to­wa­ne i reali­zo­wa­ne sys­te­mo­we rela­cyj­ne mode­le danych” jest zna­ny od dekad:

(Designing Object Systems: Object-Oriented Modelling with Syntropy Textbook Binding ? November 18, 1994 by Steve Cook (Author), John Daniels (Author))

Odejście od tej prak­ty­ki (mode­le danych i SQL od same­go począt­ku ana­li­zy i pro­jek­to­wa­nia) pozwa­la pro­jek­to­wać apli­ka­cje nie­za­leż­nie od metod imple­men­ta­cji, zro­zu­mia­łe dla inte­re­sa­riu­szy. Projekt roz­wią­za­nia na tym eta­pie (przed wybo­rem dostaw­cy) z zasa­dy powi­nien abs­tra­ho­wać od imple­men­ta­cji (jest to model PIM, nie­za­leż­ny od plat­for­my imple­men­ta­cji). Dzięki cze­mu cała doku­men­ta­cja, jeże­li zosta­nie napi­sa­na języ­kiem i słow­nic­twem inte­re­sa­riu­sza (patrz DDD), może być zro­zu­mia­ła dla niego. 

No i na koniec: chmu­ro­we sys­te­my utrwa­la­nia danych czę­sto nie ope­ru­ją języ­kiem SQL i rela­cyj­nym mode­lem danych, więc pora w koń­cu zapo­mnieć o SQL i rela­cyj­nie zor­ga­ni­zo­wa­nych danych na eta­pie ana­li­zy i pro­jek­to­wa­nia. Zresztą dużych trans­ak­cyj­nych sys­te­mów, nie­ko­rzy­sta­ją­cych z SQL i rela­cyj­ne­go sys­te­mu orga­ni­za­cji danych, jest bar­dzo dużo, nie tyl­ko sklep Amazon. 

Tak więc poniż­sze bazgro­ły nie są mode­lem dzie­dzi­ny systemu”:

Lista wzorców wykorzystana w artykule

  • BCE (Boundary, Control, Entity) – pro­jek­to­wa­nie zorien­to­wa­ne na odpo­wie­dzial­ność klas: B – pośred­ni­cze­nie pomię­dzy apli­ka­cją a jej oto­cze­niem, C – reali­za­cja logi­ki dzie­dzi­no­wej, E – utrwalanie,
  • agre­gat – prze­cho­wy­wa­nie danych w zwar­tej, her­me­tycz­nej, hie­rar­chicz­nej struk­tu­ry (np. jako doku­ment, np. JSON, XML),
  • saga – zarzą­dza­nie sce­na­riu­sza­mi (sekwen­cje, pro­ce­du­ry) z jed­ne­go miejsca,
  • łań­cuch odpo­wie­dzial­no­ści – kaska­do­we prze­ka­zy­wa­nie wywo­łań od inter­fej­su kom­po­nen­tu do danych z uży­ciem polimorfizmu,
  • repo­zy­to­rium – sepa­ro­wa­nie (her­me­ty­za­cja) danych i dostę­pu do danych od resz­ty aplikacji,
  • micro ser­wis (lub mikro-apli­ka­cja) – imple­men­ta­cja każ­dej usłu­gi sys­te­mu jako odręb­ne­go komponentu, 
  • adap­ter – izo­lo­wa­nie i unie­za­leż­nia­nie wewnętrz­nych kom­po­nen­tów apli­ka­cji od jej otoczenia, 
  • enve­lo­pe – prze­cho­wy­wa­nie danych (agre­gat) w indek­so­wa­nych prost­szych obiektach,
  • publish/subscribe – komu­ni­ka­cja np. pomię­dzy obiek­tem kon­tro­lu­ją­cym dostęp do danych a nośni­ka­mi tych danych (enti­ty) meto­dą wywo­ły­wa­nia ich po ID, 
  • wszyst­kie powyż­sze prak­tycz­nie doty­czą tak­że inte­gra­cji aplikacji. 

Dostępny jest warsz­tat, na któ­rym może w prak­ty­ce poznać te wzor­ce i prze­ćwi­czyć ich sto­so­wa­nie w prak­ty­ce: ZAPRASZAM. Wzorce DDD i BCE wyko­na­ne w UML: Dokumentacja DDD.

Źródła

Akehurst, D. H. (2004). Computer Science at Kent. Citeseer.
Ambler, S. W. (2002). Agile mode­ling. John Wiley & Sons.
Bertalanffy, L. (2003). General sys­tem the­ory: foun­da­tions, deve­lop­ment, appli­ca­tions (Rev. ed., 14. paper­back print). Braziller.
Cook, S., & Daniels, J. (1994). Designing object sys­tems: object-orien­ted model­ling with Syntropy. Prentice Hall.
D’Souza, D. (1998). Objects, Components, and Frameworks with UML The CatalysisTM Approach. 116.
Dennis, A., Wixom, B. H., & Roth, R. M. (2012). Systems ana­ly­sis and design (5th ed). John Wiley.
Dürr, K., Lichtenthäler, R., & Wirtz, G. (2021). An Evaluation of Saga Pattern Implementation Technologies. ZEUS, 74 – 82.
Evans, E. (2003). Domain-Driven Design. Pearson Education (US).
Fowler, M. (1997). Analysis pat­terns: reu­sa­ble object models. Addison Wesley.
Gamma, E. (Ed.). (1995). Design pat­terns: ele­ments of reu­sa­ble object-orien­ted softwa­re. Addison-Wesley.
Garba, M. (2020). A Comparison of NoSQL and Relational Database Management Systems (RDBMS). 1(2), 9.
Garcia-Molina, H., & Salem, K. (1987). Sagas. ACM Sigmod Record, 16(3), 249 – 259.
Győrödi, C., Győrödi, R., Pecherle, G., & Olah, A. (2015). A com­pa­ra­ti­ve stu­dy: MongoDB vs. MySQL. 2015 13th International Conference on Engineering of Modern Electric Systems (EMES), 1 – 6. https://​doi​.org/​1​0​.​1​1​0​9​/​E​M​E​S​.​2​0​1​5​.​7​1​5​8​433
IIBA. (n.d.). A Guide to the Business Analysis Body of Knowledge®. Retrieved October 30, 2021, from https://www.iiba.org/career-resources/a‑business-analysis-professionals-foundation-for-success/babok/
Jaiswal, M. (2019). Software Architecture and Software Design. International Research Journal of Engineering and Technology (IRJET) e‑ISSN, 2395 – 0056.
Jenney, J., Gangl, M., Kwolek, R., Melton, D., Ridenour, N., & Coe, M. (2010). Modern methods of sys­tems engi­ne­ering: with an intro­duc­tion to pat­tern and model based methods. Joe Jenney.
Lippert, M., Roock, S., & Züllighoven, H. (n.d.). From Documents to Applications via Frameworks: the Tools and Materials appro­ach. 2.
Michael Buckland. (1998). Landscape of Information Science: ASIS at 62. Berkeley Univerity of California. https://people.ischool.berkeley.edu/~buckland/asis62.html
Object Management Group. (2017, December). Unified Modeling Language (UML) [OMG​.org]. UML. https://​www​.omg​.org/​s​p​e​c​/​U​ML/
Object Management Group. (2014). Model Driven Architecture (MDA) MDA Guide rev. 2.0. Object Management Group. https://​www​.omg​.org/​c​g​i​-​b​i​n​/​d​o​c​?​o​r​m​s​c​/14 – 06-01.pdf
Osis, J., Asnina, E., & Grave, A. (2007). Formal Computation Independent Model of the Problem Domain within the MDA. ISIM.
Ozkaya, M., & Fidandan, I. (2020). MVCLang: A Software Modeling Language for the Model-View-Controller Design Pattern: Proceedings of the 15th International Conference on Software Technologies, 75 – 83. https://​doi​.org/​1​0​.​5​2​2​0​/​0​0​0​9​5​7​1​4​0​0​7​5​0​083
Rosenberg, D., & Scott, K. (1999). Use case dri­ven object mode­ling with UML. Springer.
Rosenberg, D., & Stephens, M. (2007). Introduction to ICONIX Process. Use Case Driven Object Modeling with UML: Theory and Practice, 1 – 20.
Rosenberg, D., Stephens, M., & Collins-Cope, M. (2005). Agile deve­lop­ment with ICONIX pro­cess: people, pro­cess, and prag­ma­tism. Apress.
Rosenberger, P., Gerhard, D., & Dumss, S. (2019). Modelling the Behaviour of Context-awa­re Systems: State-of-the-Art Analysis and Introduction of a Customized UML Profile. MODELSWARD, 519 – 526.
Š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).
Štefanko, M., Chaloupka, O., Rossi, B., van Sinderen, M., & Maciaszek, L. (2019). The Saga pat­tern in a reac­ti­ve micro­se­rvi­ces envi­ron­ment. Proc. 14th Int. Conf. Softw. Technologies (ICSOFT 2019), 483 – 490.
Wirfs-Brock, R., & McKean, A. (2009). Object design: roles, respon­si­bi­li­ties, and col­la­bo­ra­tions. Addison-Wesley.
Wirfs-Brock, R., & McKean, A. (2006). Object Design: Roles, Responsibilities and Collaborations,. 88.
Zelinski, J. (2020). Synthesis of MOF, MDA, PIM, MVC, and BCE Notations and Patterns. In Applications and Approaches to Object-Oriented Software Design: Emerging Research and Opportunities (pp. 78 – 89). IGI Global. https://​www​.igi​-glo​bal​.com/​b​o​o​k​/​a​p​p​l​i​c​a​t​i​o​n​s​-​a​p​p​r​o​a​c​h​e​s​-​o​b​j​e​c​t​-​o​r​i​e​n​t​e​d​-​s​o​f​t​w​a​r​e​/​2​3​5​699
Züllighoven, H., & Beeger, R. F. (2005). Object-orien­ted con­struc­tion hand­bo­ok: deve­lo­ping appli­ca­tion-orien­ted softwa­re with the tools & mate­rials appro­ach. Morgan Kaufmann ; dpunkt.verlag.

Jarosław Żeliński

Jarosław Żeliński: autor, badacz i praktyk analizy systemowej organizacji: Od roku 1991 roku, nieprzerwanie, realizuje projekty z zakresu analiz i projektowania systemów, dla urzędów, firm i organizacji. Od 1998 roku prowadzi samodzielne studia i prace badawcze z obszaru analizy systemowej i modelowania (modele jako przedmiot badań: ORCID). Od 2005 roku, jako nieetatowy wykładowca akademicki, prowadzi wykłady i laboratoria (ontologie i modelowanie systemów informacyjnych, aktualnie w Wyższej Szkole Informatyki Stosowanej i Zarządzania pod auspicjami Polskiej Akademii Nauk w Warszawie.) Oświadczenia: moje badania i publikacje nie mają finansowania z zewnątrz, jako ich autor deklaruję brak konfliktu interesów. Prawa autorskie: Zgodnie z art. 25 ust. 1 pkt. 1) lit. b) ustawy o prawie autorskim i prawach pokrewnych zastrzegam, że dalsze rozpowszechnianie artykułów publikowanych w niniejszym serwisie jest zabronione bez indywidualnej zgody autora (patrz Polityki Strony).

Dodaj komentarz

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.