Związki w UML czyli abstrakcja vs rzeczywistość

Wstęp

Tym razem o kil­ku powszech­nie popeł­nia­nych błę­dach w korzy­sta­niu z UML. Chodzi o poję­cia abs­trak­cji, meta­mo­de­li i zależ­no­ści oraz o związ­ki mię­dzy ele­men­ta­mi na dia­gra­mach. Kluczową, moim zda­niem, przy­czy­ną two­rze­nia złych” mode­li obiek­to­wych jest uży­wa­nie nota­cji UML do two­rze­nia mode­li struk­tu­ral­nych, nie mają­cych z obiek­to­wym para­dyg­ma­tem nic wspól­ne­go. Druga to nie­zro­zu­mie­nie poję­cia para­dyg­ma­tu obiek­to­we­go. Ogromna ilość dia­gra­mów wyko­na­nych z uży­ciem sym­bo­li nota­cji UML, z UML i para­dyg­ma­tem obiek­to­wym ma nie­wie­le wspólnego.

Najpierw kil­ka defi­ni­cji i pojęć.

Paradygmat pro­gra­mo­wa­nia (ang. pro­gram­ming para­digm) ? wzo­rzec pro­gra­mo­wa­nia kom­pu­te­rów przed­kła­da­ny w danym okre­sie roz­wo­ju infor­ma­ty­ki ponad inne lub cenio­ny w pew­nych oko­licz­no­ściach lub zasto­so­wa­niach. (Źródło: Paradygmat pro­gra­mo­wa­nia ? Wikipedia, wol­na ency­klo­pe­dia)

No to teraz obiek­to­wy paradygmat:

Programowanie obiek­to­we (ang. object-orien­ted pro­gram­ming) ? para­dyg­mat pro­gra­mo­wa­nia, w któ­rym pro­gra­my defi­niu­je się za pomo­cą obiek­tów ? ele­men­tów łączą­cych stan (czy­li dane, nazy­wa­ne naj­czę­ściej pola­mi) i zacho­wa­nie (czy­li pro­ce­du­ry, tu: meto­dy). Obiektowy pro­gram kom­pu­te­ro­wy wyra­żo­ny jest jako zbiór takich obiek­tów, komu­ni­ku­ją­cych się pomię­dzy sobą w celu wyko­ny­wa­nia zadań. Podejście to róż­ni się od tra­dy­cyj­ne­go pro­gra­mo­wa­nia pro­ce­du­ral­ne­go, gdzie dane i pro­ce­du­ry nie są ze sobą bez­po­śred­nio zwią­za­ne. (Źródło: Programowanie obiek­to­we ? Wikipedia, wol­na ency­klo­pe­dia)

albo:

Programowanie obiek­to­we lub ina­czej pro­gra­mo­wa­nie zorien­to­wa­ne obiek­to­wo (ang. object-orien­ted pro­gra­ming, OOP) to para­dyg­mat pro­gra­mo­wa­nia przy pomo­cy obiek­tów posia­da­ją­cych swo­je wła­ści­wo­ści jak pola (dane, infor­ma­cje o obiek­cie) oraz meto­dy (zacho­wa­nie, dzia­ła­nia jakie wyko­nu­je obiekt). Programowanie obiek­to­we pole­ga na defi­nio­wa­niu obiek­tów oraz wywo­ły­wa­niu ich metod, tak aby współ­dzia­ła­ły wza­jem­nie ze sobą. (Źródło: Programowanie obiek­to­we ? Encyklopedia Zarządzania

Słownik języ­ka pol­skie­go mówi:

współ­dzia­łać
1. ?dzia­łać wspól­nie z kimś?
2. ?przy­czy­niać się do cze­goś razem z inny­mi czyn­ni­ka­mi?
3. ?o mecha­ni­zmach, narzą­dach itp.: funk­cjo­no­wać w powią­za­niu z innymi?

wywo­łać ? wywo­ły­wać
1. ?woła­niem skło­nić kogoś do wyj­ścia skądś?
2. ?przy­po­mnieć sobie lub innym coś?
3. ?spo­wo­do­wać coś lub stać się przy­czy­ną cze­goś?
4. ?oznaj­mić coś publicz­nie?
5. ?oddzia­łać na kli­szę, bło­nę lub papier foto­gra­ficz­ny środ­ka­mi che­micz­ny­mi w celu uwi­docz­nie­nia obra­zu uta­jo­ne­go na mate­ria­le światłoczułym?

Tak więc stwier­dze­nie, że obiek­ty z sobą współ­dzia­ła­ją” ozna­cza, że wywo­łu­ją się” wza­jem­nie w celu spo­wo­do­wa­nia cze­goś kon­kret­ne­go. Innymi sło­wy obiek­ty two­rzą­ce pro­gram (sys­tem) są od sie­bie wza­jem­nie uza­leż­nio­ne. Dlatego pod­sta­wo­wym związ­kiem w pro­ce­sie ana­li­zy i pro­jek­to­wa­nia zorien­to­wa­ne­go obiek­to­wo jest wza­jem­na zależ­ność”, nazy­wa­na w ory­gi­nal­nej spe­cy­fi­ka­cji UML związ­kiem usłu­go­daw­ca-usłu­go­bior­ca”.

Zależności

Związek ten nale­ży utoż­sa­miać z każ­dą wza­jem­ną zależ­no­ścią. Z uwa­gi na to, że mamy wie­le typów zależ­no­ści, wska­zu­je­my kon­kret­ny typ z pomo­cą ste­reo­ty­pu («[nazwa_typu]»).

Najczęściej wystę­pu­ją­cy typ zależ­no­ści to zwią­zek uży­cia. Oznacza on, że jeden obiekt wywo­łu­je umie­jęt­no­ści (ope­ra­cje) inne­go czy­li uży­wa go” do reali­za­cja swo­je­go zada­nia. Związek taki ozna­cza­ny ste­reo­ty­pem «use»:

uml-diagram-klas-zwiazek-uzycia

F uży­wa (jest zależ­ny od) E (co do zasa­dy tu F nie jest samo­dziel­ny w tym co robi”).

Formą zależ­no­ści jest tak­że dość rzad­ko wyko­rzy­sty­wa­na abs­trak­cja («Abstraction»). Związek ten jest wyko­rzy­sty­wa­ny do łącze­nia dwóch pojęć, z któ­rych jed­no jest abs­trak­cją dru­gie­go. Inna czę­sto wyko­rzy­sty­wa­na zależ­ność to «instanceOf» ozna­cza zależ­ność mode­lu (obiek­tu) od jego meta­mo­de­lu (kla­sy­fi­ka­to­ra) a tak­że od meta­me­ta­mo­de­lu.

Tak więc model opro­gra­mo­wa­nia w nota­cji UML z uży­ciem obiek­to­we­go para­dyg­ma­tu powi­nien wyglą­dać mniej wię­cej tak:

Wzorzec BCE

Na dia­gra­mie uży­to sym­bo­li klas (gra­ficz­na repre­zen­ta­cja ste­reo­ty­pów) zaczerp­nię­tych wzor­ca archi­tek­to­nicz­ne­go BCE.

Realizacja i kompozycja

Dokumentowanie deta­li struk­tu­ry ele­men­tów np. repo­zy­to­rium, wyma­ga stwo­rze­nia kolej­ne­go dia­gra­mu: mode­lu struk­tu­ry obiek­tów repre­zen­tu­ją­cych np. zło­żo­ną struk­tu­rę obiek­tu nio­są­ce­go infor­ma­cje (np. z formularza).

uml-diagram-klas-zwiazki-realizacja

Korzystamy tu ze związ­ku reali­za­cja i związ­ku kom­po­zy­cja. Realizacja to zwią­zek pomię­dzy spe­cy­fi­ka­cją a jej reali­za­cją (pro­jek­tem, imple­men­ta­cją, itp.), wska­zu­je zależ­ność imple­men­ta­cji od jej mode­lu. C2 jest spe­cy­fi­ka­cją (opi­sem, doku­men­ta­cją) reali­za­cji D2. Najczęściej zwią­zek ten jest sto­so­wa­ny pomię­dzy spe­cy­fi­ka­cją inter­fej­su a jego imple­men­ta­cją a tak­że gene­ral­nie pomię­dzy abs­trak­cją a jej reali­za­cją. Typowym przy­kła­dem uży­cia tego związ­ku jest np. poka­za­nie na jed­nym dia­gra­mie abs­trak­cji bytu w repo­zy­to­rium i reali­za­cji jej struktury:

model-dziedziny-realizacja-repozytorium

Na dia­gra­mie uży­to tak­że związ­ku całość-część”: linia zakoń­czo­na wypeł­nio­nym rom­bem na jed­nym koń­cu. Romb wska­zu­je na całość”: ele­ment nad­rzęd­ny drze­wia­stej struk­tu­ry kon­struk­cji. Jest to spe­cjal­ny zwią­zek ozna­cza­ją­cy trwa­łe (kon­struk­cyj­ne) powią­za­nie pomię­dzy deta­la­mi skła­da­ją­cy­mi się na okre­ślo­ną całość. UWAGA! Nie ma on nic wspól­ne­go z poję­ciem rela­cji” zna­nym z teo­rii rela­cyj­nych baz danych!

Biorąc pod uwa­gę fakt, jakim jest her­me­ty­za­cja jako cecha obiek­to­wych kon­struk­cji, takie enti­ties” nie współ­dzie­lą mie­dzy sobą ŻADNYCH ele­men­tów (danych). Użycie na dnie” bazy danych, wspól­nej dla całej apli­ka­cji, bazy dopro­wa­dzo­nej do tak zwa­nej znor­ma­li­zo­wa­nej posta­ci, łamie wszel­kie zasa­dy obiek­to­wych kon­struk­cji: łamie pod­sta­wo­wą zasa­dę jaką jest her­me­ty­za­cja imple­men­ta­cji obiek­tów (zakaz jakie­go­kol­wiek współ­dzie­le­nia cze­go­kol­wiek, nie nale­ży mylić współ­dzie­le­nia z re-użyciem).

Generalizacja i asocjacja

Oprócz mode­li struk­tur, powsta­ją czę­sto mode­le poję­cio­we. Są to odręb­ne dia­gra­my. Ich celem jest doku­men­to­wa­nie związ­ków seman­tycz­nych i syn­tak­tycz­nych pomię­dzy klu­czo­wy­mi poję­cia­mi wyko­rzy­sty­wa­ny­mi w pro­jek­cie. Stanowią one nazwy obiek­tów i ich typy (atry­bu­ty klas to tak­że obiek­ty). Wykorzystywane są tu dwa rodza­je związ­ków: gene­ra­li­za­cja i aso­cja­cja. Są to związ­ki repre­zen­tu­ją­ce WYŁĄCZNIE logicz­ne powią­za­nia pomię­dzy poję­cia­mi, nie mode­lu­ją one struk­tur a ni implementacji!

Jeżeli jakieś poję­cie ma swo­je spe­cja­li­zo­wa­ne typy, lub z dru­giej stro­ny, gru­pa pojęć daje się uogól­nić innym nad­rzęd­nym poję­ciem (gene­ra­li­zo­wa­nie), sto­su­je­my zwią­zek gene­ra­li­za­cji. Związek ten (korzy­sta­nie z nie­go) ma sens tyl­ko gdy licz­ba typów to co naj­mniej dwa, co do zasa­dy zwią­zek gene­ra­li­za­cji słu­ży do gru­po­wa­nia. Jeżeli pomię­dzy poję­cia­mi ist­nie­je zwią­zek wyni­ka­ją­cy z dzie­dzi­ny pro­ble­mu (np. zwią­zek pomię­dzy zwie­rzę­ciem a kar­mą dla nie­go) mode­lu­je­my go linią cią­głą łączą­cą powią­za­ne tak poję­cia. Poniżej gra­ficz­ny przy­kład uży­cia tych związków:

zwiazki-generalizacji-i-asocjacje-w-modelu-pojeciowym

B1 i B2 to kon­kret­ne typy poję­cia A (typem jest tak­że poję­cie). Analogicznie B12 i B22 to typy poję­cia A3. Pomiędzy poję­cia­mi A i A3 ist­nie­je zwią­zek logicz­ny (moż­na go nazwać, wpi­su­jąc te nazwę na linii). Typy mogą mieć wię­cej niż jeden kon­tekst dla­te­go mogą zostać pogru­po­wa­ne a każ­da gru­pa otrzy­mu­je nazwę nazwa gru­py” (oryg. Generalization Sets). Nie ma sen­su zwią­zek gene­ra­li­za­cji pomię­dzy tyl­ko jed­ną parą pojęć, bo ozna­cza wte­dy po pro­stu toż­sa­mość. Np. poję­cie woje­wódz­two” w Polsce ma obec­nie szes­na­ście spe­cja­li­za­cji, mają one swo­je nazwy, i to jest jed­na gru­pa typów. Jednak woje­wódz­twa moż­na podzie­lić tak­że np. ze wzglę­du na wiel­kość na np. trzy gru­py: małe woje­wódz­two, śred­nie woje­wódz­two i duże woje­wódz­two, i to będzie dru­ga i nie­za­leż­na gru­pa typów.

Modele…

Wszystkie powyż­sze przy­kła­dy to dia­gra­my klas nota­cji UML, jed­nak jak widać każ­dy ma zupeł­nie inne prze­zna­cze­nie (jest mode­lem cze­go inne­go). Nie oma­wia­łem tu zupeł­nie dia­gra­mów klas mode­lu­ją­cych kod pro­gra­mów. Zaznaczę jedy­nie, że są to kolej­ne mode­le doku­men­to­wa­ne z uży­ciem dia­gra­mów klas nota­cji UML, i omó­wio­ne powy­żej związ­ki dzie­dzi­cze­nia i aso­cja­cje na mode­lach poję­cio­wych mają tam zupeł­nie inne znaczenie.

Modele mogą być róż­ne i doty­czyć róż­nych rze­czy (patrz Modele.…). Tu chcę zwró­cić uwa­gę na bar­dzo waż­ny aspekt: abs­trak­cyj­ne i rze­czy­wi­ste poję­cia w mode­lach (na dia­gra­mach). Dostrzegam ogrom­ny bała­gan nie tyl­ko w doku­men­tach pro­jek­to­wych ale tak­że i w lite­ra­tu­rze, gdzie auto­rzy poka­zu­ją wie­le róż­nych przy­kła­dów, któ­re nie­ste­ty są złe i pozba­wio­ne uzasadnienia.

Przede wszyst­kim mode­le dzie­li­my, jak już wspo­mnia­łem, na poję­cio­we i te mode­lu­ją­ce jakąś okre­ślo­ną rze­czy­wi­stość. Modele poję­cio­we to mode­le poka­zu­ją­ce poję­cia oraz seman­tycz­ne i syn­tak­tycz­ne związ­ki mie­dzy nimi. Modele poję­cio­we słu­żą do udo­ku­men­to­wa­nia dzie­dzi­no­wej tak­so­no­mii co z jed­nej stro­ny pozwa­la utrzy­mać peł­ną jed­no­znacz­ność doku­men­ta­cji a z dru­giej, na eta­pie imple­men­ta­cji, pozwa­la podej­mo­wać decy­zje o typach danych. Służą one np. do budo­wa­nia słow­ni­ków i ety­kie­to­wa­nia np. pól for­mu­la­rzy (pole Nazwa woje­wódz­twa, któ­re­go zawar­tość będzie wybie­ra­na ze słow­ni­ka zawie­ra­ją­ce­go szes­na­ście nazw). Na tych mode­lach poja­wia­ją się w zasa­dzie wyłącz­nie poję­cia sta­no­wią­ce abs­trak­cje i typy, nie są to mode­le żad­ne­go kodu, dzie­dzi­ny itp. Tu przy­po­mnę, że model dzie­dzi­ny sys­te­mu to model opi­su­ją­cy mecha­nizm jego (sys­te­mu, apli­ka­cji) dzia­ła­nia, repre­zen­to­wa­ny jest przez liter­kę M we wzor­cu MVC, poważ­nym błę­dem jest uzna­wa­nie tych mode­li za mode­le danych.

Modele struk­tu­ry to mode­le opi­su­ją­ce okre­ślo­ne kon­struk­cje”, głów­nie na dwóch pozio­mach abs­trak­cji: jako model i jako meta­mo­del. Z regu­ły, w pro­jek­tach zwią­za­nych z opro­gra­mo­wa­niem, ta kon­struk­cja to wła­śnie Model Dziedziny czy­li mecha­nizm dzia­ła­nia, tak zwa­na logi­ka biznesowa/dziedzinowa aplikacji.

Podsumowanie

Tak więc nie ma cze­goś takie­go jak dia­gram klas dla pro­jek­tu”. Mamy dla dane­go pro­jek­tu: model poję­cio­wy, mode­le logi­ki sys­te­mu, mode­le struk­tu­ry obiek­tów, mode­le imple­men­ta­cji. To wszyst­ko są dia­gra­my klas ale każ­dy z nich do model cze­goś inne­go”. Paradygmat obiek­to­wy jasno mówi: obiek­ty współ­pra­cu­ją, więc stan­dar­do­wym związ­kiem w mode­lach logi­ki dzia­ła­nia są związ­ki uży­cia a nie aso­cja­cje ani związ­ki dzie­dzi­cze­nia czy kom­po­zy­cji. Diagramy te nie są żad­ny­mi mode­la­mi danych mię­dzy inny­mi dla­te­go, że z zasa­dy para­dyg­mat obiek­to­wy ukry­wa je (her­me­ty­za­cja), na zewnątrz” dostęp­ne są wyłącz­nie publicz­ne ope­ra­cje obiek­tów. Utrwalanie obiek­tów (zapis war­to­ści atry­bu­tów np. w bazie danych) to zada­nie do roz­wią­za­nia dopie­ro na eta­pie imple­men­ta­cji, pole­ga­ją­ce na zagwa­ran­to­wa­niu zacho­wa­nia” sta­nów obiek­tów na czas wyłą­cze­nia zasi­la­nia, by nie ule­cia­ły” z pamię­ci kom­pu­te­ra, któ­ry jest śro­do­wi­skiem wyko­na­nia pro­gra­mu. Na eta­pie ana­li­zy obiek­to­wej i mode­lo­wa­nia logi­ki sys­te­mu nie mode­lu­je­my żad­nych danych.

Poniższy przy­kład, jakich wie­le w sie­ci, jest wzor­co­wym antyprzykładem.

(https://​www​.wie​dza​na​plus​.pl/​p​r​o​g​r​a​m​o​w​a​n​i​e​/​3​3​-​u​m​l​/​6​8​-​j​e​z​y​k​-​u​m​l​-​p​r​o​j​e​k​t​-​s​k​l​e​p​u​-​k​o​m​p​u​t​e​r​o​w​e​g​o​.​h​tml)

Pierwsza zła cecha tego dia­gra­mu to czę­sty błąd nazy­wa­ny popu­lar­nie prze­cią­ża­niem obiek­tów”: tu obiekt Faktura ma ope­ra­cje spo­rządź”. Klasyczny błąd archi­tek­to­nicz­ny pole­ga­ją­cy na obcią­ża­niu obiek­tu cudzą odpo­wie­dzial­no­ścią. Jeżeli kla­sa Faktura repre­zen­tu­je np. fak­tu­ry sprze­da­ży, to sys­tem mają­cy w pamię­ci kolek­cję setek fak­tur i każ­da z kodem (ma te ope­ra­cję) słu­żą­cym do jej spo­rzą­dze­nia był­by masa­krą zaję­to­ści pamię­ci. Dodam, że model taki nie ma nic wspól­ne­go z rze­czy­wi­sto­ścią, bo fak­tu­ry wysta­wia ktoś” a nie fak­tu­ra”. Trzecia rzecz: fak­tu­ra zaku­pu i fak­tu­ra sprze­da­ży to niczym nie róż­nią­ce się struk­tu­ry, więc two­rze­nie takie­go roz­róż­nie­nia jest pozba­wio­ne sen­su. To błę­dy poję­cio­we i ten dia­gram ma masę takich błę­dów. Druga wada: błęd­ne uży­cie związ­ku kom­po­zy­cji: powyż­szy dia­gram nale­ża­ło­by inter­pre­to­wać jako struk­tu­rę o jed­nej zwar­tej kon­struk­cji, np. takiej jak samo­chód skła­da­ją­cy się z setek pod­ze­spo­łów ale sta­no­wią­cy jed­nak jed­ną całość. Brak mode­lu poję­cio­we­go i słow­ni­ka powo­du­je wie­le nie­jed­no­znacz­no­ści. Np. zwią­zek pomię­dzy Klientem a rekla­ma­cją wska­zu­je, że Reklamacje są inte­gral­ną czę­ścią Klienta (tak jak koła i sil­nik są inte­gral­ną czę­ścią samo­cho­du) co nawet w świe­tle potocz­ne­go rozu­mie­nia tych słów kłó­ci się ze zdro­wym rozsądkiem.

Użycie związ­ków poję­cio­wych (aso­cja­cja) jest zupeł­nie nie­zro­zu­mia­łe w tym przy­pad­ku. Nazwa aso­cja­cji zawie­ra” nie ma kie­run­ku a więc nie wia­do­mo co jest zawar­te w czym. Związki zależ­no­ści tak­że są nie­ja­sne: jak inter­pre­to­wać np. zapis mówią­cy, ze obiek­ty kla­sy użyt­kow­ni­cy zale­żą od obiek­tów kla­sy Raporty? Jeżeli autor miał na myśli użyt­kow­nik uży­wa rapor­tów” to popły­nął w sfe­rę mowy potocz­nej”, to chy­ba naj­czę­ściej spo­ty­ka­ny błąd pole­ga­ją­cy na tym, że autor dia­gra­mu nadal pisze spe­cy­fi­ka­cję pro­zą, ale z uży­ciem sym­bo­li (tu UML) zamiast słów.

Mogę się jedy­nie domy­ślać, że autor dia­gra­mu miał w gło­wie” model rela­cyj­ny związ­ków encji i użył ikon z nota­cji UML w cał­ko­wi­cie innych zna­cze­niach niż ta nota­cja defi­niu­je. Takie dia­gra­my nie powin­ny powsta­wać, są one nie­ste­ty dowo­dem na to, że pro­gra­mi­ści mówią­cy te doku­men­ty z UML nic nie wyja­śnia­ją i są nie­pre­cy­zyj­ne, i tak musi­my sami powtó­rzyć te ana­li­zę” mają rację. Są tak­że dowo­dem, że są to jed­nak pro­jek­ty struk­tu­ral­ne a nie obiek­to­we, a uży­cie nota­cji UML pole­ga­ło na sko­rzy­sta­niu z zesta­wu ikon tak się to robi two­rząc nie­sfor­ma­li­zo­wa­ne sche­ma­ty blo­ko­we z uży­ciem np. pro­gra­mów do two­rze­nia pre­zen­ta­cji takich jak PowerPoint. Zapewne poza auto­rem tego dia­gram, nikt nie ma poję­cia o co w nim cho­dzi.… Jeżeli autor miał na celu udo­ku­men­to­wa­nie mode­lu danych” to powi­nien użyć nota­cji ERD. A tak to mamy sche­mat blo­ko­wy, w któ­rym ktoś użył UML jako biblio­te­ki sym­bo­li wpro­wa­dza­jąc czy­tel­ni­ka w błąd.

Z przy­kro­ścią muszę przy­znać, że od takich błę­dów nie są wol­ne tak­że nie­któ­re pod­ręcz­ni­ki i mate­ria­ły szko­le­nio­we… a tak­że doku­men­ty two­rzo­ne przez pra­cow­ni­ków wie­lu firm na ryn­ku IT.

P.S.

Na przy­kła­dy popraw­nych dia­gra­mów z uza­sad­nie­niem zapra­szam do mojej książ­ki i na moje szko­le­nia i warsz­ta­ty.

Specyfikacja UML v.2.5

Niestety spraw­ne” korzy­sta­nie z takich spe­cy­fi­ka­cji wyma­ga umie­jęt­no­ści czy­ta­nia mode­li poję­cio­wych (dia­gra­mów klas UML) opi­su­ja­cych syn­tak­ty­kę (syn­tax) jak wyżej (ich two­rze­nie też do łatwych nie nale­ży…). Przytaczam to jako źró­dło tego o czym tu pisałem.

W UML wszyst­ko jest kla­są”, związ­ki mię­dzy ele­men­ta­mi dia­gra­mów tak­że. Zostało to poka­za­ne w spe­cy­fi­ka­cji UML v.2.5.:

uml-zaleznosci
uml-klacyfikator
uml-zwiazki

W UML 2.5 prak­tycz­nie zni­ka w koń­cu dzie­dzi­cze­nie i agre­ga­cja. Uff… poni­żej pod­su­mo­wa­nie na jed­nym diagramie.

Dodatek [2022 – 07-22]

…chciał­bym zapy­tać o dzie­dzi­cze­nie w UML. Brałem ostat­nio udział w kil­ku roz­mo­wach o pra­cę. Moi roz­mów­cy czę­sto utrzy­mu­ją, że w UML jest to dzie­dzi­cze­nie. Mało tego, wyko­rzy­stu­ją to dzie­dzi­cze­nie na dia­gra­mach klas, w czymś co nazy­wa­ją mode­lem dzie­dzi­ny (oczy­wi­ście bez ope­ra­cji klas). Zajrzałem do spe­cy­fi­ka­cji UML i jestem tro­chę zdez­o­rien­to­wa­ny, ponie­waż poję­cie dzie­dzi­cze­nie dość czę­sto wystę­pu­je w tej doku­men­ta­cji, choć­by w tym fragmencie. 

W jakim zna­cze­niu jest tu uży­te poję­cie dzie­dzi­cze­nia? Czy jest gdzieś w spe­cy­fi­ka­cji wprost infor­ma­cja o usu­nię­ciu dzie­dzi­cze­nia z UMLa?

Porównując ze spe­cy­fi­ka­cją 2.4. nie ma, poję­cie dzie­dzi­cze­nia nadal jest obec­ne w języ­kach pro­gra­mo­wa­nia, a w spe­cy­fi­ka­cji 2.5.xx sło­wo inhe­ri­tan­ce” poja­wia sie tyl­ko 4 razy, i doty­czy wyłącz­nie komen­ta­rzy zwią­za­nych z uogólnieniami. 

Cytowany zwią­zek Generalizacji jest związ­kiem poję­cio­wym a nie struk­tu­ral­nym cze­goś ist­nie­ją­ce­go (struk­tu­ra mode­lo­wa­ne­go sys­te­mu). Formalnie w UML mamy zwią­zek Generalizacji, i jest to zwią­zek poję­cio­wy, ale nie ma w UML roz­dzia­łu Dziedziczenie”. Inherit w j. angiel­skim to tak­że prze­ję­cie cech po czymś” czy­li zwią­zek gene­ra­li­zo­wa­nia i spe­cja­li­zo­wa­nia. Generalziacja, jako zwią­zek ogól­ny-szcze­gól­ny, poka­zu­je że szcze­gól­ny przy­pa­dek, poję­cie i jego defi­ni­cja, ma wszyst­kie cechy przy­pad­ku ogól­niej­sze­go, więc pies jako szcze­gól­ny typ ssa­ka ma wszyst­kie cechy ssa­ka (cho­dzi o defi­ni­cje tego czym jest ssak). Czyli:
1. ssak: krę­go­wiec, któ­re­go mło­de kar­mią się mle­kiem mat­ki,
2. pies: <ssak> któ­ry szcze­ka,
więc:

pies: <krę­go­wiec, któ­re­go mło­de kar­mią się mle­kiem mat­ki>, któ­ry szczeka, 

czy­li pies (a kon­kret­nie defi­ni­cja psa) dzie­dzi­czy” po ssa­ku (defi­ni­cji ssa­ka) jego okre­ślo­ne cechy, czy­li ozna­cza to, że są one (cechy ssa­ka) np. dla psa i kota wspól­ne, a nie że, kot czy pies coś dzie­dzi­czy” po ssaku :). 

Dlatego w UML teraz jest napi­sa­ne, że mamy gene­ra­li­za­cję jako zwią­zek mię­dzy kla­sa­mi, ale nigdzie nie ma związ­ku dzie­dzi­cze­nia” mię­dzy klasami.

Tekst rozdz. 9.2.3.2. tłu­ma­czy­my tak, ze gene­ra­li­za­cja ozna­cza, że gene­ra­li­zo­wa­na defi­ni­cja (cechy czy­li atry­bu­ty i zacho­wa­nia) są wspól­ne (dzie­dzi­czą) dla spe­cja­li­zo­wa­nych ele­men­tów. W mode­lu poję­cio­wym (name­spa­ce) tak to dzia­ła. I teraz: model struk­tu­ry cze­go­kol­wiek ist­nie­ją­ce­go nie ma abs­trak­cji (a gene­ra­li­zo­wa­ne poję­cia to abs­trak­cje, poję­cie ssak to poję­cie abs­trak­cyj­ne). Opisując więc trak­tor jako pojazd czy doku­men­ty w księ­go­wo­ści jako doku­en­ty, nie ma nad nimi uogól­nień”, po któ­rych dzie­dzi­czą (sa to jed­nak poję­cia słow­ni­ko­we). Po tra­wie nie bie­ga­ją ssa­ki” tyl­ko psy, koty, lwy… 

Znakomita więk­szość zna­nych mi ludzi w IT nie odróż­nia mode­lu poję­cio­we­go od mode­lu struk­tu­ry sys­te­mu, któ­ry zbu­do­wa­ny jest (każ­dy) z real­nych ele­men­tów. W miej­sce sta­re­go” dzie­dzi­cze­nia w UML wpro­wa­dzo­no poję­cia: sza­blon (tem­pla­te) oraz rola (real­nym czymś w samo­cho­dzie jest sil­nik”, poję­cie napęd” to nazwa funkcji/roli okre­ślo­ne­go kom­po­nen­tu, ale nie pisze­my: „<sil­nik> dzie­dzi­czy po <napę­dzie>” tyl­ko „<sil­nik> peł­ni rolę <napę­du>” tak samo jak nie powie­my „<pies> dzie­dzi­czy po <zwie­rzę domo­we>” tyl­ko „<pies> peł­ni rolę <zwie­rzę­cia domowego>”. 

Języki pro­gra­mo­wa­nia pozwa­la­ją na tak zwa­ne re-uży­cie kodu, czy­li wycią­ga­nie pew­nych wspól­nych cech ponad kon­kret­ne komponenty/klasy (abs­trak­cja) po to by tyl­ko raz pisać kod kom­po­nen­tów mają­cych wspól­ne cechy. Jednak pro­jek­tu­jąc model dzie­dzi­ny” nie ma w niej abs­trak­cji, mając model dzie­dzi­ny (mecha­nizm dzia­ła­nia apli­ka­cji) zamie­nia­my gene­ra­li­za­cje i dzie­dzi­cze­nia” poję­cio­we na atry­bu­ty i typy real­nych rze­czy, tak to opi­sa­no książ­ce o mode­lo­wa­niu sys­te­mów już w 2007 roku: 

Oczywiście pro­gra­mi­sta może uży­wać gdzie chce dzie­dzi­cze­nia (ma taką moż­li­wość w każ­dym obiek­to­wym języ­ku pro­gra­mo­wa­nia) ale to jed­na z naj­gor­szych prak­tyk, bo łamią­cych klu­czo­wą zasa­dę jaką jest her­me­ty­za­cja kom­po­nen­tów („zakaz” współ­dzie­le­nia cze­go­kol­wiek). To dla­te­go od wie­lu lat OOP (Object-orien­ted Programming, języ­ki i pro­gra­mo­wa­nie obiek­to­we) i OOAD (Object-orien­ted Analysis and Design) to odręb­ne dzie­dzi­ny”.

Plansza do gry w szachy czyli analiza i projektowanie

Na ten wpis pew­nie wie­lu z Was cze­ka, tak przy­naj­mniej suge­ru­ją listy do mnie i gło­sy na forach, a tak­że poten­cjal­ni klien­ci. Ci, któ­rych nie­ste­ty cza­sem kry­ty­ku­ję, tak­że pew­nie cze­ka­ją. Pokażę na pro­stym przy­kła­dzie, pro­ces od ana­li­zy przez wyma­ga­nia aż do pro­jek­tu dedy­ko­wa­ne­go opro­gra­mo­wa­nia. Całość będzie zgod­na z faza­mi CIM/PIM (www​.omg​.org/​mda). Projekt dzie­dzi­ny, któ­ry powsta­nie będzie speł­niał zasa­dy SOLID pro­jek­to­wa­nia obiek­to­we­go, pro­jek­to­wa­nia przez kom­po­zy­cje (zamiast dzie­dzi­cze­nia) (pole­cam arty­kuł Łukasza Barana) i DDD. Opis doty­czy każ­de­go pro­jek­tu zwią­za­ne­go z opro­gra­mo­wa­niem, tak­że goto­wym np. ERP, CRM, EOD itp.

Korzystałem z opi­su zasad gry w sza­chy zamiesz­czo­ne­go na WIKI:

Zasady gry w sza­chy ? pra­wi­dła regu­lu­ją­ce spo­sób roz­gry­wa­nia par­tii sza­chów. Choć pocho­dze­nie gry nie zosta­ło dokład­nie wyja­śnio­ne, to współ­cze­sne zasa­dy ukształ­to­wa­ły się w śre­dnio­wie­czu. Ewoluowały one do począt­ków XIX wie­ku, kie­dy to osią­gnę­ły wła­ści­wie swą bie­żą­cą postać. W zależ­no­ści od miej­sca zasa­dy gry róż­ni­ły się od sie­bie, współ­cze­śnie za prze­pi­sy gry odpo­wia­da Międzynarodowa Federacja Szachowa (Fédération Internationale des Échecs, FIDE). Przepisy te mogą się róż­nić w przy­pad­ku róż­nych warian­tów gry, np. dla sza­chów szyb­kich, bły­ska­wicz­nych czy kore­spon­den­cyj­nych. (Zasady gry w sza­chy ? Wikipedia, wol­na ency­klo­pe­dia).

To na co chcę zwró­cić tu uwa­gę w szcze­gól­no­ści, to metafora:

pro­jek­tu­jąc (mode­lu­jąc) opro­gra­mo­wa­nie dla czło­wie­ka, mode­lu­je­my narzę­dzie dla tego czło­wie­ka a nie jego samego.

Swego cza­su pisa­łem, w arty­ku­le o nazy­wa­niu klas, że opro­gra­mo­wa­nie z regu­ły zastę­pu­je dotych­cza­so­we narzę­dzie czło­wie­ka a nie czło­wie­ka jako takie­go. Druga waż­na rzecz: aktor jest rów­no­praw­nym ele­men­tem sys­te­mu (tu sys­te­mem jest orga­ni­za­cja z jej ludź­mi i uży­wa­ny­mi przez nich narzę­dzia­mi). No to zaczynamy.

Czytaj dalej… Plansza do gry w sza­chy czy­li ana­li­za i pro­jek­to­wa­nie”

Bo banki od wszystkiego są do niczego czyli złe modele dziedziny

Ten arty­kuł to odpo­wiedź na pew­ną dys­ku­sję roz­po­czę­tą od tezy, że na wie­lu stro­nach WWW (w nie­któ­rych książ­kach tak­że) mamy nie­ste­ty do czy­nie­nia z pseudowiedzą…

W arty­ku­le Cholerny dia­gram klas pisa­łem o mode­lu dzie­dzi­ny. Modelowana jest dia­gra­mem klas (nota­cja to narzę­dzie), zawie­ra logi­kę biz­ne­so­wą. W kon­wen­cji DDD ([[Domain Driven Design]]), model ten jest szkie­le­tem kom­po­nen­tu Model we wzor­cu MVC.

Tym razem napi­sze kil­ka słów o poje­dyn­czych kla­sach w mode­lu dzie­dzi­ny. Błąd numer jeden: kla­sy w mode­lu dzie­dzi­ny odwzo­ro­wu­ją poję­cia mode­lu poję­cio­we­go! Nie, model poję­cio­wy (słow­nik pojęć ich wza­jem­nych związ­ków) to nie model dzie­dzi­ny sys­te­mu. Tak się pro­jek­to­wa­ło encje w mode­lach rela­cyj­nych baz danych, prze­no­sze­nie tych doświad­czeń na grunt obiek­to­wy to powszech­na, cięż­ka cho­ro­ba, to rak toczą­cy te pro­jek­ty. Owszem, jeże­li ktoś zade­kla­ru­je, że two­rzy sys­tem meto­da­mi struk­tu­ral­ny­mi już może prze­stać czy­tać, ale niech uży­wa nota­cji i dia­gra­my ERD a nie UML i nie nazy­wa tego meto­da­mi obiek­to­wy­mi ana­li­zy i projektowania.

Niestety przy­kła­dy dia­gra­mów klas” na stro­nach wie­lu firm dorad­czych, szko­le­nio­wych i stro­nach wie­lu kon­sul­tan­tów”, «tre­ne­rów” itp. poka­zu­ją, że duch ana­li­zy struk­tu­ral­nej nadal żyje oraz, że myle­nie nota­cji UML z meto­da­mi obiek­to­wy­mi ana­li­zy i pro­jek­to­wa­nia jest powszech­ne. Przypomnę tu tyl­ko, że dia­gram klas to nota­cja, któ­rej moż­na użyć do wie­lu rze­czy, w tym do mode­lo­wa­nia pojęć, struk­tu­ry kodu opro­gra­mo­wa­nia obiek­to­we­go (zgod­ne­go z obiek­to­wym para­dyg­ma­tem, a nie tyl­ko korzy­sta­ją­ce­go z pole­ce­nia class w uży­tym języ­ku pro­gra­mo­wa­nia), sta­tycz­nych mode­li orga­ni­za­cji i wie­lu innych. Tak więc zda­nie pro­szę zro­bić dia­gram klas” nie zna­czy nic, to coś jak weź samo­chód o pojeź­dzij trosz­kę”, z trans­por­tem nie ma to nic wspólnego.

Jeżeli jed­nak uzna­my, że pro­wa­dzi­my ana­li­zę obiek­to­wą to zna­czy, że model rze­czy­wi­sto­ści (mode­lo­wa­nej) budu­je­my jako zespół współ­pra­cu­ją­cych obiek­tów reali­zu­ją­cych okre­ślo­ny cel”. Wtedy dia­gram klas to nie żad­ne dane, encje i inne nie­obiek­to­we pomy­sły (znam takich co mode­lu­ją klu­cze rela­cyj­ne w dia­gra­mach klas a to już jest tra­ge­dia nie­ste­ty, jest nawet wyda­na w Polsce książ­ka z taki­mi przy­kła­da­mi!). Projekt zaczy­na­my od klas i ich ope­ra­cji a nie od atrybutów!

Uwaga dodat­ko­wa. Sprawdzoną meto­dą ana­liz (w ogó­le) jest ana­li­za sys­te­mo­wa, jest to:

meto­da roz­wią­zy­wa­nia zło­żo­nych pro­ble­mów wyko­rzy­stu­ją­ca podej­ście sys­te­mo­we (holi­stycz­ne). Polega na trak­to­wa­niu ana­li­zo­wa­nej orga­ni­za­cji (zja­wi­ska) jako zło­żo­ne­go sys­te­mu, któ­re­go poszcze­gól­ne czę­ści pra­cu­ją” na powo­dze­nie cało­ści”. Obejmuje ona czte­ry zasad­ni­cze eta­py roz­wią­zy­wa­nia pro­ble­mu: (1) iden­ty­fi­ka­cja i sfor­mu­ło­wa­nie pro­ble­mu, (2) bada­nie (ana­li­zo­wa­nie) sytu­acji pro­ble­mo­wej (gro­ma­dze­nie infor­ma­cji, wyja­śnia­nie kwe­stii, ana­li­zo­wa­nie fak­tów itp., (3) ana­li­za pro­ble­mu (dekom­po­zy­cja zło­żo­ne­go pro­ble­mu na mniej­sze), (4) pro­jek­to­wa­nie roz­wią­za­nia (budo­wa mode­li, spe­cy­fi­ka­cje, symu­la­cja, warian­ty itp.).

Jak widać podo­bień­stwo para­dyg­ma­tu obiek­to­we­go i ana­li­zy sys­te­mo­wej jest bar­dzo duże, żeby nie powie­dzieć uderzające.

Tak więc ana­li­za i mode­lo­wa­nie (na eta­pie ana­li­zy) to roz­ło­że­nie ana­li­zo­wa­nej orga­ni­za­cji (ana­li­zo­wa­ne­go śro­do­wi­ska) na pro­ste obiek­ty, każ­dy o pro­stej odpo­wie­dzial­no­ści”. Wyłania się obraz mode­li skła­da­ją­cych się z tych czę­ści, któ­re pra­cu­ją na powo­dze­nie cało­ści”. Jakie powin­ny być owe czę­ści? Teraz pora na dwa cyta­ty z blo­gów pew­nych pro­gra­mi­stów (lubię dobrych pro­gra­mi­stów, bo przy­ta­ku­ją mi lub negu­ją a nie raz moc­no uczą poko­ry to co myślę czy­li nie błą­dzę w chmurach):

Single Responsibility Principle mówi, że kla­sa powin­na robić jed­ną rzecz, mieć jed­ną odpo­wie­dzial­ność. Jeśli ma jed­ną odpo­wie­dzial­ność to nie powin­na raczej grze­bać we wszyst­kich war­stwach. Wątpliwe jest aby kla­sa, któ­ra ma jed­ną odpo­wie­dzial­ność musia­ła się­gać do bazy danych i inter­fej­su użyt­kow­ni­ka i pli­ków i logi­ki biz­ne­so­wej i Bóg raczy wie­dzieć gdzie jesz­cze. (za using – papie­rek lak­mu­so­wy Twojej archi­tek­tu­ry | arek onli­ne | Arkadiusz Benedykt).

…naj­bar­dziej traf­ną meta­fo­rą obiek­tów pro­gra­mi­stycz­nych jest orga­nizm bio­lo­gicz­ny. Podobnie jak komór­ki, obiek­ty nie wie­dzą”, co dzie­je się wewnątrz innych obiek­tów, ale komu­ni­ku­ją się z nimi reali­zu­jąc bar­dziej zło­żo­ne cele. W prze­ci­wień­stwie do takie­go orga­ni­zmu pro­gram mono­li­tycz­ny przy­po­mi­na mecha­nizm zegar­ka, zawie­ra­ją­cy nie­prze­li­czal­ną (sic!) licz­bę try­bi­ków. Trybiki nie mają żad­nej inte­li­gen­cji i są bez­u­ży­tecz­ne poza mecha­ni­zmem, w któ­rym pra­cu­ją. Taki pro­jekt nie ma szans powo­dze­nia. Budując mecha­ni­zmy zega­ro­we, docho­dzisz w koń­cu do takiej zło­żo­no­ści, że całość prze­sta­je funk­cjo­no­wać. (Holistycznie o inży­nie­rii opro­gra­mo­wa­nia: Bo naj­waż­niej­sza jest odpo­wie­dzial­ność Synu…).

i nie­ste­ty to co widu­ję na wie­lu stro­nach WWW, w pro­jek­tach itp. (dru­ga wada czę­sto spo­ty­ka­nych mode­li dziedzinowych):

Dopisujemy kolej­ne meto­dy a tym­cza­sem kla­sa puch­nie. Przy osią­gnię­ciu masy kry­tycz­nej, wpro­wa­dze­nie jakiej­kol­wiek zmia­ny, nawet tej naj­mniej­szej powo­du­je, że spę­dza­my godzi­ny na debu­go­wa­niu kodu i spraw­dza­niu dla­cze­go nie zawsze dzia­ła tak jak byśmy tego chcie­li. (Single Responsibility Principle | arek onli­ne).

Swego cza­su na jed­nej z kon­fe­ren­cji o ana­li­zie wyma­gań, mówi­łem o potrze­bie zro­zu­mie­nia funk­cjo­no­wa­nia ana­li­zo­wa­nej orga­ni­za­cji (fir­my) o i tym jak to udokumentować:

…wszyst­ko to co nas ota­cza, samo w sobie jest natu­ral­nie pro­ste. Złożone są, nie poszcze­gól­ne rze­czy, a to, że jest ich wie­le i mają na sie­bie wza­jem­ny wpływ. Pamiętajmy, że jed­na z naj­trud­niej­szych gier na świe­cie ? sza­chy ? to tyl­ko kil­ka­na­ście figur i pro­ste regu­ły ich prze­miesz­cza­nia, sno­oker – naj­trud­niej­sza gra w bilar­da – to to tyl­ko pro­ste kule i kij. Nawet naj­więk­szą orga­ni­za­cję moż­na, w toku ana­li­zy, roz­ło­żyć na skoń­czo­ną licz­bę ról i reguł ich postę­po­wa­nia by zro­zu­mieć jej funk­cjo­no­wa­nie. (żr. Jarosław Żeliński, refe­rat na kon­fe­ren­cji o sys­te­mach ERP).

Analiza biz­ne­so­wa to etap opi­su (zro­zu­mie­nia) mode­lo­wa­nej orga­ni­za­cji (mode­le pro­ce­sów itp.). Potem, powsta­je model roz­wią­za­nia, któ­rym jest nie raz wła­śnie opro­gra­mo­wa­nie, jego logi­ka (patrz powyż­szy cytat) to obiek­to­wy model dzie­dzi­ny sys­te­mu”, a nie jakiś dia­gram klas nafa­sze­ro­wa­ny atry­bu­ta­mi i pozba­wio­ny ope­ra­cji bo jest dokład­nie odwrotnie:

zly modelAnemic Domain Model: This is one of tho­se anti-pat­terns tha­t’s been aro­und for quite a long time, yet seems to be having a par­ti­cu­lar spurt at the moment. I was chat­ting with Eric Evans on this, and we’ve both noti­ced they seem to be get­ting more popu­lar. As gre­at boosters of a pro­per Domain Model, this is not a good thing. (AnemicDomainModel).

Dla kon­tra­stu cytat z jed­nej ze stron WWW pew­nej fir­my szkoleniowej:

Zwróćmy uwa­gę, że na mode­lu dzie­dzi­ny nie umiesz­cza­my klas imple­men­tu­ją­cych logi­kę apli­ka­cji, jej inter­fejs użyt­kow­ni­ka czy war­stwę dostę­pu do danych. Nie war­to też na mode­lu dzie­dzi­ny umiesz­czać metod. (Diagramy klas – model dzie­dzi­ny i pro­jekt apli­ka­cji).

I tyle mam dzi­siaj do powie­dze­nia o nie­któ­rych kon­sul­tan­tach i wykła­dow­cach … (a tu trosz­kę praw­dy)

P.S.

Bardzo czę­sto spo­ty­kam się z tezą, że model dzie­dzi­ny powi­nien opra­co­wy­wać archi­tekt by doko­nać ewen­tu­al­nych opty­ma­li­za­cji jesz­cze przed imple­men­ta­cją. Stawianie takich tez ma w moich oczach dwa głów­ne źró­dła: dostaw­ca usłu­gi (deve­lopr) szu­ka oka­zji by pro­jekt nagiąć do swo­ich potrzeb, do posia­da­nych goto­wych kom­po­nen­tów nie speł­nia­ją­cych jed­nak wyma­gań. Innym powo­dem jest zwy­kła nie­wie­dza. O opty­ma­li­za­cji kil­ka pro­stych tez usta­mi pro­gra­mi­sty: 3 zasa­dy opty­ma­li­za­cji. Więc powtó­rzę: na eta­pie ana­li­zy i pro­jek­to­wa­nia nicze­go nie uprasz­cza­my ani nie opty­ma­li­zu­je­my bo nie wie­my czy w ogó­le zaist­nie­je taka potrze­ba, a opty­ma­li­za­cja ZAWSZE psu­je model.