Komponenty wydzielaj według odpowiedzialności i kontraktu#

Podział systemu na komponenty powinien grupować powiązane zachowanie i dane w elementy o czytelnych granicach oraz jawnych kontraktach. Komponent UML jest wymienialną, kapsułkowaną częścią systemu, która udostępnia usługi przez interfejsy i może wymagać usług innych elementów. Dobre granice ułatwiają rozumienie, rozwój i zmianę systemu; sam diagram nie gwarantuje jednak, że architektura będzie łatwa w utrzymaniu.

Nie dziel systemu wyłącznie według liczby klas, folderów, zespołów lub technologii. Jedna funkcja biznesowa może obejmować wiele klas, a jedna aplikacja może zawierać kilka komponentów logicznych. Najpierw określ perspektywę: architekturę logiczną, wdrażalne moduły, subsystemy, usługi czy komponenty wykonawcze. Słowo „komponent” bywa używane szeroko, więc opisz zakres diagramu.

Zacznij od wymagań, zmian i odpowiedzialności#

Wypisz funkcje systemu, główne pojęcia, źródła danych, reguły i integracje. Szukaj grup, które zmieniają się z podobnych powodów, realizują spójny cel i mają wyraźny kontrakt z otoczeniem. Sprawdź, które obszary mogą być rozwijane lub zastępowane niezależnie.

Przydatne pytania:

  • Które zachowania należą do tej samej funkcji lub kontekstu domenowego?
  • Jakie dane i reguły powinny być chronione za granicą komponentu?
  • Które decyzje projektowe mogą się zmieniać niezależnie?
  • Jakie usługi komponent udostępnia innym?
  • Jakich usług potrzebuje od otoczenia?
  • Czy każda zależność ma uzasadniony kierunek i stabilny kontrakt?
  • Czy model pomaga lokalizować odpowiedzialność za zmianę lub awarię?

Są to kryteria do oceny, nie automatyczna formuła. Wymagania organizacyjne, niezawodność, bezpieczeństwo i możliwości wdrożeniowe mogą uzasadnić inne granice niż sama domena biznesowa.

Interfejsy dostarczane i wymagane#

Interfejs dostarczany (provided interface) opisuje usługi, które komponent oferuje. Interfejs wymagany (required interface) wskazuje usługi, z których komponent korzysta. Połączenie wymagania z dostawcą wyjaśnia kontrakt między elementami i pozwala zauważyć, że komponent nie jest samowystarczalny.

Nie utożsamiaj interfejsu UML wyłącznie z interfejsem języka programowania. Może oznaczać kontrakt logiczny, API, port protokołu, zbiór operacji lub inny punkt współpracy. Konkretna technologia, format komunikatu i wersjonowanie należą do szczegółów, jeśli diagram ma pozostać na wyższym poziomie.

Port (port) jest punktem interakcji klasyfikatora z otoczeniem i może grupować dostarczane lub wymagane interfejsy. Użyj portu, gdy trzeba pokazać miejsce podłączenia, rolę lub granicę komunikacji komponentu. Nie dodawaj portów do prostego diagramu zależności, jeśli nie wnoszą informacji.

Zależności i kierunek zmian#

Zależność pokazuje, że jeden komponent korzysta z usług drugiego. Strzałkę skieruj od klienta zależności do dostawcy lub wymaganego kontraktu zgodnie z używaną notacją. Interfejs jako jawny element może pomóc oddzielić kontrakt od implementacji, zwłaszcza gdy wielu dostawców może go realizować.

Oceniaj nie tylko liczbę połączeń, ale także ich kierunek, stabilność i wpływ zmian. Cykliczne zależności mogą utrudniać niezależne rozwijanie elementów. Kontrakt powinien być możliwie mały i ukierunkowany na potrzebę klienta; ogólny „interfejs do wszystkiego” ukrywa rzeczywiste sprzężenie.

Przykład: sklep internetowy#

Diagram komponentów pokazuje interfejs sklepu zależny od komponentu katalogu i zamówień; komponent zamówień wymaga interfejsu płatności dostarczanego przez zewnętrzną bramkę.
Odpowiedzialności komponentów oraz kierunek zależności interfejsów.

Interfejs sklepu korzysta z katalogu i obsługi zamówień. Komponent zamówień wymaga kontraktu płatniczego, który dostarcza bramka. Dzięki temu można rozmawiać o zamianie dostawcy bez uzależniania modelu od konkretnej biblioteki lub klasy implementacyjnej. Diagram nie pokazuje protokołu, autoryzacji, retry ani sposobu wdrożenia komponentów.

Oceń jakość granic#

Spójny komponent skupia odpowiedzialności, które należą do siebie; luźne sprzężenie ogranicza wiedzę o szczegółach innych elementów. W praktyce kompromisy są nieuniknione. Bardzo drobny podział zwiększa liczbę kontraktów, wdrożeń, obsługi błędów i przekazań. Zbyt duży komponent kumuluje niezależne funkcje i utrudnia zmianę.

Przetestuj granice na przykładowych zmianach: nowy dostawca płatności, inna polityka rabatowa, zmiana źródła katalogu, wymaganie odseparowania danych. Sprawdź, które elementy trzeba modyfikować, jak zmiany przepływają przez interfejsy i czy odpowiedzialność pozostaje czytelna.

Awaria jest kolejnym sprawdzianem: który komponent może zawieść, kto wykrywa brak odpowiedzi i jak zachowuje się reszta? Sam komponentowy widok logiczny nie określa redundancji ani izolacji awarii; do tych pytań potrzebne są dodatkowe widoki i wymagania jakościowe.

Powiąż komponenty z innymi diagramami#

Diagram klas może pokazać wewnętrzne typy i relacje komponentu, diagram przypadków użycia — funkcje widoczne dla aktorów, a diagram wdrożenia — węzły wykonawcze i artefakty. Diagram struktury złożonej może zajrzeć do wnętrza komponentu i opisać jego części oraz połączenia.

Nie utożsamiaj komponentu z węzłem wdrożeniowym. Komponent może być realizowany przez artefakt, a artefakt wdrażany na węźle; te pojęcia opisują inne aspekty architektury.

Procedura podziału#

  1. Określ, czy modelujesz architekturę logiczną, usługi, moduły czy jednostki wdrożeniowe.
  2. Zbierz funkcje, reguły, dane, integracje i wymagania jakościowe.
  3. Grupuj odpowiedzialności o spójnym celu i podobnych powodach zmiany.
  4. Dla każdej granicy nazwij dostarczane i wymagane kontrakty.
  5. Zaznacz zależności i sprawdź ich kierunek oraz stabilność.
  6. Przetestuj podział na scenariuszach zmian, awarii i rozwoju zespołów.
  7. Usuń granice, które tylko rozpraszają proste zachowanie bez korzyści.
  8. Uzupełnij innym diagramem aspekt, którego ten widok nie pokazuje.

Typowe błędy#

  • Komponent jako arbitralna grupa klas. Powinien mieć sensowną odpowiedzialność i granicę.
  • Podział według technologii bez kontekstu. Stack może się zmienić, a podział funkcji nadal powinien wyjaśniać system.
  • Brak kontraktów. Połączenie bez znaczenia nie informuje, co komponent oferuje.
  • Interfejs jako etykieta dekoracyjna. Pokaż rzeczywisty dostarczany lub wymagany kontrakt.
  • Każdy moduł jako osobna usługa. Granica logiczna nie przesądza o mikroserwisie ani wdrożeniu.
  • Komponent mylony z serwerem. Węzeł wdrożenia i komponent to inne elementy modelu.
  • Zbyt wiele portów i operacji. Szczegóły kontraktu powinny odpowiadać celowi diagramu.
  • Cykliczne zależności bez uzasadnienia. Mogą utrudnić niezależne zmiany i testowanie.
  • Ignorowanie wymagań jakościowych. Bezpieczeństwo, dostępność i opóźnienia wpływają na granice.
  • Brak scenariusza zmiany. Podział oceniaj na realnych potrzebach, nie tylko estetyce diagramu.

Lista kontrolna#

  • Czy wiadomo, co oznacza „komponent” i na jakim poziomie jest diagram?
  • Czy każda granica grupuje spójną odpowiedzialność?
  • Czy kontrakty dostarczane i wymagane są jawne?
  • Czy zależności mają uzasadniony kierunek?
  • Czy podział wspiera przewidywane zmiany, testowanie i odpowiedzialność?
  • Czy odróżniono komponenty logiczne od artefaktów i węzłów wdrożenia?
  • Czy diagram pokazuje tylko szczegóły potrzebne odbiorcy?

Dobry podział komponentów wynika z odpowiedzialności i kontraktów, a następnie jest sprawdzany na zmianach, awariach i sposobie pracy zespołów. Diagram UML pomaga wyjaśnić granice, ale nie zastępuje decyzji architektonicznych ani uzasadnienia kompromisów.