UML - graficzny język modelowania różnych aspektów działania systemu informatycznego - jest standardem bardzo rozbudowanym. W jego skład wchodzi 13 rodzajów diagramów. Każdy tzw. klasyfikator (klasa, relacja, przypadek użycia, czynność, ...) ma w UML-u kilkadziesiąt własności. Dokumentacja języka UML 2.1 liczy ponad 1000 stron. Czy aby tworzyć eleganckie i poprawne diagramy UML trzeba znać pełną notację tego języka?
Zacznijmy od ustalenia, jaki jest cel (lepszej lub gorszej) znajomości języka UML. Jeśli jest nim np. zdanie trudnego egzaminu na certyfikat, to oczywiście powinniśmy znać jak najwięcej konstrukcji języka UML, nawet tych rzadko używanych i egzotycznych. Najczęściej jednak celem jest po prostu tworzenie eleganckich i poprawnych modeli analitycznych i projektowych. Elegancki model powinien się cechować między innymi prostotą. I tu nadmiar konstrukcji języka UML może wręcz zaszkodzić.
Jako analityk praktycznie korzystam z UML-a od dobrych paru lat. Mimo pracy w dużych i skomplikowanych projektach, niektórych rodzajów diagramównie nie zdarzyło mi się nigdy użyć. Gdyby nie to, że jestem autorem cyklu szkoleń z języka UML, pewnie nigdy bym się nie dowiedział, że są w UML-u np. diagramy struktur połączonych czy diagramy sterowania interakcją. Nigdy nie spotkałem tych diagramów w realnych projektach (nie licząc desperackich prób uzasadnienia potrzeby ich istnienia, podejmowanych przez autorów literatury). Dlatego uważam, że ucząc się modelowania w UML-u nie ma sensu sobie nimi zaprzątać głowy. Do wykonania pełnej analizy i projektu w zupełności wystarczy kilka podstawowych rodzajów diagramów - wg mnie są to:
- diagramy czynności,
- diagramy przypadków użycia,
- diagramy klas,
- diagramy stanów.
Czasami przydają się jeszcze diagramy sekwencji. Na etapie wdrożenia całkiem przydatne mogą też być diagramy wdrożeniowe (tzn. diagramy komponentów i rozlokowania).
Nawet w ramach tych kilku podstawowych rodzajów diagramów jest sporo konstrukcji nadmiernie skomplikowanych i zaciemniających model. Przyjrzyjmy się najważniejszym i najczęściej używanym diagramom - diagramom klas. Są w nich dostępne m. in. dwie konstrukcje: dziedziczenie z częścią wspólną (ang. overlapping) oraz dziedziczenie wieloaspektowe (ang. multi-aspect). Dziedziczenie z częścią wspólną polega na tym, że zbiory definiowane przez podklasy nie są rozłączne (mają część wspólną). W przykładzie z rys. 1. niektórzy kontrahenci mogą być jednocześnie dostawcami, jak i klientami. Natomiast dziedziczenie wieloaspektowe polega na określeniu kilku hierarchii dziedziczenia, każdej wg innego kryterium, tak jak na rys. 2.
Rys. 1 | Rys. 2 |
Efekt stosowania tych konstrukcji jest taki, że niektóre obiekty mają przypisane kilka klas jednocześnie (np. firma będąca dostawcą i klientem jest obiektem klasy Dostawca i jednocześnie klasy Klient; leasingowany samochód osobowy jest obiektem klasy SamochódOsobowy i jednocześnie obiektem klasy SamochódWLeasingu). Taka sytuacja nie jest zrozumiała z punktu widzenia analizy i projektowania obiektowego. Nie da się jej także zaimplementować w obiektowych językach programowania, gdzie obiekt nie może mieć przypisanych kilku klas.
Na szczęście takie konstrukcje można łatwo zastąpić znacznie prostszymi modelami, opartymi na kompozycji. Na rys. 3. i 4. są pokazane zmodyfikowane diagramy dla naszych dwóch przykładów. Opierają się one na spostrzeżeniu, że dostawca i klient nie są specjalizacjami kontrahenta, lecz rolami granymi przez kontrahenta. Analogicznie, samochód osobowy, samochód ciężarowy, samochód - własność oraz samochód w leasingu nie są specjalizacjami samochodu, lecz jego cechami. Zauważmy, że diagramy z rys. 3. i 4. wcale nie są mniej czytelne od diagramów z rys. 1. i 2. Wręcz przeciwnie - jasno i czytelnie pokazują zasadnicze cechy obu modelowanych sytuacji.
Rys. 3 | Rys. 4 |
W zasadzie każdy diagram klas można narysować korzystając wyłącznie z następujących konstrukcji:
- klas, atrybutów i metod,
- relacji między klasami (w tym agregacji i kompozycji),
- zwykłego dziedziczenia (określanego w specyfikacji UML jako "disjoint").
Takie ograniczenie się do podstawowych konstrukcji powoduje, że model staje się prosty i czytelny. Taki model można bezpośrednio (bez dodatkowych przekształceń) zaimplementować w obiektowych językach programowania. Natomiast modele z rys. 1. i 2. nie nadają się do implementacji, ponieważ dziedziczenie z częścią wspólną i dziedziczenie wieloaspektowe nie są wspierane przez obiektowe języki programowania.
W analogiczny sposób można wyeliminować jako nadmiarowe i niepotrzebnie zaciemniające model niektóre konstrukcje pozostałych najczęściej uzywanych rodzajów diagramów.
Ograniczenie się do podstawowego podzbioru notacji ma jeszcze jedną zaletę: zwiększa szanse, że wszyscy udziałowcy projektu (programiści, inni analitycy, a nawet klient) zrozumieją nasze diagramy. Użycie skomplikowanych i rzadko używanych elementów notacji oznacza ryzyko, że nasz model będzie tylko "sztuką dla sztuki" i zwyczajnie nie zostanie zrozumiany (lub zostanie zrozumiany niezgodnie z naszymi intencjami).
Podsumowując, mam nieodparte wrażenie, że - mimo dobrych intencji - autorzy języka UML przedobrzyli z jego złożonością. Nadmiar skomplikowanych konstrukcji i egzotycznych rodzajów diagramów powoduje zamieszanie, utrudnia rozumienie diagramów i ich implementację. Dlatego warto w ramach własnej praktyki wypracować sobie pewien ograniczony podzbiór konstrukcji języka UML, z których będziemy świadomie korzystać. A jeśli pracujemy w większym zespole - warto ten podzbiór opisać w obowiązującym ten zespół procesie analizy.
Szymon Zioło
Zobacz także:
Wrycza, S., Marcinkowski, B., A Light Version of UML 2: Survey And Outcomes, Proceedings of the 2007 Computer Science and IT Education Conference, http://csited.org
Komentarze