Jak pokazuje przykład 8, programiści muszą radzić sobie z zależnościami, które powstają w wyniku ich dekompozycji problemu i jego rozwiązania na pewną liczbę modułów. Mówimy, że moduł systemu zależy od innego, jeśli jest możliwe, że zmiana w jednym module wymaga zmiany w innym. Na przykład, jeśli firma zmienia swoje metody produkcji, może to spowodować konsekwentną zmianę w sposobie obliczania płatności wymaganych za towary, które produkuje.
Deweloper musi zajmować się nie tylko naturą każdej zależności, ale także liczbą zależności. W inżynierii oprogramowania, „sprzężenie” jest używane w odniesieniu do stopnia współzależności pomiędzy różnymi częściami systemu. Łatwo zauważyć, że niektóre systemy mogą mieć łańcuchy współzależnych modułów, gdzie, na przykład, moduł A zależy od modułu B, który zależy od modułu C, i tak dalej. W niektórych przypadkach łańcuchy te mogą się połączyć i stworzyć zależność kołową, która jest szczególną formą silnego (lub wysokiego) sprzężenia.
Deweloperzy starają się konstruować systemy luźno sprzężone, ponieważ są one łatwiejsze do zrozumienia i utrzymania. Tak więc dobry system oprogramowania ma niskie sprzężenie, co oznacza, że zmiany w jednej części są mniej prawdopodobne, aby propagować przez resztę systemu. Kolejną korzyścią z niskiego sprzężenia jest to, że komponenty są łatwe do zastąpienia i, potencjalnie, ponownego użycia.
Cokolwiek poziom sprzężenia w systemie oprogramowania, ważne jest, aby wiedzieć, które moduły są sprzężone. Gdyby nie było żadnych zapisów o sprzężeniu między modułami, programista musiałby spędzić czas na pracy przez moduły, aby określić, czy każda z nich została dotknięta zmianą, czy nie. Rezultatem byłoby wiele wysiłku poświęconego na sprawdzanie, nawet jeśli żadne zmiany nie byłyby potrzebne. Przykład 9 ilustruje niebezpieczeństwo związane z posiadaniem więcej niż jednego modułu korzystającego ze wspólnych lub współdzielonych danych.
Przykład 9
Obsługa daty zawsze stanowiła problem dla twórców oprogramowania. Dla aplikacji w pewnym wieku, najbardziej stosowanym formatem zapisu dla reprezentacji roku była liczba z przedziału od 0 do 99. Miało to sens, ponieważ rok 1966 był przechowywany jako 66, rok 1989 jako 89, i tak dalej, dlatego mniej miejsca było potrzebne do przechowywania tylko dwóch cyfr. Ponadto, jeśli daty były przechowywane jako liczby, zadania, które wymagały sortowania według kolejności dat, były proste – 22 stycznia 1989 roku przechowywany jako 890122, jest po 22 grudnia 1966 roku przechowywany jako 661222.
Niestety, wiele z tych aplikacji było nadal w użyciu, gdy zbliżał się rok 2000, więc każdy moduł w każdej aplikacji, który używał krótkiej formy roku, musiał zostać zbadany.
Głównym aspektem problemu w przykładzie 9 było to, że różni programiści mieli różne sposoby odczytywania i manipulowania wartościami przechowywanymi w zmiennych, które używały sześciocyfrowego formatu daty. Zwiększyło to wysiłek potrzebny do rozwiązania tak zwanego błędu milenijnego. Gdyby programiści mieli spójny sposób manipulowania datami, który nie zależał od formatu przechowywania, błąd milenijny nie stanowiłby problemu.
Spójność jest sposobem opisania, jak ściśle działania w ramach jednego modułu są ze sobą powiązane. Spójność jest ogólnym pojęciem – na przykład, dział w organizacji może mieć spójny zestaw obowiązków (np. konta), lub nie (różne usługi). W systemach oprogramowania, wysoce spójny moduł wykonuje jedno zadanie lub osiąga jeden cel – „rób jedną rzecz i rób ją dobrze” jest użytecznym mottem do zastosowania. Moduł powinien implementować pojedyncze zadanie logiczne lub pojedynczy byt logiczny.
Niskie sprzężenie i wysoka spójność to konkurujące ze sobą cele. Jeśli każdy moduł wykonuje tylko jedną rzecz na niskim poziomie abstrakcji, możemy potrzebować złożonego gmachu wysoce sprzężonych modułów, aby wykonać czynność na wyższych poziomach abstrakcji. Programista powinien starać się osiągnąć najlepszą równowagę pomiędzy poziomami sprzężenia i spójności dla systemu oprogramowania. Na przykład, hotele generują dochód poprzez wynajmowanie swoich pokoi gościom. Koncepcja pokoju będzie prawdopodobnie reprezentowana gdzieś w systemie oprogramowania do rezerwacji dla hotelu. Wygodne może być użycie modułu lub klasy reprezentującej pojęcie pokoju do zbierania i przechowywania danych o dochodach generowanych przez wynajmowanie pokoi. Lepszym rozwiązaniem jest jednak osobny moduł rachunków lub płatności, ponieważ jest on bardziej spójny, zwłaszcza gdy hotel generuje dochody w inny sposób, na przykład z tytułu serwowania posiłków osobom niebędącym gośćmi-rezydentami.
Działanie 5 Dziel i zdobywaj
- a.Dlaczego można rozważyć podział dużego projektu na mniejsze kawałki?
- b.Jak złożoność systemu oprogramowania wpływa na zadanie konserwacji?
- c.Co to jest moduł?
- d.Dlaczego pomaga mieć niskie sprzężenie w systemie oprogramowania?
- e.Podaj przykłady rodzajów informacji, które byłyby cenne przy rozważaniu zmiany danego modułu.
- f.Co to są zależności kontekstowe modułu? Jak odnoszą się one do interfejsu modułu?
- g.Jakie są korzyści z używania modułów ze zdefiniowanymi interfejsami?
- h.Dlaczego pomocna jest wysoka spójność modułów systemu oprogramowania?
- i.Jakie cechy powinien wykazywać moduł, które pomogą zapewnić, że jest on łatwy i tani w rozwijaniu i utrzymaniu, a błędy są ograniczone do minimum?
- j.Dlaczego ważne jest osiągnięcie równowagi między sprzężeniem a spójnością?
Odpowiedź
- a.Istnieje ograniczenie tego, ile jedna osoba może zrozumieć w danym momencie. Tak więc istnieje limit wielkości systemu oprogramowania, z którym może sobie poradzić jedna osoba. Dzieląc duży projekt na mniejsze kawałki, można zidentyfikować pewną liczbę zadań, którymi można lepiej zarządzać, dla osób zaangażowanych w projekt.
- b.Istotne jest, aby móc dokonać zmiany w systemie oprogramowania, nie musząc wiedzieć wszystkiego o tym systemie. Każda zmiana staje się trudna, gdy przepływ sterowania i zależności w programach są złożone. Im większa liczba i charakter zależności, tym trudniej jest utrzymać system oprogramowania.
- c.Moduł to dowolna identyfikowalna część systemu oprogramowania, która jest rozpatrywana oddzielnie. Na przykład, moduły mogą być podprogramami (w języku proceduralnym odpowiednikiem metod), klasami (w języku obiektowym), funkcjami bibliotecznymi lub innymi konstrukcjami, które mogą być traktowane niezależnie.
- d.Przy niskim sprzężeniu istnieje niewiele zależności między modułami. Dlatego zmiany dokonane w jednej części (jednym lub kilku modułach) systemu oprogramowania są mniej prawdopodobne, aby propagować w całym systemie. (Jasny zapis zależności między modułami pomaga przewidzieć wpływ proponowanej zmiany na system oprogramowania.)
- e.Istnieją dwa rodzaje informacji, które przyczyniają się do analizy proponowanej zmiany:
- Które moduły są klientami danego modułu? Ta informacja wskazuje, jak daleko zmiana może się rozprzestrzeniać w systemie oprogramowania.
- Jakie założenia zostały przyjęte w modułach klienckich danego modułu? Zrozumienie oczekiwanych usług modułu pomoże ocenić ryzyko związane z daną zmianą.
- f.Zależności kontekstowe dla modułu są usługami innych modułów, których moduł potrzebuje, aby działać poprawnie. Możesz wyrazić zależności kontekstowe dla modułu w kategoriach innych interfejsów. W efekcie możesz wyrazić obowiązki modułu w kategoriach jego interfejsu i zależności kontekstowych. Jeśli kontekst zapewnia usługi, których potrzebuje moduł, a klienci spełniają wszelkie warunki określone w interfejsie, moduł może zagwarantować świadczenie usług opisanych w swoim interfejsie.
- g.Korzyści są następujące:
- Deweloperzy będą musieli wiedzieć tylko o interfejsie modułu (jego składni oraz o tym, czego wymaga i co osiąga – jego semantyce), a nie o tym, jak zapewnia te usługi. W rezultacie programiści mogą być bardziej produktywni.
- Deweloperzy mogą dokładniej zrozumieć aspekty systemu oprogramowania, więc mniej błędów zostanie wprowadzonych.
- Powinno być łatwiej znaleźć błędy, ponieważ unika się nieistotnych modułów.
- Możliwość ponownego użycia modułu jest zwiększona, gdy wiadomo, co ten moduł zapewnia i wymaga.
- h.Przy wysokiej spójności, moduł wykonuje sensowny zestaw operacji lub działań. Idealnie wysoka spójność implikuje tylko jedną główną abstrakcję na moduł. Interfejs abstrahuje od tego, co programista musi wiedzieć, aby móc używać modułu. Ułatwia to programistom zrozumienie celu modułu i sposobu jego użycia. Dodatkowo wysoka spójność ma tendencję do czynienia modułu bardziej wielokrotnego użytku w innych aplikacjach, ponieważ zapewnia zestaw operacji, które naturalnie siedzą razem.
- i.Moduł powinien mieć niskie sprzężenie i wysoką spójność, reprezentować dobrą abstrakcję i mieć dobrze zdefiniowany interfejs, który jest zamkniętą abstrakcją dobrze rozumianej koncepcji.
- j.W konstruowaniu systemu, możesz mieć wybór pomiędzy mniejszym zestawem luźno sprzężonych, mniej spójnych modułów, lub większym zestawem ściśle sprzężonych, bardziej spójnych modułów. W pierwszym przypadku każdy moduł może być trudny do zrozumienia, podczas gdy w drugim przypadku relacje między nimi mogą być zbyt skomplikowane. Musisz znaleźć odpowiednią równowagę.
.