wtorek, 25 listopada 2014

Diagram prawdę Ci powie

porozmawiajmy o diagramach

Zdaję sobie sprawę, że pewnie wielu z Was odrzuca na samą myśl o UML-ach, ale chcąc nie chcąc, na pewnym etapie Waszej kariery się z nimi spotkacie i możliwe, że nawet sami będziecie musieli je wykorzystać do pracy twórczej.

Dlaczego tylu programistów czuje awersję do diagramów? Cóż, przypuszczam, że wynika to z pewnej niechęci do tego, czego nie znamy, w tym konkretnym przypadku – do języka, który jest nam obcy. Bo tym właśnie jest UML, językiem, który nie wszyscy rozumiemy, którym nie wszyscy mówimy. Dzisiaj jednak nie o tym.

Jak to z każdym językiem bywa, niekiedy jesteśmy w stanie wydobyć bardzo wiele nawet bez zbytniego wgłębiania się w szczegóły, po prostu wiemy, że niektóre rzeczy są ważniejsze niż inne. Tak jak w zdaniach, których spójnikiem jest „ale”. Każdy wie, że wszystko to, co przed owym „ale” się znajduje jest niewarte słuchania :P I właśnie kilka takich przypadków chciałbym dzisiaj opisać. Sytuacji, w których rozumienie całego kontekstu jest zbędne, wystarczy szybki rzut okiem na diagram, aby wiedzieć co jest najważniejsze.

W omawianych przeze mnie przypadkach chodzi o szybkie wyłapanie błędów projektowych, bez konieczności zagłębiania się w logikę, która kryje się za diagramami.

„strzałki” powiedzą Ci wszystko

Dzisiaj przedstawię kilka sytuacji, kilka diagramów klas, które od razu mówią nam, że jest coś z nimi „nie tak”. Do określenia jakości tego typu diagramów wystarczą nam oznaczenia, które determinują zależności pomiędzy klasami. W niektórych przypadkach naprawdę nie warto zaczynać „czytać” tego, co zostało przedstawione, bo już pierwszy kontakt w zupełności wystarcza do stwierdzenia, że coś jest nie w porządku, a co ważniejsze – do określenia tego CO nie spełnia naszych oczekiwań.

dziedziczenia nigdy nie dość mi

Popatrzcie na diagram obok. Co widzicie?

Dziedziczenie. To jest rzecz, która przykuwa naszą uwagę od samego początku. Drzewo dziedziczenia. To odciąga uwagę od kontekstu i od tego, co stoi za powstaniem takiego, a nie innego projektu.

Wielu programistów zaraz po tym pierwszym spojrzeniu na diagram zabrałoby się za zapoznawanie z tym, jakie rozwiązanie zostało tutaj zaproponowane. Ja mam jednak dla Was radę na przyszłość. Nie bądźcie jednymi z tych programistów i pamiętajcie, że to, co rzuca się w oczy, to, co razi od pierwszego wejrzenia, jest właśnie tym, na co należy zwracać szczególną uwagę.

Widząc taki diagram należy „pognębić” trochę autora diagramu i zapytać się o motywy i powody stworzenia takiej konstrukcji. Bo, cóż… to nie jest dobre rozwiązanie. I nie trzeba się wgłębiać w logikę, nawet nie trzeba wiedzieć o jaką aplikację chodzi. Takie drzewo zależności może być jedynie źródłem wielu problemów w przyszłości. Tego typu twory nigdy nie są czytelne i mają często tendencję do produkowania „special case’ów” i powstaje nam szereg dziedziczonych metod, które tak naprawdę nie są potrzebne na najniższym szczeblu.

Pamiętajcie – relacje ponad dziedziczenie. I z tym hasłem na ustach idźcie do autora (lub poproście o pomoc, jeżeli to Wy jesteście tym autorem :) i w myśl tej zasad zrefaktoryzujcie projekt. Dzięki temu Wasza funkcjonalność będzie otwarta na rozszerzenia, a zamknięta na zmiany.

Naprawdę bardzo rzadko (nigdy?) zdarzają się sytuacje, kiedy taki projekt jest rozwiązaniem optymalnym i jednym z najlepszych.

I jeszcze jedno. Zwróćcie uwagę, że w przedstawionym diagramie mamy do czynienia z klasami i dziedziczeniem. Czy podobnie negatywne odczucia powinien u nas budzić diagram, w którym zamiast klas nie finalnych pojawiłyby się interfejsy? Czy to jest również sytuacja, która powinna wzmóc naszą czujność?

ogień krzyżowy

Na kolejnym diagramie widzimy taki zbiór klas:

Czegoś tu za dużo, nie sądzicie? A czego? Oczywiście strzałek, a w przełożeniu na nasze – relacji pomiędzy klasami. Jak widać, ktoś zapomniał o zasadach wysokiej spójności i niskiej zależności. Albo mu się pomieszała kolejność słów i zdecydował się zrobić dokładnie na odwrót :)
Jak widzicie, prawie każda klasa ma powiązanie z pozostałymi, w dodatku mamy jeszcze przypadki relacji w obu kierunkach. I o ile to drugie nie koniecznie jest czymś złym, to w takim towarzystwie jest dość wymowne.

Gdy widzicie takie projekty to wiedzcie, że coś się dzieje. Co z resztą widać po ilość relacji :)

Często idealnym pierwszym krokiem na wybrnięcie z takiego rozwiązania jest wprowadzenie klas pośredniczących (rzućcie okiem na wzorzec Mediator). Dzięki temu unikamy tych krzyżowych relacji i odpowiedzialność za zarządzanie nimi przenosimy na inną klasę, która zajmuje się tylko tym.

To jest oczywiście dopiero pierwszy krok, niemniej jednak jest to dobry punkt wyjścia i zazwyczaj już po nim widać, co można zrobić dalej.

tak wiele chciałbym Ci dać

Ostatni diagram, który chciałem Wam przedstawić prezentuje się następująco:

Co możecie o nim powiedzieć? Z pewnością, że obiekty tej klasy posiadają wiele „dóbr”, ale jak naucza nas staropolskie przysłowie – „co za dużo, to nie zdrowo”. I trzeba przyznać naszym rodzicom i dziadkom, że owo wpasowuje się w tą sytuację idealnie.

Jakie problemy rodzą takie twory? Zbyt wiele zależności wskazuje na kilka rzeczy. Po pierwsze, świadczy o tym, że istnieje spore prawdopodobieństwo, że klasa jest obarczona zbyt wieloma zadaniami. Po drugie, jest całkiem sporo miejsc, które mają potencjalnie wpływ na jej działanie.

Prostym rozwiązaniem na obydwa te problemy jest ekstrakcja części kodu z klasy wykorzystującej do kolejnych klas. Należy zamienić jedną klasę na n mniej złożonych, z których każda będzie odpowiedzialna za odpowiednio mniejszą ilość instrukcji. Co za tym idzie, będzie posiadała mniej zależności oraz wpływ z zewnątrz na jej działanie również będzie zmniejszony.

diagram prawdę Ci powie

Przedstawione przeze mnie przykłady nie są jedynymi rodzajami diagramów, które już na pierwszy rzut oka zdają się wymownie krzyczeć do nas, że „coś tu jest nie tak”. Wydaje mi się jednak, że są one tymi najpopularniejszymi.

Z chęcią jednak dowiem się co Wam potrafią przekazać Wasze diagramy?