Professional Documents
Culture Documents
Inżynieria Oprogramowania W Ujęciu Obiektowym. UML, Wzorce Projektowe I Java
Inżynieria Oprogramowania W Ujęciu Obiektowym. UML, Wzorce Projektowe I Java
1?
1I
I
Bernd Bruegge, Allen H. Dutoit
Inżynieria
oprogramowania
w ujęciu
obiektowym
U ML, wzorce projektowe i Java
Helion
Dla Goega, Toby'ego i Clary.
-B.B
Dla mojej kochanej rodziny:
Vicky, Eleni, Anny Marii, Michelle i Chrisa.
— A.H.D
Spis treści
Przedmowa 17
Wstęp 19
Podziękowania 31
CZĘŚĆ I Zaczynamy 33
Dodatki 769
Jakieś dziesięć lat temu dowiedziałem się o kursie z zakresu inżynierii oprogramowania,
prowadzonym przez Bernda Bruegge'a na Uniwersytecie Carnegie Mellon. Większość prowa-
dzonych przez inne uniwersytety kursów o tej tematyce realizowana jest zwykle w ten sposób,
że każda z niewielkich — trzy- lub czteroosobowych — grup otrzymuje do rozwiązania kon-
kretny problem, w określonym czasie, powiedzmy, jednego miesiąca. I ciąg dalszy zazwyczaj
wygląda tak, że jeden „wiodący" programista narzuca swą koncepcję całemu zespołowi — nie
ma mowy o praktykowaniu umiejętności w zakresie sprawnej komunikacji, o rozwiązywaniu
wątpliwości i niejasności projektowych, niepotrzebne stają się narzędzia do modelowania. Za-
danie do rozwiązania jest wszak dość proste — by nie powiedzieć: rozrywkowe — i tego typu
quasi-profesjonalne praktyki mają nawet duże szansę powodzenia. W rezultacie jednak studenci
kończący semestralny kurs pozostają nieprzygotowani do zmagania się ze złożonością praw-
dziwych wyzwań, jakie wkrótce postawią przed nimi rzeczywiste problemy projektowe.
Na kursie Bruegge'a było jednak inaczej: cała klasa zaangażowana była w realizację
wspólnego projektu, jakim było stworzenie opartego na kwerendach systemu nawigacji dla
miasta Pittsburgh. W projekcie tym wykorzystywano interaktywny system map, zrealizowany
w ramach podobnego kursu w poprzednim semestrze; system ten, opracowany na użytek miej-
scowego departamentu planowania i służb zarządzających lokalnym portem lotniczym miał
jednak tę bolączkę, że dane geograficzne oraz rozkłady jazdy lokalnych autobusów nie dość,
że najeżone były błędami ortograficznymi, to na dodatek przechowywane były w kilku nie-
zgodnych ze sobą formatach. Studenci jednak poradzili sobie z tymi niedostatkami, tworząc
w ciągu semestru bardzo dobry projekt o rozmiarze kodu źródłowego w granicach 27 000 wier-
szy — cóż za znakomita różnica w porównaniu ze wspomnianą powyżej rutyną „rozrywko-
wych" projektów! I choć projektom tej skali daleko jeszcze do wielu olbrzymich przedsięwzięć
programistycznych, to skala ta jest całkowicie wystarczająca, by docenić znaczenie strategii,
organizacji i narzędzi w trudach zmagania się z zawiłościami i złożonością otaczającego nas
świata. Studenci zgłębiali tajniki inżynierii oprogramowania w taki sposób — jedyny skuteczny —
w jaki uczy się każdego rzemiosła: przez praktykę na bazie realnego świata.
Treść tej książki stanowi odzwierciedlenie owej pragmatycznej filozofii tworzenia opro-
gramowania, postrzeganego jako dyscyplina inżynierska. Autorzy prezentują tę skomplikowaną
tematykę w bardzo przystępnym ujęciu, ułatwiającym zrozumienie nawet najtrudniejszych jej
aspektów — w ujęciu zorientowanym obiektowo, z wykorzystaniem UML. Czytelnicy znajdą
tu obszerną dyskusję na temat zarówno technik modelowania, jak i rozwijania umiejętności
w zakresie komunikacji interpersonalnej, tak istotnej dla osiągnięcia sukcesu. Kilka rozdziałów
18 Przedmowa
Jim Rumbaugh
Wstęp
System (AAS) zawieszony został w roku 1994, czego bezpośrednią przyczyną okazały się pro-
blemy z oprogramowaniem, objawiające się przekraczaniem założonych harmonogramów
0 miesiące i lata oraz nadprogramowymi wydatkami budżetowymi sięgającymi miliardów
dolarów.
Oba przytoczone przykłady ilustrują sytuacje, gdy funkcjonowanie i tak już skompliko-
wanych systemów zderza się z nieprzewidywalnymi zmianami i powinno wyjść z tej konfron-
tacji obronną ręką. Wyzwania, jakie kreuje sama złożoność systemów, ewidentnie przekraczają
możliwości pojedynczego człowieka, a pojawiające się dodatkowo nowe okoliczności zmuszają
do wyjścia poza (niewystarczające już) rutynowe rozwiązania i poszukiwanie ad hoc nowych,
adekwatnych do nowej sytuacji. Wymaga to sprawnego współdziałania wszystkich uczestników
przedsięwzięcia — porażka w tym względzie przekłada się w prostej konsekwencji na klęskę
całego projektu.
Celem tej książki jest dostarczenie czytelnikom wiedzy o tym, jak skutecznie radzić
sobie z takimi wyzwaniami.
Temat
Zasady
Ograniczoność zasobów. Gdy dysponuje się wystarczającą ilością czasu i zasobów, można
tworzyć systemy niemal idealne. Taka sytuacja jest jednak utopią i to z dwóch zasadniczych
powodów. Po pierwsze, czas realizacji projektu zawsze jest ograniczony, a przeznaczone na tę
realizację zasoby są mniej lub bardziej limitowane. Po drugie — nawet przy założeniu do-
statecznego bogactwa zasobów, gdy szczegóły problemu zmieniają się gwałtownie podczas jego
rozwiązywania, może się zdarzyć, że zbudowany właśnie system rozwiązuje nie ten problem, co
potrzeba. Konieczne jest więc założenie, że proces tworzenia systemu podlega ograniczeniom
w kontekście dostępnych zasobów; założenie takie ma dodatkowo tę cenną zaletę, że dążymy
do jak najlepszego ich wykorzystywania, stosując podejście oparte na komponentach oraz wy-
korzystując wielokrotnie wiedzę, elementy projektu i fragmenty kodu. Innymi słowy — trak-
tujemy tworzenie oprogramowania jako dyscyplinę inżynierską.
Książka
innych, których słabe i mocne strony staramy się wyraźnie eksponować. Mamy zatem nadzieję,
że każdy czytelnik tej książki znajdzie w niej dla siebie coś pożytecznego.
Treść książki, w naszym zamierzeniu przeznaczona jako materiał dla jednosemestralnego
kursu, składa się z 16 rozdziałów, podzielonych na trzy części.
I tak w części pierwszej, zatytułowanej „Wprowadzenie" i obejmującej trzy rozdziały,
zajmujemy się problematyką podstawowych umiejętności programisty, warunkujących jego
zdolność do funkcjonowania w kontekście inżynierii oprogramowania.
Kurs
Krótkie kursy technologiczne. Książka przydatna będzie także dla krótkich, intensywnych
kursów adresowanych do profesjonalistów. Kursy tego rodzaju, koncentrujące się na języku
UML i metodach obiektowo zorientowanych, powinny czerpać z rozdziałów 1., 2., 4., 5.,
6., 7., 8., 9., 10. i 11. (w tej kolejności), obejmujących wszystkie fazy tworzenia systemu, od
zbierania wymagań do testowania. W kursach bardziej zaawansowanych można także wyko-
rzystać rozdziały 12., „Zarządzanie racjonalizacją", i 13., „Zarządzanie konfiguracją".
Krótkie kursy dla menedżerów. Książka okaże się również pożyteczna na intensywnych
kursach dla menedżerów. Szczególnie przydatne będą rozdziały związane z menedżerskimi
aspektami realizacji projektów — komunikacją, zarządzaniem ryzykiem, racjonalizacją, mo-
delami dojrzałości i językiem UML — czyli rozdziały (kolejno) 1., 2., 3., 14., 15., 16., 12. i 13.
Konwencje typograficzne
Aby treść książki była bardziej czytelna, zróżnicowaliśmy styl jej poszczególnych ele-
mentów, i tak:
• gdy nowy termin pojawia się po raz pierwszy, wyróżniamy go czcionką pogrubioną,
• tytuły książek i rozdziałów, wyróżnione terminy oraz adresy URL pisane są kursywą,
• nazwy systemów i nazwy związane z modelowanymi elementami (klasami, atrybu-
tami, operacjami, stanami, zmiennymi) pojawiają się w postaci czcionki o s t a ł e j
szerokości,
• nazwy klas abstrakcyjnych pisane są pochylę czcionką o stałej szerokości,
• nazwy obiektów na rysunkach mają postać podkreślonej czcionki o s t a ł e j
szerokości,
• przykładowy kod źródłowy pisany jest czcionką o s t a ł e j szerokości, przy czym
słowa kluczowe są pogrubione, a komentarze pochylone.
28 Wstęp
Notka produkcyjna
Autorzy
Fotografie
widok z samolotu na Denali (rozdziały 2. i 4.), początek drogi przez West Rib (rozdział 3.),
widok z West Rib 1000 m w dół (zauważalne są nasze ślady na East Kahiltna Glacier (roz-
dział 5.), Mount Foraker z obozu 5. (rozdział 6.), piękną, lecz trudną do zdobycia grań na wy-
sokości 5000 m (rozdział 7.), obóz bazowy na drodze normalnej, gdzie wykorzystaliśmy resztki
igloo (rozdział 8.), lądowisko dla samolotu Douga Geetinga (rozdział 9.), biwak na drodze przez
West Rib, zwany „Hotel Crux", bo nie da się tam wykopać platformy wystarczającej do rozbicia
namiotu (rozdział 10.), przekraczanie szczeliny brzeżnej(rozdział 11.), świeże lawinisko (roz-
dział 12.), Denali z drogą Cassina (rozdział 13.), plany różnych dróg na szczyt (rozdział 14.),
„horyzontalny" wschód słońca u podnóża drogi Cassina (rozdział 15.) i wierzchołek Denali.
A na fotografii z okładki majestatycznie prezentuje się szczyt K2.
Podziękowania
Uczestnicy kursów projektowych: Workstation Fax (1989), Interactive Maps (1991), Interac-
tive Pittsburgh (1991), FRIEND (1992, 1993, 1994), JEWEL, GEMS (1991, 1994, 1995),
DIAMOND (1995, 1996), OWL (1996, 1997), JAMES (1997, 1998), PAID (1998, 1999),
STARS (1999, 2000, 2001), TRAMP (2001, 2002), ARENA (2002, 2003), CampusTV
(2004,2005), Virtual Symphony Orchester (2005), WALOS (2006) i DOLLI (2007, 2008).
32 Podziękowania
Redaktorzy i korektorzy, którzy wskazali nam nasze uchybienia i udzielali cennych wska-
zówek: Martin Barrett, Brian Berenbach, Alex Borgida, Ramsey Bualuan, Dave Chesney,
Andrea De Lucia, Debora East, Thomas Eichhorn, Henry Etlinger, Ray Ford, Jim Helm, Jonas
Helming, Korbinian Herrmann, Allen Holliday, John Keklak, Robert Lechner, Max Koegel,
Jonathan Maletic, Jeff McKinstry, Bruce Maxim, Gerhard Mueller, Michael Nagel, Helmut
Naughton, Barbara Paech, Dennis Pagano, Daniel Paulish, Joan Peckham, Gary Pollice, David
Rine, Florian Schneider, Ingo Schneider, Anthony Sullivan, Damla Turgut i wielu nieznanych
nam z imienia i nazwiska. Wszelkie błędy, które mimo to uchowały się w kolejnych wydaniach,
zawinione są wyłącznie przez nas.
Ekipa z Prentice Hall, która pomogła nam przydać realizmu naszym książkom, szczególnie:
Alan Apt — nasz pierwszy wydawca, który nie pozwolił nam stracić wiary we własne siły;
Lakshmi Balasubramanian, Toni Holm, Patrick Lindner, Camille Trentacoste, Jake Warde
i (przy obecnej edycji) Tracy Dunkelberger, Scott Disanno, a także wielu innych, których ciężka
praca umożliwiła doprowadzenie wydania do szczęśliwego końca i którym nie mieliśmy
okazji podziękować osobiście.
1.8. Ćwiczenia 59
Bibliografia 61
Wprowadzenie
do inżynierii
oprogramowania
Programista amator ma to do siebie, że wciąż poszukuje magicznych
narzędzi, które sztukę tworzenia aplikacji miałyby sprowadzić
do banalnego zadania. W chwili gdy uświadamia sobie, że takich
narzędzi po prostu nie ma, staje się programistą profesjonalistą.
* — Grady Booch Object-Oriented Analysis and Design
Złożoność i zmiany
S p ó j r z m y n a p o n i ż s z e p r z y k ł a d y , z a c z e r p n i ę t e z k s i ą ż k i P. N e u m a n n a [ N e u m a n n , 1995].
Błąd roku 1 9 0 0
W 1992 roku Mary z miasteczka Winona w stanie Minnesota otrzymała zaproszenie do dziecięcego
parku zabaw. Nie byłoby w tym nic dziwnego, gdyby nie fakt, że Mary skończyła właśnie 104 lata.
Błąd roku p r z e s t ę p n e g o
Pewien supermarket zapłacił 1000 dolarów grzywny za sprzedaż przeterminowanych porcji mięsa
mielonego. Ich przydatność do spożycia, zgodnie z nadrukiem na etykiecie, kończyła się 1 marca 1988
roku, podczas gdy faktyczny termin ważności upływał dzień wcześniej. W programie drukującym
etykietki przeoczono fakt, że rok 1988 jest rokiem przestępnym.
N a d u ż y c i e interfejsu
10 kwietnia 1990 pociąg londyńskiego metra odjechał ze stacji bez maszynisty. Maszynista nacisnął
starter, ale przecież wiedział, że pociąg pozostanie unieruchomiony, dopóki nie zamkną się wszystkie
drzwi; zablokował w tym celu drzwi najbliższe kabinie i wyszedł z pociągu. Nieświadomy niczego
konduktor chwilę później usunął blokadę ze wspomnianych drzwi — te się zamknęły i . . .
Bezpieczeństwo
CERT (Computer Emergency Response Team)' w Software Engineering Institute jest organizacją
rządu USA, zajmującą się bezpieczeństwem informacji — jego naruszeniem, jego zagrożeniami
i wiedzą dotyczącą jego zapewnienia. Liczba zgłoszonych przypadków naruszenia owego bezpieczeń-
stwa zwiększyła się z 252 w 1990 roku do 21 756 w roku 2000, by w roku 2001 przekroczyć liczbę 40 000.
Z a p ó ź n o i p o z a b u d ż e t e m na bis
W 2002 roku system kontroli ruchu lotniczego w Swanick zawiadywał wszystkimi trasami lot-
niczymi przebiegającymi nad Anglią i Walią. Przy jego realizacji znacznie przekroczono budżet
— zamiast planowanych 350 min funtów wydano ostatecznie 623 min, a realizacje tę ukończo-
no z 6-letnim opóźnieniem. Dwie główne poprawki wprowadzano do systemu w czasie, gdy
trwało już szkolenie personelu kontroli lotów.
1
Zespół ds. reagowania na przypadki naruszenia bezpieczeństwa teleinformatycznego — organizacja utwo-
rzona w listopadzie 1988 roku przez DARPA, po znanym incydencie z robakiem Morrisa — przyp. tłum,
cytat z Wikipedii, patrz http://pl.wikipedia.org/wiki/CERT i http://pl.wikipedia.org/wiki/Robak_Morrisa.
1.1. Wprowadzenie: niepowodzenia w inżynierii oprogramowania 37
Niepotrzebne komplikacje
Stworzenie samolotu C-17 firmy McDonnell Douglas pochłonęło 500 min dolarów ponad plan,
z powodu licznych błędów w systemie pokładowym. Trudno się temu dziwić, zważywszy na fakt, że
wspomniany system składał się z 19 komputerów i 80 mikroprocesorów, oprogramowanych przy
użyciu 6 różnych języków. 4
Każde z opisanych powyżej niepowodzeń daje się w prostej linii wywieść od problemów
związanych z oprogramowaniem. W niektórych przypadkach programiści nie uwzględnili
rzadko zdarzających się sytuacji (ludzie żyjący dłużej niż 100 lat, rok przestępny i okres
przydatności do spożycia przecinający granicę lutego i marca), kiedy indziej ich wyobraźnia
okazała się niewystarczająca do uwzględnienia nietypowych zachowań ludzkich (opuszczenie
kabiny przez maszynistę po uprzednim włączeniu startera, eksploatowanie przez hakerów
luk bezpieczeństwa w oprogramowaniu sieciowym). Innym jeszcze razem dało o sobie znać
nieudolne zarządzanie realizacją systemu, czego efektem było przekroczenie ram czasowych
i budżetowych, bądź też dostarczenie, owszem, na czas i w założonym budżecie, systemu nie-
spełniającego oczekiwań klientów albo systemu nadmiernie skomplikowanego i stąd wysoce
podatnego na awarie.
Systemy informatyczne są tworami skomplikowanymi. Wykonują zwykle wiele funkcji,
tworzone są z myślą o osiągnięciu wielu różnych, często sprzecznych ze sobą, celów. Składają
się z wielu komponentów, z których większość to gotowe produkty innych („trzecich") pro-
ducentów, skomplikowane same w sobie — tworzone przy udziale specjalistów z wielu różnych
dziedzin. Realizacja typowego systemu informatycznego i jego cykl życiowy rozciągają się za-
zwyczaj na wiele lat. To wszystko przesądza o tym, że prawdziwy system informatyczny przekra-
cza możliwości ogarnięcia wszystkich jego szczegółów przez pojedynczą osobę. Niektóre systemy
są na tyle trudne do zrozumienia już na etapie opracowywania, że ich realizacja nie zostaje
ukończona — oprogramowanie tej fatalnej kategorii zyskało sobie potoczną nazwę vaporware2.
Projekty systemów informatycznych są z natury obiektami podatnymi na nieustanne
zmiany. Wymagania stawiane złożonemu systemowi same są skomplikowane, a często wymagają
też weryfikacji, gdy odkryty zostanie błąd w rozumowaniu bądź też programiści, w miarę
postępu w realizacji systemu, zaczynają coraz lepiej rozumieć rozmaite jego aspekty. Jeśli re-
alizacja takiego projektu ciągnie się przez lata, wiąże się z zaangażowaniem licznego personelu,
wymagającego niezbędnych szkoleń i treningu. Na przestrzeni owych wielu lat zmieniają się
także dostępne technologie — cykl życiowy określonej technologii implementacyjnej jest zwykle
krótszy niż cykl życiowy systemu, na potrzeby realizacji którego można tę technologię wy-
korzystywać. Jeżeli w tych warunkach menedżerowie projektu potraktują wymagania stawiane
systemowi jako byt raz określony i niezmienny, możemy być prawie pewni, że owocem
owych wielu lat pracy będzie system niespełniający oczekiwań użytkowników.
Ang. vapor — opar, mgła, mrzonka, trafna analogia czegoś, co nie miało szczęścia fizycznie zaistnieć,
mimo szczytnych koncepcji i celów — przyp. tłum.
38 Rozdział 1. • Wprowadzenie do inżynierii oprogramowania
1.2.1. Modelowanie
Zadaniem nauki jest opisywanie i rozumienie złożonych systemów, takich jak atomowa struk-
tura materii, zachowania ludzi i społeczności, czy Układ Słoneczny. Usankcjonowany, zgod-
nie z tradycją, podział dyscyplin naukowych na nauki przyrodnicze i nauki społeczne wyznacza
granicę umożliwiającą odróżnienie dwóch kategorii systemów. Przedmiotem zainteresowania
nauk przyrodniczych — biologii, chemii, fizyki czy paleontologii — jest przyroda (natura)
i jej podsystemy; dla odmiany, przedmiotem zainteresowania psychologii i socjologii, jako
nauk społecznych, jest ludzkie życie oraz interakcje międzyludzkie w ramach społeczności.
1.2. Czym jest inżynieria oprogramowania? 39
Odrębną grupę systemów stanowią systemy sztuczne, których przykładem może być
statek kosmiczny, rozproszona aplikacja rezerwacji miejsc w samolotach czy system obsługu-
jący transakcje giełdowe. H. Simon [Simon, 1970] określił nawet dyscypliny naukowe zajmu-
jące się takimi systemami jako sciences of the artificial („nauki o sztuczności"). Podczas gdy
nauki przyrodnicze i społeczne mają za sobą kilkusetletnią historię, sciences of the artificial
są bytem stosunkowo młodym — na przykład informatyka, rozumiana jako naukowe ujęcie
rozmaitych aspektów systemów komputerowych, jest dzieckiem XX wieku.
Wiele metod, z powodzeniem stosowanych w ramach nauk przyrodniczych i społecz-
nych, przydaje się także w odniesieniu do sciences of the artificial — jedną z nich jest modelo-
wanie. Model stanowi abstrakcyjną reprezentację systemu, umożliwiającą udzielenie odpo-
wiedzi na wiele pytań formułowanych pod adresem tegoż systemu. Model systemu staje się
użyteczny i często niezastąpiony, w sytuacji-gdy oryginalny system byłby zbyt ogromny, zbyt
miniaturowy, zbyt skomplikowany czy zbyt drogi w kontekście eksperymentowania. Modele
okazują się koniecznym substytutem systemów, które już nie istnieją, oraz tych, których ist-
nienie jest dopiero planowane.
Paleontolodzy odnajdują zachowane fragmenty kości i uzębienia dinozaurów, których
z oczywistych względów nigdy nie widzieli w naturze. Z tych fragmentów rekonstruują mo-
dele organizmów zwierzęcych, opierając się na regułach anatomii. Im więcej dostępnego
materiału z wykopalisk, tym klarowniejsza staje się idea, jak poszczególne elementy tego
materiału poskładać ze sobą, i tym większe zaufanie do modelu mającego odzwierciedlać
rzeczywisty organizm żyjącego w zamierzchłych czasach dinozaura. Dysponując dostateczną
ilością kości, zębów i szponów, mogą zyskać niemal całkowitą pewność co do tego, że ich
model odzwierciedla rzeczywistość z należytą dokładnością; co więcej — mogą formułować
rozmaite hipotezy dotyczące jego brakujących elementów: przykładowo, nogi występują zwykle
parami, jeśli zatem dysponują kośćmi jedynie lewej nogi, mogą w sposób niemal pewny
odtworzyć postać brakującej prawej nogi oraz jej pozycję w budowanym modelu. Tak z grubsza
prezentuje się modelowanie systemów, które już nie istnieją.
Podobnie ma się rzecz z modelowaniem systemów nierealistycznych bądź nieogarnio-
nych jak Wszechświat. Fizycy zajmujący się badaniem materii w obliczu wysokich energii
znajdują się na pozycji porównywalnej z położeniem paleontologów odnajdujących szczątki
prehistorycznych organizmów. Obserwując zachowanie cząstek elementarnych i mierząc ich
rozmaite właściwości, próbują stworzyć model materii i energii odzwierciedlający zarówno
ich makrostrukturę, jak i strukturę na poziomie subatomowym. Wieloletnie eksperymenty
przy użyciu akceleratorów cząstek elementarnych dostarczają fizykom coraz to więcej dowo-
dów na to, że budowane przez z nich modele należycie odzwierciedlają rzeczywistość, i jedno-
cześnie pozwalają im żywić nadzieję na to, że brakujące jeszcze ich elementy, gdy zostaną
już zidentyfikowane, również wpiszą się gładko w tzw. model standardowy.
W przypadku obu typów modelowania mamy do czynienia z encjami dwóch kategorii:
systemem rzeczywistym, manifestującym swą obecność poprzez fakty i zjawiska, oraz mode-
lem jego dziedziny aplikacyjnej, stanowiącej zbiór wzajemnie uzależnionych od siebie kon-
cepcji. Do pierwszej z wymienionych kategorii należą dinozaury i cząstki elementarne, do
drugiej — opisy tych ich aspektów, które okazują się istotne (relewantne) dla rozwiązywanego
właśnie problemu.
40 Rozdział 1. • Wprowadzenie do inżynierii oprogramowania
1. Sformułowanie problemu,
2. Analiza problemu,
3. Poszukiwanie dostępnych rozwiązań,
4. Wybór odpowiedniego rozwiązania,
5. Specyfikacja rozwiązania.
1.2. Czym jest inżynieria oprogramowania? 41
3
Georg Philipp Harsdórffer (1607 - 1658), Poetischer Trichter, die teutsche Dicht- und Reimkunst,
ohn Behuf der lateinischen Sprache, in 6 Stunden einzugiefien, Nuernberg, 1630.
42 Rozdział 1. • Wprowadzenie do inżynierii oprogramowania
Pozyskiwanie wiedzy nie jest jednak procesem linearnym: pojawienie się nowego faktu
czy nowej informacji może postawić pod znakiem zapytania lub po prostu przekreślić całą
dotychczasową wiedzę, jaką nabyliśmy podczas uczenia się rozumienia naszego systemu. I jeśli
nawet owo rozumienie zostało już odzwierciedlone w postaci dokumentacji i kodu źródło-
wego („kod systemu jest gotowy w 90%, resztę napiszemy w przyszłym tygodniu"), musimy
być mentalnie przygotowani na to, że pisanie dokumentacji czy (co ważniejsze) tworzenie
kodu systemu będziemy musieli rozpocząć od zera. A to w istotny sposób przekłada się na
zbiór aktywności i ich wzajemnych interakcji, jakie zdefiniowaliśmy w związku z tworzeniem
wspomnianego systemu. Na gruncie inżynierii oprogramowania odpowiednikiem teorii „umysłu
pojemnika" jest sekwencyjny model kaskadowy, zgodnie z którym poszczególne kroki zwią-
zane z tworzeniem systemu realizowane są w sposób sekwencyjny.
Istnieje kilka różnych technik i metodologii zmierzających do unikania krępującej se-
kwencyjności modelu kaskadowego — i tak na przykład istotą programowania sterowanego
ryzykiem jest przewidywanie zawczasu problemów, jakie mogą pojawić się w późnych sta-
diach realizacji projektu; dokonuje się tego poprzez identyfikowanie komponentów obarczonych
wysokim ryzykiem. Metodologia programowania sterowanego problemami zmierza natomiast
do całkowitego wyeliminowania narzuconej a priori linearności. Każda z poszczególnych
aktywności związanych z tworzeniem systemu — analiza, projekt systemu, projekt obiektów,
implementowanie, testowanie i wdrażanie — ma mniejszy lub większy wpływ na pozostałe
i na przykład na gruncie programowania sterowanego problemami wszystkie one realizo-
wane są równolegle. Takie nielinearne modele, choć bardziej adekwatne do realiów, mają tę
niedogodność, że trudno się nimi zarządza.
1.2.4. Racjonalizacja
Opisując pozyskiwanie wiedzy i jej ewoluowanie, z konieczności stajemy na pozycji mniej
pewnej w porównaniu z opisywaniem rzeczywistego, istniejącego systemu. Podręczniki wsze-
lakich dyscyplin matematycznych pełne są dowodów, rzadko jednak napotkać można w nich
wzmiankę na temat ich genezy, na temat inspiracji, jakie skierowały myślenie autora w tę czy
inną stronę. Dzieje się tak chyba dlatego, że matematycy nie uważają tego aspektu sprawy za
szczególnie istotny: gdy określi się zbiór pojęć pierwotnych, zbiór aksjomatów i reguł dedukcji,
sam dowód staje się kwestią wręcz automatycznej konstrukcji.
Inżynierowie programiści znajdują się w sytuacji cokolwiek trudniejszej. W przeciwień-
stwie do matematyków, obracających się w komfortowych środowisku ustalonych aksjo-
matów, muszą stawiać czoła nieustannym zmianom. I jeżeli nawet będą mieć to szczęście, że
modele dziedziny aplikacyjnej w miarę ustabilizują się po pewnych czasie, to na pewno modele
dziedziny realizacyjnej gwarantują borykanie się z nieustanną płynnością. Błędy projektowe
i implementacyjne, bezlitośnie obnażane w trakcie testowania, oraz problemy związane
z użytecznością objawiające się przy pierwszym kontakcie użytkowników z nowymi elemen-
tami systemu wymagają często nawet drastycznych zmian w modelu dziedziny realizacyjnej.
Zmiany takie mogą być również wymuszane przez postęp technologiczny: nowa kategoria
długożyciowych akumulatorów oraz nowe osiągnięcia w zakresie szybkiej komunikacji bez-
przewodowej z naturalnych względów wymagają zrewidowania przyjętych wcześniej kon-
cepcji projektowych przenośnego terminala.
1.3. Podstawowe koncepcje inżynierii oprogramowania 43
4
Staramy się przy tym zachować jak największą zgodność z definicjami standardów IEEE w zakre-
sie inżynierii oprogramowania [IEEE Std. 610.12-1990].
44 Rozdział 1. • Wprowadzenie do inżynierii oprogramowania
Rysunek 1.1. Podstawowe koncepcje inżynierii oprogramowania przedstawione w formie diagramów klas
UML [OMG, 2009]
5
T i c k e t D i s t r i b u t o r jest systemem stosunkowo prostym, dlatego Zoe pełni podwójną rolę: specja-
listy ds. czynnika ludzkiego i testera, podobnie podwójna rola — analityka i dokumentalisty — przy-
pisana jest Johnowi.
46 Rozdział 1. • Wprowadzenie do inżynierii oprogramowania
1.3.3. Produkty
Produkt to coś użytecznego, co powstaje w trakcie realizacji systemu, na przykład dokument
lub fragment programu, przeznaczony dla klienta lub na wewnętrzne potrzeby projektu — tę
drugą kategorię nazywa się często produktem wewnętrznym, należący natomiast do kategorii
pierwszej produkt określa się jako produkt docelowy. Te ostatnie definiowane są typowo
jeszcze przed rozpoczęciem projektu, na podstawie kontraktu wiążącego wykonawcę z klien-
tem. W tabeli 1.2 przedstawiliśmy krótki opis produktów związanych z systemem Ticket
"-•Distributor.
Raport o statusie Produkt Jest to bieżący raport o zadaniach, które już zostały zakończone,
projektu wewnętrzny i tych właśnie wykonywanych. Taki raport sporządzany jest
na użytek szefa (Alicji) i rzadko u d o s t ę p n i a n y klientom
(kompanii kolejowej).
Baza danych taryf i cennika Zasób Baza ta zawiera przykładowy plan taryfowy, wraz
z przykładową siecią połączeń. Klient będzie ją oceniać
pod względem zgodności ze swymi wymaganiami,
a następnie wykorzystywać do testowania powstających
fragmentów systemu.
48 Rozdział 1. • Wprowadzenie do inżynierii oprogramowania
dostarcza ona przeto żadnych metod zbierania wymagań. Metodologia jednolitego procesu
(Unified Software Development Process)1' także obejmuje aktywność analizy, lecz w przeciwień-
stwie do OMT aktywności projektowania systemu i projektu obiektów połączone są w po-
jedynczą aktywność zwaną projektowaniem. Z kolei metodologia Catalysis, stosując tę samą
notację, co jednolity proces, skupia się w większym stopniu na wielokrotnym wykorzystywaniu
projektów i kodu, dostarczając odpowiednich wzorców i narzędzi do tego celu. Niezależnie
jednak od opisanych różnic, wszystkie wymienione metodologie stworzone zostały w tym
samym celu — w celu uporania się ze złożonością tworzonych systemów.
W książce tej prezentujemy metodologię tworzenia złożonych systemów w obliczu ko-
niecznych, dynamicznych zmian. W czasie prowadzonych przez nas kursów i badań ([Bruegge,
1992], [Bruegge i Coyne, 1993], [Bruegge i Coyne, 1994], [Coyne i in., 1995]) zaadaptowaliśmy
i udoskonaliliśmy wiele metod zaczerpniętych z różnych źródeł. W związku z aktywnościami
modelowania dziedziny aplikacyjnej, czyli zbieraniem wymagań i analizą, opisujemy metody
podobne do przedstawionych w OOSE [Jacobson i in. 1992]. Dla aktywności związanych z mo-
delowaniem dziedziny realizacyjnej, takich jak projektowanie systemu i projekt obiektów,
przewidzieliśmy zorientowane obiektowo aktywności podobne do znanych z OMT. Wśród ak-
tywności związanych z zarządzaniem zmianami szczególną uwagę poświęcamy zarządzaniu
racjonalizacją, wzorując się na badaniach racjonalizacji projektowej [Moran & Carroll, 1996],
oraz zarządzaniu konfiguracją w sposób zbliżony do opisanego [Babich, 1986] w związku
z konserwowaniem dużych systemów.
6
Patrz sekcja 15.4.2 — przyp. tłum.
50 Rozdział 1. • Wprowadzenie do inżynierii oprogramowania
Rysunek 1.2. Ogólny obraz aktywności związanych z obiektowo zorientowanym tworzeniem oprogra-
mowania oraz produktów generowanych przez te aktywności. Powyższy diagram odzwierciedla jedynie
logiczne zależności między produktami; obiektowo rozumiana inżynieria oprogramowania jest dyscy-
pliną iteracyjną — niektóre aktywności mogą występować w wielu instancjach i równolegle z innymi
Sekwencja zdarzeń 1. Travel er wybiera strefę, w której zlokalizowana jest stacja docelowa
2. Ti cketDi s t r i b u t o r wyświetla cenę biletu.
3. Travel e r wprowadza do automatu środki płatnicze w wysokości
nie niższej niż cena biletu.
4. Ti cketDi s t r i butor drukuje żądany bilet i wydaje ewentualną resztę.
Warunek wstępny Travel e r staje przed automatem zlokalizowanym na stacji początkowej
lub dowolnej stacji pośredniej.
Wymagania jakościowe Jeżeli transakcja nie została ukończona, a bezczynność Travel era trwa
dłużej niż minutę, Ti cketDi s t r i butor zwraca ewentualną gotówkę
wprowadzoną już przez Travel e r a w ramach bieżącej transakcji.
1.4.2. Analiza
Na etapie analizy programiści dążą do stworzenia modelu systemu — poprawnego, kom-
pletnego, spójnego i wolnego od niejednoznaczności. Dokonują transformacji przypadków
użycia, zdefiniowanych podczas zbierania wymagań, w model obiektowy, który jest komplet-
nym opisem systemu. Ewentualne przejawy niejednoznaczności i niespójności w modelu
przypadków użycia wyjaśniane są w drodze negocjacji z klientem. Rezultatem analizy jest mo-
del systemu wzbogacony o atrybuty, operacje i skojarzenia. Model ten daje się opisać w kate-
goriach struktury systemu i jego dynamicznego współdziałania. Na rysunku 1.3 przedstawiamy
przykładowy model dynamiczny systemu Ti cketDi s t r i butor, zaś na rysunku 1.4 — jego
model obiektowy.
Etap analizy, z uwzględnieniem modeli obiektowych, opisujemy z detalami w roz-
dziale 5. „Analiza wymagań", zaś szczegóły notacji UML wykorzystywanej do reprezento-
wania obiektów wyjaśniamy w rozdziale 2. „Modelowanie w języku UML".
Rysunek 1.3. Model dynamiczny systemu Ti cketDi s t r i butor (diagram sekwencyjny UML). Na dia-
gramie tym uwidoczniliśmy obiekty będące elementami przypadku użycia PurchaseOneWayTi cket
oraz interakcje zachodzące między systemem a aktorem Travel e r w ramach tego przypadku
Rysunek 1.4. Model obiektowy systemu Ti cketDi s t r i b u t o r (diagram klas UML). W ramach przy-
padku użycia PurchaseOneWayTi cket aktor Traveler inicjuje transakcję, reprezentowaną przez obiekt
Transaction, której rezultatem jest wyprodukowanie obiektu Ticket. Bilet reprezentowany przez ten
obiekt ważny jest tylko w strefie reprezentowanej przez obiekt Zone. W ramach wspomnianej transakcji
system kontroluje jej bilans (reprezentowany przez obiekt Bal ance), zliczając narastająco wartość wpro-
wadzanych do automatu monet (Coi n) i porównując tę wartość z ceną biletu (Bi 11)
Rysunek 1.5. Przykład dekompozycji systemu Ti cketDi s t r i butor (diagram klas UML — pakiety repre-
zentują podsystemy, a linie przerywane — zależności między nimi). Podsystem Travel e r l n t e r f a c e
odpowiedzialny jest za kolekcjonowanie informacji wejściowych i sprzężenie zwrotne z podróżnym
(między innymi wyświetlenie ceny biletu, wydrukowanie biletu, wydanie reszty). Zadaniem podsystemu
Local T a r i f f jest obliczenie ceny biletu na podstawie cennika zapisanego w lokalnej bazie danych.
Podsystem Central Tari f f, zlokalizowany na centralnym komputerze, ma za zadanie utrzymywanie
kopii referencyjnej bazy danych taryfowych; zapewnienie zgodności z tą kopią każdej lokalnej bazy
w poszczególnych egzemplarzach systemu T i c k e t D i s t r i b u t o r jest zadaniem podsystemu Updater
1.4.5. Implementowanie
Implementowanie to tłumaczenie dziedziny realizacyjnej na kod źródłowy aplikacji. W prak-
tyce oznacza to kodowanie atrybutów i metod każdego obiektu w języku programowania i in-
tegrowanie wszystkich obiektów w funkcjonujący pojedynczy system. Aktywność implemen-
towania wypełnia lukę pomiędzy uszczegółowionym projektem obiektów a kompletnym,
kompilowalnym kodem źródłowym. Czynność mapowania modeli UML w kod źródłowy opi-
szemy szczegółowo w rozdziale 10. „Odwzorowywanie modelu na kod"; zakładamy, że czytel-
nikom nieobce są podstawowe koncepcje programistyczne oraz umiejętność programowania
struktur danych i algorytmów w języku zorientowanym obiektowo, takim jak Java czy C++.
54 Rozdział 1. • Wprowadzenie do inżynierii oprogramowania
1.4.6. Testowanie
Testowanie to etap wynajdywania różnic między urzeczywistnionymi fragmentami systemu
a ich modelami, za pomocą specjalnie przygotowanych w tym celu danych wejściowych. I tak
w czasie testowania modułów programiści porównują modele stworzone na etapie projekto-
wania obiektów z każdym zaimplementowanym modelem i podsystemem; testy integracyjne
to weryfikacja prawidłowości połączenia podsystemów w całość, w kontekście modelu stwo-
rzonego na etapie projektowania systemu. Wreszcie, na etapie testowania systemowego na-
stępuje konfrontacja zachowania się systemu w nietypowych i wyjątkowych sytuacjach z mo-
delem stworzonym na etapie zbierania wymagań. Celem testowania jest wykrycie jak największej
liczby usterek i poprawienie ich przed dostarczeniem systemu klientowi. Planowanie poszcze-
gólnych rodzajów testów odbywa się równolegle z innymi fazami tworzenia systemu — i tak
testy systemowe planowane są równolegle ze zbieraniem wymagań i analizą, planowanie testów
integracyjnych towarzyszy projektowaniu systemu, zaś projektowanie obiektów połączone
jest z planowaniem testów modułowych. Zależności te opiszemy dokładniej w rozdziale 11.
„Testowanie".
Gdy gotowy system zostanie przekazany klientowi, rozpoczyna się proces, który nazwać
można ogólnie utrzymaniem lub konserwację tegoż systemu. W książce nie będziemy zajmo-
wać się tą tematykę, ograniczymy się do kilku uwag w tym miejscu. Tradycyjnie konserwację
powierza się zespołowi innemu niż ten, który system wyprodukował; czyni się tak ze względu
na fakt, że jest ona procesem wybitnie sterowanym zachodzącymi zmianami i z definicji od-
dzielonym od tworzenia systemu. Ponieważ jednak współczesne projekty informatyczne także
realizowane są w obliczu dynamicznych zmian, granica między jednym a drugim staje się co-
kolwiek płynna; w rezultacie wiele opisywanych w tej książce aktywności — projektowanie
obiektów, implementowanie, testowanie, zarządzanie racjonalizacją i konfiguracją — realizo-
wanych jest także w fazie konserwacji.
1.5. Zarządzanie tworzeniem oprogramowania 55
1.5.1. Komunikacja
Komunikacja to najbardziej krytyczna i czasochłonna aktywność inżynierii oprogramowania.
Nieporozumienia i przeoczenia często prowadzą do powstawania usterek i opóźnień, kosz-
townych i trudnych do naprawienia w późniejszych fazach. Komunikacja obejmuje wymianę
modeli i dokumentów dotyczących systemu i jego dziedziny aplikacyjnej, raportowanie statusu
produktów i realizowanie sprzężenia zwrotnego dotyczącego ich jakości, formułowanie i ne-
gocjowanie problemów oraz oznajmianie różnorodnych decyzji.
Komunikacja staje się utrudniona ze względu na różnice między kwalifikacjami po-
szczególnych uczestników, na ich rozproszenie geograficzne oraz ze względu na komplek-
sowość, rozmiar i ewoluowanie wymienianej informacji.
Aby sprawnie radzić sobie z tymi trudnościami, uczestnicy mają do dyspozycji wiele
metod i narzędzi, wśród których do najbardziej efektywnych zaliczyć należy wszelkiego ro-
dzaju konwencje: gdy uczestnicy porozumieją się co do notacji reprezentującej informację, co
do narzędzi służących do jej przetwarzania oraz procedur zgłaszania i negocjowania proble-
mów, eliminują tym samym dość spory repertuar potencjalnych źródeł rozmaitych nieporo-
zumień. Przykładem takiej uzgodnionej notacji mogą być diagramy UML, szablony różnych
dokumentów czy schematy nazewnictwa poszczególnych komponentów aplikacji. Do narzę-
dzi tego rodzaju zaliczyć można te z kategorii CASE (Computer Aided Software Engineering
— „wspomagana komputerowo inżynieria oprogramowania") służące do operowania na mo-
delach, edytory tekstów i standardy formatów publikowania informacji. Przykładowymi pro-
cedurami komunikacyjnymi mogą być wzorcowe zasady organizowania, prowadzenia i do-
kumentowania spotkań roboczych, procedury analizowania i oceniania dokumentów czy
procedury inspekcyjne zmierzające do wykrywania defektów w modelach i kodzie źródłowym.
Uzgodnione konwencje nie muszą być „najlepsze iż najlepszych": ważne jest, by były zrozu-
miałe dla wszystkich uczestników i przez wszystkich akceptowane. Zagadnienia związane ze
sprawnym komunikowaniem się opisujemy w rozdziale 13. „Zarządzanie konfiguracją".
1.5.6. Podsumowanie
Treść rozdziałów od 1. do 15. tej książki odzwierciedla bieżący stan wiedzy na temat metod
obiektowo zorientowanej inżynierii oprogramowania. Czytelnicy mogą potraktować tę treść
jako zawartość swoistej książki kucharskiej — problem jednak w tym, że książka kucharska
rzadko jest wystarczająca dla nowicjusza sztuki kulinarnej: nie zdoła on przygotować kom-
pletnego posiłku, polegając wyłącznie na książce kucharskiej. Gdy zabraknie mu któregoś
składnika i jest zmuszony improwizować, nie zda się ona na nic.
Dwa rozdziały: 14. „Zarządzanie konfiguracją", o treści skupiającej się na planowa-
niu i kontrolowaniu projektów, oraz 15. „Cykl życiowy oprogramowania" poświęcony
modelowaniu, usprawnianiu i powtarzalności procesów składających się na cykl życiowy
aplikacji, koncentrujące się na technikach i modelach, niosą optymistyczne raczej przesłanie
w kwestii realizowania projektów informatycznych. W rozdziale 16. „Wszystko razem, czy-
li metodologie" zajmujemy się jednak sytuacjami wymagającymi wyjścia poza tradycyjną
wiedze podręcznikową: opisujemy metodologie i heurystyki służące realizowaniu koncepcji
opisywanych w poprzednich rozdziałach, tyle że w specyficznych warunkach, przedstawiamy
kilka „zwinnych" i mniej zwinnych metodologii.
budżecie. Od tego czasu minęło wiele lat, programiści dostali do swych rąk nowe technologie,
narzędzia i metody — po to, by dzielniej zmagać się z kolejnymi problemami, coraz bardziej
kosztownymi coraz bardziej spektakularnymi. Wiele podstawowych lekcji wyniesionych z do-
świadczeń minionych dekad wciąż zachowuje swą aktualność.
Książka P. Neumanna [Neumann, 1995] zawiera ciekawy przegląd rozmaitych nieszczęść
spowodowanych (ogólnie rzecz ujmując) wadami technologii informatycznych. Autor, uświa-
damiając czytelnikom powagę konsekwencji, jakie nieść może ze sobą ułomność procesu
wytwarzania oprogramowania, rozważa jednocześnie przyczyny opisywanych niepowodzeń
i dostarcza wskazówki pomagające unikać takich i podobnych incydentów. Tę naprawdę rze-
czową książkę przeczytać powinien każdy programista, któremu choćby tylko marzy się two-
rzenie skomplikowanych systemów informatycznych.
Książka K. Poppera [Popper, 1992] to esej na temat konstruowania wiedzy. Autor zrywa
z tradycyjnymi teoriami w tym względzie, datującymi się jeszcze z czasów Arystotelesa, przed-
stawiając własny punkt widzenia, zgodnie z którym wiedza naukowa, od kiedy tylko zaistniała
jako pojęcie, rozwija się jako odrębna całość poprzez selekcję. Jako że tworzenie oprogramo-
wania jest procesem zespołowym, związanym ze zdobywaniem wiedzy i konstrukcją, wspo-
mniana książka może być użyteczna jako zachęcająca do krytycznych przemyśleń i cechująca
się niecodziennym spojrzeniem na inżynierię oprogramowania.
W tej książce skupiamy się na obiektowo zorientowanej inżynierii oprogramowania i ad-
resujemy ją do zaawansowanych kursów o tej tematyce. W konsekwencji pomijamy więc wiele
zagadnień o charakterze historycznym lub czysto menedżerskim, takich jak metryki opro-
gramowania, szacowanie kosztów czy metody formalne konstruowania programów. Prze-
gląd tych zagadnień zainteresowani czytelnicy znajdą w podręcznikach o bardziej ogólnym
charakterze, takich jak na przykład autorstwa I. Sommerville'a [Sommerville, 2006] czy
R. S. Pressmana [Pressman, 2009].
1.8. Ćwiczenia
1.1. Co jest celem modelowania?
1.2. Język programowania to notacja przeznaczona do reprezentowania algorytmów
i struktur danych. Wymień dwie zalety i dwie wady użytkowania tej notacji jako
jedynej w procesie tworzenia aplikacji.
1.3. Wyobraź sobie, że stajesz w obliczu realizacji zadania, na temat którego masz nikłe
pojęcie — na przykład przed skonstruowaniem samochodu w ogóle nieprodukują-
cego spalin. Jak zabrałbyś się do takiego zadania?
1.4. Jak rozumiesz stwierdzenie „pozyskiwanie wiedzy nie jest procesem sekwencyjnym"?
Podaj konkretny przykład uzasadniający prawdziwość tego stwierdzenia.
1.5. Spróbuj wymyślić hipotetyczną racjonalizację dla następujących decyzji projektowych:
• Automat realizujący system Ti cketDi s t r i butor nie może być wyższy niż półtora
metra.
• System Ti cketDi s t r i butor powinien być zrealizowany w oparciu o dwa dublujące
się komputery.
60 Rozdział 1. • Wprowadzenie do inżynierii oprogramowania
Bibliografia
[Babich, 1986] W. Babich Software Configuration Management, Addison-Wesley, Reading,
MA, 1986.
[Booch, 1994] G. Booch Object-Oriented Analysis and Design with Applications, wyd. drugie,
Benjamin/Cummings, Redwood City, CA, 1994.
[Brooks, 1995] F. P. Brooks The Mythical Man Month: Anniversary Edition: Essays on Software
Engineering, wyd. Addison-Wesley, Reading, MA, 1995.
[Bruegge, 1992] B. Bruegge „Teaching an industry-oriented software engineering course",
Software Engineering Education, SEI Conference, Lecture Notes in Computer
Sciences, t. 640, str. 65 - 87, Springer-Verlag, październik 1992.
[Bruegge i Coyne, 1993] B. Bruegge, R. Coyne „Model-based software engineering in larger scale
project courses", IFIP Transactions on Computer Science and Technology,
t. A-40, str. 273 - 287, Elsevier Science, Netherlands, 1993.
[Bruegge i Coyne, 1994] B. Bruegge, R. Coyne „Teaching iterative object-oriented development:
Lessons and directions", w: J. L. Diaz-Herrera (red.), 7h Conference on
Software Engineering Education, Lecture Notes in C o m p u t e r Science,
t. 750, str. 413 - 427, Springer-Verlag, 1994.
[Coyne i in., 1995] R. Coyne, B. Bruegge, A. Dutoit, D. Rothenberger „Teaching m o r e
c o m p r e h e n s i v e model-based software engineering: Experience with
Objectory's use case approach", w: L. Ibraham (red.), 8'k Conference on
Software Engineering Education, Lecture Notes in C o m p u t e r Science,
str. 339 - 374, Springer-Verlag, kwiecień 1995.
[De Marco, 1978] T. De M a r c o Structured Analysis and System Specification, Yourdon,
N e w York, 1978.
[D'Souza i Wills, 1999] D. F. D'Souza, A. C. Wills Objects, Components, and Frameworks with UML:
The Catalysis Approach, Addison-Wesley, Reading, MA, 1999.
[IEEE Std. 610.12-1990] IEEE Standard Computer Dictionary: A Compilation of IEEE Standard
ComputerGlossaries, NY, 1990.
[Jacobson i in. 1992] I. Jacobson, M. Christerson, P. Jonsson, G. Overgaard Object-Oriented Software
Engineering — A Use Case Driven Approach, Addison-Wesley, Reading, MA, 1992.
[Moran i Carroll, 1996] T. P. Moran i J. M. Carroll (red.) Design Rationale: Concepts, Techniques,
and Use, Lawrence Erlbaum Associates, Mahwah, NJ, 1996.
[Neumann, 1995] P. G. Neumann Computer-Related Risks, Addison-Wesley, Reading, MA, 1995.
[OMG, 2009] Object Management Group, OMG Unified Modeling Language Specification.
Version 2.2, 2009. http://www.omg.org.
[Popper, 1992] K. P o p p e r Objective Knowledge: An Evolutionary Approach, Clarendon,
O x f o r d , 1992.
[Pressman, 2009] R S. Pressman Software Engineering: A Practitioner's Approach, wyd. siódme,
McGraw-Hill, 2009.
[Royce, 1998] W . Royce Software Project Management: A Unified Framework,
Addison-Wesley, Reading, MA, 1998.
[Rumbaugh i in., 1991] J. Rumbaugh, M. Błaha, W. Premerlani, F. Eddy, W. Lorensen Object-Oriented-
Modeling and Design, Prentice Hall, Englewood Cliffs, NJ, 1991.
[Simon, 1970] H. A. Simon The Sciences of the Artificial, MIT Press, Cambridge, MA, 1970.
[Sommerville, 2006] I. Sommerville Software Engineering, wyd. ósme Addison-Wesley,
Reading, MA, 2006.
[Spivey, 1989] J. M. Spivey The Z Notation, A Reference Manual, Prentice Hall, Hertfordshire,
2.1. Wprowadzenie 64
Bibliografia 109
Modelowanie
m
w języku UML
2.1. Wprowadzenie
Język UML powstał jako efekt unifikacji kilku innych notacji: OMT (Object Modeling Technique
[Rumbaugh i in., 1991]), notacji Boocha [Booch, 1994] oraz OOSE (Object-Oriented Software
Engineering [Jacobson i in., 1992]). Pewien wpływ na ostateczną postać języka wywarło także
kilka innych standardów, takich jak notacje zaproponowane przez Mellora i Shlaer [Mellor
i Shlaer, 1998], Coada i Yourdona [Coad i in., 1995], Wirfs-Brock [Wirfs-Brock i in., 1990]
oraz Martina i Odella [Martin & Odell, 1992],
Celem języka UML jest dostarczenie standardowej notacji, która z jednej strony byłaby
użyteczna dla wszelkich metodologii zorientowanych obiektowo, z drugiej natomiast pro-
mowała najlepsze cechy swych poprzedniczek. Istotnie, w języku UML spotkać możemy dia-
gramy przypadków użycia przejęte z OOSE oraz wiele cech wywodzących się z OMT diagramów
klas. Jednocześnie UML przynosi wiele nowatorskich, niespotykanych wcześniej koncepcji,
takich jak mechanizmy rozszerzające czy język ograniczeń. UML zaprojektowany został z myślą
o szerokim zakresie zastosowań, dostarcza zatem konstrukcji przydatnej dla systemów i ak-
tywności różnego rodzaju (na przykład systemów rozproszonych, analizy systemów, pro-
jektowania systemu czy wdrażania). Tworzenie systemu ujmowane jest z perspektywy UML
w postaci trzech różnych modeli (patrz rysunek 1.2). Oto one.
w sekcji 2.3 opiszemy fundamentalne koncepcje modelowania, w sekcji 2.4 przyjrzymy się
dokładniej pięciu wymienionym rodzajom diagramów w świetle tychże koncepcji, zaś w kolej-
nych rozdziałach omawiać będziemy owe diagramy na rozmaitym poziomie szczegółowości,
przy okazji dyskusji na temat odzwierciedlanych przez nie aktywności.
Rysunek 2.1. Diagram przypadków użycia ukazujący funkcjonalność prostego zegarka Simpl eWatch.
Aktor WatchUser może bądź to odczytywać wskazanie czasu (przypadek użycia ReadTime), bądź je
korygować (przypadek użycia SetTime). Jednak tylko aktor WatchRepai rPerson może wymieniać baterię
w zegarku (przypadek użycia ChangeBattery). Aktorzy reprezentowani są na diagramie przez sugestywne
figurki, zaś przypadki użycia — przez elipsy. Prostokąt otaczający elipsy jest granicą między aktorami
a przypadkami użycia
skojarzony jest z obiektami klas PushButton, Display, Time i Battery reprezentującymi od-
powiednio przyciski, wyświetlacze, czas i baterie. Liczby przy końcach linii oznaczających
skojarzenia ukazują liczbę skojarzonych obiektów — i tak obiekt klasy Simpl eWatch skoja-
rzony jest z dokładnie dwoma obiektami klasy PushButton (zegarek ma dwa przyciski), jed-
nym obiektem klasy Di spl ay (zegarek jest prosty, ma więc jeden wyświetlacz) i jednym obiek-
tem klasy Time (każdy zegarek, jakkolwiek byłby nastawiony, wskazuje w danej chwili jakiś
konkretny czas), i dwoma obiektami klasy Battery (dwie bateryjki służą do zasilania zegarka).
Podobnie każdy obiekt klas PushButton, Di spl ay, Time i Battery skojarzony jest z dokładnie
jednym obiektem klasy Simpl eWatch (zakładamy, że bateria znajduje się wewnątrz zegarka
i wskazuje on jakiś czas).
Na etapie analizy skojarzenia z diagramu reprezentują istniejące w rzeczywistości związki
między encjami — i tak na przykład zegarek (Simpl eWatch) wyposażony jest w odpowiednią
liczbę przycisków (PushButton), posiada wyświetlacz (Di spl ay), wskazuje konkretny czas
(Time) i zasilany jest energią pochodzącą z odpowiedniej liczby bateryjek (Battery). W tym
przykładzie skojarzenia są symetryczne: zegarek nie mógłby funkcjonować bez przycisków, zaś
przycisk nie ma znaczenia samoistnego, a istnieje jedynie jako część zegarka. UML umożliwia
także reprezentowanie relacji jednokierunkowych, czego przykłady przedstawimy w sekcji
2.4.2. Na etapie implementacji skojarzenia odzwierciedlane są jako referencje lub wskaźniki
(pointers) do obiektów.
2.2. Ogólnie o UML 67
Rysunek 2.3. Diagram sekwencji dla zegarka (: Watch). Skrajna lewa kolumna reprezentuje moment,
w którym aktor : WatchUser inicjuje przypadek użycia. Pozostałe kolumny związane są z obiektami
uczestniczącymi w przypadku użycia. Podkreślenie nazwy obiektu oznacza, że mamy do czynienia z kon-
kretnym obiektem, nie z całą klasą. Etykietowane strzałki reprezentują sygnały (bodźce), które aktor
lub inny obiekt wysyła do innych obiektów
Rysunek 2.4. Diagram stanów dla przypadku użycia SetTime zegarka Watch
Rysunek 2.5. Przykład diagramu aktywności, reprezentującego zachowanie systemu w kategoriach ak-
tywności i ich warunków wstępnych: zakończenie jednej aktywności może stanowić wyzwalacz inicjujący
inną aktywność (Openlncident — reakcja na zdarzenie, „otwarcie" incydentu; Al locate Resources
— przydzielenie zasobów niezbędnych do obsługi incydentu; Coordinate Resources — koordynacja
wykorzystywania zasobów; Document Incident — dokumentowanie incydentu; Archive Incident
— przeniesienie dokumentacji incydentu do archiwum)
Tak z grubsza prezentują się diagramy pięciu kategorii, składające się na podstawową
notację UML. W następnych sekcjach przyjrzymy się im bardziej szczegółowo: w sekcji 2.3
omówimy podstawowe koncepcje modelowania — pojęcia systemu, modelu, typu, instancji,
abstrakcji i falsyfikacji. W sekcjach 2.4.1 - 2.4.5 opiszemy szczegółowo diagramy przypadków
użycia, diagramy klas, diagramy sekwencji, diagramy stanów i diagramy aktywności, ilustrując
ich zastosowania prostymi przykładami. Sekcję 2.4.6 poświęcimy różnorodnym konstrukcjom
pokrewnym, wykorzystywanym we wszystkich pięciu typach diagramów — między innymi
pakiety i notatki. Notację tę stosować będziemy w całej książce w celu opisywania systemów
informatycznych, produktów, aktywności i organizacji projektów. Wykorzystując systema-
tycznie, w sposób spójny, niewielkie podzbiory tej notacji, mamy nadzieję dostarczyć czy-
telnikowi obszerną wiedzę na temat możliwości języka UML.
zanim jeszcze zdążylibyśmy zapytać klienta o cokolwiek. Nieuniknione w tej sytuacji póź-
niejsze korekty i poprawki — jako skutek zmieniających się wymagań klienta — byłyby bardzo
pracochłonne i zajmowałyby dużo czasu.
Niestety, często same modele bywają bardzo skomplikowane i trudne do zrozumienia.
Na szczęście, paradygmat „dziel i zwyciężaj" i tutaj przychodzi z pomocą, dostarczając kolejny
środek upraszczający — widoki. Widok to podzbiór wybranych cech modelu, bardziej zrozu-
miały niż model ujmowany całościowo. Jak pokazaliśmy to na rysunku 2.6, zbiór podręczników
i instrukcji serwisowych związanych z samolotem jest właśnie takim podzbiorem, podobnie jak
system paliwowy czy system okablowania. Jest zrozumiałe, że widoki nie muszą być rozłączne
— na przykład elementem okablowania samolotu jest okablowanie jego systemu paliwowego.
Rysunek 2.6. Model jest abstrakcją opisującą podzbiór systemu, podobnie widok ukazuje tylko wybrany
aspekt modelu. Poszczególne widoki tego samego modelu mogą nakładać się na siebie
Notacja to tekstowe lub graficzne reguły reprezentowania widoków. Diagram klas jest
graficznym widokiem modelu obiektowego. Na diagramie okablowania samolotu każda linia
ciągła reprezentuje przewód lub wiązkę przewodów. Na diagramie klas prostokąt opatrzony
tytułem reprezentuje klasę, zaś linia łącząca dwa prostokąty odpowiada relacji istniejącej mię-
dzy odnośnymi klasami. Zauważmy, że ten sam widok może być reprezentowany w formie
różnych notacji, czego przykładem jest rysunek 2.7.
Rysunek 2.7. Przykład przedstawienia modelu w formie dwóch różnych notacji. Na wspomniany
model składają się dwie klasy: Książka i Rozdział, połączone oczywistą zależnością „Książka składa się
z rozdziałów". W notacji UML klasy przedstawione są w formie prostokątów, zaś agregacja symboli-
zowana jest przez linię zakończoną małym rombem. W notacji Boocha natomiast klasy przedstawiane
są w formie chmur, zaś linia reprezentująca agregację zakończona jest zaczernionym kółeczkiem
72 Rozdział 2. • Modelowanie w języku UML
1
Odwołania do operacji będą mieć w tej książce postać nazwy, po której następuje lista parametrów
zamknięta w nawias; dla operacji bezargumentowych jest to nawias pusty. Operacjami zajmiemy
się szczegółowo w następnej sekcji.
2.3. Podstawowe koncepcje modelowania 73
Rysunek 2.8. Diagram klas prezentujący dwie powiązane klasy — Watch i CalculatorWatch. Klasa
Cal cul atorWatch stanowi rozwinięcie klasy Watch o elementy typowe dla kalkulatora, niespotykane
w „normalnych" zegarkach. Na diagramach UML klasy reprezentowane są przez prostokąty podzielone
w pionie na trzy części: w najwyższej z nich znajduje się nazwa klasy, w środkowej — jej atrybuty, w naj-
niższej natomiast wyszczególnione są jej operacje. W niektórych przypadkach dwie ostatnie części po-
mijane są ze względów prostoty lub przejrzystości. Relacja dziedziczenia odzwierciedlona jest przez li-
nię zakończoną małym trójkątem, zlokalizowanym po stronie superklasy
Jeżeli klasa pełni jedynie rolę generalnego wzorca dla swych subklas, dostarczając im
wspólnych atrybutów i operacji, a więc gdy nie przewiduje się tworzenia jej instancji (obiek-
tów), nazywamy ją klasą abstrakcyjną. Klasy abstrakcyjne używane są do reprezentowania
ogólnych koncepcji dziedziny aplikacyjnej, a ich nazwy wyróżniane są na diagramach pochy-
loną czcionką. W diagramie na rysunku 2.9 klasa Benzen reprezentująca związek chemiczny
o tej samej nazwie i o określonej strukturze molekularnej jest subklasą klasy ZwiqzekOrganiczny,
reprezentującej jakąś substancję chemii organicznej w ogólności, bez jakiejś konkretnej struk-
tury molekuł.
2
Często zwana także „klasą bazową" lub „klasą macierzystą" — przyp. tłum.
' Często nazywana też „klasą pochodną" — przyp. tłum.
74 Rozdział 2. • Modelowanie w języku UML
Rysunek 2.9. Przykład klasy abstrakcyjnej: klasa ZwiązekOrganiczny nie reprezentuje żadnego konkret-
nego związku chemicznego, istnieje tylko jako reprezentant wszystkich związków organicznych w ogólności.
Jej nazwa, jako nazwa klasy abstrakcyjnej, pisana jest na diagramie klas kursywą
W języku Java klasa abstrakcyjna Col 1 ecti on uosabia wspólne cechy wszystkich kolekcji
i pełni rolę superldasy dla klas reprezentujących konkretne rodzaje kolekcji, między innymi
Li nkedLi s t , ArrayLi s t i HashMap. W przeciwieństwie do tych ostatnich, klasa Col 1 ecti on jest
zbyt ogólna na to, by można było tworzyć jej instancje. Należy w tym miejscu zauważyć, że nie
wszystkie klasy generalizujące pewną funkcjonalność są klasami abstrakcyjnymi — nie jest
na przykład klasą abstrakcyjną klasa Watch z diagramu na rysunku 2.8. Na gruncie modelo-
wania systemów informatycznych klasy abstrakcyjne niekiedy nie posiadają odpowiedników
w postaci koncepcji z dziedziny aplikacyjnej, lecz wprowadzane są do modelu raczej z myślą
o zredukowaniu jego złożoności czy też wielokrotnym wykorzystaniu pewnych wzorców.
Częścią definicji klasy jest definicja jej operacji, którym poddawane są instancje klasy.
Operacja zdefiniowana w superklasie może być dziedziczona przez subklasę i stosowana do
jej obiektów. Przykładowo w diagramie na rysunku 2.8 operacja SetDate(d), odpowiadająca
ustawieniu konkretnej daty w zegarku reprezentowanym przez klasę Watch, stosuje się także
do obiektów klasy Cal cul atorWatch. Dla odróżnienia, definiowana w subklasie operacja
EnterCal cMode() nie ma sensu w odniesieniu do klasy Watch.
Atrybutem klasy jest jej nazwana własność, określona w odniesieniu do każdego jej
obiektu z osobna. Każdy atrybut ma w ramach klasy unikalną nazwę i posiada określony typ.
Klasa Watch posiada atrybuty time i date; klasa Cal cul atorWatch, dziedzicząc te atrybuty ze
swej superldasy, dodaje do nich atrybut cal cul a t o r S t a t e .
Obiekt jest instancją klasy. Każdy obiekt jest jednoznacznie identyfikowany i przecho-
wuje określony zbiór wartości atrybutów swej klasy. Każdy obiekt należy do dokładnie jednej
klasy. Na diagramach UML obiekty reprezentowane są w postaci prostokątów, a ich nazwa jest
podkreślona. Podkreślenie ma na celu odróżnienie obiektów od Idas4. W diagramie na rysunku
2.10 obiekt simpl eWatchl291 jest instancją klasy Watch, a obiekt calculatorWatchl515 jest
instancją klasy Cal cul atorWatch. Warto zwrócić uwagę na pewien ważny fakt: mimo iż obiekt
cal cul atorWatchl515 nie jest instancją klasy Watch, stosują się do niego operacje tej klasy.
Atrybuty obiektu mogą być widoczne dla innych części systemu, zależnie od konkretnego
języka programowania; język Java umożliwia bardzo szczegółowe definiowanie widoczności
poszczególnych atrybutów.
4
Podkreślenia używamy także do oznaczenia lokalizatorów URL, zatem w celu polepszenia czytelności
nie podkreślamy nazw obiektów w tekście otwartym, przez co stają się one nieodróżnialne od nazw klas.
Staramy się jednak przy tym, by zawsze w takich sytuacjach jasno wynikało z kontekstu, czy mamy do
czynienia z klasą, czy też z konkretnym obiektem. W diagramach na rysunkach podkreślenia są jednak
konsekwentnie stosowane.
2.3. Podstawowe koncepcje modelowania 75
Rysunek 2.10. Dwie klasy i ich instancje na diagramie UML. Mimo iż operacje klasy Watch stosują się
także do obiektu cal cul atorWatchl515, ten nie jest instancją klasy Watch
Rysunek 2.11. Przykłady komunikatów przesyłanych między obiektami. Obiekt Watch wysyła do obiektu
Time komunikat getTime() oznaczający żądanie udostępnienia bieżącej wartości czasu GMT, po czym
wysyłając do obiektu TimeZone komunikat getTimeDeltaQ, żąda wartości przesunięcia czasu lokalnego
dla bieżącej strefy czasowej. Otrzymane zwrotnie wyniki (fakt ich przesiania zaznaczony jest linią prze-
rywaną ze strzałką) są sumowane, co daje wartość odpowiednią do wyświetlenia
76 Rozdział 2. • Modelowanie w języku UML
5
Dziedzina aplikacyjna może podlegać dalszemu podziałowi na dziedzinę użytkownika i dziedzinę
klienta. Pierwsza obejmuje wszelkie zagadnienia znaczące dla użytkownika systemu — funkcjonalność,
wygodę użytkowania, prostotę obsługi oraz łatwość nauczenia się jej i tym podobne; do dziedziny
klienta należą natomiast takie aspekty systemu jak koszt jego wytworzenia, ogólny koszt posiadania
i konserwacji czy też wpływ systemu na całokształt organizacji firmy.
2.3. Podstawowe koncepcje modelowania 77
Rysunek 2.12. Model dziedziny aplikacyjnej reprezentuje encje środowiska związane z kontrolą ruchu
lotniczego (między innymi samoloty i kontrolerów). Model systemu reprezentuje natomiast encje
stanowiące część tego systemu — wyświetlacz map, bazę rozkładu lotów i tym podobne. W ramach
obiektowo zorientowanej analizy i projektu model dziedziny aplikacyjnej staje się częścią modelu
systemu. Innymi słowy, model systemu stanowi rozwinięcie modelu dziedziny aplikacyjnej o koncepcje
pochodzące z dziedziny realizacyjnej, reprezentowane między innymi przez klasy SummaryDisplay,
MapDispl ay i FI ightPl anDatabase (do tej kwestii powrócimy w rozdziale 5. „Analiza wymagań")
6
Patrz http://wwwxs.cmu.edu/afs/andrew.cmu.edu/inst/ini/www/WIRELESS/FRIEND/index.html
— przyp. tłum.
80 Rozdział 2. • Modelowanie w języku UML
Rysunek 2.13. Przykład przypadku użycia dla bazy FRIEND systemu zarządzania sytuacjami kryzysowymi.
Skojarzenia między aktorami i przypadkami użycia oznaczają przepływ informacji. Skojarzenia te mają
charakter dwukierunkowy: mogą oznaczać inicjowanie przypadku użycia przez aktora (na przykład za-
inicjowanie przypadku ReportEmergency przez aktora F i e l d O f f i c e r ) lub dostarczenie informacji
aktorowi ( D i s p a t c h e r jest informowany w ramach przypadku użycia ReportEmergency). Prostokąt
zamykający przypadki użycia wyznacza granice systemu
P r z y p a d k i użycia z a p i s y w a n e są w j ę z y k u n a t u r a l n y m . Jest to n i e z b ę d n e z p e r s p e k t y w y
k o m u n i k a c j i p r o g r a m i s t ó w z u ż y t k o w n i k a m i , u k t ó r y c h z reguły n i e m o ż n a zakładać z n a j o -
m o ś c i t e r m i n o l o g i i i n o t a c j i p r o g r a m i s t y c z n e j . Użycie języka z r o z u m i a ł e g o dla wszystkich m a
jeszcze tę zaletę, że u m o ż l i w i a z r o z u m i e n i e w y m a g a ń s y s t e m u p r z e z u c z e s t n i k ó w r e p r e z e n t u -
j ą c y c h dyscypliny w i e d z y i n n e niż inżynieria o p r o g r a m o w a n i a czy n a w e t dziedzina aplikacyj-
n a . P o n a d t o w j ę z y k u n a t u r a l n y m często wiele rzeczy d a się w y r a ż a ć z g r a b n i e j i czytelniej n i ż
za p o m o c ą d i a g r a m ó w .
W d i a g r a m a c h p r z y p a d k ó w użycia w y s t ę p u j ą cztery r o d z a j e zależności: k o m u n i k a c j a ,
z a w i e r a n i e , r o z s z e r z e n i e i d z i e d z i c z e n i e . P r z y j r z y j m y i m się n i e c o d o k ł a d n i e j .
82 Rozdział 2. • Modelowanie w języku UML
Zależności komunikacyjne
Aktor i przypadek użycia komunikują się, gdy między nimi wymieniana jest informacja.
Relacja komunikacji reprezentowana jest w diagramie za pomocą linii ciągłej łączącej
aktora z przypadkiem użycia. W diagramie z rysunku 2.13 aktorzy Fi el dOf f i cer i Di spatcher
komunikują się z przypadkiem użycia ReportEmergency. Aktor Dispatcher (i tylko on) ko-
munikuje się ponadto z przypadkami użycia Openlncident i Al 1 ocateResources. Z relacji
komunikacyjnych można odczytywać dostęp aktorów do poszczególnych elementów funk-
cjonalnych systemu: we wspomnianym diagramie obaj aktorzy — Fi el dOf f i cer i Di spatcher
posługują się odmiennymi interfejsami i mają dostęp do różnych funkcji systemu.
Relacja zawierania
Tabela 2.2. Tekstowa reprezentacja relacji zawierania z rysunku 2.14 (słowo „dołączyć" wyszczególnione
jest czcionką pogrubioną)
Warunki końcowe • Dla obiektu Inci dent zostały przydzielone dodatkowe zasoby
• Obiekty Resource otrzymały informację o nowym przydziale
8
F i e l d O f f i c e r reagujący na Incident otrzymał informację
o przydziale zasobów
Relacja rozszerzania
Tabela 2.3. Tekstowa reprezentacja relacji rozszerzania zawierania z rysunku 2.15 (słowo „rozszerza"
wyszczególnione jest czcionką pogrubioną)
Relacja dziedziczenia
Authenticate
WithCard
Rysunek 2.16. Przykład relacji dziedziczenia. Przypadek użycia Authenti c a t e jest wysokopoziomowym
przypadkiem opisującym proces uwierzytelniania w kategoriach ogólnych. Przypadki A u t h e n t i c a t e
^-WithPassword i Authenti cateWi thCard są jego specjalizacjami
Scenariusze
Przypadek użycia jest abstrakcją, która opisuje wszelkie możliwe scenariusze związane
z określonym elementem funkcjonalnym systemu. Scenariusz jest instancją przypadku użycia,
opisującą konkretny ciąg akcji. Scenariusze używane są jako przykłady ilustrujące konkretne
sytuacje — ich treść koncentruje się na zrozumiałości. Przypadki użycia przeznaczone są do
opisywania ogółu sytuacji pewnego rodzaju — sens istnienia przypadków użycia zasadza się
na kompletności. Scenariusze opisywać będziemy w postaci szablonu składającego się z trzech
pól, określających kolejno:
Zauważmy, że dla scenariusza nie określa się warunków wstępnych ani warunków
końcowych. Warunki te są bowiem abstrakcjami umożliwiającymi programistom opisywanie
całego spektrum założeń, których spełnienie jest konieczne do wywołania przypadku użycia.
Ponieważ scenariusz dedykowany jest konkretnej sytuacji, warunki te są zbędne.
W tabeli 2.5 zamieszczamy przykładowy scenariusz odzwierciedlający zdarzenie po-
żaru w hurtowni.
Nazwa warehouseOnFi re
Klasy i obiekty
Diagramy klas opisują strukturę systemu w kategoriach klas i obiektów. Klasa jest
abstrakcją specyfikującą atrybuty i zachowanie zbioru obiektów — składa się na nią kolekcja
wszystkich obiektów współdzielących identyczny zbiór atrybutów, który odróżnia te obiekty
od obiektów należących do innych kolekcji. Obiekt jest encją zamykającą (enkapsulujacą)
w sobie określony stan i zachowanie. Każdy obiekt ma swoją tożsamość — można się do niego
jednoznacznie odwoływać, odróżniając go od innych obiektów.
2.4. UML. — głębszy wgląd 87
Rysunek 2.17. Przykładowy diagram klas uczestniczących w przypadku użycia ReportEmergency. Szcze-
gółowe informacje na temat typu atrybutów są zwykle pomijane, aż do etapu projektowania obiektów
(patrz rozdział 9. „Projektowanie obiektów: specyfikowanie interfejsów")
W diagramie na rysunku 2.17 ldasa FieldOfficer posiada dwa atrybuty: name i badge
^Number, odpowiadające imieniu i numerowi odznaki funkcjonariusza; oznacza to, że atrybuty
te posiadać będzie każdy obiekt klasy Fi el dOff i cer. W diagramie na rysunku 2.18 w obiektach
bob: Fi el dOf f i cer i al i ce: Fi el dOf f i cer atrybuty te mają konkretne wartości, odpowiednio
„Bob D." i „132" oraz „Alice W." i „23". Atrybut FieldOfficer.name jest wielkością typu
S t r i n g , co oznacza że mogą mu być przypisywane jako wartości tylko instancje klasy
String. Generalnie typ atrybutu określa zbiór wartości, jakie atrybut ten może przyjmować.
88 Rozdział 2. • Modelowanie w języku UML
Jeżeli w danym kontekście nie jest istotny typ atrybutu, decyzję o jego ustaleniu odkłada się
na późniejsze stadia projektu. Pozwala to programistom skoncentrować się na funkcjonal-
ności systemu i uwalnia od drobiazgowych zmian każdorazowo, gdy zmienia się obraz tej
funkcjonalności.
Skojarzenia i łącza
Łącze reprezentuje połączenie między dwoma obiektami. Skojarzenie jest relacją mię-
dzy klasami i może być uważane za grupę łączy. Każdy obiekt klasy Fi el dOf f i cer powiązany
jest z listą raportów (stanowiących obiekty klasy EmergencyReport) sporządzonych przez
funkcjonariusza reprezentowanego przez ten obiekt — na rysunku 2.17 linia łącząca klasy
Fi el dOffi cer i EmergencyReport jest skojarzeniem. Linia łącząca obiekty al i ce: Fi el dOff i cer
i report_129ł: EmergencyReport jest łączem. Łącze to reprezentuje w systemie informację
o tym, że funkcjonariusz al i c e : F i e l d O f f i c e r sporządził raport report_1291:Emergency
•-•Report.
Skojarzenia UML mogą być symetryczne (dwukierunkowe) lub asymetryczne (jedno-
kierunkowe). Na rysunku 2.19 widzimy przykład jednokierunkowego skojarzenia między
klasami Wielokąt i Punkt. Strzałka skierowana w stronę pierwszej z tych klas oznacza, że
system realizuje nawigację jedynie z klasy Wi el okąt do klasy Punkt. Innymi słowy, mając dany
konkretny wielokąt, możemy wyliczyć wszystkie punkty będące jego wierzchołkami; dla kon-
kretnego punktu nie sposób jednak wskazać wielokąta, którego wierzchołkiem jest (ewen-
tualnie) ów punkt.
Wielokąt Punkt
Rysunek 2.19. Przykład skojarzenia jednokierunkowego. Programiści zwykle pomijają nawigację na etapie
analizy i określają ją dopiero na etapie projektowania obiektów (patrz rozdziały 8. „Projektowanie
obiektów: wielokrotne wykorzystywanie rozwiązań wzorcowych" i 9. „Projektowanie obiektów: spe-
cyfikowanie interfejsów")
Klasy skojarzeniowe
Role
Każdy z końców skojarzenia może być etykietowany przez rolę. Na rysunku 2.17 sko-
jarzenie między klasami F i e l d O f f i c e r i EmergencyReport etykietowane jest rolami author
(„autor") i reportsGenerated („utworzone raporty"). Etykietowanie skojarzeń za pomocą ról
nie tylko ułatwia rozróżnienie wielu skojarzeń wychodzących z tej samej klasy, lecz także
sprawia, że znaczenie samych skojarzeń staje się czytelniejsze.
Krotność
Każdy koniec skojarzenia może być także etykietowany za pomocą zbioru nieujemnych
liczb całkowitych. Liczby te określają dopuszczalną liczbę skojarzeń wychodzących z instancji
danej klasy, a zbiór tych liczb nazywany jest krótko krotnością skojarzenia. Na rysunku 2.17
90 Rozdział 2. • Modelowanie w języku UML
skojarzenie po stronie etykietowanej rolą author ma krotność równą 1 — oznacza to, że każdy
raport (EmergencyReport) sporządzany jest przez dokładnie jednego autora funkcjonariusza
(FieldOfficer); innymi słowy, każdy obiekt klasy EmergencyReport połączony jest łączem
z dokładnie jednym obiektem klasy F i e l d O f f i c e r . Dla odmiany, krotność skojarzenia
po stronie etykietowanej jako reportsGenerated ma postać „wiele", wyrażaną przez gwiazd-
kę, która z kolei jest skrótową formą zapisu 0. .n. Ten ostatni zapis wyraża oczywisty fakt,
że dany funkcjonariusz teoretycznie sporządzać może wiele raportów lub nie sporządzić
żadnego.
W języku UML krotność może być dowolnym podzbiorem zbioru nieujemnych liczb
całkowitych — na przykład zbiorem liczb pierwszych, zbiorem liczb parzystych i tak dalej.
W praktyce jednak większość używanych skojarzeń da się podzielić na trzy typy (patrz ry-
sunek 2.22).
Rysunek 2.22. Przykłady różnych krotności skojarzeń — kolejno od góry „jeden do jednego", „jeden na
wiele" i „wiele na wiele"
Określenie krotności skojarzeń zwiększa ilość informacji, jaką możemy uzyskać w za-
kresie dziedziny aplikacyjnej lub dziedziny realizacyjnej. Krotność staje się czynnikiem kry-
tycznym wówczas, gdy określamy liczbę przypadków użycia niezbędnych do manipulowania
2.4. UML. — głębszy wgląd 91
Rysunek 2.23. Przykład hierarchicznego systemu plików. Katalog (Di r e c t o r y ) może zawierać dowolną
liczbę elementów (FileSystemElement), z których każdy może być plikiem ( F i l e ) lub katalogiem
(Di r e c t o r y ) , lecz każdy taki element jest częścią dokładnie jednego katalogu
Rysunek 2.24. Przykład niehierarchicznego systemu plików. Katalog (Directory) może zawierać do-
wolną liczbę elementów (Fi 1 eSystemEl ement), z których każdy może być plikiem (Fi 1 e) lub katalogiem
(Di r e c t o r y ) , i każdy taki element może być częścią wielu katalogów równocześnie
W tym miejscu czytelnik może odnieść wrażenie, że zagłębiamy się zbytnio w szczegóły,
które istotne bywają raczej w dalszych stadiach realizacji projektu. Otóż niezupełnie: różnice
między hierarchicznym a niehierarchicznym systemem plików mają także swój funkcjonalny
wymiar. Jeśli w systemie możliwe jest, by dany plik był częścią kilku katalogów, musimy
opracować przypadki użycia opisujące między innymi dodawanie pliku do istniejącego już
katalogu (na przykład za pomocą uniksowego polecenia link czy opcji MakeAl i as z menu
kontekstowego pliku w systemie Mac OS X). Ponadto czynność usuwania pliku wymaga opra-
cowania co najmniej dwóch przypadków użycia, obejmujących (odpowiednio) usuwanie
pliku z jednego konkretnego katalogu lub permanentne usuwanie pliku ze wszystkich ka-
talogów, w których jest obecny. Nic w tym dziwnego, że skojarzenia „wiele na wiele" skut-
kować mogą bardziej skomplikowanymi systemami.
92 Rozdział 2. • Modelowanie w języku UML
Agregacja
Komisariat O - Policjant
Katalog O - P1 i k
Rysunek 2.25. Przykład agregacji: Województwo składa się z Powi atów, te zaś — z Gmi n; Komi s a r i a t za-
trudnia (czyli składa się z) Pol i cjantów; Katal og może zawierać wiele PI i ków
Kwalifikowanie
Dziedziczenie
Dziedziczenie jest relacją wiążącą klasę ogólną z klasami bardziej szczegółowymi, bę-
dącymi jej konkretyzacjami. Dziedziczenie umożliwia opisywanie atrybutów i operacji wspól-
nych dla całego zbioru klas. Przykładowo zarówno funkcjonariusz (Fi el dOffi cer), jak i dys-
pozytor (Di spatcher) posiadają nazwisko (atrybut name) i odznakę z unikalnym numerem
(atrybut badgeNumber), chociaż funkcjonariusz kojarzony jest z raportem o zagrożeniu
(EmergencyReport), zaś dyspozytor kojarzony jest z samym zdarzeniem nadzwyczajnym
(Incident). Oba wspólne atrybuty — name i badgeNumber — stają się wobec tego podstawą
do zdefiniowania bardziej ogólnej klasy, wspólnej dla Fi el dOffi cer i Di spatcher — klasy
PoliceOfficer reprezentującej policjanta w ogóle (patrz rysunek 2.27). Taka ogólna klasa
nazywa się superklasą, zaś dziedziczące po niej klasy bardziej konkretne nazywane są sub-
klasami. Subklasy dziedziczą po swej superklasie wszystkie atrybuty i operacje. Superklasa
może być klasą abstrakcyjną — wyjaśnialiśmy to pojęcie w sekcji 2.3.3 — jej nazwa pisana
jest wówczas kursywą. Taką klasą abstrakcyjną jest na rysunku 2.27 klasa PoliceOfficer.
Klasy abstrakcyjne wykorzystywane są w modelowaniu zorientowanym obiektowo do re-
prezentowania powiązanych ze sobą koncepcji, dzięki czemu zmniejsza się złożoność modeli.
Rysunek 2.27. Przykład dziedziczenia. PoliceOfficer jest klasą abstrakcyjną definiującą wspólne atry-
buty i operacje dla swych konkretnych subklas Fi el dOffi cer i Di s p a t c h e r
94 Rozdział 2. • Modelowanie w języku UML
Zachowanie obiektu opisywane jest przez jego operacje. Jeden obiekt żąda wykonania
określonej operacji przez drugi, wysyłając mu komunikat. Otrzymany komunikat kojarzony
jest z odpowiednią metodą definiowaną w klasie, do której należy obiekt adresat komunikatu,
łub w którejś7 z jej superklas. Metoda jest obiektowym mechanizmem implementowania operacji.
Rozróżnienie między operacją a metodą pozwala na odróżnienie zachowania obiektu
(reprezentowanego przez operację) od jego implementacji (uosabianej przez metodę lub zbiór
metod, definiowanych w różnych klasach na zasadzie dziedziczenia). Na rysunku 2.28 dla klasy
Incident zdefiniowana jest operacja assignResource(), która zainicjowana przez dyspo-
zytora (Dispatcher) powoduje utworzenie skojarzenia między zdarzeniem (obiektem klasy
Incident) a konkretnym zasobem (będącym obiektem klasy Resource). Operacja assignRe-
source() prawdopodobnie przejawia także efekty uboczne, między innymi w postaci „poin-
formowania" przydzielonego zasobu o fakcie i czasie dokonania przydziału. Operacja close()
klasy Incident powoduje zakończenie obsługi wydarzenia reprezentowanego przez obiekt tej
klasy. Mimo iż język UML odróżnia operacje od metod, programiści często ignorują tę różnicę,
mówiąc po prostu o „metodach".
7
Dana klasa może mieć kilka superklas nawet w warunkach jednokrotnego dziedziczenia: po prostu re-
lacja „bycia superklasą" jest relacją przechodnią — superklasa superklasy jest superklasą — p r z y p . tłum.
2.4. UML. — głębszy wgląd 95
nie leżą w gestii tych modeli. Dopiero na następnych etapach diagramy klas uzupełniane są
o elementy reprezentujące koncepcje pochodzące z obszaru dziedziny realizacyjnej. Wtedy
właśnie programiści definiują klasy reprezentujące bazy danych, okna interfejsu użytkownika,
otoczki adaptujące gotowy przestarzały kod do nowych potrzeb, optymalizację kodu i tak dalej.
Klasy te grupowane są zwykle w podsystemy z dobrze zdefiniowanymi interfejsami. Budowanie
takich modeli opisujemy w rozdziałach 6. „Projektowanie systemu — dekompozycja na
podsystemy", 8. „Projektowanie obiektów: wielokrotne wykorzystywanie rozwiązań wzor-
cowych", 9. „Projektowanie obiektów: specylikowanie interfejsów" i 10. „Odwzorowywanie
modelu na kod".
Przejście między stanami to zmiana stanu wywołana przez zdarzenie, spełnienie wa-
runku lub upływ czasu. Na diagramie z rysunku 2.32 widoczne są trzy przejścia, odpowiednio
o d s t a n u Active d o Inactive, o d Inactive d o Cl osed.i o d Closed d o Archived.
Stan reprezentowany jest na diagramie przez zaokrąglony prostokąt, zaś przejście między
stanami — przez linię ciągłą, zakończoną otwartą strzałką i łączącą prostokąty reprezentujące
owe stany. Każdy stan etykietowany jest przez swą nazwę. Małe czarne kółeczko reprezentuje
stan początkowy, zaś czarne kółeczko otoczone białym.pierścieniem — stan końcowy.
Na rysunku 2.33 widzimy inny przykład — maszynę stanów dla zegarka 2Bwatch (tego
samego, dla którego skonstruowaliśmy diagram sekwencji widoczny na rysunku 2.29). Z per-
spektywy najwyższego poziomu abstrakcji zegarek ten może znajdować się w dwóch stanach:
MeasureTime, który odpowiada pomiarowi czasu, oraz SetTime, który odpowiada korygo-
waniu wskazania czasu. Naciśnięcie równocześnie obu jego przycisków powoduje zmianę
stanu; przy przejściu ze stanu SetTime do stanu MeasureTime zegarek wydaje krótki sygnał
2.4. UML. — głębszy wgląd 99
• w momencie wchodzenia obiektu w określony stan (jak akcja bl ink hours w stanie
SetTime na rysunku 2.34),
• w momencie wychodzenia obiektu z określonego stanu (jak akcja stop bl i nki ng
w stanie SetTime na rysunku 2.34).
8
Gdy zegarek znajduje się w stanie SetTime i przez 2 minuty nie zostanie naciśnięty żaden przycisk,
zegarek samoczynnie przełącza się do stanu MeasureTime — przyp. tłum.
100 Rozdział 2. • Modelowanie w języku UML
Rysunek 2.35. Udoskonalona maszyna stanów skojarzona ze stanem SetTime. Akcje 1B i rB reprezentują
naciskanie (odpowiednio) lewego i prawego przycisku
Rysunek 2.36. Diagram aktywności dla klasy Incident. W ramach akcji Handl elnci dent dyspozytor
otrzymuje raporty i przydziela zasoby. Gdy obsługa incydentu zostanie zamknięta, sporządzana jest
jego dokumentacja — w aktywności Documentlncident uczestniczą funkcjonariusze (FieldOfficer)
i dyspozytor (Dispatcher). Gdy incydent przestanie być już tematem nr 1, przenosi się (aktywność
Archivelncident) jego dokumentację do archiwum, zrealizowanego w oparciu o nośnik zapewniający
bardziej efektywne magazynowanie dużej porcji informacji za cenę mniej sprawnego wyszukiwania
(na przykład streamer)
więcej ścieżek wejściowych i z którego wychodzą dwie lub więcej ścieżek wyjściowych. Każda
ścieżka wyjściowa etykietowana jest przez warunek decydujący o jej wyborze. Liczba możli-
wych wartości warunku selekcyjnego determinuje liczbę ścieżek wyjściowych. Na rysunku 2.37
widzimy sytuację, gdy po zakończeniu aktywności Openlncident podejmowana jest decyzja
wyboru jednego z trzech wariantów sterowania: jeśli incydent jest pożarem (fi re) i ma wysoki
priorytet (hi ghPri ori ty), alarmowany jest komendant straży pożarnej; jeśli incydent ma wy-
soki priorytet, lecz jest zdarzeniem innym niż pożar (not fi re), alarmowany jest szef lokalnej
policji. Gdy incydent jest zdarzeniem o niskim priorytecie (1 owPri ori ty), nie ma potrzeby
alarmowania osób na wyższym szczeblu zarządzania, od razu przechodzi się do aktywności
przydzielania zasobów.
Rysunek 2.37. Przykład podejmowania decyzji, zależnie od rodzaju incydentu. Rozróżniane są trzy
wartości warunku selekcyjnego: pożar o wysokim priorytecie ( f i re & hi ghPri ori ty), zdarzenie o wysokim
priorytecie inne niż pożar (not f i r e & hi ghPri ori ty) i zdarzenie o niskim priorytecie (1 owPri ori ty)
Rysunek 2.40. Przykład grupowania przypadków użycia w pakiety — organizacja systemu FRIEND
z perspektywy udziału aktorów
Rysunek 2.41. Kolejny przykład pakietów — są to pakiety z rysunku 2.40, bez uwidaczniania ich zawartości
Rysunek 2.43. Przykład notatki. Notatka może być związana z konkretnym elementem diagramu
2.6. Ćwiczenia
2.1. Traktując bankomat jako system, wymień co najmniej trzech współdziałających z nim
aktorów.
2.2. Czy system istniejący jedynie w zamyśle projektantów może być reprezentowany
przez aktora? Uzasadnij odpowiedź.
2.3. Jaka jest różnica między scenariuszem a przypadkiem użycia? Kiedy używa się
każdej z tych konstrukcji?
2.4. Narysuj diagram przypadków użycia automatu do sprzedaży biletów. System za-
wiera dwóch aktorów: podróżnego kupującego bilet określonego rodzaju i cen-
tralny komputer utrzymujący bazę danych o taryfach i cenniku. Przypadki użycia
powinny obejmować zakup zwykłego biletu (BuyOneWayTicket), zakup karnetu
tygodniowego lub miesięcznego (BuyWeeklyCard i BuyMonthlyCard) oraz aktu-
alizację informacji taryfowej o cenach (UpdateTari ff). Nie zapomnij o uwzględ-
nieniu przypadków wyjątkowych, takich jak przeterminowanie transakcji (Timeout
— podróżny po zainicjowaniu transakcji wykazuje zbyt długą bezczynność), anulo-
wanie transakcji (Transacti onAborted — podróżny zainicjował transakcję, lecz
wycofał się z zamiaru kupna biletu, naciskając odpowiedni przycisk), brak nomi-
nałów do prawidłowego wydania reszty (Di s t r i butorOutOfChange) i wyczerpanie
papieru w drukarce (Di s t r i butorOutOfPaper).
2.5. Opisz przepływa zdarzeń i określ wszystkie elementy przypadku użycia Update
"-•Tari f f z ćwiczenia 2.4. Nie zapomnij o relacjach między obiektami.
2.6. Narysuj diagram klas reprezentujący książkę zdefiniowaną następująco: „Książka
podzielona jest na kilka części, z których każda składa się z pewnej liczby rozdziałów.
Rozdziały podzielone są na sekcje". Zwróć szczególną uwagę na klasy i skojarzenia
między nimi.
2.7. Uzupełnij skojarzenia z ćwiczenia 2.6 o krotności.
2.8. Narysuj diagram zawierający obiekty reprezentujące pierwszą część tej książki
„Zaczynamy". Upewnij się, że stworzony przez Ciebie diagram jest spójny z dia-
gramem z ćwiczenia 2.6.
Bibliografia 109
2.10. Zauważ, że klasy diagramu z ćwiczenia 2.9, reprezentujące część, rozdział i sekcję,
zawierają wspólne atrybuty — tytuł i numer. Dodaj do diagramu abstrakcyjną
superklasę dla tych klas, definiującą wspomniane atrybuty.
2.11. Narysuj diagram klas reprezentujący relację między rodzicami a dziećmi. Pamiętaj,
że człowiek może być zarówno dzieckiem, jak i jednym z rodziców. Zaetykietuj
skojarzenia ich rolami i krotnościami.
2.12. Narysuj diagram klas reprezentujący bibliografię i odwołania do jej pozycji. Twój
diagram powinien być jak najbardziej szczegółowy. Przetestuj go na podstawie
dodatku C do tej książki.
2.13. Narysuj diagram sekwencji dla scenariusza warehouseOnFi re z tabeli 2.5, uwzględ-
niając obiekty bob, al ice, john i FRIEND oraz ewentualne instancje innych klas.
Ogranicz się do pierwszych pięciu przesyłanych komunikatów.
2.14. Narysuj diagram sekwencji dla przypadku użycia ReportEmergency z tabeli 2.1.
Ogranicz się do pierwszych pięciu przesyłanych komunikatów. Upewnij się, że
stworzony przez Ciebie diagram jest spójny z diagramem z ćwiczenia 2.13.
2.15. Przeanalizuj proces zamawiania pizzy przez telefon. Narysuj diagram aktywności
reprezentujący każdy krok tego procesu, od momentu sięgnięcia po telefon do mo-
mentu rozpoczęcia konsumpcji dostarczonej pizzy. Dla uproszczenia pomiń możliwe
sytuacje wyjątkowe. Uwzględnij również aktywności innych obiektów uwikłanych
w proces.
2.16. Dodaj obsługę możliwych sytuacji wyjątkowych do diagramu utworzonego w ćwi-
czeniu 2.15 — uwzględnij co najmniej trzy (na przykład dostarczenie pizzy pod
niewłaściwy adres, dostarczenie niewłaściwego rodzaju pizzy, dostawca powyjadał po
drodze co smakowitsze anchovis i tym podobne).
2.17. Narysuj diagram dla aktywności opisanych w sekcji 1.4 poprzedniego rozdziału, za-
kładając ich ściśle sekwencyjne wykonanie. Narysuj następny diagram, przy założeniu
wykonywania wspomnianych aktywności w sposób przyrostowy (jedna partia syste-
mu jest analizowana, projektowana, implementowana i wyczerpująco testowana
przed rozpoczęciem prac nad następną partią). Wreszcie, na trzecim diagramie
załóż wykonywanie tychże aktywności w sposób równoległy.
Bibliografia
[Booch, 1994] G. Booch Object-Oriented Analysis and Design with Applications,
wyd. drugie, Benjamin/Cummings, Redwood City, CA, 1994.
[Booch i in., 2005] G. Booch, J. Rumbaugh, I. Jacobson The Unified Modeling
Language User Guide, Addison-Wesley, Reading, MA, 2005.
110 Rozdział 2. • Modelowanie w języku UML
[Coad i in., 1995] P. Coad, D. North, M. Mayfield Object Models: Strategies, Patterns,
& Applications, Prentice Hall, Englewood Cliffs, NJ, 1995.
[Constantine i Lockwood, 2001] L. L. Constantine & L.A.D. Lockwood „Structure and style in use
cases for user interface design," w: M. van Harmelen (red.) Object-
Oriented User Interface Design, 2001.
[Douglass, 1999] B. P. Douglass Doing Hard Time: Using Object Oriented Programming
and Software Patterns in Real Time Applications, Addison-Wesley,
Reading, MA, 1999.
[Fowler, 2003] M. Fowler UML Distilled: A Brief Guide To The Standard Object
Modeling Language, wyd. trzecie, Addison-Wesley, Reading, MA, 2003.
[Harel, 1987] D. Harel Statecharts: A visual formalism for complex systems,
„Science of Computer Programming", str. 231 - 274, 1987.
[Jacobson i in., 1992] I. Jacobson, M. Christerson, P. Jonsson, G. Overgaard Object-Oriented
Software Engineering — A Use Case Driven Approach, Addison-Wesley,
Reading, MA, 1992.
[Martin i Odell, 1992] J. Martin, J. J. Odell Object-Oriented Analysis and Design, Prentice
Hall, Englewood Cliffs, NJ, 1992.
[Mellor i Shlaer, 1998] S. Mellor, S. Shlaer Recursive Design Approach, Prentice Hall,
Upper Saddle River, NJ, 1998.
[Miller, 1956] G. A. Miller The magical number seven, plus or minus two: Some limits
on our capacity for processing information, „Psychological Review",
t. 63, str. 81 - 97, 1956.
[OMG, 2009] Object M a n a g e m e n t G r o u p OMG Unified Modeling Language
Superstructure. Version 2.2, http://www.omg.org.
[Popper, 1992] K. Popper Objective Knowledge: An Evolutionary Approach, Clarendon,
Oxford, 1992.
[Rumbaugh i in., 1991] J. R u m b a u g h , M. Błaha, W . Premerlani, F. Eddy, W . Lorensen
Object-Oriented Modeling and Design, Prentice Hall, Englewood
Cliffs, NJ, 1991.
Bibliografia 153
Organizacja projektu
i komunikacja
Dwa podzespoły rakiety, dostarczone przez dwóch różnych
podwykonawców, połączone były parą przewodów. Kontrola
przedstartowa wykazała, że połączenie jest nieprawidłowe —przewody
są skrzyżowane i należy zamienić ich kolejność po jednej ze stron.
Śledztwo prowadzone w związku ze spłonięciem rakiety na stanowisku
startowym wykazało, że obaj podwykonawcy sumiennie zastosowali
się do zalecenia — każdy zamienił końcówki po swojej stronie.
Ariane 501
4 czerwca 1996 roku rakieta Ariane 501 — pierwszy prototyp serii Ariane 5 — eksplodowała pół
minuty po starcie. Oprogramowanie głównego komputera nawigacyjnego zakończyło swą pracę awa-
ryjnie z powodu wystąpienia nadmiaru operacji arytmetycznej; główny komputer oddelegował
kontrolę do komputera zapasowego i wyłączył się. Niestety, komputer zapasowy wyłączył się uła-
mek sekundy wcześniej z identycznej przyczyny. W efekcie rakieta, gwałtownie pozbawiona
systemu nawigacyjnego, dokonała ostrego skrętu, mającego na celu skorygowanie zboczenia z kursu,
które w rzeczywistości nie wystąpiło.
System nawigacyjny rakiety odpowiedzialny jest za obliczanie korekcji odchyleń kursu od założonej
trajektorii na podstawie informacji pochodzącej z systemu referencyjnego, mającego naturę bezwład-
nościową, złożonego głównie z żyroskopów i mierników przyspieszenia. System ten stanowi jedyny
punkt odniesienia dla obliczania aktualnej pozycji rakiety — obliczanie to odbywa się więc w całko-
witym oderwaniu od świata zewnętrznego. Niezbędne jest wobec tego odpowiednie zainicjowanie
owego systemu referencyjnego, przez skorelowanie jego stanu z tymże światem zewnętrznym oraz
z aktualną pozycją rakiety. Inicjowanie to odbywa się bezpośrednio przed startem i trwa w przybliżeniu
45 minut; po starcie rakiety dane z systemu przekazywane są do komputerowego systemu nawigacyj-
nego, który po uwzględnieniu dodatkowych czynników (głównie ruchu obrotowego Ziemi) oblicza
bieżącą pozycję rakiety i konfrontuje ją z pozycją oczekiwaną w danej chwili; obliczenia te trwają ok.
50 sekund i w takim też odstępie odbywa się wspomniane kontrolowanie położenia rakiety. Odliczanie
do startu może być wstrzymane na żądanie; jego wznowienie nie wymaga powtórzenia owych
45-minutowych obliczeń inicjacyjnych. Po udanym starcie komputer pokładowy jeszcze przez
40 sekund generuje dane inicjacyjne, które jednak są wtedy całkowicie bezużyteczne.
System komputerowy serii Ariane 5 różnił się od tego z serii Ariane 4 między innymi zdublowaniem
platformy sprzętowej — dublowany był sam system referencyjny, komputery wykonujące niezbędne
obliczenia oraz urządzenia korygujące położenie rakiety; w przypadki awarii któregoś z podzespołów
jego funkcje automatycznie przejmowała replika.
Projekt może być zdefiniowany w sposób formalny lub nieformalny. Pisemny kontrakt
między wykonawcą a klientem, uzgadniający dostarczenie systemu informatycznego w termi-
nie trzech miesięcy za cenę miliona dolarów, to nic innego jak formalne określenie projektu;
projektem może być jednak również nieformalna obietnica zainstalowania nowego opro-
gramowania na komputerze kolegi, w przyszłym tygodniu.
Projekty bywają zróżnicowane pod względem typu i rozmiaru. Niekiedy typ projektu
definiuje się na podstawie natury jego produktu docelowego — i tak na przykład stworzenie
systemu informatycznego dla celów zarządzania księgowością przedsiębiorstwa określa się
mianem projektu programistycznego, natomiast budowa promu kosmicznego zaliczana jest
do projektów systemowych. Projekty mogą mieć rozmiary banalne albo gigantyczne: budowa
promu kosmicznego, wraz z niezbędną infrastrukturą informatyczną, trwająca 10 - 15 lat
i wyceniona na 10 miliardów dolarów, zdecydowanie zalicza się do tych drugich, w odróżnie-
niu od np. przemeblowywania mieszkania, reprezentującego zdecydowanie pierwszą kategorię.
Gdy spojrzeć na realizację projektu pod kątem dynamicznym, wyróżnić można kilka
jej faz, przedstawionych symbolicznie na rysunku 3.2.
• inspekcję problemu, podczas której programiści uzyskują niezbędne dla siebie in-
formacje z zakresu dziedziny aplikacyjnej — na podstawie deklaracji problemu oraz
interakcji z klientem i przyszłymi użytkownikami systemu;
• zebrania statusowe, w ramach których zespoły analizują postęp swoich prac;
• przeglądy partnerskie, obejmujące identyfikowanie usterek we wstępnych wersjach
produktów oraz poszukiwanie sposobów niwelowania tych usterek;
• przeglądy kliencki i projektowy, w czasie których klient i inni uczestnicy dokonują
oceny jakości produktów, szczególnie produktów docelowych;
o emisje, polegające na przekazaniu klientowi i użytkownikom kolejnych wersji pro-
duktów docelowych wraz z niezbędną dokumentacją.
Rysunek 3.3. Zespołowa organizacja projektu: jednostkę organizacji stanowi zespół, składający się z pro-
gramistów lub innych zespołów
Rysunek 3.4. Przykład prostej organizacji projektu: raportowanie, decydowanie i komunikowanie reali-
zowane są przez skojarzenie agregacyjne z poziomem organizacyjnym
Rysunek 3.5. Przykład hierarchicznej struktury raportowania: informacja o statusie projektu raportowana
jest menedżerowi projektu, który następnie przekazuje swe decyzje programistom za pośrednictwem
kierowników zespołów; menedżer wraz w kierownikami zespołów tworzą zespół zarządzający
Rysunek 3.6. Przykład struktury łącznikowej. Zespół składa się z pięciorga programistów: Alice jest
kierownikiem, a więc również łącznikiem z zespołem zarządzającym; John jako inżynier API jest łączni-
kiem z zespołem architektonicznym; Mary jest łącznikiem z zespołem dokumentacyjnym; Chris i Sam,
jako implementatorzy, kontaktują się z innymi zespołami jedynie w sposób nieformalny
122 Rozdziat 3. • Organizacja projektu i komunikacja
przez jego macierzysty zespół, redaktor postrzegany jest jako dostawca usługi. Zaj-
muje się także dokumentowaniem informacji wewnątrzzespołowej, powstającej
między innymi w ramach spotkań i narad zespołu.
• Menedżer konfiguracji to rola związana z zarządzaniem różnymi wersjami doku-
mentów, modeli i fragmentów kodu, produkowanych w ramach zespołu. Gdy zasady
owego zarządzania nie są skomplikowane, rolę menedżera konfiguracji może pełnić
kierownik zespołu.
• Tester odpowiada za zgodność rzeczywistego funkcjonowania podsystemu ze spe-
cyfikacją jego projektanta. Często testowanie powierza się odrębnemu zespołowi,
który nie zajmuje się programowaniem — takie rozdzielenie ról implementatora
i testera skutkuje zwykle bardziej efektywnym testowaniem.
p o d o b n y m . P r o d u k t y s t a n o w i ą rezultaty w y k o n y w a n i a o k r e ś l o n y c h z a d a ń , są p o d s t a w ą f o r -
m u ł o w a n i a h a r m o n o g r a m ó w i w a r u n k u j ą w y k o n y w a n i e i n n y c h z a d a ń . P r z y k ł a d o w o aktyw-
n o ś ć p l a n o w a n i a t e s t ó w dla p o d s y s t e m u z a r z ą d z a n i a b a z ą d a n y c h s k u t k u j e p r o d u k t e m w p o -
staci zestawu p r z y p a d k ó w testowych i ich o c z e k i w a n y c h rezultatów, k t ó r e s t a n o w i ą m a t e r i a ł
n i e z b ę d n y dla i n n e j a k t y w n o ś c i — t e s t o w a n i a d a n e g o p o d s y s t e m u ( p a t r z r y s u n e k 3.8).
Rysunek 3.8. Produkty podsystemu zarządzania bazą danych. Skojarzenia reprezentują zależności między
produktami
Obiekty trwałe Model klas Ten model klas opisuje wyczerpująco obiekty przeznaczone
do trwałego przechowywania w bazie danych stanowiącej
przedmiot podsystemu. Dla każdej klasy definiowane są
atrybuty, skojarzenia, krotności i role.
Obiekty projektu Model klas Ten model opisuje inne obiekty niezbędne do przechowywania
danych w bazie, niebędące obiektami trwałymi.
Plan testów Dokument Dokument ten opisuje strategie testowanie, kryteria testowania
i przypadki testowe dedykowane wykrywaniu usterek tkwiących
w implementacji podsystemu zarządzania bazą danych.
Usterki wykryte Dokument Dokument ten opisuje usterki wykryte podczas inspekcji
podczas inspekcji kodu kodu dokonywanej przez programistów zespołu. Każdej
wykrytej usterce towarzyszy propozycja jej naprawienia.
3.3.4. Harmonogramy
Harmonogram jest odwzorowaniem zadań na upływający czas: dla każdego zadania określa
się moment jego rozpoczęcia i zakończenia. Stanowi to podstawę do planowanie terminów
dostarczania poszczególnych produktów docelowych. Dwiema często używanymi notacjami
dla harmonogramów są wykresy Gantta [Gantt, 1910] i grafy PERT. Wykres Gantta jest
zwartą prezentacją przebiegu realizacji projektu w czasie: równolegle do poziomej osi czasu
lysowane są poziome słupki oznaczające poszczególne zadania: początek i koniec słupka od-
zwierciedla rozpoczęcie i zakończenie konkretnego zadania. Harmonogram w postaci wy-
kresu Gantta dla podsystemu zarządzania bazą danych pokazany jest na rysunku 3.10.
Graf PERT jest acyklicznym grafem skierowanym, którego wierzchołki reprezentują
zadania, a krawędzie — następstwo powiązanych zadań. Planowane rozpoczęcie i zakoń-
czenie każdego zadania staje się podstawą do wyznaczenia tzw. ścieżki krytycznej, będącej
najkrótszą ścieżką w grafie. Jej długość stanowi dolne ograniczenie na czas realizacji grupy
3.3. Koncepcje organizacyjne projektu 127
Tabela 3.3. Przykładowe pakiety związane z realizacją podsystemu zarządzania bazą danych
Rysunek 3.10. Przykładowy harmonogram dla realizacji podsystemu zarządzania bazą danych — wykres
Gantta
Rysunek 3.11. Przykładowy harmonogram dla realizacji podsystemu zarządzania bazą danych — graf PERT.
Pogrubione krawędzie tworzą ścieżkę krytyczną
• Prezentowanie problemu,
• Przegląd kliencki,
3.3. Koncepcje organizacyjne projektu 129
• Przegląd projektowy,
• Przegląd partnerski,
• Przegląd statusowy,
• Burzę mózgów,
• Emisje,
• Przegląd post mortem.
|
Przyjrzyjmy się pokrótce poszczególnym z nich.
Deklaracja problem u
W inteligentnym miejscu pracy pożądane jest zaadaptowanie trzech form sterowania wyżej wy-
mienionymi czynnikami: reaktywnej, planowej i doraźnej. Kontrola reaktywna polega na samoczyn-
nym dostosowywaniu stanu wybranych komponentów do wskazań czujników; kontrola planowa
odnosi się do przewidywalnych zdarzeń, zjawisk i czynników, dzięki czemu stan wspomnianych
komponentów można bezpośrednio kontrolować i modyfikować, zgodnie ze starannie opracowa-
nym harmonogramem. Przykładem przewidywalnych danych jest pozycja Słońca, dzięki czemu re-
gulowanie dostępności światła dziennego może odbywać się w sposób a priori zaprogramowa-
ny. Sterowanie doraźne to nic innego jak możliwość bezpośredniego sterowania wymienionymi
czynnikami przez samych pracowników, stosownie do ich aktualnych potrzeb — jeśli będą chcieli
ingerować w automatyczną kontrolę swego środowiska pracy, należy im to umożliwić.
Przedmiotem tego projektu jest stworzenie systemu OWL (Object-Oriented Workplace Laboratory)
jako próby usprawnienia sposobu budowania biurowców.
2. Scenariusze
[...]
2.5. Utrzymanie i konserwacja budynku
[...]
3.3. Koncepcje organizacyjne projektu 131
Przegląd kliencki
Celem przeglądu klienckiego jest umożliwienie klientowi oceny postępu prac prowa-
dzonych przez programistów, a także dostarczenie programistom potwierdzenia wymagań
lub żądania zmian pod adresem tworzonego systemu. Przegląd kliencki stanowi więc okazję do
potwierdzenia oczekiwań z obu stron i budowania coraz lepszego porozumienia między
uczestnikami projektu. Przedmiotem zainteresowania przeglądu klienckiego są elementy funk-
cjonalne systemu i ewentualne ograniczenia istotne dla klienta (wydajność, platforma sprzęto-
wa oraz systemowa i tym podobne). W większości przypadków pomijane są kwestie związane
z projektowaniem i implementowaniem systemu, chyba że są interesujące (bo nieobojętne)
dla ldienta lub użytkownika — wyjątki dotyczą najczęściej kwestii bezpieczeństwa lub ograniczeń
o charakterze prawnym.
Przegląd kliencki przeprowadzany jest jako formalna prezentacja, w czasie której
programiści skupiają się na specyficznym aspekcie funkcjonalności z perspektywy klienta.
Przegląd kliencki poprzedzany jest emisją produktu — dokumentu specyfikacji, makiety in-
terfejsu czy ewaluacyjnego prototypu podsystemu. W odpowiedzi na wspomnianą prezentację
klient przekazuje swoje uwagi programistom; uwagi te mogą sprowadzać się do generalnej
aprobaty zaprezentowanych rozwiązań bądź też mogą zawierać wymogi lub sugestie w zakresie
funkcjonalności systemu lub harmonogramu. W tabeli 3.4 widoczny jest przykład agendy
przeglądu klienckiego.
Przegląd projektowy
Przegląd partnerski
Dwie techniki, które walnie przyczynić się mogą do poprawy jakości systemu, to in-
spekcja kodu źródłowego i wędrówki po kodzie; techniki te praktykowane są w czasie prze-
glądu partnerskiego (w odróżnieniu od przeglądu projektowego czy przeglądu klienckiego).
W ramach wędrówek po kodzie programista prezentuje swoim kolegom programistom napi-
sany przez siebie kod źródłowy, wiersz po wierszu. Daje to okazję wychwycenia wielu podej-
rzanych konstrukcji i tym samym wczesnego zidentyfikowania przyczyn rozmaitych błędów.
Rolą programisty prezentera jest kierowanie prezentacją i odpowiadanie na pytania kolegów
z zespołu. Inspekcja kodu jest natomiast badaniem zgodności kodu z predefiniowaną listą kry-
teriów (na przykład sprawdzanie, czy dany fragment kodu istotnie jest implementacją kon-
kretnego algorytmu albo czy fragment kodu odwołuje się do innych podsystemów, zgodnie
ze specyfikacją ich API). Role uczestników są tu odwrotne w stosunku do wędrówki po kodzie
— tutaj zespół zadaje pytania, na które programista musi odpowiadać. Należy jednak pamiętać,
że podmiotem inspekcji oraz wędrówki po kodzie jest sam kod, a nie jego autor.
W czasie przeglądu partnerskiego wspólnym punktem odniesienia w komunikacji mię-
dzy uczestnikami jest kod źródłowy. Inspekcje i wędrówki mają ten sam cel, co przegląd pro-
jektowy — poprawę jakości kodu i rozpowszechnienie niezbędnych informacji operacyjnych
— różnią się jednak od niego mniej formalnym charakterem, ograniczonym liczebnie audyto-
rium i dłuższym zazwyczaj czasem trwania. Jak dowodzą tego liczne przykłady (między in-
nymi [Fagan, 1976]), inspekcja kodu i wędrówki po kodzie są technikami powszechnie stosowa-
nymi przez programistów, są bowiem efektywne pod względem wczesnego wykrywania usterek
kodu. Wędrówkami po kodzie zajmiemy się dokładniej w rozdziale 11. „Testowanie".
3.3. Koncepcje organizacyjne projektu 133
Przegląd statusowy
Burza mózgów
Celem burzy mózgów jest wygenerowanie jak największej liczby propozycji rozwiązań
problemu, niezależnie od ich rzeczywistej wartości merytorycznej, a następnie ocena każdej
z tych propozycji. Burzę mózgów urzeczywistnia się zwykle w ramach spotkań osobistych,
lecz równie dobrze można ją prowadzić za pomocą e-maili lub grup dyskusyjnych, komu-
nikatorów i tym podobnych form komunikacji. Sens burzy mózgów zasadza się na prostym
spostrzeżeniu, iż każda propozycja, choćby nawet najbardziej dziwaczna, może stać się
inspiracją dla bardziej konkretnych pomysłów. Co więcej, w przypadku problemów szczegól-
nie skomplikowanych rozwiązanie pojawić się może za pośrednictwem idei, która począt-
kowo wydawała się niedorzeczna. Istotą burzy mózgów jest myślenie poza utartymi sche-
matami. Burza mózgów ma ponadto dwa korzystne efekty uboczne: ocena pomysłów na
forum grupy skłania do formułowania bardziej czytelnych kryteriów tej oceny, a poza tym
łatwiej osiąga się wówczas konsensus dotyczący wybranego rozwiązania.
134 Rozdziat 3. • Organizacja projektu i komunikacja
Emisje
Emisja produktu, często w celu zastąpienia jego starszej wersji, wymaga udostępnienia
innym uczestnikom informacji o tym fakcie. Informacja ta może mieć formę tak prostą jak
dwulinijkowy komunikat (jak poniżej) bądź też może składać się z wielu części, na przykład
opisu nowej wersji produktu, listy zmian od jego poprzedniego wydania, listy nierozwiąza-
nych wciąż problemów i wątpliwości oraz nazwiska autora.
Od: Al
Grupy dyskusyjne: cs413.f96.architecture.discuss
Temat: SDD
Data: 2003-11-25 03:39:23
Lines: 6
Message-ID: <3299B30.3507@andrew.emu.edu>
MimeVersion: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Nowa wersja dokumentacji API dla podsystemu powiadamiania dostępna jest pod adresem
http: //decaf/~al/FRIEND/notifapi.html
—Al
Kierownik grupy powiadamiania
W ten oto sposób duża porcja informacji może być szybko rozpowszechniona w formie
kontrolowanej i spójnej — wiele zmian rozpowszechnionych zostaje łącznie, w jednym
miejscu. Przeglądy kliencki i projektowy poprzedzane są zwykle informacją o konkretnym
produkcie docelowym lub kilku produktach.
W rozdziale 13. „Zarządzanie konfiguracją" opiszemy zarządzanie wersjami dokumen-
tów, modeli i podsystemów.
Celem przeglądu post mortem jest wyciągnięcie wniosków z całego procesu tworzenia
systemu, który został właśnie dostarczony klientowi. Im szybciej taki przegląd zostanie prze-
prowadzony, tym mniejsze ryzyko utraty lub zniekształcenia istotnych informacji. Zakończenie
realizacji projektu to dobry moment do oceny technik, metod i narzędzi oraz wskazania tych,
które w stopniu krytycznym przyczyniły się do powodzenia (lub klęski) tej realizacji.
Przegląd post mortem może być przeprowadzany jako sesja burzy mózgów, jako wy-
wiad poparty strukturalnym kwestionariuszem bądź jako zestaw indywidualnych raportów
stworzonych przez uczestników (lub zespoły). Niezależnie od formy, konieczne jest uwzględ-
nienie wszystkich narzędzi, metod, organizacji i procedur wykorzystywanych w związku z za-
kończonym projektem.
3.3. Koncepcje organizacyjne projektu 135
W tabeli 3.5 widoczne są przykładowe pytania, jakie paść powinny w ramach przeglądu
post mortem. Nawet jeśli rezultaty przeglądu post mortem nie zostaną rozpowszechnione
oficjalnymi kanałami (na przykład w formie raportów technicznych), mogą być przekazywane
pośrednio uczestnikom projektu. Ci bardzo często przydzielani są do kolejnych projektów czy
oddelegowani do pełnienia innych funkcji, mają więc okazję upowszechniać wewnątrz firmy
wnioski z lekcji wyciągniętych przy realizacji poprzednich projektów. Przegląd post mortem
jest zatem idealną okazją do wszelkich podsumowań związanych z ostatnio zakończonymi
(lub zaniechanymi) projektami.
• celami projektu,
• realnością uwzględnionych przypadków użycia,
Niedziela, 29 marca 1998. Uczestnicy projektu JAMES1 gorączkowo przygotowują się do dostarczenia
klientowi ukończonego systemu. Rozpoczęcie testów akceptacyjnych uzgodnione zostało z klientem
na 31 marca, na godzinę 15:00 środkowoeuropejskiego czasu letniego. Z powodu przejścia na czas
letni w nocy z 28 na 29 marca programistom ubyła jedna godzina. Testy akceptacyjne prowadzone
będą w formie trójstronnej wideokonferencji między klientem w Stuttgarcie, niemieckimi progra-
mistami z Technical University Munich (TUM) w Monachium i amerykańskimi programistami
z Carnegie Mellon University (CMU) w Pittsburgu. Amerykanie mają rozpocząć konferencję o godz.
9:00 swojego czasu. Gotowa jest agenda — każdy zespół ma 12 minut na zaprezentowanie funkcjo-
nalności swojego podsystemu.
Późnym wieczorem. Niemieccy programiści dowiadują się nagle, niejako przypadkiem, od przeby-
wającego u nich studenta-programisty z CMU, że w USA przejście na czas letni dokonuje się o ty-
dzień później niż w Europie, wobec czego różnica czasu między Monachium a Pittsburgiem wynosi
obecnie 7, nie 6 godzin, a zatem Amerykanie powinni rozpocząć wideokonferencję o godzinie 8:00,
nie 9:00 swojego czasu. Niecałe 48 godzin przed rozpoczęciem testów akceptacyjnych Amerykanie
uświadamiają sobie, że o mały włos nie rozminęli się o godzinę z harmonogramem! Powiadomienie
o tym fakcie wszystkich członków amerykańskiego zespołu wymagać będzie być może całego dnia.
• żądania wyjaśnień,
• żądania zmian,
• rozwiązywanie problemów.
Żądanie wyjaśnień
Żądanie wyjaśnień, choć wiąże się często z intensywną komunikacją między uczest-
nikami projektu, jest zdarzeniem nieprzewidywalnym. Uczestnicy mogą żądać wyjaśnień
dotyczących dowolnego aspektu systemu, niezrozumiałego lub niejasnego dla nich. Forma
wymiany związanej z tym informacji bywa rozmaita, zależnie od środków komunikowania
dostępnych dla uczestników — mogą to być e-maile, rozmowy telefoniczne, nieformalne spo-
tkania i tym podobne. Oto przykład żądania wyjaśnień za pomocą postu grupy dyskusyjnej:
1
Patrz sekcja 16.5.3 — przyp. tłum.
3.3. Koncepcje organizacyjne projektu 137
Od: Alice
Grupy dyskusyjne: cs413.architecture.discuss
Temat: SDD
Data: 2010-10-10 23:12:48
Message-ID: <325DBB30.4380@andrew.cmu.edu>
MimeVersion: 1.0
Content-Type: text/plain; charset=us-ascii
Żądanie zmian
Rozwiązywanie problemów
Rysunek 3.14. Przykłady mechanizmów komunikacyjnych. Komunikacja planowa może być reali-
zowana zarówno przez mechanizmy synchroniczne, jak i asynchroniczne; komunikacja pozaplano-
wa może być realizowana jedynie za pomocą środków synchronicznych
Konwersacje okazjonalne
Sally i Bob, uczestniczący w tym samym projekcie, spotkali się przy automacie z kawą. Sally, odpo-
wiedzialna jest za interfejs użytkownika. Wiedząc, że Bob jest członkiem zespołu powiadamiania,
odpowiedzialnym za komunikację między podsystemami klienckimi a serwerem, informuje go
o nieregularnych kłopotach z pobieraniem pakietów z serwera: nie jest pewna, czy przyczyna tych
kłopotów nie leży przypadkiem w jej kodzie. I dowiaduje się od Boba, iż równolegle z jej próbami
pobierania pakietów testowana była nowa rewizja systemu komunikacyjnego; Bob, w trosce o oszczęd-
ność czasu, pominął obowiązujące w takich przypadkach oficjalne procedury związane z zarządza-
niem konfiguracją. Ostatecznie wyjaśnia to całą zagadkę.
Celem kwestionariusza jest zebranie informacji od jednej lub kilku osób w sposób
strukturalny. Kwestionariusze stosowane są zazwyczaj do pozyskiwania wiedzy od użytkow-
ników i ekspertów, w celu lepszego zrozumienia wymagań i priorytetów klienta, mogą być też
używane na potrzeby wyciągania wniosków z przeglądu post mortem. Kwestionariusz może
zawierać zarówno pytania o charakterze otwartym, jak i opcje wyboru (być może wielokrotne-
go). Kwestionariusze mają tę zaletę, że pozyskiwanie informacji odbywa się przy minimalnym
fatygowaniu użytkownika. Oczywiście, każdy kwestionariusz musi być sporządzony indywidual-
nie, niezależnie od pozostałych, a wszelkie niejasności lub niekompletne odpowiedzi powinny
zostać wyjaśnione w ramach wywiadu strukturalnego. Podstawową wadą kwestionariuszy jest
fakt, że trudno je właściwie projektować; wysiłek włożony w ich zaprojektowanie jest jednak
opłacalny, jeśli weźmie się pod uwagę potencjalne konsekwencje niedostatecznego zrozumienia
potrzeb klienta przez programistów. Projektowanie kwestionariuszy i wywiadów strukturalnych
omówione jest między innymi w książce J. T. T. Barone'a i J. Switzera [Barone i Switzer, 1995].
Spotkania
Agenda spotkania składa się z przynajmniej trzech części: nagłówka określającego pla-
nowane miejsce i czas spotkania, listy tematów zgłoszonych przez uczestników oraz listy pro-
blemów, dla których w trakcie zebrania poszukiwać się będzie rozwiązań. Każdemu elemen-
towi zebrania przydziela się maksymalny czas, dzięki czemu chronometrażysta może zapewnić,
że całe zebranie zakończy się w wyznaczonym terminie. W tabeli 3.9 widzimy przykład agendy;
agenda przedstawiona w tabeli 3.10, mimo pozorów poprawności, jest w istocie bezwartościowa
(załączone komentarze wyjaśniają, dlaczego).
choć w danej chwili tylko jeden może modyfikować ów przedmiot dyskusji: zabieranie głosu
może mieć charakter anarchiczny (wszyscy wypowiadają się w sposób niekontrolowany) bądź
sekwencyjny (użytkownik mający głos nie może być z niego wywłaszczony, dopóki sam nie
przekaże go kolejnemu dyskutantowi).
Słabą stroną takich „synchronicznych" dyskusji jest trudność koordynowania poczynań
poszczególnych dyskutantów. Pisanie na klawiaturze jest trudniejsze (wolniejsze) od swobod-
nego wypowiadania się (dla typowego, niezaprawionego w czatowaniu użytkownika), poza
tym zredukowanie formy wymiany informacji do tekstu pisanego stwarza ryzyko zagubienia
wielu informacji, które w rozmowie bezpośredniej można wyrazić na przykład przez gesty-
kulację. Co więcej, drobne nawet zakłócenia w działaniu sieci (internetu) mogą powodo-
wać interferencję działań grożącą zupełną utratą koordynacji. I mimo iż dostępna przepusto-
wość internetu zwiększa się nieustannie, a na rynku dostępne są znakomite narzędzia do
obsługi internetowych wideokonferencji — takie jak Lotus Sametime [Lotus] — narzędziom
tym jeszcze daleko do dojrzałości wymaganej w związku z niezawodnością codziennej pracy.
W konsekwencji praca grupowa w rozproszeniu wciąż pozostaje dla projektantów i pro-
gramistów niebagatelnym wyzwaniem, któremu stawić czoła można jedynie poprzez staranne
jej planowanie z odpowiednim wyprzedzeniem. Grupowe opracowywanie procedur wspoma-
gających pracę grupową to kolejne wyzwanie w sytuacji, gdy kontakt bezpośredni oraz niewer-
balne kanały komunikacji nie są dostępne.
Na przestrzeni ostatnich dwudziestu lat coraz większą popularność zdobywa sobie asyn-
chroniczna komunikacja grupowa. W swej najprostszej formie stanowi ona analogię tablicy,
na której uczestnicy mogą zapisywać swoje komentarze, w podziale na wątki dedykowane
poszczególnym tematom. Sieć W W W zapewnia ponadto szeroki dostęp do ogromnych repo-
zytoriów dokumentów pochodzących z rozmaitych źródeł. Obecnie w każdym projekcie an-
gażującym więcej niż tylko garstkę uczestników w powszechnym użyciu są rozmaite narzędzia
i procedury stanowiące kombinacje forów dyskusyjnych, repozytoriów, kalendarzy i książek
adresowych, w rozmaitej skali — od darmowych narzędzi dedykowanych małym projektom
do komercyjnych rozwiązań wspomagających olbrzymią organizację. I tak na przykład dar-
mowe Yahoo Groups [Yahoo] stwarza zespołowi platformę wymiany plików i fotografii, pla-
nowania zdarzeń, umieszczania ogłoszeń i dyskutowania problemów. BSCW (Basic Support
for Cooperative Work) [BSCW] także umożliwia współpracę za pośrednictwem WWW, w po-
staci wysyłania (uploadu) dokumentów, powiadamiania o zdarzeniach i zarządzania pracą
zespołu. Wiki [Wiki] to inny przykład prostej, lecz użytecznej platformy współpracy na bazie
WWW; interesującą osobliwością Wiki jest możliwość edycji stron W W W przez każdego
użytkownika, wspomaganej automatycznym tworzeniem hiperłączy między poszczególnymi
stronami.
Wśród narzędzi komercyjnych Sharepoint Team Services [Microsoft] zawiera mechani-
zmy współpracy dla użytkowników pakietu Microsoft Office. Narzędzia wspierające przepływ
działań, takie jak Lotus Notes [Lotus], dostarczają mechanizmy replikacji, obsługi repozyto-
riów i książek adresowych upubliczniających strukturę organizacyjną. Powtarzane regularnie
czynności mogą być automatyzowane. Sformalizowane aktywności, jak asynchroniczny prze-
gląd dokumentu przez wielu uczestników, wspomagane są adnotacjami, którymi opatrywać
można dokument na jego drodze poprzez potok użytkowników.
146 Rozdziat 3. • Organizacja projektu i komunikacja
Tabela 3.12. Przydział ról dla członków zespołu baz danych projektu OWL
Potrzeby
Uczestnik Role Kwalifikacje
szkoleniowe
Alice Kierownik zespołu Zarządzanie: kierownik zespołu UML
Programowanie: C Umiejętności
Zarządzanie konfiguracją komunikacyjne
John Łącznik z zespołem Programowanie: C++ Java
architektonicznym Modelowanie: UML
Implementator
Podobnie prezentuje się grupa forów zespołowych, z których każde jednak ograniczone jest
tylko do konkretnego zespołu. Generalnie programiści mają nieograniczoną możliwość czytania
wszystkich forów zespołowych, lecz posty umieszczać mogą tylko na forum własnego zespołu.
Kreowanie forów rozpoczyna się w momencie, gdy dekompozycja systemu staje się już
względnie stabilna. Oczywiście, wraz z tworzeniem forów definiowane są także konta dla
poszczególnych uczestników.
Szczególnie istotne jest pierwsze spotkanie tego typu: poszczególni członkowie zespołu n a ogół
nie znają się jeszcze osobiście i tylko nieliczni ś w i a d o m i są f o r m a l n y c h ról i p r o c e d u r obowiązują-
cych n a takich z e b r a n i a c h . K i e r o w n i c y z e s p o ł ó w m a j ą więc o k a z j ę w p r o w a d z e n i a wszystkich
c z ł o n k ó w we w s p o m n i a n e p r o c e d u r y , w y j a ś n i e n i a ich istotności i z m o t y w o w a n i a d o ich
przestrzegania. P o n i ż e j w i d o c z n a jest a g e n d a s t w o r z o n a p r z e z k i e r o w n i k a z e s p o ł u w związku
z pierwszym spotkaniem.
Przeglądy projektowe mogą być związane także z uruchamianiem „na sucho"2 systemu przed
przekazaniem go klientowi do testów akceptacyjnych. Terminy wszystkich przeglądów ustalane
są przez menedżera projektu w fazie planowania. Przykładowy harmonogram przeglądów
przedstawiony jest w tabeli 3.13.
Przegląd projektu obiektów 13. tydzień (dwie sesje) Dokument projektu obiektów
Przegląd wewnętrzny 16. tydzień Testy modułowe i integracyjne
„Suchy przebieg" przed 17. tydzień Wszystkie produkty docelowe projektu
testami akceptacyjnymi
2
Uruchamianie na sucho, suchy przebieg (ang. dry run) — mentalne „uruchamianie" programu
przez programistę, który analizując krok po kroku wykonywanie kolejnych instrukcji, obserwuje
skutki tego wykonywania. W odniesieniu do testów akceptacyjnych termin ten ma jednak trochę
inne znaczenie — odnosi się do kompletnego przetestowania systemu, zanim przekazany zostanie
klientowi do testowania. Interesująca etymologia tego terminu — w kontekście przymiotnika dry
— opisana jest pod adresem http://www.worldwidewords.org/qa/qa-dryl.htm —przyp. tłum.
Ów tydzień stanowi pewną rezerwę czasową dla opóźnionych dokumentów: zdarza się bowiem, że zo-
stają one dostarczone nawet na dzień przed planowanym przeglądem, co rodzi dwojakiego rodzaju
problemy: po pierwsze, dokumenty te muszą zostać udostępnione wszystkim uczestnikom, po drugie,
każdy uczestnik musi mieć czas na zapoznanie się z dokumentem.
3.6. Literatura uzupełniająca 151
3.7. Ćwiczenia
3.1. Jaka jest różnica między rolą a uczestnikiem?
3.2. Czy jedna rola może być współdzielona między kilku uczestników? Dlaczego tak albo
dlaczego nie?
3.3. Jaka jest różnica między klientem a użytkownikiem?
3.4. Do jakich ról przypisałbyś poniższe zadania:
• Zmiana interfejsu podsystemu w celu uwzględnienia nowych wymagań,
• Zakomunikowanie zmiany interfejsu innym zespołom,
• Uwzględnienie zmiany interfejsu w dokumentacji,
• Zaprojektowanie zestawu testowego w celu wykrycia ewentualnych usterek wyni-
kających ze zmiany,
• Upewnienie się, że zmiana została wykonana terminowo.
3.5. Załóżmy, że jesteś odpowiedzialny za koordynację projektu systemu obsługi wnio-
sków kredytowych dla banku: w jakich rolach obsadziłbyś następujących uczestników,
by jak najlepiej wykorzystać ich kwalifikacje?
• pracownik banku, odpowiedzialny za obsługę wniosków kredytowych,
• menedżer IT banku, kontraktujący system,
• niezrzeszony programista, który w przeszłości uczestniczył w realizacji podobnych
systemów,
• dokumentalista techniczny,
• Ty.
3.6. Narysuj diagram aktywności UML reprezentujący zebranie jako proces opisany
w sekcji 3.4.1. Zwróć szczególną uwagę na produkty generowane przed zebraniem
i po nim, takie jak agenda i protokół. Wykorzystaj partycjonowanie aktywności do
wyodrębnienia poszczególnych ról.
3.7. Jaka jest różnica między produktem a pakietem? Kiedy definiowany jest pierwszy,
a kiedy drugi? Rozpatrz sytuację, gdy dwóch studentów uczestniczy w tworzeniu
podsystemu sortowania listy nazwisk, przy czym każdy student stosuje inny algo-
rytm sortowania. Oczekiwanymi produktami docelowymi są: kod źródłowy, do-
kumentacja podsystemu orz instrukcja dla innych programistów opisująca sposób
integrowania nowego algorytmu sortowania z kodem wywołującym. Podaj przykłady
pakietów i produktów związanych z tym projektem.
3.8. Jaka jest różnica między zespołem podsystemu a zespołem międzyfunkcyjnym?
3.9. Skoro przewidywanych jest wiele krytycznych zdarzeń komunikacyjnych (przegląd
kliencki, przegląd projektowy, przegląd partnerski), dlaczego istnieje ewentualność
komunikacji pozaplanowej (w związku z żądaniami wyjaśnień, żądaniami zmian,
rozwiązywaniem problemów)?
Bibliografia 153
3.10. Dla dowolnego dnia w Twoim tygodniu roboczym wymień wszystkie aktywności
kwalifikujące się jako zdarzenia komunikacyjne (koleżeńskie spotkania przy kawie,
rozmowa z zaprzyjaźnionym studentem, negocjowanie, ogłaszanie, przeglądanie
stron WWW). Jaki udział aktywności te mają w ogólnym bilansie Twoich dziennych
aktywności?
3.11. Załóżmy, że jesteś członkiem zespołu odpowiedzialnego za podsystem interfejsu
użytkownika, jesteś odpowiedzialny za zaimplementowanie formularza kolekcjonu-
jącego informację o użytkowniku (nazwisko, imię adres, e-mail, stopień doświadcze-
nia). Informacja zbierana za pomocą formularzy kolekcjonowana jest w bazie danych
i wykorzystywana przez podsystem raportowania. Nie jesteś pewien, które pola muszą
być wypełnione obowiązkowo, a które opcjonalnie — jak rozwiązałbyś ten problem?
3.12. W związku z weryfikacją planów i rotacją personelu zostałeś przeniesiony z zespołu
interfejsu użytkownika do zespołu baz danych. Implementacja projektu jest wysoce
zaawansowana. W jakiej obecnie roli sprawdziłbyś się najlepiej, jeżeli wziąć pod uwagę
Twoje doświadczenia nabyte przy implementowaniu interfejsów użytkownika?
3.13. Załóżmy, że programiści tworzą system na platformie uniksowej, a dokumentaliści
tworzą dokumenty na macintoshu. Klient wymaga dokumentacji czytelnej również
w systemie Windows. Programiści tworzą dokumentację projektową przy użyciu
Adobe FrameMaker. Zespół dokumentacyjny wykorzystuje MS Word do pisania do-
kumentacji użytkowej. Klient przysyła poprawki, lecz nie żąda ich uwzględnienia
w dokumentach już dostarczonych. Jak należy zorganizować przepływ informacji
(dotyczący narzędzi, formatów i tym podobnych) między programistami, doku-
mentalistami i klientem, by zminimalizować duplikowanie plików i jednocześnie
respektować wybór preferowanej platformy przez każdego z uczestników?
3.14. Jakie zaproponowałbyś zmiany w organizacji i infrastrukturze komunikacyjnej dla
projektu będącego sukcesorem Ariane 5 w obliczu katastrofy rakiety Ariane 501, opi-
sanej na początku tego rozdziału?
Bibliografia
[Barone i Switzer, 1995] J. T. T. Barone, J. Switzer Interviewing: Art and Skill, Allyn & Bacon, 1995.
[Curtis i in. 1988] B. Curtis, H. Krasner, N. Iscoe A field study of the software design
process for large systems, „Communications of the ACM", t. 31, nr 11,
1268 - 87, 1988.
[Doyle i Straus, 1982] M. Doyle, D. Straus How to make meetings work, T h e Berkeley
Publishing Group, NY, 1982.
[Fagan, 1976] M. E. Fagan Design and code inspections to reduce errors in program
development, „IBM System Journal", t. 15, nr 3, str. 182 - 211, 1976.
[Fisher i in., 1991] R. Fisher, W. Ury, B. Patton Getting to Yes: Negotiating Agreement
Without Giving In, wyd. drugie, Penguin Books, 1991.
154 Rozdziat 3. • Organizacja projektu i komunikacja
[Gantt, 1910] H. L. Gantt, Work, wages, and profits, „The Engineering Magazine",
New York, 1910.
[Grudin, 1988] J. Grudin „Why CSCW applications fail: Problems in design and evaluation
of organization interfaces", Proceedings CSCW'88, Portland, OR, 1988.
[Kayser, 1990] T. A. Kayser Mining Group Gold, Serif, El Segundo, CA, 1990.
[Lions, 1996] J.-L. Lions ARIANE 5 Flight 501 Failure: Report by the Inquiry Board,
http://www.esrin.esa.it/htdocs/tidc/Press/Press96/ariane5rep.htrnl, 1996.
Bibliografia 208
4
Zbieranie wymagań
Standardowe wzorce
W edytorze tekstu Emacs sekwencja klawiszy Cłrl+X Ctrl+C powoduje wyjście z programu; jeśli
jednak w edytowanym pliku istnieją niezapisane jeszcze zmiany, wyświetlane jest pytanie Save file ...?
(y om) („Czy zapisać plik...?"). Naciśnięcie klawisza y spowoduje zapisanie zmian i wyjście z edytora,
naciśnięcie klawisza n spowoduje wyjście z edytora bez zapisywania zmian. Wiele edytorów hołduje
jednak odmiennej konwencji, wyświetlając w takiej sytuacji zapytanie w rodzaju: „Czy naprawdę
chcesz wyjść z programu?", przy zachowaniu znaczenia klawiszy^ i n jako (odpowiednio) akceptacji
i sprzeciwu. Dotychczasowy użytkownik Emacsa, przesiadając się na edytor tej drugiej kategorii,
może się wiele razy pomylić (z różnym skutkiem), zanim przyzwyczai się do nowej konwencji.
4.4 zajmiemy się aktywnościami wchodzącymi w skład zbierania wymagań, zaś sekcję 4.5
poświęcimy aktywnościom menedżerskim związanym ze zbieraniem wymagań. Przedmiotem
sekcji 4.6 będzie analiza przypadku, jakim jest system ARENA.
Zbieranie wymagań i ich analiza koncentrują się jedynie na spojrzeniu na system z per-
spektywy jego użytkownika. Częścią wymagań są więc takie aspekty systemu jak jego elementy
funkcjonalne, jego interakcja z użytkownikami, kategoria błędów, na które działanie systemu
powinno być odporne, czy uwarunkowania środowiska, w którym system będzie funkcjono-
wał. Inne jego aspekty, niewidoczne bezpośrednio dla użytkownika — struktura, technologie
implementacyjne, projekt systemu, projekt obiektów — nie są przedmiotem zainteresowania
w fazie zbierania i analizy wymagań.
160 Rozdział 4. • Zbieranie wymagań
• Joint Application Design (JAD) („połączony projekt2 aplikacji") — istotą tej metody
jest budowanie konsensusu między programistami, klientem i użytkownikami w celu
wspólnego wypracowania specyfikacji wymagań.
• Identyfikowałność — metoda ta sprowadza się do rejestrowania, strukturalizowania,
łączenia i grupowania zarówno zależności między samymi wymaganiami, jak i ich
relacji do innych produktów projektu.
2
Słowo „projekt" (design) w wyjaśnieniu akronimu JAD może być tu cokolwiek mylące, występuje
bowiem w zupełnie innym znaczeniu niż to, w jakim używane jest w rozdziałach poświęconych
projektowi systemu i projektowi obiektów.
4.3. Koncepcje zbierania wymagań 161
SatWatch jest naręcznym zegarkiem wyświetlającym aktualny czas, zgodnie ze strefą czasową
właściwą dla bieżącej lokalizacji. W celu określenia tej lokalizacji (i uzyskania związanych z nią
struktur danych) SatWatch kontaktuje się z satelitami GPS.
SatWatch gwarantuje dokładny pomiar czasu bez potrzeby jakichkolwiek zabiegów dostosowu-
jących ze strony użytkownika. Gdy użytkownik przekracza geograficzną lub polityczną strefę
czasową, następuje automatyczne uwzględnienie tego faktu, w związku z czym SatWatch nie po-
siada żadnych przycisków regulacyjnych dostępnych dla użytkownika. ]ako że działanie zegarka
SatWatch uzależnione jest od systemu GPS, obarczone jest tymi samymi mankamentami i ogra-
niczeniami, co generalnie wszystkie urządzenia korzystające z tego systemu, między innymi niemoż-
nością określenia lokalizacji w pewnych porach dnia w rejonie górzystym. W czasie, gdy GPS
nie jest dostępny, SatWatch przyjmuje, że nie została przekroczona strefa czasowa; gdy tylko
uda m u się nawiązać łączność z GPS, wskazanie czasu jest korygowane do właściwej wartości.
Na wypadek, gdyby zmieniły się polityczne granice stref czasowych, istnieje możliwość uaktualnienia
programowania zegarka, za pomocą urządzenia WebifyWatch (dostarczanego wraz z zegarkiem)
i komputera podłączonego do internetu.
• Użytecznością rozumianą jako łatwość uczenia się przez użytkownika obsługi systemu
(lub jego komponentu), przygotowywania jego danych wejściowych i interpretowania
wyników. Wymagania tej kategorii mogą dotyczyć konwencji związanych z interfej-
sem użytkownika, zakresu pomocy online, stopnia szczegółowości dokumentacji
i tym podobnych. Często zdarza się, że klient, w celu uproszczenia obsługi systemu,
żąda od programistów zgodności interfejsu GUI z określoną konwencją kolorystyczną,
czcionkami czy firmowym logo.
• Niezawodnością oznaczającą zdolność systemu lub jego komponentu do spełniania
wymaganych funkcji w określonych warunkach i w określonym przedziale czasu.
Elementem niezawodności może być na przykład średni czas pracy między awariami
(MTBF — mean time between failures), wykrywanie specyficznych awarii czy skuteczne
odpieranie ataków na zabezpieczenia. Ostatnio kategorię tę zastąpiła nowa, zwana
pewnością działania (ang. dependability), która oznacza, że usługi świadczone przez
system mogą być uważane za godne zaufania; składają się na nią: niezawodność,
solidność (rozumiana jako zdolność do poprawnego radzenia sobie z nieprawidłowymi
danymi wejściowymi lub uciążliwymi warunkami środowiska, na przykład dużym ob-
ciążeniem) i bezpieczeństwo (będące miarą braku katastroficznych konsekwencji dla
środowiska).
• Wydajnością, czyli mierzalnymi aspektami działania systemu w postaci między innymi
czasu reakcji systemu na akcję użytkownika, przepustowości (mierzonej jako ilość
pracy wykonywanej w jednostce czasu), stopnia dostępności (operatywności) systemu
lub komponentu, gdy zachodzi potrzeba jego użycia oraz dokładności.
• Wspieralności wyrażającej się łatwością wprowadzania zmian do systemu po jego
wdrożeniu, czyli między innymi w związku z pojawianiem się nowych koncepcji
w dziedzinie aplikacyjnej (adaptowalność), usuwaniem usterek, implementowaniem
nowych technologii (łatwość utrzymania) czy poszerzaniem o nowe konwencje re-
gionalne (internacjonalizacją) — języki, jednostki miar, formaty liczb i dat i tym
podobne. Standard ISO 9126 dotyczący jakości oprogramowania [ISO Std. 9126],
podobny do modelu FURPS+, zastępuje tę kategorię dwiema innymi: łatwością
utrzymania i przenośnością rozumianą jako łatwość transferowania systemu lub
jego komponentu między różnymi platformami sprzętowymi i programowymi.
3
FURPS+ jest akronimem utworzonym z pierwszych liter słów Functionality (funkcjonalność), Usability
(użyteczność) Reliability (niezawodność), Performance (wydajność) i Supportability (wspierałność);
znak „+" symbolizuje pozostałe kategorie. Model FURPS został zaproponowany po raz pierwszy w pracy
Grady'ego [Grady, 1992], Jego definicję na potrzeby tego rozdziału zaczerpnęliśmy z opisu standardu
[IEEE Std. 610.12-1990],
4
Patrz sekcja 15.4.2 — przyp. tłum.
4.3. Koncepcje zbierania wymagań 163
• Produkt musi posiadać dobry interfejs użytkownika — znaczenie słowa „dobry" nie
jest precyzyjnie zdefiniowane.
• Produkt musi być wolny od wszelkich defektów — zweryfikowanie tego wymagania
wymagałoby użycia nadmiernej ilości zasobów.
• W większości przypadków produkt musi reagować na akcję użytkownika w ciągu
1 sekundy — co to znaczy „w większości przypadków"?
Specyfikacja jest identyfikowalna, jeśli każde z wymagań może być wyraźnie odniesione
do określonego podzbioru funkcji systemu, i vice versa — gdy każda funkcja systemu daje się
zidentyfikować w aspekcie zbioru wymagań przemawiających za jej istnieniem. Identyfiko-
walność obejmuje także możliwość śledzenia zależności między poszczególnymi wymaganiami,
funkcjami systemu i pośrednimi artefaktami projektowymi — komponentami systemu, kla-
sami, metodami i atrybutami obiektów. Staje się ona cechą krytyczną w przypadku planowa-
nia testów i oceniania konsekwencji zmian: dzięki niej tester może określać stopień pokrycia
testowego kodu, czyli identyfikować te wymagania, które faktycznie podlegają przetestowaniu,
zaś programiści są w stanie określać wpływ dokonywanych zmian na poszczególne kompo-
nenty systemu.
na tworzeniu systemu „od zera", gdyż nie istnieje żaden jego pierwowzór, oraz inżynierię
wtórną (nazywaną często niezbyt zgrabnie „reinżynierią", od ang. reingeenering), której istotą
jest ponowne zaimplementowanie lub przeprojektowanie istniejącego systemu, w związku
z nowymi potrzebami biznesowymi lub pojawieniem się nowych technologii. Piszą o tym
M. Hammer i J. Champty [Hammer i Champy, 1993]. Opisywany wcześniej projekt zegarka
SatWatch jest przykładem inżynierii pierwotnej.
Przedmiotem inżynierii interfejsu jest interfejs użytkownika istniejącego systemu
— poza ponownym zaprojektowaniem lub ponownym zaimplementowaniem tego interfejsu,
wszystkie inne cechy systemu pozostają bez zmian. Sytuacja taka występuje wówczas, gdy
rachunek ekonomiczny przemawia raczej za użytkowaniem dotychczasowego systemu niż
za tworzeniem zupełnie nowego.
W przypadku dwóch pierwszych kategorii programiści starają się zebrać jak najwięcej
informacji z zakresu dziedziny aplikacyjnej, którą to informację znaleźć mogą między innymi
w podręcznikach systemu, dokumentacji dla nowych pracowników, słownikach, ściągawkach
i innych notatkach użytkowników, no i — oczywiście — w czasie bezpośrednich wywiadów
z klientem i użytkownikami. Jakkolwiek wywiady te są z założenia nieocenionym narzędziem,
nie pomagają jednak w uzyskiwaniu żądanej informacji, gdy zadaje się niewłaściwe pytania;
dlatego też programiści powinni uzyskać najpierw jak najwięcej wiadomości, zanim zastosują
owo podejście bezpośrednie.
Zajmiemy się teraz szczegółowo aktywnościami związanymi ze zbieraniem wymagań.
Rysunek 4.2. Aktorzy związani z systemem SatWatch. WatchOwrer wykorzystuje wskazania zegarka,
zegarek współdziała z GPS-em w celu ustalenia bieżącej lokalizacji, zaś urządzenie Webi fyWatch umożliwia
aktualizację wewnętrznych danych związanych z polityką zmiany czasu (na przykład zmianą początkowej
i końcowej daty czasu letniego)
Rysunek 4.3. Aktorzy współdziałający z systemem FRIEND. Aktorzy nie tylko wykorzystują różne
elementy funkcjonalności systemu, lecz także posługują się różnymi komputerami
168 Rozdział 4. • Zbieranie wymagań
• Które z tych grup zajmować się będą funkcjami wtórnymi, takimi jak administrowanie i utrzymanie?
• Z jakim zewnętrznym sprzętem lub oprogramowaniem współpracować ma tworzony system?
3
EPA — Environmental Protection Agency, Agencja Ochrony Środowiska, federalna organizacja rządu
USA — przyp, tłum.
4.4. Aktywności związane ze zbieraniem wymagań 169
Tabela 4.2. Scenariusz warehouseOnFi re jako instancja przypadku użycia Report Emergency
Nazwa warehouseOnFire
Scenariusze nie powinny opisywać podejmowania decyzji — do tego potrzebna jest para
scenariuszy: jeden odpowiadający decyzji na „tak", drugi odpowiadający decyzji na „nie".
W procesie zbierania wymagań — a także w innych stadiach projektu — scenariusze
mogą mieć rozmaite zastosowania. W pracy J. M. Carrola [Carroll, 1995] wyróżniono kilka
typowych grup scenariuszy.
• Scenariusz bieżący opisuje aktualną sytuację. Przykładowo w ramach inżynierii
wtórnej programiści obserwują zachowanie użytkowników aktualnie eksploatowane-
go systemu, opisując ich akcje w formie scenariuszy. Scenariusze tej kategorii są póź-
niej weryfikowane przez użytkowników pod kątem poprawności i dokładności.
• Scenariusz wizjonerski opisuje fragment systemu istniejącego dopiero w zamyśle
projektantów. Taki scenariusz może być zarówno punktem w przestrzeni modelowa-
nia programistów, którzy w ten sposób doskonalą swe wyobrażenie na temat przy-
szłego systemu, jak i medium komunikacji z użytkownikami. Scenariusze wizjonerskie
mogą być uważane za tanie odmiany prototypów.
170 Rozdział 4. • Zbieranie wymagań
6
Z ang. fender-bender to „stłuczka" — p>'zyp- tłum.
4.4. Aktywności związane ze zbieraniem wymagań 171
Tabela 4.3. Przykładowy przypadek użycia — ReportEmergency. W opisie przepływu zdarzeń lewa
kolumna identyfikuje akcje podejmowane przez aktorów, prawa — reakcje systemu
Pisanie przypadków użycia jest umiejętnością, którą analityk doskonali poprzez prak-
tykę. Doskonalenie to wiąże się z wypracowywaniem własnego stylu, co — niestety — prowa-
dzi do zróżnicowania stylów poszczególnych analityków i trudności w tworzeniu spójnych
specyfikacji wymagań. Analitycy mogą uniknąć tego zagrożenia, posiłkując się określonymi
wytycznymi dotyczącymi pisania przypadków użycia. Poniżej widzimy przykład takich wy-
tycznych, zaczerpnięty z pracy A. Cockburna [Cockburn, 2001], zaś w tabeli 4.4 widoczny jest
przykład przypadku użycia wyraźnie odbiegającego od tych wytycznych.
Przykład z tabeli 4.3 jest wystarczającą ilustracją tego, jak system FRIEND obsługuje
powiadamianie o incydentach i jak współpracują z nim poszczególni użytkownicy: jest on
jednak zbyt mało szczegółowy, by mógł stanowić element specyfikacji wymagań. Zobacz-
my więc, w jaki sposób możliwe jest doskonalenie przypadków użycia i wzbogacanie ich
w niezbędne szczegóły.
7
Także w języku polskim strona czynna („Policjant wzywa karetkę") udostępnia więcej informacji
niż strona bierna („Wezwana została karetka"), czy użycie trybu zwrotnego („Zjawia się karetka")
— tylko w pierwszym przypadku jest mowa o policjancie — przyp. tłum.
174 Rozdział 4. • Zbieranie wymagań
Tabela 4.5. Uszczegółowiony przypadek użycia Report Emergency; dodane szczegóły wyróżnione są kursywą
Przepływ zdarzeń 1. Fi el dOf f i cer aktywuje funkcję „Raportuj zdarzenie" na swym terminalu.
2. System FRI END wyświetla w odpowiedzi stosowny formularz.
Formularz ten zawiera pola określające między innymi rodzaj
niebezpieczeństwa (ogólne, pożar, komunikacyjne), lokalizację
zdarzenia, jego opis, żądanie zasobów i udział materiałów
niebezpiecznych.
3. Fi el dOf f i c e r wypełnia formularz z obowiązkowymi polami
reprezentującymi typ zdarzenia i jego krótki opis. Fi el dOf f i cer określa
także możliwe sposoby pierwszej reakcji na zagrożenie i wymagane
do tej reakcji zasoby. Po wypełnieniu f o r m u l a r z a F i e l d O f f i c e r
wysyła go do systemu.
4. System FRI END p o w i a d a m i a dyspozytora (Di s p a t c h e r )
o zdarzeniu poprzez wyświetlenie okna ze stosownym
komunikatem i sygnał dźwiękowy.
5. Di spatcher analizuje informacje zawarte w formularzu, po czym tworzy
nowy obiekt Inci dent w bazie, realizując przypadek użycia Openlnci dent.
Cała informacja zawarta we wspomnianym formularzu automatycznie
włączana jest do obiektu Incident. Di spatcher określa sposób reakcji,
dokonując przydziału odpowiednich zasobów (reprezentowanego
przez przypadek użycia Al T o c a t e R e s o u r c e s j i zatwierdza raport,
wysyłając stosowny komunikat do aktora Fi el dOf f i cer.
6. System FRI END informuje aktora Fi el dOf f i cer o zatwierdzeniu
raportu i przekazuje m u informację od dyspozytora.
Warunki wstępne [...]
Warunki końcowe [...]
Wymagania jakościowe
jakościowe [...]
[...]
4.4. Aktywności związane ze zbieraniem wymagań 175
Przypadek użycia może pełnić funkcję rozszerzania innego przypadku użycia, jeśli ten
drugi obejmuje zachowanie reprezentowane przez ten pierwszy (przy spełnieniu określonych
warunków). Załóżmy, że w momencie, gdy F i e l d O f f i c e r zamierza wysłać formularz zgło-
szenia incydentu, urywa się połączenie sieciowe jego laptopa z internetem (na przykład ze
względu na zanik sygnału w tunelu): Fi el dOffi cer musi wówczas zostać poinformowany
(przez aplikację działającą we wspomnianym laptopie), że formularz zgłoszeniowy nie został
4.4. Aktywności związane ze zbieraniem wymagań 177
Rysunek 4.4. Przykład relacji komunikacyjnych między aktorami a przypadkami użycia w systemie
FRIEND. Aktor F i e l d O f f i c e r inicjuje przypadek użycia ReportEmergency, natomiast D i s p a t c h e r
inicjuje przypadki użycia Openlncident i A l l o c a t e R e s o u r c e s . Aktor F i e l d O f f i c e r nie ma więc
prawa do rejestrowania („otwierania") nowego incydentu ani do decydowania o przydzielaniu zaso-
bów potrzebnych do jego obsługi
Rysunek 4.5. Przykład relacji rozszerzania. Przypadek użycia ConnectionDown jest rozszerzeniem przy-
padku użycia ReportEmergency. Użycie relacji rozszerzania przyczynia się do uproszczenia przypadku
ReportEmergency i jego skoncentrowania na czynności zasadniczej — powiadamianiu o niebezpieczeństwie
(wozów strażackich) znajdujących się w pobliżu owego pożaru. Szczegóły czynności wykony-
wanych przez aktora Di spatcher w związku z korzystaniem z mapy wyodrębnione zostają
w postaci osobnego przypadku użycia ViewMap, wykorzystywanego przez dwa inne przypadki
użycia — Open Incident i AllocateResources, co p o k a z a n o n a r y s u n k u 4.6.
AllocateResources
Rysunek 4.6. Przykład relacji zawierania między przypadkami użycia. Przypadek ViewMap opisuje
przepływ zdarzeń związanych z przeglądaniem m a p y (przewijanie, powiększanie, wyszukiwanie
obiektów według nazwy i tym podobne) i wykorzystywany jest przez przypadki użycia Openlnci dent
i AllocateResources
Relacja rozszerzania jest bardziej odpowiednia dla zdarzeń wyjątkowych lub zachodzących
sporadycznie — na przykład dla zerwania połączenia, anulowania transakcji czy uruchomie-
nia pomocy kontekstowej.
Ilustracją porównania obu relacji (zawierania i rozszerzania) jest tabela 4.6, w której
widoczne są efekty powiązania ze sobą przypadków użycia ReportEmergency i ConnectionDown.
Relacja zawierania (lewa kolumna) wymaga dołączenia w dwóch miejscach nadrzędnego
przypadku (ReportEmergency) tekstu oznaczającego dołączenie przypadku ConnectionDown,
aktywowanego pod określonym warunkiem. W przypadku relacji rozszerzania przypadek nad-
rzędny pozostaje nietknięty, natomiast w przypadku rozszerzającym (ConnectionDown) spe-
cyfikowany jest zestaw przypadków nadrzędnych podlegających rozszerzaniu („każdy przypa-
dek użycia, w ramach którego może zdarzyć się zerwanie połączenia sieciowego między
Fi el dOff i cerem a Di spatcherem"). Możliwość modelowania nowych zachowań bez potrzeby
ingerowania w tekst istniejących przypadków użycia — dzięki relacji rozszerzania — jest
bardzo cenna, by nie rzec: krytyczna, z punktu widzenia stabilności modelu i ryzyka popeł-
niania błędów. Rozróżnienie między obiema relacjami, jeśli dokonane właściwie, ma pozytywny
wpływ na jakość dokumentacji, ponieważ zmniejsza redundancję przypadków użycia, redukuje
zależności między przypadkami i zmniejsza ryzyko popełniania błędów w sytuacji zmiany
wymagań. Trzeba jednak przyznać, że z perspektywy innych aktywności programistycznych
różnica między wspomnianymi relacjami jest kwestią marginalną.
We właściwym zastosowaniu jednej albo drugiej relacji mogą okazać się pomocne
heurystyki opisane w ramce.
Niezależnie od opisanych różnic, obie relacje służą jednak temu samemu celowi — redu-
kowaniu lub usuwaniu redundancji z modelu, a w konsekwencji zmniejszaniu ryzyka wystą-
pienia niespójności.
1. [...] 1. [...]
2. [...] 2. [...]
3. Fi el dOf f i cer wypełnia formularz, określając 3. Fi el dOf f i cer wypełnia formularz, określając
typ zdarzenia, stopień zagrożenia, jego typ zdarzenia, stopień zagrożenia, jego
lokalizację i krótki opis sytuacji. Fi el dOf f i cer lokalizację i krótki opis sytuacji. Fi el dOf f i cer
określa także możliwe sposoby pierwszej określa także możliwe sposoby pierwszej
reakcji na zagrożenie. Po wypełnieniu reakcji na zagrożenie. Po wypełnieniu
f o r m u l a r z a Fi el dOf f i cer wysyła go do f o r m u l a r z a Fi el dOf f i c e r wysyła go
systemu. do systemu.
Gdyby zerwane zostało połączenie sieciowe,
wykorzystywany będzie przypadek użycia
ConnectionDown.
4. Jeśli nawiązane jest połączenie sieciowe, 4. System FRIEND powiadamia dyspozytora
system FRIEND powiadamia dyspozytora (Di s p a t c h e r ) o zdarzeniu. Di s p a t c h e r
(Di s p a t c h e r ) o zdarzeniu. Di s p a t c h e r analizuje informacje zawarte w formularzu,
analizuje informacje zawarte w formularzu, po czym tworzy nowy obiekt Inci dent
p o czym tworzy nowy obiekt I n c i d e n t w bazie, realizując p r z y p a d e k użycia
w bazie, realizując przypadek użycia Openlncident. D i s p a t c h e r określa sposób
Openlncident. D i s p a t c h e r określa sposób reakcji i zatwierdza raport.
reakcji i zatwierdza raport
Gdyby zerwane zostało połączenie sieciowe,
wykorzystywany będzie przypadek użycia
ConnectionDown.
5. ...
1. Fi el d O f f i c e r i D i s p a t c h e r otrzymują 1. F i e l d O f f i c e r i D i s p a t c h e r otrzymują
informację o zerwaniu połączenia, być może informację o zerwaniu połączenia, być może
połączoną z wyjaśnieniem prawdopodobnej połączoną z wyjaśnieniem prawdopodobnej
przyczyny zerwania (modem poza zasięgiem przyczyny zerwania (modem poza zasięgiem
sieci, na przykład w tunelu). sieci, na przykład w tunelu).
2. Fakt zerwania połączenia rejestrowany jest 2. Fakt zerwania połączenia rejestrowany jest
w systemie; gdy łączność zostanie przywrócona, w systemie; gdy łączność zostanie przywrócona,
następuje próba ponowienia przerwanej następuje próba ponowienia przerwanej
transmisji danych. transmisji danych.
Jeśli dwa przypadki użycia odnoszą się do tej samej koncepcji, odpowiadające sobie
obiekty powinny nazywać się i wyglądać identycznie. Jeśli dwa obiekty o tej samej nazwie nie
odzwierciedlają tej samej koncepcji, należy przynajmniej jedną z tych nazw zmienić, tak by
uwydatnić różnicę między wspomnianymi koncepcjami; dzięki takiej konsolidacji unikniemy
wieloznaczności używanej terminologii. W tabeli 4.7 widoczna jest początkowa postać listy
obiektów uczestniczących w przypadku użycia ReportEmergency.
8
Nazywanym powszechnie „słownikiem danych".
182 Rozdział 4. • Zbieranie wymagań
G d y o b i e k t y u c z e s t n i c z ą c e w p o s z c z e g ó l n y c h p r z y p a d k a c h użycia z o s t a n ą j u ż s k o n -
s o l i d o w a n e , p r o g r a m i ś c i m o g ą użyć ich w c h a r a k t e r z e listy k o n t r o l n e j w celu u p e w n i e n i a się,
że z b i ó r o p r a c o w a n y c h p r z y p a d k ó w użycia jest k o m p l e t n y .
• W którym z przypadków użycia tworzony jest ten konkretny obiekt — kiedy wartości jego
atrybutów wprowadzane są do systemu?
• Którzy aktorzy mają dostęp do informacji zawartej w tym obiekcie?
• Które przypadki użycia mogą modyfikować i (lub) usuwać ten konkretny obiekt — w których
przypadkach użycia następuje edytowanie lub usuwanie informacji zawartej w tym obiekcie?
• Który aktor może inicjować ten konkretny przypadek użycia?
• Czy ten konkretny obiekt w ogóle jest potrzebny — czy chociaż jeden przypadek użycia
zależny jest od zawartej w tym obiekcie informacji?
Niezawodność • Jak wysoce niezawodny, dostępny i solidny powinien być tworzony system?
•
(w tym solidność, Czy dopuszczalny jest restart systemu w przypadku jego awarii?
bezpieczeństwo • Jaki stopień utraty danych powinien być tolerowany przez system?
i zabezpieczenia) • W jaki sposób system powinien reagować na sytuacje wyjątkowe?
• Czy od systemu wymaga się szczególnych cech w zakresie bezpieczeństwa
• dla użytkowników i środowiska?
Czy i jakie mechanizmy zabezpieczeń mają być obecne w systemie?
Implementacja • Czy istnieją konkretne wymagania dotyczące platformy sprzętowej dla systemu?
a Czy istnieją wymagania pod adresem zespołu utrzymania systemu?
•
Czy istnieją wymagania dotyczące testowania systemu?
Rysunek 4.7. Aktywności metodologii JAD. Centralną jej częścią jest Sesja, w ramach której wszyscy
uczestnicy wspólnie wypracowują specyfikację wymagań. Aktywności poprzedzające Sesją mają na celu
zwiększenie jej efektywności. Dokument końcowy, będący wynikiem S e s j i , jest odzwierciedleniem
decyzji podejmowanych na jej forum
Metoda JAD wykorzystywana była przez firmę IBM i kilka innych firm. JAD wykorzy-
stuje zalety dynamiki grupowej w celu usprawnienia komunikacji między uczestnikami i szyb-
szego osiągnięcia konsensusu. Po zakończeniu sesji JAD programiści są bardziej świadomi
potrzeb użytkowników, użytkownicy mają natomiast pojęcie o wielu kompromisach, jakie
przychodzi programistom rozstrzygać. Przyczynia się to do zmniejszenia prawdopodobieństwa
4.5. Zarządzanie zbieraniem wymagań 187
wnoszenia poprawek do projektu w dalszych jego etapach. Jako że sukces metody JAD zasadza
się na dynamice społeczności, uwarunkowany jest w dużej mierze kwalifikacjami facilitatora
prowadzącego cały proces. Więcej szczegółowych informacji na temat metody JAD znaleźć
mogą czytelnicy w pracy J. Wooda i D. Silvera [Wood i Silver, 1989].
9
Generalnie, sprawdzoną i formalnie zaakceptowaną wersję produktu nazywa się linią bazową. Za-
rządzanie konfiguracją to proces śledzenia i akceptowania zmian wprowadzanych do linii bazo-
wej. Zarządzaniu konfiguracją poświęcony jest rozdział 13.
190 Rozdział 4. • Zbieranie wymagań
A R E N A — deklaracja problemu
1. P r o b l e m
Popularność internetu i W W W wyzwoliła fenomen kreowania społeczności wirtualnych — grup
ludzi, którzy powiązani są wspólnymi sprawami, zainteresowaniami i tym podobnymi rzeczami,
lecz być może nigdy nie spotkali się i nie spotkają osobiście. Grupy takie mogą mieć charakter
doraźny (jak w przypadku czatu czy rozgrywania turnieju) bądź długotrwały (czego przykładem
są liczne grupy dyskusyjne). Grupy takie mogą być kilkuosobowe, lecz równie dobrze mogą
obejmować tysiące uczestników.
Upowszechnienie internetu i społeczności wirtualnych nie ominęło także obszaru gier kompu-
terowych. Wydostały się one z ciasnych ram pojedynczych komputerów i sieci lokalnych na forum
„globalnej wioski", w której wspomniane społeczności kreują się także w związku właśnie z rozgry-
waniem rozmaitych gier, rozgrywek, pojedynków czy turniejów. Poszczególni gracze informowani są
0 nowościach w zakresie „swojej" gry, mogą organizować, rozgrywać i obserwować rozgrywki,
porównywać wyniki i wymieniać doświadczenia. Producenci gier online zyskują dzięki temu pożytek
w postaci reklamowania swych produktów i ogólnie generowania dochodów w inny sposób.
W tej konstelacji społeczności gier brakuje jednak koordynacji: każda gra (czy też — każdy pro-
ducent) kreuje społeczność opartą na swych własnych zasadach, odmiennej infrastrukturze, odmien-
nych koncepcjach, zapewniając o d m i e n n e sposoby wsparcia dla uczestników. Ta redundancja
1 niespójność ma wiele mankamentów, między innymi w postaci trudności w zakresie uczenia się
nowych zasad, doświadczanej przez graczy dołączających do kolejnych społeczności. Dla producen-
tów oznacza to konieczność budowania infrastruktury „od zera", dla reklamodawców koniecz-
ność kontaktowania się osobno z każdą ze społeczności. Specyfika infrastruktury w poszczególnych
społecznościach utrudnia także budowanie wspólnych doświadczeń.
5.6. Analiza przypadku — system AREIMA 191
2. Cele
Wobec powyższego, stworzenie systemu ARENA ma w zamierzeniu zrealizować następujące cele:
® dostarczenie powszechnej infrastruktury unifikującej operacje często stosowane na scenie gry:
rejestrowanie nowych gier i graczy, organizowanie rozgrywek i śledzenie ich rezultatów;
• dostarczenie kapitanowi ligi środowiska umożliwiającego planowanie liczby i sekwencji
rozgrywek oraz gromadzenie punktów graczy w rankingach;
3. Wymagania funkcyjne
W systemie ARENA wyróżnia się pięć typów użytkowników:
• operator, definiujący nowe gry, nowe style rozgrywek (wygrana przez nokaut, mistrzostwa,
najlepszy w serii i tym podobne) i nowe formuły rankingu oraz zarządzający użytkownikami;
® kapitan ligi, definiujący nową ligę, organizujący i anonsujący nowe rozgrywki w ramach ligi,
prowadzący turnieje i ogłaszający zwycięzców;
• gracz, rejestrujący się na scenie, dołączający do ligi, rozgrywający meczę i ewentualnie rezygnujący
z rozgrywki;
4. Wymagania pozafunkcyjne
• Niski koszt użytkowania. O p e r a t o r musi mieć możliwość instalowania systemu ARENA
i administrowania jego instancją bez potrzeby dokupywania dodatkowego oprogramowania
i bez pomocy administratora systemu operacyjnego.
• Rozszerzalność. Operator musi mieć możliwość dodawania nowych gier, definiowania nowych
stylów rozgrywek i nowych f o r m u ł rankingu. Czynności te mogą wymagać chwilowego
zamknięcia systemu i dodania do niego nowych modułów (na przykład klas w języku Java),
nie mogą jednak powodować konieczności jego modyfikowania.
® Skalowalność. System musi umożliwiać równoległe prowadzenie wielu rozgrywek (powiedzmy 10),
z których każda obejmuje do 64 graczy i kilkuset kibiców.
® Male wymagania dotyczące przepustowości. Gracze muszą mieć możliwość rozgrywania meczów,
dysponując połączeniem analogowym o szybkości 56 Kb/s lub szybszym.
5. Platforma docelowa
® Gracz musi mieć możliwość dostępu do wybranej instancji systemu za pośrednictwem dowolnej
przeglądarki W W W akceptującej cookies. Funkcje administracyjne (dodawanie nowych gier,
definiowanie nowych stylów, definiowanie użytkowników) nie powinny być dostępne za
pośrednictwem przeglądarki W W W .
• System musi działać niezawodnie na dowolnej platformie uniksowej (na przykład MacOS X,
Linux czy Solaris).
192 Rozdział 4. • Zbieranie wymagań
10
Pod nazwą Tic-Tac-Toe ukrywa się popularna gra w kółko i krzyżyk — przyp. tłum.
5.6. Analiza przypadku — system AREIMA 193
Przepływ zdarzeń 1. Joe, kolega Alice jest entuzjastą gry w kółko i krzyżyk, i zgłasza chęć
zorganizowania rozgrywek w tej grze.
2. Alice rejestruje Joego na scenie jako kapitana ligi.
16. Joe postanawia urządzić kolejne turnieje w swojej lidze; znani gracze
otrzymają wówczas powiadomienia o terminie rozpoczęcia turnieju
1 o pierwszeństwie przed nowymi graczami.
194 Rozdział 4. • Zbieranie wymagań
• Klient: Tak, lecz powinno się akceptować również niekompletne informacje rejestra-
cyjne. Powinno się zachęcać rejestrującego się użytkownika do wypełnienia ankiety
o jego zainteresowaniach i tym podobnych, lecz nie można go do tego zmuszać pod
rygorem nieprzyjęcia rejestracji. Niezależnie od kompletności zgłoszenia, użytkownik,
rejestrując się, wyraża domniemaną zgodę na otrzymywanie informacji reklamowych.
• Czy profile użytkowników powinny być automatycznie przydzielane do list mailin-
gowych?
• Klient: Nie, zakładamy bowiem, że w naszej społeczności użytkownik sprawować bę-
dzie pełną kontrolę nad swymi subskrypcjami. Ukryte subskrypcje z pewnością nie
wywołają u niego wrażenia, iż kontroluje sytuację.
Krok 13. Bill ogląda statystyki meczów i następny mecz chciałby obejrzeć „na żywo".
Zauważmy, że głównym celem zadawania pytań klientowi jest zrozumienie jego potrzeb
oraz pozyskanie wiedzy z zakresu dziedziny aplikacyjnej. Gdy tę wiedzę zdobędziemy i spo-
rządzimy pierwszą wersję specyfikacji wymagań, możemy przystąpić do negocjowania z klien-
tem kompromisów między sprzecznymi wymaganiami, na przykład między zakresem funk-
cjonalnym systemu a jego kosztem. Nie spieszmy się jednak — zbyt wczesne przeplatanie
zbierania wymagań z ich negocjowaniem na ogół nie bywa zbyt produktywne.
Gdy pierwszy scenariusz zostanie dopracowany do tego stopnia, że uzgodnione zostaną
z klientem granice systemu (dla tego jednego scenariusza), możemy zająć się ogólnie rozu-
mianym obrazem funkcjonalnym tego systemu. Dokonywać będziemy tego sukcesywnie,
identyfikując wiele krótszych scenariuszy, oddzielnie dla poszczególnych aktorów; nie będą
one jeszcze zbyt szczegółowe, pokryją jednak znaczącą część wspomnianej funkcjonalności
(patrz rysunek 4.8). Gdy napotkamy nieporozumienia i wieloznaczności, konieczne stanie się
udoskonalanie wspomnianych scenariuszy. W naszym przykładzie scenariusze defineKnockOut
*-*-Styl e i i nstal 1 Ti cTacToeGame powinny być uszczegółowione na poziomie porównywalnym
ze scenariuszem organizeTicTacToeTournament z tabeli 4.9.
5.6. Analiza przypadku — system AREIMA 195
Rysunek 4.8. Wysokopoziomowe scenariusze dla systemu ARENA. Kwalifikują się do uszczegółowie-
nia w celu wyjaśnienia niejednoznaczności lub wykrycia nieporozumień
Typowy uszczegółowiony scenariusz zajmuje kilka stron tekstu, dla uniknięcia nieporo-
zumień konieczne jest więc utrzymywanie oficjalnego słownika terminologii, który z jednej
strony zapewnia spójność specyfikacji, z drugiej natomiast wymusza komunikację językiem
użytkownika. Przeglądając scenariusz z tabeli 4.9, łatwo zauważyć, że wyrazy „mecz", „gra",
„turniej" i „liga", choć oznaczają istotne koncepcje dziedziny aplikacyjnej, używane są bez
wyjaśnienia ich znaczenia. W świecie gier stosowane są w różnych kontekstach, aby więc
uniknąć późniejszych komplikacji związanych z tym faktem, konieczny jest precyzyjny opis
ich znaczenia — i od niego właśnie zaczniemy budowanie wspomnianego słownika, którego
zaczątek widoczny jest w tabeli 4.10.
Gdy tylko programiści porozumieją się z klientem co do zakresu funkcjonalnego
systemu, formalizują zdobytą wiedzę w postaci wysokopoziomowych przypadków użycia.
Tabela 4.10. Początkowa postać słownika roboczego dla systemu ARENA. Sprawowanie kontroli nad
kluczową terminologią i jej definicjami gwarantuje spójność specyfikacji oraz daje pewność, że pro-
gramiści będą porozumiewać się z klientem w jego języku
i d e n t y f i k u j e m y k o l e j n e g o a k t o r a — Anonymous, r e p r e z e n t u j ą c e g o p o t e n c j a l n e g o u ż y t k o w n i k a ,
k t ó r y n i e p o s i a d a jeszcze k o n t a w systemie ARENA. P o d o b n i e r o z d z i e l a m y f u n k c j o n a l n o ś ć , zwią-
z a n ą z o g l ą d a n i e m byłych m e c z ó w o r a z z z a r z ą d z a n i e m p r o f i l a m i u ż y t k o w n i k ó w , m i ę d z y d w a
k o l e j n e p r z y p a d k i użycia: B r o w s e T o u r n a m e n t H i s t o r y i M a n a g e O w n P r o f i l e , i n i c j o w a n e p r z e z
a k t o r ó w ( o d p o w i e d n i o ) S p e c t a t o r i PI a y e r . W r e s z c i e , w celu dalszego s k r ó c e n i a p r z y p a d k u
użycia Organ i z e T o u r n a m e n t , w y d z i e l a m y p r z y p a d e k użycia D e f i neLeague, w r a m a c h k t ó r e g o
a k t o r i n i c j u j ą c y LeagueOwner m o ż e o r g a n i z o w a ć wiele t u r n i e j ó w , z g o d n i e z r e g u ł a m i swej ligi.
P r z e w i d u j ą c , że instalacja n o w y c h gier i d e f i n i o w a n i e n o w y c h stylów t u r n i e j u w y m a g a ć będzie
5.6. Analiza przypadku — system AREIMA 197
Aby zbytnio nie komplikować naszego opisu, nie przedstawimy tu kompletnego pro-
cesu uszczegółowiania; ograniczymy się do jednego szczególowego przypadku użycia dla każ-
dego z kroków wysokopoziomowego przypadku użycia Organi zeTournament i w rezultacie
otrzymamy diagram przedstawiony na rysunku 4.10. Następnie zajmiemy się przypadkiem
użycia AnnounceTournament, przedstawionym w tabeli 4.13 oraz związanymi z nim sytuacja-
mi wyjątkowymi, zobrazowanymi schematycznie na rysunku 4.11. Doskonalenie pozostałych
przypadków użycia odbywać się będzie w podobny sposób.
Na rysunku 4.10 wszystkie przypadki użycia inicjowane są przez aktora LeagueOwner,
z wyjątkiem przypadków ApplyForTournament i PI ayMatch inicjowanych przez aktora gracza
(PI ayer). Reklamodawca (Adverti ser) uczestniczy w przypadku użycia AnnounceTournament,
zaś kibic (Spectator) bierze udział w przypadkach AnnounceTournament i PI ayMatch. Gracz
(Player) uczestniczy we wszystkich przypadkach użycia stanowiących udoskonalenie
przypadku Organi zeTournament. By nie zaciemniać czytelności i tak już skomplikowanego
diagramu, zrezygnowaliśmy z jawnego przedstawienia relacji « i n i t i a t e s wiążącej aktora
LeagueOwner z uszczegółowionymi przypadkami użycia; używając narzędzi UML, musimy
jednak pamiętać o ich uwzględnieniu. W tabeli 4.13 widoczny jest kolejny szczegółowy
przypadek użycia — AnnounceTournament.
200 Rozdział 4. • Zbieranie wymagań
Rysunek 4.10. Szczegółowy przypadek użycia jako efekt udoskonalenia przypadku Organi zeTournament
Powyższe decyzje stanowią efekty uzgodnień z klientem, co jest o tyle istotne, że różni
klienci, funkcjonujący w różnych realiach, mogą odmiennie rozstrzygać rozmaite kompromisy
między sprzecznymi wymaganiami. Przykładowo pełna automatyzacja obsługi sponsoringu,
wraz z bezpiecznym uwierzytelnianiem, skutkuje systemem bardziej złożonym, więc droższym.
Tańszą alternatywą może być wybór sponsorów za pomocą e-maili, lecz odbieranie ich zobo-
wiązań drogą telefoniczną: system będzie wówczas prostszy, bardziej złożone stają się nato-
miast działania kapitana ligi. Przy rozstrzyganiu takich dylematów decydujący głos ma klient,
zdający sobie — oczywiście — sprawę z wpływu podjętej decyzji na koszt realizacji i termin
dostarczenia systemu.
Z każdym przypadkiem użycia wiążą się określone sytuacje wyjątkowe, które można zi-
dentyfikować, analizując każdy krok z właściwą podejrzliwością. Opiszemy krótko sytuacje
wyjątkowe, jakie mogą wystąpić w związku z przypadkiem użycia AnnounceTournament, który
tym samym rozszerzony zostaje (w sensie relacji «extend») o przypadki użycia reprezentujące
owe sytuacje (patrz rysunek 4.11 i tabela 4.14).
Zwróćmy uwagę, że nie wszystkie z opisanych sytuacji są do siebie podobne — ich
zróżnicowane typy predestynują je do rozwiązywania w różnych fazach realizacji projektu.
Są zatem wśród nich wyjątki spowodowane wyczerpaniem zasobów (MaxNumberOfTournaments
^•Exceeded), błędnymi danymi wejściowymi (Inval idDate, NamelnUse) i ograniczeniami
z zakresu dziedziny aplikacyjnej (Adverti serCredi tExceeded, NoMatchi ngSponsorFound).
Obsługę wyjątków związanych z zasobami najlepiej załatwia się na etapie projektu systemu,
dopiero wówczas bowiem wiadome jest, które z zasobów podlegają jakim ograniczeniom i jak
najefektywniej rozdzielać je między użytkowników. Poprawność wprowadzanych danych to
z kolei kwestia interfejsu użytkownika — programiści decydują o tym, w którym momencie
przeprowadzać kontrolę wprowadzonych danych, w jakiej postaci wyświetlać związane z tym
5.6. Analiza przypadku — system AREIMA 203
4.6.6. Wnioski
W tej sekcji opracowaliśmy kilka przypadków użycia i stworzyliśmy zaczątki obiektowego
modelu analitycznego, bazowaliśmy przy tym na deklaracji problemu dostarczonej przez klienta.
Scenariusze i pytania zadawane klientowi posłużyły jako narzędzia do wyjaśniania wątpliwości
i niejednoznaczności oraz wykrywania brakującej informacji. Zebraliśmy także kilka wymagań
pozafunkcyjnych. Na tej podstawie możemy już wyciągnąć kilka ważnych wniosków. Oto one.
Tabela 4.15. Skonsolidowana lista wymagań pozafunkcyjnych dla systemu ARENA, jako pochodna
pierwszej szczegółowej wersji przypadku użycia AnnounceTournament
Użyteczność • Kibice muszą mieć możliwość obserwowania postępu meczu, bez konieczności
uprzedniej rejestracji i bez uprzedniej znajomości rozgrywanych turniejów.
• Z b i e r a n i e w y m a g a ń o d b y w a się p r z y z n a c z ą c y m z a a n g a ż o w a n i u k l i e n t a .
• P r o g r a m i ś c i n i e p o w i n n i n i g d y z a k ł a d a ć , że d o k ł a d n i e z n a j ą p o t r z e b y k l i e n t a .
4.8. Ćwiczenia
4.1. Potraktuj swój zegarek jako system i skoryguj wyświedany czas o 2 minuty w przód.
Opisz każdą swoją interakcję z zegarkiem w postaci scenariusza. Uwzględnij wszystkie
interakcje, również te w postaci informacji zwrotnej przekazywanej przez zegarek.
4.2. W scenariuszu stworzonym w zadaniu 4.1 zidentyfikuj aktorów. Następnie utwórz
odpowiedni przypadek użycia SetTime. Uwzględnij wszystkie możliwe sytuacje: ko-
rygowanie czasu w przód i w tył, korygowanie godzin, minut i sekund.
4.3. Załóżmy, że zegarek, o którym mowa w ćwiczeniach 4.1 i 4.2, wyposażony jest w bu-
dzik. Opisz ustawianie alarmu jako niezależny przypadek użycia SetAl armTime.
4.4. Przeanalizuj dokładnie przypadki użycia SetTime i SetAl armTime z ćwiczeń 4.2 i 4.3.
Wyeliminuj z nich ewentualną redundancję za pomocą relacji zawierania. Wyjaśnij,
dlaczego relacja zawierania jest w tym przypadku bardziej odpowiednia niż relacja
rozszerzania.
4.5. Załóżmy, że Fi el dOf f i cer ma do dyspozycji system pomocy online, który dostarcza
szczegółowy opis każdego pola oraz wykaz pól obowiązkowo wypełnianych na for-
mularzu raportu o wypadku (EmergencyReport). Stwórz przypadek użycia Hel pReport
^-Emergency reprezentujący tę funkcjonalność, a następnie zmodyfikuj odpowiednio
przypadek użycia ReportEmergency (opisany w tabeli 4.5). Jakiej relacji użyjesz do
powiązania obu przypadków?
4.6. Które z poniższych wymagań pozafunkcyjnych są weryfikowalne, a które nie?
• „System musi być użyteczny",
o „System musi w sposób widoczny zareagować na akcję użytkownika w ciągu jednej
sekundy od wydania polecenia",
« „Dostępność systemu musi kształtować się na poziomie ponad 95%",
® „Interfejs użytkownika w nowym systemie musi być na tyle podobny do interfejsu
starego systemu, by użytkownik znający stary system mógł łatwo nauczyć się
obsługi nowego".
4.7. Potrzeba stworzenia kompletnej specyfikacji może zachęcać analityków do budowania
obszernych i szczegółowych dokumentów. Które z cech wymienionych w tabeli 4.1
mogą skłaniać analityków do tworzenia krótszych specyfikacji?
4.8. Utrzymywanie identyfikowalności w czasie zbierania wymagań i następnych ak-
tywności jest kosztowną procedurą, bowiem konieczne jest zbieranie i przetwarzanie
dodatkowych informacji. Jakie korzyści płynące z identyfikowalności usprawiedli-
wiają ten dodatkowy nakład pracy? Które z tych korzyści są bezpośrednio widoczne
dla analityka?
208 Rozdział 4. • Zbieranie wymagań
Bibliografia
[Bruegge i in., 1994] B. Bruegge, K. O'Toole, D. Rothenberger „Design considerations
for an accident management system," w: M. Brodie, M. Jarke,
M. Papazoglou (red.), Proceedings of the Second International
Conference on Cooperative Information Systems, str. 90 - 100,
University of Toronto Press, Toronto, Canada, m a j 1994.
[Carroll, 1995] J. M. Carroll (red.) Scenario-Based Design: Envisioning Work
and Technology in System Development, Wiley, New York, 1995.
[Chung i in., 1999] L. Chung, B. A. Nixon, E. Yu, J. Mylopoulos Non-Functional
Requirements in Software Engineering, Kluwer Academic, Boston, 1999.
[Cockburn, 2001] A. Cockburn Writing Effective Use Cases, Addison-Wesley, Reading,
MA, 2001.
[Constantine i Lockwood, 1999] L. L. Constantine, L. A. D. Lockwood Software for Use, Addison-Wesley,
Reading, MA, 1999.
[Grady, 1992] R. Grady Practical Software Metrics for Project Management and
Process Improvement, Prentice Hall, Englewood Cliffs, NJ, 1992.
Bibliografia 209
' Oczywiście, dzień tygodnia da się obliczyć na podstawie aktualnej daty za pomocą prostego algorytmu
(jeden z licznych przykładów: http://www.mimuw.edu.pl/delta/artykuly/delta2010-03/2010-03-tydzien.pdf),
który — włączony do oprogramowania zegarka — całkowicie oddziela użytkownika od bezpośredniego
manipulowania tą częścią wyświetlanej daty. Teoretycznie można sobie jednak wyobrazić prymitywny
zegarek, w którym początkowe ustawienie, dokonane przez użytkownika, inkrementowane jest (cy-
klicznie) z upływem każdej doby — przyp. tłum.
212 Rozdział 4. •Zbieraniewymagań
A gdyby rysunek 5.1 był specyfikacją wymagań, jaki model — wazonu czy konwersacji tete
a tete — należałoby zbudować na jej podstawie? Typowa specyfikacja wymagań początkowo ma
w sobie coś na kształt takiego właśnie rysunku, co jest konsekwencją zarówno nieprecyzyjnej
natury języka naturalnego (w nim formułowane są wymagania), jak i ukrytych założeń, niejawnie
(i czasami nieświadomie) przyjmowanych przez autorów tejże specyfikacji. Kilka tego przykła-
dów opisaliśmy już na początku poprzedniego rozdziału, sami też często popełniamy błędy tego
rodzaju, na przykład podając znajomym z odległego kraju nasz numer telefonu bez prefiksu +48.
Proces formalizowania wymagań ma na celu wykrycie takich właśnie przeoczeń, wielo-
znaczności i innych uchybień w specyfikacjach, które to uchybienia rozstrzygane są następnie
w drodze konsultacji z klientem dostarczającym dodatkowych informacji. W taki oto sposób
aktywności zbierania wymagań i ich analizowania sukcesywnie przeplatają się ze sobą.
Rysunek 5.3. Model analityczny jako złożenie modelu funkcjonalnego, analitycznego modelu obiekto-
wego i modelu dynamicznego. W języku UML model funkcjonalny reprezentowany jest w postaci
diagramów przypadków użycia, model obiektowy — w postaci diagramów klas, a model dynamiczny
— w postaci diagramów sekwencji i diagramów stanów
czy Network (sieć) nie powinny w ogóle pojawić się w modelu analitycznym z tego prostego
względu, że użytkownikowi mogą być zupełnie obce koncepcje reprezentowane przez te klasy.
Notabene nie zmienia to w niczym faktu, że większość klas występujących w modelu anali-
tycznym ma swe odzwierciedlenie w postaci klas języka programowania używanego do imple-
mentacji systemu, jednak klasy tej drugiej grupy posiadają zazwyczaj więcej atrybutów i uwi-
kłane są w bogatszy układ interakcji niż ich pierwowzory. W konsekwencji klasy modelu
analitycznego mogą być uważane za wysokopoziomowe abstrakcje, których ukonkretnienie
odbywać się będzie w dalszych stadiach projektu.
Na rysunku 5.4 widzimy przykład dobrego i złego wyboru klas dla modelu analitycznego
reprezentującego przykładowy zegarek SatWatch.
Rysunek 5.4. Przykłady i kontrprzykłady wyboru klas dla modelu analitycznego zegarka SatWatch
Rysunek 5.6. Przykład generalizowania koncepcji: w korzeniu drzewa reprezentowana jest koncep-
cja najbardziej ogólna, w jego liściach koncepcje najbardziej szczegółowe
• Modelowanie interakcji między obiektami za pomocą kart CRC (patrz sekcja 5.4.5),
• Identyfikację skojarzeń (patrz sekcja 5.4.6),
• Identyfikację agregacji (patrz sekcja 5.4.7),
• Identyfikację atrybutów (patrz sekcja 5.4.8),
• Modelowanie zachowania poszczególnych obiektów uzależnionego od ich stanu
(patrz sekcja 5.4.9),
• Modelowanie relacji dziedziczenia między obiektami (patrz sekcja 5.4.10),
• Przeglądy modelu analitycznego (patrz sekcja 5.4.11).
Analiza opisu przypadków użycia w języku naturalnym ma tę zaletę, iż język ten odzwier-
ciedla świat widziany z perspektywy użytkownika. Ma ona jednak wiele ograniczeń, z których
najważniejsze są dwa. Po pierwsze, jakość wynikowego modelu w dużej mierze zależy od stylu
pisarskiego analityka (spójności używanej terminologii, transformacji między częściami mowy
i tym podobnych). Języka naturalny jest bardzo nieprecyzyjnym narzędziem i model tworzenie
modelu obiektowego literalnie na bazie nieprecyzyjnego opisu niesie ze sobą ryzyko, iż model
ten będzie równie nieprecyzyjny. Programiści starają się unikać tego ryzyka poprzez odpo-
wiednie przeredagowywanie specyfikacji wymagań w taki sposób, by używana w niej termi-
nologia była w jak najwyższym stopniu zestandaryzowana. Drugi mankament wynika z bo-
gactwa i redundancji samego języka naturalnego: liczba rzeczowników jest znacznie większa
od liczby rzeczy identyfikowanych przez te rzeczowniki. Na określenie danego przedmiotu,
koncepcji, zjawiska i tak dalej istnieje zwykle wiele synonimów; zidentyfikowanie, sortowanie
i utożsamianie owych synonimów w obszernej specyfikacji wymagań jest procesem niezwykle
pracochłonnym. Dlatego heurystyki Abbotta nadają się raczej do wstępnego określenia
obiektów kandydatów na rzeczywiste obiekty modelu na podstawie krótkich opisów, na przy-
kład opisów przepływu zdarzeń w scenariuszach i przypadkach użycia. W uzupełnieniu do heu-
rystyk Abbotta można polecić kilka następujących:
220 Rozdział 4. •Zbieraniewymagań
Programiści przyporządkowują obiektom nazwy i krótkie opisy, określają też ich atry-
buty i znaczenie każdego z nich. Używanie unikalnych nazw dla obiektów przyczynia się do
promowania standardowej terminologii. Dla obiektów encji zalecamy bezwzględnie wykorzy-
stywanie nazw, którymi posługują się użytkownicy i specjaliści z dziedziny aplikacyjnej; opisy
obiektów, nawet krótkie, pozwalają programistom na wyjaśnienie koncepcji reprezentowanej
przez te obiekty i unikanie nieporozumień (wynikających na przykład z używania tego samego
obiektu do reprezentowania koncepcji powiązanych ze sobą, choć całkowicie różnych). Pro-
gramiści nie powinni jednak ustalać nadmiernej szczegółowości obiektów zbyt wcześnie, gdy
proces analizy jest jeszcze tak naprawdę w stadium nieustalonym: powinni oni dokumentować
te atrybuty i koncepcje, które nie są oczywiste; dla pozostałych obiektów wystarczające okażą
się nazwy (być może tymczasowe) i treściwe opisy. Potrzebne będzie jeszcze wiele iteracji,
w ramach których zmieniać się będą zarówno funkcje realizowane przez poszczególne obiekty,
jak i prawdopodobnie nazwy tychże obiektów. Gdy jednak model analityczny stanie się już
stabilny, opis każdego obiektu powinien być tak szczegółowy, jak tylko jest to konieczne
(powrócimy do tej kwestii w sekcji 5.4.11).
I tak na przykład w przypadku użycia prezentowanym w tabeli 5.2 wykorzystaliśmy
wiedzę z zakresu dziedziny aplikacyjnej i wywiady z użytkownikami do identyfikacji klas
Dispatcher, EmergencyReport, F i e l d O f f i c e r i Incident. Zauważmy przy tym, że obiekt
klasy EmergencyReport nie jest nigdzie przywoływany explicite przez nazwę, a jedynie w formie
opisowej („otrzymane od Fi el dOf f i cera informacje zawarte w formularzu"); po konsultacjach
z klientem dowiadujemy się, że taka informacja nazywana jest potocznie „raportem o niebez-
pieczeństwie" (emergency report) i decydujemy się na reprezentowanie jej w postaci stosow-
nego obiektu, którego klasę nazywamy EmergencyReport.
Zebrana w ten sposób wiedza prowadzi do początkowej postaci modelu analitycznego,
którego obiekty encji przedstawiamy w tabeli 5.3 Zauważmy, że modelowi temu bardzo daleko
do kompletnego opisu systemu implementującego przypadek użycia ReportEmergency.
W następnej sekcji zajmiemy się obiektami brzegowymi przypadku użycia Report
^-Emergency.
Heurystyki p o m o c n e w identyfikowaniu o b i e k t ó w b r z e g o w y c h
Zwróćmy uwagę, że obiekt Inci dentForm nie występuje jawnie w przypadku użycia
ReportEmergency. Zidentyfikowaliśmy jego istnienie, uświadamiając sobie, że Dispatcher
potrzebuje odpowiedniego interfejsu do przeglądania raportu przysłanego przez Fi el dOffi cera
i do odesłania mu potwierdzenia. Zauważmy także, iż nazwa tego obiektu odzwierciedla wy-
łącznie jego funkcję, abstrahując od konkretnej realizacji — ta stanowi bowiem część dziedziny
realizacyjnej, o której nie da się po prostu rozmawiać wyłącznie językiem użytkownika.
Identyfikując obiekty encji i obiekty brzegowe, dokonaliśmy pewnego postępu w opisy-
waniu przyszłego systemu — dysponujemy już bowiem zdefiniowanym interfejsem między
aktorami a systemem. Nie dysponujemy jednak jeszcze innymi istotnymi informacjami, ta-
kimi jak na przykład kolejność, w jakiej następują poszczególne interakcje aktorów z systemem.
Zajmijmy się więc trzecią kategorią obiektów odpowiedzialnych za ten i wiele innych aspek-
tów systemu — obiektami sterującymi.
Rysunek 5.8. Diagram sekwencji dla przypadku użycia ReportEmergency (kontynuacja rysunku 5.7)
Rysunek 5.9. Diagram sekwencji dla przypadku użycia ReportEmergency (kontynuacja rysunku 5.8)
Przepływ zdarzeń 2. System FRI END wyświetla w odpowiedzi stosowny formularz. Formularz
ten zawiera pola określające między innymi rodzaj niebezpieczeństwa
(ogólne, pożar, komunikacyjne), lokalizację zdarzenia, jego opis, żądanie
zasobów i udział materiałów niebezpiecznych.
Karty indeksowe przydają się w zespołowych sesjach modelowania. W trakcie takiej sesji,
w której uczestniczą zwykle programiści i eksperci z dziedziny aplikacyjnej, analizowany jest
scenariusz i identyfikowane są kolejne klasy biorące w nim udział; dla każdej nowo ziden-
tyfikowanej klasy na tablicy pojawia się nowa karta indeksowa. Dla każdej klasy negocjo-
wany jest zakres odpowiedzialności, identyfikowane są też zależności od pozostałych klas.
Karty mogą być modyfikowane lub nawet usuwane na bok tablicy jako nieaktualne; nie są
jednak z tablicy usuwane, mogą bowiem za chwilę znowu okazać się przydatne, gdy pojawią
się nowe pomysły.
Karty CRC i diagramy sekwencji to dwie różne metody opisywania tych samych aktyw-
ności. Diagramy bardziej nadają się do modelowania w pojedynkę oraz dla celów dokumenta-
cyjnych, gdyż są bardziej precyzyjne i bardziej zwarte; karty CRC sprawdzają się natomiast
lepiej w grupowym („burza mózgów") budowaniu i ulepszaniu struktury obiektowej przypad-
ków użycia, ponieważ łatwiej je tworzyć i modyfikować.
• nazwę związaną z jego charakterem (sporządza na rysunku 5.11); jest ona opcjo-
nalna i nie musi być globalnie unikalna;
• role identyfikujące funkcje każdego z uczestników skojarzenia (autor i dokument na
rysunku 5.11);
• krotność precyzującą dopuszczalną liczbę instancji klas po każdej ze stron skojarze-
nia (gwiazdka na rysunku 5.11 oznacza, że funkcjonariusz ( F i e l d O f f i c e r ) może
sporządzić dowolną liczbę raportów (EmergencyReport) lub nie sporządzić żadnego;
liczba 1 oznacza natomiast, że każdy raport ma dokładnie jednego autora).
Początkowo model może zawierać nadmiar skojarzeń, jeśli programiści zastosują się do
heurystyk opisywanych w tabeli 5.1; przykładowo w diagramie na rysunku 5.12 klasa repre-
zentująca wypadek (Incident) uwikłana jest w dwa skojarzenia: z raportem (EmergrncyReport)
— ponieważ zaistnienie wypadku skutkuje utworzeniem raportu — i z funkcjonariuszem
(Fi el dOffi cer), który wypadek raportuje. Drugie z tych skojarzeń jest jednak redundantne,
wynika bowiem z dwóch pozostałych — nie ma potrzeby jego reprezentowania explicite.
Utrzymywanie zbędnych skojarzeń ma niekorzystny wpływa na model, bo wprowadza do
niego redundancję i utrudnia jego zrozumienie.
2
Kwalifikowanie skojarzeń autorzy opisują w sekcji 2.4.2 — pTzyp. tłum.
5.4. Aktywności analizy wymagań: od przypadków użycia do obiektów 231
3
Różnicę między agregacją a skojarzeniem „jeden na wiele" w ogólności autorzy wyjaśniają w sekcji
2.4.2 — przyp. tłum.
232 Rozdział 4. •Zbieraniewymagań
4
Na podstawie pracy ]. Rumbaugha, M. Błahy, W. Premerlaniego, F. Eddyego, W. Lorensena [Rumbaugh
i in., 1991].
234 Rozdział 4. •Zbieraniewymagań
w którym większość zmian będzie mieć charakter kosmetyczny, należy przystąpić do następ-
nego etapu — projektowania systemu. W procesie zbierania wymagań przychodzi taki mo-
ment, że nie sposób już przewidzieć kolejnych problemów bez prototypowania, analizy uży-
teczności, przeglądu dostępnych technologii czy (właśnie) projektowania systemu. Dążenie do
nadmiernej szczegółowości może stać się syzyfową pracą, bowiem niektóre ze szczegółów przy
następnej zmianie mogą okazać się nieaktualne. Menedżer projektu powinien rozpoznać ten
moment i zarządzić przejście do następnej fazy realizacji.
W punkcie 3.4.3 dokumentu RAD opisane są szczegółowo wszystkie obiekty, ich atry-
buty i operacje (na diagramach sekwencji). Każdy obiekt opisywany jest w postaci tekstowej,
natomiast relacje między obiektami uwidaczniane są na diagramach klas.
W punkcie 3.4.4 udokumentowane jest zachowanie obiektów modelu w kategoriach dia-
gramów stanów i diagramów sekwencji. Jakkolwiek informacja ta jest redundantna z modelem
przypadków użycia, modele dynamiczne umożliwiają bardziej precyzyjne opisywanie skom-
plikowanych zachowań, między innymi przypadków użycia angażujących wielu aktorów.
4.5. Zarządzaniez b i e r a n i e mwymagań 239
• Wyraźne określenie granic. Definiowanie ról, opisane w sekcji 5.5.2, jest częścią tego
procesu, który obejmuje także zdefiniowanie granic prywatności informacji: przykła-
dowo każdy zespół ma do dyspozycji własne, wewnętrzne forum dyskusyjne, niewi-
doczne dla klienta, z którym dyskusja odbywa się w ramach zupełnie innego forum
(opisywaliśmy to w rozdziale 3. „Organizacja projektu i komunikacja"). Na zasadzie
wzajemności — programiści nie powinni ingerować w wewnętrzną politykę klienta
i użytkowników.
• Wyraźne zdefiniowanie celów oraz kryteriów powodzenia. Wspólne definiowanie
czytelnych, mierzalnych i weryfikowalnych celów oraz kryteriów powodzenia przy-
czynia się do łagodzenia konfliktów między programistami a klientem. Czytelne
zdefiniowanie weryfikowalnego celu nie jest zadaniem banalnym, gdy weźmie się pod
uwagę tendencję do pozostawiania definicji celów w stanie mało precyzyjnym. Cele
i kryteria powodzenia powinny być opisane w punkcie 1.3 dokumentu RAD.
• Burza mózgów. Szybkie proponowanie rozmaitych rozwiązań podczas zebrania
wszystkich uczestników projektu w jednym pomieszczeniu sprzyja przełamywaniu
barier komunikacyjnych. Podobny efekt dać mogą przeglądy produktów docelowych
dokonywane wspólnie przez klienta i programistów w czasie tej samej sesji.
Burza mózgów
Ustalanie
Dojrzewanie
• Czy dotyczą zasadniczej funkcjonalności systemu, czy też jego opcjonalnych funkcji?
• Jakie są ich konsekwencje dla spójności i niezawodności systemu? Dla interfejsu
systemu?
Gdy wspomniane zmiany okazują się uzasadnione, klient i programiści definiują ich
zakres, ich oczekiwany efekt i przystępują do modyfikowania modelu analitycznego. Gdy
model ten jest kompletny, wprowadzanie do niego nowych elementów funkcjonalnych jest
łatwiejsze, choć trudniejsza staje się wtedy ich implementacja.
• listę priorytetów,
• proces rewizji dokumentu,
• listę kryteriów zaakceptowania lub odrzucenia gotowego systemu,
• harmonogram i budżet.
o pośredni priorytet — funkcje tej grupy muszą zostać wzięte pod uwagę w czasie projektowania
systemu i projektowania obiektów, ich prezentacja przewidywana jest w trakcie drugiej iteracji
tworzenia systemu,
° niski priorytet — funkcje tej grupy stanowią ilustrację możliwości zarządzania systemu w dłuższej
perspektywie.
Podpisane przez klienta wymagania uzyskują status linii bazowej i mogą zostać wyko-
rzystane do dokładniejszego oszacowania kosztów projektu. Oczywiście, nie oznacza to końca
zmian w samych wymaganiach, lecz odtąd każda z tych zmian dokonywana będzie w ramach
formalnego procesu rewizji. Nieuchronność tych zmian wynika z błędów, przeoczeń, zmian
244 Rozdział 4. •Zbieraniewymagań
Nazwa AnnounceTournament
W tabeli 5.9 prezentujemy listę obiektów encji, ich atrybutów oraz skojarzeń między
ich klasami zidentyfikowanych dotychczas na podstawie opisu przypadku użycia Announce
"-•Tournament. Dokonaliśmy przyporządkowania rozpoznanych atrybutów i skojarzeń do
odpowiednich klas, zdefiniowaliśmy też nowe klasy. Każdą klasę opatrzyliśmy także opisem
słownym, głównie z dwóch powodów. Po pierwsze, sama nazwa klasy nie jest na tyle specyficzna,
by jednoznacznie wskazywać wszystkim uczestnikom koncepcję, którą klasa ta reprezentuje
248 Rozdział 4. •Zbieraniewymagań
— wyrazy „mecz" (Match) czy „gra" (Game) używane są w różnych kontekstach w znaczeniu
potocznym; w systemie ARENA reprezentują one jednak ściśle zdeterminowane koncepcje: i tak
„gra" to zestaw reguł, których zachowanie wymuszane jest przez odpowiedni fragment opro-
gramowania, a „mecz" to rozgrywka między graczami (PI ayer). Po drugie, obiekty zidentyfi-
kowane na etapie analizy odpowiadają także terminom zawartym w słowniku, którego tworze-
nie rozpoczęliśmy na etapie zbierania wymagań; uczestnicy wykorzystują ów słownik w celu
rozwiązywania niejasności i ustanowienia standardowej terminologii, zatem krótka definicja
znaczenia każdej z klas jest znakomitym środkiem do zapobiegania wieloznacznościom i nie-
porozumieniom. Odłożenie „na później" tych definicji stwarzałoby ryzyko utraty informacji,
prowadzącej w konsekwencji do ich niekompletności.
Identyfikowanie obiektów encji i ich atrybutów rzadko jest oczywiste i zwykle rodzi serię
dodatkowych pytań pod adresem klienta. Przykładowo, gdy rozpoznajemy implikowane atry-
buty i skojarzenia, powinniśmy się solidnie zastanowić wraz z klientem, czy intuicja nie zwiodła
nas na manowce — może się bowiem okazać, że strony skojarzenia nie są określone jedno-
znacznie. Poniżej widzimy przykładowy zestaw pytań, związanych z obiektami encji uczestni-
czącymi w przypadku użycia AnnounceTournament.
250 Rozdział 4. •Zbieraniewymagań
• Czy reklamodawcy mogą wyrażać chęć wyłącznego sponsorowania wybranych lig, czy jedynie
chęć uczestniczenia w sponsoringu na arenie?
• Czy reklamodawcy p o w i n n i przyporządkowywać swe b a n e r y do określonych gier,
w celu ich trafniejszego losowego wyboru przez system, w sytuacji gdy nie ma
wyłącznego sponsora?
• Czy zryczałtowana opłata za wyłączny sponsoring powinna być stała w danej instancji
systemu, czy też zróżnicowana dla poszczególnych lig i (lub) turniejów?
• Jak można się zareklamować przy okazji nowego turnieju, jeśli brakuje grup
zainteresowanych tym turniejem?
® W jaki sposób użytkownicy powinni być powiadamiani o zdarzeniach (przez e-mail, telefon
komórkowy czy dedykowaną skrzynkę osobistą w systemie ARENA)?
5.6. Analiza przypadku — system AREIMA 251
Rysunek 5.19. Diagram sekwencji UML dla przypadku użycia AnnounceTournament, część odpowie-
dzialna za organizację nowego turnieju
5.6. Analiza przypadku — system AREIMA 253
Rysunek 5.20. Diagram sekwencji UML dla przypadku użycia AnnounceTournament, część odpowie-
dzialna za sponsoring
Rysunek 5.21. Diagram sekwencji UML dla przypadku użycia AnnounceTournament, część odpowie-
dzialna za powiadamianie zainteresowanych grup
Rysunek 5.22. Obiekty encji zidentyfikowane na podstawie analizy przypadku użycia Announce
^Tournament
Kolejny nasz diagram klas (ten z rysunku 5.23) uwidacznia relacje dziedziczenia między
poszczególnymi klasami. Jakkolwiek język UML umożliwia reprezentowanie skojarzeń i relacji
dziedziczenia na tym samym diagramie klas, zalecaną praktyką jest rysowanie dwóch odręb-
nych diagramów. Powody tego są dwa: po pierwsze, skojarzenia i dziedziczenie reprezento-
wane są za pomocą podobnych symboli, które łatwo pomylić ze sobą, po drugie — skojarzenia
między klasami i hierarchia klas to zagadnienia, którymi analitycy zajmują się w różnym
czasie; jak jednak zobaczymy w następnych czterech rozdziałach, nie jest to prawda na etapie
projektowania systemu i projektowania obiektów, kiedy to często konieczne jest uwzględnianie
obu relacji dla lepszego zrozumienia powiązań między klasami.
Na rysunku 5.30 widoczne są trzy hierarchie dziedziczenia. Pierwsza z nich rozpoczyna
się od abstrakcyjnej klasy User, zdefiniowanej w wyniku generalizacji i reprezentującej (w po-
staci odpowiednich atrybutów) własności wspólne dla wszystkich użytkowników, takie jak
informacje kontaktowe i procedury rejestracyjne. Zauważmy przy tym, że terminu „użytkow-
nik" (user) używaliśmy już wielokrotnie w deklaracji problemu i w przypadkach użycia, tak
więc dokonujemy teraz formalizacji terminu stosowanego dotąd w znaczeniu intuicyjnym.
Dwie pozostałe hierarchie są wynikiem specjalizacji Idas Game i TournamentStyle, reprezen-
tujących koncepcje (odpowiednio) gry i stylu rozgrywek. Klasy Ti cTacToe i Chess, stanowiące
wynik specjalizowania klasy Game, odpowiadają (kolejno) grze w kółko i krzyżyk oraz szachom.
256 Rozdział 4. •Zbieraniewymagań
Rysunek 5.23. Hierarchia dziedziczenia między klasami obiektów encji przypadku użycia Announce
^Tournament
5.6.6. Wnioski
W tej sekcji stworzyliśmy część analitycznego modelu obiektowego, odpowiadającą przy-
padkowi użycia AnnounceTournament w systemie ARENA. Rozpoczęliśmy od zidentyfikowania
obiektów encji, wykorzystując heurystyki Abbotta, po czym zidentyfikowaliśmy obiekty brze-
gowe i obiekt sterujący, by następnie za pomocą diagramów sekwencji odnaleźć dodatkowe
5.6. Analiza przypadku — system AREIMA 257
Rysunek 5.24. Skojarzenia między obiektami brzegowymi, obiektem sterującym i wybranymi obiektami
encji przypadku użycia AnnounceTournament
5.8. Ćwiczenia
5.1. Rozpatrzmy system plików z graficznym systemem użytkownika, na przykład
Windows Explorer, Finder Macintosha czy linuksowy KDE. W przypadku użycia
opisującym kopiowanie pliku z dyskietki na dysk twardy zidentyfikowano następujące
obiekty: Fi 1 e (plik), Icon (ikona), TrashCan (kosz), Fol der, Di sk, Poi nter (wskaźnik).
Które z nich są obiektami encji, które brzegowymi, a które sterującymi?
5.2. W systemie wspomnianym w ćwiczeniu 5.1 rozpatrzmy scenariusz obejmujący wy-
bór pliku (File) na dyskietce, przeciągnięcie myszą wybranej pozycji do folderu
(Folder) i zwolnienie lewego przycisku myszy. Zidentyfikuj i zdefiniuj choć jeden
obiekt sterujący uczestniczący w tym scenariuszu.
5.3. Zorganizuj obiekty, o których mowa w ćwiczeniach 5.1 i 5.2, w poziomą strukturę
typową dla diagramu sekwencji: począwszy od lewej, najpierw obiekty brzegowe,
potem sterujące i na końcu obiekty encji. Narysuj sekwencję interakcji prowadzącą
do upuszczenia wybranego pliku w folderze docelowym. Zignoruj możliwe sytuacje
wyjątkowe.
5.4. Przeanalizuj diagram sekwencji utworzony w ćwiczeniu 5.3 i zidentyfikuj skojarzenia
między obiektami.
5.8. Ćwiczenia 259
5.7. Czy operując jedynie krotnościami skojarzeń, możesz tak zmodyfikować model wi-
doczny na rysunku 5.25, by programista nieobeznany z kalendarzem gregoriańskim
potrafił wydedukować liczbę dni w każdym miesiącu? Zidentyfikuj ewentualne do-
datkowe klasy potrzebne do wykonania tego zadania.
5.8. Rozpatrz system sygnalizacji świetinej na skrzyżowaniu dwóch dróg dwukierunko-
wych. Zakładając najprostszy algorytm sterowania ruchem (dopuszczenie do ruchu
na jednej z dróg, przy jednoczesnym zablokowaniu ruchu w kierunku prostopadłym,
z cyldiczną zmianą), zidentyfikuj stany tego systemu i narysuj diagram stanów ilu-
strujący jego funkcjonowanie. Dla każdego sygnalizatora zakładamy trzy stany, od-
powiadające światłom: zielonemu, żółtemu i czerwonemu.
5.9. Narysuj diagram Was odpowiadający diagramowi sekwencji z rysunku 2.29. Wska-
zówka: Rozpocznij od zidentyfikowania obiektów na wspomnianym diagramie.
5.10. Rozpatrz dodanie wymagania pozafunkcyjnego stanowiącego, że działania zmie-
rzające do wyłącznego sponsorowania turnieju wymagać mają jak najmniejszego
wysiłku ze strony reklamodawcy. Zmodyfikuj w związku z tym przypadki użycia
AnnounceTournament (patrz tabela 5.8) i ManageAdvertisements (rozwiązanie ćwi-
czenia 4.12), tak by reklamodawca mógł zaznaczyć w swym profilu opcję powo-
dującą, iż na otrzymane od kapitana ligi zapytanie o chęć wyłącznego sponsorowa-
nia automatycznie udzielona zostanie odpowiedź twierdząca.
260 Rozdział 4. •Zbieraniewymagań
Bibliografia
[Abbott, 1983] R. Abbott „Program design by informal English descriptions",
Communications of the ACM, t. 26, nr 11, 1983.
[Jacobson i in., 1999] I. Jacobson, G. Booch, J. Rumbaugh The Unified Software Development
Process, Addison-Wesley, Reading, MA, 1999.
Bibliografia 298
6
Projektowanie systemu
— dekompozycja
na podsystemy
Oprogramowanie można tworzyć na dwa sposoby: tak prosto,
że w oczywisty sposób będzie wolne od błędów, albo tak skomplikowanie,
że nie będzie w nim oczywistych błędów.
C. A. R. Hoare The Emperor's Old Clothes
Rysunek 6.1. Przykład projektu układu pomieszczeń w mieszkaniu. Kolejne wersje coraz lepiej reali-
zują wymaganie zmniejszenia łącznej drogi pokonywanej przez mieszkańców oraz jak najpełniejsze
wykorzystywanie światła dziennego
nr 2 — kuchnia i schody znajdują się zbyt daleko od drzwi wejściowych. W wersji nr 3 prze-
sunięcie drzwi wejściowych na ścianę północną usuwa ten problem, dodatkowo pozwalając
na zbliżenie drugiej sypialni do sypialni głównej i przesunięcie łazienki bliżej obu sypialni.
Efektem ubocznym jest powiększenie powierzchni salonu. Wszystko to odbywa się w zgodzie
z wymienionymi na wstępie ograniczeniami.
266 Rozdział 6. • Projektowanie systemu — dekompozycja na podsystemy
Mając już ustalony rozkład poszczególnych pomieszczeń, możemy zająć się lokalizacją
okien i drzwi tak, by jak najlepiej spełnione zostały wymienione wymagania. To zadanie koń-
czy projekt, bez określenia szczegółowego umeblowania poszczególnych pomieszczeń. Można
teraz przystąpić do projektowania sieci elektrycznej, wodociągowej, kanalizacyjnej i grzew-
czej budynku.
Nieprzypadkowo sięgnęliśmy po analogię architektoniczną, projektowanie domów
i mieszkań ma bowiem wiele wspólnego z inżynierią oprogramowania, co pokrótce uzasad-
niamy w tabeli 6.1. W obu przypadkach zadanie projektowania podzielone jest na prostsze
komponenty i interfejsy, w obu mamy do czynienia z wymaganiami funkcyjnymi i pozafunk-
cyjnymi, oba też niosą ze sobą jednakowo poważne konsekwencje ewentualnych pomyłek i nie-
dopatrzeń. Oba wreszcie przypadki abstrahują od szczegółowego projektu poszczególnych
komponentów.
Koncepcja inżynierii
Koncepcja architektoniczna
oprogramowania
Komponenty Pomieszczenia Podsystemy
Interfejsy Drzwi Usługi
Wymagania pozafunkcyjne Maksymalizacja powierzchni Minimalizacja czasu reakcji
mieszkalnej
Model analityczny jest opisem systemu widzianego oczami aktorów i stanowi podstawę
komunikacji między klientem a programistami. Model analityczny nie zawiera jednak informacji
na temat wewnętrznej struktury systemu, jego konfiguracji sprzętowej i, ogólnie rzecz ujmując,
6.3. Koncepcje projektowania systemu 267
sposobów jego realizacji. Pierwszym krokiem w tym kierunku jest bowiem projektowanie sys-
temu, którego rezultat stanowią następujące produkty:
różne sposoby, którymi zajmiemy się w sekcji 6.3.4: architektura warstwowaoznacza hie-
rarchiczną organizację podsystemów, w ramach której każda warstwa hierarchii dostarcza
usługi na potrzeby warstw wyższych, jednocześnie korzystając z usług oferowanych przez
warstwy niższe, natomiast partycjonowanie oznacza organizację podsystemów jako wzajem-
nych partnerów, nawzajem świadczących sobie usługi. W sekcji 6.3.5 przedstawimy natomiast
kilka typowych, najczęściej spotykanych w praktyce przykładów stylów architektonicznych
dekompozycji.
I tak na przykład wielokrotnie już cytowany system FRI END można w wyniku dekompo-
zycji podzielić na kilka prostszych podsystemów:
1
We współczesnych implementacjach języka Pascal (Delphi, FreePascal, Lazarus i tym podobnych) ce-
lowi temu służyć mogą moduły (units) i pakiety (packages). Większość współczesnych środowisk pro-
gramistycznych umożliwia także tworzenie bibliotek DLL, będących „cegiełkami", z jakich buduje
się złożony system — czego koronny przykład zaobserwować możemy w systemach linii Windows
— przyp. tłum.
270 Rozdział 6. • Projektowanie systemu — dekompozycja na podsystemy
Rysunek 6.4. Diagram komponentowy UML przedstawiający dekompozycję systemu FRIEND; kom-
ponentami są podsystemy stanowiące rezultat tej dekompozycji. Skierowane linie przerywane ozna-
czają zależności między poszczególnymi podsystemami
pozostała część ikony, popularnie nazywana piłką (bali) lub lizakiem (lollipop), odzwierciedla
udostępnianie operacji. Na rysunku 6.5 widoczne jest zastosowanie tej notacji do przedsta-
wienia powiązań podsystemów F i e l d O f f i c e r l n t e r f a c e i Di s p a t c h t e r l n t e r f a c e z pod-
systemem ResourceManagement. Podsystem Fi eldOff i c e r l n t e r f a c e wykorzystuje usługę
ResourceUpdateServi ce do aktualizacji informacji o statusie i lokalizacji funkcjonariusza,
zaś podsystem D i s p a t c h e r l n t e r f a c e korzysta z usługi R e s o u r c e A l l o c a t i o n S e r v i c e
w celu zidentyfikowania dostępnych aktualnie zasobów i przydzielenia ich do obsługi wypadku.
Obie wymienione usługi udostępniane są przez podsystem ResourceManagement.
Rysunek 6.5. Udostępnianie usług przez podsystem ResourceManagement (przykład notacji „kółko-
-gniazdo")
Notacja „kółko-gniazdo" staje się użyteczna dopiero wówczas, gdy proces dekompo-
zycji przybiera zdecydowanie stabilny kształt i gdy po dobrym określeniu poszczególnych
podsystemów przychodzi kolej na definiowanie oferowanych przez nie usług. Gdy brakuje
jeszcze wyraźnego określenia funkcjonalności poszczególnych podsystemów, wystarczająca
okazuje się notacja odzwierciedlająca jedynie powiązania między podsystemami, widoczna na
rysunku 6.4.
Definiowanie podsystemu w kategoriach oferowanych przez niego usług pomaga skupić
się na jego interfejsie, w oderwaniu od konkretnej jego implementacji. Należy przy tym unikać
uzależniania konkretnych elementów interfejsu od szczegółów implementacyjnych, przy-
kładowo definicja operacji przetwarzającej kolekcję danych nie powinna w żaden sposób na-
wiązywać do jakiejkolwiek implementacji tej kolekcji (listy wiązanej, tablicy haszowanej, drzewa
binarnego i tym podobnych); w ten sposób sprawiamy, że wspomniane szczegóły implemen-
tacyjne staja się niewidoczne dla innych podsystemów, a więc nie wywołują żadnych zewnętrz-
nych konsekwencji w przypadku zmiany implementacji.
Rysunek 6.6. Przykład redukowania sprzężenia w zbiorze podsystemów (dla przejrzystości pominęliśmy
podsystem N o t i f i c a t i o n ) . W wariancie 1. wszystkie podsystemy korzystające z usług podsystemu
Database czynią to bezpośrednio, co uwrażliwia je na zmiany w zakresie interfejsu tegoż podsystemu.
W wariancie 2. podsystem S t o r a g e pełni rolę bariery ochronnej oddzielającej wspomniane systemy
klienckie od interfejsu p o d s y s t e m u Database. U podstaw takiego rozwiązania legło założenie, że
podsystem S t o r a g e cechować się będzie interfejsem daleko stabilniejszym niż podsystem Database
Reprezentowany na rysunku 6.7 system śledzenia decyzji jest na tyle mały, że nie było
niczym nadzwyczajnym zamknięcie wszystkich jego klas w formie pojedynczego podsystemu
DecisionSubsystem. Bliższe przyjrzenie się strukturze powiązań między wspomnianymi
klasami skłania jednak do wniosku, iż graf tych powiązań da się naturalnie podzielić na dwa
podgrafy. Jeden z nich, odpowiadający podsystemowi RationaleSubsystem, wiąże klasy
DesignProblem, Option, Criterion i Decision; drugi, reprezentujący podsystem Planning
'-•Subsystem, zawiera klasy Task, SubTask i Actionltem (patrz rysunek 6.8).
274 Rozdział 6. • Projektowanie systemu — dekompozycja na podsystemy
DecisionSubsystem
Rysunek 6.8. Dekompozycja podsystemu z rysunku 6.7 na dwa odrębne podsystemy. Spoistość wynikowych
podsystemów Rati onal eSubsystem i PI anni ngSubsystem jest znacznie większa niż spoistość pierwotnego
podsystemu Deci si onSubsystem. Oba podsystemy są ponadto prostsze, jednak konieczne jest zdefiniowanie
interfejsu między nimi, w celu zrealizowania powiązań między klasami Task i Deci si on
6.3. Koncepcje projektowania systemu 275
Rysunek 6.9. Dekompozycja systemu na trzy warstwy (przedstawione jako pakiety UML). Podzbiór
podsystemów, zawierający co najmniej jeden podsystem z każdej warstw)', nazywamy pionowym wycin-
kiem; takim wycinkiem jest podzbiór {A, B, E}, nie jest nim natomiast podzbiór {D, G}
2
W społeczności programistów termin „architektura otwarta" używany jest także w zupełnie innym zna-
czeniu — na określenie architektury sprzętowej lub programowej, niewykazującej cech uzależnienia
od technologii konkretnego dostawcy. W tym miejscu używam tego terminu w znaczeniu identycznym
ze znaczeniem w książce J. Rumbaugha, M. Błahy, W. Premerlaniego, F. Eddy'ego i W. Lorensena
[Rumbaugh i in., 1991],
276 Rozdział 6. • Projektowanie systemu — dekompozycja na podsystemy
3
Odwracanie kolejności bajtów w strukturach wielobajtowych ma na celu zniwelowanie różnic między
architekturą little endian a architekturą bigendian (patrz http://pl.wikipedia.org/wiki/Kolejność_bajtów)
— przyp. tłum.
6.3. Koncepcje projektowania systemu 277
Rysunek 6.10. Przykład zamkniętej architektury warstwowej — sieciowy model odniesienia OSI-ISO
Rysunek 6.11. Odwzorowanie warstw modelu OSI-ISO w rzeczywiste komponenty sprzętowe i progra-
mowe. Mechanizm CORBA, stanowiący efektywną implementację warstw sesji i prezentacji, pozwala na
komunikowanie się obiektów rezydujących na różnych komputerach, zaimplementowanych być może
z użyciem odmiennych języków programowania
278 Rozdział 6. • Projektowanie systemu — dekompozycja na podsystemy
Rysunek 6.12. Przykład otwartej architektury warstwowej: aplikacja wykonywana w środowisku za-
wierającym bibliotekę Swing. X l i to podsystem odpowiedzialny za niskopoziomowe operacje graficzne;
AWT jest abstrakcją reprezentującą mechanizmy okienkowe i jednocześnie izolującą warstwy wyższe
od konkretnej implementacji tych mechanizmów. Biblioteka Swing udostępnia aplikacji bogaty repertuar
wykoncypowanych obiektów typowych dla interfejsu użytkownika, mimo to, niektóre aplikacje pomijają
tę biblioteką, odwołując się bezpośrednio do usług oferowanych przez warstwę A W T
Podstawową przyczyną, dla której niektóre warstwy architektury otwartej sięgają niżej
niż tyłko do warstwy sąsiedniej, jest niwelowanie wąskich gardeł wydajnościowych. Archi-
tektura zamknięta okazuje się nader korzystna, gdy spojrzeć na nią z perspektywy programistycz-
nej: ponieważ podsystemy należące do różnych warstw są ze sobą bardzo luźno powiązane
(lub niepowiązane w ogóle), czyli ponieważ minimalny jest stopień sprzężenia podsystemów,
mogą być one integrowane i testowane w sposób przyrostowy. Ta wygoda ma jednak swoją
cenę: każdy nowy poziom (warstwa) wnosi do ogólnej architektury zarówno pewne spowol-
nienie wykonywania systemu, jak i dodatkowe zapotrzebowanie na pamięć. Zsumowanie
się tych narzutów może spowodować, że niemożliwe stanie się spełnienie wymagań poza-
funkcyjnych. Ponadto dodawanie nowych elementów funkcjonalnych — zwłaszcza nieprzewi-
dzianych zawczasu — może okazać się trudne w przypadku „głębokiej' architektury. W prakty-
ce, typowy system składa się z najwyżej trzech — wyjątkowo czterech lub pięciu — warstw.
Odmiennym sposobem dekompozycji systemu jest jego partycjonowanie na równo-
rzędne podsystemy, z których każdy odpowiedzialny jest za inną klasę usług. Przykładowo
system pokładowy samochodu może być zdekomponowany na podsystemy zarządzające (od-
powiednio) nawigacją i trasą (w postaci informowania kierowcy na bieżąco o lokalizacji i wy-
maganym kierunku jazdy), personalizacją środowiska (pozycją fotela, ulubioną stacją radiową),
informacją o zużyciu paliwa oraz harmonogramem przeglądów i napraw. Każdy z tych pod-
systemów jest luźno powiązany z pozostałymi, lecz równie dobrze może funkcjonować w ode-
rwaniu od nich.
Dekompozycja przeprowadzana w praktyce ma zwykle charakter pośredni między opi-
sanymi skrajnościami. Dekomponowanie systemu rozpoczyna się najczęściej od jego partycjo-
nowania na wysokopoziomowe podsystemy, z których każdy odpowiedzialny jest za specy-
ficzny aspekt funkcjonalności bądź też przeznaczony do pracy na konkretnym węźle sprzętowym.
Każdy z tych podsystemów może być (o ile uzasadnia to jego złożoność) sukcesywnie dekom-
ponowany w sposób hierarchiczny, aż poszczególne warstwy staną się na tyle proste, że możliwe
6.3. Koncepcje projektowania systemu 279
Repozytorium
Rysunek 6.13. Przykład architektury repozytoryjnej. Każdy podsystem zależny jest jedynie od central-
nego repozytorium, które nie posiada jednak żadnej wiedzy na temat poszczególnych podsystemów
4
Patrz na przykład http://pl.wikipedia.org/wiki/Architektura_tablicowa — przyp. tłum.
6.3. Koncepcje projektowania systemu 281
centralne repozytorium rychło stać się'może wąskim gardłem i to zarówno pod względem
wydajności, jak i modyfikowalności — poszczególne podsystemy są przecież z tym repozyto-
rium wysoce sprzężone, zatem wszelkie zmiany dokonywane w jego obrębie przekładają się
na konieczność być może daleko posuniętych zmian w samych podsystemach.
Model-widok-kontroler (MVC)
3
Ten krok wykonywany jest — oczywiście — jednorazowo, prawdopodobnie w fazie inicjacji systemu
— przyp. tłum.
282 Rozdział 6. • Projektowanie systemu — dekompozycja na podsystemy
Rysunek 6.16. Przykład zastosowania architektury MVC. „Modelem" jest tu nazwa pliku 9Design-
PAtterns2.ppt, powiązana z dwoma „widokami": oknem zatytułowanym CBSE, wyświedającym zawartość
folderu, i oknem pierwszoplanowym, wyświetlającym właściwości pliku. Gdy zmieni się nazwa pliku,
oba widoki zostaną uaktualnione na skutek interwencji „kontrolera"
Rysunek 6.17. Diagram komunikacyjny ukazujący przepływ informacji w związku ze zmianą nazwy
pliku w systemie pokazanym na rysunku 6.16
Klient-server
W ramach tej architektury (patrz rysunek 6.18) podsystem zwany serwerem jest dostawcą
usług dla (jednej lub wielu) instancji innych podsystemów, zwanych klientami i odpowiedzial-
nych za interakcję z użytkownikiem (użytkownikami). Żądanie usługi odbywa się zwykle za
pośrednictwem zdalnego wywoływania procedur (RPC — Remote Procedure Calif bądź za po-
średnictwem obiektów brokerów (jak w przypadku technologii CORBA, Java RMI czy proto-
kołu HTTP). Podsystemy klienckie funkcjonują niezależnie od podsystemu serwera, z wyjąt-
kiem synchronizacji niezbędnej do zarządzania żądaniami klientów i odpowiedziami serwera.
Przykładem zastosowania architektury klient-serwer jest system informacyjny oparty
na centralnej bazie danych. Każdy podsystem klienta odpowiedzialny jest za obsługę dialogu
z użytkownikiem, walidację wprowadzanych przez niego danych i inicjowanie transakcji ba-
zodanowych, gdy wynik tej walidacji okaże się pozytywny. Serwer jest natomiast odpowiedzialny
za wykonywanie żądanych transakcji i gwarantowanie integralności danych. W tym kontekście
6
A także książkę Head First Design Patterns. Edycja polska (Rusz głową!), wyd. Helion 2005,
(http://helion.pl/ksiazki/head_Jirst_design _patterns_edycja _polska_rusz_glowa_eric_jreeman_elisabeth_
freeman_kathy_sierra_bert_bates,hfdepa.htm) —przyp. tłum.
1
Mechanizmy powiadamiania o zmianach zachodzących w systemie plików udostępniane są przez systemy
operacyjne na zasadzie subskrypcji za pomocą odpowiednich funkcji API, przykładowo w systemie
Windows temu celowi służą między innymi funkcje Win32 API Fi ndFi rstChangeNoti f i c a t i on
i FindNextChangeNotifi c a t i o n — p r z y p . tłum.
8
Lub zaawansowanych mechanizmów zbudowanych na bazie RPC, takich jak COM, D C O M czy
C O M + firmy Microsoft — przyp. tłum.
284 Rozdział 6. • Projektowanie systemu — dekompozycja na podsystemy
Rysunek 6.18. Architektura klient-serwer. Klienci żądają usług od jednego lub większej liczby ser-
werów. Serwery nie dysponują żadną informacją na temat klientów. Architektura klient-serwer mo-
że być uważana za specjalizację architektury repozytoryjnej
serwer może być uważany za szczególny przypadek repozytorium (realizowanego jako proces
zarządzający centralnymi danymi), zaś architektura klient-serwer — za szczególny przypadek
(specjalizację) architektury repozytoryjnej. Systemy klient-serwer mogą jednak wykorzy-
stywać wiele serwerów — czego ewidentnym przykładem jest choćby sieć WWW, w której
każdy klient może z łatwością pobierać dane z wielu tysięcy serwerów (patrz rysunek 6.19).
Peer-to-peer
Styl architektoniczny peer-to-peer 9 (patrz rysunek 6.20), w skrócie P2P, może być
uważany za uogólnienie (generalizację) architektury klient-serwer, bowiem każdy z podsys-
temów spełniać może obie funkcje: klienta i serwera — w tym sensie, że może zarówno żądać
usług, jak i sam je udostępniać. Funkcjonowanie poszczególnych podsystemów jest niezależne,
z wyjątkiem synchronizacji koniecznej dla obsługi żądań.
Przykładem architektury P2P jest system wykorzystujący bazę danych, która zarówno
realizować może żądania związane z odczytem, wyszukiwaniem i modyfikowaniem danych,
jak i powiadamiać aplikację o dokonywaniu zmian w pewnych obszarach danych (patrz rysu-
nek 6.21). Systemy P2P są trudniejsze do projektowania niż systemy utrzymane w architektu-
rze klient-serwer, bo cechują się bardziej skomplikowanym przepływem sterowania i stwarzają
zagrożenie wystąpienia niepożądanych zjawisk w rodzaju zastoju (deadlock).
konsument
Peer
*
usługalO
usługa2()
dostawca
usługaNO
Rysunek 6.20. Architektura peer-to-peer (P2P). Każdy podsystem może spełniać funkcje zarówno
klienta, jak i serwera
Rysunek 6.21. Przykład architektury P2P. Serwer zarządzania bazą danych (DBMS — Database Mana-
gement System) może zarówno realizować żądania otrzymywane od klienta, jak i powiadamiać go
o zaistniałych zdarzeniach
Z systemami P2P wiąże się mechanizm odwołania zwrotnego (callback). Klient może
mianowicie wskazać serwerowi jedną ze swych operacji i zażądać, by serwer wywołał tę ope-
rację w przypadku wystąpienia określonego zdarzenia. W przykładzie pokazanym na rysunku
6.21 klient DBUser wykorzystuje tę możliwość w stosunku do serwera bazy danych DBMS.
Systemy P2P, w których „serwery" odwołują się do „klientów" jedynie za pośrednictwem od-
wołań zwrotnych, utożsamiane są z systemami klient-serwer — co jest o tyle nieadekwatne,
że w tym przypadku połączenie między klientem a serwerem może być nawiązywane także
z inicjatywy serwera.
Architektura trójwarstwowa
Architektura czterowarstwowa
Filtry i potoki
wyjście
Rysunek 6.24. Architektura filtr-potok. Każdy filtr może posiadać wiele wejść i wyjść, każdy potok
natomiast łączy dokładnie dwa filtry
Architektura filtr-potok jest bardzo elastyczna — poszczególne filtry można łatwo wy-
mieniać i modyfikować, stosownie do bieżących potrzeb.
Najbardziej spektakularnym przykładem obecności tej architektury jest powłoka
systemu UNIX opisana przez D. M. Ritchie i K. Thompsona [Ritchie i Thompson, 1974]l0.
Większość filtrów tworzona jest w ten sposób, że dane pobierane są ze standardowych
potoków wejściowych i wysyłane na standardowe potoki wyjściowe, co umożliwia łatwe or-
ganizowanie zaawansowanego przetwarzania. Na rysunku 6.25 widzimy uniksową sekwencję
filtrów prowadzącą do czytelnego wyświetlenia listy procesów należących do użytkownika
d u t o i t . Najpierw za pomocą polecenia ps uzyskujemy listę wszystkich procesów; program
grep eliminuje z tej listy pozycje związane z innymi użytkownikami, program s o r t sortuje
wynik tej eliminacji w żądanej kolejności, zaś program more organizuje wyświetlanie posor-
towanej listy w porcjach dostosowanych do wysokości ekranu terminala.
Cechą charakterystyczną (i podstawową zaletą) architektury filtr-potok jest jej automa-
tyzm — skomplikowane przetwarzanie informacji może odbywać się bez ingerencji użytkownika.
Architektura ta nie nadaje się jednak do zastosowań wymagających bardziej zaawansowanych
interakcji między komponentami — systemów informacyjnych czy systemów interaktywnych.
10
Analogiczny mechanizm istnieje także w systemie Windows. Jego pierwowzór istniał już nawet
w systemie MS DOS, z naturalnym dla tego systemu ograniczeniem — poszczególne filtry uruchamiane
były sekwencyjnie. W danej chwili aktywny był więc dokładnie jeden filtr, wykorzystujący dwa potoki
— standardowe wejście i standardowe wyjście, oba zrealizowane jako pliki tymczasowe tworzone i usu-
wane przez system — przyp. tłum.
288 Rozdział 6. • Projektowanie systemu — dekompozycja na podsystemy
Rysunek 6.25. Sekwencja poleceń uniksowych zrealizowana jako kombinacja filtrów i potoków
Tabela 6.4. Znaczenie klas modelu analitycznego systemu MyTri p, przedstawionych na rysunku 6.26
• Modyfikowalność: MyTri p powinien być modyfikowalny, czyli musi umożliwiać wybór między
różnymi usługami planowania podróży [wynik przewidywania przyszłych potrzeb klienta].
Ogólnie cele projektowe wybierane są z długiej listy najbardziej pożądanych cech syste-
mu. W tabelach od 6.5 do 6.9 przedstawiamy listy grupujące możliwe kryteria projektowania.
Kryteria te zorganizowaliśmy w pięć grup, związanych z (kolejno) wydajnością, pewnością
6.4. Aktywności projektowania systemu: od obiektów do podsystemów 291
Przepustowość Ile zadań system zdolny jest wykonać w ustalonym przedziale czasu?
Kryteria pewności działania (tabela 6.6) związane są z wysiłkiem, jaki należy zain-
westować w minimalizowanie zarówno prawdopodobieństwa awarii systemu, jak i konse-
kwencji ewentualnych awarii. Jak często system może się załamywać? W jakim stopniu
powinien być dostępny dla użytkowników? W jakim zakresie powinien tolerować awarie
i konsekwencje swych własnych błędów? Czy użytkowanie systemu pociąga za sobą zagro-
żenia dla środowiska? Jeśli tak, to jakie ? Czy awaria systemu może zagrażać bezpieczeń-
stwu jego użytkowników?
danych do nowej postaci, wymaganej przez nowy system (bądź za pomocą innej procedury
o charakterze pośrednim między wymienionymi skrajnościami). Nie można także zapominać
0 kosztach szkolenia użytkowników nowego systemu i kosztach jego pielęgnowania.
Modyfikowalność Jak łatwo można zmieniać funkcje aktualnie realizowane przez system?
Kryteria użytkownika (tabela 6.9) obejmują te cechy systemu, które istotne są z per-
spektywy jego użytkownika, lecz nie zostały ujęte w kategoriach wydajności ani pewności
działania. Jak trudna jest nauka obsługi systemu? Czy typowy użytkownik zdolny będzie do
bezbłędnego wykonywania powierzonych mu zadań? Często zdarza się, że pytań tego rodzaju
nie traktuje się z należytą uwagą — zwłaszcza wówczas, gdy klient kontraktujący system
nie jest jego bezpośrednim użytkownikiem.
6.4. Aktywności projektowania systemu: od obiektów do podsystemów 293
Kompromis Przesłanki r o z s t r z y g a n i a
Szybkość kontra Jeśli aplikacja nie spełnia wymagań pod względem maksymalnego czasu
zapotrzebowanie na reakcji czy minimalnej przepustowości, można przyspieszyć jej działanie,
pamięć stosując na przykład cache'owanie, co wymaga dodatkowej pamięci. Jeśli
aplikacja jest zbyt pamięciożerna, można zmniejszyć zapotrzebowanie na
pamięć, przykładowo przez kompresję danych czy wielokrotne obliczanie
tych samych wielkości zamiast ich zapamiętywania — co oczywiście
wymaga dodatkowego czasu procesora.
Czas dostarczenia Jeśli terminowe dostarczenie systemu zagrożone jest z powodu trwających
kontra jakość testów systemu, m e n e d ż e r może zdecydować o dostarczeniu systemu
n i e k o m p l e t n i e przetestowanego lub zawierającego r o z p o z n a n e błędy
(dła których w terminie późniejszym przewidziane są łaty łub poprawki)
albo dostarczyć z opóźnieniem system lepiej przetestowany, po usunięciu
znanych błędów.
Czas dostarczenia Gdy terminowość realizacji poszczególnych części systemu staje się zagrożona,
kontra siły menedżer projektu może zdecydować o zaangażowaniu w projekt kolejnych
wytwórcze uczestników. Zwiększenie liczebności personelu ma jednak pozytywne skutki
raczej we wczesnych stadiach realizacji projektu, bowiem w późniejszych
fazach nowi uczestnicy wymagają przeszkolenia wiążącego się z czasowo
obniżoną produktywnością. Niezależnie od pozytywnych efektów, przydział
dodatkowych zasobów do projektu zawsze wiąże się z dodatkowymi kosztami.
294 Rozdział 6. • Projektowanie systemu — dekompozycja na podsystemy
Tabela 6.11. Funkcje podsystemów systemu MyTri p, wyodrębnionych w ramach jego wstępnej de-
kompozycji
11
Oraz cytowana już książka Head First Design Patterns. Edycja polska (Rusz głowę!), wyd. Helion, 2005
— przyp. tłum.
296 Rozdział 6. • Projektowanie systemu — dekompozycja na podsystemy
Rysunek 6.28. Przykład zastosowania wzorca projektowego Fasada do ukrywania prywatnych szcze-
gółów podsystemu
Wiele analiz przypadku, jakie pojawiły się w ostatniej dekadzie ubiegłego wieku, podaje
ewidentne przykłady korzyści wynikających ze stosowania wzorcowych architektur oprogra-
mowania, nie tylko z technicznego punktu widzenia (czyli decyzji projektowych dotyczących
struktur i wielokrotnego wykorzystywania komponentów), lecz także z perspektywy zarzą-
dzania projektami (powtarzalnych metod organizowania zespołów i ich komunikowania się
ze sobą). W Instytucie Inżynierii Oprogramowania uniwersytetu Carnegie Mellon zgroma-
dzono i opracowano wiele materiałów na temat architektury oprogramowania i jej konkretnych
zastosowań. Prace L. Bassa, P. Clementsa i R. Kazmana [Bass i in., 2003] oraz P. Clementsa, R.
Kazmana i M. Kleina [Clements i in., 2002] zawierają opis metod i analizy przypadków zwią-
zanych z wyborem i oceną konkretnej architektury oprogramowania. Przykłady praktycznych
zastosowań architektury oprogramowania w rozwiązaniach przemysłowych znajdą natomiast
czytelnicy w książce C. Hofmeister, R. Norda i D. Soniego [Hofmeister, 2000],
6.6. Ćwiczenia
6.1. Dekomponowanie systemu na podsystemy z jednej strony zmniejsza złożoność,
z którą muszą borykać się programiści, poprzez redukowanie sprzężenia między
podsystemami i zwiększanie spoistości każdego z nich; z drugiej jednak strony przy-
czynia się do wzrostu złożoności, poprzez zwiększanie rozdrobienia systemu i liczby
interfejsów. Jeśli maksymalna spoistość ma być przesłanką przemawiającą za dziele-
niem podsystemów na coraz mniejsze części, to jaka konkurencyjna przesłanka
przemawia za utrzymywaniem liczby podsystemów na możliwie niskim poziomie?
6.2. W sekcji 6.4.2 zaklasyfikowaliśmy cele projektowe w pięciu kategoriach: wydajności,
pewności działania, kosztów, pielęgnowalności i kryteriów użytkownika. Przyporządkuj
każdy z poniższych celów do jednej lub kilku z wymienionych kategorii:
• użytkownik musi otrzymać od systemu odpowiedź najdalej po sekundzie od wy-
słania żądania,
• Ti cketDi s t r i butor musi być zdolny do wydrukowania biletu, nawet w przypad-
ku awarii sieci,
• sprzęt hostujący system Ti cketDi s t r i butor musi umożliwiać instalowanie nowych
przycisków, jeżeli wymagać tego będzie większe zróżnicowanie typów biletów,
• bankomat musi powstrzymywać ataki polegające na próbie odgadnięcia numeru
PIN za pomocą systematycznych prób.
6.3. Opracowując system, przechowujący swe dane w uniksowym systemie plików, prze-
widujesz, że w przyszłości tworzona będzie wersja Twojego systemu dla środowiska
przechowującego pliki w odmienny sposób. Zaprojektuj dekompozycję Twojego
systemu uwzględniającą tę perspektywę.
6.4. Starsze kompilatory projektowane były zgodnie z architekturą filtr-potok, w której
każdy z filtrów przekształcał otrzymane dane do pewnej postaci pośredniej i przeka-
zywał je następnemu filtrowi. Współczesne środowiska programistyczne, obejmujące
zintegrowany kompilator, edytor świadomy składni języka i debugger na poziomie
kodu źródłowego wykorzystują architekturę repozytoryjną. Spróbuj określić cele
projektowe, które prawdopodobnie stały się przyczyną tej zmiany.
298 Rozdział 6. • Projektowanie systemu — dekompozycja na podsystemy
Bibliografia
L. Bass, P. Clements, R. Kazman Software Architecture in Practice,
[Bass i in., 2003]
wyd. drugie, Addison-Wesley, Reading, MA, 2003.
[OMG, 2008] Object Management Group Common Object Request Broker Architecture
(CORBA) Specification: Version 3.1, http://www.omg.org 2008.
[RMI, 2009] Java Remote Method Invocation, JDK Documentation, Javasoft, 2009.
Bibliografia 349
Projekt systemu:
realizacja celów
projektowych
Dublowanie systemu komputerowego statku kosmicznego nie jest pomysłem nowym. Rakieta Saturn,
która wyniosła statek Apollo, wykorzystywała trzy identyczne kopie systemu — każdy jego kom-
ponent występował w trzech egzemplarzach. Gdy wynik produkowany przez jeden egzemplarz da-
nego komponentu różnił się od wyniku produkowanego przez dwa pozostałe egzemplarze, uzna-
wane to było za awarię: wadliwy komponent uznany zostawał za przegłosowany, przyjmowany był
wynik produkowany przez pozostałe egzemplarze — tak oto maskowana była pojedyncza awaria.
Takie rozwiązanie było po pierwsze trudne do zrealizowania, po drugie zdolne było sobie radzić
z incydentalnymi awariami, nie z masową katastrofą, jaką było na przykład spłonięcie Apollo 13.
W stacji orbitalnej Skylab zastosowano inne rozwiązanie. Dwa bliźniacze egzemplarze systemu kom-
puterowego umieszczone były na dwóch różnych krańcach statku. Gdyby zawiódł jeden z tych sys-
temów, drugi powinien przejąć jego funkcje. Podczas gdy stosunkowo długi czas przełączenia
między systemami jest całkowicie akceptowalny dla stacji orbitalnej (która do pewnego stopnia może
tracić wysokość bez kłopotliwych konsekwencji), jest on nie do przyjęcia w przypadku promu ko-
smicznego, którego komputery reagować muszą błyskawicznie na szybko następujące po sobie
zdarzenia związane ze zboczeniem z kursu lub przebiegiem lądowania. Z tego względu system kom-
puterowy promu kosmicznego powinien być zarówno zdublowany (jak w stacji Skylab), jak i szybko
przełączalny (podobnie jak w rakiecie Saturn).
Zgodnie z początkowymi wymaganiami ze strony NASA, prom kosmiczny powinien umieć pora-
dzić sobie z dwiema awariami pod rząd, bez konieczności przerywania misji: prowadziło to do sys-
temu zawierającego pięć identycznych komputerów z pięcioma uruchomionymi egzemplarzami tego
samego oprogramowania. Gdyby zawiodły dwa spośród wspomnianych komputerów, trzy pozostałe
powinny zapewnić kontynuowanie misji; gdyby zawiódł kolejny, dwa pozostałe powinny zapewnić
bezpieczne wylądowanie. Ze względu na wysokie koszty takiego rozwiązania, NASA zdecydowała
się obniżyć swe wymagania do jednej tolerowanej awarii — dwie następujące bezpośrednio po sobie
miały powodować przerwanie misji. Ponieważ jednak zaawansowany już projekt zależny był od
koncepcji pięciu komputerów (które zostały już dostarczone), piątemu komputerowi powierzono
funkcję komputera zapasowego. Zauważmy, że wszystkie cztery pozostałe komputery wykonywać
miały to samo oprogramowanie, zatem powielenie systemu nie zapewniało żadnego zabezpieczenia
przed konsekwencjami błędów programistycznych. Na wspomnianym komputerze zapasowym wy-
konywana miała być uproszczona wersja systemu, zawierająca jedynie funkcje niezbędne do prawi-
dłowej obsługi startu i lądowania.
gdy decyzje projektowe koncentrują się głównie wokół systemu programistycznego, wymagają
nieco innego podejścia niż w przypadku promu kosmicznego, gdzie równie istotne były kwe-
stie sprzętowe; mimo to, niezmienna pozostaje zasada, że cele projektowe rozpatrywane są
pojedynczo, za każdym razem wpływając na kształt dekompozycji systemu i interfejsy po-
szczególnych podsystemów. Projektowanie systemu obejmuje przeanalizowanie kolejno
wszystkich celów projektowych. W sekcji 7.2 opisujemy ogólnie związane z tym aktywności,
w sekcji 7.3 prezentujemy nowy typ diagramów UML — diagramy wdrażania. Sekcję 7.4
poświęcamy szczegółowemu opisowi aktywności związanych z projektowaniem systemu i ich
powiązaniom. Sekcja 7.5 zawiera omówienie zagadnień menedżerskich związanych z projek-
towaniem systemu. Opisane koncepcje ilustrujemy w sekcji 7.6 w ramach analizy przypadku,
jakim jest system ARENA.
1
Przykład hermetyzowania systemu bazy danych widzieliśmy już na rysunku 6.6 w poprzednim
rozdziale — przyp. tłum.
304 Rozdział 7. • Projekt systemu: realizacja celów projektowych
załamanie całego systemu. Tego typu zagadnienia muszą być rozpatrywane w sposób
spójny na poziomie całego systemu — zwykle wtedy odbywa się wybór konkretnego
komponentu bazodanowego i definiowanie towarzyszących mu podsystemów reali-
zujących zarządzanie trwałymi danymi.
• Kontrola dostępu. Kto posiada dostęp do poszczególnych części danych? Czy reguły
kontroli tego dostępu mogą być dynamicznie zmieniane? W jaki sposób reguły te są
definiowane i realizowane? Kontrola dostępu do danych i ich bezpieczeństwo także
są zagadnieniami ogólnosystemowymi — innymi słowy, polityka dostępu do okre-
ślonych partii danych musi być identyczna dla wszystkich podsystemów.
• Przepływ sterowania. Jaka jest sekwencja poszczególnych operacji w systemie? Czy
system sterowany jest zdarzeniami? Czy jest zdolny do obsługi kilku równoczesnych
interakcji? Wybór konkretnego schematu przepływu sterowania ma swe konsekwen-
cje dla interfejsów poszczególnych podsystemów: w systemie sterowanym zdarzeniami
poszczególne podsystemy muszą zapewniać obsługę tych zdarzeń, w systemie wie-
lowątkowym muszą być zdefiniowane mechanizmy szeregowania dostępu do wspól-
nych danych, w postaci wzajemnych wykluczeń i sekcji krytycznych.
• Warunki graniczne. W jaki sposób system rozpoczyna i kończy swą pracę? Jak ob-
sługiwane są sytuacje wyjątkowe? Realizacja inicjowania i kończenia pracy systemu
skupia większą część jego złożoności, szczególnie w środowisku rozproszonym. Ini-
cjowanie, kończenie pracy i obsługa sytuacji wyjątkowych mają wpływ na postać
interfejsów potencjalnie wszystkich podsystemów.
między węzłami reprezentowane są przez linie ciągłe; linie te mogą być etykietowane stereo-
typami oznaczającymi protokoły komunikacji między parami węzłów. Na diagramie z rysunku
7.2 widoczne są dwie przeglądarki WWW, wyświetlające informację otrzymywaną z serwera
WWW; serwer ten z kolei komunikuje się z serwerem bazy danych. Zwróćmy uwagę, że żadna
z przeglądarek nigdy nie uzyskuje bezpośredniego dostępu do serwera bazy danych.
guracji sprzętowej wiąże się także z wyborem docelowej maszyny wirtualnej dla systemu. Taka
maszyna wirtualna obejmuje system operacyjny i wszelkie niezbędne komponenty, takie jak
system(y) zarządzania bazą danych czy pakiety komunikacyjne. Właściwy wybór maszyny
wirtualnej redukuje dystans między systemem a platformą sprzętową, na której ma być eks-
ploatowany. Im bardziej funkcjonalne wspomniane komponenty, tym mniej pracochłonne
będzie opracowywanie samego systemu. Wybór maszyny wirtualnej może być jednak poważ-
nie ograniczony, na przykład przez fakt, że klient kontraktujący system dysponuje już odpo-
wiednią bazą sprzętową. Nie bez znaczenia są także kryteria kosztowe: być może samodzielne
zaimplementowanie jakiegoś komponentu jest bardziej opłacalne niż zakup gotowej wersji
— jednak tego typu dylematy rzadko są łatwe do rozstrzygania.
Z wymagań dotyczących systemu MyTrip wnioskujemy, że jego podsystemy Planning
^Subsystem i Routi ngSubsystem funkcjonować mają na dwóch różnych węzłach: pierwszy
na serwerze WWW realizującym odpowiednie usługi, drugi na pokładowym komputerze sa-
mochodu. Ten fakt odzwierciedlony jest na rysunku 7.4, na którym widoczne są dwa urządzenia:
:OnBoardComputer (komputer pokładowy) i :WebHost (komputer serwera WWW); na tym
ostatnim funkcjonuje środowisko wykonawcze : Apache. Jako maszynę wirtualną dla serwera
W W W wybraliśmy odmianę UNIX-a, rolę maszyn wirtualnych w komputerze pokładowym
spełniają przeglądarki Internet Explorer i Safari.
2
W języku angielskim słowo to oznacza pełnomocnika — przyp. tłum.
3
Oraz cytowana już w poprzednim rozdziale książka Head First Design Patterns. Edycja polska
(Rusz głową!), wyd. Helion, 2005 — przyp. tłum.
7.4. Aktywności realizacji celów projektowych 309
Tabela 7.1. Nowe klasy i podsystemy zrewidowanego modelu projektu systemu MyTri p
Rysunek 7.6. Dekompozycja systemu MyTrip uwarunkowana konkretnym wyborem strategii prze-
chowywania danych
Tabela 7.2. Nowe elementy dekompozycji systemu MyTrip, związane z wyborem strategii przecho-
wywania danych
4
Krotka (ang. tupie), zwana także „n-tką" (czyt. „entką"), to zbiór wartości przypisywanych atrybutom
z predefiniowanego zbioru — przyp. tłum.
312 Rozdział 7. • Projekt systemu: realizacja celów projektowych
I tak na przykład w systemie MyTrip równoczesna obsługa wielu klientów stwarza od-
powiednie wymagania pod względem bezpieczeństwa: trasy podróży (Tri p) przechowywane
w systemie mogą być udostępniane tylko tym klientom, którzy sami je stworzyli, a nieuwie-
rzytelnieni użytkownicy w ogóle nie powinni mieć dostępu do systemu. Wymaganie to, spójne
z celami projektowymi sformułowanymi w sekcji 6.4.2, ma swe odzwierciedlenie w zdefinio-
waniu klasy Driver, reprezentującej klientów (kierowców) i skojarzonej z klasą Trip. Pod-
system PlanningSubsystem odpowiedzialny jest za uwierzytelnienie użytkownika przed
przyjęciem od niego żądania dotyczącego określonych tras. Dla większego bezpieczeństwa
dane przesyłane między podsystemami PI anni ngSubsystem i Routi ngSubsystem są szyfrowane
— funkcję tę wykonuje podsystem CommunicationSubsystem. Definicję klasy Driver oraz
zmodyfikowane definicje podsystemów PI anni ngSubsystem i Communi cati onSubsystem przed-
stawione są w tabeli 7.3; nowe elementy wyróżnione są kursywą.
Definiowanie kontroli dostępu dla typowego systemu jest zwykle bardziej skompliko-
wane niż w systemie MyTri p, dla każdego aktora konieczne jest bowiem precyzyjne określenie,
jakie operacje ma prawo wykonywać na poszczególnych obiektach. Przykładowo kasjer w banku
ma prawo realizować uznania i obciążenia na koncie klienta, ale tylko do pewnego predefi-
niowanego limitu kwotowego; transakcja wykraczająca poza ten limit musi być zatwierdzona
przez menedżera. Podobnie każdy z menedżerów może analizować statystyki ze swego oddziału,
nie ma jednak dostępu do statystyk z innych oddziałów. Analityk ma dostęp do wszystkich
statystyk, nie może jednak modyfikować żadnego z kont. Reguły dostępu poszczególnych ak-
torów do poszczególnych obiektów najłatwiej modelować za pomocą macierzy, której wiersze
odpowiadają aktorom, a kolumny — klasom podlegającym kontroli. Każda komórka tej ma-
cierzy, odpowiadająca parze (aktor-klasa) zawiera listę operacji (zwaną prawami dostępu),
jakie dany aktor ma prawo wykonywać na instancjach danej klasy. Tabela 7.4 jest przykładem
takiej właśnie macierzy.
314 Rozdział 7. • Projekt systemu: realizacja celów projektowych
Tabela 7.4. Macierz dostępu w systemie bankowym. Kasjer m a prawo dokonywania drobnych trans-
akcji (postSmallDebit() i p o s t S m a l l C r e d i t ( ) ) i przeglądania stanów kont (examineBalance()). Me-
nedżer ma prawo dokonywania wszelkich transakcji na kontach (postSmal 1 Debi t (), postSmal 1 Credi t (),
p o s t L a r g e D e b i t ( ) i p o s t L a r g e C r e d i t Q ) , przeglądania stanów i historii kont (examineBalanceQ
i examineHistory()) i analizowania statystyk dotyczących własnego oddziału (examineBranchStats()).
Analitycy mają dostęp do wszystkich statystyk (examineGlobalStatsQ i examineBranchStatsQ), nie
mogą jednak wykonywać żadnych transakcji na kontach
• Globalna tabela dostępu, w której każda niepusta komórka macierzy dostępu re-
prezentowana jest w postaci jednej lub kilku krotek postaci (aktor, klasa, operacja).
Rozstrzyganie, czy określony aktor ma prawo wykonywać określoną operację na
obiektach określonej kl asy, sprowadza się do poszukiwania odpowiedniej krotki
— gdy taka nie istnieje, aktor nie uzyska zezwolenia.
• Listy kontroli dostępu, po jednej liście dla każdej klasy; każda z tych list składa się
z par postaci (aktor, operacja). Przy każdej próbie wykonania przez określonego
aktora określonej operacji na obiekcie danej klasy, w liście związanej z tą klasą
poszukiwana jest odpowiednia para — gdy nie zostanie znaleziona, aktor nie uzyska
zezwolenia. Przykładem takiej listy jest lista gości zaproszonych na imprezę: każdy
przybyły gość konfrontowany jest przez organizatora z listą zaproszonych osób, na
której obecność jest warunkiem koniecznym i wystarczającym do udziału w imprezie.
• listy uprawnień, po jednej liście dla każdego aktora; każda z tych list składa się z par
postaci (ki asa, operacja). Przy każdej próbie wykonania przez określonego aktora
określonej operacji na obiekcie danej klasy, w liście związanej z tym aktorem po-
szukiwana jest odpowiednia para — gdy nie zostanie znaleziona, aktor nie uzyska
zezwolenia. Analogią takiej listy może być zbiór zaproszeń, jakimi aktualnie dys-
ponuje bywalec różnych imprez — w danej imprezie może uczestniczyć wyłącznie
na podstawie odpowiedniego zaproszenia..
cechują się dużym zapotrzebowaniem na pamięć; listy kontroli dostępu są bardziej efektywne
przy rozstrzyganiu uprawnień dostępu z perspektywy konkretnej klasy, zaś listy uprawnień
— bardziej efektywne przy rozstrzyganiu uprawnień dostępu z perspektywy konkretnego aktora.
Każdy wiersz macierzy dostępu reprezentuje konkretny „widok dostępowy" do instancji
klas ze zbioru określonego przez zbiór kolumn tej macierzy. Owe „widoki" powinny być spójne
w obrębie całej macierzy, mimo to, są one zwykle implementowane poprzez definiowanie
osobnych subklas dla różnych typów krotek (aktor, operacja). Przykładowo w omawianym
przed chwilą systemie bankowości moglibyśmy w tym celu zaimplementować dwie subklasy
klasy Account — AccountVi ewedByTel 1 er i AccountVi ewedByManager, reprezentujące (odpo-
wiednio) konto w postaci dostępnej dla kasjera (Tel 1 er) i konto w postaci dostępnej dla me-
nedżera (Manager). Tylko wybrane klasy będą wówczas dostępne dla określonego aktora
— i tak na przykład nie istnieje podklasa klasy Account odpowiednia dla analityka (Analyst),
ten bowiem nie ma prawa wykonywać żadnych operacji na kontach. W oprogramowaniu
przeznaczonym dla analityka nie będzie więc zaimplementowana żadna klasa, która takie
operacje mogłaby umożliwiać — zmniejsza to ryzyko uzyskania przez niego nieautoryzowanego
dostępu do kont w rezultacie ewentualnych błędów w oprogramowaniu.
Często liczba aktorów i (lub) liczba chronionych klas jest na tyle duża, że imple-
mentacja uprawnień w postaci zarówno list kontroli dostępu, jak i list uprawnień stano-
wiłaby zbyt duże obciążenie pamięciowe. W takich przypadkach implementuje się macierz
dostępu w postaci bardziej zwartej — w formie zbioru reguł. Przykładem takiej reprezentacji
są zapory sieciowe {firewalls) chroniące usługi zlokalizowane w intranecie przed dostępem
ze strony komputerów podłączonych do internetu. Bazując na adresie hosta źródłowego, nu-
merze portu źródłowego, adresie hosta docelowego, numerze portu docelowego i rozmiarze
pakietu zapora sieciowa decyduje o dopuszczeniu albo niedopuszczeniu tego pakietu do kom-
putera docelowego. Ponieważ liczba potencjalnych kombinacji opisanej postaci jest praktycz-
nie nieskończona, są one uogólniane w postaci ciągu3 reguł: dla każdego pakietu docierające-
go do zapory analizowane są kolejne reguły w celu znalezienia reguły „pasującej" do tegoż
pakietu; gdy taka zostanie znaleziona, stosowana jest akcja określona przez tę regułę (czyli za-
akceptowanie albo odrzucenie pakietu). Dla kompletności, ostatnia reguła na liście powinna
pasować do dowolnego pakietu — będzie on wówczas określać akcję domyślną dla pakietów,
dla których nie stosuje się żadna z pozostałych reguł. W tabeli 7.5 widzimy ciąg reguł dla
zapory widocznej na rysunku 7.7. Dwie pierwsze reguły zezwalają dowolnemu hostowi
(zlokalizowanemu w internecie lub w intranecie) na dostęp do usług http oferowanych przez
serwer W W W oraz na dostarczanie poczty do serwera pocztowego (protokół smtp). Dwie
kolejne reguły pozwalają dowolnemu komputerowi znajdującemu się w intranecie na mody-
fikowanie stron zapamiętanych na serwerze WWW (rsync) i odczytywanie poczty z serwera
pocztowego (pop). Ze względy na owe dwie reguły, żaden z hostów zlokalizowanych w inter-
necie nie ma prawa modyfikowania treści w ramach serwera W W W ani odczytywania poczty
z serwera pocztowego — i w ogóle korzystania z usług obu tych serwerów (oczywiście, z wy-
jątkiem usług będących przedmiotem dwóch pierwszych reguł). Dla czytelności i dla celów
niezawodności fakt ten został wyartykułowany w postaci trzech następnych reguł blokujących
pakiety (wiersze 5 - 7 w tabeli 7.3).
3
„Ciągu", a nie „zbiom", ponieważ istotna jest kolejność stosowania poszczególnych reguł — przyp. tłum.
316 Rozdział 7. • Projekt systemu: realizacja celów projektowych
Rysunek 7.7. Zapora sieciowa filtrująca pakiety: filtr zlokalizowany w routerze decyduje o akcepto-
waniu lub odrzucaniu poszczególnych pakietów na podstawie zawartej w nich informacji
Tabela 7.5. Uproszczony przykład ciągu reguł filtrowania pakietów dla zapory widocznej na rysunku 7.7
Gdy liczba aktorów jest duża, ciąg reguł filtrujących jest znacznie bardziej zwarty od list
kontroli dostępu i list uprawnień; co więcej, niewielki stosunkowo ciąg reguł jest bardziej
czytelny i łatwiejszy do zrozumienia (oraz udowodnienia poprawności) przez człowieka, co
w przypadku systemu o wysokich wymaganiach w kwestii bezpieczeństwa jest czynnikiem
krytycznym.
Niezależnie od konkretnej implementacji, macierz dostępu reprezentuje statyczną po-
litykę dostępu. Oznacza to, że reguły dostępu mogą być modelowane w postaci atrybutów
obiektów systemu. W naszym przykładowym systemie bankowym przyjrzyjmy się brokerowi,
któremu przydzielono zbiór portfolio. Z założenia żaden broker nie ma dostępu do portfolio
zarządzanych przez innych brokerów. W tej sytuacji uprawnienia dostępu brokerów do po-
szczególnych portfolio mają charakter dynamiczny i jako takie muszą być modelowane. Na
6
„Dowolny" oznacza jakikolwiek komputer w internecie lub intranecie, również wspomniany ser-
wer W W W i serwer pocztowy.
7.4. Aktywności realizacji celów projektowych 317
rysunku 7.8 widzimy przykład realizacji' takiego modelu przy użyciu wzorca projektowego
Proxy (patrz sekcja A.8 i wspominana już książka E. Gammy i innych [Gamma i in., 1994]).
Dla każdego portfolio definiujemy mianowicie chroniący je przed nieuprawnionym dostępem
obiekt Portfol ioProxy. Skojarzenie Access między uprawnionym brokerem a obiektem
Portfol i oProxy reprezentuje próbę dostępu brokera do tegoż obiektu. Broker w celu uzyska-
nia dostępu do odpowiedniego portfolio wysyła odpowiedni komunikat do proxy chroniącego
to portfolio; proxy sprawdza najpierw istnienie skojarzenia ze wspomnianym brokerem i jeśli
skojarzenie takie istnieje, komunikat delegowany jest do odpowiedniego portfolio (przy braku
skojarzenia komunikat jest blokowany i próba dostępu kończy się niepowodzeniem).
Rysunek 7.8. Dynamiczna kontrola dostępu implementowana za pomocą ochronnego proxy. Klasa
skojarzeniowa Access zawiera zbiór operacji wykorzystywanych przez brokera do uzyskania dostępu do
konkretnego portfolio. Każda z operacji wywołuje operację i sAccessi bl e ( ) w celu sprawdzenia, czy
żądanie dostępu jest legalne, i zależnie od wyniku tego sprawdzenia komunikat wysłany przez brokera
jest delegowany do docelowego obiektu Portfol i o lub blokowany. Pojedyncze skojarzenie Access może
być używane do kontrolowania dostępu do wielu portfolio (stąd skojarzenie „jeden na wiele")
znać hasła, trzeba jeszcze posiadać odpowiednią kartę. Kolejnymi zabezpieczeniami mogą
być detektory cech biometrycznych: czytniki linii papilarnych czy analizatory gałek ocznych
— utożsamienie się pod względem tych wzorców z legalnym użytkownikiem jest dla intruza
znacznie trudniejsze niż kradzież karty chipowej.
W środowisku, w którym zasoby współdzielone są przez wielu użytkowników, uwie-
rzytelnianie nie zawsze okazuje się wystarczającym zabezpieczeniem. W środowisku siecio-
wym na przykład łatwo intruzowi podsłuchiwać (za pomocą odpowiednich narzędzi) pakiety
generowane przez innych użytkowników (patrz rysunek 7.9). Tak się niedobrze składa, że po-
wszechnie dziś używane protokoły sieciowe, takie jak TCP/IP, nie był)' projektowane ze szcze-
gólną troską o bezpieczeństwo: intruz może fabrykować pakietv tak, by wyglądały jak gene-
rowane przez legalnych użytkowników.
Rysunek 7.9. Atak bierny: wykorzystując obecną technologię, pasywny intruz może podsłuchiwać
cały ruch sieciowy. Aby utrudnić m u działania destruktywne, szyfruje się przesyłaną informację, co
sprawia, że staje się trudna do zrozumienia
Listing 7.1. Przykład sterowania proceduralnego (w języku Java): widoczny kod wypisuje kolejne
komunikaty i po każdym z nich oczekuje na wprowadzenie danych
• Sterowanie zdarzeniowe. W ramach tego schematu (patrz listing 7.2) w głównej pętli
powtarzany jest cykl obejmujący oczekiwanie na (dowolne) zdarzenie i po jego
wystąpieniu przekazanie go do obsługi przez odpowiednie obiekty, określone na pod-
stawie zawartości komunikatu informującego o wspomnianym wystąpieniu. Zaletą
takiego rozwiązania jest scentralizowanie wprowadzania informacji wejściowej
w pojedynczej, głównej pętli, co prowadzi do prostszej struktury programu. Bardziej
skomplikowane staje się natomiast implementowanie wielokrokowych sekwencji.
320 Rozdział 7. • Projekt systemu: realizacja celów projektowych
Listing 7.2. Przykład sterowania zdarzeniowego (w języku Java). W każdym obrocie głównej pętli ze
strumienia eventStream pobierany jest komunikat związany z kolejnym zdarzeniem i przekazywany
do obiektów zainteresowanych wystąpieniem tego zdarzenia
Listing 7.3. Przykład wielowątkowej obsługi zdarzeń (w języku Java). Obiekt eventHandl er, dedykowany
obsłudze zdarzeń, posiada metodę run (), wywoływaną w rezultacie uruchomienia nowego wątku
Thread thread;
Event event;
EventHandler eventHandl er;
boolean done;
/ * •••*/
while ('.done) {
event = eventStream.getNextEvent();
eventHandler = new EventHandler(event)
thread = new Thread(eventHandler);
thread.start();
}
* j
7
Patrz sekcja 6.3.2 — przyp. tłum.
322 Rozdział 7. • Projekt systemu: realizacja celów projektowych
Ogólnie rzecz biorąc, zdarzeniem wyjątkowym jest błąd zaistniały w czasie wykonywania
systemu. Zdarzenia takie mogą być powodowane trzema podstawowymi przyczynami. Oto one.
• Awaria sprzętu. Sprzęt starzeje się i od pewnego momentu zaczyna być coraz bardziej
zawodny; awaria dysku twardego może prowadzić do nieodwracalnej utraty danych,
awaria routera może spowodować nagłe zerwanie połączenia.
• Zmiany w środowisku operacyjnym. Praca systemu uzależniona jest od wielu ele-
mentów jego środowiska. System mobilny może utracić połączenie z serwerem, gdy
antena modemu znajdzie się poza zasięgiem nadajnika; awaria zasilania może mo-
mentalnie unieruchomić system, jeśli komputer pozbawiony jest możliwości na-
tychmiastowego, automatycznego przełączenia się na zasilanie bateryjne.
• Błędy w oprogramowaniu. Taki błąd, nawet gdy występuje tylko w obrębie jednego
komponentu, może potencjalnie załamać cały system. Mimo iż całkowite wyelimi-
nowanie błędów z oprogramowania jest niedoścignionym ideałem, można jednak
uodpornić każdy podsystem na przewidywane błędy, które potencjalnie mogłyby
wystąpić w nim i w pozostałych podsystemach.
Obsługa sytuacji wyjątkowych to sposób traktowania takich sytuacji przez system i me-
chanizm realizujący owo traktowanie. I tak w przypadku wprowadzenia przez użytkownika
błędnych danych najbardziej rozsądną reakcją wydaje się wyświetienie komunikatu wyjaśniają-
cego użytkownikowi przyczynę błędu i zachęcającego do ponownego wprowadzenia danych,
tym razem poprawnych. W przypadku awarii sieci system może zachować informację o swym
bieżącym w stanie, by wznowić pracę, gdy sieć ponownie zacznie prawidłowo funkcjonować.
Rozpatrzmy jako przykład system nawigacyjny samochodu, pobierający na żądanie
informacje z centralnego komputera; gdy samochód wjedzie do tunelu, transfer informacji
może zostać przerwany, w wyniku czego warstwa sieciowa8 nie będzie mogła sformować kolej-
nego pakietu, co zasygnalizuje przez zgłoszenie wyjątku („niespodziewane zamknięcie gniazda").
8
Poszczególne warstwy sieciowego modelu odniesienia OSI-ISO przedstawione są na rysunku 6.10
— przyp. tłum.
7.4. Aktywności realizacji celów projektowych 325
Rysunek 7.11. Administracyjne przypadki użycia dla systemu MyTri p. Przypadek użycia ManageDrivers
wywoływany jest w celu dodawania, usuwania lub modyfikowania danych dotyczących kierowców (nazw,
haseł, historii transakcji, generowanych kluczy szyfrowania), przypadek ManageMaps — w celu dodawania,
usuwania i modyfikowania m a p służących do generowania tras, natomiast przypadek ManageServer
obejmuje wszelkie funkcje związane z uruchamianiem i zamykaniem serwera
326 Rozdział 7. • Projekt systemu: realizacja celów projektowych
Rewizja modelu przypadków użycia, w postaci dodania trzech przypadków, nie wpłynęła
na dekompozycję systemu, dodaliśmy jednak nowe przypadki użycia do istniejących podsys-
temów: podsystem MapDBStoreSubsystem obarczony został obowiązkiem sprawdzania, czy jego
poprzednie użytkowanie zakończyło się poprawnym zamknięciem — jeżeli nie, musi on wykonać
kolejne zadanie: sprawdzić spójność danych i w razie potrzeby przywrócić ich poprawną po-
stać. Oczywiście, fakt ten znajduje swe odzwierciedlenie w opisie podsystemu (patrz tabela 7.7).
• Czy istnienie każdego podsystemu da się uzasadnić przez przypadek użycia lub wy-
maganie pozafunkcyjne?
• Czy każdy przypadek użycia może być odwzorowany w podzbiór zdefiniowanych
podsystemów?
• Czy każdy cel projektowy można wywieść z wymagania pozafunkcyjnego?
• Czy każde wymaganie pozafunkcyjne zostało uwzględnione w modelu projektu
systemu?
• Czy dla każdego aktora zdefiniowano zasady kontroli dostępu?
• Czy wszystkie zasady kontroli dostępu spójne są z wymaganiami pozafunkcyjnymi
dotyczącymi bezpieczeństwa i zabezpieczeń?
Model jest spójny, jeśli jest niesprzeczny, co sprowadza się do następujących kwestii:
Wreszcie, model jest czytelny, jeśli zrozumiały jest dla programistów nieuczestniczących
w jego tworzeniu. Czytelność modelu przekłada się na następujące pytania:
W przypadku wielu projektów daje się zauważyć częściowe nakładanie się projektowa-
nia systemu i jego implementowania; przykładowo w celu oceny i weryfikacji nowych tech-
nologii tworzy się prototypy wybranych podsystemów, zanim jeszcze ustabilizuje się architek-
tura systemu. Konsekwencją tego jest wiele przeglądów cząstkowych zamiast pojedynczego
przeglądu klienckiego związanego z akceptacją modelu analitycznego. Mimo iż takie po-
dejście sprawia, że projekt staje się bardziej elastyczny, wymaga od programistów bardziej
uważnego traktowania otwartych problemów. Rozwiązywanie wielu trudnych problemów
odkłada się na później nie dlatego, że są trudne, lecz ze względu na to, iż zdają się burzyć
względny ład istniejący w procesie.
Pierwsza sekcja dokumentu SDD jest wprowadzeniem. Jej przeznaczeniem jest dostar-
czenie krótkiego opisu architektury oprogramowania i celów projektowych. Zawiera także
odwołania do innych dokumentów (między innymi powiązanego dokumentu RAD) i infor-
mację o identyfikowalności (powołanie się na istniejące systemy czy ograniczenia dotyczące
architektury).
Sekcja druga opisuje architekturę istniejącego systemu, który ma zostać zastąpiony przez
tworzony system. Jeśli nowy system tworzony jest od zera, można w tym miejscu zawrzeć
przegląd architektur stosowanych w podobnych systemach. Celem tej części jest jawne wyar-
tykułowanie informacji, na jakich opierają się architekci systemu, przyjmowanych przez nich
założeń oraz problemów, jakie nowy system ma rozwiązywać.
Trzecia sekcja, poświęcona modelowi projektu nowego systemu, podzielona jest na siedem
następujących części:
Ważne jest, by projektowaniem systemu zajmowali się ludzie, którzy w naturalny sposób
ponosić będą konsekwencje podejmowanych przez siebie decyzji. Zespół architektoniczny
rozpoczyna swą pracę, gdy tylko ustabilizuje się model analityczny, i funkcjonuje, aż do fazy
integrowania systemu; stanowi to zachętę dla jego członków do przewidywania potencjalnych
problemów, jakie pojawić się mogą w związku z tym integrowaniem.
Oto kilka najważniejszych ról, jakie przypisane zostają członkom zespołu architek-
tonicznego:
• Rozmiar. Liczba problemów, z jakimi przychodzi się zmagać, rośnie w miarę postępu
w projektowaniu. Zwiększa się liczba elementów, jakimi manipulować muszą pro-
gramiści: każdy aspekt funkcjonalny wymaga uwzględnienia wielu operacji na wielu
obiektach. Dodatkową komplikację stanowi analizowanie wielu projektów i rozpo-
znawanie szczegółów nowych technologii.
332 Rozdział 7. • Projekt systemu: realizacja celów projektowych
Niezależnie od tego, jak starannie i jakim kosztem wykonany został projekt systemu,
kształt dekompozycji systemu i interfejsy podsystemów prawie na pewno zmieniać się będą
w fazie implementacji. Przyczyną tego będzie nie tylko coraz lepsze rozumienie systemu przez
programistów i odkrywane w związku z tym możliwości ulepszenia projektu, lecz także
pojawienie się nowych technologii i nowych pakietów zawierających gotowe rozwiązania.
Programiści powinni być świadomi tego faktu i muszą zarezerwować sobie trochę czasu na
uaktualnienie dokumentu SDD przed przystąpieniem do integrowania systemu.
9
Prototyp pionowy (wertykalny) to kompletna implementacja wąskiego wycinka funkcjonalności,
zwykle związanej z określonym przypadkiem użycia i jego obiektami brzegowymi, encji i sterującymi.
Prototyp poziomy (horyzontalny) jest natomiast częściową implementacją szerokiego zakresu funkcjo-
nalności, na przykład implementacją jedyne obiektów brzegowych obszernego zbioru przypadków użycia.
7.6. Analiza przypadku — system ARENA 335
Rysunek 7.12. Pierwszy fragment wyniku dekompozycji systemu ARENA — podsystemy odpowie-
dzialne za część organizacyjną
10
Patrz http://pl.wikipedia.org/wiki/Strategiczna_gra_turowa — przyp. tłum.
338 Rozdział 7. • Projekt systemu: realizacja celów projektowych
Rysunek 7.13. Drugi fragment wyniku dekompozycji systemu ARENA — podsystemy odpowiedzialne
za rozgrywanie gier
realizujący logikę aplikacji, przechowywanie danych i tym podobne, czyli ogólnie udostępniają-
cy usługi systemu ARENA. Podsystemy ArenaCl ient i MatchFrontEndPeer zlokalizowane będą
bezdyskusyjnie na węźle UserMachi ne. Co się tyczy pozostałych podsystemów, to przy założeniu
niewielkiego obciążenia ze strony użytkowników mogłyby one być zlokalizowane na poje-
dynczym węźle ServerMachine; mając jednak na względzie postulat skalowalności systemu,
definiujemy kolejny podsystem Adverti sementServer dedykowany przesyłaniu banerów
reklamowych do przeglądarki i przypisujemy podsystemy Adverti sementServer, GamePeer,
ArenaStorage i ArenaServer do odrębnych procesów, z których każdy może być realizowany
na oddzielnym węźle ServerMachine. W komponencie ArenaServer zagnieżdżamy pod-
systemy TournamentManagement, UserManagement i GameManagement (patrz rysunek 7.14).
Dla realizacji części organizacyjnej' systemu ARENA wybraliśmy środowisko Java EE. Sta-
nowi ono kolekcję interfejsów i standardów opracowanych przez firmę Sun Microsystems oraz
siłami wspólnoty entuzjastów, a umożliwia tworzenie wieloplatformowych systemów w języku
Java. Zaletą języka Java jest jego implementacja w szeregu produktów, zarówno komercyjnych,
jak i klasy open source, co ułatwia pogodzenie dwóch sprzecznych wielkości: skali (mierzonej
liczbą graczy, lig i turniejów) oraz kosztów (związanych między innymi z licencjonowaniem
komponentów). Ponadto komponenty klasy open source mają zwykle to do siebie, że łatwo się
je instaluje, a administrowanie nimi nie wymaga zaawansowanej wiedzy.
Podsystem ArenaCl ient fizycznie realizowany jest w postaci przeglądarki WWW, na-
tomiast ArenaServer i powiązane z nim podsystemy dostępne są za pośrednictwem serwera
WWW. Do realizacji tych podsystemów użyliśmy dwóch składników środowiska Java EE:
Java Servlets i Java Server Pages (JSP) jako głównej technologii implementowania obiektów
brzegowych. Klasy Java Servlets, zlokalizowane w węźle ServerMachi ne, przetwarzają żądania
otrzymywane z serwera WWW, produkując w odpowiedzi strony w języku HTML. JSP jest
natomiast zwięzłym narzędziem do programowania serwletów w języku zbliżonym do HTML,
który następnie przetwarzany jest przez preprocesor; wykorzystamy JSP do realizacji obiek-
tów brzegowych systemu ARENA. Obiekty brzegowe odwoływać się będą do metod obiektów
encji i obiektów sterujących, zrealizowanych także z użyciem klas Java Foundation.
Po zidentyfikowaniu podsystemów, współbieżności i odwzorowania sprzętowo-
programowego zajmijmy się teraz zarządzaniem obiektami trwałymi.
oraz jego przepustowość (gdy jedno żądanie oczekuje na odpowiedź od podsystemu bazy
danych, inne mogą być przetwarzane przez procesor). Wybór paradygmatu wielowątkowego
skutkuje jednak większą złożonością systemu, wynikającą z konieczności synchronizowania
współbieżnych wątków. W systemie ARENA solidność rozwiązania w zakresie synchronizacji
przy dostępie do wspólnych danych zapewnić mają następujące założenia.
• Obiekty brzegowe nie powinny definiować żadnych pól. Obiekty brzegowe powinny
utrzymywać informację o stanie realizowanych żądań w lokalnych zmiennych, nie
w swych polach. Pozwoli to na uniknięcie zjawiska wyścigu („hazardu") w sytuacji,
gdy obiekt brzegowy współdzielony jest przez kilka wątków".
• Obiekty sterujące nie powinny być współdzielone przez wątki. Dla każdej sesji powi-
nien istnieć co najwyżej jeden obiekt sterujący, a użytkownicy nie powinni mieć
możliwości wysyłania równoległych żądań w tej samej sesji12. Reguła ta staje się
szczególnie istotna w odniesieniu do obiektów sterujących nieznikających po zakoń-
czeniu obsługi pojedynczego żądania.
• Obiekty encji nie powinny udostępniać bezpośrednio swoich pól. Wszelki dostęp do
tych pól musi odbywać się wyłącznie za pośrednictwem dedykowanych metod. Po-
nadto metody te powinny odwoływać się wyłącznie do pól tego obiektu, który zaini-
cjował ich wywołanie (identyfikowanego przez zmienną thi s), nie do pól w innych
instancjach tej samej klasy. W klasach zrealizowanych jako abstrakcyjne typy danych
(patrz sekcja 2.3.2) wszystkie pola powinny już być polami prywatnymi.
• Metody odczytujące lub modyfikujące stan obiektu powinny być synchronizowane.
Mechanizm synchronizacji dostarczany przez język Java zapewnia wówczas, iż dana
metoda wykonywana jest w danej chwili w ramach co najwyżej jednego wątku.
• Należy unikać zagnieżdżonych wywołań synchronizowanych metod, czyli wywoły-
wania jednej synchronizowanej metody w ciele innej synchronizowanej metody.
Takie zagnieżdżone wywołania stwarzają ryzyko wystąpienia zastoju (deadlock).
Gdy wywołań talach nie sposób uniknąć w obecnej postaci metod, programiści po-
winni dokonać tego poprzez ich rozdrobnienie albo przynajmniej wymusić określoną
kolejność wywoływania uzależnionych metod synchronizowanych 13 .
• Redundantne informacje o stanie obiektu powinny być opatrywane znacznikami
czasowymi. Gdy dwóch użytkowników przystępuje równocześnie do modyfikowania
stanu tego samego obiektu trwałego, informacja o tym stanie znajduje się w trzech
różnych miejscach: w bazie przechowującej ów obiekt i w formularzach obu użyt-
kowników. Te dwie ostatnie instancje informacji powinny być opatrzone znacznikiem
wskazującym chwilę ich wysłania, co ułatwi rozstrzygnięcie konfliktu między nimi.
11
Każdy wątek posiada wtedy własny, oddzielny zestaw zmiennych lokalnych, dzięki czemu po-
szczególne wątki nie interferują ze sobą; pola obiektu są natomiast wspólne dla wszystkich wątków
— przyp. tłum.
12
Czyli formułowania kolejnego żądania przed zakończeniem obsługi poprzedniego — przyp. tłum.
13
Wymuszenie określonej kolejności żądania zasobów przez równoległe wątki jest jedną ze standar-
dowych metod unikania zastojów — przyp. tłum.
7.6. Analiza przypadku — system ARENA 343
• Decydując się na wybór jednego z dwóch podsystemów jako docelowego dla nowej
usługi, staramy się koncentrować funkcjonalność w podsystemie, w którym definio-
wany jest obiekt sterujący odnośnego przypadku użycia. Z jednej strony, prowadzi
to do dużej spoistości podsystemu, z drugiej jednak, stwarza ryzyko jego nadmiernej
komplikacji.
• Definiowanie usług na bazie poszczególnych kroków przypadku użycia prowadzi do
drobnoziarnistych usług. Mimo iż drobnoziarnistość ta może być znakomitym spraw-
dzianem dla dokonanej dekompozycji, to jednak jej konsekwencją jest duża liczba
interfejsów dedykowanych pojedynczym operacjom. To znak, że zbyt szybko zbli-
żamy się do etapu projektowania obiektów. Należy wówczas zastanowić się nad
konsolidacją powiązanych ze sobą usług w pojedyncze usługi, co pozwoli zachować
stopień abstrakcji właściwy dla poziomu architektury systemu i jednocześnie zapo-
biegnie utracie czytelności modelu. Staranne wybieranie dla usług odpowiednich
nazw, w postaci rzeczowników oznaczających kolekcje operacji, może stanowić
czynnik przeciwdziałający wspomnianemu rozdrobnieniu.
Rysunek 7.15. Część organizacyjna dekompozycji systemu ARENA, widoczne są zidentyfikowane usługi.
Dla przejrzystości zrezygnowaliśmy z uwidocznienia zależności między podsystemami
7.6. Analiza przypadku — system ARENA 345
Tabela 7.9. Dodatkowe, graniczne przypadki użycia związane z obiektami trwałymi systemu ARENA
Jak to widać na diagramie wdrażania z rysunku 7.14, system ARENA zawiera pięć
komponentów wykonawczych: WebBrowser, ArenaServer (zawierający pięć podsystemów
— UserManagement, GameManagement, TournamentManagement, Notification i ArenaStorage),
346 Rozdział 7. • Projekt systemu: realizacja celów projektowych
System ARENA może w swej pracy doświadczyć awarii dających się sklasyfikować w ra-
mach czterech następujących kategorii:
• awaria sieci powodująca zerwanie jednego lub wielu połączeń między instancjami
podsystemów MatchFrontEndPeer i GamePeer,
• awaria hosta lub komponentu, wskutek której nieoczekiwanie przerwana zostaje
praca jednej lub wielu instancji podsystemu MatchFrontEndPeer lub GamePeer,
• awaria sieci powodująca zerwanie jednego lub wielu połączeń między instancja-
mi podsystemów WebBrowser i ArenaServer,
• awaria serwera powodująca nagłe przerwanie pracy komponentu ArenaServer.
Obsługę dwóch pierwszych klas zdecydowaliśmy się powierzyć obiektom Game repre-
zentującym konkretne gry. Co prawda, wyposażymy komponenty MatchFrontEndPeer
i GamePeer w generyczne metody przywracania zerwanych połączeń i przywracania stanu
przerwanych meczów, jednakże szczegółowa reakcja na zerwanie połączenia zależna jest
od specyfiki konkretnej gry: gry symulacyjne i gry rozgrywane w czasie rzeczywistym muszą
zostać zakończone lub ponownie rozpoczęte, podczas gdy w przypadku gier planszowych
krótkotrwałe utraty połączeń mogą być nawet niezauważalne dla graczy. Pozostawiliśmy
zatem twórcom gier swobodę w zakresie postępowania z awariami tego typu.
7.6. Analiza przypadku — system ARENA 347
Tabela 7.11. Dodatkowe, graniczne przypadki użycia związane z awariami systemu ARENA
7.6.9. Wnioski
W zakończonej właśnie sekcji przeanalizowaliśmy problemy związane z projektem systemu
ARENA. Zidentyfikowaliśmy cele projektowe i nadaliśmy im priorytety, dokonaliśmy de-
kompozycji systemu, odwzorowaliśmy poszczególne podsystemy w komponenty i platformę
sprzętowo-programową, wybraliśmy strategię przechowywania trwałych danych, zdefiniowa-
liśmy założenia kontroli dostępu do obiektów systemu, dostarczyliśmy rozwiązania najważ-
niejszych problemów związanych ze współbieżnością, wreszcie skonstruowaliśmy przypadki
użycia odzwierciedlające obsługę sytuacji granicznych i wyjątkowych. Na podstawie przepro-
wadzonej analizy mogliśmy się przekonać, że:
7.8. Ćwiczenia
7.1. Rozpatrzmy system złożony z serwera W W W i dwóch serwerów bazodanowych.
Oba serwery bazodanowe są identyczne: pierwszy funkcjonuje jako główny serwer,
drugi — jako redundantny serwer zapasowy, włączany w przypadku awarii pierw-
szego. Użytkownicy wykorzystują przeglądarkę W W W w celu dostępu do danych,
za pośrednictwem — oczywiście — serwera WWW, lecz mają także do dyspozycji
dedykowane narzędzie, umożliwiające dostęp do serwera bazodanowego w sposób
bezpośredni. Narysuj diagram wdrażania UML przedstawiający odwzorowanie tego
systemu w węzły sprzętowo-programowe.
Bibliografia 349
7.2. Producent samolotów posługuje się przestarzałym, opartym na faksie systemem ra-
portowania błędów. Ty uczestniczysz w projekcie zastąpienia tego systemu syste-
mem komputerowym, obejmującym bazę danych i podsystem powiadamiania. Klient
wymaga, by faks nadal pozostał urządzeniem wejściowym, Ty proponujesz e-mail
jako narzędzie wprowadzania problemów do systemu. Opisz dekompozycję systemu
uwzględniającą interfejsy dla obu tych rozwiązań. Weź pod uwagę fakt, że inten-
sywność raportowania problemów może być bardzo duża (2000 faksów dziennie).
7.3. Wyobraź sobie, że projektujesz założenia kontroli dostępu dla systemu realizującego
sklep internetowy. Klienci, kontaktujący się ze sklepem za pośrednictwem przeglą-
darki WWW, mogą przeglądać ofertę towarów, wprowadzać swoje dane osobowe
i informacje na temat płatności, i — oczywiście — kupować towary. Dostawcy mogą
rejestrować nowe produkty, modyfikować informacje o swoich produktach i przyj-
mować zamówienia. Właściciel sklepu ustala ceny detaliczne, formułuje zróżnico-
wane oferty dla poszczególnych klientów, bazując na ich profilach, i świadczy usługi
marketingowe. W systemie tym należy uwzględnić trzech aktorów: administratora
(StoreAdmi ni s t r a t o r ) , dostawcę (Supplier) i klienta (Customer). Zaprojektuj listy
uprawnień dla każdego z wymienionych aktorów. Nowi klienci mogą sami rejestro-
wać się za pośrednictwem WWW, lecz nowych dostawców rejestrować może tylko
administrator.
7.4. Zaproponuj najbardziej odpowiedni mechanizm przepływu sterowania dla każdego
z wymienionych poniżej podsystemów. Ponieważ w większości przypadków wybór
nie jest oczywisty, uzasadnij swoje preferencje.
® Serwer W W W zdolny wytrzymać długotrwałe duże obciążenie.
® Interfejs GUI procesora tekstów.
• Osadzony (wbudowany) system czasu rzeczywistego, na przykład system ste-
rowania startem satelity.
7.5. Dlaczego graniczne przypadki użycia nie są konstruowane na etapie zbierania wy-
magań ani na etapie ich analizy?
7.6. Projektujesz właśnie podsystem cache'owania informacji pobieranych z internetu
(lub innej sieci) na szybszym nośniku, na przykład dysku twardym. W związku ze
zmianami w wymaganiach zamierzasz wyposażyć swój podsystem w nową usługę
konfiguracyjną, umożliwiającą ustalanie parametrów cache'owania (na przykład
maksymalnej wielkości przestrzeni dyskowej, jaką można zużyć na potrzeby tego
cache'owania). Których uczestników projektu powinieneś powiadomić o tej zmianie?
Bibliografia
[Bass i in., 2003] L. Bass, P. Clements, R. Kazman Software Architecture in Practice,
wyd. drugie, Addison-Wesley, Reading, MA, 2003.
[Błaha i Premerlani, 1998] M. Błaha, W. Premerlani Object-Oriented Modeling and Design for
Database Applications, Prentice Hall, Upper Saddle River, NJ, 1998.
[Siewiorek & Swarz, 1992] D. P. Siewiorek, R. S. Swarz Reliable Computer Systems: Design
and Evaluation, wyd. drugie, Digital, Burlington, MA, 1992.
8.1. Wstęp: wpadki produkcyjne 354
Bibliografia 396
Projektowanie obiektów:
wielokrotne
wykorzystywanie
rozwiązań wzorcowych
Oszukujesz, jeśli nie doceniasz wkładu innych.
— Uniwersytet Carnegie Mellon, kurs 15-413
„Introduction to Software Engineering"
(http:// www. cs. cm u.edul-ałdrichlcourses!413!)
Projektowanie obiektów, podobnie jak projektowanie systemu, nie jest procesem algo-
rytmicznym: sednem rozwiązania problemu staje się właściwa identyfikacja dostępnych wzor-
ców i komponentów — związane z tym aktywności są właśnie treścią tego i dwóch następ-
nych rozdziałów. W tym rozdziale skupimy się na wykorzystywaniu gotowych rozwiązań,
w następnym zajmiemy się specyfikowaniem usług; w rozdziale 10. omówimy zabiegi doty-
czące optymalizacji modelu.
354 Rozdział 8. • Projektowanie obiektów: wielokrotne wykorzystywanie rozwiązań wzorcowych
Titanic (1997)
Jack, prosty rybak, uczy Rose, damę z wyższych sfer, trudnej sztuki plucia. Pokazuje jej tajniki tej
sztuki i zachęca do praktykowania, gdy nagle zjawia się matka Rose. Gdy Jack zaczyna odwracać się
do niej, ma twarz całkiem czystą; za chwilę jednak, gdy zwrócony jest w stronę matki Rose, widzimy
ślady oplucia na jego podbródku. Budżet filmu: 200 milionów dolarów.
Podobne wpadki zdarzają się w wielu filmach, co — zważywszy na budżet ich realizacji
i na banalny w gruncie rzeczy charakter wspomnianych niedopatrzeń — może wydawać się
cokolwiek zdumiewające. Produkcja filmu jest jednak przedsięwzięciem skomplikowanym
znacznie bardziej, niż mogłoby się to wydawać w pierwszej chwili.
Przysłowiowe licho, które nie śpi i tylko podstępnie czyha na biednych realizatorów, kon-
spiruje ukryte pod wieloma czynnikami. Przy kręceniu i produkcji filmu współpracuje mnó-
stwo ludzi, sceny kręcone są zwykle w kolejności innej od tej, w jakiej następują w scenariuszu,
niektóre „dokręcane" są poza harmonogramem; szczegóły — kostiumy, rekwizyty — zmie-
niają się w czasie zdjęć. Po nakręceniu scen, gdy film jest edytowany i montowany, występuje
silna presja na ukończenie prac w założonym terminie. Kolejne sceny muszą być nagrywane
w sposób spójny — stan każdej sceny musi być zgodny ze stanem scen poprzedzających ją
i następujących po niej. Ów „stan" obejmuje mnóstwo drobiazgów: od ubioru aktora, jego fry-
zury, makijażu, biżuterii, aż po elementy otoczenia odbijające się w szkłach jego okularów. Gdy
w którejś ze scen następuje jakaś istotna zmiana, na przykład pojawienie się lub zniknięcie
rekwizytu, nie może ona pozostawać w sprzeczności z żadną z pozostałych scen. Gdy poje-
dyncze sceny integrowane są ze sobą, nad zachowaniem opisywanej spójności czuwa osoba
zwana „redaktorem ciągłości" (continuity editor).
Nie bez powodu nawiązujemy tu do świata filmu, bowiem tworzenie systemu informa-
tycznego ma w sobie coś z kręcenia i montowania filmu: jest skomplikowane, podatne na
zmiany i odbywa się pod presją harmonogramu. Etap projektowania obiektów przypomina
jako żywo dokręcanie brakujących scen: jego istotą jest wypełnianie luki, jaka istnieje między
obiektami dziedziny aplikacyjnej, zidentyfikowanymi na etapie analizy wymagań, a sprzętowo-
-programową platformą wykonawczą, jaka określona została na etapie projektowania systemu.
8.2. O projektowaniu obiektów ogólnie 355
Rysunek 8.1. Projektowanie obiektów jako proces likwidujący przepaść między obiektami dziedziny
aplikacyjnej określonymi na etapie analizy a gotowymi k o m p o n e n t a m i wybranymi na etapie pro-
jektowania systemu
Projektowanie obiektów nie jest procesem sekwencyjnym. Mimo iż każda grupa wymie-
nionych powyżej aktywności dedykowana jest rozwiązywaniu specyficznego problemu,
aktywności poszczególnych grup realizowane są zazwyczaj równolegle. Gotowy komponent
„z półki" może na przykład narzucać ograniczenie na liczbę typów wyjątków i powodować ko-
nieczność zrewidowania interfejsu podsystemu. Wykorzystywanie gotowych komponentów
przyczynia się do redukcji wysiłku programistów, wymaga jednak zwykle konstruowania nowych
obiektów spajających owe komponenty z resztą systemu. Wreszcie, restrukturyzowanie i opty-
malizowanie modelu może prowadzić do zmniejszenia liczby obiektów wymagających im-
plementacji, dzięki zwiększeniu stopnia wielokrotnego wykorzystywania tego samego kodu.
Zazwyczaj specyfikowanie interfejsów i poszukiwanie możliwości wykorzystywania
gotowych komponentów oraz gotowego kodu odbywa się w pierwszej kolejności. Dostajemy
wówczas model projektu obiektów i weryfikujemy go za pomocą przypadków użycia związa-
nych z konkretnym podsystemem. Restrukturyzacje i optymalizacje są odpowiednie raczej dla
1
Różnica między zamkniętą a otwartą architekturą warstwową wyjaśniona jest w sekcji 6.3.4 — przyp. tłum.
358 Rozdział 8. • Projektowanie obiektów: wielokrotne wykorzystywanie rozwiązań wzorcowych
Wspaniale! Mamy wszystko, czego potrzeba, bez wielkiego wysiłku — wszystko, czego
potrzebujemy, wzięliśmy żywcem z klasy Hashtabl e. Hojne dziedziczenie okazało się jednak
nazbyt hojne i przez to zdradliwe: nasza klasa MySet posiada bowiem także elementy, które
mogą stać się przyczyną poważnych kłopotów. Zauważmy, że klasa MySet dziedziczy po klasie
Hashtable metodę containsKey(), która nie dość, że nie jest do niczego potrzebna, to do-
datkowo staje się przysłowiową kulą u nogi: funkcjonuje ona identycznie z (przedefiniowaną)
metodą containsValue(), więc programista wykorzystujący nową klasę ma prawo używać
tych dwóch metod zamiennie. Gdy w przyszłości zaimplementujemy klasę MySet w inny sposób,
362 Rozdział 8. • Projektowanie obiektów: wielokrotne wykorzystywanie rozwiązań wzorcowych
na przykład na bazie listy wiązanej, nieposiadającej metody containsKey(), kod aplikacji wy-
magać może daleko idących zmian. Owszem, można by przedefiniować metodę contai nsKey ()
tak, by jej wywoływanie generowało wyjątek, ale czytelności i zrozumiałości kodu raczej to nie
poprawi.
Dziedziczenie ma w sobie coś z obosiecznego miecza: z jednej strony, zmniejsza powią-
zanie między podobnymi klasami, „wyciągając" z nich wspólną funkcjonalność do wspólnej
superklasy, z drugiej jednak, generuje silne powiązanie tej superklasy z każdą z jej subklas.
I podczas gdy jest to zjawisko jak najbardziej pożądane w przypadku budowania hierarchii
opartej na taksonomii (jak w przypadku wspomnianej kolekcji obrazków), powiązanie takie
staje się kłopotliwe w innych sytuacjach. W naszym przykładzie relacja dziedziczenia wiąże ze
sobą klasy Hashtable i MySet, reprezentujące dwie różne koncepcje, co niesie ze sobą nieko-
rzystne konsekwencje co najmniej pod dwoma względami: po pierwsze, wszelkie modyfikacje
klasy Hashtable automatycznie odbijać się będą na klasie MySet, po drugie, potraktowanie
klasy MySet jako konkretyzacji (specjalizacji) klasy Hashtable może dawać dziwaczne re-
zultaty w przypadku zastąpienia (w kodzie programu) obiektu klasy Hashtable przez obiekt
klasy MySet. Wszystko to wynika z braku taksonomii między obiema klasami — po prostu
zbiór elementów nie jest szczególnym przypadkiem tablicy haszowanej.
Jeżeli mimo to sięgnęliśmy po dziedziczenie, zrobiliśmy to z zamiarem wykorzystania
gotowego kodu, gotowej implementacji. Relacja dziedziczenia, wykorzystywana w takim wła-
śnie celu, mimo różnic koncepcyjnych między powiązanymi klasami, nazywa się dziedzicze-
niem implementacyjnym. Zamiast pisać od zera własny kod nowej klasy, wykorzystuje się
gotowy, wzięty z innej klasy, co najwyżej poddając go niewielkim modyfikacjom. Dla odróż-
nienia, dziedziczenie mające swe odzwierciedlenie w taksonomii klas nazywane jest dzie-
dziczeniem specyfikacyjnym lub dziedziczeniem interfejsu. Widoczny na rysunku 8.4 dia-
gram klas ilustruje zależności między czterema różnymi typami dziedziczenia.
8.3.3. Delegowanie
Alternatywą dla dziedziczenia implementacyjnego jest delegowanie implementacji. Zamiast
wykorzystywać określoną metodę konkretnej klasy poprzez dziedziczenie, wywołujemy ją
najzwyczajniej, a dokładniej — wywołuje ją obiekt lub klasa, do którego to wywołanie delegu-
jemy. Na listingu 8.2 pokazaliśmy, jak można wykorzystać metodę containsKeyO klasy
Hashtabl e, nie wprowadzając w ogóle dziedziczenia po tej klasie: jak widać, jedyną znaczącą
zmianą jest pojawienie się prywatnego pola tabl e i jego inicjacja przez konstruktor; w wy-
niku wspomnianej inicjacji pole to wskazuje na obiekt klasy Hashtable, do którego metoda
contai nsVal ue () deleguje wywołanie metody contai nsKey (). Odzwierciedlenie tej sytuacji na
diagramie klas widoczne jest w prawej części rysunku 8.3.
class MySet {
private Hashtable t a b l e ;
MySet () {
t a b l e = Hashtabl e ( ) ;
}
void put(Object element) {
if (!containsValue(element)){
table.put(element,this);
}
}
boolean containsValue(Object element) {
return (table.containsKey(element));
)
... inne metody ...
Interpretacja
W odniesieniu do projektowania obiektowego zasada zastępowania Liskov oznacza, że jeśli wszystkie
klasy są podtypami swych superldas, to wszystkie relacje dziedziczenia między klasami są dziedzi-
czeniem specyfikacyjnym. Innymi słowy, wszystkie metody definiowane w danej superklasie mogą
być wywoływane zarówno na rzecz obiektów tejże superklasy, jak i obiektów jej dowolnej subklasy
— bez jakiejkolwiek informacji o tym, z którą klasą mamy aktualnie do czynienia. W praktyce ozna-
cza to, że dla dowolnej klasy możemy dowolnie definiować jej nowe subklasy, bez wpływu na kod
kliencki; w ten sposób realizuje się postulat rozszerzalności systemu. Jeżeli wszystkie subklasy dzie-
dziczą po swej superklasie, zgodnie z zasadą Liskov, mówimy wówczas o ścisłym dziedziczeniu.
Nawiązując do definiowania nowej Idasy MySet (patrz rysunek 8.3), chcielibyśmy uzy-
skać jej zgodność z istniejącym interfejsem (czy interfejsem Set języka Java), przy jednocze-
snym wykorzystaniu funkcjonalności kryjącej się w klasie Hashtable. Zarówno interfejs Set,
jak i klasa Hashtabl e są już zdefiniowane i ich definicji zmienić nie można, aby więc zrealizować
nasze zadanie, posłużymy się wzorcem projektowym o nazwie Adapter (patrz tabela 8.1
i sekcja A.2), szablonowym dla rozwiązywania problemów tego typu. Wzorzec ten funkcjonuje
następująco: ldasa adaptera (nazwijmy ją umownie Adapter) implementuje wszystkie metody
zadeklarowane w klasie klienckiej (Cl i e n t l n t e r f a c e ) w kategoriach żądań wysyłanych do
klasy istniejącej i niezmiennej (LegacyCl ass). Wszelkie konwersje danych, zachowania i tym
podobne właściwe dla klasy LegacyCl ass wykonywane są wewnątrz klasy Adapter, która
na zewnątrz zachowuje się dokładnie tak, jak oczekuje tego klient na podstawie interfejsu
Cl i e n t l n t e r f a c e . Tak oto udaje się pogodzić dwa niekompatybilne byty — interfejs Cl ient
"-•Interface i klasę LegacyCl ass — bez potrzeby modyfikowania któregokolwiek z nich.
Ponieważ ten sam Adapter może być użyty do wszelkich podtypów klasy LegacyCl ass
(zgodnie z zasadą zastępowania Liskov), wzorzec projektowy Adapter realizuje postulat roz-
szerzalności systemu. Odnosząc ten wzorzec do klasy MySet czyniącej zadość interfejsowi Set,
otrzymamy schemat odpowiadający delegowaniu przedstawionemu na listingu 8.2 (patrz
rysunek 8.5).
Zauważmy, że wzorzec projektowy Adapter wykorzystuje zarówno dziedziczenie, jak
i delegowanie. Reguła ta odnosi się zresztą do wielu wzorców projektowych, które na pierwszy
rzut oka mogą z tego powodu wyglądać łudząco podobnie, lecz jednak te same mechanizmy
używane są przez każdy z nich na różne sposoby, często różniące się subtelnymi szczegółami.
By zrozumieć te różnice, używać będziemy następujących określeń na poszczególne klasy
uwikłane we wzorzec projektowy.
Tabela 8.1. Przykład wzorca projektowego Adapter (zaczerpnięty z książki E. Gammy, R. Heima,
R. Johnsona i J. Ylissadesa [Gamma i in., 1994])
Opis problemu Konwersja interfejsu prezentowanego przez istniejącą klasę na inny interfejs
narzucony przez klienta, bez potrzeby modyfikowania zarówno wspomnianej
klasy, jak i wymagań klienta.
Konsekwencje ' Interfejs Cl i ent i klasa LegacyCl ass mogą współpracować ze sobą bez żadnych
modyfikacji.
• Ten sam Adapter może być zastosowany do wszelkich subklas klasy LegacyCl ass
• Dla każdej specjalizacji (subklasy) interfejsu Cl i ent konieczne jest utworzenie
osobnego Adaptera.
Rysunek 8.5. Zastosowanie wzorca projektowego Adapter do problemu implementacji klasy MySet
z rysunku 8.3
• Nowe widoki. Testowanie systemu przez jego użytkowników może obnażyć wiele
problemów związanych z użytecznością. Ich rozwiązywanie może wymagać stworze-
nia dodatkowych widoków dla istniejących danych.
• Zmiany w zakresie dziedziny aplikacyjnej. Podczas wdrażania systemu mogą obja-
wić się nowe pomysły o charakterze generalizacyjnym: przykładowo udane wdrożenie
systemu bankowego w jednym oddziale może stanowić impuls do stworzenia po-
dobnego systemu zarządzającego wieloma oddziałami równocześnie. Sama dziedzina
aplikacyjna też może ulegać przeobrażeniom: przykładowo, o ile poprzednio każdy
samolot identyfikowany był pojedynczym numerem lotu, to teraz, w konsekwencji
współpracy przewoźników, ten sam lot może być identyfikowany w inny sposób
u każdego przewoźnika i z pojedynczym samolotem może być w danej chwili zwią-
zany nie jeden, ale kilka różnych numerów lotu.
• Błędy. Gdy użytkownicy przystąpią do testowania systemu, mogą uwidocznić się błędy
(nawet liczne) w wymaganiach stawianych temu systemowi.
Tabela 8.2. Wybrane wzorce projektowe w powiązaniu z przyczynami zmian, przy których wprowa-
dzaniu mogą okazać się pomocne
dla podsystemu TournamentManagement. Obiekty encji będą doznawać jeszcze wielu zmian
i na tym etapie trudno zidentyfikować wszelkie „wąskie gardła" związane z ich przechowywa-
niem. W konsekwencji efektywny system przechowywania danych systemu nie jest na tym etapie
zagadnieniem numer 1 i w pierwszym prototypie systemu poprzestajemy na mechanizmie
„płaskich" plików. Jak jednak pisaliśmy w sekcji 7.6.4, w drugim prototypie przewidujemy jednak
opcję zastosowania relacyjnej bazy danych obok wspomnianych „płaskich" plików. Aby jak
najwcześniej można było rozpocząć testy integracyjne, przed ukończeniem implementowania
mechanizmów opartych na owych „płaskich" plikach potrzebne będą ich atrapy.
Zastosowanie wzorca projektowego Most do rozwiązania tego problemu przedstawione
jest na rysunku 8.6. LeagueStore jest klasą interfejsu tego wzorca, która dostarcza wysokopo-
ziomową funkcjonalność związaną z przechowywaniem danych. LeagueStorelmpl ementor
370 Rozdział 8. • Projektowanie obiektów: wielokrotne wykorzystywanie rozwiązań wzorcowych
Interfejs wzorca projektowego Most realizowany jest przez klasę3 Abstract! on*, zaś jego
zachowanie — przez jedną z klas Concretelmpl ementor-. Wzorzec może być rozszerzany
przez dostarczanie nowych klas RefinedAbstraction- lub Concretelmpl ementor. Stanowi on
klasyczny przykład połączenia dziedziczenia specyfikacyjnego z delegowaniem, dzięki czemu
zapewnia zarówno wykorzystywanie gotowych rozwiązań, jak i elastyczność. Z jednej strony,
relacja dziedziczenia specyfikacyjnego wiąże abstrakcyjny interfejs Impl ementor z klasami
Concretelmpl ementor, zatem każda z tych ostatnich może w programie stanowić substytut dla
klas Abstraction- i RefinedAbstraction-. Daje to jednocześnie zapewnienie, że programi-
ści, opracowując klasę Concretelmpl ementor, będą się starali upodobnić jej zachowanie do za-
chowania innych klas tej grupy. Z drugiej strony, między klasami Abstraction- i Impl ementor
istnieje relacja delegowania, co zapewnia dystrybucję różnego zachowania po obu stronach
mostu. Przykładowo klasa LeagueStore z rysunku 8.6 reprezentuje wysokopoziomowe aspekty
przechowywania danych związanych z poszczególnymi ligami, podczas gdy każda z klas grupy
2
W każdym „płaskim" pliku przechowywany będzie obraz jednego lub więcej obiektów, w formacie
XML — przyp. tłum.
3
W opisach zastosowań poszczególnych wzorców projektowych autorzy używają nazw pochodzących
z dwóch obszarów: bieżących rysunków rozdziału oraz terminologii zawartej w dodatku A. Dla lepszej
czytelności nazwy tej drugiej grupy wyróżnione są gwiazdką — przyp. tłum.
8.4. Wybór wzorców projektowych i gotowych komponentów 371
4
Przy tworzeniu systemu całkowicie „od zera" rzadko zdarza się, że trzeba użyć adapterów z tej
prostej przyczyny, że nowe ldasy definiować można od razu zgodnie z wymaganymi interfejsami.
372 Rozdział 8. • Projektowanie obiektów: wielokrotne wykorzystywanie rozwiązań wzorcowych
Rysunek 8.7. Zastosowanie wzorca projektowego Adapter do sortowania tablicy łańcuchów; patrz
także listing 8.3
Listing 8.3. Przykład zastosowania wzorca projektowego Adapter w języku Java. Statyczna metoda s o r t ()
klasy A r r a y wymaga dwóch a r g u m e n t ó w : s o r t o w a n e j tablicy e l e m e n t ó w (a) oraz k o m p a r a t o r a
porównującego elementy (c). Aby posortować tablicę elementów klasy MyStri ng, potrzebujemy komparatora
MyStri ngComparator zgodnego z interfejsem Comparator. Klasa MyStri ngComparator jest adapterem
}
/* istniejący klient */
class Array {
static void s o r t ( 0 b j e c t [] a , Comparator c);
}
/* nowa klasa - klasa adaptera */
class M y S t r i n g C o m p a r a t o r implements Comparator {
int c o m p a r e ( O b j e c t o l , O b j e c t o2) {
int r e s u l t ;
if ( ( ( S t r i n g ) o l ) . g r e a t e r T h a n ( o 2 ) ) {
result = 1
} else if ( ( ( S t r i n g ) o l ) . e q u a l s ( o 2 ) ) {
r e s u l t = 0;
} else (
result = -1;
}
8.4. Wybór wzorców projektowych i gotowych komponentów 373
return result;
}
}
sieciowych; kontekst (klasa Context ) realizowany jest przez obiekt NetworkConnection, repre-
zentujący połączenie „punkt-punkt" między komputerem przenośnym a zdalnym hostem.
Rolę klienta (Cl i ent-) pełni aplikacja pracująca na tym komputerze. Klasa ustalająca zasady
(Policy) reprezentowana jest tu przez klasę LocationManager, odpowiedzialną za moni-
torowanie dostępnych warunków połączenia w bieżącej lokalizacji i automatyczne wybieranie
odpowiedniej specjalizacji Networklnterface stosownie do tych warunków. Gdy obiekt klasy
LocationManager wywołuje metodę s e t N e t w o r k l n t e r f a c e Q , obiekt NetworkConnection
kończy pracę aktualnie wybranej implementacji i przełącza się na inną, w sposób przezro-
czysty dla reszty aplikacji.
Listing 8.4. Zastosowanie wzorca projektowego Strategia do hermetyzacji wielu implementacji interfejsu
N e t w o r k l n t e r f a c e (w języku Java). Dla uproszczenia pominęliśmy między innymi obsługę sytuacji
wyjątkowych, patrz także diagram klas na rysunku 8.8
W kontekście rysunków 8.6 i 8.8 wzorce Most i Strategia wydają się niemal identyczne.
Różnica między nimi kryje się w kreatorze klas implementujących interfejs: w ramach wzorca
Most klasy te (Concretelmpl ementati on-) tworzone są oraz inicjowane przez klasę Abstracti on-,
376 Rozdział 8. • Projektowanie obiektów: wielokrotne wykorzystywanie rozwiązań wzorcowych
do fabryki, reprezentowanej przez abstrakcyjny interfejs (tu HouseFactory); nie jest on przy
tym świadom konkretnej fabryki (EIBFactory albo LuxmateFactory) implementującej ów
interfejs. Ten właśnie szczegół ułatwia przystosowywanie aplikacji do specyfiki różnych
producentów — wystarczy zmienić implementację interfejsu HouseFactory, bez ingerowania
w resztę aplikacji.
Command• (na rysunku 8.10 jest to klasa Move). Klasa ta deklaruje operacje wykonywania, cofania
i rejestrowania poleceń, podczas gdy każda z klas ConcreteCommand- (czyli na przykład klasy
Ti cTacToeMove i ChessMove) implementuje specyfikę tych czynności dla konkretnej gry. Za-
pewnienie zarządzania ruchami dla nowo dodanej gry sprowadza się do zaimplementowania
stosownej subklasy klasy Move.
Rysunek 8.10. Zastosowanie wzorca projektowego Polecenie do rejestrowania historii meczów (Match)
w systemie ARENA
W miarę jak okna te stają się coraz bardziej skomplikowane i obejmują coraz więcej
kontrolek, zarządzanie nimi (przesuwanie, zmiana rozmiarów) w sposób zapewniający za-
chowanie układu i wyglądu stwarza coraz większe ryzyko wymknięcia się spod kontroli.
W związku z tym, nowoczesne narzędzia opisywanej kategorii umożliwiają programiście orga-
nizowanie interfejsu użytkownika w sposób hierarchiczny: wybrane kontrolki grupowane
zostają w panele, które same stają się złożonymi kontrolkami, bowiem każdym panelem zarządza
się tak samo jak „zwykłą" kontrolką. W naszym przykładowym oknie wyboru preferencji
(patrz rysunek 8.11) można wyodrębnić trzy takie panele: górny — obejmujący tytuł i krótką
instrukcję dla użytkownika, środkowy — zawierający kontrolki wyboru i opatrujące je etykiety
oraz dolny — zawierający przyciski OK i Cancel. Każdy panel odpowiedzialny jest za zawarte
w nim kontrolki i „podpanele", całe okno dialogowe ma więc do czynienia jedynie z trzema
panelami zamiast z kilkunastoma niezależnymi kontrolkami.
Rysunek 8.11. Anatomia okna wyboru preferencji. Agregaty zwane panelami grupują kontrolki w celu
ich skonsolidowanego zachowania się przy przemieszczaniu i zmianie rozmiaru okna
p r o j e k t o w e p o z o s t a j ą w z w i ą z k u z k o n k r e t n y m i celami p r o j e k t o w y m i i w y m a g a n i a m i p o z a -
f u n k c y j n y m i , m o ż n a p o k u s i ć się o i d e n t y f i k o w a n i e w z o r c ó w p r o j e k t o w y c h n a p o d s t a w i e
o k r e ś l o n y c h fraz języka n a t u r a l n e g o w y s t ę p u j ą c y c h w d o k u m e n t a c h analizy w y m a g a ń ( R A D )
8.4. Wybór wzorców projektowych i gotowych komponentów 381
Tabela 8.3. Heurystyczne reguły identyfikowania fraz języka naturalnego jako kandydatur na stoso-
wanie wzorców projektowych
Prawdopodobny
Fraza
wzorzec projektowy
„niezależność od dostawcy" Fabryka abstrakcyjna
„niezależność od platformy"
Frameworki aplikacyjne
realizowana jest za pomocą tak zwanych metod zahaczanych (hook methodsf, które mogą być
nadpisywane w docelowych aplikacjach. Metody zahaczane systematycznie oddzielają inter-
fejsy od konkretnego zachowania, specyficznego dla danej dziedziny aplikacyjnej, co daje
możliwość szybkiego implementowania nowych cech i usług.
Frameworki, pod względem usytuowania w ogólnym procesie tworzenia aplikacji, po-
dzielić można na trzy następujące kategorie:
Dwie pierwsze kategorie frameworków mają istotne znaczenie dla (ogólnie pojmowa-
nego) szybkiego tworzenia systemów wysokiej jakości, lecz zwykle nie mają żadnego znaczenia
z punktu widzenia użytkowników tych systemów. Frameworki aplikacyjne stanowią na-
tomiast istotne wsparcie dla tworzenia aplikacji użytkowych. W rezultacie zakup gotowych
rozwiązań dwóch pierwszych kategorii okazuje się wyraźnie bardziej opłacalny niż ich samo-
dzielne tworzenie, o czym piszą M. E. Fayad i D. S. Hamu [Fayad i Hamu, 1997].
Frameworki, ze względu na możliwy sposób ich użytkowania, można także podzielić na
dwie następujące grupy:
5
Zwanych także „punktami zaczepienia" — przyp- tłum.
8.4. Wybór wzorców projektowych i gotowych komponentów 383
6
Zbiór bitowy to reprezentacja podzbioru pewnego wzorcowego zbioru X, w której każdego ele-
mentowi zbioru X odpowiada jeden bit; wartość 1 tego bitu oznacza przynależność elementu do
podzbioru. Reprezentacja taka stosowana jest powszechnie w różnych odmianach języka Pascal do
implementowania zmiennych typu Set ot T, które są podzbiorami zbioru zawierającego wszystkie
wartości typu T — przyp. tłum.
384 Rozdział 8. • Projektowanie obiektów: wielokrotne wykorzystywanie rozwiązań wzorcowych
Przykład frameworku
7
Co więcej, wobec niebotycznych cen sprzętu, liczonych często w milionach dolarów, żądanie dodat-
kowych pieniędzy za oprogramowanie wydawało się klientowi wręcz niemoralne — przyp. tłum.
8.5. Zarządzanie wykorzystywaniem gotowych rozwiązań 387
Ograniczymy się przy tym do gier polegających na wymianie ruchów (Move) między
graczami (PI ayer), pomijając na razie problem gier obejmujących równoległe akcje ze strony
wielu graczy.
Rysunek 8.16. Obiekty modelu analitycznego systemu ARENA związane z jego niezależnością od kon-
kretnej gry
8
Dla uproszczenia piszemy o „specjalizacjach obiektów", choć prawidłowo powinno się pisać o „specja-
lizacjach klas": dla uproszczenia, pod pojęciem „specjalizacji obiektu T" rozumieć będziemy „obiekt bę-
dący instancją klasy stanowiącej specjalizację klasy T" — przyp. tłum.
392 Rozdział 8. • Projektowanie obiektów: wielokrotne wykorzystywanie rozwiązań wzorcowych
8.6.4. Wnioski
Pokazaliśmy praktyczne zastosowanie trzech wybranych wzorców projektowych w realizacji
celu, jakim jest niezależność systemu ARENA od konkretnych gier. Nawet ten prosty przykład
dostarczył dowodów na to, że:
8.8. Ćwiczenia
8.1. Dla każdego z poniższych obiektów modelu systemu ARENA wskaż przynależność
do konkretnej dziedziny — aplikacyjnej albo realizacyjnej:
• League,
• LeagueStore,
• LeagueXMLStorelmpl ementor,
• Match,
• MatchVi ew,
• Move,
• ChessMove.
Bibliografia
[BEA] BEA WebLogic Platform, http://www.bea.com/products/weblogic/platform.
[Birrer, 1993] E. T. Birrer „Frameworks in the financial engineering domain: An experience
report", ECOOP'93 Proceedings, Lecture Notes in Computer Science,
n r 707, 1993.
[Bruegge i in., 1993] B. Bruegge, T. Gottschałk, B. Luo A framework for dynamic program analyzers,
OOPSLA' 93, (Object-Oriented Programming Systems, Languages,
and Applications), Washington DC, str. 65 - 82, wrzesień 1993.
[Buschmann i in., 1996] F. Buschmann, R. Meunier, H. Rohnert, P. Sommerlad, M. Stal Pattern-Oriented
Software Architecture: A System of Patterns, Wiley, Chichester, U.K., 1996.
[Campbell i Islam, 1993] R. H. Campbell, N. Islam A technique for documenting the framework of
an object-oriented system, „Computing Systems", nr 6, str. 363 - 389, 1993.
[Fayad i Hamu, 1997] M. E. Fayad, D. S. Hamu Object-oriented enterprise frameworks: Make vs. buy
decisions and guidelines for selection, „The Communications of ACM", 1997.
[Fowler, 1997] M. Fowler Analysis Patterns: Reusable Object Models, Addison-Wesley,
Reading, MA, 1997.
[Gamma i in., 1994] E. Gamma, R. Helm, R. Johnson, J. Vlissides Design Patterns: Elements of
Reusable Object-Oriented Software, Addison-Wesley, Reading, MA, 1994.
Wydanie polskie Wzorce projektowe. Elementy oprogramowania obiektowego
wielokrotnego użytku, Helion 2010.
Bibliografia 397
[Goldberg i Kay, 1976] A. Goldberg, A. Kay Smalltalk-72 Instruction Manual, Xerox Palo Alto, CA, 1976.
[IBM] IBM WebSphere Software Platform for E-Business,
http://www. ibm.com/websphere/.
[JavaEE, 2009] Java Platform, Enterprise Edition, Javasoft 2009, http://java.sun.com/.
[JFC, 2009] Java Foundation Classes, JDK Documentation. Javasoft 2009.
R. Johnson, B. Foote Designing reusable classes, „Journal of Object-Oriented
[Johnson i Foote, 1988] Programming", t. 1, nr 5, str. 22 - 35, 1988.
B. Liskov Data abstraction and hierarchy, „SIGPLAN Notices", t. 23,
[Liskov, 1988] nr 3, maj 1988.
J. Martin, J. J. Odell Object-Oriented Analysis and Design, Prentice Hall,
[Martin i Odell, 1992] Englewood Cliffs, NJ, 1992.
B. Meyer Object-Oriented Software Construction, wyd. drugie, Prentice
[Meyer, 1997] Hall, Upper Saddle River, NJ, 1997.
M. Minsky „A framework for representing knowledge," w P. Winston
[Minsky, 1975] (red.) The Psychology of Computer Vision, McGraw-Hill, 1975.
Object Management Group, Common Object Request Broker Architecture
[OMG, 2008] (CORBA) Specification: Version 3.1, http://www.omg.org 2008.
J. Rumbaugh, M. Blaha, W. Premerlani, F. Eddy, W. Lorensen Object-
[Rumbaugh i in., 1991] Oriented Modeling and Design, Prentice Hall, Englewood Cliffs, NJ, 1991.
D.C. Schmidt „Applying design patterns and frameworks to develop
[Schmidt, 1997] object oriented communication software" w Peter Salus (red.) Handbook
of Programming Languages, t. 1, MacMillan Computer, 1997.
[Weinand i in., 1988] A. Weinand, E. Gamma, R. Marty „ET++ — An object-oriented application
framework in C++" w Object-Oriented Programming Systems, Languages,
and Applications Conference Proceedings, San Diego, CA, wrzesień 1988.
[Wilson i Ostrem, 1999] G. Wilson, J. Ostrem WebObjects Developer's Guide, Apple, Cupertino, CA, 1998.
9.1. Wstęp: kolej miejska i tramwaje 400
Bibliografia 442
Projektowanie obiektów:
specyfikowanie interfejsów
• rozstawu szyn. Kolej miejska poruszała się po torowisku o standardowym rozstawie 1450 mm,
podczas gdy tramwaje były taborem „metrowym", czyli korzystającym z rozstawu 1000 m m .
Uniwersalne torowisko umożliwiające ruch obu typów taboru musiało więc składać się z trzech,
nie dwóch szyn, co — oprócz zwiększonego zużycia stali — przekładało się natychmiast na
bardziej skomplikowane zwrotnice.
1
Prędkość handlowa środka transportu jest średnią jego prędkością na danej trasie, czyli ilorazem długości
tej trasy przez czas, w jakim została przebyta. Zależy nie tylko od możliwości samego pojazdu, lecz także
od bieżących warunków, w jakich się porusza, między innymi postojów na przystankach pośrednich
i zatłoczenia („zakorkowania") dróg, jest zatem miarodajnym czynnikiem oceny środka transportu
z perspektywy jego pasażera — przyp. tłum, na podstawie pl.wikipedia.org.
9.2. O specyfikowaniu interfejsów ogólnie 401
W kontekście rozciągnięcia w czasie opisanej modernizacji system dualnego taboru znakomicie zdał
egzamin: udało się sprostać rosnącym potrzebom transportu publicznego, również dzięki wyelimi-
nowaniu konieczności wyłączania z ruchu poszczególnych linii. Cały projekt zakończył się szczę-
śliwie w grudniu 2007 roku, kiedy to z ulic Stuttgartu zniknął ostatni tramwaj.
Multum obiektów, duża liczba programistów pracujących nad tymi obiektami, wysoka
dynamika zmian i mnóstwo podejmowanych równolegle decyzji — wszystko to sprawia, że faza
projektowania obiektów jest znacznie bardziej skomplikowana niż analiza wymagań czy pro-
jektowanie systemu. Złożoność ta pociąga za sobą niebagatelne wyzwania dla menedżera
projektu, bowiem wiele wspomnianych decyzji podejmowanych jest niezależnie i większość
z nich nie jest zwykle komunikowana ogółowi uczestników.
Projektowanie obiektów łączy się z zapewnieniem dostępności dużej ilości informacji dla
dużej liczby programistów, tak by podejmowane przez nich decyzje były spójne i zgodne z celami
projektowymi. Informację taką zapewnia Dokument Projektu Obiektów, w skrócie ODD (Object
Design Document) — „żywy" dokument zawierający szczegółową specyfikację każdej klasy.
9.4. Aktywności specyfikowania interfejsów 403
W kontekście abstrakcyjnej klasy Game systemu ARENA (patrz rysunek 9.2) programista
opracowujący operacje wspólne dla wszystkich subklas tej klasy jest jej implementatorem.
Użytkownikami klasy Game są między innymi implementatorzy klas League i Tournament
— obiekty tych klas korzystają z klasy Game w celu organizowania i rozpoczynania meczów
(Match). Z kolei programiści implementujący klasy Ti cTacToe i Chess, będące subklasami
(specjalizacjami) klasy Game, są z jej perspektywy ekstenderami.
Rysunek 9.2. Zależności klas systemu ARENA od klasy Game w kontekście ról programistycznych
przedstawionych na rysunku 9.1
każdego atrybutu określamy jego typ, dla każdej operacji — liczbę i typy jej parametrów oraz
typ wyniku. Dla każdego atrybutu i każdej operacji ustalamy też zakres ich widzialności. Pod
pojęciem typu atrybutu rozumiemy zbiór (zakres) wartości, jakie ów atrybut może przyjmo-
wać, oraz operacji, jakie mają zastosowanie do tego atrybutu. Przykładowo wartościami atrybutu
maxNumPl ayers klasy Tournament (patrz rysunek 9.3), określającego maksymalną liczbę graczy
(PI ayer), mogą być liczby całkowite, co jest odpowiednikiem typu i nt 2 . Do wielkości tego typu
stosują się operacje mające sens dla liczb całkowitych: porównywanie, dodawanie, odejmowa-
nie, mnożenie przez liczbę całkowitą i tym podobne.
Identyczne znaczenie ma pojęcie typu w odniesieniu do każdego z parametrów operacji
i do zwracanego przez nią wyniku. Wektor (krotkę) danej operacji, jaki tworzą kolejne typy
jej parametrów i typ wyniku, nazywamy jej sygnaturą. Przykładowo operacja acceptPl ayer()
klasy Tournament wymaga jednego parametru typu PI ayer i nie zwraca żadnej wartości, jej
sygnatura ma zatem postać (Pl ayer): voi d;podobnie operacja getMaxNumPl ayers () tej samej
klasy ma sygnaturę (voi d ) : i nt.
Programiści w każdej z trzech ról — implementatora, użytkownika i ekstendera klasy —
korzystają z operacji i atrybutów tej klasy. Zależnie jednak od konkretnej, roli mają zróżnico-
wane potrzeby w tym względzie i nie dla każdego z nich dostęp do wszystkich operacji jest
potrzebny lub pożądany, przykładowo atrybuty i operacje związane z wewnętrznymi struk-
turami i mechanizmami klasy z oczywistych względów dostępne dla jej implementatora,
2
O d ang. integer — „całkowity" — przyp. tłum.
9.4. Aktywności specyfikowania interfejsów 405
niekoniecznie muszą być (a nawet nie powinny być) dostępne dla jej użytkownika. Z kolei dla
ekstendera klasy interesujące mogą być jedynie wybrane elementy zbioru jej wewnętrznych
atrybutów i operacji. Zróżnicowana dostępność poszczególnych atrybutów i operacji określana
jest mianem ich widzialności. W języku UML rozróżnia się cztery następujące poziomy
widzialności.
• Prywatny (pri vate) atrybut widoczny jest jedynie w obrębie implementacji swej
macierzystej klasy, podobnie prywatna operacja może być wywoływana wyłącznie
w ramach tej implementacji. Prywatne atrybuty i operacje przeznaczone są wyłącz-
nie dla implementatora klasy i nie są widoczne dla innych klas, nawet dla subklas
danej klasy; nie są zatem widoczne ani dla użytkownika tej klasy, ani dla jej ekstendera.
• Chroniony (protected) atrybut i chroniona operacja dostępne są zarówno w obrębie
implementacji swej macierzystej klasy, jak i w obrębie implementacji jej subklas.
Dla innych klas są niedostępne. Widoczne są zatem dla implementatora i ekstendera
klasy, ale nie dla jej użytkownika.
• Publiczny (publ i c) atrybut lub klasa dostępne są bez ograniczeń dla wszystkich klas.
Zbiór publicznych atrybutów i operacji danej klasy składa się na to, co nazywamy
jej publicznym interfejsem, przeznaczonym dla użytkowników.
• Pakietowy (package) atrybut lub operacja widoczne są bez ograniczeń w obrębie
wszystkich klas wchodzących w skład tego samego pakietu. Umożliwia to współdzie-
lenie atrybutów i operacji przez powiązane ze sobą klasy tworzące spójną całość
(na przykład podsystem), jednocześnie chroni przedmiotowe atrybuty i operacje
przed dostępem z zewnątrz do macierzystego pakietu.
406 Rozdział 9. • Projektowanie obiektów: specyfikowanie interfejsów
W języku UML widzialność elementu (atrybutu lub klasy) oznaczana jest przez jedno-
znakowy przedrostek poprzedzający nazwę: minus (-) oznacza element prywatny (pri vate),
kratka (#) — element chroniony (protected), plus (+) — element publiczny (pub! ic), zaś tylda
(-) — element pakietowy (package). W diagramie na rysunku 9.3 atrybut maxNumPl ayers klasy
Tournament jest jej atrybutem prywatnym, podczas gdy wszystkie jej operacje są publiczne.
Typ atrybutu nie zawiera jednak kompletnej informacji na temat dopuszczalnego zbioru
wartości, jakie atrybut ten może przyjmować; przykładowo typ i nt atrybutu maxNumPl ayers
zezwala na nadawanie mu wartości ujemnych, bezsensownych jednak z punktu widzenia
dziedziny aplikacyjnej. Ten problem rozwiązywany jest za pomocą mechanizmu zwanego
kontraktem.
Jako przykładem posłużmy się interfejsem klasy Tournament z rysunku 9.3. Klasa ta posiada
metodę acceptPlayer() realizującą dodawanie nowego gracza (Player) do turnieju, metodę
removePl ayer() wycofującą gracza z turnieju i metodę getMaxNumPl ayers () zwracającą mak-
symalną dopuszczalną liczbę graczy w danym turnieju. Przykładem niezmiennika tej klasy
jest dodatnia wartość zwracana przez metodę getMaxNumPlayers(); gdyby była ona zerowa,
każde wywołanie metody acceptPl ayer () stanowiłoby naruszenie jej kontraktu i turniej repre-
zentowany przez instancję klasy Tournament nie mógłby się w ogóle rozpocząć. Niezmiennik
ten zapisać możemy w postaci wyrażenia boolowskiego:
t.getMaxNumPlayers() > 0
gdzie t jest instancją klasy Tournament.
Przykładem warunku wstępnego dla metody acceptPl ayer () jest wymaganie, by gracz
(PI ayer) stanowiący argument wywołania tej metody nie uczestniczył jeszcze w odnośnym
turnieju oraz by dla turnieju tego nie wyczerpano jeszcze maksymalnej liczby uczestników.
Oznaczając przez t instancję klasy Tournament reprezentującą wspomniany turniej, zaś
9.4. Aktywności specyfikowania interfejsów 407
przez p instancję klasy PI ayer reprezentującą gracza aplikującego do udziału w turnieju, wa-
runek ten możemy zapisać w postaci następującego wyrażenia boolowskiego:
Słowo kluczowe context wskazuje encję, do której odnosi się ograniczenie, po czym na-
stępuje określenie rodzaju graniczenia w postaci jednego z trzech słów kluczowych: i nv (nie-
zmiennik, od invariant), pre (warunek wstępny, od precondition) albo post (warunek końco-
wy, od postcondition). Odpowiednikami tych słów kluczowych na diagramie UML są stereotypy
(odpowiednio) «invariant», «precondition» i «postcondition». Potem następuje odpowied-
nie wyrażenie języka OCL. Składnia języka OCL podobna jest do składni języków zoriento-
wanych obiektowo, takich jak Java czy C++. Jednak w przeciwieństwie do nich język OCL
nie jest językiem proceduralnym — operacje mogą być używane w jego wyrażeniach, pod wa-
runkiem że nie powodują efektów ubocznych.
Dla niezmienników kontekstem wyrażenia jest klasa, której one dotyczą. Instancje tej
klasy reprezentowane są w wyrażeniach przez słowo kluczowe sel f 3 . Atrybuty i operacje iden-
tyfikowane są za pomocą kwalifikowanej notacji „kropkowej", na przykład sel f.maxNumPl ayers
oznacza wartość atrybutu maxNumPl ayers dla instancji łdasy stanowiącej kontekst ograniczenia.
Słowo sel f można pominąć, jeśli to nie prowadzi do niejednoznaczności.
Dla warunku wstępnego i warunku końcowego kontekstem wyrażenia OCL jest opera-
cja; parametry przekazywane do tej operacji mogą być używane jako zmienne w tym wyra-
żeniu. Przykładowo ograniczenie w postaci:
context T o u r n a m e n t : : a c c e p t P ł a y e r ( p : P l a y e r ) pre:
lisPlayerAccepted(p)
context T o u r n a m e n t : : a c c e p t P l a y e r ( p : P l a y e r ) pre:
getNumPlayers() < getMaxNumPlayers()
context T o u r n a m e n t : : a c c e p t P l a y e r ( p : P I a y e r ) post:
isPlayerAccepted(p)
context T o u r n a m e n t : : a c c e p t P l a y e r ( p : P l a y e r ) post:
getNumPlayersQ = self@pre. getNumPlayersQ + 1
Listing 9.1. Deklaracje metod klasy Tournament opatrzone adnotacjami dotyczącymi warunków
wstępnych, warunków końcowych i niezmienników, zapisanymi przy użyciu znaczników Javadoc
/ ** Turniej (Tournament) jest serię meczów (Match) rozgrywanych między grupami graczy
* (Player) i kończęcych się wyłonieniem jednego zwycięzcy. Reguły gry i styl rozgrywania
* turnieju określone są przez obiekty będęce specjalizacjami klas Game i TournamentStyle
* skojarzonymi z klasę Tournament.
V
.... konstruktor....
public void r e m o v e P l a y e r ( P I a y e r p) { . . . }
Rysunek 9.5. Skojarzenia między klasami League, Tournament i PI ayer systemu ARENA
1. Turniej wi nter :Tournament trwa dwa dni, turniej xmas :Tournament trzy dni — czyli
oba poniżej tygodnia.
2. Wszyscy gracze (PI ayer) uczestniczący w turnieju wi nter: Tournament, a także wszyscy
uczestnicy turnieju xmas:Tournament, zarejestrowani są w lidze tttExpert:League.
Gracz zoe nie jest jednak członkiem ligi t t t E x p e r t : League i nie uczestniczy w żad-
nym turnieju.
412 Rozdział 9. • Projektowanie obiektów: specyfikowanie interfejsów
Rysunek 9.6. Przykład ograniczeń obejmujący dwie ligi, dwa turnieje i pięcioro graczy
Powyższe ograniczenia już na pierwszy rzut oka wyglądają odmiennie: pierwsze z nich
ogranicza się do jednej klasy, drugie obejmuje trzy klasy (PI ayer, Tournament, League) i sko-
jarzenia między nimi, przedmiotem trzeciego jest zbiór meczów (Match) powiązanych z okre-
ślonym turniejem. W każdym z tych przypadków startujemy od konkretnej klasy i nawigujemy
po innych klasach modelu. W ogólnym przypadku nawigacja ta obejmować może trzy różne
zakresy (co schematycznie przedstawiono na rysunku 9.7):
• lokalne atrybuty — czyli atrybuty pojedynczej klasy, takie jak data rozpoczęcia ( s t a r t )
i zakończenia (end) turnieju (Tournament),
• klasy bezpośrednio powiązane — nawigacja odbywa się wyłącznie na jednym pozio-
mie skojarzenia (na przykład skojarzenia graczy z turniejami lub skojarzenia ligi
z turniejem),
• klasy powiązane pośrednio — nawigacja obejmuje kilka poziomów skojarzeń (na
przykład skojarzenie ligi z graczami biorącymi udział w co najmniej jednym turnieju
organizowanym przez tę ligę).
Wyróżniliśmy owe trzy podstawowe typy nawigacji, bowiem każde ograniczenie w ję-
zyku OCL da się wyrazić za ich pomocą. Na podstawie treści poprzedniej sekcji możemy już
z łatwością zapisać pierwsze z przedstawionych ograniczeń — ograniczenie maksymalnego
czasu trwania turnieju do tygodnia.
9.4. Aktywności specyfikowania interfejsów 413
Rysunek 9.7. Trzy podstawowe typy nawigacji — za pomocą ich kombinacji można formułować
wszelkie ograniczenia w języku OCL
W sytuacjach, gdy istotny jest jedynie fakt przynależności danego obiektu do wielo-
zbioru, bez względu na krotność tej przynależności, wielozbiór można łatwo skon-
wertować na zwykły zbiór za pomocą operacji asSet () (patrz tabela 9.1).
Operowanie na kolekcjach OCL umożliwiają różne operacje udostępniane przez ten język;
najczęściej używane z nich przedstawiamy w tabeli 9.1.
W języku OCL odwołania do atrybutów różnią się od odwołań do kolekcji: pierwsze mają
postać notacji „kropkowej", drugie używają operatora ->. Przykładowo drugie ze sformuło-
wanych wcześniej wymagań — dostępność danego turnieju wyłącznie dla członków ligi orga-
nizującej ten turniej — można wyrazić następująco 4 :
context T o u r n a m e n t : : a c c e p t P l a y e r ( p : P l a y e r ) pre:
league.piayers->includes(p)
4
Choć autorzy nie piszą tego wyraźnie, z treści i późniejszych rysunków wynika, ze p l a y e r s jest
tutaj nazwą skojarzenia — przyp. tłum.
9.4. Aktywności specyfikowania interfejsów 415
context L e a g u e : : g e t A c t i v e P l a y e r s : S e t post:
result = tournaments.players->asSet()
Gdy na przykład chcemy się upewnić, że wszystkie mecze w ramach danego turnieju
rozpoczynają się i kończą w zakreślonych dla tego turnieju ramach czasowych, możemy sfor-
mułować następujący niezmiennik:
5
Podobnie i tutaj tournaments i pl ayers są nazwami odnośnych skojarzeń — przyp. tłum.
416 Rozdział 9. • Projektowanie obiektów: specyfikowanie interfejsów
Rysunek 9.8. Obiekty modelu analitycznego systemu ARENA zidentyfikowane w ramach analizy przypadku
użycia AnnounceTournament. Dla uproszczenia pominięto niektóre elementy
9.4. Aktywności specyfikowania interfejsów 417
Rysunek 9.10. Wzbogacenie modelu projektu obiektów systemu ARENA o specyfikację typów, sy-
gnatur i widzialności. Dla przejrzystości pominięto niektóre elementy
context T o u r n a m e n t C o n t r o l : : s e l e c t S p o n s o r s ( a d v e r t i s e r s ) pre:
interestedSponsors->notEmpty()
Kolejny warunek chroni przed wielokrotnym wyborem sponsora dla turnieju — operacja
TournamentControl . s e l e c t S p o n s o r s ( ) może być wywołana tylko raz:
context T o u r n a m e n t C o n t r o l : : s e l e c t S p o n s o r s ( a d v e r t i s e r s ) pre:
tournament.sponsors->isEmpty()
context T o u r n a m e n t C o n t r o l : : s e l e c t S p o n s o r s ( a d v e r t i s e r s ) post:
tournament.sponsors.equals(adverti sers)
context T o u r n a m e n t C o n t r o l : : s e l e c t S p o n s o r s ( a d v e r t i s e r s ) post:
tournament.sponsors.equals(adverti sers)
context T o u r n a m e n t C o n t r o l : : a d v e r t i s e T o u r n a m e n t ( ) pre:
tournament.sponsors->isEmpty() and not tournament.advertised
context T o u r n a m e n t C o n t r o l : : a d v e r t i s e T o u r n a m e n t ( ) post:
tournament.advertised
context T o u r n a m e n t C o n t r o l : : a c c e p t P l a y e r ( p ) pre:
tournament.advertised and
i nterestedPlayers->includes(p) and
not isPlayerOverbooked(p)
context T o u r n a m e n t C o n t r o l : : a c c e p t P l a y e r ( p ) post:
tournament.piayers->i ncludes(p)
Podobne zabiegi redukujące liczbę operacji w zapisie ograniczeń są jak najbardziej po-
żądane z punktu widzenia czytelności tych ograniczeń.
Jak wynika z przytoczonych przykładów, stosunkowo łatwo generować obszerne nawet
zbiory ograniczeń dla poszczególnych klas. Łatwość ta nie zawsze jednak idzie w parze z czy-
telnością, bo formułowanie czytelnych i poprawnych ograniczeń takie łatwe już nie jest. Nie
zapominajmy, że celem artykułowania niezmienników jest wyeksponowanie założeń, jakie
implementator klasy przyjmuje względem jej użytkowników. Niezmienniki powinny zatem
9.4. Aktywności specyfikowania interfejsów 423
w p i e r w s z y m rzędzie o d z w i e r c i e d l a ć w y r a ź n e w a r u n k i g r a n i c z n e , k t ó r e p o d i n n ą p o s t a c i ą n i e
byłyby tak oczywiste. P o n i ż e j p r z e d s t a w i a m y kilka h e u r y s t y k , k t ó r e ułatwić m o g ą f o r m u ł o -
wanie ograniczeń w sposób czytelny i zrozumiały.
Heurystyki p o m o c n e w c z y t e l n y m f o r m u ł o w a n i u o g r a n i c z e ń
Skoncentruj się na czasie życia instancji danej klasy. Ograniczenia specyficzne dla operacji lub tylko
dla pewnych stanów obiektu najlepiej wyrażają się jako warunki wstępne lub końcowe, na przykład:
• „różni gracze m a j ą różne adresy e-maił" — to i n f o r m a c j a p e r m a n e n t n a o charakterze
niezmiennika,
• „dany gracz może być w danym momencie zarejestrowany w co najwyżej jednym z odbywających
się równolegle turniejów" — to warunek wstępny operacji Tournament Form. appl y ForTournament ().
Zidentyfikuj wartości specjalne dla każdego atrybutu. Wartość zero, wartość pusta, wartości
szczególne w danym zakresie oraz atrybuty zależne od innych atrybutów to najczęstsze źródła
nieporozumień i błędów, na przykład:
• w meczu musi brać udział co najmniej jeden gracz,
® rezultatem meczu jest wyłonienie dokładnie jednego zwycięzcy.
Zidentyfikuj szczególne przypadki skojarzeń, zwłaszcza te ich aspekty, których nie sposób wyra-
zić za pomocą krotności, na przykład:
• zbiór graczy uczestniczących w turnieju (tournament. pl ayers) jest podzbiorem zbioru
członków ligi organizującej ten turniej (tournament. 1 eague.pl ayers).
Jeżeli jednak zdefiniujemy dla klasy Match operację pomocniczą getGame (), zwracającą obiekt sub-
klasy Game reprezentujący grę właściwą danemu meczowi, powyższe ograniczenie będziemy mogli
napisać w bardziej czytelnej postaci:
• match.getGame().maxMatchDuration
N i e z m i e n n i k i , w a r u n k i w s t ę p n e i w a r u n k i k o ń c o w e określają s e m a n t y k ę d a n e j operacji
p r z e z j a w n e w y a r t y k u ł o w a n i e o k o l i c z n o ś c i , k t ó r e m u s z ą w y s t ę p o w a ć p r z e d jej w y w o ł a n i e m
i p o jej z a k o ń c z e n i u . K o n t r a k t klasy s t a n o w i więc czytelną d o k u m e n t a c j e dla jej u ż y t k o w n i k a .
Jak za chwilę z o b a c z y m y , k o n t r a k t d a n e j klasy jest r ó w n i e ż i s t o t n y dla jej e k s t e n d e r a .
424 Rozdział 9. • Projektowanie obiektów: specyfikowanie interfejsów
Rysunek 9.11. Prosty przykład dziedziczenia kontraktu. Niezmiennik zdefiniowany dla superklasy
musi być zachowany w każdej z jej subklas
6
Dodawanie do zbioru elementu już w nim obecnego nie wywołuje żadnej akcji, nie zwiększa zatem
liczebności zbioru — przyp. tłum.
9.5. Zarządzanie projektowaniem obiektów 425
Dziedziczenie kontraktów staje się szczególnie użyteczne przy definiowaniu klas abstrak-
cyjnych lub interfejsów podlegających na przedefiniowywaniu (implementowaniu) przez
ekstenderów. Precyzyjne zdefiniowanie granic między klasą kliencką a interfejsem umożliwia
ekstenderom implementowanie specjalizowanych subklas bez znajomości kodu źródłowego,
w którym będą wykorzystywane. Dziedziczenie kontraktów jest ponadto konsekwencją zasady
zastępowania Liskov (patrz sekcja 8.3.4), ponieważ każde wystąpienie klasy oryginalnej może
być zastąpione wystąpieniem jej subklasy.
Zajmiemy się tymi wyzwaniami w sekcji 9.5.1, w której też opiszemy dokument projektu
obiektów (ODD) — jego tworzenie i utrzymywanie aktualności oraz relacje z innymi dokumen-
tami. W sekcji 5.9.1 omówimy natomiast role przypisywane uczestnikom w związku z projek-
towaniem obiektów.
7
Nie mylić z dekompozycją systemu na podsystemy, dokonywaną na etapie projektowania systemu
— przyp. tłum.
426 Rozdział 9. • Projektowanie obiektów: specyfikowanie interfejsów
między zespołami oraz jako punkt odniesienia na etapie testowania. Odbiorcami dokumentu
ODD są między innymi architekci systemu (czyli programiści, którzy uczestniczyli w fazie
projektowania systemu), programiści implementujący podsystemy oraz testerzy.
Podczas budowania dokumentu ODD możemy skorzystać z trzech podejść. Oto one.
Rysunek 9.12. Wbudowywanie modelu projektu obiektów w kod programu. Model ten dokumentowany
jest w formie znacznikowanych komentarzy, na podstawie których generować można dokument O D D
Oferta narzędzi modelujących kurczy się wydatnie, gdy żądamy obsługi zależności
w dwóch kierunkach, szczególnie zależności między modelem analitycznym a kodem źró-
dłowym. Niektóre narzędzia, między innymi Rationale Rose [Rational, 2002] i Together Control
Center [TogetherSoft, 2002], realizują to zadanie przez wbudowywanie w kod źródłowy
komentarzy zawierających informacje dotyczące modelu analitycznego, takich jak informacje
o skojarzeniach i innych konstrukcjach UML. Mimo iż umożliwia to śledzenie zmian syntak-
tycznych w kodzie programu, programiści wciąż muszą aktualizować opisy zawarte w modelu
w celu czytelnego uwzględniania dokonywanych zmian. W efekcie programista zmuszony jest
do używania dwóch różnych narzędzi, dla kodu źródłowego i dla modelu, nie jest więc nie-
spodzianką, że zwykle cierpi na tym model.
Dopóki więc nie pojawią się narzędzia oferujące lepszą obsługę utrzymywania spójności
między modelami obiektowymi a kodem źródłowym, najbardziej rozsądną metodologią wy-
daje się generowanie dokumentu ODD w oparciu o kod źródłowy i ograniczanie dokumentu
RAD wyłącznie do dziedziny aplikacyjnej. Redukuje to rozmiar redundantnej informacji, którą
utrzymywać trzeba w aktualnym stanie, w dalszym ciągu jednak spójność między kodem źró-
dłowym a modelem analitycznym musi być utrzymywana ręcznie. Nie jest to trudne zadanie,
bowiem zmiany w kodzie źródłowym wymagają w większości modyfikowania tylko doku-
mentu ODD, rzadziej dokumentu RAD.
Poniżej widoczny jest przykładowy szablon generowanego automatycznie dokumentu
ODD.
Listing 9.2. Znacznikowane komentarze Javadoc stowarzyszone z kodem źródłowym klasy Tournament
/** Turniej, reprezentowany przez obiekt klasy Tournament, jest serię meczów,
* reprezentowanych przez instancje klasy Match, rozgrywanych między graczami,
430 Rozdział 9. • Projektowanie obiektów: specyfikowanie interfejsów
* Każdy turniej jest początkowo pusty; po jego ogłoszeniu dołączają do niego gracze,
* planowane są mecze, które następnie zostają rozgrywane.
* Niezmienniki:
*
p u b l i c c l a s s Tournament {
* @pre HsPlayerAccepted(p)
* @pre getPlayersQ.sizeQ < getMaxNumPlayersQ
* @post isPlayerAccepted(p)
* @post getPlayersQ.sizeQ = self@pre.getPlayers().size() +1
*/
public void acceptPlayer (Player p) ( ... }
* @pre isPlayerAccepted(p)
* @post HsPlayerAccepted(p)
* @postgetPlayers().size() = self@pre.getPlayers().size() -1
V
public void removePlayer(Player p) { ... }
Aby uczynić zadość tym wymaganiom, zdefiniujemy nową klasę Round (patrz rysunek
9.13). Klasa ta reprezentuje pojedynczą rundę, czyli zbiór meczów, które mogą być rozgrywane
równolegle, niezależnie od siebie, zatem harmonogram turnieju może być reprezentowany
w postaci listy (sekwencji) rund (obiektów subklasy Round). W związku z tym, dodamy do
klasy Tournament operację pl anRounds (), zwracającą w wyniku wspomnianą listę, powstałą
w wyniku utworzenia obiektów reprezentujących wszystkie mecze i zorganizowania ich w serię
rund. Operacja pl anRounds () odpowiedzialna będzie ponadto za przydzielenie graczy do
wszystkich meczów pierwszej rundy (i ewentualnie do następnych rund, jeżeli taki przydział
a priori jest dla tych rund możliwy). Ewentualny przydział graczy do kolejnych (nieobsadzonych
jeszcze) rund realizowany będzie za pomocą operacji Round.plan (), wywoływanej na rzecz
obiektów reprezentujących te rundy.
10.6. Analiza przypadku — system ARENA 435
Rysunek 9.13. Nowa klasa Round oraz jej skojarzenia z klasami Tournament i Match. Zmiany wyróż-
nione są pogrubionymi liniami
/* Dowolne dwa mecze należące do różnych rund muszą być rozłączne czasowo 7
context TournamentStyle::planRounds(t:Tournament) post:
result->forAll(rl,r2| rl<>r2 implies
rl.getEndDate().before(r2.getStartDate())
or
rl.getStartDate().after(r2.getEndDate())
10.6. Analiza przypadku — system ARENA 437
matches->forAl1(ml:Match|
ml.players->forAll(p:Player|
p.matches->forAll(m2:Match| ml <> m2 implies ml.round <> m2.round)))
Zauważmy, że niezmiennik ten pozostaje prawdziwy nawet wówczas, gdy żaden gracz
nie jest przyporządkowany do meczu 8 .
Przyjrzyjmy się teraz informacji o stanie, przechowywanej w ramach klasy Round. Obiekt
tej klasy może znajdować się w jednym z trzech stanów, reprezentujących (odpowiednio) rundę:
• niezaplanowaną — to stan początkowy, w którym istnieje lista meczów, lecz nie dla
wszystkich zdefiniowano obsadę,
• zaplanowaną — w tym stanie do wszystkich meczów przyporządkowani są gracze;
obiekt wchodzi w ten stan po wykonaniu operacji pl an (),
• zakończoną — ten stan oznacza zakończenie rundy: wszystkie mecze zostały rozegra-
ne, w każdym wyłoniony został zwycięzca.
Informacja o stanie obiektu udostępniana będzie przez jego dwie metody: Round, is
•^Planned() i Round. isCompleted(), zwracające wartość True dla stanu reprezentującego rundę
(odpowiednio) „zaplanowaną" i „zakończoną". Informacja ta jest niezbędna zarówno dla
klasy Round, jak i dla klasy Tournament. Przydzielanie graczy do meczów danej rundy mo-
że wymagać zakończenia rundy poprzedniej, podobnie przed zakończeniem bieżącej rundy
nie może być rozpoczęta runda następna; za spełnienie pierwszego z tych warunków odpowie-
dzialna jest klasa Round, za spełnienie drugiego — klasa Tournament. Zapis odpowiednich
ograniczeń widoczny jest na listingu 9.3.
8
Dla pustej kolekcji kwantyfikator forAl 1 () zawsze zwraca wartość true, niezależnie od podanego
warunku — przyp. tłum.
438 Rozdział 9. • Projektowanie obiektów: specyfikowanie interfejsów
context R o u n d . p l a n ( ) post:
@pre.getPreviousRound() .isCompletedO implies isPlannedQ
/* Runda znajduje się w stanie "zaplanowana", jeśli dla wszystkich
* jej meczów zdefiniowana została obsada
V
context R o u n d . i s P l a n n e d ( ) post:
r e s u l t implies
matches->forAl1(m|m.players->size = tournament.league.game.numPlayersPerMatch)
I* Runda znajduje się w stanie "zakończona", jeśli zakończone zostały
* wszystkie jej mecze, czyli w każdym meczu wyłoniony został zwycięzca
7
context R o u n d . i s C o m p l e t e d O post:
r e s u l t implies matches->forAll(m[ m.winner <> null)
Jak za chwilę zobaczymy, informacja niezbędna do planowania rundy może być do-
stępna dopiero po zakończeniu poprzedniej rundy (choć nie jest to regułą).
9
Wykorzystuje się tu własność, że jeśli x jest potęgą liczby 2, to floor(log, x)= log, x (floor oznacza część
całkowitą wyrażenia). Wartość logarytmu przy podstawie 2 oblicza się na podstawie tożsamości
log, x = (ln oznacza logarytm naturalny, reprezentowany przez funkcję 1 og ()) —przyp. tłum.
In 2
10.6. Analiza przypadku — system ARENA 439
9.6.4. Wnioski
Definiując kontrakty dla klas TournamentStyle, Round, KnockOutStyle i KnockOutRound,
mieliśmy okazję przekonać się, że:
9.8. Ćwiczenia
9.1. Dla interfejsu List z pakietu j a v a . u t i l , reprezentującego uporządkowaną ko-
lekcję obiektów, zdefiniuj warunki wstępne i warunki końcowe w kontekście na-
stępujących operacji:
• i n t s i z e ( ) zwracającej liczbę elementów w liście,
• voi d add (Object e) powodującej dołączenie obiektu e na końcu listy,
• void remove(0bject e) powodującej usunięcie obiektu e z listy,
® boolean contains(Object e) badającej, czy obiekt e znajduje się w liście,
® Object get ( i n t idx) zwracającej obiekt identyfikowany przez indeks i dx
(pierwszy obiekt w liście ma indeks równy 0).
8.8. Ćwiczenia 441
9.2. Sformułuj w języku OCL warunki wstępne i warunki końcowe dla następujących
operacji interfejsu Set z pakietu Java, uti 1:
• i n t s i ze () zwracającej liczbę elementów w zbiorze,
• void add (Object e) powodującej dodanie obiektu e do zbioru; jeżeli obiektu e
znajduje się już w zbiorze, operacja nie powoduje żadnej akcji,
• void remove(0bject e) powodującej usunięcie obiektu e ze zbioru,
• boolean contains(Object e) badającej, czy obiekt e znajduje się w zbiorze.
9.3. Dla klasy Collection z pakietu j a v a . u t i l , będącej superklasą dla klas List i Set,
sformułuj warunki wstępne i warunki końcowe dla wymienionych poniżej operacji:
• i n t s i ze () zwracającej liczbę elementów w kolekcji,
• void add(0bject e) powodującej dodanie obiektu e do kolekcji,
• void remove(Object e) powodującej usunięcie obiektu e z kolekcji,
• boolean contains(Object e) badającej, czy obiekt e znajduje się w kolekcji.
Następnie zmodyfikuj ograniczenia stworzone w ramach ćwiczeń 9.1 i 9.2 tak, by
spełnione były zasady dziedziczenia kontraktów. Nie zapomnij o zasadzie zastę-
powania Liskov.
9.4. Rozpatrzmy klasy Rectangl e i Square reprezentujące (odpowiednio) prostokąt i kwa-
drat; Square jest subklasą klasy Rectangl e.
• Sformułuj warunki końcowe dla operacji R e c t a n g l e . s e t M i d t h ( w : i n t )
i Rectangl e. setHei ght (h: i nt) w kategoriach operacji Rectangl e. getWi dth ( ) : i nt
i Rectangle.getHeight() : i n t .
o Sformułuj dla klasy Square niezmiennik stanowiący, że wysokość i szerokość
kwadratu zawsze są równe.
• Czy w kontekście operacji Square.setWidthQ i Square.setHeightQ speł-
nione są reguły dziedziczenia kontraktów opisane w sekcji 9.4.5? Jeśli nie, dla-
czego? Co trzeba zmienić w modelu, by zapewnić ich spełnienie?
9.5. Sformułuj w języku OCL niezmiennik wyrażający fakt posortowania elementów listy.
9.6. Dla posortowanego drzewa binarnego sformułuj w języku OCL niezmienniki stano-
wiące, że:
• dla każdego węzła jego lewe poddrzewo albo jest puste, albo zawiera w swych wę-
złach liczby całkowite nie większe od liczby całkowitej zawartej w tymże węźle,
• dla każdego węzła jego prawe poddrzewo albo jest puste, albo zawiera w swych wę-
złach liczby całkowite nie mniejsze od liczby całkowitej zawartej w tymże węźle,
• drzewo jest zrównoważone 10 .
9.7. Wyobraź sobie zwykłe skrzyżowanie dwóch prostopadłych dróg dwukierunkowych,
z czterema sygnalizatorami świetlnymi. Załóżmy prosty algorytm cyklicznego
10
Drzewo binarne jest zrównoważone, jeśli dla każdego węzła wysokości jego poddrzew są jednakowe.
Wysokością drzewa nazywamy liczbę węzłów na jego najdłuższej ścieżce prowadzącej od korzenia do li-
ścia; wysokość drzewa pustego równa jest umownie 0 — przyp. tłum.
442 Rozdział 9. • Projektowanie obiektów: specyfikowanie interfejsów
Bibliografia
[Borning, 1981] A. Borning The programming language aspects of ThingLab,
a constraint-oriented simulation laboratory, w „ACM TOPLAS" 3 (4),
październik 1981.
[Contract4J] http://www.contract4j.org/
[Dijkstra, 1976] E.W. Dijkstra A Discipline of Programming, Prentice Hall, Englewood
Cliffs, NJ, 1976.
R. W. Floyd Assigning meanings to programs, w Proceedings of the
[Floyd, 1967]
American Mathematics Society Symposium in Applied Mathematics,
t. 19, str. 19 - 31, 1967.
B. Freeman-Benson Kaleidoscope: Mixing objects, constraints, and
[Freeman-Benson, 1990]
imperative programming, w „OOPSLA/SIGPLAN Notices" 25 (10):
77:88, październik 1990.
C.A.R. H o a r e An axiomatic basis for computer programming,
[Hoare, 1969]
„Communications of the ACM", t. 20, nr 6, str. 576 - 580, październik 1969.
[Horn, 1992] B. H o r n Constraint patterns as a basis for object-oriented programming,
Proceedings of the OOPSLA'92, Vancouver, Canada, 1992.
[Javadoc, 2009a] Sun Microsystems, strona główna Javadoc http://java.sun.com/j2se/javadoc/.
[Javadoc, 2009b] Sun Microsystems, How to write doc comments for Javadoc,
http://java.sun.com/j2se/javadoc/writingdoccomments/.
[j Contractor] http://jcontractor.sourceforge.net/
[Johnson i Foote, 1988] R. Johnson, B. Foote Designing reusable classes, „Journal of Object-
Oriented Programming", t. 1, nr 5, str. 22 - 35, 1988.
R. Kramer, ,,iContract-The Java Design by Contract Tool" Technology
[Kramer, 1998] of Object-Oriented Languages and Systems, IEEE Computer Society
Press, 1998, str. 295.
B. Liskov, J. Guttag Abstraction and Specification in Program Development,
[Liskov i Guttag, 1986] McGraw-Hill, New York, 1986.
Bibliografia 443
Bibliografia 487
Odwzorowywanie
modelu na kod
Z rzeczami, które nigdy nie mogą się zepsuć, jest ten problem,
że gdy się zepsuję, nijak nie można ich już naprawić.
— Douglas Adams Mostly Harmless
W Wielkiej Brytanii wydawnictwo Allen & Unwin opublikowało w październiku 1966 zrewidowany
rękopis, w twardej oprawie. Nie mogło ono jednak wykorzystać oryginalnego rękopisu z załącznikami,
gdyż ten po prostu zaginął; na potrzeby załączników posłużyło się więc wczesną kopią używaną
przez Ballantine Books — ta jednak nie zawierała drugiego zbioru poprawek, a co gorsza, w druku
wprowadzonych zostało mnóstwo błędów. Latem 1966 roku Tolkien dokonał ponownej rewizji tekstu,
jednakże w czerwcu Allen & Unwin poinformowało, że jest zbyt późno, by dokonane poprawki włączyć
do nowego wydania. I tak oto pod koniec roku 1966 w obiegu istniało wiele znacząco różnych i nie-
spójnych ze sobą wersji Władcy Pierścieni, z których żadna w pełni nie oddawała intencji Tolkiena.
Każde wydanie Władcy Pierścieni wiązało się z szeregiem transformacji, jakich doznawał
tekst książki na drodze od rękopisu do wydrukowanej książki. Autor najpierw przepisywał rę-
kopis na maszynie i przesyłał wydawcy. Maszynopis poddawany był korekcie i redagowany
przed przekazaniem do składu w drukarni. Składanie tekstu wiązało się z wprowadzaniem do
niego błędów wynikających zarówno z ludzkiej omylności („literówek"), jak i podejmowanych
w dobrej wierze, choć często opacznie, zabiegów korektorskich. Jeżeli dodać do tego błędy po-
wstałe w trakcie samego drukowania — takie jak niewłaściwa kolejność lub błędna orientacja
stron — to mamy pełnię obrazu rzeczonej transformacji. I choć obecnie procedura wydawni-
cza jest wysoce zautomatyzowana, wciąż mogą wkradać się do niej błędy popełnione przez
autora, wydawcę lub drukarza — a ich poprawianie stanowi doskonałą okazję do wprowa-
dzania nowych błędów.
Mimo iż niektóre etapy procesu wydawniczego — takie jak przepisywanie rękopisu —
mogą się wydać mało wyzywające intelektualnie i są z natury proste, jednak ich monotonny
charakter i rozmiar (sześć tomów Władcy Pierścieni liczy 1000 z okładem stron) uniemożliwia
wręcz ustrzeżenie się wszelkich błędów.
Tworzenie i implementowanie modelu projektu obiektów w podobny sposób łączy się
z wieloma transformacjami. Przykładowo programiści dokonują lokalnych usprawnień mo-
delu pod kątem poprawy jego modularności i wydajności; dokonują także przekształcania
skojarzeń obecnych w modelu na referencje między obiektami, języki programowania nie wy-
kazują bowiem żadnego wsparcia dla koncepcji skojarzeń. Większości języków programowania
obca jest też idea kontraktów, programiści muszą więc implementować we własnym zakresie
weryfikację ich spełnienia. Także starannie zdefiniowane interfejsy nie są bytem niezmiennym,
bo zmieniające się wymagania klienta mogą prowadzić do ich modyfikowania — czynności
pociągającej intelektualnie zdecydowanie mniej niż na przykład analiza wymagań czy pro-
jektowanie systemu, lecz koniecznej do wykonania, mechanicznej, powtarzalnej i męczącej,
gdy wziąć pod uwagę jej skalę. Co gorsza, nie da się ona zbyt dalece automatyzować, bo wy-
maga podejmowania decyzji, których nie sposób rozstrzygać w sposób algorytmiczny.
Każda ze wspomnianych transformacji niesie ze sobą ryzyko popełnienia błędów, wy-
krywanych później na etapie testowania. Przedstawimy teraz kilka technik (ilustrowanych
stosownymi przykładami) umożliwiających redukowanie tego ryzyka.
Rysunek 10.1. Cztery typy transformacji opisywane w tym rozdziale, czyli transformacja modelu,
refaktoryzacja kodu, inżynieria postępująca i inżynieria odwracająca
Z reguły każde tworzenie systemu może być traktowane jak ciąg transformacji modelu
analitycznego dający w efekcie model projektu obiektów, który następnie uzupełniany jest suk-
cesywnie obiektami realizacyjnymi. Jakkolwiek transformacja modelu jest czynnością w dużym
stopniu mechaniczną, właściwy wybór transformacji dla określonego zbioru klas wymaga du-
żego doświadczenia.
450 Rozdział 10. • Odwzorowywanie modelu na kod
10.3.2. Refaktoryzacja
Refaktoryzacja kodu ma na celu polepszenie jego czytelności lub modyfikowalności, bez wpływu
na funkcjonalność, o czym pisze M. Fowler [Fowler, 2000]. Refaktoryzacja koncentruje się
zwykle na specyficznym polu lub metodzie klasy; aby wyeliminować ryzyko niezamierzonego
wprowadzenia zmian w zachowaniu systemu, refaktoryzację przeprowadza się zwykle jako
serię prostych kroków, z których każdy weryfikowany jest za pomocą odpowiednich testów
(refaktoryzacja przeplata się więc z testowaniem). Istnienie zestawu testowego dla każdej klasy
pozwala programistom z jednej strony, nabierać zaufania do poprawności przeprowadzanych
przez siebie zabiegów, z drugiej natomiast, zachęca ich do pozostawiania interfejsów w nie-
zmienionym stanie bądź ewentualnie modyfikowania ich tylko w takim stopniu, jaki naprawdę
jest konieczny.
I tak na przykład transformacja przedstawiona na rysunku 10.2 przekłada się na trzy
refaktoryzacje. Pierwsza obejmuje wciągnięcie pola (Pull Up Field) z subklas do wspólnej su-
perklasy; druga — wciągnięcie treści konstruktora (Pull Up Constructor Body) — przenosi
z subklas do superklasy kod inicjujący to pole, trzecia wreszcie — wciągnięcie metod (Pull Up
Method) — polega na przeniesieniu z subklas do superklasy metod operujących na polu (atry-
bucie) emai 1. Przyjrzyjmy się szczegółowo wszystkim trzem.
Wciągnięcie pola, ukazane na listingu 10.1, obejmuje następujące kroki:
} }
} }
public class LeagueOwner extends User { public class LeagueOwner extends User {
public LeagueOwner(String email) { public LeagueOwner(String email) {
this.email = email; super(email);
} }
} }
public class Advertiser extends User { public class Advertiser extends User {
public Advertiser(String email) { public Advertiser(String emai1) {
this.email = email; super(email);
} }
} }
Uzyskaliśmy zatem zlokalizowane pole emai 1 i jego inicjację w klasie User. Kolejnym
krokiem będzie wyodrębnienie z klas PI ayer, LeagueOwner i Adverti ser metod operujących
na polu emai 1 i wciągnięcie tych metod do superklasy.
1. Analizując klasę PI ayer, zauważamy metodę not i fy (), operującą wyłącznie na polu
emai 1 i niewykonującą żadnych czynności specyficznych dla klasy PI ayer.
2. Kopiujemy metodę not i f y () do superklasy User i rekompilujemy kod.
3. Usuwamy metodę not i fy () z klasy PI ayer.
4. Kompilujemy i testujemy kod.
5. W analogiczny sposób identyfikujemy podobne metody w klasach LeagueOwner
i Adverti s e r i dla każdej z tych metod powtarzamy kroki od 2. do 4.
452 Rozdział 10. • Odwzorowywanie modelu na kod
User LeagueOwner
+email:String +niaxNumLeagues:1nt
+notify(msg:String)
Rysunek 10.3. Realizacja klas User i LeagueOwner w postaci diagramu klas UML i fragmentów kodu
w języka Java. W wyniku transformacji publiczna widzialność atrybutów emai 1 i maxNumLeagues od-
zwierciedlona zostaje w postaci par publicznych metod przeznaczonych do odczytywania i modyfikowa-
nia wartości tych atrybutów. Same atrybuty reprezentowane są natomiast w postaci pól prywatnych
Decyzja o kolapsacji danej klasy nie zawsze jest decyzją oczywistą. Z klasą Soci al Securi ty
mogły być na przykład skojarzone operacje generowania unikalnych identyfikatorów w opar-
ciu o numer ubezpieczenia i specyfikę komputera, na którym ma być docelowo eksploatowany
system. Ogólnie zatem programiści powinni powstrzymywać się z kolapsacją, aż do czasu roz-
poczęcia implementowania danej klasy, kiedy to zakres jej odpowiedzialności stanie się w pełni
oczywisty. Ponieważ istnieć już będzie najprawdopodobniej duża porcja kodu, w następstwie
kolapsacji klasy może być konieczna jego refaktoryzacja.
10.4. Aktywności odwzorowywania 457
W książce M. Fowlera [Fowler, 2000] opisana jest metoda transformacji kodu źródłowego,
stanowiąca odpowiednik kolapsacji wykonywanej na modelu obiektów, a nazywana popularnie
wchłonięciem klasy (w oryginale Inline Class Refactoring). Jej wykonanie przekłada się na na-
stępujący ciąg kroków:
Niektóre metody, wywoływane bardzo wiele razy, zwracają wynik bazujący na warto-
ściach, które zmieniają się bardzo rzadko albo nie zmieniają się wcale. W metodach tego ro-
dzaju kryją się potężne nieraz możliwości poprawy wydajności systemu: niezmieniającą się
wartość można obliczyć jeden raz i każdorazowo, gdy będzie potrzebna w przyszłości, odwo-
ływać się do zapamiętanego wyniku (przy okazji jednak pilnując jego aktualności). Jako przykład
458 Rozdział 10. • Odwzorowywanie modelu na kod
Rysunek 10.5. Opóźnianie kosztownych operacji przy użyciu wzorca projektowego Proxy
public class A d v e r t i s e r {
private Account account;
public A d v e r t i s e r ( ) {
account = new Account();
}
public Account getAccount() {
return a c c o u n t ;
}
}
Nadawanie wartości obu polom odbywa się z inicjatywy konstruktora klasy Adverti ser:
do wywoływanego konstruktora klasy Account obiekt wywołujący przekazuje referencję do
samego siebie ( t h i s ) jako wartość przeznaczoną do przypisania polu owner, jednocześnie
obiekt ten przypisuje własnemu polu account referencję do obiektu utworzonego przez kon-
struktor klasy Account:
W układzie z rysunku 10.7 obie klasy są od siebie uzależnione również w tym sensie, że
w przypadku zmian w jednej z nich obie wymagają rekompilacji. W przypadku skojarzenia
jednokierunkowego związek ten był nieco luźniejszy — klasa Account była niewrażliwa na
zmiany w obrębie klasy Adverti ser. Wybór między użyciem skojarzenia jedno- albo dwukie-
runkowego jest zawsze uwarunkowany specyfiką konkretnego kontekstu; by ułatwić sobie
ewentualną zmianę między jednym a drugim, pozostawiamy ukryte oba atrybuty reprezentu-
jące skojarzenie, co sprawia, że stają się one osiągalne tylko za pośrednictwem metod dostępo-
wych get... (), co minimalizuje ewentualne zmiany w interfejsie API.
Skojarzenia „jeden na wiele". Skojarzenia „jeden na wiele" nie są realizowalne ani za pomocą
pojedynczej referencji, ani za pomocą pary referencji: po stronie „wiele" wystąpić musi
kolekcja referencji. Załóżmy, że w systemie ARENA jednemu reklamodawcy (Adverti ser)
przyporządkowano wiele kont (Account), z których każde dedykowane jest reklamowaniu
innego produktu. Skojarzenie klasy Adverti ser z klasą Account jest więc skojarzeniem typu
„jeden na wiele" (patrz rysunek 10.8). Ponieważ konta należące do jednego reklamodawcy nie
występują w jakiejś określonej kolejności i dane konto należy do co najwyżej jednego rekla-
modawcy, po stronie „wiele" skojarzenia użyjemy zbioru referencji, nazwanego accounts. Jako
że opisywane skojarzenie jest dwukierunkowe, stąd, oprócz oczywistych metod addAccount ()
i removeAccount () definiowanych w klasie Adverti ser i służących do modyfikowania kolekcji
accounts, w klasie Account pojawia się metoda setOwnerQ służąca przypisywaniu konta do
jego właściciela poprzez nadawanie odpowiedniej wartości polu owner.
Podobnie jak w przypadku skojarzenia „jeden do jednego", skojarzenia między obiek-
tami klas Adverti ser i Account muszą zostać zrealizowane podczas ich tworzenia. Ponieważ
jednak z danym obiektem Adverti ser może być skojarzona różna liczba obiektów Account,
za wywoływanie konstruktora klasy Account nie odpowiada obiekt klasy Adverti ser, a specjalny
obiekt sterujący, odpowiedzialny za tworzenie i archiwizowanie obiektów Account.
Zauważmy także, iż wybór konkretnego wariantu kolekcji po stronie „wiele" uwarun-
kowany jest ograniczeniem narzuconym na skojarzenie: ponieważ wśród obiektów Account
skojarzonych z konkretnym obiektem Adverti ser nie istnieje żadne szczególne uporząd-
kowanie, referencje do tych obiektów przechowywane są w formie zwykłego zbioru (HashSet);
gdyby jednak istniała wśród nich relacja porządkującą, musielibyśmy przechowywać je w postaci
listy (List). Aby uniezależnić interfejs od tej różnicy, zdefiniowaliśmy metodę getAccountsQ
tak, by zwracała wynik typu Col 1 e c t i on — to wspólna superklasa dla klas Li s t i Set.
Skojarzenia „wiele na wiele". Jak łatwo się domyślić, w tym przypadku obie strony skoja-
rzenia reprezentowane są w postaci kolekcji referencji, a odpowiednie operacje mają za
zadanie utrzymywanie spójności między tymi kolekcjami. Sięgnijmy znów do systemu ARENA,
gdzie w danym turnieju (Tournament) może być zarejestrowanych wielu graczy (PI ayer) i jed-
nocześnie dany gracz może być zarejestrowany w wielu turniejach. Obie wspomniane kolekcje
mają tym razem postać listy ( L i s t ) , a za zarządzanie nimi odpowiedzialne są metody
addPlayerQ, removePlayerQ, addTournamentQ i removeTournamentO (patrz rysunek 10.9);
dwie początkowe operacje zidentyfikowaliśmy w modelu projektu obiektów (patrz rysunek
9.10) z tą różnicą, że pierwsza z nich nosiła tam nazwę acceptPl ayer (), którą to nazwę zmie-
niliśmy tu na addPl ayer ()w celu utrzymania spójności z kodem generowanym dla innych
462 Rozdział 10. • Odwzorowywanie modelu na kod
Rysunek 10.10. Przykład realizacji dwukierunkowego skojarzenia kwalifikowanego; strzałki wskazują kie-
runek transformacji
464 Rozdział 10. • Odwzorowywanie modelu na kod
Rysunek 10.11. Transformacja skojarzenia „wiele na wiele" na dwa skojarzenia z pośredniczącą kla-
są skojarzeniową
10.4. Aktywności odwzorowywania 465
Listing 10.3. Przykład generowania i obsługi wyjątku w języku Java. Klasa TournamentForm przechwytuje
wyjątek wygenerowany przez klasę TournamentControl i przekazuje go klasie ErrorConsol e w celu
wyświetlenia stosownego komunikatu dla użytkownika
}
public class TournamentForm {
private TournamentControl control;
private List players;
Jeżeli zatem nie dysponujemy narzędziem w rodzaju iContract, opisanym przez R. Kra-
mera [Kramer, 1998], które dokonuje automatycznego generowania kodu, musimy zastoso-
wać podejście pragmatyczne, godzące względy poprawności systemu z wymienionymi powyżej
przesłankami przemawiającymi przeciwko nadmiernemu jej weryfikowaniu. Jak pamiętamy,
kontrakty stanowią narzędzie wspomagające komunikację między programistami, zatem ge-
nerowanie wyjątków w związku z naruszeniem tych kontraktów powinno koncentrować się
raczej wokół interfejsów klas niż wokół ich implementacji. Poniższy zestaw heurystyk może
okazać się pomocny przy rozstrzyganiu rozmaitych kompromisów w tym względzie.
Rysunek 10.13. Przykład tabeli relacyjnej bazy danych, z trzema kolumnami i trzema rekordami
470 Rozdział 10. • Odwzorowywanie modelu na kod
Kluczem głównym (primary key) tabeli jest minimalny zbiór jej atrybutów ze swej natury
jednoznacznie identyfikujący poszczególne jej rekordy. Klucz ten pełni istotną rolę w identy-
fikowaniu rekordów tabeli w przypadku ich modyfikowania, usuwania i dodawania nowych.
W tabeli z rysunku 10.13 rolę klucza głównego może pełnić atrybut 1 ogi n, lecz równie do-
brze mógłby ją pełnić atrybut emai 12. Każdy zbiór atrybutów kwalifikujących się do miana
klucza głównego nazywany jest kluczem kandydackim; klucz główny jest więc rezultatem
wyboru spośród wszystkich kluczy kandydackich.
Klucz obcy (foreign key) to zbiór atrybutów (lub pojedynczy atrybut) stanowiący odwoła-
nie do klucza głównego innej tabeli. Klucz obcy wiąże konkretny rekord jednej tabeli z rekor-
dem lub grupą rekordów w innej. Na rysunku 10.14 widzimy fragment tabeli League ukazujący
dwie kolumny reprezentujące nazwę ligi (name) i login jej kapitana (owner) — ten ostatni
jest kluczem obcym do tabeli User z rysunku 10.13. Tak więc Alice (login am384) jest kapitanem
lig t i ctactoeNovi ce i t i ctactoeExpert, zaś John (login j s289) jest kapitanem ligi chessNovi ce.
Rysunek 10.14. Przykład klucza obcego: atrybut owner tabeli League odpowiada kluczowi główne-
m u tabeli User
2
Pod warunkiem, że dwoje różnych użytkowników nie będzie mogło współdzielić tego samego ad-
resu e-mail, co nie jest takie oczywiste jak w przypadku unikalności loginu — przyp. tłum.
10.4. Aktywności odwzorowywania 471
Stri ng w pole tekstowe jest o tyle utrudnione, że większość systemów baz danych (zgodnie
zresztą z semantyką języka SQL) wymaga określenia maksymalnej długości przechowywanego
napisu. I tak na przykład w systemie ARENA, odwzorowując klasę User, można ograniczyć dłu-
gość nazwy (imienia) użytkownika do 25 znaków, co odpowiada typowi text [25] języka SQL.
Ograniczenie to wiąże się z koniecznością zdefiniowania odpowiednich warunków wstępnych
dla obiektów encji i obiektów brzegowych.
Klucz główny tabeli zdefiniować można na dwa sposoby: identyfikując zbiór atrybutów
unikalnie identyfikujący każdy rekord 3 albo definiując w tym celu osobny atrybut, którego
unikalna wartość będzie automatycznie generowana dla każdego nowo dodawanego rekordu.
W tabeli pokazanej na rysunku 10.13 zastosowaliśmy pierwsze podejście. Mimo iż jest
to podejście intuicyjne, ma jednak tę niedogodność, że gdy zmieni się wartość pola wchodzą-
cego w skład klucza (tu: pola 1 ogi n), należy zaktualizować wszystkie tabele, które powołują się
na ten klucz (za pomocą swego klucza obcego). Jeżeli ponadto atrybuty wchodzące w skład
klucza głównego zaczerpnięte są z dziedziny aplikacyjnej, stajemy przed perspektywą ewentu-
alnej przebudowy całej bazy w przypadku zmian zachodzących w tej dziedzinie. Przykładowo
w systemie ARENA login każdego użytkownika jest unikalny w ramach jednej instancji tego
systemu. Jeżeli w przyszłości zdecydowalibyśmy się utrzymywać w pojedynczej tabeli dane
wszystkich użytkowników powiązanych z pewnym zbiorem instancji tego systemu, może się
zdarzyć, że w ramach tej tabeli dwóch użytkowników posiadać będzie ten sam login — nie bę-
dziemy więc mogli użyć pola 1 ogi n w charakterze klucza głównego.
Generowanie unikalnego, niezmiennego identyfikatora (id) dla każdego nowo doda-
wanego rekordu tabeli oferowane jest przez wiele współczesnych systemów baz danych. Daje
ono w rezultacie bardziej solidny schemat i prostszy, bo jednokolumnowy, klucz. Przykładowo
w systemie ARENA klasę User odwzorować można w tabelę o czterech kolumnach: i d, f i rstName,
1 ogi n i emai 1 (patrz rysunek 10.15). W pole i d każdego nowo tworzonego rekordu wpisywana
jest wartość pewnej ukrytej zmiennej, inkrementowanej przy każdym dodawaniu rekordu.
Rysunek 10.15. Odwzorowanie klasy User w tabelę bazy danych, z wykorzystaniem automatycznie
generowanego pola kluczowego (i d)
3
Tak zdefiniowany klucz główny nazywany jest kluczem naturalnym — przyp. tłum.
472 Rozdział 10. • Odwzorowywanie modelu na kod
Odwzorowywanie skojarzeń
zbiór rekordów prowadzących do turniejów, w których gracz ten się zarejestrował. Z zawartości
tabel przedstawionych na rysunku 10.17 wynika, że gracze al ice i john zarejestrowani są
w t u r n i e j u novi ce.
Zauważmy, że skojarzenia „jeden do jednego" i „jeden na wiele" również mogą być re-
alizowane za pomocą tabeli skojarzeniowej, zamiast przy użyciu skrytych powiązań. Imple-
mentacja taka sprawia, że schemat staje się bardziej elastyczny: jeżeli na przykład zmienimy
typ odnośnego powiązania z „jeden na wiele" na „wiele na wiele", nie będzie trzeba w ogóle
zmieniać schematu bazy danych. Ceną płaconą za tę elastyczność będzie jednak większa liczba
tabel i bardziej czasochłonna trawersacja skojarzeń — znowu mamy do czynienia z kompro-
misem, który rozstrzygnięty musi być w oparciu o takie przesłanki jak prawdopodobieństwo
zmiany typu skojarzenia w przyszłości oraz krytyczność czasu reakcji systemu.
Gdy więc chcemy odczytać z bazy określony obiekt, rozpoczynamy od tabeli reprezentu-
jącej superklasę. Poszczególne pola odnalezionego rekordu zawierać będą informację dziedzi-
czoną z superklasy oraz wskazanie tabeli reprezentującej subklasę, w której to tabeli należy poszu-
kiwać rekordu zawierającego resztę informacji. W przypadku dziedziczenia wielopoziomowego
opisaną zależność stosuje się rekurencyjnie.
10.5. Zarządzanie transformacjami 475
4
O ile nie będą w bazie przechowywane rekordy będące instancjami tej superklasy — przyp. tłum.
476 Rozdział 10. • Odwzorowywanie modelu na kod
kodu źródłowego. By jednak tego typu doświadczenia mogły zachowywać swą użyteczność
przez cały czas życia systemu, konieczne jest dokumentowanie wszelkich transformacji, tak
by można było je w sposób spójny powtarzać w przypadku wprowadzania zmian do modelu
lub kodu źródłowego.
Inżynieria odwracająca pomyślana została jako działanie mające złagodzić związane
z tym problemy poprzez odtworzenie modelu obiektów na podstawie kodu źródłowego. Ge-
neralnie, jeżeli utrzymujemy odpowiedniość „jeden do jednego" między kodem źródłowym
a modelem, nie potrzebujemy żadnej dokumentacji: używane narzędzia powinny zapewnić
spójność kodu z modelem, gdy wprowadzamy zmiany do jednego lub drugiego. Problem jed-
nak w tym, że te najbardziej użyteczne transformacje, włącznie z opisywanymi w tym rozdziale,
nie są transformacjami „jeden do jednego" i gubią część informacji.
• Skojarzenia jednokierunkowe typu „jeden na wiele" dają w rezultacie taki sam kod
źródłowy jak skojarzenia jednokierunkowe typu „wiele na wiele" w procesie trans-
formowania w kolekcje. Narzędzia inżynierii odwracającej przyjmują w takiej sytuacji
wariant mniej restrykcyjny, czyli zakładają typ „wiele na wiele" oryginalnego skoja-
rzenia. Ogólnie informacja na temat krotności danego skojarzenia rozproszona jest
po kodzie źródłowym, między innymi znajduje się zwykle również w kodzie weryfi-
kującym kontrakty dla obiektów brzegowych.
• Skryte powiązania implementujące w schematach baz danych skojarzenia typu
„jeden do jednego" i „jeden na wiele" obarczone są tym samym mankamentem. Co
więcej, implementacje skojarzeń za pomocą tabel pośredniczących kompletnie gubią
informację na temat typu tych skojarzeń.
• Warunki końcowe i niezmienniki. Odwzorowując niespełnione kontrakty w genero-
wanie wyjątków (sekcja 10.4.3), uwzględniamy zwykle tylko warunki wstępne, pomi-
jając sprawdzanie warunków końcowych niezmienników. Ryzykujemy w ten sposób
gubienie informacji o warunkach końcowych i niezmiennikach, przez co w wyniku
kolejnych zmian system może stawać się coraz bardziej niespójny.
Przeprowadzenie danej transformacji po raz pierwszy nie wydaje się być zadaniem szcze-
gólnie skomplikowanym, ta oczywistość blednie jednak przy powtórnym stosowaniu wspo-
mnianej transformacji w wyniku wprowadzonych zmian. Dlatego przypisując poszczególne
zakresy odpowiedzialności, należy być świadomym tego, kto powinien być powiadamiany o tych
zmianach.
z interfejsem klasy S t a t i s t i cs, jest zadaniem programistów opracowujących grę. Jeżeli kon-
kretna gra nie wymaga specyficznej statystyki, system ARENA oferuje jej programistom klasę
Defaul t S t a t i s t i c s realizującą statystykę standardową. Jak wynika z rysunku 10.20, system
ARENA nie odwołuje się do konkretnych specjalizacji klas Game i Stati s t i c s , co jest potwier-
dzeniem jego niezależności od specyfiki konkretnej gry.
Rysunek 10.20. Specjalizowany obiekt Stat istics jako jeden z produktów Fabryki abstrakcyjnej Game
Jednym z celów projektowych systemu ARENA jest nadanie interfejsowi klasy Stati s t i cs
jak najprostszej postaci, tak by programiści tworzący nowe gry mogli z łatwością imple-
mentować zbieranie statystyki w sposób specyficzny dla tej gry; innymi słowy, specjalizacja
obiektu Stati s t i cs dla konkretnej gry powinna być odpowiedzialna jedynie za definiowanie
formuł statystycznych dla tej gry — zarządzanie zakresami poszczególnych statystyk leży już
bowiem w gestii systemu ARENA.
Wobec powyższego na etapie projektowania obiektów podejmujemy decyzję o obli-
czaniu wszelkich statystyk w sposób przyrostowy, to znaczy po zakończeniu każdego meczu
(Match). Dla każdego zakresu przewidzianego w systemie ARENA (vide lista na początku tej
sekcji) utrzymywać więc będziemy oddzielny licznik, co prowadzi do osobnych obiektów
S t a t i s t i cs dla każdej gry (Game), ligi (League) i turnieju (Tournament) oraz dla każdej kom-
binacji „gracz-gra", „gracz-liga" i „gracz-turniej".
I tak na przykład załóżmy, że gracz John bierze udział w dwóch turniejach: t l i tZ, w lidze
nowicjuszy gry w kółko i krzyżyk. Po pewnym czasie awansuje do ligi ekspertów tej gry i bie-
rze udział w turnieju t 3 organizowanym przez tę ligę. Załóżmy ponadto, że interesują nas
liczba wygranych Johna w każdej z gier (Game). Spełnienie powyższych założeń wymaga zbie-
rania sześciu statystyk, obejmujących:
480 Rozdział 10. • Odwzorowywanie modelu na kod
Rysunek 10.21. N-arne skojarzenie klasy S t a t i s t i c z klasami PI ayer, Game, League i Tournament
Rysunek 10.23. Klasa S t a t i s t i csVaul t jako fasada separująca obiekty brzegowe i sterujące od obli-
czania i przechowywania statystyk
482 Rozdział 10. • Odwzorowywanie modelu na kod
publ ic Li s t g e t S t a t N a m e s Q {...}
Zauważmy, że wyjątek Inval idScope wspólny jest dla trzech warunków wstępnych.
W rezultacie otrzymujemy podobne deklaracje wszystkich trzech aspektów metody getStat (),
co umożliwia klasie wywołującej jednolitą obsługę wyjątków generowanych przez wszystkie te
aspekty. Generalnie, wszystkie aspekty tej samej metody przeciążonej powinny mieć podobny
interfejs, wszystkie implementują bowiem tę samą operację, a różnią się jedynie typami para-
metrów wywołania.
484 Rozdział 10. • Odwzorowywanie modelu na kod
Rysunek 10.24. Schemat bazy danych odzwierciedlający n-arne skojarzenie klasy S t a t i s t i c s z ry-
sunku 10.21
10.6.5. Wnioski
Transformując n-arne skojarzenie klasy Stati s t i cs na kod źródłowy programu i schemat bazy
danych, mogliśmy zauważyć, że:
10.8. Ćwiczenia
10.1. Na stronie W W W tabela złożona jest z wierszy, które z kolei składają się z komórek.
Szerokość i wysokość każdej komórki ustalana jest na bieżąco na podstawie jej
zawartości (tekstu, obrazka), a wysokość wiersza przyjmowana jest jako największa
wysokość jego komórki. Wynika stąd, że ostateczny układ tabeli na stronie W W W
może zostać ustalony dopiero wówczas, gdy cała wyświetlana zawartość zostanie po-
brana z internetu. Wykorzystując wzorzec projektowy Proxy, przedstawiony na
rysunku 10.5, zaproponuj model obiektowy i algorytm umożliwiający przeglądarce
rozpoczęcie wyświetlania tabeli, zanim jeszcze staną się ostatecznie wiadome roz-
miary jej komórek — oczywiście, gdy staną się znane, może być konieczne ponowne
narysowanie całej tabeli.
10.2. Zastosuj opisane w sekcji 10.4.2 transformacje do skojarzeń przedstawionych na
rysunku 10.25. Zakładamy, że wszystkie skojarzenia są dwukierunkowe i że mogą się
zmieniać w czasie życia obiektów. Utwórz kod źródłowy zarządzający tymi skoja-
rzeniami, wraz z deklaracjami klas, pól i metod i ich widzialności oraz implementa-
cjami metod.
10.4. Na rysunku 10.12 widoczny jest kod weryfikujący kontrakt dla metody Tournament.
^ a d d P l a y e r (). Napisz podobny kod dla innych ograniczeń związanych z klasą
Tournament, widocznych na listingu 9.2.
10.5. Dla kontraktów klas TournamentStyle i Round, omówionych w sekcji 9.6.2, napisz
kod weryfikujący warunki wstępne, warunki końcowe i niezmienniki.
10.6. Zaprojektuj schemat relacyjnej bazy danych dla modelu obiektowego przedstawionego
na rysunku 10.26. Zakładamy, że z każdym obiektem klasy League, Tournament,
PI ayer i Round związany jest unikalny identyfikator, a ponadto w klasie Tournament
i Round zdefiniowane są atrybuty s t a r t i end reprezentujące m o m e n t rozpoczęcia
i zakończenia (odpowiednio) turnieju i rundy. Wybierając między dostępnymi trans-
formacjami, uwidocznij kryteria tego wyboru.
10.7. Narysuj diagram klas reprezentujący poniższe fakty z dziedziny aplikacyjnej i od-
wzoruj je na schematy relacyjnej bazy danych.
• Projekt obejmuje pewną liczbą uczestników.
• Uczestnik może brać udział w projekcie jako menedżer projektu, kierownik
zespołu lub programista.
• W ramach projektu każdy programista i każdy kierownik zespołu muszą być
członkami co najmniej jednego zespołu.
• Uczestnik jednego projektu może uczestniczyć także w innym projekcie, być może
w innej roli: przykładowo programista w projekcie A może być kierownikiem
zespołu w projekcie B i menedżerem projektu C. Jego rola w każdym z projektów
pozostaje niezmienna.
10.8. Istnieją dwa podejścia do odwzorowywania skojarzeń na zbiory kolekcji. W sekcji
10.6.2 przedstawiliśmy odwzorowanie n-arnego skojarzenia klasy Stati s t i cs na dwie
klasy: S t a t i s t i c s , utrzymującą atrybuty skojarzenia, oraz S t a t i s t i csVaul t utrzy-
mującą stan powiązań między obiektami. W sekcji 10.4.2 opisaliśmy podejście alter-
natywne, polegające na reprezentowaniu skojarzenia w jednym lub obu obiektach
będących jego uczestnikami. W tym drugim przypadku mamy do czynienia z parą
rekursywnych metod zapewniających spójność obu struktur danych. Wykorzystaj
to alternatywne podejście do odwzorowania n-arnego skojarzenia Stati s t i cs w zbiór
kolekcji. Jakie są zalety obu wspomnianych rozwiązań i jakie kompromisy trzeba
rozstrzygać przy wyborze między jednym a drugim?
Bibliografia
[Beck i Andres, 2005] K. Beck, C. Andres Extreme Programming Explained: Embrace Change,
wyd. drugie, Addison-Wesley, Reading, MA, 2005.
[Gamma i in., 1994] E. Gamma, R. Helm, R. Johnson,}. Vlissides Design Patterns: Elements
of Reusable Object-Oriented Software, Addison-Wesley, Reading, MA,
1994. Wydanie polskie Wzorce projektowe. Elementy oprogramowania
obiektowego wielokrotnego użytku, Helion 2010.
[Kramer, 1998] R. Kramer „iContract — The Java design by contract tooF' Technology
of Object-Oriented Languages and Systems, IEEE Computer Society Press,
str. 295, 1998.
[Tolkien, 1995] J.R.R. Tolkien The Lord of The Rings, Harper Collins, 1995.
11.1. Wstęp: testowanie wahadłowców 492
Bibliografia 544
Testowanie
W trakcie prawie 250 000 sekund pracy zdarzyło się 16 poważnych awarii silników. Inżyniero-
wie bardzo poważnie przeanalizowali przyczyny tych awarii i podjęli wysiłki w celu ich jak naj-
szybszego usunięcia. Pomogły im w tym testowe analizy różnych atrap eksperymentalnych, za-
projektowanych specjalnie w związku ze wspomnianymi awariami, pozwalającymi na formułowanie
i weryfikowanie rozmaitych hipotez [...].
Zespół głównych silników wahadłowca to bardzo skomplikowane urządzenie, od którego wymaga się
wysokiej niezawodności i do którego zaufanie wynika wprost z zaufania do jego poprzedników. Jest
ono jednak budowane na granicy — a wielu przypadkach poza granicą — dotychczasowych do-
świadczeń. Nie dziwią więc rozmaite usterki zdarzające się przy tej okazji — usterki trudne do
wykrywania i naprawiania, ze względu na „zstępującą" strategię konstruowania wahadłowca.
Zamierzenie projektantów zrealizowania przez SSME odpowiedników 55 misji (27 000 operacji,
symulujących 500-sekundowe misje) nie zostało wykonane. Silniki wymagają obecnie częstych
przeglądów i napraw kluczowych części, takich jak turbopompy, łożyska, osłony i pokrycia bla-
szane i tym podobnych. Wysokoprężne p o m p y paliwowe wymagały wymiany co trzeci lub
czwarty ekwiwalent misji (choć później były naprawiane), zaś p o m p y tłoczące ciekły tlen — co
sześć ekwiwalentnych misji. To zaledwie 10% początkowych zamiarów.
1
Patrz http:/7pl.wikipedia.org/ wiki/Główne_silntki_promu_kosrnicznego — przyp. tłum.
2
Feynman napisał swój artykuł [Feynman, 1988] w czasie, gdy był członkiem prezydenckiej komisji
badającej przyczyny eksplozji promu kosmicznego Challenger w dniu 28 stycznia 1986 roku. Przyczynę
katastrofy upatrywał w uszczelce O-ring w zespole rakiet wspomagających, a dokładniej — w utracie
przez tę uszczelkę elastyczności wskutek zamarznięcia. W artykule, oprócz problemów związanych
z testowaniem głównych silników i rakiet wspomagających, zawarte są również uwagi na temat stop-
niowo zmieniających się kryteriów kluczowych testów akceptacyjnych oraz problemów wynikają-
cych z niedostatecznej komunikacji między kierownictwem projektu a jego wykonawcami w ramach
ściśle hierarchicznej organizacji.
494 Rozdział 11. • Testowanie
• Unikanie usterek polega na ich wykrywaniu w sposób statyczny, bez związku z wyko-
nywaniem oprogramowania ani z jego modelami czy kodem źródłowym. Jest to de
facto zapobieganie usterkom za pomocą odpowiednich metodologii programistycz-
nych, zarządzania konfiguracją i weryfikacji.
• Wykrywanie usterek przy użyciu debugowania i testowania, które stanowią (od-
powiednio) niekontrolowany i kontrolowany eksperyment, to identyfikowanie błęd-
nych stanów systemu przed przekazaniem go do eksploatacji. Techniki wykrywania
usterek pomagają w ich odnajdywaniu, nie obejmują jednak likwidowania powodo-
wanych przez nie awarii. Zasadniczo techniki te stosowane są w czasie tworzenia
systemu, ale w pewnych przypadkach mogą być wykorzystywane także po jego
przekazaniu do eksploatacji. Przykładem ich zastosowania są czarne skrzynki w sa-
molotach, rejestrujące kilka ostatnich minut lotu.
• Tolerowanie usterek oznacza radzenie sobie przez pracujący system z konsekwen-
cjami tychże usterek. Przykładowo w systemie ze zwielokrotnionymi modułami kilka
redundantnych komponentów wykonuje równocześnie to samo zadanie, po czym
wyniki uzyskane przez wszystkie komponenty są ze sobą porównywane. Na pokładzie
promu kosmicznego znajduje się pięć komputerów wykonujących dwa różne rodzaje
oprogramowania w celu wykonywania tych samych zadań.
3
To „szukanie dziury w całym" realizowane jest poprzez dobór jak najbardziej dziwacznych, kurio-
zalnych danych testowych; testerzy w tym kontekście nazywani bywają często „zawodowymi
idiotami" (nie ma to być obelga), posługują się bowiem danymi, których w innych okoliczno-
ściach mógłby użyć tylko kompletny idiota. Analogicznie, solidne oprogramowanie opierające się
skutecznie p r ó b o m załamania w ten sposób określane bywa popularnie m i a n e m „idiotoodporne-
go" (follproof) — przyp. tłum.
11.2. O testowaniu ogólnie 497
4
C2ytelnikom, którym kwestia ta wydaje się oczywista, proponuję mały eksperyment: na podstawie znanego
I N N
wzoru na odchylenie standardowe cr = - ^ - ^ ( x / - x f ( x oznacza średnią arytmetyczną: )
I /=l /=i
napiszcie prosty program, a następnie zweryfikujcie jego zachowanie dla N = 0 (rzecz oczywista) oraz dla
N= 1 (rzecz już mniej oczywista, choć nie mniej ważna: dla N = 1 przyjmuje się (7= 0) — przyp. tłum.
498 Rozdział 11. • Testowanie
Rysunek 11.1. Aktywności testowania i związane z nimi produkty. Partycje diagramu wskazują wy-
konawców poszczególnych testów
• usterka (fault), zwana także „pluskwą" lub „defektem", to błąd projektu lub błąd
kodowania, mogący powodować nienormalne zachowanie systemu,
• błędny stan (erroneous state) to manifestowanie się usterki w czasie wykonywania
systemu; błędny stan może być konsekwencją jednej lub kilku usterek, a jego następ-
stwem jest awaria,
• awaria (failure) to rozbieżność między specyfikacją a faktycznym zachowaniem
systemu; awaria może być wywołana przez jeden lub kilka błędnych stanów, choć
nie każdy błędny stan musi doprowadzić do awarii 5 ,
• przypadek testowy (test case) to zestaw danych wejściowych dla systemu oraz wyni-
ków oczekiwanych od systemu na podstawie tych danych; w czasie testowania roz-
bieżność między wynikami oczekiwanymi a faktycznie produkowanymi przez system
jest świadectwem usterki,
• namiastka testowa (test stub) to częściowa implementacja komponentów, od któ-
rych uzależnione jest działanie testowanego komponentu, natomiast sterownik te-
stowy (test driver)to częściowa implementacja komponentów, których działanie uza-
leżnione jest od testowanego komponentu, namiastki i sterowniki testowe umożliwiają
izolowanie testowanych komponentów (w czasie testowania) od reszty systemu,
• poprawka (correction) to zmiana wprowadzana do komponentu w celu naprawienia
(usunięcia) usterki; poprawki, mimo swego przeznaczenia, mogą stawać się źródłem
kolejnych usterek.
5
Należy zaznaczyć, że poza kręgami programistycznymi rzadko praktykuje się tak szczegółowe roz-
różnienie, kwalifikując wszelkie usterki, błędne stany i awarie jako (po prostu) „błędy".
500 Rozdział 11. • Testowanie
Rysunek 11.3. Przykład usterki — oczekujemy, że pojazd szynowy nie wykolei się
Generalnie, aby mówić o usterce, błędnym stanie czy awarii, musimy zarówno określić
oczekiwane zachowanie (w postaci przypadków użycia zapisanych w RAD), jak i zaobserwować
konkretne przejawy rzeczywistego zachowania. Do ewentualnego postrzegania niewyrównania
torowiska jako usterki sprecyzujmy więc to pierwsze w postaci przypadku użycia, przedstawione-
go w tabeli 11.1 i opisującego ruch pojazdu szynowego po pierwszym odcinku toru w kierunku
drugiego odcinka.
Tabela 11.1. Przypadek użycia Dri veTrai n specyfikujący oczekiwane zachowanie pojazdu szynowego
Warunek wstępny Trai nOperator uruchamia pojazd za pomocą dźwigni na panelu sterowania.
Przepływ zdarzeń 1. Pojazd zaczyna poruszać się po pierwszym odcinku toru w kierunku
drugiego.
2. Pojazd przejeżdża na drugi odcinek toru.
Kryteria zaliczenia!załamania testu Test zostaje zaliczony, jeśli pojazd poruszać się będzie
przez 5 sekund, pokonując co najmniej dwa odcinki toru.
Jeśli jednak nawet oba zespoły prawidłowo („zgodnie ze specyfikacją") ułożą („zaimple-
mentują") torowisko, mimo to, usterka może się w nim pojawić w codziennej eksploatacji, na
przykład wskutek osunięcia się podłoża spowodowanego trzęsieniem ziemi (patrz rysunek 11.6).
Innym, mniej spektakularnym niż trzęsienie ziemi przykładem usterki mechanicznej
jest usterka maszyny wirtualnej, na której działa system: jeśli nawet sam system zaimple-
mentowany jest prawidłowo, błędy odczytu lub zapisu na dysku czy błędna implementacja
którejś funkcji systemowej mogą zniekształcać pożądane zachowanie systemu. Usterki te-
go typu stają się szczególnie prawdopodobne w sytuacji, gdy sprzęt systemu projektowany
i tworzony jest równolegle z jego oprogramowaniem, bo wówczas maszyna wirtualna wciąż
11.4. Aktywności związane z testów_niem 503
jest bytem mało uchwytnym i nigdy nie można mieć gwarancji, że funkcjonuje tak, jak
oczekuje tego od niej oprogramowanie. Wreszcie, nawet przy bezbłędnej maszynie wirtu-
alnej i starannie przetestowanym oprogramowaniu może zdarzyć się usterka mechaniczna
w postaci wyłączenia zasilania. W tym kontekście pojęcia „usterki" i „awarii" nabierają rela-
tywnego znaczenia: awaria jednego komponentu (na przykład zasilacza) może stanowić
usterkę prowadzącą do wystąpienia awarii w innym komponencie (podsystemie).
Atrybut Znaczenie
name Nazwa przypadku testowego
location Kompletna ścieżka określająca lokalizację przypadku testowego
input Dane lub polecenia wejściowe
oracle Oczekiwane rezultaty testu, przeznaczone do konfrontacji z rzeczywistymi rezultatami
log Rzeczywiste wyniki produkowane przez system
Poszczególne przypadki testowe mogą być powiązane w dwojaki sposób: poprzez agrega-
cję lub poprzedzanie. Relacja poprzedzania, reprezentowana na diagramie przez skojarzenie
precede, określa wymaganą kolejność wykonywania dwóch testów. W przykładowym modelu
pokazanym na rysunku 11.7 przypadek testowy Test A składa się z dwóch przypadków składo-
wych TestAl i TestA2 (wykonanie obu oznacza wykonanie przypadku TestA, który nie posiada
fizycznej reprezentacji). TestA musi być wykonany przed rozpoczęciem wykonywania które-
gokolwiek z przypadków TestB i TestC, te jednak są od siebie wzajemnie niezależne i mogą być
przeprowadzanie równolegle. Dobry model testowy powinien posiadać jak najmniej skojarzeń,
gdyż wtedy składające się na niego testy mogą być w dużym stopniu zrównoleglone.
Rysunek 11.7. Skojarzenia między przypadkami testowymi w modelu testowania. TestA składa się z dwóch
testów TestAl i TestA2; testy TestB i TestC mogą być wykonywane niezależnie od siebie, przedtem
jednak konieczne jest wykonanie testu TestA
Zależnie od testowanych aspektów systemu lub modelu, przypadki testowe dzielą się na
czarnoskrzynkowe i białoskrzynkowe. Testy czarnoskrzynkowe (blackbox tests) skupiają się
wyłącznie na danych wejściowych i danych produkowanych przez komponent, w oderwaniu
od jego struktury wewnętrznej i tych aspektów jego zachowania, które są na zewnątrz niewi-
doczne. Testy białoskrzynkowe (whitebox tests) wnikają natomiast szczegółowo w wewnętrzną
strukturę i zachowanie komponentu, co ma przynieść zapewnienie, że niezależnie od przete-
stowania zewnętrznych aspektów zachowania komponentu, przetestowane zostaną wszystkie
powiązania między obiektami i wszystkie stany modelu dynamicznego. Testowanie biało-
skrzynkowe jest więc techniką wyraźnie bardziej obszerną; istotnie, większość testów biało-
skrzynkowych wykorzystuje dane niedające się wyprowadzić wyłącznie w oparciu o wyma-
gania funkcyjne. Testowanie jednostkowe łączy obie techniki: testy czarnoskrzynkowe
weryfikują funkcjonalność komponentu, podczas gdy testy białoskrzynkowe stanowią weryfi-
kację jego aspektów strukturalnych i dynamicznych.
11.4. Aktywności związane z testów_niem 505
11.3.4. Poprawki
Oczywiście, konsekwencją znalezienia usterek jest ich naprawianie poprzez dokonywanie
poprawek. Poprawki te mogą mieć rozmaitą skalę: od kosmetycznych modyfikacji pojedynczej
klasy do kompletnego przeprojektowania całego podsystemu, zawsze jednak niosą ze sobą ry-
zyko wprowadzenia nowych usterek. Minimalizowanie tego ryzyka umożliwiają rozmaite
techniki, między innymi:
506 Rozdział 11. • Testowanie
• Test scenariusza. Jednemu użytkownikowi lub kilku z nich prezentuje się wizjonerski
scenariusz systemu. Programiści uważnie oceniają stopień rozumienia tego scenariusza
przez użytkowników w kategoriach szybkości percepcji, adekwatności reprezentowa-
nia ich modelu pracy i ogólnego nastawienia do obrazu nowego systemu. Wspo-
mniany scenariusz powinien być jak najbardziej szczegółowy i realistyczny. Może on
11.4. Aktywności związane z testów_niem 509
6
Poszczególne etapy scenariusza mogą być także odzwierciedlone w formie scenopisu rysunkowego
(.storyboard), jakiego używa się w filmach animowanych: kolejne szkice mogą być chronologicznie
ułożone na ścianie lub podłodze, wtedy są łatwo dostępne do oglądania i oceny. W średniej wielkości
pomieszczeniu można w ten sposób zmieścić nawet kilkaset takich szkiców.
510 Rozdział 11. • Testowanie
Matematycznie podział zbioru elementów na klasy równoważności odbywa się w ten spo-
sób, że każda klasa stanowi jego podzbiór, poszczególne Masy są parami rozłączne i każdy ele-
ment należy do dokładnie jednej klasy. Podstawą tego podziału jest pewna relacja równoważno-
ści, zachodząca między dwoma dowolnymi elementami tej samej klasy i niezachodząca między
dowolnymi dwoma elementami należącymi do różnych klas. W przypadku testowania czarno-
skrzynkowego wspomnianymi elementami są wszelkie możliwe konfiguracje danych wejścio-
wych, zaś dwie konfiguracje uważane są za równoważne sobie, jeśli wywołują takie samo działanie
testowanego systemu. W tym kontekście pojawia się pomysł podziału wszystkich możliwych
danych wejściowych na klasy równoważności i użycie (w charakterze przypadków testowych) dla
danej klasy jedynie kilku reprezentantów. Oczywiście, zarówno wspomniany podział, jak i wybór
reprezentantów jest specyfiką konkretnego systemu, niemniej jednak przy ich dokonywaniu
należy mieć na względzie wspomniane na wstępie własności klas równoważności, czyli:
Dla każdej klasy równoważności należy uwzględnić co najmniej dwa elementy: jeden
reprezentujący „normalne" dane (z punktu widzenia poprawności) i drugi, reprezentujący dane
ewidentnie nieprawidłowe, których napotkanie system powinien skwitować wygenerowaniem
wyjątku. Jeśli trudno takiego wyboru dokonać, być może podzbiór elementów nie jest klasą
równoważności, bo został skonstruowany dość ogólnie i wymaga podziału na kilka prostszych
podzbiorów, które spełniać już będą własności klas równoważności.
Jako przykład zastosowania opisanej techniki rozpatrzmy testowanie metody zwracającej
liczbę dni w danym miesiącu danego roku kalendarza gregoriańskiego (patrz listing 11.1). Oba
parametry — rok i miesiąc — podane są w postaci liczb całkowitych i mogą przyjmować war-
tości o d -maxlnt d o maxlnt.
Listing 11.1. Interfejs metody obliczającej liczbę dni w danym miesiącu danego roku. Rok i miesiąc
podawane są w postaci parametrów będących liczbami całkowitymi.
c l a s s MyGregorianCalendar {
Testowanie graniczne
Testowanie ścieżek
jomości kodu źródłowego i użytych w nim struktur danych. Punktem wyjścia do testowania
ścieżek jest graf przepływów. Węzły tego grafu reprezentują bloki wykonywalne kodu, zaś
krawędzie — przepływ sterowania między tymi blokami. Graf taki skonstruować można na
podstawie kodu źródłowego, odwzorowując instrukcje „decyzyjne" (czyli związane z wybo-
rem kierunku przepływu sterowania — między innymi i f, whi 1 e) na węzły. Bloki w ramach
instrukcji decyzyjnych (blok then, blok el se) odwzorowywane są w oddzielne węzły. Między
poszczególnymi węzłami występuje relacja poprzedzania. Na listingu 11.2 widoczna jest błędna
implementacja metody getNumDaysInMonth(), zaś na rysunku 11.8 przedstawiamy wspo-
mniany graf odpowiadający tej implementacji, w formie diagramu aktywności UML: bloki
kodu odpowiadają tu akcjom UML, decyzje — rozgałęzieniom, zaś przepływ sterowania
reprezentowany jest w formie przejść.
Rysunek 11.8. Graf przepływów dla implementacji metody getNumDays I nMonth () z listingu 11.2 (funkcja
1 eap () zwraca wartość true, gdy jej argument identyfikuje rok przestępny i f a l se w przeciwnym razie)
Tabela 11.6. Przypadki testowe i odpowiadające im ścieżki przepływu sterowania dla grafu z rysunku 11.8
Rysunek 11.9. Graf przepływów odpowiadający (błędnej) implementacji metody i sLeapYear () z listingu
11.2 i związane z tą metodą przypadki testowe. Kursywę wyróżniliśmy przypadki użyte już do testowania
metody getNumDaysInMonth ()
W ten oto sposób, konstruując przypadki testowe dla wszystkich ścieżek w implementacji
każdej z metod, możemy uporać się ze złożonością wynikającą z dużej liczby metod.
Opierając się na teorii grafów, można udowodnić, że minimalna liczba testów niezbęd-
nych do pokrycia każdego z rozgałęzień równa jest liczbie niezależnych ścieżek w grafie
[McCabe, 1976]. Liczba ta, zwana cyklomatyczną złożonością grafu (w skrócie CC, od Cyclomatic
Complexity), wyraża się wzorem 7 :
7
W ogólnym przypadku CC = liczba krawędzi - liczba węzłów + 2 * liczba składowych spójnych
grafu. Poszczególne składowe spójne reprezentują niezależne metody lub procedury. Graf spójny
jest swą jedyną składową, otrzymujemy więc dla niego prezentowany wzór — przyp. tłum.
516 Rozdział 11. • Testowanie
przepływów (patrz tabela 11.6 i rysunek 11.9), zauważymy pewną różnicę. W obu przypadkach
luty był obiektem szczególnego zainteresowania, ponieważ jednak implementacja metody
i sLeapYear () nie traktuje osobno lat podzielnych przez 100, testowanie ścieżek nie do-
prowadziło do żadnego przypadku testowego uwzględniającego tę klasę równoważności.
Naturalnym ograniczeniem testów białoskrzynkowych jest możliwość wykrywania jedy-
nie usterek ukrywających się na istniejących ścieżkach sterowania, takich jak błędna instrukcja
numDays=32. Test białoskrzynkowy nie wykryje błędów logicznych rodem z dziedziny aplika-
cyjnej, na przykład nieuwzględnienia faktu, że rok 1900 nie był rokiem przestępnym. Testowa-
nie ścieżek związane jest organicznie ze strukturą sterowania programu, jest więc bezsilne
wobec usterek związanych z naruszeniem niezmienników dotyczących struktur danych, na
przykład wobec przekroczenia granic tablicy. Generalnie jednak żadna metoda testowania
nie zagwarantuje wykrycia wszystkich usterek. W naszym przykładzie żadna z prezentowa-
nych metod nie wykryła usterki związanej z błędnym traktowaniem sierpnia przez metodę
getNumDaysInMonth().
Rysunek 11.10. Diagram stanów dla przypadku użycia SetTime zegarka 2BWatch
Tabela 11.7. Kolejno wykonywane przypadki testowe dla zegarka 2BWatch; wymieniono tylko 8 po-
czątkowych bodźców
Przewidywany
Bodziec T e s t o w a n e przejście
stan wynikowy
Testowanie polimorfizmu
P o l i m o r f i z m w p r o w a d z a n o w ą komplikację d o testowania p r o g r a m ó w : d a n y k o m u n i k a t
m o ż e b y ć w i ą z a n y z r ó ż n y m i m e t o d a m i , zależnie o d jego d o c e l o w e j klasy. M i m o iż stwarza t o
o g r o m n e możliwości p o d w z g l ę d e m w i e l o k r o t n e g o w y k o r z y s t y w a n i a k o d u , w y m a g a k o n s t r u -
owania wielu p r z y p a d k ó w testowych, przetestowane b o w i e m m u s z ą być wszystkie możliwe
wiązania [Binder, 2000].
518 Rozdział 11. • Testowanie
Listing 11.3. Przykład transformacji wywołania polimorficznego (lewa część) na jawny wybór
konkretnej metody (prawa część), na potrzeby tworzenia przypadków testowych
Rysunek 11.12. Graf przepływów odpowiadający rozwiniętej wersji kodu z listingu 11.3
kować zasoby niezbędne do przeprowadzania testów. W kolejnych sekcjach opiszemy dwie stra-
tegie (a właściwie grupy strategii) definiujące wspomnianą kolejność: integrowanie poziome,
w ramach którego integrowanie komponentów prowadzi do stopniowego budowania kolej-
nych warstw systemu, i integrowanie pionowe, w ramach którego konstruowane są stopniowo
poszczególne mechanizmy funkcjonalne systemu.
Rysunek 11.13. Przykład hierarchicznej, trój warstwowej dekompozycji systemu; warstwy reprezen-
towane są przez pakiety
Rysunek 11.14. Testowanie wstępujące — kolejno testowane są: komponenty E, F i G, trójka B-E-Fi para D-G
Rysunek 11.15. Testowanie zstępujące — najpierw testowany jest k o m p o n e n t A, potem pary A-B, A-C
i A-D, potem czwórka A-B-C-D
Podstawową zaletą tej metody jest możliwość zrównoleglenia wielu testów (co widać
w przykładzie na rysunku 11.16), a także wcześniejsze niż w przypadku integrowania wstępują-
cego testowanie komponentów tworzących interfejs użytkownika. Testowanie kanapkowe ma
jednak tę wadę, że deprecjonuje warstwę środkową pod względem przetestowania jej poszcze-
gólnych komponentów. W przykładzie przedstawionym na rysunku 11.16 brakuje testu jed-
nostkowego komponentów B, C i D.
Zmodyfikowane testowanie kanapkowe (patrz rysunek 11.17) polega na indywidu-
alnym testowaniu każdej z warstw, przed poddaniem ich przyrostowemu testowaniu inte-
gracyjnemu. Zastosowanie tej strategii rozpoczyna się od fazy wstępnej, obejmującej ko-
lejno trzy następujące etapy:
524 Rozdział 11. • Testowanie
Rysunek 11.16. Strategia testowania kanapkowego. Żaden z komponentów warstwy środkowej (B, C i D)
nie jest testowany oddzielnie
Rysunek 11.17. Zmodyfikowana metoda kanapkowa. Komponenty warstwy środkowej zostają pod-
dane testom jednostkowym przed zintegrowaniem ich z k o m p o n e n t a m i warstw sąsiednich
Testowanie funkcjonalności
tych, które są istotne dla użytkownika, i tych dających duże prawdopodobieństwo wykrycia
usterek. Zauważmy, że testowanie funkcjonalności jest czymś różnym od innych testów rów-
nież mających swe źródło w modelu przypadków użycia — testów spełnienia wymagań poza-
fiinkcyjnych związanych z użytecznością, opisanych w rozdziale 4.: te ostatnie konfrontują
system z oczekiwaniami jego użytkowników, podczas gdy testowanie systemu weryfikuje jego
zgodność z wymaganiami zapisanymi w dokumencie RAD.
W celu zbudowania przypadków testowych dla testowania funkcjonalności przeprowa-
dzamy inspekcję modelu przypadków użycia i identyfikujemy te instancje przypadków użycia,
które wydają się najbardziej prawdopodobnymi źródłami usterek; identyfikacja taka opiera się
na postępowaniu podobnym do tworzenia testowych klas równoważności i testów granicznych
(które opisywaliśmy w sekcji 11.4.3). Wspomniane przypadki testowe powinny uwzględniać
zarówno „normalne", jak i wyjątkowe sytuacje. Rozpatrzmy przykładowo wielokrotnie już
cytowany system T i c k e t D i s t r i b u t o r realizujący automatyczną sprzedaż biletów w metrze
(patrz rysunek 11.18). Jego normalne funkcjonowanie ujęte jest w ramach przypadku użycia
PurchaseTicket, opisującego kroki wykonywane przez podróżnego (czyli aktora Passenger)
w celu otrzymania żądanego biletu. Przypadki użycia TimeOut, Cancel, OutOfOrder i NoChange
opisują natomiast sytuacje wyjątkowe związane z (kolejno) zbyt długą bezczynnością podróż-
nego, anulowaniem przez niego transakcji, awarią automatu i brakiem bilonu odpowiedniego
do wydania reszty.
Rysunek 11.18. Przykład modelu przypadków użycia związanego z automatem sprzedającym bilety
W tabeli 11.8 znajduje się przypadek użycia PurchaseTicket opisujący normalny prze-
bieg interakcji między podróżnym a automatem biletowym, czyli między aktorami Passenger
i Ti cketDi s t r i butor. Uważne przestudiowanie tego opisu pozwala wykryć co najmniej
trzy cechy automatu, których realizacja może nie potwierdzić się w testowaniu:
Tabela 11.8. Przykładowy przypadek użycia zaczerpnięty z modelu przypadków użycia dla automatu
sprzedającego bilety
Przepływ zdarzeń 1. Podróżny naciska jeden lub więcej przycisków reprezentujących strefy.
Dla automatu wiążący jest jedynie przycisk naciśnięty najpóźniej.
2. Automat wyświetla kwotę do zapłaty.
3. Podróżny wrzuca nominały.
4. Jeśli podróżny naciśnie przycisk identyfikujący strefę przed
wrzuceniem nominałów składających się na żądaną kwotę, automat
zwraca nominały wrzucone dotychczas przez podróżnego.
5. Jeżeli podróżny wrzuci nominały składające się na kwotę większą
niż wymagana, automat wydaje resztę.
6. Automat drukuje bilet.
7. Podróżny odbiera bilet i ewentualną resztę.
Testowanie wydajności
Warunek końcowy Podróżny dysponuje trzema biletami na dwie strefy, jednym biletem
na jedną strefę i jednym biletem na cztery strefy.
Testowanie pilotażowe
Testy pilotażowe, zwane także testami polowymi (field tests), wykonywane są przez
niewielką grupę użytkowników, wykorzystujących system w taki sam sposób, w jak ma on być
eksploatowany w codziennej pracy. Użytkownicy ci nie otrzymują żadnych wytycznych czy
scenariuszy testowania. Takie testy mają kluczowe znaczenie w sytuacji, gdy system tworzony
jest bez wyraźnie określonych wymagań lub dla anonimowych użytkowników. Grupa zaufa-
nych użytkowników testuje wówczas system przez pewien okres czasu, dzieląc się swymi spo-
strzeżeniami z jego autorami.
Testowanie pilotażowe odbywające się w środowisku programistycznym, w którym sys-
tem jest tworzony, nazywane jest powszechnie alfa-testowaniem. Testowanie pilotażowe pro-
wadzone przez użytkowników w ich środowisku eksploatacyjnym nosi nazwę beta-testowania.
Testy pilotażowe tym różnią się od testów użyteczności, iż zachowanie użytkowników testują-
cych system nie jest w żaden sposób rejestrowane ani obserwowane, w rezultacie więc beta-testy
nie są w stanie skutecznie wykrywać problemów z użytecznością systemu. W przypadku inte-
raktywnych systemów, dla których łatwość użytkowania jest jednym z kluczowych wymagań,
beta-testy nie mogą zatem zastąpić testów użyteczności.
Znaczenie beta-testów zwiększyło się znacznie dzięki internetowi, rozwiązującemu
problem dystrybucji testowanego oprogramowania. Istotnie, wiele firm wpisało beta-testy na
stałe w politykę testowania nowych rozwiązań. Ponieważ beta-testerzy sami pobierają testowane
oprogramowanie, beta-testy nie wymagają większej fatygi ze strony producentów tego opro-
gramowania. W związku z tym, do przeszłości należy także problem ograniczonej podaży
beta-testerów: coraz więcej firm oferuje testowanie swych produktów każdemu chętnemu,
który też coraz częściej może trochę zarobić na beta-testowaniu.
Testy akceptacyjne
Ewaluacja systemu przez klienta, w ramach testów akceptacyjnych, może odbywać się
na trzy sposoby. Przystępując do testu wzorcowego (benchmark test), klient przygotowuje ze-
staw przypadków testowych reprezentuj ących typowe warunki funkcjonowania systemu; samo
wykonanie testu może być powierzone użytkownikom systemu lub wyspecjalizowanemu ze-
społowi; ważne jest jednak, by osoby testujące zapoznane zostały z wymaganiami funkcyjnymi
i pozafunkcyjnymi stanowiącymi podstawę testowania.
W przypadku inżynierii wtórnej, czyli opracowywania nowego systemu jako następcy
systemu aktualnie eksploatowanego, przeprowadza się zwykle dwa rodzaje testów porównują-
cych oba systemy. W ramach „testowania rywala" (competitor testing) nowy system testowany
jest w kontekście analogicznych funkcji występujących w istniejącym systemie (i ewentualnie
w podobnych systemach, o ile takie są dostępne do testu). Z kolei „testowanie w cieniu"
11.5. Zarządzanie testowaniem 531
(shadow testing) to równoległe wykonywanie tych samych zadań przez oba systemy i porów-
nywanie otrzymywanych wyników.
W wyniku przeprowadzonych testów akceptacyjnych klient informuje menedżera pro-
jektu (w formie stosownego raportu), które z wymagań stawianych systemowi nie zostały speł-
nione. Testy akceptacyjne stwarzają także okazję do dialogu między klientem a programistami
w sprawie wymagań, które muszą zostać dodane, zmodyfikowane lub anulowane w związku
z zaistniałymi zmianami. Gdy konieczna jest zmiana wymagań, żądania klienta w tym wzglę-
dzie muszą być ujęte w formie protokołu wieńczącego wykonany test akceptacyjny, protokół
ten stanowi bowiem podstawę do następnej iteracji w cyklu rozwojowym systemu.
Testy instalacyjne
8
Patrz sekcja 3.3.4 — przyp. tłum.
9
Dla prostoty pominęliśmy inne dokumenty wymienione w standardzie IEEE 829, na którym bazuje
treść niniejszej sekcji, między innymi raport dotyczący przechodzenia komponentów między poszcze-
gólnymi etapami testowania (Test Item Transmittal Report). Uprościliśmy też nieco strukturę nie-
których omawianych dokumentów. Czytelników zainteresowanych szczegółami wspomnianego
standardu odsyłamy do lektury oryginału [IEEE Std. 829-2008].
11.5. Zarządzanie testowaniem 533
Plan t e s t ó w
1. Wstęp
2. Powiązanie z innymi dokumentami
3.Ogólna charakterystyka systemu
4. Cechy podlegające i niepodlegające testowaniu
5. Kryteria zaliczenia/niezaliczenia testów
6. Zastosowane podejścia
7. Zawieszanie i wznawianie testów
8. Materiały (sprzęt i oprogramowanie) niezbędne do przeprowadzania testów
9. Przypadki testowe
10. H a r m o n o g r a m testowania
Pierwsza sekcja planu testów opisuje cele testowania i ich rozmiar, w celu wyznaczenia
ram czasowych i kosztowych dla menedżera i programistów planujących testy.
W sekcji drugiej znajdują się odniesienia do innych dokumentów produkowanych
w związku z tworzeniem systemu, takich jak dokument analizy wymagań (RAD), dokument
projektu systemu (SDD) i dokument projektu obiektów (ODD). Odniesienia te specyfikują
powiązanie poszczególnych testów z wymaganiami funkcyjnymi i pozafunkcyjnymi oraz do
szczegółów projektu systemu. W razie potrzeby w sekcji tej zdefiniowane zostają także sche-
maty nazewnictwa odzwierciedlające związki między testami a testowanymi wymaganiami.
Treść sekcji trzeciej odzwierciedla strukturalne aspekty testowania, czyli przegląd syste-
mu w kategoriach komponentów podlegających testowaniu jednostkowemu. Definiowana jest
także ziarnistość komponentów i zależności między nimi.
Sekcja czwarta, koncentrująca się na funkcjonalnych aspektach testowania, wyszczegól-
nia testowane cechy i ich kombinacje. W sekcji tej wymienione są także cechy niepodlegające
testowaniu, wraz ze wskazaniem powodów, dla których rezygnuje się z ich testowania.
W sekcji piątej definiowane są ogólne kryteria kwalifikowania testu jako „zaliczony" albo
„niezaliczony". Zauważmy, że z tej perspektywy „niezaliczenie" testu oznacza test pomyślny
w świetle wcześniej przyjętej przez nas definicji.
Sekcja szósta poświęcona jest ogólnemu opisowi podejścia do procesu testowania. Dys-
kutowane są tu powody wyboru określonych strategii integracyjnych (do testowania integra-
cyjnego różnych części systemów mogą być stosowane odmienne strategie). Zależności między
poszczególnymi testami jednostkowymi oraz związek testów jednostkowych z testami inte-
gracyjnymi odzwierciedlone są na diagramie klas UML
W sekcji siódmej określone są kryteria powodujące zawieszenie testowania poszczegól-
nych komponentów, a także aktywności, które należy powtórzyć przy wznowieniu testowania.
Sekcja ósma wymienia i opisuje zasoby wymagane do testowania: sprzęt, oprogramowa-
nie, specjalne narzędzia i zasoby innych kategorii (na przykład pomieszczenia biurowe).
Sekcja dziewiąta, stanowiąca sedno planu testowania, wymienia wszystkie przypadki te-
stowe wykorzystywane w procesie testowania. Każdy z tych przypadków opisany jest szczegó-
łowo w osobnej Specyfikacji przypadków użycia, a wykonywanie każdego z nich dokumento-
wane jest w Raporcie zdarzeń testowych. Oba te dokumenty opiszemy w dalszej części tej sekcji.
11.5. Zarządzanie testowaniem 535
I d e n t y f i k a t o r p r z y p a d k u t e s t o w e g o jest u n i k a l n ą n a z w ą , o d r ó ż n i a j ą c ą g o o d i n n y c h
p r z y p a d k ó w testowych. K o n w e n c j e zalecające t w o r z e n i e n a z w p r z y p a d k ó w t e s t o w y c h sto-
s o w n i e d o t e s t o w a n y c h k o m p o n e n t ó w l u b ich cech u ł a t w i a j ą p r o g r a m i s t o m o d w o ł y w a n i e się
d o p o s z c z e g ó l n y c h testów. K o m p o n e n t y i (lub) ich c e c h y p o d l e g a j ą c e t e s t o w a n i u p r z y u ż y c i u
d a n e g o p r z y p a d k u testowego w y m i e n i o n e są sekcji d r u g i e j specyfikacji. Sekcja trzecia zawiera
d a n e wejściowe, zaś sekcja czwarta — oczekiwane w y n i k i p r o d u k o w a n e p r z e z system n a p o d -
stawie tych d a n y c h . O c z e k i w a n e w y n i k i m o g ą być obliczane ręcznie albo p r o d u k o w a n e p r z e z
analogiczny system, n a p r z y k ł a d system d o t y c h c z a s e k s p l o a t o w a n y . W sekcji piątej o p i s a n e są
cechy platformy sprzętowej i p r o g r a m o w e j niezbędnej do zastosowania danego przypadku
użycia, a także wszystkie sterowniki i n a m i a s t k i testowe związane z t y m p r z y p a d k i e m . O g r a n i -
czenia w s t o s o w a n i u p r z y p a d k u testowego, n a p r z y k ł a d związane z u w a r u n k o w a n i a m i czaso-
w y m i , obciążeniem serwera czy i n t e r w e n c j ą o p e r a t o r a , o p i s a n e są w sekcji szóstej, sekcja siód-
m a zawiera n a t o m i a s t opis e w e n t u a l n y c h zależności d a n e g o p r z y p a d k u testowego o d i n n y c h .
Raport zdarzeń testowych (TIR, od Test Incident Report) zawiera listę rezultatów otrzy-
m a n y c h w w y n i k u z a s t o s o w a n i a d a n e g o p r z y p a d k u użycia i w y k a z e w e n t u a l n y c h awarii, jakie
wystąpiły w związku z t e s t o w a n i e m . O p i s w y n i k ó w m u s i zawierać wyszczególnienie testowa-
n y c h cech i wyjaśnienie, dlaczego t e s t o w a n i e d a n e j c e c h y rozstrzygnięte zostało p o z y t y w n i e .
O p i s o w i każdej awarii towarzyszyć m u s i i n f o r m a c j a wystarczająca d o r e p r o d u k o w a n i a tej awarii
n a żądanie 1 0 . Awarie zaistniałe w w y n i k u stosowania wszystkich p r z y p a d k ó w testowych zebra-
n e są w Raporcie sumarycznym, k t ó r y dla p r o g r a m i s t ó w s t a n o w i p o d s t a w ę d o p o s z u k i w a n i a
i naprawiania odnośnych usterek, zgodnie z ustalonymi priorytetami.
D l a p o r z ą d k u m u s i m y w t y m m i e j s c u w s p o m n i e ć , że s t a n d a r d [IEEE Std. 8 2 9 - 2 0 0 8 ]
d o k u m e n t o w a n i a o p r o g r a m o w a n i a zaleca t r o c h ę i n n ą s t r u k t u r ę poszczególnych d o k u m e n t ó w ,
szczególnie p r z y d a t n ą dla o g r o m n y c h organizacji i wysoce s k o m p l i k o w a n y c h s y s t e m ó w
10
Znaczenie powtarzalności niepożądanych zachowań systemu dla efektywności testowania wyjaśnione
jest obszernie w książce P. Butchera Debugowanie. Jak wyszukiwać i naprawiać błędy w kodzie oraz im
zapobiegać, wyd. Helion 2010, http://helion.pI/ksiazki/debugo.htm — przyp. tłum.
536 Rozdział 11. • Testowanie
• M e n e d ż e r o w i e p r o j e k t ó w o b a w i a j ą się, że u ż y t k o w n i c y t e s t u j ą c y s y s t e m o m i j a ć b ę d ą
u s t a n o w i o n ą o r g a n i z a c j ę k o m u n i k a c y j n ą , k o n t a k t u j ą c się b e z p o ś r e d n i o z p r o g r a m i -
stami, co m o ż e wpływać destrukcyjnie n a wykonywanie codziennych zadań powie-
rzonych tym programistom;
N a l e ż y p a m i ę t a ć , że w p r z y p a d k u t e s t o w a n i a u ż y t e c z n o ś c i s y s t e m u liczy się p r z e d e
w s z y s t k i m z d a n i e u ż y t k o w n i k ó w d o k o n u j ą c y c h t e g o t e s t o w a n i a . Jeśli w i ę c t e s t o w a n i e t o s t a n i e
się ś w i a d e c t w e m w y r a ź n y c h p r o b l e m ó w , k o n i e c z n e jest w y s ł u c h a n i e o p i n i i t e s t e r ó w , d l a c z e g o
(ich z d a n i e m ) p r o b l e m y te w ogóle wystąpiły. R e k o m e n d a c j e d o t y c z ą c e u s p r a w n i e n i a t e s t o w a -
nych k o m p o n e n t ó w p o w i n n y zostać przekazane p r o g r a m i s t o m jak najszybciej p o zakończe-
niu testów.
T e s t o w a n i e r e g r e s y j n e z a w s z e w i ą ż e się z w i e l o k r o t n y m w y k o n y w a n i e m d u ż e j l i c z b y
t e s t ó w . Jest w i ę c o p ł a c a l n e t y l k o w ó w c z a s , jeśli d a j e się w d u ż y m s t o p n i u a u t o m a t y z o w a ć p o d
względem konfigurowania, uruchamiania i weryfikowania wyników.
• Stereotyp «sut» reprezentujący testowany system (system under test), którym może
b y ć k o m p l e t n y s y s t e m l u b tylko jego część — p o d s y s t e m albo p o j e d y n c z a klasa.
• S t e r e o t y p « t e s t O b j e c t i ve» r e p r e z e n t u j ą c y cel t e s t o w a n i a w p o s t a c i n i e f o r m a l -
n e g o o p i s u ( w j ę z y k u p o t o c z n y m ) z w i ą z a n e g o z j e d n y m l u b k i l k o m a p r z y p a d k a m i te-
s t o w y m i . C e l e m t y m jest zazwyczaj w y m a g a n i e (lub j e g o w y b r a n y aspekt) p o d l e g a j ą c e
weryfikacji. P r z y k ł a d o w o p r z y p a d e k t e s t o w y di s p l a y T i c k e t P r i c e s m a za z a d a n i e
z w e r y f i k o w a n i e p o p r a w n o ś c i w y ś w i e t l a n i a c e n b i l e t ó w p r z e z s p r z e d a j ą c y je a u t o m a t
p r z y z a ł o ż e n i u , że p o d r ó ż n y m o ż e d o w o l n i e o p e r o w a ć p r z y c i s k a m i o z n a c z a j ą c y m i
strefy.
• I n t e r f e j s S c h e d u l e r , r e p r e z e n t u j ą c y z a r z ą d c ę t e s t o w a n i a , czyli m e c h a n i z m od-
p o w i e d z i a l n y za t w o r z e n i e i w y k o n y w a n i e k o l e j n y c h p r z y p a d k ó w t e s t o w y c h .
N a r y s u n k u 11.21 w i d o c z n y jest d i a g r a m U 2 T P o d z w i e r c i e d l a j ą c y ś r o d o w i s k o t e s t o w e
s y s t e m u T i c k e t D i s t r i b u t o r p r z e d s t a w i a n e g o n a r y s u n k u l ł . 1 8 o r a z w t a b e l a c h 11.8 i 11.9.
K o n t e k s t t e s t o w y P u r c h a s e T i c k e t S u i t e g r u p u j e wszystkie p r z y p a d k i t e s t o w e z w i ą z a n e z p r z y -
p a d k i e m użycia P u r c h a s e T i c k e t . T e s t o w a n y m s y s t e m e m jest o p r o g r a m o w a n i e a u t o m a t u d o
s p r z e d a ż y b i l e t ó w Ti c k e t D i s t r i b u t o r . A b y u ł a t w i ć s o b i e s t e r o w a n i e t y m s y s t e m e m i j e g o
i n s t r u m e n t a c j ę , s y m u l u j e m y wyświetlacz w s p o m n i a n e g o a u t o m a t u za p o m o c ą k o m p o n e n t u
DisplaySimulator.
10.7. Literatura uzupełniająca 541
Rysunek 11.22. Przykładowy przebieg testu dla przypadku testowego di spl ayTi cketPri ces (). Widoczne
są jedynie interakcje prowadzące do werdyktu pass
świadczących o tym, iż nawet ograniczone testy użyteczności mogą w drastyczny sposób przy-
czynić się do usprawnienia systemu. W książce autorstwa D. J. Mayhewa [Mayhew, 1999] opi-
sana jest integracja testowania użyteczności z ogólnym cyklem życia oprogramowania zo-
rientowanego obiektowo.
Tworzenie niezawodnych systemów wykracza daleko poza tylko testowanie. Jak pisaliśmy
we wstępie do tego rozdziału, może być ono uzupełnione o takie techniki jak unikanie błędów
i tolerowanie usterek. Znakomitego omówienia tego tematu dostarcza książka autorstwa
D. P. Siewiorka i R. S. Swarza [Siewiorek i Swarz, 1992].
U2TP to odpowiedź konsorcjum na propozycje OMG dotyczące opracowania profilu
UML dedykowanego testowaniu. Finalna wersja U2TP jest obecnie oficjalnym standardem
OMG [OMG, 2005]. Praktyczne wprowadzenie do testowania opartego na modelach, z wyko-
rzystywaniem U2TP, znajdą czytelnicy w książce P. Bakera, Z. R. Daiego i R. Grabowskiego
[Baker i in., 2008].
11.7. Ćwiczenia
11.1. Skoryguj usterki w metodach i sLeapYear() i getNumDaysInMonth() na listingu
11.2 i skonstruuj dla nich przypadki użycia z wykorzystaniem metody testowania
ścieżek. Czy Twoje przypadki użycia różnią się od przedstawionych w tabeli 11.6
i na rysunku 11.9? Dlaczego? Czy zaprojektowane przez Ciebie przypadki użycia
mogłyby wykryć usterki, które właśnie poprawiłeś?
11.2. Napisz w języku Java kod odpowiadający diagramowi stanów dla przypadku użycia
SetTime zegarka 2BWatch z rysunku 11.10. Skonstruuj przypadki testowe dla testo-
wania tego kodu metodami klas równoważności, testowania granicznego i testowania
ścieżek. Jak mają się te przypadki testowe do wykorzystywanych w testowaniu stero-
wanym stanami?
11.3. Skonstruuj diagram stanów odpowiadający przypadkowi użycia PurchaseTi cket
z tabeli 11.8 oraz przypadki testowe dla testowania sterowanego stanami. Prze-
dyskutuj problem liczby przypadków testowych i porównaj je z przypadkiem
PurchaseTi cket_CommonCase z tabeli 11.9.
11.4. Dla poniższej dekompozycji systemu
544 Rozdział 11. • Testowanie
Jakie decyzje menedżera odzwierciedla ten plan? Jakie są jego mocne i słabe strony?
11.5. Wyobraź sobie, że jesteś odpowiedzialny za testowanie integracyjne systemu szyfro-
wania danych przesyłanych przez sieć. Jednym z elementów tego systemów jest
podsystem generowania losowych kluczy. W czasie testowania integracyjnego pod-
system ten symulowany jest przez namiastkę dającą przewidywalne wyniki, jednakże
w docelowej wersji wspomniany podsystem faktycznie generować będzie klucze lo-
sowe, nieprzewidywalne dla obserwatora (intruza). Zaimplementuj infrastrukturę
testową dla tego systemu, wykorzystując jeden z wzorców projektowych opisywa-
nych w rozdziale 8. „Projektowanie obiektów: wielokrotne wykorzystywanie rozwią-
zań wzorcowych" w celu zapewnienia łatwej wymiany obu implementacji generatora.
Uzasadnij swój wybór.
11.6. Wykorzystaj testowanie ścieżek do skonstruowania przypadków testowych dla
wszystkich metod klasy NetworkConnection przedstawionej na rysunku 11.11 i li-
stingu 8.4. Rozpocznij od rozwinięcia kodu źródłowego w sposób eliminujący poli-
morfizm. Ile przypadków testowych musisz skonstruować do pokrycia wszystkich
ścieżek? Ile musiałbyś skonstruować dla kodu w oryginalnej (polimorficznej) postaci?
11.7. Znajdź analogię między terminologią z zakresu inżynierii oprogramowania z nastę-
pującymi określeniami użytymi w cytowanym na wstępie artykule R. Feynmana:
• pęknięcie łopatki,
• inicjacja pęknięcia,
• wysoka niezawodność silnika,
• zamierzenie projektantów,
• 10% początkowych zamiarów.
Co rozumie Feynman pod pojęciem „weryfikacji", używając sformułowania „wykryte
usterki są korygowane i zmodyfikowany komponent poddawany jest weryfikacji
w ramach następnych testów"?
Bibliografia
[Beck i Andres, 2005] K. Beck, C. Andres Extreme Programming Explained: Embrace Change,
wyd. drugie, Addison-Wesley, Reading, MA, 2005.
[Baker i in., 2008] P. Baker, Z. R. Dai, R. Grabowski Model-Driven Testing: Using the UML
Testing Profile, Springer, Berlin, 2008.
[Binder, 2000] R. V. Binder Testing Object-Oriented Systems: Models, Patterns, and Tools,
Addison-Wesley, Reading, MA, 2000.
Bibliografia 545
[Fagan, 1976] M. E. Fagan „Design and code inspections to reduce errors in program
development", IBM Systems Journal, t. 15, nr 3,1976.
[Feynman, 1988] R. P. Feynman „Personal observations on the reliability of the Shuttle",
Rogers Commission The Presidential Commission on the Space Shuttle
Challenger Accident Report, Washington, DC, czerwiec 1986.
[Grudin, 1990] J. Grudin „Obstacles to user involvement in interface design in large product
d e v e l o p m e n t organizations", Proceedings of IFIP INTERACT'90 Third
International Conference on Human-Computer Interaction, Cambridge,
U.K., sierpień 1990.
[Hopper, 1981] G. M. Hopper „The First Bug" Annals of the History of Computing 3,
str. 2 8 5 - 2 8 6 , 1 9 8 1 .
[IEEEStd. 829-2008] IEEE Standard for Software Test Documentation, IEEE Standards Board,
lipiec 2008.
[IEEEStd. 982.2-1988] IEEE Guide for the Use of IEEE Standard Dictionary of Measures to Produce
Reliable Software, IEEE Standards Board, czerwiec 1988.
[Jones, 1977] T. C. Jones „ P r o g r a m m e r quality a n d p r o g r a m m e r productivity",
IBM TR-02.764, 1977.
[JUnit, 2009] JUnit, http://www.junit.org/.
[Kelly, 1984] J. F. Kelly „An iterative design methodology for user-friendly natural
language office information applications", ACM Transactions on Information
Systems, t.2, nr 1, styczeń 1984.
[Mayhew, 1999] D. J. Mayhew The Usability Engineering Lifecycle: A Practitioner's Handbook
for User Interface Design, Morgan Kaufmann, 1999.
[McCabe, 1976] T. McCabe „A software complexity measure", IEEE Transactions on Software
Engineering, t.2, nr 12, grudzień 1976.
[Myers, 1979] G. J. Myers The Art of Software Testing, Wiley, New York, 1979. Wydanie
polskie: G. J. Myers, C. Sandler, T. Badgett, T. M. Thomas Sztuka testowania
oprogramowania, wyd. Helion 2005, http://helion.pl/ksiazki/artteo.htm.
[Nielsen i Mack, 1994] J. Nielsen, R L. Mack (red.) Usability Inspection Methods, Wiley, New York, 1994.
[OMG, 2005] Object M a n a g e m e n t G r o u p UML Testing Profile Version 1.0.
http://www.omg.org/ 2005.
[Parnas i Weiss, 1985] D. L. Parnas, D. M. Weiss „Active design reviews: principles and practice",
Proceedings of the Eighth International Conference on Software Engineering,
London, U.K., str. 132 - 136, sierpień 1985.
[Popper, 1992] K. Popper Objective Knowledge: An Evolutionary Approach, Clarendon,
Oxford, 1992.
[Porter i in., 1997] A. A. Porter, H. Siy, C.A. Toman, L.G. Votta „An experiment to assess the
costbenefits of code inspections in large scale software development" IEEE
Transactions on Software Engineering, t. 23, nr 6, str. 329 - 346, czerwiec 1997.
[Royce, 1998] W. Royce Software Project Management: A Unified Framework, Addison-
Wesley, Reading, MA, 1998.
[Rubin, 1994] J. Rubin Handbook of Usability Testing, Wiley, New York, 1994.
[Siewiorek i Swarz, 1992] D. P. Siewiorek, R. S. Swarz Reliable Computer Systems: Design and Evaluation,
wyd. drugie, Digital, Burlington, MA, 1992.
[Turner i Robson, 1993] C. D. Turner, D. J. Robson „The state-based testing of object-oriented
programs" Conference on Software Maintenance, str. 302 - 310, wrzesień 1993.
12.1. Wstęp: przycinanie wędzonej szynki 550
Bibliografia 594
Zarządzanie racjonalizacją
Można opisywać motocykl w kategoriach „co?" i „jak", czyli w kategoriach
komponentów, z których się składa, oraz zasad, według których
komponenty te funkcjonują; oglądając ilustrację motocykla, można
się jednak tylko domyślać tych wszystkich „gdzie?" i „dlaczego?"
decydujących o takim, a nie innym kształcie poszczególnych części
i ich wzajemnym rozmieszczeniu.
— Robert Pirsig Zen i sztuka oporządzania motocykla
1
Ponieważ większość badań związanych z racjonalizacją koncentrowała się początkowo na etapie
projektowania systemu, do samego rzeczownika „racjonalizacja" przylgnął na dobre przymiotnik
„projektowa" (design rationale). Jak jednak pokazujemy w tym rozdziale, racjonalizacja jest nie-
rozłącznie związana ze wszystkimi etapami projektu, dlatego będziemy o niej pisać bez przymiot-
ników wiążących ją z konkretnymi etapami czy aktywnościami.
550 Rozdział 12. • Zarządzanie racjonalizacją
Mary zapytała kiedyś swego męża Johna, dlaczego przycina szynkę na obu końcach przed włoże-
niem jej do wędzarni. John odparł, że tak robiła jego mama, prawdopodobnie zgodnie z jakimś prze-
pisem, on sam nigdy się nad tym nie zastanawiał.
Zaciekawiona Mary zapytała więc o to swą teściową, Ann. Ta odrzekła, że jej mama, Zoe, wymyśliła
taki właśnie sposób na poprawienie smaku wędzonej szynki
Indagowana na tę okoliczność Zoe wyraziła głębokie zdziwienie: nigdy nie przycinała szynki przed
wędzeniem, a już sugestia, jakoby takie przycinanie miało poprawiać smak szynki, jest kompletnym
absurdem dla kogoś, kto ma choć blade pojęcie na temat kulinariów. Po chwili Zoe przypomniała
sobie jednak, że gdy Ann była małą dziewczynką, zdarzyło się wielokrotnie, iż standardowych roz-
miarów szynka nie mieściła się w zbyt ciasnym piecu i faktycznie trzeba ją było skracać o kilka cen-
tymetrów z obu końców. Wkrótce jednak kupiono nową, większą wędzarnię i technologia skracania
szynki poszła w zapomnienie.
2
Popularna historyjka niewiadomego autorstwa.
12.2. O racjonalizacji ogólnie 551
• Kryteria (criteria). Określają one cechy, którymi charakteryzować się powinno roz-
wiązanie problemu — i tak na przykład przepis na uwędzenie szynki powinien być
wykonalny przy użyciu podstawowego wyposażenia domowej kuchni, a programiści
decydujący się pół wieku temu na dwucyfrowy zapis roku dążyli do oszczędności
pamięci masowych. Na etapie analizy wymagań wspomniane kryteria mają postać
wymagań pozafunkcyjnych i ograniczeń dotyczących między innymi łatwości użyt-
kowania systemu czy oczekiwanej liczby błędów popełnianych codziennie przez
użytkownika wprowadzającego dane wejściowe. Na etapie projektowania systemu
kryteria te wyrażają cele projektowe w postaci niezawodności, czasu reakcji i tym
podobnych. Z perspektywy menedżera projektu kryteria te wyrażają jego specy-
ficzne cele oraz kompromisy, które musi rozstrzygać — na przykład kompromis
między jakością systemu a terminem jego dostarczenia.
• Argumentacja (arguments). Zarówno sztuka kulinarna, jak i inżynieria oprogra-
mowania nie są dyscyplinami algorytmicznymi, bowiem kucharze i programiści
napotykają rozmaite problemy i poszukują różnych sposobów ich rozwiązywania,
uwzględniając zalety i wady danego sposobu w porównaniu z innymi. Argumento-
wanie dotyczy wszelkich aspektów procesu decyzyjnego — kryteriów, uzasadnień,
rozważanych ewentualności oraz rozstrzyganych kompromisów.
• Decyzje (decisions). Decyzja to rozwiązanie problemu, reprezentujące konkretną
ewentualność wybraną zgodnie z określonymi kryteriami ewaluacji. Kilkucentyme-
trowe skracanie wędzonej szynki czy ignorowanie cyfr stulecia w zapisie lat to przy-
kłady konkretnych decyzji. Konkretny kształt modelu analitycznego czy modelu
projektu systemu jest niczym innym, jak skumulowanym efektem ciągu podjętych
decyzji. Być może wiele z tych decyzji podjętych zostało bez starannego przeanalizo-
wania rozwiązywanego problemu lub należytej eksploracji możliwych ewentualności.
Przez cały czas realizowania projektu, na wszystkich jego etapach, zmuszeni jesteśmy
do podejmowania licznych decyzji, wspomaganych modelami racjonalizacji, i tak:
zmiany w systemie rozpoczynają swój żywot od zarejestrowania ich w tej bazie, w for-
mie dyskusji towarzyszącej poszczególnym decyzjom. Wspomniana baza stanowi
zatem swoiste podsumowanie decyzji, których konsekwencje rozproszone są po
modelach systemu.
W latach 60. ubiegłego wieku pulpity sterownicze systemu CTC miały postać dedyko-
wanych urządzeń wyposażonych w żarówki wyświetlające stan poszczególnych odcinków
izolowanych oraz przyciski służące do przestawiania zwrotnic i ustawiania sygnalizacji. W la-
tach 70. dedykowane pulpity zastąpione zostały monitorami kineskopowymi, umożliwiają-
cymi wyświetlanie większej ilości szczegółów na mniejszej powierzchni. Ostatnio monitory
556 Rozdział 12. • Zarządzanie racjonalizacją
train del ay?: Issue Jak szybko dyspozytor powinien być informowany o opóźnieniu pociągu?
display?: Issue W jakiej postaci na ekranie stacji roboczej ma być wyświetlany stan
odcinków izolowanych?
widokami tego samego obiektu?. Propozycja może stać się także źródłem nowego zagadnienia:
propozycja Należy wykorzystywać automatyczne odśmiecanie jako odpowiedź na zagadnienie
Jak minimalizować wycieki pamięci? prowadzi natychmiast do zagadnienia Jak minimalizować
degradację reaktywności systemu spowodowaną automatycznym zarządzaniem pamięcią?.
Rozważając sensowność propozycji w kontekście danego zagadnienia, należy brać pod uwagę
także wszystkie jego zagadnienia wynikowe.
Na diagramach UML propozycje reprezentowane są jako instancje klasy Proposal.
W klasie tej (podobnie jak w klasie Issue) definiowane są atrybuty subject i descri pti on. Zgod-
nie z konwencją, nazwa propozycji powinna mieć formę krótkiej frazy czasownikowej. Propo-
zycje jako obiekty klasy Proposal powiązane są z odnośnymi zagadnieniami, jako obiektami
klasy Issue, za pomocą dwojakiego typu skojarzeń: skojarzenie addressed by wskazuje za-
gadnienie, dla którego dana propozycja jest odpowiedzią, zaś skojarzenie raises wskazuje
jedno lub kilka zagadnień generowanych przez daną propozycję.
Powróćmy do CTC. Rozważając zagadnienie związane z interfejsem dyspozytora, ma-
my do wyboru dwie propozycje: graficzny interfejs typu „wskaż i kliknij" (poi nt&cl ick)
oraz interfejs tekstowy (text-based), w ramach którego odcinki izolowane reprezentowane
są w postaci znaków semigraficznych. Propozycja interfejsu tekstowego generuje zagadnienie
wynikowe dotyczące wyboru konkretnej emulacji terminala. Wzajemne powiązanie tych za-
gadnień i propozycji widoczne jest na rysunku 12.4.
poi nt&cl i c k : Proposal Interfejs dyspozytora powinien być zrealizowany jako interfejs GUI
typu „wskaż i kliknij".
text only: Proposal Interfejs dyspozytora powinien mieć postać tekstową, a odcinki izolowane
powinny być wyświetlane za pomocą znaków semigraficznych.
Rysunek 12.5. Przykład oceny propozycji przez kryteria. Kryteria wyróżnione zostały pogrubioną
ramką. Spełnienie kryterium przez propozycję reprezentowane jest przez etykietę meets skojarzenia
assesment, niespełnienie — przez etykietę fai 1 s
Rysunek 12.6. Przykład argumentu (reprezentujący go obiekt został wyróżniony pogrubioną ramką)
rozwiązaniem, atrybut status ma wartość act i ve; w przeciwnym razie ma on wartość obsol ete.
Z zamkniętym zagadnieniem skojarzone jest dokładnie jedno rozstrzygnięcie o statusie act i ve
i dowolna liczba (lub zero) rozstrzygnięć o statusie obsol ete.
Ostatecznie więc zdecydowaliśmy się na wybór tekstowego interfejsu dla naszego sys-
temu CTC. Decyzja taka podyktowana została większym priorytetem kryterium dostępności
w stosunku do kryterium użyteczności; w konsekwencji dyspozytor nie będzie mógł oglądać
tak dużej ilości danych jednocześnie jak w przypadku interfejsu GUI, a wprowadzanie danych
za pomocą klawiatury będzie trwało dłużej i będzie mniej wygodne w porównaniu z klikaniem.
W zamian jednak zyskujemy większą pewność funkcjonowania całego systemu. Na diagramie
U M L (patrz rysunek 12.7) wybrane przez nas rozwiązanie reprezentowane jest jako obiekt
klasy Resol uti on skojarzony z dwoma obiektami klasy Issue.
Dodanie rozstrzygnięcia do modelu zagadnień oznacza formalne zakończenie dyskusji
nad danym zagadnieniem. Wobec iteratywnego charakteru procesu tworzenia systemu mogą
pojawić się potrzeby otwarcia któregoś z zamkniętych zagadnień i ponownego ocenienia od-
rzuconych ewentualności. Gdy jednak proces ten zostanie zakończony, większość zagadnień
musi być zamknięta, a otwarte powinny być jawnie opisane w dokumentacji w postaci listy
znanych problemów.
Rysunek 12.7. Przykład zamkniętego zagadnienia. Jego rozstrzygnięcie wyróżnione jest pogrubioną ramką
częścią modelu zadań (patrz rozdział 14. „Zarządzanie projektem"); mimo to, opisujemy je w tym
miejscu, ponieważ są ściśle powiązane z modelami zagadnień. Na diagramach UML elementy
działania reprezentowane są jako instancje klasy Actionltem definiującej atrybuty subject,
description, owner, deadl ine i status. A t r y b u t owner r e p r e z e n t u j e o s o b ę o d p o w i e d z i a l n ą za
wykonanie zadania związanego z elementem działania, atrybut status może przyjmować cztery
wartości reprezentujące stan wspomnianego zadania: todo („do wykonania"), notDoabl e
(„niewykonalne"), inProgress („trwające") i done („wykonane"). Rozstrzygnięcie powiązane
jest z odnośnym elementem działania poprzez skojarzenie i s imp! emented by. Na rysunku
12.8 widoczny jest element działania generowany przez rozstrzygnięcie z rysunku 12.7.
Zakończyliśmy opis notacji wykorzystywanej do reprezentowania racjonalizacji w po-
staci modelu zagadnień i jego integracji z modelem zadań, przyjrzyjmy się więc funkcjo-
nującym w praktyce wybranym systemom zarządzania racjonalizacją.
updateSDD: Act i on Item Dla Alice: uaktualnij SOD w związku z wyborem tekstowego interfejsu.
i nvest i gateTerm: Act i onltem Dla Dave: przeanalizuj możliwości poszczególnych emulacji terminala
tekstowego i ich przydatności do wyświetlania stanu odcinków
w systemie CTC.
Rysunek 12.8. Przykład implementacji rozstrzygnięcia. Element działania wyróżniony jest pogru-
bioną ramką
IBIS wspierany jest przez narzędzie hipertekstowe o nazwie gIBIS, opisane przez J. Con-
klina i K. C. Burgessa-Yakemovica [Conklin i Burgess-Yakemovic, 1991], i wykorzystywany
do kolekcjonowania racjonalizacji w trakcie spotkań osobistych. Stanowi jednocześnie bazę
dla większości późniejszych rozwiązań bazujących na modelach zagadnień, między innymi
DRL i QOC.
Innym efektem rozszerzenia systemu IBIS jest system o nazwie Questions, Options, and
Criteria (QOC) („pytania, opcje i kryteria"). Węzły klasy Questi on („pytania") składają się na
reprezentację rozwiązywanego problemu. Propozycje jego rozwiązań reprezentowane są przez
„opcje", czyli węzły klasy Option (odpowiadającej klasie Proposal opisywanej w sekcji 12.3.3).
12.3. Koncepcje racjonalizacji 565
Opcje mogą generować kolejne pytania; są też oceniane (dodatnio lub ujemnie) według kryte-
riów (Criteria) stanowiących relatywną miarę dobroci definiowaną przez programistów.
Argumenty (Argument) mogą wspierać lub kwestionować pytania, opcje i kryteria oraz skoja-
rzenia między nimi. Model systemu QOC przedstawiony jest schematycznie na rysunku 12.11.
QOC i IBIS różnią się jednak zasadniczo na poziomie procesów. Zadaniem systemu
IBIS jest kolekcjonowanie elementów racjonalizacji na bieżąco, gdy pojawiają się w toku dys-
kusji i rejestrowane są za pomocą wspomnianego narzędzia gIBIS. W systemie QOC struktura
modelu tworzona jest natomiast jako wynik refleksji nad bieżącym stanem projektu. Koncep-
cyjna separacja faz konstrukcji i argumentacji akcentuje systematyczność i strukturalny cha-
rakter racjonalizacji, w przeciwieństwie do budowania jej „na gorąco". Z perspektywy modelu
QOC racjonalizacja jest opisem eksplorowania przestrzeni projektowej przez programistów,
system IBIS postrzega natomiast racjonalizację jako chronologiczny zapis analizy prowadzącej
do określonego projektu. W praktyce każde z tych podejść okazuje się przydatne do kolekcjo-
nowania racjonalizacji w wystarczającym kształcie. (Aktywnościami związanymi z kolekcjo-
nowaniem racjonalizacji i zarządzaniem nią zajmiemy się w sekcji 12.4).
NFR
3
Skrót od Non-Functional-Requirements — „wymagania pozafunkcyjne" — przyp. tłum.
566 Rozdział 12. • Zarządzanie racjonalizacją
4
„Spełnienie" to właściwość kategoryczna: cel może być spełniony albo nie. „Usatysfakcjonowanie"
to wielkość mierzalna: dany cel jest tym bardziej „usatysfakcjonowany", im więcej podcelów jest z nim
zgodnych. Odpowiednio duży wskaźnik usatysfakcjonowania jest więc „rozmytym" odpowiednikiem
spełnienia — przyp. tłum.
12.4. Aktywności racjonalizacji — od zagadnień do decyzji 567
Rysunek 12.12. Dekompozycja celów projektowych w ramach frameworku NFR na przykładzie me-
chanizmu uwierzytelniania transakcji bankomatowych
• Dostępność. Awarie systemu nie mogą się zdarzać częściej niż jedna na miesiąc,
a powrót systemu do normalnej pracy po awarii nie powinien trwać dłużej niż 10
minut.
• Bezpieczeństwo. Żadna encja zlokalizowana poza nastawniami nie może uzyskiwać
dostępu do informacji o stanie zarządzanych odcinków izolowanych ani też nie może
mieć możliwości manipulowania jakimikolwiek urządzeniami.
• Użyteczność. Przeszkolony dyspozytor może pomyłkowo wydawać błędne polecenia
nie częściej niż dwa razy dziennie.
Każdy dyspozytor posiada własny węzeł kliencki, zaś całością systemu zarządza para du-
blujących się serwerów (patrz rysunek 12.13 i tabela 12.1). Serwery te odpowiedzialne są także
za przechowywanie trwałych danych; dane te przechowywane są w formie niezależnych plików,
które można kopiować offline i następnie importować do bazy danych w celu przetwarzania
ich zawartości. Komunikacja systemu z urządzeniami (stacjami przydrożnymi) odbywa się za
pośrednictwem modemów zarządzanych przez dedykowaną maszynę. Oprogramowanie midd-
leware realizuje dwa rodzaje komunikacji między podsystemami: wywoływanie metod reali-
zujących żądania oraz powiadamianie o zdarzeniach istotnych dla poszczególnych podsystemów.
Przed nami zadanie rozwiązania zagadnień związanych z kontrolą dostępu oraz mechanizma-
mi zabezpieczającymi dyspozytorów przed ingerowaniem w ich sekcje dyspozycyjne przez
innych dyspozytorów.
12.4. Aktywności racjonalizacji — od zagadnień do decyzji 569
Rysunek 12.13. Dekompozycja systemu CTC. Zarządzanie stanem systemu jest zadaniem serwera
mai nServer, który w razie awarii zastępowany jest przez serwer hotBackup. Serwer wysyła polecenie i odbiera
informację o stanie odcinków za pośrednictwem modemów, którymi zarządza węzeł ModemPool
1. Cel
Pierwszą rewizję projektów odwzorowania sprzętowo-programowego i systemu przechowywania
danych m a m y już za sobą, konieczne jest teraz zdefiniowanie m o d e l u kontroli dostępu i jego
integracji z istniejącymi podsystemami, między innymi Noti f i c a t i onServi ce i Tracki ngSubsystem.
2. Oczekiwane wyniki
Rozwiązanie zagadnień związanych z integracją kontroli dostępu i powiadamiania.
3. Rozpowszechniana informacja [czas: 15 minutl
Al [1]: Dave: Analiza modelu kontroli dostępu realizowanej przez middleware.
4. Dyskusja [czas: 35 minut]
I [1]: Czy dyspozytor ma prawo oglądać sekcje dyspozycyjne kontrolowane przez innych dyspozytorów?
I [2] :Czy dyspozytor ma prawo wysyłania poleceń do urządzeń znajdujących się w sekcjach
dyspozycyjnych k o n t r o l o w a n y c h przez innych dyspozytorów?
I [3]: W jaki sposób kontrola dostępu powinna być zintegrowana z podsystemami Tracki ngSubsystem
i NotificationService?
5. Podsumowanie [czas: 5 minut]
Przegląd i przyporządkowanie nowych elementów działania.
Uwagi krytyczne
12.4. Aktywności racjonalizacji — od zagadnień do decyzji 571
Rysunek 12.14. Propozycja P [ l ] : Dostęp do klasy TrackSection kontrolowany jest za pomocą listy
uprawnień utrzymywanej przez ten komponent. W oparciu o tę listę usługa Noti f i c a t i onServi ce
sprawdza, czy żądający informacji dyspozytor ma prawo do jej uzyskiwania
Rysunek 12.15. Propozycja P[2]: klient zostaje pozbawiony dostępu do usługi Noti f i c a t i onServi ce,
całość operacji związanych z kontrolą dostępu skupiona zostaje w klasie TrackSecti on, za pośrednictwem
której klient subskrybuje żądaną informację
5
Autorzy używają tu przymiotnika „chroniona" (protected) na określenie faktu, że wykonanie danej
operacji uzależnione jest od uprawnień podsystemu wywołującego tę operację, czyli poprzedzone
weryfikacją tych uprawnień (operacja „chroniona" jest przez mechanizm kontroli dostępu). Nie należy
więc tym razem kojarzyć słowa „chroniona" z innym jego znaczeniem — poziomem widzialności
p r o t e c t e d elementu klasy (patrz sekcja 9.3.2) — przyp. tłum.
12.4. Aktywności racjonalizacji — od zagadnień do decyzji 573
Tabela 12.3. Opis elementów modelu widocznego na rysunku 12.15; zmiany w stosunku do tabeli
12.2 wyróżnione zostały kursywę
Rysunek 12.16. Propozycja P[3]: jedynie próby modyfikowania stanu obiektu TrackSection podlegają
kontroli dostępu, więc usługa Noti f i c a t i onServi ce przestaje być zależna od tego mechanizmu
574 Rozdział 12. • Zarządzanie racjonalizacją
Tabela 12.4. Opis elementów modelu widocznego na rysunku 12.16; zmiany w stosunku do tabeli 12.2
wyróżnione zo
Z e s p ó ł a r c h i t e k t o n i c z n y z d e c y d o w a ł o w y b o r z e p r o p o z y c j i E d a , dzięki jej p r o s t o c i e .
Ed jako protokolant sporządza przedstawiony poniżej chronologiczny protokół.
1. Cel
Pierwszą rewizję projektów odwzorowania sprzętowo-programowego i systemu przechowywania
d a n y c h m a m y już za sobą, konieczne jest teraz zdefiniowanie m o d e l u k o n t r o l i dostępu
i jego integracji z istniejącymi p o d s y s t e m a m i , między i n n y m i Noti f i c a t i onServi ce
i TrackingSubsystem.
2. Oczekiwane wyniki
Rozwiązanie zagadnień związanych z integracją kontroli dostępu i powiadamiania.
3. Rozpowszechniana informacja
Al [1]: Dave: Analiza modelu kontroli dostępu realizowanej przez middleware.
Status: Middleware udostępnia silne mechanizmy szyfrowania i uwierzytelniania, poza
tym nie wprowadza żadnych ograniczeń do modelu dostępu; konieczne jest więc
zaimplementowanie reguł dostępu na serwerze.
4. Dyskusja
I [1]: Czy dyspozytor m a prawo oglądać sekcje dyspozycyjne kontrolowane przez innych
dyspozytorów?
Ed: Tak, wynika to ze specyfikacji CTC.
I [2]: Czy dyspozytor m a prawo wysyłania poleceń do urządzeń znajdujących się w sekcjach
dyspozycyjnych kontrolowanych przez innych dyspozytorów?
Zoe: Nie, tylko dyspozytor przydzielony do d a n e j sekcji dyspozycyjnej m a p r a w o
manipulować urządzeniami tej sekcji. Zauważmy przy tym, że możliwa jest dynamiczna
zmiana przydziału dyspozytorów do sekcji.
Ed: To też wynika ze specyfikacji CTC.
12.4. Aktywności racjonalizacji — od zagadnień do decyzji 575
2. Oczekiwane wyniki
Rozwiązanie zagadnień związanych z integracją kontroli dostępu i powiadamiania.
576 Rozdział 12. • Zarządzanie racjonalizacją
3. Rozpowszechniana i n f o r m a c j a
Al [1]: Dave: Analiza modelu kontroli dostępu realizowanej przez middleware.
Status: Middleware u d o s t ę p n i a silne m e c h a n i z m y szyfrowania i uwierzytelniania,
poza tym nie wprowadza żadnych ograniczeń do modelu dostępu; konieczne jest
więc z a i m p l e m e n t o w a n i e reguł dostępu na serwerze.
4. Dyskusja
I [1]: Czy dyspozytor ma prawo oglądać sekcje dyspozycyjne kontrolowane przez innych
dyspozytorów?
R [ 1]: Tak (wynika to ze specyfikacji CTC i potwierdzone jest przez Zoe, użytkownika
testującego).
I [2]: Czy dyspozytor ma prawo wysyłania poleceń do urządzeń znajdujących się w sekcjach
dyspozycyjnych kontrolowanych przez innych dyspozytorów?
R[2]: Nie, tylko dyspozytor przydzielony do d a n e j sekcji m a p r a w o m a n i p u l o w a ć
urządzeniami tej sekcji. Zauważmy przy tym, że możliwa jest dynamiczna zmiana
przydziału dyspozytorów do sekcji (wynika to ze specyfikacji CTC i potwierdzone
jest przez Zoe, użytkownika testującego).
I [3]: W jaki sposób kontrola dostępu powinna być zintegrowana z podsystemami
Tracki ngSubsystem i Noti f i c a t i onServi ce?
P [3.1]: W klasie TrackSecti on zaimplementowana jest lista uprawnień. Dany podsystem,
aby subskrybować powiadamianie o zdarzeniach tej sekcji, wysyła żądanie do usługi
powiadamiania, która z kolei k o n t a k t u j e się z p r z e d m i o t o w ą sekcją w celu
zweryfikowania uprawnień wspomnianego podsystemu.
P [3.2]: W klasie TrackSecti on skupione zostają wszystkie chronione operacje. Podsystem
zamierzający subskrybować informacje o stanie danej sekcji, kontaktuje się z tą
właśnie sekcją, która p o zweryfikowaniu jego u p r a w n i e ń wywołuje usługę
p o w i a d a m i a n i a w celu dokonania rzeczonej subskrypcji.
A [3.1] na rzecz P [3.2]: Chronione operacje i kontrola dostępu zostają zintegrowane
w ramach jednej klasy.
P [ 3 . 3 ] : Nie trzeba k o n t r o l o w a ć dostępu związanego z odczytywaniem informacji,
UICLi ent może więc żądać subskrypcji od usługi powiadamiania bez względu
na swe uprawnienia — usługa powiadamiania nie musi w ogóle interesować się
listami uprawnień.
A [3.2] na rzecz P [3.3]: Dyspozytorzy mogą bez ograniczeń oglądać wszystkie sekcje
(patrz R[l]).
A [ 3 . 3 ] na rzecz P [ 3 . 3 ] : Prostota.
R[3]: P [ 3 . 3 ] . Patrz Al [2].
5. Podsumowanie
Al [2]: Alice: Zaprojektowanie kontroli dostępu dla podsystemu Tracki ngSubsystem w oparciu
o uwierzytelnianie i szyfrowanie udostępniane przez middleware, zgodnie z rozstrzygnięciem R[3]
tego protokołu.
R e a s u m u j ą c , r e z u l t a t e m s p o t k a n i a p o ś w i e c o n e g o k o n t r o l i d o s t ę p u b y ł o u s t a l e n i e , że:
• k o n t r o l a d o s t ę p u o d b y w a się n a p o d s t a w i e listy u p r a w n i e ń s k o j a r z o n e j z k a ż d y m
obiektem klasy T r a c k S e c t i o n ,
• s c e n t r a l i z o w a n i e w s z y s t k i c h c h r o n i o n y c h m e t o d w klasie T r a c k S e c t i o n b y ł o a k -
ceptowaną regułą.
m y ś l e n i a jest p r a w i d ł o w y i w z w i ą z k u z t y m wysyła n a g r u p ę d y s k u s y j n ą w i d o c z n y p o n i ż e j
post, w k t ó r y m d o d a t k o w o p r o p o n u j e , b y w k o n s e k w e n c j i z a b r o n i ć u s ł u d z e T r a c k i n g S e r v i c e
subskrybowania jakichkolwiek zdarzeń.
Temat: Data
I[ 1 ]: Czy dyspozytor ma prawo oglądać sekcje dyspozycyjne kontrolowane przez 14 wrz
innych dyspozytorów?
I[2]: Czy dyspozytor ma prawo wysyłania poleceń do urządzeń znajdujących się 14 wrz
w sekcjach dyspozycyjnych kontrolowanych przez innych dyspozytorów?
I[3]: W jaki sposób kontrola dostępu powinna być zintegrowana z podsystemami 14 wrz
TrackingSubsystem i NotificationService?
P[3.1]: W klasie TrackSection zaimplementowana jest lista uprawnień. 14 wrz
P[3.2]: W klasie TrackSection skupione zostają operacje subskrypcyjne. 14 wrz
+A[3.1]: Rozszerzalność. 14 wrz
+A[3.2]: Scentralizowanie wszystkich chronionych operacji. 14 wrz
P[3.3]: Usługa NotificationService nie jest związana z kontekstem kontroli 14 wrz
dostępu.
+A[3.3]: Dyspozytorzy mogą oglądać wszystkie sekcje. 14 wrz
+A[3.3]: Prostota. 14 wrz
Od: Mary
Grupy dyskusyjne: ctc.architecture.discuss
Temat: Zagadnienie wynikowe: Czy dopuszczalne jest realizowanie żądań przy użyciu
powiadamiania?
Data: 15 wrz, czw, 13:12:48 -0400
I[4] w odpowiedzi na A[3.3]: w związku z listami uprawnień w kontekście możliwości:
> Dyspozytorzy mogą oglądać stan wszystkich sekcji, mają więc dostęp do wszystkich zdarzeń.
Z a k ł a d a m y zatem, że stan sekcji TrackSection nie jest sterowany z d a r z e n i a m i i zdarzenia
wykorzystywane są tylko do informowania podsystemów o zmianie stanu w innych podsystemach.
Czy dla większego bezpieczeństwa nie powinniśmy zabronić usłudze TrackingService subskrybowania
jakichkolwiek informacji o zdarzeniach?
W y k o r z y s t y w a n i e tego s a m e g o m o d e l u z a g a d n i e ń z a r ó w n o n a z e b r a n i a c h , j a k i n a p o -
t r z e b y dyskusji o n l i n e u m o ż l i w i a i n t e g r o w a n i e i n f o r m a c j i z w i ą z a n e j z racjonalizacją. M i m o iż
integrację tę z a p e w n i ć m o ż n a p r z y użyciu p r o s t y c h technologii, takich j a k g r u p y d y s k u s y j n e ,
poszczególne elementy — modele zagadnień, agendy oraz protokoły zebrań i związane z n i m i
k o m u n i k a t y — m o g ą być i n t e g r o w a n e także za p o m o c ą z a a w a n s o w a n y c h n a r z ę d z i group ware,
j a k Lotus N o t e s czy w i e l o u ż y t k o w a b a z a z a g a d n i e ń d o s t ę p n a w sieci W W W (czego p r z y k ł a d
w i d z i m y n a r y s u n k u 12.17). U s t a n a w i a j ą c o d p o w i e d n i e p r o c e d u r y w s p o m n i a n e j integracji,
m o ż e m y k o l e k c j o n o w a ć o b s z e r n ą i n f o r m a c j ą z w i ą z a n ą z racjonalizacją. I t u p o j a w i a się k o -
lejne w y z w a n i e — u t r z y m y w a n i e tej i n f o r m a c j i w stanie a k t u a l n y m , s t o s o w n i e d o d o k o n y w a -
nych zmian.
12.4. Aktywności racjonalizacji — od zagadnień do decyzji 579
Rysunek 12.17. Przykład bazy zagadnień — szablon bazy danych (LN IBIS w Domino Lotus Notes).
W tej bazie za pomocą formularzy W W W programiści mogą rejestrować zagadnienia, propozycje,
argumenty i rozstrzygnięcia
Protokół ten przydatny jest do dwóch celów: określa racjonalizację nowej zmiany i jed-
nocześnie odnosi ją do istniejącej racjonalizacji. Tę ostatnią przywołuje jako cytat z protokołu
dokumentującego poprzednie zebrania oraz postu na grupie dyskusyjnej zespołu architekto-
nicznego. Wspomniany protokół opublikowany zostanie na rzeczonej grupie dyskusyjnej, by
programiści nieobecni na zebraniu mogli przedyskutować jego treść, zamykając w ten sposób
cykl rejestrowania i wyjaśniania informacji składającej się na racjonalizację. Gdy używane są
narzędzia hipertekstowe, odniesienie do istniejącej racjonalizacji ma formę hiperłączy, co
umożliwia wygodne nawigowanie po powiązanych egzemplarzach informacji.
Nawet jeśli do rejestrowania i śledzenia poszczególnych zagadnień wykorzystywana jest
zaawansowana baza danych, gromadzona w niej informacja może szybko przerodzić się
w ogromny chaos, bez wyraźnej struktury. Co więcej, nie wszystkie zagadnienia są w tej bazie
rejestrowane, bo nie wszystkie są przedmiotem dyskusji na zebraniach: wiele z nich rozstrzy-
ganych jest w ramach nieformalnych konwersacji lub nawet przez pojedynczych programi-
stów, bez jakichkolwiek konsultacji. Konieczne zatem staje się rekonstruowanie umykającej
w ten sposób informacji i integrowanie jej z bieżącą racjonalizacją.
4. Kontrola dostępu
Kontrola dostępu w systemie CTC realizowana jest na poziomie sekcji dyspozycyjnych (TrackSecti on):
dyspozytor (Dispatcher) przydzielony do danej sekcji może modyfikować ich stan, czyli prze-
stawiać sygnały i zwrotnice oraz operować innymi urządzeniami. Dyspozytor może również
oglądać stan sekcji przylegających do jego sekcji macierzystej, bez możliwości modyfikowania
ich stanu. Dyspozytor może w ten sposób obserwować pociągi zbliżające się do kontrolowanej
przez niego sekcji.
Kontrola dostępu zaimplementowana jest w postaci list uprawnień, utrzymywanych przez po-
szczególne obiekty TrackSection reprezentujące konkretne sekcje. Dla danej sekcji lista ta za-
wiera identyfikację dyspozytora uprawnionego do modyfikowania tej sekcji („pisarza") oraz
identyfikacje dyspozytorów uprawnionych do obserwowania ich stanu („czytelników") 6 . Ze
względów ogólności (rozszerzalności) lista zaimplementowana jest w ten sposób, że może za-
wierać wielu „czytelników" i wielu „pisarzy". Lista utrzymywana przez daną sekcję sprawdzana
jest przed wykonaniem każdej operacji odczytującej lub modyfikującej jej stan.
Gdy podsystem żąda subskrybowania określonej informacji, dotyczącej stanu danej sekcji, wy-
woływana przez niego usługa N o t i f i c a t i o n S e r v i c e kontaktuje się z tą sekcją w celu zweryfi-
kowania praw wspomnianego podsystemu do odczytywania jej stanu. Gdy modyfikuje się listę
uprawnień związaną z daną sekcją, sekcja ta wywołuje usługę N o t i f i c a t i o n S e r v i c e w celu
anulowania nieuprawnionych subskrypcji.
6
To analogia do paradygmatu „czytelników i pisarzy", o tyle jednak daleka, że nie mamy tu do czynienia
z rywalizowaniem o dostęp do zasobów — przyp. tłum.
584 Rozdział 12. • Zarządzanie racjonalizacją
I [1]: Jak powinno się zintegrować kontrolę dostępu z klasą TrackSection i usługą powiadamiania?
Kontrola dostępu w systemie CTC realizowana jest na poziomie sekcji dyspozycyjnych (TrackSecti on):
dyspozytor (Di spatcher) przydzielony do danej sekcji może modyfikować ich stan, czyli przestawiać
sygnały i zwrotnice oraz operować innymi urządzeniami. Dyspozytor może również oglądać stan
sekcji przylegających do jego sekcji macierzystej, bez możliwości modyfikowania ich stanu. Dyspozytor
może w ten sposób obserwować pociągi zbliżające się do kontrolowanej przez niego sekcji.
R[l]:
P [ 2 ] . Propozycja P [1] mogłaby być lepszym rozwiązaniem, ze względu na wyłączenie usługi
powiadamiania z kontekstu kontroli dostępu, gdyby nie konieczność związanej z tym znaczącej
przeróbki istniejącego kodu. W przypadku propozycji P [2] przeróbka ta jest znacznie mniejsza.
gdyż każdy taki dokument rychło stawałby się nieaktualny i nieadekwatny do pozostałych do-
kumentów. Odpowiedniejszym podejściem jest utrzymywanie racjonalizacji w formie repozy-
torium, nieustannie aktualizowanego i uzupełnianego o nowe zagadnienia i decyzje. Zawartość
tego repozytorium musi być jednak utrzymywana w aktualnym stanie i łatwo dostępna dla
wszystkich zainteresowanych. Wymaganie to prowadzi wprost do ścisłego zintegrowania re-
pozytorium racjonalizacji z innymi narzędziami i procesami programistycznymi. Przykładem
narzędzia realizującego taką integrację jest REQuest; narzędzie to umożliwia formułowanie
przypadków użycia w kontekście ich racjonalizacji, o czym piszą A. H. Dutoit i B. Paech
[Dutoit i Paech, 2002]. Na rysunku 12.18 widzimy przykładowy ekran tej aplikacji; lewa
kolumna zapewnia dostęp do poszczególnych wymagań systemu, w podziale na przypadki
użycia i wymagania pozafunkcyjne, zaś w prawej kolumnie prezentowane są elementy racjo-
nalizacji związane z poszczególnymi wymaganiami, w kategoriach rozszerzonego modelu
QOC. Przyciski w górnej części lewej kolumny umożliwiają programistom formułowanie pytań
w różnych kategoriach (klarowności, kompletności, spójności, prawidłowości uformowania,
poprawności, uzasadnienia) i kojarzenie ich z aktualnie wyświetlanym elementem.
Zielone, żółte i czerwone wskaźniki towarzyszące elementom racjonalizacji wymienio-
nym w lewej kolumnie oznaczają status zagadnienia reprezentowanego przez ten element.
Klikając wspomniany wskaźnik, otrzymujemy opis odnośnego zagadnienia w prawej kolumnie.
• Jeden protokolant dla każdego zespołu. Zebrania są zwykle organizowane przez zespoły
zajmujące się poszczególnymi podsystemami lub zespół międzyfunkcyjny. Rolę proto-
kolanta mogą rotacyjnie pełnić poszczególni programiści, co przyczynia się do równo-
miernego rozłożenia tego czasochłonnego obowiązku w całym cyklu realizacji projektu.
• Jeden i ten sam redaktor racjonalizacji przez cały czas realizacji projektu. T a rola wy-
maga pełnoetatowego zaangażowania, w przeciwieństwie więc do rotacyjnej roli pro-
tokolanta wymaga zachowania spójności i z tego względu powinna być przypisana
pojedynczej osobie. W przypadku małych projektów rolę tę pełnić może architekt
systemu (patrz rozdział 6. „Projektowanie systemu — dekompozycja na podsystemy").
588 Rozdział 12. • Zarządzanie racjonalizacją
aspektów systemu czy podjęcie ważnych decyzji — które znacznie ułatwią rozwiąza-
nie patowego dotąd problemu. Niebezpieczeństwem tej strategii jest zagrożenie, iż
wymusza ona podejmowanie decyzji krótkowzrocznych, optymalizujących kryteria
krótkoterminowe — na przykład łatwość implementacji — a ignoruje cele daleko-
siężne, takie jak modyfikowalność i pielęgnowalność.
12.7. Ćwiczenia
12.1. W sekcji 12.3 o m a w i a l i ś m y z a g a d n i e n i e z w i ą z a n e z k o n t r o l ą d o s t ę p u i p o w i a d a -
m i a n i e m w systemie C T C . P o d a j p r z y k ł a d i n n e g o zagadnienia, jakie m o ż e w y n i k n ą ć
w związku z t w o r z e n i e m takiego systemu, przedstaw możliwe propozycje, kryteria
i a r g u m e n t y . Z a p r o p o n u j oraz u z a s a d n i j rozstrzygnięcie. O t o d w a m o ż l i w e p r z y k ł a d y
wspomnianych zagadnień:
• Jak z a p e w n i ć s p ó j n o ś ć m i ę d z y s e r w e r e m g ł ó w n y m (mai n S e r v e r ) a z a p a s o w y m
(hotBackup)?
• Jak w y k r y w a n e b ę d ą a w a r i e s e r w e r a g ł ó w n e g o i j a k z a i m p l e m e n t o w a n e b ę d z i e
przejęcie pracy przez serwer zapasowy?
12.2. W y o b r a ź sobie, że t w o r z y s z p r o g r a m n a r z ę d z i o w y w s p o m a g a j ą c y m o d e l o w a n i e
w języku U M L i p o s t a n o w i ł e ś ściśle z i n t e g r o w a ć z a r z ą d z a n i e racjonalizacją z i n n y m i
m e c h a n i z m a m i modelowania. Opisz, w jaki sposób programista wykorzystujący
T w o j e narzędzie kojarzył będzie z a g a d n i e n i a z i n n y m i e l e m e n t a m i m o d e l u . N a r y s u j
d i a g r a m klas p r z e d s t a w i a j ą c y m o d e l z a g a d n i e ń i w s p o m n i a n e s k o j a r z e n i a .
Bibliografia
[Boehm i in., 1998] B. Boehm, A. Egyed, J. Kwan, D. Port, A. Shah, R. Madachy
Using the WinWin spiral model: A case study, „IEEE Computer"
31(7): str. 3 3 - 4 4 , 1998.
[Chung i in., 1999] L. Chung, B. A. Nixon, E. Yu, J. Mylopoulos Non-Functional
Requirements in Software Engineering, Kluwer Academic,
Boston, 1999.
[Conklin i Burgess-Yakemovic, 1991] J. Conklin, K. C. Burgess-Yakemovic A process-oriented
approach to design rationale, „Human-Computer Interaction",
t.6, str. 3 5 7 - 391, 1991.
[Dutoit i Paech, 2001] A.H. Dutoit, B. Paech „Rationale management in software
engineering" w: S. K. Chang (red.) Handbook of Software
Engineering and Knowledge Engineering, t.l, World
Scientific Publishing, 2001.
[Dutoit i Paech, 2002] A. H. Dutoit, B. Paech Rationale-based use case
specification, „Requirements Engineering Journal", 7(1):
str. 3 - 19, 2002.
[Dutoit i in., 2006] A. H. Dutoit, R. McCall, I. Mistrik, B. Paech (red.) Rationale
Management in Software Engineering, Springer,
Heidelberg, 2006.
[Fisher i in., 1991] R. Fisher, W . Ury, B. P a t t o n Dochodząc do TAK.
Negocjowanie bez poddawania się, Polskie Wydawnictwo
Ekonomiczne, Warszawa, 2000.
[Kunz i Rittel, 1970] W . Kunz, H. Rittel „Issues as elements of i n f o r m a t i o n
systems", Working Paper Nr 131, Institut fur Grundlagen
der Plannung, Universitat Stuttgart, Germany, 1970.
[Lee, 1990] J. Lee „A qualitative decision management system" w: P. H.
Winston, S. Shellard (red.) Artificial Intelligence at MIT:
Expanding Frontiers, t.l, str. 104 - 133, MIT Press, Cambridge,
MA, 1990.
[MacLean i in., 1991] A. MacLean, R. M. Young, V. Bellotti, T. Moran „Questions,
options, and criteria: Elements of design space analysis",
„ H u m a n - C o m p u t e r Interaction", t.6, str. 201 - 250,1991.
[Moran i Carroll, 1996] T. P. Moran, J. M. Carroll (red.) Design Rationale: Concepts,
Techniques, and Use, Lawrence E r l b a u m Associates,
Mahwah, NJ, 1996.
Bibliografia 595
Bibliografia 634
Zarządzanie konfiguracją
Airbus A320
A321 i A 3 1 9
Sukces A320 skłonił konsorcjum Airbus do opracowania dwóch zbliżonych modeli: krótszego,
124-miejscowego A319 i dłuższego, 185-miejscowego A321. Projektowanie nowego modelu po-
przez skrócenie albo wydłużenie istniejącego to powszechna praktyka w przemyśle lotniczym. Pro-
ducentom pozwala na zmniejszenie kosztów i skrócenie czasu produkcji poprzez wykorzystywanie
dużej części istniejącego projektu, liniom lotniczym umożliwia zmniejszenie kosztów operacyjnych,
między innymi przez używanie tego samego zestawu części zamiennych. Airbus posunął się nieco
dalej: wszystkie trzy modele mają taki sam pulpit sterowniczy i tę samą charakterystykę sterowania
— A321 wyposażono w klapy ze szczelinami i nieco zmodyfikowane skrzydła, by sterowało się nim
podobnie jak A320, od którego jest dłuższy i cięższy. W konsekwencji pilot posiadający certyfikat na
dowolny z wymienionych modeli może pilotować pozostałe dwa, co powoduje kolejne oszczędności
w postaci mniejszej liczby szkoleń pilotów i personelu serwisującego, jednego typu symulatora lotów
i wykorzystywaniu takich samych części zamiennych do wszystkich trzech modeli.
1
Dosł. „latanie za pomocą kabli" — elektroniczny system sterowania samolotem, eliminujący mecha-
niczne połączenia z elementami steru. Patrz także http://plwikipedia.org/wiki/Fly-by-wire —przyp. tłum.
13.1. Wstęp: samoloty 599
A330 i A340
Dwa kolejne modele — A330 i A340 — to dalsze kroki na drodze rozwojowej airbusów. Zaprojek-
towane na średnie i dalekie trasy mogą zabierać dwukrotnie więcej pasażerów niż A320 i latać trzy
razy dalej. Mają taki sam kokpit i pulpit sterowniczy jak A320; pilot posiadający certyfikat na modele
rodziny A320 może prowadzić modele A330 i A340 po niewielkim przeszkoleniu. Dla odróżnienia
— Boeing 737 (który można porównać do A319) ma charakterystykę sterowania całkowicie różną
od Boeinga 747 (który można by porównać do A340).
2
Polska stała się członkiem JAA w listopadzie 2002 roku. JAA zakończyły działalność 30 czerwca
2009 roku, ich działalność szkoleniową kontynuuje holenderska organizacja JAA-Training Orga-
nisation — przyp. tłum.
600 Rozdział 12. • Zarządzanie r a c j o n a l i z a c j ą
Ponadto kilka innych aktywności często postrzeganych jest jako część zarządzania kon-
figuracją, pisze o tym S. Dart [Dart, 1991]. Są to między innymi:
3
Proces ten, określany w języku angielskim za pomocą czasownika build („budować"), polega na gene-
rowaniu binarnych wersji plików (modułów wykonywalnych, nakładek, bibliotek DLL, zasobów, pli-
ków systemu pomocy i tym podobnych) na podstawie ich pierwowzorów w postaci kodu źródłowego,
przy użyciu kompilatorów, konsolidatorów i innych podobnych narzędzi. Ponieważ w wyniku wpro-
wadzenia zmian do któregoś z komponentów zwykle tylko niektóre komponenty wymagają ponow-
nego generowania, zidentyfikowanie ich pozwala znacznie zaoszczędzić czas „budowania", dzięki
sprowadzeniu go do rozmiarów minimalnych, czyli „budowania przyrostowego" zwanego także „od-
budowywaniem". Gdy nie można przeprowadzić takiej identyfikacji, jedynym wiarygodnym sposo-
bem uzyskania spójnych binariów systemu jest przeprowadzenie „budowania" wszystkich kompo-
nentów, co nazywane jest „budowaniem zupełnym". Większość środowisk programistycznych
udostępnia narzędzia do śledzenia zależności między komponentami, co w większości przypadków
pozwala na wiarygodne stosowanie budowania przyrostowego. W sytuacji gdy budowanie binariów
odbywa się kilkadziesiąt, a nawet kilkaset razy dziennie różnica czasowa między budowaniem
przyrostowym a zupełnym nabiera wyjątkowego znaczenia praktycznego — p r z y p . tłum.
602 Rozdział 12. • Zarządzanie r a c j o n a l i z a c j ą
Jak już wspominaliśmy, tradycyjnie zarządzanie konfiguracją pojmowane jest jako dys-
cyplina menedżerska, wspomagająca menedżerów w kontrolowaniu zmian, obserwowaniu
statusu i audycie — informacje na ten temat znaleźć można w pracy E. H. Bersoffa, V. D.
Hendersona i S. G. Siegela [Bersoff i in.,1980] oraz w wytycznych IEEE [IEEE Std. 1042-1987]
— jednakże od niedawna zarządzanie konfiguracją rozpatrywane bywa także w kontekście
pracy programistów, którym pomaga w walce z dużą liczbą zmian, komponentów i wariantów,
o czym pisze W. A. Babich [Babich, 1986]. Ten właśnie kontekst stanowić będzie główną treść
tego rozdziału, pobieżnie potraktujemy natomiast kwestię kontrolowania zmian i obsługi statusu.
Konieczność zarządzania konfiguracją towarzyszy programistom przez cały cykl życiowy
projektu: zarządzanie to rozpoczyna się od identyfikowania elementów konfiguracji, zaraz po-
tem jak zdefiniowane zostaną elementy konfiguracji i produkty finalne, później rozciąga się
na wszystkie produkty powstające na etapach analizy, projektowania systemu, projektowania
obiektów i implementacji. W połączeniu z zarządzaniem racjonalizacją (patrz rozdział 12.
„Zarządzanie racjonalizacją") zarządzanie konfiguracją jest podstawowym narzędziem umoż-
liwiającym programistom zapanowanie nad zmianami.
4
Linux (http://www.linux.org) to powszechnie dostępny system operacyjny, stanowiący odmianę systemu
POSIX [POSIX, 1990], stworzony przez Linusa Torvaldsa.
13.3. Koncepcje zarządzania konfiguracją 603
CI - Element konfiguracji
CM Aggregate - Agregat CM
nego produktu powstaje przez wprowadzenie do niego jednej lub kilku zmian, polegających
cyjnego (na przykład FAA lub JA A), zanim dopuszczony zostanie do eksploatacji. Każda póź-
uzyskuje się pewność, że zmiany modelu nie spowodują jego odstępstwa od celów projekto-
Rysunek 13.3. Przykłady linii bazowych, wersji i wariantów. Warianty A319, A320 i A321 bazują na tym
samym projekcie, różnią się głównie długością i kadłubem
I tak na przykład niedługo potem jak pierwsza wersja A320 uzyskała certyfikat dopusz-
czający ją do eksploatacji (w lutym 1988 roku), zrewidowana wersja A320-200 ponownie zo-
stała poddana procesowi certyfikacji. Zamierzeniem projektantów nowej wersji było zwięk-
szenie zasięgu (maksymalnego dystansu podróży) oraz zwiększenie dopuszczalnej masy startowej
(przekładające się na większą liczbę pasażerów), co miało zostać zrealizowane przez dodanie
wingletów5 na końcach skrzydeł (zmniejszenie zawirowań powietrza miało przyczynić się do
mniejszego zużycia paliwa). Koszt paliwa jest najważniejszym składnikiem kosztów eksplo-
atacji samolotu, stąd ciągła presja na producentów w kierunku jego obniżania.
Żądanie zmiany, w którym szczegółowo opisano nowe winglety, ewaluację ich wydajno-
ści oraz szacowane koszty, zostało zaakceptowane i model A320-200 uzyskał certyfikat eks-
ploatacyjny w listopadzie 1988 roku. Dla porównania, żądanie zmian w jądrze systemu opera-
cyjnego Linux miało formę e-maila wysłanego do Linusa Torvaldsa.
5
Winglet — aerodynamiczne skrzydełko na końcu skrzydła, mające za zadanie zmniejszenie oporu
wywołanego przez turbulencje, a w konsekwencji poprawę współczynnika doskonałości lotu i zmniej-
szenie zużycia paliwa. Patrz także http://pl.wikipedia.org/wiki/Winglet — przyp. tłum.
606 Rozdział 12. • Zarządzanie r a c j o n a l i z a c j ą
się wykrycia przez nich nowych usterek oraz dokonania subiektywnej oceny jakości przed-
miotowego oprogramowania. Gdy poprawione zostaną ewentualne usterki, kolejne rewizje
systemu są przekazywane do zespołu kontroli jakości, a po uzyskaniu akceptacji emitowane
ponownie do użytkowników.
Należy w tym miejscu zwrócić uwagę, że wiele obecnych systemów zarządzania konfi-
guracją określa jako „repozytorium" bibliotekę służącą do przechowywania zarówno promocji,
jak i emisji. Zamiast powyższego trójstopniowego podziału mamy więc podział dwustopniowy:
programiści tworzą nowe promocje, importując elementy konfiguracji z przestrzeni roboczej
do repozytorium, natomiast w ramach repozytorium promocje odróżniane są od emisji za
pomocą odpowiednich konwencji identyfikowania wersji.
6
DosŁ: człowiek słomiany, drewniany, cynowy, żelazny i stalowy — przyp. tłum.
13.3. Koncepcje zarządzania konfiguracją 607
Rysunek 13.4. Trzyczęściowy schemat identyfikowania wersji. Składnia schematu opisana jest w notacji
Backusa-Naura (BNF)
Ów prosty schemat sprawdza się jednak tylko w przypadku ściśle sekwencyjnego ge-
nerowania nowych wersji. Odstępstwem od tej sekwencyjności są gałęzie, reprezentujące
równoległe ścieżki opracowywania poszczególnych wersji, wymagające niezależnego trakto-
wania z perspektywy zarządzania konfiguracją. Co prawda, dla użytkownika kolejne emisje
608 Rozdział 12. • Zarządzanie r a c j o n a l i z a c j ą
Rysunek 13.5. Schemat identyfikowania wersji w systemie CVS. Składnia schematu opisana jest w notacji
Backusa-Naura (BNF). Gałęzie wywodzą swą identyfikację od wersji, z której biorą swój początek
linii przerywanych. Zbiory zmian związane z tymi rewizjami, odpowiednio emptyCl assFix:
^ChangeSet i dashedLi neFi x: ChangeSet, są niezależne o d siebie i m o g ą być z a s t o s o w a n e d o
linii bazowej w dowolnej kolejności. Konkretnie: stosując zbiór zmian emptyCl assFix do
wersji MUE 1.0, otrzymaliśmy wersję MUE 1. Ib, zaś zastosowany do tej ostatniej zbiór zmian
dashedLi neFi x dał wersję MUE 1.2. Moglibyśmy jednak zmienić tę kolejność: rewidując linię
bazową MUE 1.0 przez zbiór zmian dashedLi neFi x, otrzymalibyśmy wersję MUE 1. la, której
rewizja przez zbiór zmian emptyCl assFix dałaby w rezultacie wersję MUE 1.2. Te dwie moż-
liwości reprezentowane są przez dwie gałęziena rysunku 13.6.
Reprezentowanie ewoluującej konfiguracji w postaci ciągu zmian jest bardziej ogólne niż
jej reprezentowanie w postaci ciągu stanów, pozwala bowiem na ujęcie ciągu powiązanych
wersji różnych elementów konfiguracji w pojedynczą akcję. Co więcej, gdy zbiory zmian są
rozłączne, mogą być stosowane do kilku wersji. Właściwość ta wykorzystywana jest do „łata-
nia" wyemitowanych wersji w przypadku wykrycia w nich błędów: każda poprawka dostar-
czana jest w postaci osobnej łaty i, jeżeli zbiory zmian związane z poszczególnymi poprawkami
są rozłączne, poszczególne poprawki mogą być instalowane w dowolnej kolejności.
610 Rozdział 12. • Zarządzanie r a c j o n a l i z a c j ą
Rysunek 13.6. Dwie niezależne rewizje linii bazowej MUE 1.0, reprezentowane przez zbiory zmian
emptyCl assFix:ChangeSet i dashedlineFix:ChangeSet mogą być wykonane w dowolnej kolejności
t r a n s a k c j i . S y s t e m M y C a r P a r t s z r e a l i z o w a n y jest w a r c h i t e k t u r z e k l i e n t - s e r w e r , z d w i e m a
o d m i a n a m i s t r o n y k l i e n c k i e j : ECLi e n t , p r z e z n a c z o n e j d l a u ż y t k o w n i k ó w p r o f e s j o n a l n y c h
( m e c h a n i k ó w s a m o c h o d o w y c h ) , o r a z NC1 i e n t dla u ż y t k o w n i k ó w n o w i c j u s z y i u ż y t k o w n i k ó w
n i e o b e z n a n y c h z t e c h n o l o g i ą m o t o r y z a c y j n ą (czyli dla większości p o s i a d a c z y s a m o c h o d ó w ) .
W systemie u t r z y m y w a n e są profile u ż y t k o w n i k ó w — w y m a g a n e jest uwierzytelnianie — co
u m o ż l i w i a s t o s o w a n i e z r ó ż n i c o w a n e j polityki c e n o w e j (klient z a m a w i a j ą c y d u ż ą ilość części
o t r z y m u j e s t o s o w n y rabat), p o w i a d a m i a n i e w y b r a n y c h k l i e n t ó w o i n t e r e s u j ą c y c h ich n o w o -
ściach, a także optymalizację wykorzystania sieci. S t r u k t u r a p o d s y s t e m ó w s y s t e m u m y C a r P a r t s
p r z e d s t a w i o n a jest n a r y s u n k u 13.7 i w tabeli 13.1.
T w o r z e n i e i e w o l u o w a n i e s y s t e m u myCarParts w y m a g a z a c h o w a n i a o k r e ś l o n e j k o o r -
dynacji m i ę d z y poszczególnymi jego k o m p o n e n t a m i .
13.4. Aktywności tworzące zarządzanie konfiguracją 613
Opisane wzbogacenie systemu o mapy części zamiennych stanowić będzie bazę dla na-
szych kolejnych przykładów.
7
Dla prostoty pominęliśmy na diagramie elementy r e p r e z e n t u j ą c e kod źródłowy, przypadki testowe
i podręcznik testera.
13.4. Aktywności tworzące zarządzanie konfiguracją 615
się rozwijaniem odnośnego elementu konfiguracji bez kolizji z pracami kolegów. Zapisana
w repozytorium promocja nie może być modyfikowana, uskutecznienie zmian wprowadzo-
nych przez programistę do elementu konfiguracji wymagać będzie utworzenia nowej promocji.
Spójrzmy na rysunek 13.9, przedstawiający migawki z czterech różnych przestrzeni
roboczych, w związku z realizacją następującego scenariusza wynikającego z rozszerzenia
klienta NC1 ient o mechanizm map. Programiści rozpoczynają od modyfikacji modelu anali-
tycznego, do którego dodają przypadki użycia związane z nawigowaniem po mapach oraz
modyfikują odpowiednio niektóre z istniejących przypadków użycia; efektem tych zmian jest
promocja NC1 i ent RAD .2.0. W następnej kolejności modyfikowany jest model projektu sys-
temu, w którym uwzględnione zostaje przechowywanie i wyszukiwanie map — w rezultacie
otrzymujemy promocje Protokó?.2.0 i Schemat danych.2.0. Potem dokonywana jest pierw-
sza implementacja serwerowej części zmodyfikowanego protokołu komunikacyjnego, której
efektem jest promocja Server .2.0, przeznaczona do współpracy z promocją NC1 i ent .2.0
(i wyższymi wersjami), w celu jej przetestowania. Testy wykonane przez użytkowników
doprowadzają do wykrycia kilku błędów w implementacji serwera; programiści odnajdują
i usuwają przyczyny tych błędów, czego efektem są promocje S e r v e r . 2 . 1 i Server.2.2.
W międzyczasie zespół dokumentacyjny dokonuje rewizji podręcznika użytkownika NC1 i ent
UM.2.0 w oparciu o NC1 i ent RAD .2.0. Zauważmy, że równolegle z powyższymi aktywno-
ściami zespół zajmujący się podsystemem EC 1 i ent może usuwać tkwiące w nim usterki, a do
jego testowania wykorzystywać starszą, stabilną wersję serwera (Server. 1.4). Jak widać, nawet
jeśli poszczególne zespoły zmierzają w kierunku zbudowania spójnego systemu, mogą po-
sługiwać się różnymi promocjami tego samego komponentu do czasu, aż postać wszystkich
komponentów ustabilizuje się.
Promocje reprezentują stan elementów konfiguracji w momencie udostępniania ich
programistom. Zwykle wymaga się, by były one wolne od błędów syntaktycznych (czyli dawały
się skomplikować), a kilka pomniejszych ograniczeń szczegółowo określa zasady przekazywa-
nia produktów między zespołami. Gdy jakość elementów konfiguracji zyska odpowiednio wy-
soki stopień, potwierdzony przez zespół kontroli jakości, promocjezyskują możliwość awan-
sowania do rangi emisji.
Rysunek 13.9. Migawki z przestrzeni roboczej różnych programistów pracujących nad systemem
myCarParts. Zespoły podsystemów NCI i ent i Server oraz zespół dokumentalistów zajmują się wpro-
wadzeniem nawigowalnych m a p do systemu, zespół podsystemu EClient posługuje się natomiast
starszą, stabilną wersją serwera. Dla wszystkich elementów konfiguracji wersje l.x odnoszą się do
promocji nieoferujących mechanizmu map, natomiast wersje 2.x oferują częściową lub kompletną im-
plementację tego mechanizmu
Jako przykład weźmy dwie nakładające się zmiany: podczas gdy jeden zespół zajmuje
się wprowadzaniem do podsystemów NCI i ent i Server funkcjonalności związanej z nawi-
gowalnymi mapami (o czym pisaliśmy w sekcjach 13.4.2 i 13.4.3), drugi zespół pracuje nad
skróceniem czasu reakcji serwera (Server). Oba zespoły, by zrealizować swe cele, muszą
zmodyfikować oba podsystemy, w tym ich interfejsy.
Zmiany te przyporządkowane zostały odrębnym zespołom ze względu na zróżnicowane
ryzyko, jakie niosą ze sobą: dodanie nawigowalnych map jest dobrze zdefiniowane i stanowi
poszerzenie dotychczasowej funkcjonalności, bez jakiegokolwiek uszczerbku dla jej obecnej
postaci. Dla odmiany, wysiłki zmierzające do zoptymalizowania reaktywności serwera mają
w dużej mierze charakter eksperymentalny i stanowią raczej wyprawę w nieznane: programiści
muszą zidentyfikować podstawowe źródła „wąskich gardeł" wydajności i zaprojektować heu-
rystyki zmierzające do usprawnienia realizacji najbardziej typowych żądań. Efekty tych dążeń
muszą zostać następnie ocenione zarówno pod kątem rzeczywistych osiągów, jak i (ewentual-
nych) zagrożeń dla stabilności oraz utrudnień w utrzymaniu serwera. Ponadto rozdzielenie
obu zmian stwarza bardziej elastyczne możliwości w zakresie dystrybucji: jeśli optymalizowanie
reaktywności serwera zostanie ukończone stosunkowo wcześnie, można ją uwzględnić w wersji
podsystemu NC1 ient przekazywanej klientowi, w przeciwnym razie możną ją uczynić przed-
miotem późniejszych poprawek rozpowszechnianych w formie łaty.
Aby umożliwić niezależne realizowanie obu zmian, musimy utworzyć gałąź rozpoczy-
nającą się w ostatniej promocji obu podsystemów (patrz rysunek 13.11). Zespół odpowie-
dzialny za nową funkcjonalność kontynuuje pracę w ramach głównego pnia (wychodząc od
wersji Server. 1.5 i NC1 i ent .1.6), zaś zespół odpowiedzialny za usprawnienie wydajności
serwera tworzy gałąź (zaczynającą się od wersji Server. 1.5.1.1) 8 , a jednocześnie postanawia
ograniczyć swe zmiany wyłącznie do podsystemu Server bez zmieniania jego interfejsu. Oba
zespoły pracują odtąd niezależnie, aż do ukończenia implementacji obu zmian. Implementacja
nawigowalnych map zostaje ukończona wcześniej, a jednym z jej efektów jest wersja Server . 2 . 4
(co widzieliśmy już na rysunku 13.10). Wkrótce potem kończy swą pracę drugi zespół,
produkując wersję Server. 1.5.1.7, która charakteryzuje się czterokrotnie mniejszym czasem
dostępu dla typowych żądań za cenę nieznacznego tylko rozszerzenia protokołu komuni-
kacyjnego. Stajemy więc przed koniecznością zintegrowania obu zmian do spójnej wersji
systemu myCarParts, łączącej nawigowalne mapy i sprawniejszą komunikację klientów
z serwerem.
Scalanie gałęzi wspomagane jest narzędziami dedykowanymi zarządzaniu konfiguracją,
dokonującymi próby scalania ostatnio dokonywanych zmian. Gdy wykryta zostanie zależność
między poszczególnymi zmianami, to znaczy gdy dwie lub więcej dotyczą tej samej klasy czy
metody, wymagana jest interwencja programisty, który — poinformowany za pomocą odpo-
wiedniego komunikatu (alertu) — musi ręcznie dokonać rozwiązania zaistniałego konfliktu.
W naszym przykładzie konflikt ten dotyczy klasy DBInterface, modyfikowanej przez oba ze-
społy (patrz rysunek 13.12).
Zespół zajmujący się nawigowalnymi mapami utworzył nową metodę processMap
^Request () realizującą żądanie wyszukania odpowiedniej mapy w bazie. Drugi zespół zbu-
dował natomiast metodę processPartRequest () wyszukującą w bazie część zamienną na
8
Stosujemy identyfikowanie wersji i gałęzi zgodnie ze schematem przyjętym w systemie CVS [Berliner,
1990].
13.4. Aktywności tworzące zarządzanie konfiguracją 621
Rysunek 13.11. Przykład gałęzi. W ramach głównego pnia programiści implementują w systemie
myCarParts nawigowalne mapy. W równoległej gałęzi inni programiści optymalizują wydajność
serwera i jego bazy danych. Pierwsza z tych zmian zostaje zrealizowana wcześniej i udostępniona
klientom jako emisja, druga zmiana zostaje udostępniona później jako łata
podstawie jej identyfikatora. Scalona wersja klasy DBInterface powstała poprzez wybranie
klasy processMapRequest() z głównego pnia i klasy processPartRequest () z gałęzi. Tak zre-
widowana klasa — w postaci promocji Server.2.5 — poddana została testom w celu zapew-
nienia, że rozwiązane zostały wszystkie konflikty między zmianami. Zastosowany w metodzie
processPartRequest()mechanizm cache'owania okazał się na tyle skuteczny, że programiści
postanowili go użyć także w metodzie processMapRequest(), co ich zdaniem powinno
wydatnie przyczynić się do dalszego skrócenia czasu odpowiedzi serwera; po odpowied-
nim zmodyfikowaniu metody i przetestowaniu pracy serwera z jej nową wersją utworzyli
nową promocję Server.2.6.
Jak widzieliśmy na przykładzie, scalanie dwóch gałęzi nie jest wcale operacją oczywistą.
Wymaga zwykle wsparcia ze strony narzędzi zarządzania konfiguracją oraz (co ważniejsze) zna-
czącej interwencji programistów, a wersja będąca wynikiem scalenia wymaga zaawansowane-
go przetestowania weryfikującego poprawność tego scalenia. W zaprezentowanym przykładzie
622 Rozdział 12. • Zarządzanie r a c j o n a l i z a c j ą
scaleniu podlegały dwie proste zmiany, w dodatku ograniczone do jednego podsystemu (Server)
i niezmieniające jego interfejsu. Tego rodzaju ograniczenia zmniejszają prawdopodobieństwo
pojawienia się zależności między zmianami; gdy wprowadzanie zmian w ramach poszczegól-
nych gałęzi odbywa się żywiołowo, bez żadnych ograniczeń, rozbiegają się one tak dalece, że
ich scalenie okazuje się niewykonalne. I choć nie istnieje żadna recepta na skuteczne rozwią-
zywanie tego problemu, przestrzeganie kilku prostych zasad (heurystyk) może przyczynić się do
zmniejszenia rozbieżności między gałęziami.
Tak czy inaczej, decyzja o utworzeniu gałęzi jest istotnym zdarzeniem w realizacji projektu,
powinna być więc starannie przemyślana, zaplanowana i zaaprobowana przez menedżera.
Rysunek 13.13. Przykłady dwóch strategii realizacji systemu wielowariantowego. W przypadku zrówno-
leglonych projektów warianty podsystemu NC1 i ent dla macintosha i dla peceta realizowane są cał-
kowicie niezależnie od siebie, w przypadku pojedynczego projektu realizowane są jako uniwersalne
podsystemy, oferujące zróżnicowane interfejsy GUI i TCP dla każdej z platform
• Jeden producent, wielu konsumentów. Jeśli proponowana zmiana jest typowa dla
konkretnego wariantu, nie powinna w żaden powodować modyfikacji współdzielo-
nych podsystemów; jeśli natomiast może być pożyteczna dla wszystkich wariantów,
powinna być w całości skoncentrowana we współdzielonych podsystemach. Rozwiąza-
nie przedmiotowego problemu jest więc kwestią starannego zarządzania zmianami.
• Długi cykl realizacji żądania zmiany może zostać wydatnie skrócony, jeśli zespołowi
proponującemu daną zmianę pozostawi się również kwestię jej walidacji. Zmiana
ta zostaje zaimplementowana jako nowa promocja współdzielonego podsystemu,
która zostaje przekazana wspomnianemu zespołowi w celu jej przetestowania; pozo-
stałe zespoły pracują tymczasem z dotychczasową wersją współdzielonego pod-
systemu. Z takim właśnie scenariuszem zetknęliśmy się już w sekcji 13.4.4, gdzie
zespół odpowiedzialny za wprowadzenie nawigowalnych map do systemu NC1 ient
modyfikował w związku z tym oprogramowanie serwera, podczas gdy zespół pod-
systemu EC1 ient korzystał z dotychczasowej, stabilnej wersji serwera. W sytuacji
gdy kilka zespołów zgłasza różne propozycje zmian we współdzielonym podsystemie,
zespół odpowiedzialny za ten podsystem organizuje realizację każdej z nich w ramach
odrębnej gałęzi, w celu wykluczenia ich wzajemnego wpływu na siebie do czasu, gdy
każda z nich stanie się względnie stabilna.
• Niespójności między platformami można minimalizować, dążąc do dekompozycji
niezależnej od konkretnego wariantu. Niskopoziomowe różnice między platforma-
mi rozwiązywane będą wówczas w podsystemach specyficznych dla poszczególnych
wariantów, być może za cenę dodatkowych obiektów pośredniczących lub redun-
dancji między podsystemami specyficznymi a współdzielonymi. Gdy jednak strategia
ta okaże się nieskuteczna (bo poszczególne warianty wyraźnie różnią się między so-
bą), być może zrównoleglenie projektów będzie rzeczywiście lepszą alternatywą.
626 Rozdział 12. • Zarządzanie r a c j o n a l i z a c j ą
Zarządzanie wieloma wariantami systemu jest, jak widać, trudnym zadaniem. Strategia
współdzielonych systemów, mimo iż wymaga dodatkowych inwestycji w fazie projektowania
systemu, daje w rezultacie wiele korzyści, z których najważniejsze to lepsza jakość i większa
stabilność współdzielonego kodu oraz lepsza spójność jakościowa między poszczególnymi
wariantami. Ponadto, gdy liczba wariantów jest dość duża, przewidywanie zawczasu proble-
mów specyficznych dla poszczególnych wariantów i planowanie w związku z nimi odpo-
wiedniego zarządzania konfiguracją pozwoli uzyskać znaczne oszczędności kosztów i czasu.
1. Zostaje zgłoszona propozycja zmiany, dotycząca wykrytej usterki lub nowej funkcjo-
nalności. Zgłaszającym może być każdy, w tym programista lub klient.
2. Propozycja zostaje oceniania pod kątem zgodności z celami projektowymi. W przy-
padku dużych projektów oceny takiej dokonuje dedykowany zespół, w mniejszym
projekcie — jego menedżer. Ocena taka może również obejmować analizę kosztów
i korzyści oraz wpływu proponowanej zmiany na resztę systemu.
3. Konsekwencją dokonanej oceny jest zaakceptowanie albo odrzucenie żądania zmiany.
4. Jeśli żądanie zmiany zostanie zaakceptowane, zostaje ona zaplanowana i zakwali-
fikowana pod względem priorytetu, po czym wyznaczeni programiści dokonują jej
implementacji.
5. Zaimplementowana zmiana poddana zostanie audytowi, przeprowadzanemu przez
zespół kontroli jakości lub osobę odpowiedzialną za zarządzanie emisjami.
13.5. Kierownicze aspekty zarządzania konfiguracją 627
• D o k u m e n t o w a n i e z a r z ą d z a n i a k o n f i g u r a c j ą ( p a t r z sekcja 13.5.1),
Wstęp d e f i n i u j e zakres t e m a t y c z n y i o d b i o r c ó w d o k u m e n t u , p o d s t a w o w ą t e r m i n o l o g i ę
i odwołania do innych dokumentów.
S e k c j a Zarządzanie opisuje organizację projektu, być m o ż e w formie odwołania do
Planu Zarządzania Projektem Programistycznym (patrz rozdział 14. „Zarządzanie projektem"),
i p o d z i a ł o d p o w i e d z i a l n o ś c i w zakresie z a r z ą d z a n i a k o n f i g u r a c j ą n a szczeblu o r g a n i z a c y j n y m
projektu.
W sekcji Aktywności o p i s a n e są s z c z e g ó ł o w o : i d e n t y f i k a c j a e l e m e n t ó w k o n f i g u r a c j i ,
p r o c e s k o n t r o l o w a n i a z m i a n , p r o c e s k r e o w a n i a emisji i ich a u d y t u o r a z p r o c e s k o n t r o l o w a n i a
s t a t u s u k o n f i g u r a c j i . O d p o w i e d z i a l n o ś ć za w y k o n y w a n i e w y m i e n i o n y c h a k t y w n o ś c i p r z y p i -
s a n a z o s t a ł a w sekcji Zarządzanie.
Sekcja Harmonogram p r e c y z u j e , k i e d y p o d e j m o w a n e m a j ą być w s p o m n i a n e a k t y w n o ś c i
i j a k b ę d ą k o o r d y n o w a n e . Szczegółowo z d e f i n i o w a n e są t u okoliczności u z a s a d n i a j ą c e ż ą d a n i e
z m i a n i ich weryfikacja w r a m a c h f o r m a l n e g o procesu.
Zasoby o b e j m u j ą narzędzia, techniki, sprzęt, p e r s o n e l i szkolenia n i e z b ę d n e d o w y k o -
nywania aktywności związanych z zarządzaniem konfiguracją.
P l a n z a r z ą d z a n i a k o n f i g u r a c j ą s a m jest d o k u m e n t e m p o d l e g a j ą c y m z m i a n o m i j a k o taki
s t a n o w i j e d e n z p o d m i o t ó w z a r z ą d z a n i a k o n f i g u r a c j ą . Z a s a d y jego u t r z y m y w a n i a i r e w i d o w a -
nia opisane są w sekcji Konserwacja planu, wymieniającej osoby odpowiedzialne za te czynności,
a także precyzującej częstotliwość jego uaktualniania i f o r m a l n y proces w p r o w a d z a n i a d o
niego zmian.
S t a n d a r d [IEEE Std. 828-2005] z d e f i n i o w a n y został z i n t e n c j ą jego p r z y d a t n o ś c i d o p r o -
jektów dowolnego typu — zarówno projektów o krytycznym znaczeniu, jak i drobnych dar-
mowych narzędzi.
• M e n e d ż e r k o n f i g u r a c j i t o o d p o w i e d z i a l n o ś ć za i d e n t y f i k a c j ę e l e m e n t ó w k o n f i g u r a c j i
i n i e k i e d y za d e f i n i o w a n i e p r o c e d u r t w o r z e n i a p r o m o c j i i e m i s j i . R o l a t a jest c z ę s t o
ł ą c z o n a z r o l ą a r c h i t e k t a s y s t e m u ( p a t r z s e k c j a 7.5.2).
• K o n t r o l e r o d p o w i e d z i a l n y j e s t za a k c e p t o w a n i e a l b o o d r z u c a n i e p r o p o n o w a n y c h
z m i a n n a p o d s t a w i e i c h relacji d o c e l ó w p r o j e k t o w y c h . Z a l e ż n i e o d k o m p l i k a c j i sa-
m e g o procesu d o k o n y w a n i a zmian, rola ta m o ż e o b e j m o w a ć także ocenianie d o k o -
n a n y c h z m i a n i p l a n o w a n i e n a s t ę p n y c h . R o l ę t ę c z ę s t o ł ą c z y się z r o l ą k i e r o w n i k a
zespołu lub menedżera projektu.
• Programista, p o z a „ n o r m a l n y m " r e a l i z o w a n i e m p r o j e k t u , t w o r z y p r o m o c j e o d z w i e r -
ciedlające p r o p o n o w a n e z m i a n y . P o d s t a w o w y m z a d a n i e m p r o g r a m i s t y w a s p e k c i e
z a r z ą d z a n i a k o n f i g u r a c j ą jest a k t u a l i z o w a n i e w e r s j i o p r o g r a m o w a n i a i r o z w i ą z y w a n i e
konfliktów występujących przy scalaniu wersji.
• A u d y t o r o d p o w i a d a za w y b ó r i e w a l u a c j ę p r o m o c j i a w a n s o w a n y c h d o r a n g i e m i s j i ,
a także za s p ó j n o ś ć i k o m p l e t n o ś ć tych emisji. Rolę tę w y k o n u j e zazwyczaj zespół
kontroli jakości.
Role z w i ą z a n e z z a r z ą d z a n i e m k o n f i g u r a c j ą d e f i n i o w a n e są w fazie p l a n o w a n i a p r o j e k t u
i p r z y d z i e l a n e s t o s u n k o w o w c z e ś n i e dla z a p e w n i a n i a s p ó j n o ś c i . Z b y t częste z m i a n y w p r z y -
dziale t y c h r ó l m o g ą p o w a ż n i e o g r a n i c z y ć k o r z y ś c i p ł y n ą c e z z a r z ą d z a n i a k o n f i g u r a c j ą i o d b i ć
się n e g a t y w n i e n a p r o c e s i e k o n t r o l o w a n i a z m i a n .
• Z d e f i n i o w a n i e i p r z y p i s a n i e ról.
• Z d e f i n i o w a n i e k r y t e r i ó w z m i a n , czyli określenie, k t ó r e a t r y b u t y p r o d u k t ó w m o g ą b y ć
z m i e n i a n e i w j a k z a a w a n s o w a n e j fazie p r o j e k t u i c h z m i a n y m o g ą b y ć d o k o n y w a n e .
C o więcej, p r o c e d u r y i n a r z ę d z i a z w i ą z a n e z z a r z ą d z a n i e m k o n f i g u r a c j ą p o w i n n y stać
się d o s t ę p n e , z a n i m j e s z c z e p o j a w i się k o n i e c z n o ś ć d o k o n a n i a p i e r w s z e j z m i a n y — t a k b y
wszystkie z m i a n y m o g ł y być rejestrowane, o c e n i a n e i śledzone.
Rysunek 13.15. CruiseControl — narzędzie wspomagające integrację ciągłą. Każdy kwadrat repre-
zentuje podsystem (w kategoriach CruiseControl nazywany „projektem")
„testem na dym" — smoke test)9, mający na celu wykrycie naj poważniej szych problemów. Po
pomyślnym przejściu przez tę fazę wykonywanie kolejnych testów (dotyczących między in-
nymi wydajności i zachowania systemu w obliczu realistycznych danych) nie blokuje już głów-
nego pnia, który staje się dostępny do integrowania dla innych poprawek. Podział poszcze-
gólnych testów na obie fazy jest więc kwestią kompromisu między wczesnym wykrywaniem
problemów a wydajnością integrowania.
Integracja ciągła sprzyja lepszemu wykorzystywaniu technik opisywanych w tym roz-
dziale i w rozdziale 11. „Testowanie", różni się jednak od nich uwydatnieniem poszczególnych
elementów i skalą czasową. Oznacza bowiem częste integrowanie drobnych zmian, w przeci-
wieństwie do integrowania wstępującego i integrowania zstępującego, które polegają na „hur-
towym" integrowaniu całych podsystemów, w stosunkowo dużych odstępach czasu. W konse-
kwencji integracja ciągła spisuje się bardzo dobrze w odniesieniu do projektów o ewoluującej
architekturze, realizowanych przez pojedynczy zespół programistów, podczas gdy integro-
wanie na poziomie podsystemów przydatne jest dla projektów o dobrze zdefiniowanej archi-
tekturze i podsystemach opracowywanych równolegle przez wiele zespołów.
9
Określenie to zaczerpnięte jest z elektroniki: objawem podłączenia zasilania do wadliwie wykonanego
obwodu może być spalenie się układu scalonego, dające w efekcie błękitny dymek. Gdy po podłącze-
niu zasilania nic się nie dymi, obwód gotowy jest do dalszych testów. Czytelnikom zainteresowanym
metafizycznym znaczeniem owego błękitnego dymku (elektronicy widzą w nim wręcz duszę układu
scalonego) oraz ogólnie kolorytem żargonowych (i nie tylko) określeń powstałych w ciągu ostatniego
półwiecza na kanwie technologii komputerowych chciałbym polecić książkę Leksykon hackingu, wyd.
Helion 2003, http://helion.pl/ksiazki/hacklk.htm — przyp. tłum.
13.7. Ćwiczenia 633
13.7. Ćwiczenia
13.1. System RCS wykorzystuje podejście zwane odwrotną deltą, polegające na prze-
chowywaniu kompletnej postaci najnowszej wersji pliku oraz ciągu różnic między
sąsiadującymi niższymi wersjami; gdy przykładowo dla danego pliku istnieją wersje
1.1, 1.2 i 1.3, RCS zapamiętuje explicite wersję 1.3, różnice między wersjami 1.2 i 1.3
oraz różnice między wersjami 1.1 i 1.2. Gdy pojawi się nowa wersja 1.4, zostanie za-
pamiętana explicite, a dotychczas przechowywana wersja 1.3 zostanie zastąpiona
zbiorem różnic między wersjami 1.3 i 1.4. Wyjaśnij, dlaczego to podejście jest bar-
dziej rozsądne od podejścia zwanego prostą deltą, zgodnie z którym jawnie zapa-
miętywana jest wersja początkowa (o najniższym numerze), a następne wersje re-
prezentowane są za pomocą różnic w stosunku do wersji poprzedniej.
13.2. System CVS wykorzystuje reguły tekstowe przy wykrywaniu konfliktów scalania:
plik traktowany jest jako ciąg wierszy tekstu, a za kolidujące uważane są zmiany od-
noszące się do tego samego wiersza. Jeżeli w jednej z wersji wiersz taki nie istnieje,
CVS traktuje to jako brak konfliktu i automatycznie dokonuje scalenia. Załóżmy na
przykład, że plik zawiera definicję klasy z trzema metodami a ( ) , b ( ) i c(), i dwóch
programistów niezależnie od siebie modyfikuje ten plik. Gdy dokonane przez nich
zmiany (wyrażające się zestawem zmodyfikowanych wierszy) nie są rozłączne w mo-
mencie scalania, CVS sygnalizuje konflikt. Wyjaśnij na stosownym przykładzie,
dlaczego takie podejście nie jest w stanie wykryć niektórych konfliktów przy scalaniu.
13.3. Systemy zarządzania konfiguracją, takie jak RCS, CVS i Perforce wykorzystują kom-
pletną ścieżkę pliku do jego identyfikowania jako elementu konfiguracji. Wyjaśnij,
w jaki sposób cecha ta przeszkadza w zarządzaniu konfiguracją agregatów CM, nawet
mimo obecności etykiet.
634 Rozdział 12. • Zarządzanie r a c j o n a l i z a c j ą
13.6. W rozdziale 11. „Testowanie" opisywaliśmy sposób znajdowania przez zespół kontroli
jakości usterek w p r o m o c j a c h t w o r z o n y c h przez zespoły p o d s y s t e m ó w . N a r y s u j dia-
g r a m aktywności U M L o b e j m u j ą c y a k t y w n o ś c i z w i ą z a n e z p r z e t w a r z a n i e m z m i a n
i t e s t o w a n i e m w w a r u n k a c h p r o j e k t u r e a l i z o w a n e g o p r z e z wiele zespołów.
Bibliografia
W. A. Babich Software Configuration Management, Addison-Wesley, Reading,
[Babich, 1986]
MA, 1986,
K. Beck, C. Andres Extreme Programming Explained: Embrace Change,
[Beck i Andres, 2005]
wyd. drugie, Addison-Wesley, Reading, MA, 2005.
B. Berliner „CVS II: Parallelizing software development", Proceedings of the
[Berliner, 1990]
1990 USENIX Conference, Washington, DC, str. 22 - 26, styczeń 1990.
E. H. Bersoff, V. D. Henderson, S. G. Siegel, Software Configuration Management:
[Bersoffiin., 1980]
An Investment in Product Integrity, Prentice Hall, Englewood Cliffs, NJ, 1980.
[CruiseControl] h ttp:// cruisecontrol. sourceforge. net/.
[Dart, 1991] S. Dart „Concepts in configuration m a n a g e m e n t systems", Third
International Software Configuration Management Workshop, ACM,
czerwiec 1991.
[Duval i in., 2007] P. Duval, S. Matyas, A. Glover Continuous Integration: Improving Software
Quality and Reducing Risk, Addison-Wesley, Reading, MA, 2007.
[IEEE Std. 828-2005] IEEE Standard for Software Configuration Management Plans, IEEE
Standards Board, sierpień 2005.
[IEEE Std. 1042- IEEE Guide to Software Configuration Management, IEEE Standards Board,
1987] wrzesień 1987.
[Kemerer, 1997] C. F. Kemerer „Case 7: Microsoft Corporation: Office Business Unit", Software
Project Management: Readings and Cases, Irwin/McGraw-Hill, Boston,
MA, 1997.
[Knuth, 1986] D. E. Knuth The TeXbook, Addison-Wesley, Reading, MA, 1986.
[Lebłang, 1994] D. Leblang „The CM challenge: Configuration management that works",
w: W. F. Tichy (red.), Configuration Management, t. 2 of Trends in Software,
Wiley, New York, 1994.
[MIL Std. 480] MIL Std. 480, U.S. Department of Defense, Washington, DC.
[Moziłła] http://www. mozilla. org/
[Perforce] http://www.perforce, com/
[POSIX, 1990] Portable Operating System Interface for Computing Environments, w: IEEE
Std. 1003.1,1990.
Bibliografia 635
Bibliografia 680
Zarządzanie projektem
1
Patrz http://www.nasaspaceflight.com/2007/01/remembering-the-mistakes-of-challenger/ — przyp. tłum.
638 Rozdział 12. • Zarządzanie racjonalizacją
metodologie") jednak zastanowimy się, co dzieje się, gdy rzeczywistość wymyka się z pod-
ręcznikowych ram i przyjrzymy się niektórym metodologiom i heurystykom umożliwiają-
cym radzenie sobie z zaskakującymi nieraz sytuacjami.
STS-51L — katastrofa C h a l l e n g e s
28 stycznia 1986 roku prom kosmiczny Challenger realizujący misję STS-51L eksplodował 73 sekundy
po starcie, w wyniku czego zginęła cała siedmioosobowa załoga. Prezydencka komisja Rogersa
powołana do zbadania przyczyny wypadku ustaliła, że zapłon gazów wydostających się przez nie-
szczelne złącze w prawej rakiecie pomocniczej na paliwo stałe spowodowało wybuch w o d o r u
w zewnętrznym zbiorniku. Zgodnie z konkluzją komisji, duży przyczynek do tragedii miały poważ-
ne defekty w zakresie procesów decyzyjnych w NASA.
Główne komponenty promu kosmicznego to orbiter, rakiety pomocnicze na paliwo stałe i zewnętrzny
zbiornik paliwa. Orbiter jest pomieszczeniem dla załogi i ekwipunku, a rakiety pomocnicze spełniają
większość funkcji związanych z wyniesieniem go na orbitę. Gdy wyczerpią zapas paliwa, stają się zbędne,
zostają odrzucone i spadają do oceanu. Zewnętrzny zbiornik, dostarczający paliwa dla maszynerii or-
bitera, także jest odrzucany przed wejściem na orbitę. Rakiety pomocnicze zbudowane zostały
przez prywatnego podwykonawcę, firmę Morton Thiokol. By możliwy był ich transport, zostały
dostarczone w częściach i poskładane na stanowisku startowym. Poszczególne sekcje połączone
były za pomocą złączy; właśnie nieszczelność tych złączy spowodowała wspomniany wyciek gazów.
Jak ustaliła komisja Rogersa, inżynierowie z firmy Thiokol świadomi byli zagrożenia spowodo-
wanego takim obrotem sprawy: analiza rakiet pomocniczych odrzucanych przez wahadłowiec
w poprzednich misjach wykazała erozję uszczelek, zwanych popularnie „O-ringami", spowodowaną
wyciekającymi gazami i szczególnie groźną w sytuacji, gdy start odbywa się przy niskiej temperaturze
otoczenia. Fakt ten zaalarmował inżynierów choćby z tego względu, że projekt O-ringów nie
przewidywał ich odporności na taki kontakt. Menedżerowie zaliczyli ten problem w poczet „akcep-
towalnego ryzyka", jako że w poprzednich misjach erozja O-ringów nie miała katastrofalnych na-
stępstw. Inżynierowie w Thiokol bezskutecznie usiłowali przekonać swych przełożonych o powadze
problemu. W dniach poprzedzających start wahadłowca inżynierowie ci zaniepokoili się niską tem-
peraturą na stanowisku startowym i próbowali przekonać swych menedżerów do zaniechania
startu. Firma Thiokol, początkowo optująca za odłożeniem startu, ostatecznie zmieniła swe oficjalne
stanowisko, uginając się pod presją NASA.
Zarówno NASA, jak i Thiokol zarządzane były zgodnie z hierarchiczną strukturą, typową dla instytucji
administracji publicznej. W ramach tej struktury inżynierowie kontaktują się bezpośrednio z mene-
dżerami swych grup, ci z kolei raportują problem menedżerowi projektu i tak dalej. Każdy szczebel
2
Prezentowany tutaj opis tragedii Challengera ma charakter wybiórczy i służy jedynie jako (spekta-
kularny) przykład błędów w zarządzaniu projektem; zarówno techniczne, jak organizacyjne błędy
p r o w a d z ą c e w rezultacie do katastrofy były bardziej skomplikowane, niż m o g ł o b y to wynikać
z przedstawionego tutaj streszczenia. Czytelników zainteresowanych szczegółami ustaleń komisji
Rogersa odsyłamy do jej raportu [Rogers i in., 1986] oraz do książek poświęconych katastrofie, między
innymi do książki D. Yaughana [Yaughan, 1996].
14.2. O zarządzaniu projektem ogólnie 639
Ostatecznie więc, mimo iż bezpośrednią przyczyną katastrofy okazał się błąd projektowy złącza rakiety
pomocniczej, to zdaniem komisji Rogersa miało na nią wpływ także wadliwe funkcjonowanie struk-
tury komunikacyjnej w Thiokol i NASA, prowadzące do nieprawidłowej oceny ryzyka i w efekcie
do startu niesprawnego wahadłowca.
• Praca — t o d z i a ł a n i e p r o w a d z ą c e d o u z y s k a n i a w y n i k u . P r a c a p o d z i e l o n a jest n a
jednostki pracy (work units), którymi są zadania (tasks) i aktywności (activities).
Z a d a n i e m jest n a j m n i e j s z a j e d n o s t k a p r a c y p o d l e g a j ą c a z a r z ą d z a n i u j a k o całość.
Zadania i aktywności m o g ą być rekursywnie g r u p o w a n e z aktywności wyższych
r z ę d ó w . P r a c a o p i s y w a n a jest w p o s t a c i p a k i e t ó w p r a c y (work packages).
Faza koncepcyjna. W trakcie tej fazy rodzi się idea projektu. W przypadku projektu
programistycznego idea ta jest zwykle konsekwencją nowych wymagań dyktowanych przez re-
alia rynkowe lub nowe technologie. Aktywności fazy koncepcyjnej mogą mieć rozmaitą postać:
dla małych projektów może to być nieformalna dyskusja zainteresowanych osób, uwieńczona
werbalnym porozumieniem.
W przypadku dużych projektów ich idea staje się przedmiotem wszechstronnej analizy,
przede wszystkim porównania kosztów ze spodziewanymi zyskami oraz technicznego stu-
dium opłacalności. Szeroko rozumiane pojęcie „zysku" może oznaczać zmniejszenie kosztów
operacyjnych, uzyskanie takiego samego zysku przy mniejszym obrocie, podniesienie morale
pracowników, zwiększenie ich produktywności i zmniejszenie absencji.
Podstawowym problemem technicznej analizy opłacalności jest pytanie, czy wymagane
innowacje staną się dostępne w trakcie realizacji projektu. Przejście do następnej fazy projektu
wymaga formalnej decyzji, poprzedzonej formalnym przeglądem wyników wspomnianych
analiz.
Faza definicyjna. W tę fazę zaangażowani są menedżer projektu, klient oraz architekt
systemu. Menedżer projektu może być jedną z zainteresowanych osób uczestniczących w fazie
koncepcyjnej lub (co jest częstsze) wywodzić się spoza tego grona. Faza definicyjna projektu
obejmuje następujące aktywności:
Faza startowa. W tej fazie menedżer projektu buduje jego infrastrukturę, zatrudnia uczest-
ników, organizuje ich w zespoły i uruchamia realizację projektu. Faza ta wiąże się z następują-
cymi aktywnościami:
• Definiowanie zakresu projektu. Gdy tylko model analityczny stanie się stabilny,
klient i menedżer projektu formalnie porozumiewają się w kwestii funkcyjnych i po-
zafunkcyjnych wymagań dla systemu, co może powodować aktualizację dokumentu
umowy projektu.
3
Zależnie od rozmiaru i złożoności projektu w skład jego infrastruktury mogą wchodzić także sys-
temy wspomagające zarządzanie finansami i kadrą uczestników. Nie będziemy się nimi zajmować
w tej książce.
644 Rozdział 14. ® Zarządzanie projektem
Faza końcowa. W tej fazie klient otrzymuje produkty finalne, kolekcjonowana jest także
historia projektu. Większość zaangażowania programistów w projekt kończy się tuż przed
rozpoczęciem tej fazy, gdy doprowadzą modele oraz kod źródłowy do ostatecznej postaci
i skompletują dokumentację. Grupa programistów, dokumentaliści i kierownicy zespołów
zaangażowani zostają w zainstalowanie systemu u klienta i przygotowanie tego systemu do
testów akceptacyjnych. Dokumentaliści kolekcjonują historię projektu na użytek przyszłych
projektów. Z fazą końcową projektu wiążą się następujące aktywności:
Wynika
N a z w a zadania Opis Wejście Wyjście
z roli
Zbieranie Projektant Zbieranie od Łącznicy. API podsystemu,
wvmaaafi dla systemu. poszczególnych model analityczny
podsystemu zespołów wymagań obiektów
zarządzania
dotyczących trwałych.
bazą danych
przechowywania
obiektów,
identyfikowanie
obiektów trwałych.
pracy to opisy tworzenia modeli obiektowych, diagramów klas oraz sekcji dokumentów lub
kompletnych dokumentów — i tak każda sekcja dokumentu analizy wymagań może odpowia-
dać pakietowi pracy określającemu jej autora i czas sporządzania.
Produkt przeznaczony dla użytkownika nazywany jest produktem finalnym (deliverable);
przykładami produktów finalnych są sam system będący wynikiem projektu i jego doku-
mentacja. Wszystkie inne produkty, tworzone na użytek innych uczestników projektu, nazy-
wamy produktami wewnętrznymi (internal work products). Elementy działania są przykładem
produktów wewnętrznych.
Rysunek 14.5. Struktura podziału pracy jako agregacja wszystkich prac składających się na realizację
projektu
14.3. Koncepcje zarządzania projektem 649
Ograniczenie Znaczenie
ASAP Możliwie najwcześniej (As soon as possible)
ALAP Możliwie najpóźniej (As late as possible)
FNET Zakończyć nie wcześniej niż (Finish no earlier than)
SNET Rozpocząć nie wcześniej niż (Start no earlier than)
FNLT Zakończyć nie później niż (Finish no later than)
SNLT Rozpocząć nie później niż (Start no later than)
MFO Wymagany moment zakończenia (Must finish on)
MSO Wymagany moment rozpoczęcia (Must start on)
Tabela 14.3. Przykładowa macierz kwalifikacji dla czterech zadań i czterech uczestników
• — przydatność pierwszorzędna O — przydatność drugorzędna — zainteresowanie
Rysunek 14.8. Model projektu z punktu widzenia jego menedżera; stanowi wzbogacenie modelu
opisywanego w rozdziale 3. o trzykrotne zastosowanie wzorca Kompozyt do generalizacji klas Produkt,
Zadanie i Uczestni k
652 Rozdział 12. • Zarządzanie racjonalizacją
1. Streszczenie
1.1. Podsumowanie projektu
1.2. Ewolucja planu
2. Odwołania
3. Definicje
4. Organizacja projektu
4.1. Interfejsy zewnętrzne
4.2. Struktura wewnętrzna
4.3. Role i zakresy odpowiedzialności
5. Plan procesu zarządzania
5.1. Plan rozpoczęcia
5.2. Plan pracy
5.3. Plan kontroli
5.4. Plan zarządzania ryzykiem
5.5. Plan zamknięcia
6. Plan procesów technicznych
6.1. Model procesu
6.2. Metody, narzędzia i techniki
6.3. Plan infrastruktury
6.4. Plan akceptacji produktów
7. Plan procesów wspomagających
7.1. Plan zarządzania konfiguracją
7.2. Plan weryfikacji i walidacji
7.3. Plan dokumentacji
7.4. Plan zapewnienia jakości
7.5. Przeglądy i audyty
7.6. Plan rozwiązywania problemów
7.7. Plan zarządzania podwykonawcami
7.8. Plan usprawnienia procesu
8. Dodatkowe plany
4
Model kaskadowy opisujemy w sekcji 15.4.1 — przyp. tłum.
14.4. Aktywności klasycznego zarządzania projektem 653
projektu. Zalecamy bowiem nadanie tym dokumentom statusu linii bazowej dopiero po za-
historię zmian: każda zmiana odnotowana zostaje w postaci krótkiego opisu, autora i daty. Do-
kument SPMP powinien być aktualizowany po podjęciu każdej decyzji mogącej wpływać na
wynik projektu, a także po wystąpieniu istotnych problemów. W dużych projektach aktual-
ność SPMP dedykowana jest wybranej osobie pełniącej rolę planisty. W przypadku projektów
nowiącej bazę dla planowania projektu wersji objętej zarządzaniem konfiguracją po podpisa
fikowanie produktów, zadań i ról. Kierownicy zespołów dołączają do projektu pod koniec fazy
654 Rozdział 12. • Zarządzanie racjonalizacją
W tej sekcji skupimy się na projektach typu klasycznego, w których charakter produktów
finalnych jest względnie dobrze zdefiniowany już na początku projektu, a celem projektu jest
ich dostarczenie w ustalonym terminie i za cenę kosztów określonych w budżecie. W sekcji
14.5 powrócimy do opisywanych tu aktywności, by przedstawić ich obraz w przypadku „zwin-
nego" projektu, którego zakres oraz wymagania dotyczące produktów finalnych definiowane są
sukcesywnie w miarę postępu w realizacji projektu, same zaś produkty dostarczane są w sposób
przyrostowy.
Rysunek 14.9. Produkty generowane w wyniku planowania projektu i ich powiązania z typowymi
produktami finalnymi
Deklaracja problemu nie jest w żadnym razie precyzyjną ani kompletną specyfikacją sys-
temu, a raczej wysokopoziomowym podsumowaniem dwóch przyszłych dokumentów
— RAD i SPMP.
Menedżer projektu i klient opracowują deklarację problemu w sposób iteracyjny, w drodze
zarówno negocjowania, jak i zbierania informacji, i w konsekwencji wzajemnego poznawania
oczekiwań oraz ograniczeń. Poza wysokopoziomowym opisem funkcjonalności tworzonego
sytemu, deklaracja problemu może także zawierać przykłady konkretnych sytuacji, rozwiązań
i tym podobnych, co dodatkowo pomaga w upewnieniu się, że obie strony mają taką samą wi-
zję przedmiotowego problemu. Aktualna i przyszła sytuacja w kontekście tego problemu mogą
być ilustrowane konkretnymi scenariuszami (patrz rozdział 4. „Zbieranie wymagań").
Struktura typowej deklaracji problemu nie jest zbyt rozbudowana. Zauważmy przy tym,
że sekcje druga, trzecia i czwarta nie zawierają precyzyjnej specyfikacji systemu, a stanowią
jedynie podstawę do zbierania wymagań.
DEKLARACJA PROBLEMU
1. Dziedzina aplikacyjna
2. Scenariusze
3. Wymagania funkcyjne
4. Wymagania pozafunkcyjne
5. Środowisko docelowe
6. Produkty finalne i terminy
Istnieją różne podejścia do opracowywania struktury podziału pracy (WBS) dla danego
projektu. Najczęściej stosowana jest dekompozycja funkcjonalna bazująca na elementach
funkcjonalnych systemu. Przykładowa struktura WBS przedstawiona w tabeli 14.4 oparta jest
na jednostkach pracy dedykowanych poszczególnym aspektom funkcjonalnym bankomatu-
-wpłatomatu.
Tabela 14.4. Przykładowa struktura podziału pracy dla prostego oprogramowania bankomatu-wpłatomatu
Rysunek 14.10. Przykład obiektowo zorientowanego podziału pracy na trzy główne zadania dla
systemu dekomponowanego na trzy podsystemy
Jeszcze inne podejście do podziału pracy typowe jest dla projektu realizowanego przez
rozproszone grupy uczestników i bazuje na ich lokalizacjach geograficznych — dla każdej
z grup opracowywane są odrębne zadania. Pokrewnym podejściem jest podział pracy między
grupy wynikające ze struktury organizacyjnej firmy — dział marketingu, dział operacyjny, dział
sprzedaży — lub wręcz między poszczególnych programistów.
Niezależnie jednak od konkretnego podejścia, ostatecznym celem podziału pracy jest jej
dekompozycja na proste, wykonalne zadania, dla których można łatwo szacować czas trwania
i które można przyporządkowywać poszczególnym programistom 5 .
Dla menedżera dokonującego podziału pracy mogą być pomocne następujące heurystyki.
5
Z pracą programisty wiąże się ponadto wiele innych czynności, które muszą oni wykonywać i których
raczej nie uwzględnia się w strukturze WBS — przychodzenie do pracy, jedzenie i tym podobne —
i których statusu nie musi on zwykle raportować kierownikowi zespołu lub menedżerowi projektu.
Istnieją jednak menedżerowie próbujący ujmować tego typu czynności w formę oficjalnych zadań
— nazywamy ich powszechnie „mikromenedżerami".
14.4. Aktywności klasycznego zarządzania projektem 659
• Wyszukuj przypadki nakładania się pracy. Dane zadanie nie powinno wchodzić
w skład więcej niż jednej aktywności. Jeżeli przykładowo testowanie podsystemów
wykonywane jest przez oddzielny zespół testerów, menedżer projektu nie powinien
pozwalać na to, by wykonywali je także programiści.
Aktywności startowe projektu, z jednej strony, mają krytyczne znaczenie dla jego jedno-
stek organizacyjnych, z drugiej, odbywają się pod silną presją czasu. Podstawowym problemem
może okazać się wówczas ta okoliczność, że poszczególni uczestnicy nie znają się dobrze i nie
mają jeszcze rozeznania w zakresie osobowości i stylów pracy kolegów. Zrozumienie rozmaito-
ści zakresów odpowiedzialności w ramach projektu to kolejne zagadnienie, którym powinien
zająć się menedżer.
Gdy tylko utworzona zostanie początkowa struktura WBS i modele zadań, menedżer
projektu ma już rozeznanie pod względem kwalifikacji niezbędnych do wykonania poszczegól-
nych zadań: do zbierania wymagań konieczna jest znajomość dziedziny aplikacyjnej, zadania
związane z dyskusjami wymagają umiejętności z zakresu komunikacji interpersonalnej, a te-
stowanie nie może się odbywać w oderwaniu od myślenia kategoriami jakościowymi, ukie-
runkowanego na szczegóły. Ogólnie rzecz biorąc, realizacja projektów programistycznych
wymaga szeregu rozmaitych umiejętności, między innymi:
Formowanie zespołów
6
Amerykanie nazywają to zjawisko „syndromem zbyt wielu kapeluszy" („too many hats" syndrome),
idiomatycznie u t o ż s a m i a j ą b o w i e m (noszony) kapelusz z rolą p e ł n i o n ą przez jego właściciela
— przyp. tłum.
664 Rozdział 12. • Zarządzanie racjonalizacją
Zebranie otwierające
7
Zwanej też popularnie c z a r t e r e m p r o j e k t u (project charter) — przyp. tłum.
i • listę dokumentów dost9.rcz3.nych klientowi,
być informacja o statusie poszczególnych jego komponentów i wpływie ich stanu na stan
zane drobne problemy, które nie mają większego wpływu na harmonogram, po skumulowaniu
Metryki
Nie sposób efektywnie zarządzać ewolucją produktu bez obiektywnych mierników jego
stanu. Chociaż zebrania i inspekcje pomagają w jakościowej ocenie statusu projektu, opierają
się na przesłankach subiektywnych, czyli percepcji wybranych uczestników i ich chęci do
dzielenia się wiedzą: w efekcie nadmierny optymizm pojedynczego uczestnika może stworzyć
wrażenie, że projekt jest bardziej zaawansowany, niż ma to miejsce w rzeczywistości.
Jedną z grup mierników ilościowych są metryki programistyczne procesu lub systemu.
Instrumentacja mająca na celu automatyzację zbierania tych metryk sprzyja ich obiektywi-
zmowi. Zaproponowano wiele rodzajów takich metryk, opartych między innymi na liczbie
wierszy kodu źródłowego, punktów rozgałęzień i rozwidleń (o czym pisze T. McCabe
[McCabe, 1976]), liczbie zmiennych i operatorów (opisanych w pracy M. H. Halsteada
[Halstead, 1977]) i liczbie wymagań funkcyjnych, o czym piszą A. J. Albrecht i J. E. Gaffney Jr.
[Albrecht i Gaffney, 1983].
Metryki programistyczne sprawdzają się średnio jako narzędzie menedżerskie z tej
prostej przyczyny, że wiele produktów wytwarzanych w ramach projektu nie wiąże się z pro-
gramowaniem sensu stricte, zatem uzyskiwane metryki czysto programistyczne wymagają
odpowiedniej interpretacji przez menedżera. Przykładowo gwałtownie eksplodująca liczba
wierszy kodu źródłowego może, co prawda, świadczyć o postępie w implementowaniu
podsystemu, ale równie dobrze może być wynikiem sztucznego duplikowania kodu zamiast
jego strukturalizacji8. W przypadku jednak podejścia iteratywnego lub podejścia ze scentrali-
8
Pamiętajmy, że znakomita większość języków programowania stwarza szeroką dowolność w zakresie
podziału kodu między wiersze — jedynym bodaj wyjątkiem w tym względzie są języki asemblerowe —
łatwo zatem sztucznie proliferować licznik wierszy kodu, nie wnosząc doń żadnych nowych elementów.
Bardziej obiektywnym miernikiem mógłby być licznik instrukcji w kodzie źródłowym — mógłby, gdyby
nie możliwość zapisywania złożonych obliczeń zarówno w formie złożonych wyrażeń ewaluowanych
w ramach jednej instrukcji, jak i w formie pojedynczych instrukcji ograniczających się do wartościowania
pojedynczych operatorów. Obie metryki — liczba wierszy i liczba instrukcji — mają zatem sens jedynie
w przypadku rozsądnego i spójnego w dłuższej perspektywie stylu kodowania — przyp. tłum.
14.4. Aktywności klasycznego zarządzania projektem 667
z o w a n ą a r c h i t e k t u r ą k o m p o n e n t y p r o g r a m o w e są ł a t w i e j w e r y f i k o w a l n e i m i e r z a l n e . C o
więcej, m e t r y k i m o g ą w ó w c z a s m i e r z y ć a t r y b u t y p r o c e s u , t a k i e j a k o d s t ę p s t w a o d h a r m o -
n o g r a m u , zużycie z a s o b ó w czy liczba u c z e s t n i k ó w r e z y g n u j ą c a z u d z i a ł u w p r o j e k c i e p r z e d
jego zakończeniem.
Rysunek 14.11. Oszacowanie kondycji finansowej projektu przy użyciu wartości wypracowanej. Koszt
rzeczywisty jest mniejszy niż wartość wypracowana, co oznacza faktyczne oszczędności; wartość wypra-
cowana jest jednak mniejsza od planowanej na daną chwilę, zatem realizacja projektu jest opóźniona
Rozdział 14. • Zarządzanie projektem
czenia) czas ten powinien być coraz dłuższy, co świadczyłoby o zwiększającej się
14.4. Aktywności klasycznego zarządzania projektem 669
Zarządzanie ryzykiem
Istotą zarządzania ryzykiem jest identyfikacja możliwych problemów i próba ich unik-
nięcia, zanim staną się zagrożeniem dla budżetu czy harmonogramu. Kluczowym elementem
zarządzania ryzykiem jest zapewnienie odpowiedniego przepływu informacji, tak by ryzyko
i problemy były raportowane dokładnie i na bieżąco. Wiele projektów załamuje się dlatego, że
nawet proste problemy zgłaszane są zbyt późno, bądź dlatego, że podejmuje się próbę rozwią-
zywania niewłaściwego problemu. W tej sekcji skupimy się na aktywnościach związanych
z identyfikowaniem możliwych konsekwencji ryzyka, analizowaniem ich i reagowaniem na
nie. Czytelnikom zainteresowanym szczegółami zarządzania ryzykiem w kontekście inżynierii
oprogramowania polecamy specjalistyczną literaturę o tej tematyce, między innymi publikację
B. Boehma [Boehm, 1991] i książkę R. N. Charetta [Charette, 1989].
Pierwszym krokiem w zarządzaniu ryzykiem jest jego identyfikacja: ryzyko potencjal-
nych problemów wynika z obszarów niepewności w projekcie. Niepewność ta może mieć cha-
rakter menedżerski lub techniczny: w pierwszym przypadku odnosi się między innymi do
organizacji, produktów, ról czy planu zadań, w drugim do modeli systemu, jego funkcjonalno-
ści, architektury i implementacji. Szczególnie groźnym ryzykiem o charakterze technicznym są
błędy wykrywane w późnych stadiach realizacji projektu. W tabeli 14.5 przedstawiliśmy przy-
kłady ryzyka związane z projektem OWL, opisywanym między innymi w sekcji 3.4.1.
Ryzyko Typ
Wybrane middleware będzie zbyt wolne dla sprostania wymogom efektywności Techniczne
rejestrowania danych.
Opracowywanie podsystemów zajmie więcej czasu niż zaplanowano. Menedżerskie
zadaje następne pytania, mające na celu wykluczenie pokrewnych elementów ryzyka. Racjona-
lizacją takiego kwestionariusza jest eksploracja wszystkich obszarów projektu, w których kryć
się może potencjalne ryzyko.
1. Wymagania
d) wydajność
Lista zidentyfikowanych elementów ryzyka może być dość pokaźna, choć poszczególne
jej pozycje mogą mieć zróżnicowane znaczenie — od błahych, pomijalnych lub wręcz nie-
prawdopodobnych do krytycznych dla projektu; na tych ostatnich powinien się w pierwszym
rzędzie skupiać menedżer projektu, co wymaga opracowania systemu ich priorytetyzacji.
Bazując na dwóch najważniejszych atrybutach czynników ryzyka — prawdopodobieństwie
zaistnienia i potencjalnym wpływie na realizację projektu — czynniki te podzielić możemy
na cztery następujące kategorie:
programiści mogą minimalizować związane z nimi ryzyko, zmieniając ich dostawcę na bardziej
wiarygodnego bądź też — redundantnie — korzystać z oferty kilku dostawców9. W większości
przypadków jednak minimalizowanie ryzyka wiąże się z dodatkowymi kosztami i dodatko-
wym zapotrzebowaniem na zasoby. W tabeli 14.7 mogą czytelnicy zobaczyć, jak można mini-
malizować czynniki ryzyka wymienione w tabeli 14.5.
Gdy opracowane zostaną już plany minimalizowania ryzyka, należy przekazać je wszyst-
kim zainteresowanym, przy użyciu tych samych kanałów, którymi komunikowane są doku-
menty techniczne; dzięki temu uczestnicy mogą skojarzyć dokumentację techniczną z to-
warzyszącymi im czynnikami ryzyka. Skuteczność zarządzania ryzykiem uwarunkowana jest
terminową komunikacją, należy więc zachęcać programistów do bieżącego raportowania
potencjalnych problemów. Wielokrotnie przecież pisaliśmy o tym, że podstawową barierą
w zmaganiach z niepewnością jest nieefektywna komunikacja.
9
Wiarygodni dostawcy, świadomi myślenia programistów kategoriami ryzyka, umożliwiają darmowe
testowanie swych produktów w konkretnym zastosowaniu, aż do (spodziewanego) komercyjnego
usankcjonowania tego zastosowania, które — oczywiście — wymaga zakupu licencji — p r z y p . tłum.
672 Rozdział 12. • Zarządzanie racjonalizacją
Akceptacja systemu
Instalowanie systemu
klientowi, są również wnioski i lekcje, jakie wynoszą z tego projektu jego uczestnicy, ku (inten-
cjonalnemu) pożytkowi w przyszłych projektach. Wiele firm programistycznych ujmuje tę
oczywistą skądinąd prawdę w formalne ramy swoistej analizy, zwanej popularnie analizą post
W tej sekcji opiszemy krótko istotę „zwinnej" technologii Serum (omówionej o pracy
K. Schwabera i M. Beedlea [Schwaber i Beedle, 2002]) jako kontrast do metodologii opisywa-
nych w poprzednich sekcjach. Zauważmy przy tym, że wiele aktywności opisywanych w po-
przednich sekcjach, związanych między innymi z zarządzaniem kwalifikacjami, zarządzaniem
ryzykiem i instalowaniem systemu, zachowuje swą aktualność także na gruncie metodologii
Serum.
10
Angielskie Serum oznacza dosłownie „młyn" i zaczerpnięte jest z terminologii rugby — patrz na przy-
kład http://pl.wikipedia.org/wiki/Scrum — przyp. tłum.
676
przebiegu. Aby można było kontrolować postęp przebiegu i oceniać pojawiające się w nim
14.6. Literatura uzupełniająca 677
14.7. Ćwiczenia
14.1. Na rysunku 14.1 przedstawiliśmy diagram stanów reprezentujący poszczególne
fazy projektu. Wykorzystaj wzorzec projektowy Stan do przedstawienia każdej z tych
faz w postaci odrębnej klasy. Zastosuj opisywane w tym rozdziale aktywności za-
rządzania projektami do upublicznienia operacji tych klas. Zakładamy zespołową
organizację projektu.
14.2. Jakie są zalety obsady płaskiej w porównaniu z obsadą stopniowaną?
14.3. Jaka jest różnica między raportowaniem statusu a podejmowaniem decyzji na ze-
braniach?
14.4. Dlaczego role architekta oprogramowania i kierownika zespołu powinny być pełnione
przez różne osoby?
14.5. Narysuj model UML organizacji zespołowej projektu ARENA dla każdej z głównych
faz (koncepcyjnej, definicyjnej, startowej, ustalonej i końcowej).
14.6. Narysuj model zadań związanych z projektowaniem systemu MyTrip opisywanego
w rozdziale 6. „Projektowanie systemu — dekompozycja na podsystemy".
14.7. Oszacuj czas potrzebny do wykonania każdego z zadań modelu, o którym mowa
w ćwiczeniu 14.6. Zidentyfikuj ścieżkę krytyczną tego modelu.
14.8. Zidentyfikuj i określ priorytety pięciu najważniejszych czynników ryzyka związanych
z projektowaniem systemu MyTri p oraz zaplanuj sposoby ich minimalizowania.
14.9. Zidentyfikuj i określ priorytety pięciu najważniejszych czynników ryzyka zwią-
zanych z projektowaniem interfejsu użytkownika systemu CTC opisywanego w roz-
dziale 12. „Zarządzanie racjonalizacją". Zaplanuj sposoby minimalizowania tego
ryzyka.
14.10. System operacyjny Linux, stanowiący spektakularny owoc zastosowania modelu ba-
zarowego, jest bardziej niezawodny i bardziej reaktywny niż wiele innych systemów
operacyjnych przeznaczonych dla procesorów firmy Intel. Zaproponuj argumenty na
rzecz zastosowania modelu bazarowego do opracowania systemu sterującego
komputerami promu kosmicznego oraz przeciwko takiemu rozwiązaniu.
14.11. Uczestnicy projektu podzieleni zostali na zespoły czteroosobowe. Każdy zespół ma
do dyspozycji następujące zasoby: 2 jajka, 1 szpulkę taśmy samoprzylepnej, 1 rolkę
papieru toaletowego, filiżankę wody, wiadro z dwoma litrami piasku, 20 piłeczek
piankowych o średnicy ok. 1 cm każda i tablicę, której powierzchnia ma się znajdować
ok. 1 metra nad podłogą. Każdy zespół ma 25 minut na zbudowanie i przetestowanie
680 Rozdział 12. • Zarządzanie racjonalizacją
14.13. Z a s t o s u j p o s z c z e g ó l n e m o d e l e z a r z ą d z a n i a dla p r o j e k t u b ę d ą c e g o p r z e d m i o t e m
ćwiczenia 14.11.
14.14. S k o n s t r u u j S P M P dla p r o j e k t u b ę d ą c e g o p r z e d m i o t e m ćwiczenia 14.11.
Bibliografia
[Albrecht i Gafifhey, 1983] A. J. Albrecht, J. E. Gaffney, jr. Software function, source lines of code, and
development effort prediction: A software science validation, „IEEE Transactions
on Software Engineering", t. SE-9, nr 6, listopad 1983.
[Boehm, 1991] B. Boehm Software risk management: Principles and practices, „IEEE Software",
t.l, str. 3 2 - 4 1 , 1991.
[Boehm i in., 2000] B. Boehm, E. Horowitz, R. Madachy, D. Reifer, B. K. Clark, B. Steece, A.
W. Brown, S. Chulani, C. Abts Software Cost Estimation with COCOMO
II, Prentice Hall, Upper Saddle River, NJ, 2000.
[Brooks, 1995] F. P. Brooks The Mythical Man Month, Anniversary Edition: Essays
on Software Engineering, Addison-Wesley, Reading, MA, 1995.
[Carr i in., 1993] M. J. Carr, S. L. Konda, I. Monarch, F. C. Ulrich, C. F. Walker Taxonomy-
Based Risk Identification, Technical Report CMU/SEI-93-TR-6, Software
Engineering Institute, Carnegie Mellon University, Pittsburgh, PA, 1993.
[Charette, 1989] R. N. Charette Software Engineering Risk Analysis and Management,
McGraw-Hill, New York, 1989.
[Cohn, 2006] M. Cohn Agile Estimating and Planning, Pearson, Upper Saddle River, NJ, 2006.
[Elssamadisy, 2009] A. Elssamadisy Agile Adoption Patterns, Addison-Wesley, Reading, MA, 2009.
[Grenning, 2002] J. Grenning, Planning Poker, http://wwwplanningpoker.com/2002.
[Halstead, 1977] M. H. Halstead Elements of Software Science, Elsevier, New York, 1977.
[IEEEStd. 1058-1998] IEEE Standard for Software Project Management Plans, IEEE Computer
Society, New York, 1998.
[Katzenbach i Smith, J. R. Katzenbach, D. K. Smith The Wisdom of Teams: Creating
1994] The High-Performance Organization, Harper Business, 1994.
[Kayser, 1990] T. A. Kayser Mining Group Gold, Serif, El Segundo, CA, 1990.
[McCabe, 1976] T. McCabe A software complexity measure, „IEEE Transactions on Software
Engineering", t. 2, nr 12, grudzień 1976.
Bibliografia 681
Bibliografia 710
Cykl życiowy
oprogramowania
W pobliżu lądu zmienia się kształt i odgłos fal morskich. Można wówczas wypatrywać specyficznych
gatunków ptactwa lądowego, które rankiem powinno kierować się w głąb morza (na rybki), by wie-
czorem powracać na wyspę. Wystarczy więc wieczorami podążać za lotem ptaków, zaś rano kierować
się w stronę punktu, z którego zaczynają swoją wyprawę. Dla odmiany, budowniczowie statków ery
Kolumba od tysięcy lat z powodzeniem wykorzystywali konstrukcje metalowe. Z lektury dzienników
Kolumba można wywnioskować, że nie posługiwał się nawigacją gwiezdną, praktykując w zamian
nawigację zliczeniową 1 : w utrzymywaniu kursu pomagał sternikowi kompas magnetyczny, ponadto
co godzinę dokonywany był pomiar prędkości statku, polegający na wyrzuceniu za burtę jakiegoś
1
Ang. dead reckoning, dosł. „tępe zliczanie", to przybliżone ustalanie bieżącej pozycji na podstawie
znajomości pozycji poprzedniej, szacowanej prędkości oraz określonego kierunku. Wraz z upo-
wszechnieniem łączności radiowej usunięte zostały w cień metody nawigacji zliczeniowej opartej na
kompasie, ale nieoczekiwanie narodziły się w nowym wcieleniu — w postaci rozmaitych systemów żyro-
skopowych. Ze względu na przyrostowy charakter procesu, jakim jest nawigowanie zliczeniowe, występuje
tendencja do kumulowania błędów w ustalaniu kolejnych pozycji. W nawigacji zliczeniowej na morzu
dodatkowym źródłem błędu jest zaniedbywanie wpływu wiatru i prądów morskich na prędkość i kie-
runek poruszania się statku — przyp. tłum.
w efekcie nieznacznie, acz systematycznie ma południe; ponieważ jednocześnie prądy morskie znosiły
go na północ, nie zdawał sobie sprawy z ograniczeń kompasu magnetycznego.
l ą d u i w y l n a c z a n i i o r a z k o r y g o w a n i ! k u r s u ) . G d y b y t a k doszło d o s p o t k a n i a załogi K o l u m b a
kłemodde nawigacji.^ ^ ^
k t ó r y m n a s t ę p u j e jego e k s p l o a t o w a n i e . A k t y w n o ś c i p r o c e s u n i e m u s z ą u k ł a d a ć się w s t r u k -
t u r ę ściśle s e k w e n c y j n ą , czego p r z y k ł a d w i d z i m y n a r y s u n k u 15.3: t w o r z e n i e s y s t e m u i b u d o -
Rysunek 15.3. Inny przykład zależności czasowych między aktywnościami cyklu życiowego
Tabela 15.1. Procesy inżynierii oprogramowania definiowane przez standard IEEE 1074
Postrealizacja Instalowanie
Eksploatacja i wsparcie dla użytkowników
Pielęgnowanie
Wycofanie z eksploatacji
Każdy proces złożony jest z aktywności. Aktywność to zadanie (lub grupa podaktywności)
przypisane uczestnikowi projektu lub zespołowi i realizowane, by osiągnąć pewien cel. Przykła-
dowo proces przetwarzania wymagań składa się z trzech aktywności. Oto one.
Rysunek 15.6. Model cyklu życiowego oprogramowania. Na cykl ten składają się grupy procesów,
każdy proces jest dążeniem do określonego celu (sformułowania wymagań, zaprojektowania syste-
mu, jego zainstalowania i tym podobnych). Proces składa się z aktywności, które z kolei podzielić
można na zadania lub podaktywności. Zadanie r e p r e z e n t u j e najmniejszą, niepodzielną część pracy
z perspektywy zarządzania nią. Każde zadanie zużywa zasoby i skutkuje wytworzeniem jednego lub
więcej produktów. Projekt jest instancją cyklu życiowego, traktowanego jako klasy
690 Rozdział 15. • Cykl życiowy oprogramowania
Spośród widocznych w tabeli 15.1 procesów definiowanych przez standard IEEE 1074,
z punktu widzenia programisty, sześć pierwszych — tych związanych z modelowaniem cyklu
życiowego, zarządzaniem projektem i prerealizacją — często już zainicjowano, zanim dołączy
on do projektu.
2
Ta kolumna tabeli (i następnych tabel w tym rozdziale) zawiera n u m e r odnośnego paragrafu
w dokumencie standardu IEEE 1074.
15.2. IEEE 1074: standard cykli życiowych 691
15.2.4. Prerealizacja
W ramach procesu prerealizacji menedżer (lub marketingowcy) i klient identyfikują ideę pro-
jektu lub przesłanki zapotrzebowania na jego realizację. Realizacja ta może mieć postać inży-
nierii pierwotnej, czyli tworzenia systemu od zera (patrz sekcja 4.3.5), albo inżynierii wtórnej,
czyli unowocześniania (zastępowania) istniejącego systemu lub też jedynie zmiany jego inter-
fejsu. Proces alokacji systemu prowadzi do ustalenia jego początkowej architektury oraz iden-
tyfikacji wymagań związanych ze sprzętem, oprogramowaniem i operacjami. Zauważmy, że
dekompozycja systemu stanowi podbudowę infrastruktury komunikowania się uczestników
projektu. Wymagania, dekompozycja systemu i infrastruktura systemu opisane są w deklara-
cji problemu 3 , która stanowi materiał wejściowy dla procesu tworzenia systemu. Proces pre-
realizacji przedstawiony jest w tabeli 15.3.
3
Deklaracja potrzeby (Statement of Need) wymieniona w standardzie IEEE 1074 podobna jest do
deklaracji problemu, nie zawiera jednak żadnych odniesień do organizacji projektu.
692 Rozdział 15. • Cykl życiowy oprogramowania
gólnych podsystemów. Efektem procesu projektowania jest projekt obiektów, ich atrybutów
i operacji oraz zorganizowanie ich w pakiety; po zakończeniu tego procesu zdefiniowane są
wszystkie metody i ich sygnatury, a także dodane nowe klasy wynikające z wymagań poza-
funkcyjnych i szczegółów poszczególnych komponentów. W tej książce proces projekto-
wania przewija się przez treść rozdziałów 6. „Projektowanie systemu — dekompozycja na
podsystemy", 8. „Projektowanie obiektów: wielokrotne wykorzystywanie rozwiązań wzor-
cowych" i 9. „Projektowanie obiektów: specyfikowanie interfejsów".
Proces implementacji to przetwarzanie modelu projektu systemu na jego wykonywalny
odpowiednik. Elementami tego procesu są aktywności planowania i przeprowadzania inte-
gracji systemu. Zwróćmy uwagę, że testy przeprowadzane w ramach tego procesu są niezależne
od tych, które wchodzą w skład weryfikowania i walidacji. W rozdziale 11. „Testowanie" opi-
saliśmy testowe i integracyjne aspekty implementowania systemu.
15.2.6. Postrealizacja
Proces postrealizacji obejmuje aktywności instalowania, pielęgnowania, eksploatowania, wsparcia
technicznego systemu i (ewentualnego) wycofywania z eksploatacji jego poprzednika (patrz
tabela 15.5).
w wyniku zastąpienia go nową wersją; wiąże się także z zakończeniem obsługi dotychczasowej
wersji. Aby przejście na nową wersję systemu odbyło się bez większych perturbacji, przez pewien
czas eksploatowane są równolegle obie wersje, zanim użytkownicy nie „przesiądą" się w pełni
na nową. W tej książce opis procesów grupy postrealizacji ograniczamy do dostarczenia systemu
klientowi i wykonania przez niego testów akceptacyjnych.
Poziom 1: Początkowa (Initial). Poziom ten oznacza konglomerat działań ad hoc, których
zdefiniowanie w formie aktywności jest raczej ewenementem niż regułą. Powodzenie tych
zadań zależy przede wszystkim od heroicznego wysiłku i niezwykłych umiejętności uczestni-
ków. Z perspektywy klienta cykl życiowy oprogramowania, jeżeli w ogóle istnieje jako taki,
jest przysłowiową czarną skrzynką: po uzgodnieniu umowy projektu klient musi poczekać
do końca na możliwość oceny jakiegokolwiek produktu, bowiem w trakcie realizacji projektu
nie ma żadnej możliwości współuczestnictwa w jego zarządzaniu.
Tabela 15.7. Kluczowe obszary procesu charakteryzujące poszczególne poziomy dojrzałości organi-
zacyjnej
4
Patrz http://pl.wikipedia.org/wiki/Software_Engineering_Institute — przyp. tłum.
15.3. Charakteryzowanie dojrzałości modeli cyklu życiowego 697
Tabela 15.7. Kluczowe obszary procesu charakteryzujące poszczególne poziomy dojrzałości organi-
zacyjnej — ciąg dalszy
Rysunek 15.7. Powiązania między procesami standardu IEEE 1074. Jak łatwo spostrzec, zależności
między procesami i aktywnościami są dość skomplikowane, co praktycznie eliminuje możliwość
wykonywania tych procesów w sposób ściśle sekwencyjny
W kolejnej sekcji przyjrzymy się kilku wybranym modelom cyklu życiowego. Większość z nich
koncentruje się na procesach realizacyjnych.
15.4. Modele cyklu życiowego 699
Model kaskadowy
V-Model
Rysunek 15.9. V-model tworzenia oprogramowania. Poziome przepływy obiektów reprezentują ka-
nały przepływu informacji między aktywnościami na tym samym poziomie abstrakcji. Zachowali-
śmy tradycyjny kształt litery V oryginalnego diagramu, jednakże w języku UML taki czy inny kształt
diagramu nie ma żadnego znaczenia semantycznego
Jak nietrudno się zorientować, wyższe poziomy abstrakcji V-modelu związane są z wy-
maganiami, pod względem ich zbierania i realizowania podczas eksploatacji systemu. Środ-
kowe poziomy abstrakcji koncentrują się na odwzorowywaniu problemów w architekturę
oprogramowania, zaś poziomy najniższe dotyczą szczegółów w postaci tworzenia kompo-
15.4. Modele cyklu życiowego 701
nentów i łączenia ich ze sobą — i tak na przykład celem aktywności „Testowanie jednostkowe"
jest walidacja jednostek pod względem ich zgodności z opisem w projekcie szczegółowym, zaś
aktywność „Integrowanie i testowanie komponentów" ma za zadanie analogiczną walidację
komponentów funkcjonalnych projektu wstępnego (wysokopoziomowego).
Model kaskadowy i jego odmiany to pod wieloma względami uproszczona abstrakcja
procesu tworzenia oprogramowania. Podstawową słabością wszystkich tych modeli jest (nie
zawsze realne) założenie, że gdy dana aktywność zostanie zakończona, a jej produkty zweryfi-
kowane, można objąć je statusem linii bazowej i przejść do kolejnych aktywności. Z sytuacją
zbliżoną do tego ideału mamy jednak do czynienia tylko wówczas, gdy specyfikacja wymagań
jest bardzo wyraźna i stabilna, co w praktyce zdarza się dość rzadko; częściej jest tak, że reali-
zacja danej aktywności identyfikuje konieczność zmian w produktach będących owocem po-
przednich aktywności.
Model spiralny
5
Na rysunku pokazaliśmy szczegółowo tylko trzy pierwsze z wymienionych rund, pozostałe repre-
zentowane są jedynie w postaci bloków w zewnętrznej warstwie spirali.
702 Rozdział 15. • Cykl życiowy oprogramowania
Rysunek 15.10. Model spiralny Boehma (na podstawie książki B. Boehma [Boehm, 1987]). Odle-
głość od początku reprezentuje zakumulowany koszt projektu. Kąt z lewą półosią reprezentuje typ
aktywności — przykładowo w projekcie PI realizowana jest aktywność analizowania ryzyka związa-
nego z wymaganiami, natomiast projekt P2 znajduje się na etapie projektowania systemu
1. Określenie celów,
2. Zdefiniowanie ograniczeń,
3. Rozpatrzenie możliwości realizacyjnych,
4. Identyfikowanie ryzyka,
5. Minimalizowanie ryzyka,
6. Opracowanie i zweryfikowanie produktu dla następnego poziomu,
7. Planowanie.
lewej ćwiartce tego układu, kolejne natomiast, w kierunku ruchu wskazówek zegara, nakładają
się kolejnymi warstwami po spirali. Współrzędne biegunowe umożliwiają łatwe określenie
statusu projektu w dowolnym momencie jego realizacji: rosnąca odległość rundy od środka
spirali reprezentuje akumulujący się koszt projektu, zaś odległość kątowa od lewej półosi wska-
zuje stan zaawansowania każdej fazy.
6
Jednolity proces stosuje własne konwencje nazewnicze, nie wzorując się na standardzie IEEE. Prze-
pływy pracy mogą być utożsamiane ze specjalnymi aktywnościami rozciągającymi się na więcej niż jedną
iterację. Inżynieryjne przepływy pracy mogą być uważane za funkcje projektowe, ponieważ czas ich
trwania pokrywa się z czasem trwania iteracji, natomiast pomocnicze przepływy pracy stanowią od-
powiedniki procesów integralnych standardu IEEE 1074.
15.4. Modele cyklu życiowego 705
muje planistyczne aspekty systemu, opisywane w rozdziale 14., druga koncentruje się wokół
samego środowiska programistycznego i automatyzowania wykonywanych w jego ramach
czynności, jak również utrzymywania tego środowiska w aktualnym stanie, szczególnie w aspek-
cie infrastruktury komunikacyjnej i zarządzania konfiguracją. Trzecia wiąże się z ocenianiem
procesów i produktów, czyli z przeglądami, wędrówkami po kodzie i inspekcjami kodu. Przed-
miotem czwartej jest przekazywanie systemu docelowym użytkownikom.
Jednolity proces uwydatnia etapowość przydziału zasobów dla każdego przepływu pracy
w danej fazie lub iteracji, wiążąc w ten sposób bardzo ściśle problemy zarządzania projektem
z innymi problemami cyklu życiowego programowania (patrz rysunek 15.13). Dzieje się tak
dlatego, że każda iteracja traktowana jest jak osobno zarządzany projekt (patrz rozdział 14.).
Ponieważ czas trwania przepływu pracy jest tożsamy z czasem trwania projektu, mogą one być
uważane za funkcje projektowe, dedykowane zróżnicowanym potrzebom poszczególnych faz.
Przykładowo w fazie Elaboration największe zapotrzebowanie na zasoby przejawia przepływ
Requirement, jednakże w fazie Construction ciężar głównego zapotrzebowania na zasoby
przesuwa się na przepływy Design i Implementation.
Rysunek 15.13. Siedem przepływów pracy w ramach jednolitego procesu — Management, Environment,
Requirements, Design, Implementation, Assessment i Deployment — to funkcje projektowe trwające
przez cały czas życia systemu. Zapotrzebowanie na zasoby zmienia się dla poszczególnych przepływów
pracy wraz ze zmianą fazy i iteracji. Histogram dla każdego przepływu wskazuje ilość zasobów potrzebną
dla iteracji — im wyższy blok, tym więcej konsumowanych zasobów (wykres na podstawie prac I. Jacob-
sona, G. Boocha i J. Rumbaugha [Jacobson i in., 1999] oraz W. W. Royce'a [Royce, 1998])
Rysunek 15.14. Widok jednolitego procesu w ukierunkowaniu na encje. Zależności między encjami
— odzwierciedlające zależnościom między modelami — oznaczają identyfikowalność modeli. Dla
przejrzystości ograniczyliśmy się do powiązań modelu przypadków użycia z innymi modelami
Rysunek 15.15. Wycinek bazy zagadnień projektu. Zagadnienia i 1 i i 5 zostały rozstrzygnięte, podczas
gdy wszystkie inne zagadnienia pozostają otwarte. Zależności między zagadnieniami wskazują na fakt, że
rozstrzygnięcie wybrane dla jednego zagadnienia może wiązać się z ograniczeniami ewentualności roz-
wiązań dla innych zagadnień
708 Rozdział 15. • Cykl życiowy oprogramowania
Rysunek 15.16. Model kaskadowy jako przypadek szczególny modelu bazującego na zagadnieniach.
Wszystkie zagadnienia należące do tej samej kategorii zawarte są w tym samym pakiecie UML. Za-
gadnienia związane ze zbieraniem wymagań i ich analizą zostały już zamknięte, przez co aktywności
zbierania wymagań i ich analizowania można uznać za zakończone
Rysunek 15.17. W skomplikowanym stanie projektu wszystkie aktywności mogą być powiązane z otwartymi
zagadnieniami, co oznacza, że wszystkie powinny być realizowane równolegle
15.6. Ćwiczenia
15.1. Przedstaw aktywności z rysunku 15.2 i produkty z rysunku 15.4 na diagramie klas
UML, uwidoczniającym powiązanie między aktywnościami a produktami.
15.2. Załóżmy, że model kaskadowy przedstawiony na rysunku 15.8 został wyprowadzony
ze standardowego modelu widocznego na rysunku 15.7 w ramach aktywności mo-
delowania cyklu życiowego. Jakich procesów i aktywności brakuje w tym kontekście
w modelu kaskadowym.
15.3. Narysuj model spiralny Boehma, widoczny na rysunku 15.10 w postaci diagramu
aktywności UML. Porównaj czytelność tego diagramu z czytelnością oryginalnej spirali.
15.4. Narysuj diagram aktywności UML opisujący zależności między aktywnościami cyklu
życiowego, w którym przetwarzanie wymagań, projektowanie, implementowanie,
testowanie i pielęgnowanie systemu wykonywane są często (taki cykl życiowy okre-
ślany bywa mianem ewolucyjnego).
15.5. Wyjaśnij, w jaki sposób aktywności testowania mogą zostać poprawnie zainicjowane
przed rozpoczęciem aktywności implementacyjnych. Uzasadnij, dlaczego takie roz-
wiązanie jest pożądane.
15.6. W zarządzaniu projektem relacja między dwoma zadaniami jest zwykle inter-
pretowana jako relacja poprzedzania w czasie — jedno zadanie musi zostać zakoń-
czone, zanim będzie można rozpocząć drugie. W przypadku cyklu życiowego relacja
między dwiema aktywnościami jest zależnością między nimi — jedna aktywność
wykorzystuje produkty wytworzone przez drugą. Przedyskutuj tę różnicę i zilustruj ją
stosownym przykładem w kontekście V-modelu.
15.7. Wyobraź sobie, że jesteś członkiem komitetu IEEE rewidującego właśnie standard
IEEE 1074. Przydzielono Ci zadanie modelowania komunikacji jako jawnego procesu
integralnego. Przedstaw przykłady aktywności należących do tego procesu.
Bibliografia
B. Boehm A spiral model of software development and enhancement,
[Boehm, 1987]
„Software Engineering Project Management", str. 128 - 142, 1987.
Bibliografia 767
Wszystko razem,
czyli metodologie
Powinniśmy być ostrożni w poleganiu wyłącznie na wiedzy wyniesionej
z doświadczenia — i niczym więcej: inaczej będziemy jak ten kot, który
nieopatrznie usiadł na gorącym piecu: już nigdy więcej nie usiądzie
na gorącym piecu (i bardzo dobrze), ale na zimnym też już nie.
— Mark Twain Following the Equator: A Journey Around the World
Nieprzewidziany obóz na K2
30 lipca 1954 Walter Bonatti i tragarz wysokogórski Mahdi wyruszyli z obozu 8. z niezbędnym
ładunkiem tlenu, przeznaczonego dla Achille Compagnoniego i Lina Lacedelliego, przebywających
obozie 9. i wytypowanych przez kierownika wyprawy jako kandydatów do zdobycia szczytu w pierw-
szej kolejności. Gdy Bonatti i Mahdi dotarli do ustalonej lokalizacji w obozie 9., nie spotkali tam
nikogo; po długotrwałych poszukiwaniach Compagnoniego i Lacedelliego udało im się w końcu
nawiązać z nimi jedynie kontakt głosowy. Około 21:30 zmuszeni zostali do powrotu do obozu.
Nieprzewidziany nocleg w obozie na wysokości 8100 m był istnym horrorem: Bonatti i Mahdi
musieli przetrwać nocną śnieżycę, bez jakiejkolwiek ochrony przed wiatrem. To niewiarygodne, ale
Bonatti wyszedł z tej gehenny bez większych obrażeń; niestety, Mahdi doznał szeregu odmrożeń, któ-
re ostatecznie doprowadziły do konieczności amputowania kilku palców u rąk i nóg. Następnego
dnia Bonatti i Mahdi zostawili swój bagaż w obozie i powrócili do obozu 8. Compagnoni i Lacedelli
zostawili swój namiot, zabrali pozostawiony dla nich tlen i ruszyli ku szczytowi. Według oficjalnej
kroniki wspinaczki, tlen skończył im się 200 m poniżej szczytu, który zdobyli o 18:00; jednak
niektóre zdjęcia przedstawiają leżące u ich stóp plecaki z butlami tlenowymi.
Dyskusja
Fakt, że Bonatti wyszedł bez szwanku z koszmarnego biwakowania, stał się przyczynkiem wielu oskar-
żeń, między innymi tego, że wbrew decyzji kierownika postanowił samodzielnie zdobyć szczyt.
Compagnoni i Lacedelli twierdzili, że tlen skończył się im przedwcześnie dlatego, że Bonatti zużył
jego część na biwaku, by zyskać siły do samotnej eskapady na szczyt; to jednak nie było możliwe,
gdyż Bonatti nie miał przy sobie maski tlenowej. Szczegółowa analiza fotografii w roku 1993 wyka-
zała, że Compagnoni i Lacedelli mieli założone maski tlenowe przez cały czas swej wyprawy na szczyt,
o czym pisze R. Marshall [Marshall, 2001]. Dlaczego więc kłamali?
Zdaniem Marshalla, Compagnoni musiał być przerażony, gdy po dotarciu do obozu 8. dowiedział
się, co wydarzyło się ubiegłej nocy. Czuł się częściowo odpowiedzialny za nieplanowany nocleg
Bonattiego i Mahdiego, obawiał się też posądzenia o przyczynienie się do obrażeń odniesionych
przez Mahdiego.
Mahdi powiedział oficerowi łącznikowemu — a też zdał sprawę kierownikowi wyprawy — że Bonatti
zamierza samodzielnie wyprawić się na szczyt. Mahdi nie mógł dowiedzieć się tego bezpośrednio
od Bonattiego, nie mieliby się bowiem jak porozumieć: Bonatti znał tylko język włoski, a Mahdi
mówił jedynie w U r d u — skąd więc taka konkluzja?
Jej źródeł należy szukać jeszcze przed drugą wojną światową. Wszystkie próby zdobywania
ośmiotysięczników wspomagane były wówczas przez doświadczonych Szerpów z Nepalu; Szer-
pów zatrudniano nawet na wyprawach na K2 i Nanga Parbat, położonych w Karakorum. Po
1
Przedstawiona dyskusja pomija cały szereg fascynujących szczegółów pierwszej wyprawy na K2. Aby
w pełni docenić złożone współzależności między wyposażeniem, motywacjami, strukturą organizacyjną,
ukrytymi motywami, oczekiwaniami, doświadczeniem i różnymi punktami widzenia, należałoby prze-
czytać rozdziały dotyczące K2 w książce Bonattiego [Bonatti, 2001], którą polecamy naszym czytelnikom.
16.1. Wstęp: pierwsze zdobycie K2 715
wojnie zatrudnienie lokalnych tragarzy stało się wręcz warunkiem koniecznym do uzyskania
zezwolenia na wspinaczkę. Oczywistymi kandydatami na pomocników byli Hunzowie z pół-
nocnego Pakistanu; byli ludźmi generalnie obytymi z górami, lecz nie mieli wówczas doświad-
czenia w wyprawach na takie wysokości.
W 1953 roku Hunza Mahdi brał udział, jako młodszy pomocnik, w pierwszym podejściu na
Nanga Parbat. Wyprawa rozpoczęła się od tradycyjnej „poręczówki", a jej uczestnicy zorgani-
zowani byli w hierarchiczną strukturę; m i m o to, ostatecznego wejścia na szczyt dokonał samo-
dzielnie H e r m a n n Buhl, po 40-godzinnej, heroicznej wspinaczce, czyniąc to wbrew postano-
wieniu kierownika wyprawy [Buhl, 1956].
Mahdi, pamiętny tej historii, nabrał widocznie przekonania, że tylko tak można skutecznie zdo-
bywać ośmiotysięczniki i na tej podstawie przypuszczał, że Bonatti podejmie samodzielną wspi-
naczkę, zamiast dostarczyć tlen kolegom. (Fałszywe) zarzuty Mahdiego pod adresem Bonattiego
musiały wywołać wściekłość Compagnoniego, który, widząc jawne pogwałcenie zarządzeń kie-
rownika, zrzucił na Bonattiego całkowitą odpowiedzialność za obrażenia odniesione przez Mahdiego.
Aby dodatkowo uwolnić się od współodpowiedzialności za te obrażenia, Compagnoni i Lacedelli
wymyślili historyjkę z przedwczesnym wyczerpaniem tlenu.
Tabela 16.1. Przykłady celów, środowisk, metod i metodologii — w himalaizmie i inżynierii opro-
gramowania
Cele projektowe obejmują kryteria oceny sukcesów w projekcie. Dla jednego pro-
jektu może to być jedynie dostarczenie konkretnego systemu w ustalonym terminie, dla
innego — głębokie aspekty strategiczne, takie jak zapewnienie powtarzalności reguł bizne-
sowych czy obniżanie kosztów biznesu.
Na środowisko projektu składają się elementy obecne na jego początku. W przypadku
projektu programistycznego środowisko definiowane jest przez klienta i bieżący stan organizacji
projektu. Elementy środowiska są czynnikami ograniczającymi menedżera, należą do nich
16.2. Środowisko projektu 717
• lokalny klient samodzielny (local king client) ma pełną swobodę podejmowania decy-
zji, których nie musi z nikim konsultować, nie musi nikomu raportować problemów,
dobrze zna dziedzinę aplikacyjną i może kontaktować się z programistami oraz me-
nedżerem projektu w efektywny, często bezpośredni sposób,
718 Rozdział 16, ® Wszystko razem, czyli metodologie
Tabela 16.2. Zdolność decyzyjna i znajomość dziedziny aplikacyjnej dla różnych typów klienta
Planując wyprawę przy użyciu kanu, można zatrzymać się na chwilę i deliberować „popły-
nę jak najbardziej w lewo, spróbuję przepłynąć między tymi dwiema skałami, po czym zro-
bię szybki zwrot w prawo, by opłynąć tę kolejnąjednakże tego typu plany mogą okazać
się niewiele warte w konkretnej sytuacji, jaka wydarzyć się może już za chwilę. Gdy bo-
wiem przychodzi do faktycznego zmagania się z prądami, być może trzeba porzucić wszelkie
plany i sterować kanu za pomocą wszelkich dostępnych umiejętności.
Często jedynym wyjściem jest zmaganie się z konkretną sytuacją, dla której znany jest pe-
wien zestaw możliwości rozwiązania; nie potrafimy wówczas określić, przynajmniej co do
szczegółów, jaki pożądany stan przyszły chcielibyśmy osiągnąć.
bardziej doświadczeni programiści. Może ona także zdefiniować „kamienie milowe" jako
prezentacje i przeglądy oparte na scenariuszach (nie na dokumentach), co skłaniać może
uczestników do wczesnego konfrontowania się z trudnymi zagadnieniami. W celu lepszej
kontroli nowatorskich projektów menedżer może zwiększyć częstotliwość „kamieni milo-
wych", pozostawiając ich „zawartość" odpowiednio elastyczną dla poszukiwania dodatkowych
okazji do doskonalenia i rewidowania celów projektowych. Menedżer powinien także wyko-
rzystywać wiedzę doświadczonych programistów, umożliwiając im rewidowanie planu pro-
jektu lub modelu procesów. W przypadku projektu realizowanego przez programistów zarówno
doświadczonych, jak i początkujących menedżer powinien tak organizować przeglądy part-
nerskie, wędrówki po kodzie i programowanie parami, by ułatwić transfer wiedzy od ekspertów
do nowicjuszy.
W czasie wyprawy na K2 hierarchiczna organizacja okazała się źródłem wąskich kanałów
komunikacyjnych: Mahdi opowiedział o swym przypuszczeniu oficerowi łącznikowego, ten
przekazał informację kierownikowi, kierownik nie porozmawiał jednak z Bonattim w celu jej
wyjaśnienia.
wykorzystuje butle tlenowe jako podstawowy element ekwipunku. Dla odmiany, styl alpejski
— z tego samego powodu — zakłada wyprawę na szczyt dostatecznie szybką, by wystarczający
dla wspinacza okazał się tlen atmosferyczny.
Na tej samej zasadzie odmienne style tworzenia oprogramowania stanowią różne kom-
binacje organizacji projektu i jego cykli życiowych. Tradycyjnie, metodologie inżynierii opro-
gramowania rozpoczęły swą ewolucję od dużych, złożonych projektów, charakteryzujących się
rozległą fazą planistyczną, szczegółowym modelowaniem (czyli rozbudowaną dokumentacją),
hierarchiczną organizacją i drobnoziarnistym planowaniem. Tak duży narzut organizacyjny
okazywał się nieuzasadniony dla krótkich i rutynowych projektów, pojawiła się więc alternatywa
w postaci „zwinnych" (agile) metodologii, takich jak programowanie ekstremalne (Extreme
Programming — opisane przez K. Becka i C. Andresa [Beck i Andres, 2005]), projektowanie
sterowane cechami (Feature-Driven Design, o którym piszą S. Palmer i J. Felsing [Palmer i Fel-
sing, 2002]) czy też opisywana w rozdziale 14. metodologia Serum (omówiona przez K. Schwa-
bera i M. Beedle'a[Schwaber i Beedle, 2002]). „Zwinność" tych metodologii zasadza się na
przyrostowym planowaniu, kod źródłowy zyskuje status najważniejszego modelu, a luźno
powiązane zespoły wykwalifikowanych programistów mają swobodę planowania i organizo-
wania swej pracy. Dodatkową zaletą zwinnych metodologii jest ich duża zdolność adaptacji do
fundamentalnych nawet zmian w wymaganiach, omówiona w pracy A. Cockburna [Cock-
burn, 2001]. Zgodnie z ogólnie przyjętą definicją, przedmiotowa „zwinność" to „zdolność za-
równo do tworzenia zmian, jak i sprawnego na nie reagowania, w obliczu burzliwego środo-
wiska biznesu". Cytat pochodzi z publikacji J. Highsmitha [Highsmith, 2004].
Tak samo jak w himalaizmie, środowisko ogranicza zbiór metod możliwych do wyboru:
styl alpejski może być sposobem na szybkie zdobycie szczytu przez sprawnego wspinacza, ale
jest raczej nieprzydatny jako metoda zaprowadzenia na Mount Everest amatorów traktujących
wspinaczkę dla rozrywki (za niezłą odpłatnością, rzec jasna). Podobnie zwinne metodologie
inżynierii oprogramowania mogą skutkować spektakularnymi wynikami, ale tylko w przypad-
ku dostępności „masy krytycznej" wysoce wykwalifikowanych uczestników projektu.
W sekcji 16.4.1 opiszemy metodologię Royce'a — patrz książka W. Royce'a [Royce, 1998]
— stanowiącą programistyczną analogię stylu poręczowego wspinaczki. Metodologia ta wynika
wprost z założeń jednolitego procesu {Unified Process) opisywanego w rozdziale 15. i dostarcza
menedżerowi wiele heurystyk pomocnych w szacowaniu, kontrolowaniu i monitorowaniu
projektów. Sekcję 16.4.2 poświęcimy programowaniu ekstremalnemu (XP — Extreme Pro-
gramming) [Beck i Andres, 2005] — wczesnej „zwinnej" metodologii stanowiącej analogię
stylu alpejskiego. XP minimalizuje generowanie modeli i dokumentacji, skupiając się na uwi-
dacznianiu projektu systemu wprost w kodzie źródłowym i rozpowszechnianiu związanej z nim
wiedzy w sposób bezpośredni. W sekcji 16.4.3 opiszemy ewoluowanie zwinnych technologii,
od metodologii rugby, opisanej przez H. Takeuchiego i I. Nonakę [Takeuchi i Nonaka, 1986],
którą można porównać do wspinaczki na nieznany szczyt, do nowoczesnych podejść, na czele
z metodologią Serum [Schwaber i Beedle, 2002].
Ile planowania?
Jako że czynienie wszelkich oszacowań w ramach owego projektu jest dosyć trudne,
Royce sugeruje wyliczenie początkowych oszacowań przy użyciu odpowiedniego modelu, takiego
jak COGOMO II (patrz praca B. Boehma, E. Horowitza, R. Madachy'ego, D. Reifera, B. K.
Clarka, B. Steecea, A. W. Browna, S. Chulaniego i C. Abtsa [Boehm i in., 2000], i następnie
ich urealnienie przy udziale menedżera projektu, programistów i testerów. Umożliwi to uwzględ-
nienie różnych punktów widzenia we wspomnianych oszacowaniach i wzmocni w uczestnikach
poczucie współodpowiedzialności za ich realność. Po każdej iteracji plan projektu jest przeglą-
dany i rewidowany w celu odzwierciedlenia rzeczywistej wydajności projektu i naprawienia
ewentualnych błędów.
Ile powtarzalności?
Ile modelowania?
Rysunek 16.1. Przykład mapy produktów w projekcie wykorzystującym jednolity proces Royce'a jako
model cyklu życiowego. Nieformalne emisje produktów oznaczone są białymi trójkątami, zaś produkty
posiadające status linii bazowej reprezentowane są przez wypełnione trójkąty. Linie kropkowane repre-
zentują końce poszczególnych faz (rysunek na podstawie pracy W. Royce'a [Royce, 1998])
stają się pierwotną przyczyną wąskich gardeł wydajności. Małe projekty charaktery-
zują się nieformalnym zarządzaniem koncentrującym się na technicznych artefaktach,
nielicznymi „kamieniami milowymi" i brakiem formalnych procesów. Większe pro-
jekty muszą być zarządzane w sposób bardziej formalny, ściśle definiować „kamienie
milowe" i koncentrować się na artefaktach zarządzania zmianami, między innymi
na żądaniach zmian i uwzględnieniu ich w zarządzaniu konfiguracją.
• Spójność udziałowców. Grupa współpracujących udziałowców posługuje się elastycz-
nym planem i nieformalnymi porozumieniami; przykładem projektu tego rodzaju
może być wytwarzanie produktu „na półkę" przez początkującą na rynku kilkuoso-
bową firmę. Zgodność i współdziałanie umożliwia doskonalenie planu i wymagań
po każdej iteracji. Dla odmiany, różnice zdań i konflikty między udziałowcami stwa-
rzają konieczność formalizowania porozumień i dobrze zdefiniowanych procesów,
by możliwe było osiągniecie konsensusu. Konflikty między udziałowcami zdarzają się
często w przypadku projektów realizowanych przez konsorcja firm, prezentujących
sprzeczne cele projektowe. W konfliktowej grupie udziałowców większy nacisk kładzie
się więc na modelowanie przypadków użycia i przeglądy bazujące na prezentacjach.
Krytyczny staje się proces weryfikowania i walidacji, a aktywności związane z prze-
glądami i zapewnieniem jakości mają pierwszeństwo przed innymi.
• Elastyczność procesów. Rygory kontraktu między klientem a firmą realizującą projekt
przekładają się na rygoryzm definiowania procesów cyklu życiowego. Rygorystyczny
kontrakt, na przykład zamówienie ze strony administracji publicznej, wymaga zwykle
precyzyjnego zdefiniowania procesów, gdy na przykład tworzenie eksperymentalnych
prototypów na własne potrzeby cechuje się znacznie większą swobodą.
• Dojrzałość procesów. Organizacje projektów realizowanych przy użyciu dojrzałych
procesów są łatwiejsze w zarządzaniu niż organizacje polegające na procesach niedoj-
rzałych. Dojrzałe organizacje prezentują doświadczenie umożliwiające precyzyjne
planowanie i wysoki stopień automatyzacji procesów.
• Ryzyko architektoniczne. W idealnym przypadku opłacalność wybranej architektury
powinna być zaprezentowana przed pełnym jej zastosowaniem. W praktyce jednak
nie zawsze możliwe jest wyeliminowanie ryzyka związanego z architekturą przed
rozpoczęciem fazy konstrukcyjnej. Nowy i nieprzetestowany styl architektoniczny
niesie ze sobą większe ryzyko w postaci kosztownych przeróbek kodu; wczesne roz-
poznanie tego ryzyka wymaga większego wysiłku projektowego i większego nacisku
na prezentacje.
• Doświadczenie dziedzinowe. Projekt realizowany przez uczestników mających wiedzę
i doświadczenie z zakresu dziedziny aplikacyjnej i dziedziny realizacyjnej cechuje się
krótszymi fazami początkowymi cyklu życiowego, głównie dzięki wykorzystywaniu
procesów opracowanych na potrzeby poprzednich projektów. Programiści mający
doświadczenie w opracowywaniu podobnych systemów w przeszłości stosują zwykle
mniej iteracji i zadowalają się mniejszą liczbą ocen statusu.
Podczas inicjowania projektu menedżer powinien wziąć pod uwagę wymienione czynniki,
decydując o stopniu szczegółowości procesów oraz o przydziale budżetu dla każdej z faz.
730 Rozdział 16, ® Wszystko razem, czyli metodologie
Ile kontroli?
Trudno zarządzać projektem, którego statusu nie da się mierzyć w sposób obiektywny.
To jeden z powodów tego, że trudno zarządzać projektem tradycyjnym, ponieważ większość
jego artefaktów stanowią dokumenty. Iteracyjny cykl życiowy częściowo rozwiązuje ten pro-
blem, gdyż szybko pojawia się w nim, obok dokumentów, wiele artefaktów o charakterze tech-
nicznym. Celem zbierania metryk jest bieżące dostarczanie adekwatnego obrazu postępu
w realizacji projektu i stanu jakościowego ewoluujących produktów, tak by można było cały
czas korygować budżet i harmonogram.
Na początku każdej iteracji aktualizowane są plan, wymagania i architektura systemu.
Ponadto rezultatem każdej iteracji są między innymi zmiany wymagań dotyczących produktów
objętych kontrolą konfiguracji, w celu sprostania nowo rozpoznanym czynnikom ryzyka.
W iteracyjnym procesie cyklu życiowego krytycznego znaczenia nabiera więc zarządzanie
zmianami: każda zmiana powinna być dokładnie śledzona, od jej zażądania, po aprobatę,
przeznaczenie do implementacji i samo implementowanie. Rozmiar kodu modyfikowanego,
dodawanego lub usuwanego w związku ze zmianą, rozmiar samej zmiany i inne podobne
metryki mają krytyczne znaczenie z perspektywy kontrolowania ogólnej jakości systemu.
Metodologia Royce'a skupia się na trzech metrykach menedżerskich i czterech metrykach
jakościowych. Do pierwszej z tych grup należą:
• praca — ile zadań zostało dotychczas zakończonych i jak ma się ta liczba do planu
zadań?
• koszty — ile zasobów zostało już skonsumowanych i jak ma się to do zaplanowanego
budżetu?
• dynamika kadrowa — ilu uczestników zrezygnowało z udziału w projekcie? Ilu
przybyło nowych uczestników?
Podsumowanie
W tabeli 16.3 znajduje się podsumowanie metodologii Royce'a w podziale na każde z opi-
sanych zagadnień.
Zagadnienie Metody
Planowanie Ewolucyjna struktura podziału pracy
Wstępne oszacowanie kosztu i h a r m o n o g r a m u , oparte na modelu (na
przykład C O C O M O II)
Iteracyjne planowanie, z udziałem wszystkich zainteresowanych
• Szybkie sprzężenie zwrotne. Szybkie wykrywanie problemów daje więcej czasu na ich
rozwiązywanie; odnosi się to zarówno do relacji klienta z programistami, jak i do
testowania systemu.
• Prostota. Projekt powinien koncentrować się tylko na bieżącym wymaganiu. Jako że
żądania zmian mogą pojawiać się dość często i tylko niektóre z nich można przewi-
dywać, łatwiej zajmować się nowymi wymaganiami dopiero wtedy, gdy się rzeczywi-
ście pojawią. Prosty projekt jest łatwiejszy do zrozumienia i modyfikowania niż
złożony projekt charakteryzujący się wieloma ukrytymi odwołaniami utrudniającymi
przewidywanie zmian.
• Przyrostowe modyfikacje. Łatwiej uwzględniać jedną zmianę na raz zamiast wielu
zmian równocześnie. Kolejne zmiany powinny być integrowane z „linią bazową"
pojedynczo.
• Oswojenie ze zmianami. Zmiany są nieuniknione i mogą zdarzać się często — to
stwierdzenie traktowane jest jak norma, nie zaś jako wyjątek, którego chciałoby
się unikać.
• Wysoka jakość. XP koncentruje się na szybkich projektach, których postęp demon-
strowany jest bardzo często. Nie może to się jednak odbywać ze szkodą dla jakości
produktów: każda zmiana powinna być implementowana starannie i kompletnie,
zainwestowanie czasu na tym etapie pozwoli na uniknięcie jego straty w związku
z późniejszymi przeróbkami.
Ile planowania?
takie kwalifikuje się do dalszej dekompozycji na prostsze zadania. Gdy oszacowana zostanie
już pracochłonność poszczególnych historii w kategoriach zadań do wykonania, klient i pro-
gramiści spotykają się w celu określenia kolejności realizacji tych historii, co przekłada się na
kolejne wersje systemu dostarczane klientowi do wdrożenia. Historie użytkownika organizo-
wane są w stos odzwierciedlający powiązania funkcjonalne między nimi. Klient dokonuje okre-
ślenia priorytetów poszczególnych historii, dzięki czemu najpierw realizowane będą najważ-
niejsze wymagania; realizację wymagań opcjonalnych można odłożyć na później. I tak właśnie
powstaje plan emisji: poszczególne historie wiązane są z przyszłymi wersjami systemu, dla
każdej wersji ustalany jest termin jej wdrożenia. Kolejne wersje emitowane są dość często,
zwykle co miesiąc lub dwa, co zapewnia szybkie sprzężenie zwrotne programistów z klientem
i użytkownikami.
Wysiłek niezbędny do realizacji historii użytkownika mierzony jest początkowo w ideal-
nych tygodniach. Idealny tydzień to tydzień roboczy, w którym cały wysiłek dedykowany jest
jednemu i tyko jednemu celowi. Jest oczywiste, że idealny tydzień dłuższy jest zwykle od kalen-
darzowego tygodnia roboczego, programiści bowiem muszą uczestniczyć w zebraniach, chorują,
przebywają na urlopach i tak dalej, a ponadto muszą zmagać się z wieloma niepewnościami,
nieoczywistościami i tym podobnymi przypadkami w projekcie. Dla nowych zespołów,
niemających doświadczeń z metodologią XP, zalecamy przyjęcie idealnego tygodnia w wymiarze
trzech kalendarzowych tygodni roboczych; w miarę zdobywania doświadczenia współczynnik
ten będzie się zapewne obniżał. Odwrotność współczynnika wyrażającego długość idealnego
tygodnia w tygodniach kalendarzowych, wyrażająca ilość tygodni idealnych realizowanych
w tygodniu roboczym, zwana jest potocznie szybkością projektu (project velocity).
Każda emisja systemu powstaje w wyniku kilku iteracji, trwających po dwa lub trzy
tygodnie. Każda z iteracji skutkuje promocją systemu, która przekazywana jest klientowi do te-
stów akceptacyjnych. W ten sposób klient, oglądając rozwój systemu w postaci niewielkich
przyrostów funkcjonalności, ma wielokrotnie okazję do żądania czy proponowania zmian.
Każda iteracja reprezentuje mały krok w stronę kolejnej emisji, ewentualne zmiany są więc
niewielkie i w razie potrzeby mogą być bez kłopotu wycofywane.
Każdą iterację poprzedza tak zwana „gra planistyczna", w ramach której klient wy-
biera historie do implementacji, przypisując każdej z nich priorytet według własnego uznania.
Dla każdej historii klient określa także testy akceptacyjne w postaci scenariuszy weryfikują-
cych jej implementację. Testy te wykorzystywane będą także do testowania regresyjnego syste-
mu przed każdą iteracją.
Po zakończeniu każdej iteracji programiści sumują pracochłonność (w tygodniach ideal-
nych) wszystkich zrealizowanych historii (czyli tych, których implementacje przeszły testy
akceptacyjne) i, odnosząc je do rzeczywistego upływu czasu, obliczają wskaźnik szybkości
projektu. Dla następnej iteracji klient wybrać może tylko taki zbiór historii, których szacowana
łączna pracochłonność nie przekracza zrealizowanej w poprzedniej iteracji. Dokonując takiego
wyboru, klient musi rozstrzygać kompromisy między funkcj onalnością a kosztem, programiści
zaś zyskują okazję do obiektywnej wyceny pracochłonności implementowania poszczególnych
cech. Czas planowania iteracji to także konieczność uporania się z testami akceptacyjnymi, któ-
re nie zostały zaliczone przy zakończeniu poprzedniej iteracji. Jeśli szybkość projektu znacząco
odbiega od oryginalnego planu przez więcej niż dwie iteracje, zwoływane jest zebranie pla-
nistyczne z udziałem klienta i weryfikowany jest harmonogram poszczególnych emisji.
734 Rozdział 16, ® Wszystko razem, czyli metodologie
Z perspektywy zarządzania projektem, historie klienta mogą być traktowane jako pakiety
pracy w strukturze podziału pracy. Zasadniczą różnicą w stosunku do tradycyjnych projektów
jest jednak fakt, że oszacowania czasochłonności poszczególnych zadań dokonywane są przez
programistów, nie przez menedżera projektu.
Ile powtarzalności?
Ile modelowania?
XP realizuje prosty proces cyklu życiowego, składający się z czterech aktywności: plano-
wania, projektowania, kodowania i testowania. Planowanie odbywa się na początku każdej
iteracji. Aktywności projektowania, kodowania i testowania następują szybko po sobie w spo-
sób przyrostowy. Na wspomniane aktywności narzuconych jest jednak kilka ograniczeń.
• Najpierw testy. Implementowanie danej jednostki (modułu) poprzedzone jest stwo-
rzeniem dla niej testów jednostkowych. Z jednej strony, zapewnia to dostępność od-
powiednich testów dla ukończonego właśnie modułu, z drugiej, umożliwia progra-
mistom doskonalenie API tworzonej klasy.
2
Także poprzez obfite, lecz przemyślane komentowanie kodu w sytuacjach, gdy semantyka kodu
nie jest wystarczająco oczywista — przyp. tłum.
16.4. Spektrum metodologii 735
Ile kontroli?
[Highsmith i Orr, 2000]. Kierownik zespołu (a nie menedżer projektu) komunikuje wizję
wymagań dla systemu i jego architektury, zachęca zarówno do wykorzystywania nowych
technologii i nowych pomysłów, jak również do uwzględniania kryjących się za nimi czynni-
ków ryzyka. Kierownik kultywuje także środowisko, w którym programiści jego zespołu mogą
efektywnie współpracować, sprawnie wymieniać informację i zdobywać wzajemne zaufanie;
niekiedy jednak musi narzucać swe decyzje, choć powinien wykorzystywać możliwości budo-
wania konsensusu. Kierownik zespołu XP porównywalny jest do Polinezyjczyka nawigatora,
kierującego swe kanu ku wyznaczonemu celowi, bez uprzedniego planu wyznaczającego a priori
kolejne kroki podróży.
Podsumowanie
Zagadnienie Metody
Planowanie Spisywanie historii klienta
Planowanie niewielkich, częstych emisji (co miesiąc lub dwa)
Tworzenie h a r m o n o g r a m u emisji
Planowanie i uruchamianie iteracji
Ile planowania?
Zwinne metodologie zyskały złą reputację jako „unikające planowania" czy „niechętne
do zobowiązań w kwestii terminów i cech systemu". Prawda jest jednak zgoła inna: zwinne
metodologie szeroko korzystają z planowania, które jednak nie zostaje skupione na samym
początku projektu. Zwinne planowanie ma charakter iteracyjny i związane jest z doskona-
leniem oszacowań, w miarę jak stabilizują się wymagania, a zespoły zyskują coraz większe
doświadczenie. W deterministycznym modelu tworzenia oprogramowania SPMP tworzony
jest jednorazowo na samym początku, w „zwinnym" niedeterministycznym modelu SPMP opra-
cowywany jest iteracyjnie i przyrostowo, w postaci przystosowywanej do bieżącej sytuacji.
Określenie iteracyjne planowanie oznacza, że planista zawsze przygotowany jest na to,
że plan okaże się błędny i trzeba będzie go skorygować, zamiast wszelkimi sposobami próbo-
wać wtłoczyć projekt w jego sztywne ramy. Tego typu sytuacje mogą zdarzać się nawet w środku
realizacji projektu, na przykład wskutek pojawienia się nowych obiecujących technologii. Na
początku projektu klient może zażądać, by produkt finalny posiadał „takie to a takie" cechy,
lecz później może uznać, że odmienny zestaw wymagań czyni ów produkt bardziej atrakcyjnym.
Opisana niepewność odzwierciedlona jest także we wszelkich modelach szacowania czasu,
budżetu i tym podobnych. M. Cohn zaleca w związku z tym trzy rodzaje oszacowań: pierwsze,
dokonywane na początku projektu, ma na celu ustalenie jedynie rzędu wielkości poszczegól-
nych wskaźników. Na kolejnym poziomie szacunkowym powinny się już pojawić wielkości
obarczone błędem nie większym niż +25% i -10%. W dalszym ciągu trwania projektu błąd ten
może zmniejszyć się do + 10% i -5% [Cohn, 2006].
Ze zwinnym planowaniem wiąże się — oczywiście — zwinne szacowanie. Jedną z jego
metod jest tak zwany poker planistyczny (Planning Poker), opisany przez J. Grenninga [Gren-
ning, 2002]. Każdy z uczestników zebrania otrzymuje od moderatora zestaw kart opatrzonych
różnymi wartościami, powiedzmy 1, 2, 3, 5, 8, 13, 20, 40 i 100. Prezentowana jest lista cech
systemu, podlegających szacowaniu — mogą nimi być wymagania funkcyjne i pozafimkcyjne,
często prezentowane w kategoriach historii użytkownika lub scenariuszy. Dla każdej pozycji
z tej listy uczestnicy dyskutują jej trudność, po czym każdy (w tajemnicy przed innymi) wybiera
jedną kartę, prezentującą odpowiednią (jego zdaniem) wartość oszacowania. Na znak mode-
ratora wszyscy odkrywają swe karty i posiadacze skrajnych ocen proszeni są o uzasadnienie
swego wyboru (konsensus za pierwszym razem zdarza się bardzo rzadko). To wywołuje
kolejną dyskusję, po czym procedura się powtarza, aż do osiągnięcia konsensusu. By jego
osiągnięcie ułatwić, można stosować rozmaite techniki pomocnicze, na przykład przyznać
16.4. Spektrum metodologii 739
autorowi wymagania większą wagę głosu. Jako że zwinne planowanie ma charakter iteracyjny,
planiści poprawiają swe oszacowania w miarę nabywania lepszego rozumienia dziedziny
aplikacyjnej i lepszego rozeznania zespołu programistów.
Ile powtarzalności?
Zalety metodologii rubgy ujawniają się przy tworzeniu nowych produktów (w ramach
inżynierii pierwotnej), kiedy to główny nacisk położony jest nie na wielokrotne wykorzystywa-
nie gotowych komponentów, lecz raczej na wielokrotne wykorzystywanie zdobytej wiedzy.
Zdobywanie wiedzy może odbywać się zarówno na poziomie zespołu, jak i na poziomie
poszczególnych programistów. Zespoły szkolą swe umiejętności techniczne — w ramach
tutoriali i programów szkoleniowych — i umiejętności społeczne. Co więcej, zespoły powinny
zdobywać wiedzę dotyczącą zagadnień powierzonych innym zespołom; pozwoli to programi-
stom rozmawiać zrozumiałym językiem z przedstawicielami innych dziedzin aplikacyjnych,
co ma pierwszorzędne znaczenie z perspektywy zbierania wymagań i odkrywania nowator-
skich projektów.
Wiedza może być rozpowszechniana między zespołami także poprzez rotacyjny przy-
dział ekspertów do poszczególnych zespołów. Organizacja jako taka zdobywa swą wiedzą
w drodze konwersji doświadczeń nabytych przy kolejnych projektach na standardowe praktyki,
strategia ta okazuje się jednak mało skuteczna w sytuacji, gdy kolejne projekty nie mają powta-
rzalnego charakteru, a realizowane są w dynamicznie zmieniającym się środowisku. Zdaniem
Takeuchiego i Nonaki uczenie się na błędach jest bardziej skuteczne niż wyciąganie wniosków
z samych sukcesów, więc programiści i menedżer powinni przede wszystkim uczyć się na wła-
snych i cudzych błędach, o czym pisze H. Petroski [Petroski, 1992]. Dopuszczalność błędów
i pomyłek w realizacji projektu jest jednym z istotnych aspektów metodologii Serum — ważne
jest ich wczesne rozpoznanie, dające wystarczająco dużo czasu na ich naprawienie. Temu
właśnie celowi służą codzienne zebrania statusowe.
Ile modelowania?
Przez całą treść tej książki przewija się koncepcja modelowania jako klucza do rozwiązy-
wania problemów inżynierii oprogramowania. UML stał się jednym z dominujących języków
modelowania systemów informatycznych. Wykorzystuje się go podczas komunikacji z klien-
tem (w postaci modeli przypadków użycia), realizacji dynamicznego zachowania (w postaci
diagramów stanów i diagramów aktywności) i opisywania instalacji systemu (w postaci dia-
gramów wdrażania).
Wielokrotnie akcentowaliśmy konieczność zachowania spójności między poszczególnymi
modelami systemu (sekcja 4.3.3). Zdaniem S. Amblera modele powinno się jednak aktualizo-
wać dopiero wtedy, gdy „poważnie rozmijają się" [Ambler, 2002], a nie po każdej, nawet drobnej
zmianie wprowadzonej do jednego modelu. Zwinne modelowania zakłada ponadto, że ta sama
koncepcja może być modelowana na wiele sposobów, w związku z czym Ambler zaleca rów-
noległe tworzenie kilku modeli, przy użyciu prostszej notacji i prostszych narzędzi; przykładowo
metodologia Serum zakłada zapisywanie zadań na karteczkach przypinanych w odpo-
wiednim układzie do tablicy.
740 Rozdział 16, ® Wszystko razem, czyli metodologie
opisany przez O. Babatundę i W. H. Raya [Tunde i Ray, 1994]. Jego rację bytu stanowi fakt, że
procesy programistyczne prezentują same z siebie zbyt dużą złożoność, by w pełni zrozumieć je
a priori, zwłaszcza w obliczu nieuchronnych, nieoczekiwanych i być może częstych zmian
w środowisku. Menedżerowie wykorzystujący modele niedeterministyczne przygotowani są
na takie nieoczekiwane zdarzenia i radzą sobie z nimi poprzez częste inspekcje prac w projekcie:
przykładowo w metodologii Serum planowanie kolejnego przebiegu („sprintu") odbywa się
w oparciu o doświadczenia ostatniej iteracji, w związku z czym przedefmiowywanie celów pro-
jektowych lub zmiana wymagań klienta uważane są za naturalne i w pełni dozwolone zabiegi.
Tak właśnie wygląda w praktyce elastyczność modelu empirycznego.
Ile kontroli?
Tak więc z jednej strony — duża swoboda, z drugiej — poważne zobowiązania. Swoboda
ta nie pozostaje jednak całkowicie poza kontrolą: menedżer ustanawia zestaw „punktów
kontrolnych" niezbędnych do tego, by efektem owej swobody nie stała się niestabilność, a w kon-
sekwencji kompletny chaos. Kontrola zespołu nie ma jednak nic wspólnego z odgórnie narzuco-
nymi sztywnymi schematami, lecz ma raczej charakter samokontroli — kontroli grupowej
dynamiki zespołu, selekcji członków zespołu na podstawie ich doświadczenia i energii oraz łą-
czenia w ramach jednego zespołu nowicjuszy z doświadczonymi programistami. Bardzo ważna
jest zdolność menedżera projektu do przewidywania błędów i radzenia sobie z nimi.
Aby szybko reagować na pojawiające się problemy, powinny być one identyfikowane jak
najszybciej. Temu właśnie służą codzienne zebrania Serum, w ramach których członkowie ze-
społów regularnie dzielą się informacją o postępie swych prac i napotykanych problemach.
Podsumowanie
Zagadnienie Metody
Planowanie Planowanie projektu w kategoriach priorytetowej listy wymagań
wysokopoziomowych
Jednomyślne definiowanie celów bieżącej iteracji
Porozumienie co do ogólnego oszacowania pracochłonności; precyzyjne
szacowanie możliwe jest tylko dla bieżącej iteracji
Codzienne rewidowanie oszacowań, na podstawie dokonanego postępu
i identyfikacji nowych zadań
Modelowanie Szkice
Prototypy papierowe
Symulacje „czarodzieja z krainy Oz"
Opiszemy w związku z tym trzy projekty, na zasadzie analizy przypadku, widziane wła-
śnie oczyma początkującego menedżera. Wszystkie realizowane były w rzeczywistości dla re-
alnych klientów, przez studentów uczestniczących w zaawansowanych kursach inżynierii
oprogramowania. Wspomniane projekty to:
Wszystkie projekty zrealizowane zostały przez studentów; weźmy pod uwagę, że w trakcie
ich realizacji studenci prawdopodobnie uczestniczyli także w innych kursach. Jest to sytuacja
podobna do spotykanej w organizacjach macierzowych, czyli takich, w których dana osoba
może być uczestnikiem wielu projektów równocześnie. Dla każdego z wymienionych projek-
tów określimy cele, środowisko, metody planowania, wielokrotne wykorzystywanie rozwiązań,
modelowanie, procesy i kontrolę oraz podsumujemy wyciągnięte wnioski.
Celprojektu
Środowisko projektu
Lokalny samodzielny klient. Rolę klienta pełnił dostawca oprogramowania, znający za-
równo technologię, jak i platformę.
Nowicjusze. Z klientem współpracowali dwaj programiści i ich nadzorca. Uczestniczyli
już w projektach programistycznych, nie mieli jednak żadnych doświadczeń z XP; wspomagał
ich więc zewnętrzny uczestnik doradzający w kwestiach zastosowania i przystosowywania
tej metodologii.
Dojrzała technologia. Ponieważ platformą dla systemu był język Java, programiści mieli
do wyboru bogatą ofertę dojrzałych komponentów.
Projekt zlokalizowany w siedzibie klienta. Programiści pracowali w styczności z klientem
i mieli nieograniczoną możliwość komunikowania się z nim. Klient mógł podejmować bez
konsultacji natychmiastowe decyzje.
Czas trwania projektu. Ponieważ programiści znali modelowanie przypadków użycia
i narzędzia związane z analizą wymagań, projekt podzielono na dwie fazy. Pierwsza, trwająca
dwa miesiące, ukierunkowana była wyłącznie na wymagania, zbiór pionowych prototypów
i model przypadków użycia. Stworzone przez programistów makiety i prototypy weryfikowa-
ne były przez klienta w kontekście modelu przypadków użycia. Druga faza, obliczona na cztery
miesiące, dedykowana była realizacji pierwszej emisji systemu według metodologii XP. Na po-
czątku tej fazy model przypadków użycia skonwertowany został na zestaw historii użytkownika,
wykorzystywanych przez klienta i programistów do nadania priorytetów poszczególnym wy-
maganiom i dokonania niezbędnych oszacowań związanych z tymi wymaganiami.
Dwufazowa struktura projektu minimalizowała ryzyko związane z użyciem nowej meto-
dologii (XP), przez jej ograniczenie do fazy konstrukcyjnej.
Ile planowania?
„Kamienie milowe" projektu znane były od samego początku, wskutek ograniczeń na-
rzuconych na programistów i nadzorcę. Poprzednie doświadczenia wyniesione z podobnych
projektów (pół roku realizacji, kilku programistów, nowy klient) sugerowały czas trwania fazy
wymagań na 6 do 8 tygodni. Koniec tej fazy zbiegał się także z początkiem nowego roku ka-
lendarzowego, dzięki czemu łatwiej było zaplanować następną fazę (w kalendarzu klienta).
Zaplanowano drugą fazę i jej dekompozycję na trzy iteracje, ale tylko pod warunkiem zakoń-
czenia fazy pierwszej. Programiści od początku nadali projektowi duże tempo, potwierdzając
swą produktywność: realizacja idealnego tygodnia zajęła im w przybliżeniu 1,5 tygodnia robo-
czego. Ku zaskoczeniu nadzorcy i klienta, szybkość ta została utrzymana przez cały projekt.
Ile powtarzalności?
specyfikowania pętli i manipulowania plikami. Język ten stawał się jednak coraz bardziej
skomplikowany, programiści zdecydowali więc o zarzuceniu pomysłu własnego interpretera
i wykorzystaniu gotowego interpretera klasy open source, bazującego na JavaScripcie. Zaletą
takiego wyboru, który notabene przywrócił planową realizację projektu, były dodatkowe
elementy funkcjonalne dla klienta oraz łatwiejsza nauka systemu dla jego użytkowników.
Ile modelowania?
Ile kontroli?
Programiści spotykali się ze swym nadzorcą krótko po zakończeniu każdej iteracji, przed
spotkaniami z klientem, by zademonstrować bieżący status kodu i omówić ewentualne nieroz-
wiązane problemy. Ponieważ projekt realizowany był zgodnie z początkowym harmono-
gramem, a po zakończeniu poszczególnych iteracji pozostawało niewiele otwartych zagadnień,
spotkania programistów z nadzorcą sprowadzały się głównie do doskonalenia jego wiedzy
z zakresu dziedziny aplikacyjnej. Kilka dni po zakończeniu każdej iteracji odbywały się spotka-
nia z klientem w celu przeprowadzenia testów akceptacyjnych emisji będącej produktem tej
iteracji.
Wynik
Wnioski
Szkolenie klienta. Mimo iż projekt realizowany był w siedzibie klienta, ten nie dyspono-
wał zasobami wystarczającymi do dedykowania odrębnemu uczestnikowi zdefiniowania historii
użytkownika i testów akceptacyjnych — organizacja była na to zbyt mała. W efekcie, klient nie
nauczył się o procesach projektu tak wiele, jak początkowo planowano. W tej sytuacji na pro-
gramistach spoczęło zebranie i zweryfikowanie stabilnego zbioru wymagań, na podstawie
zaledwie kilku spotkań z klientem na przestrzeni dwóch miesięcy obejmujących pierwszą fazę;
zadanie ułatwiły im rozmaite scenariusze, makiety i przypadki użycia. W przypadku dłużej
trwających projektów, znajomość podstawowych zasad XP przez klienta, dokonującego prze-
cież przypisywania priorytetów poszczególnym wymaganiom, jest czynnikiem krytycznym.
W ujęciu Royce'a, projekt XP musi angażować spójne grono udziałowców.
Edukowanie programistów w temacie procesów cyklu życiowego. XP wymaga udziału
doświadczonych programistów; doświadczenie pomaga im dokonywać wiarygodnych oszaco-
wań, lokalizować zmiany i decydować o tym, które problemy rozwiązywać mają samodzielnie,
a które przekazywać innym uczestnikom. ATRACT był projektem wystarczająco małym, by obaj
programiści posiadali wyczerpującą wiedzę na temat jego statusu. W większych projektach
upowszechnianie takiej (i innych) informacji odbywa się między innymi przez rotację par pi-
szących kod źródłowy, tak by początkujący programiści mieli okazję nabywać doświadczenia
we współpracy z ekspertami. Jednak należy być świadomym faktu, że uruchamianie dużych
projektów w metodologii XP, z udziałem wyłącznie nowicjuszy, skutkować będzie bardzo dłu-
gim czasem ich nauki, zanim ów projekt będzie można uznać za względnie stabilny.
Cel projektu
Środowisko projektu
Lokalny samodzielny klient. Klientem zamawiającym system FRIEND był szef lokalnej
policji, niemający początkowo żadnego pojęcia ani o inżynierii oprogramowania, ani o tech-
nologiach bezprzewodowych. Znał — oczywiście — doskonale dziedzinę aplikacyjną, mógł
także podejmować natychmiastowe decyzje dotyczące zakresu i kierunku projektu.
Nowicjusze. Realizacja projektu obejmowała około czterdziestu uczestników, o dosko-
nałych kwalifikacjach technicznych, lecz małym doświadczeniu w zakresie realizacji projektów
takiej skali. Dziedzina aplikacyjna była dla nich nowością.
Dostępność użytkowników. Klient pełnił także rolę użytkownika, ponadto inni wybrani
użytkownicy wykonywali testy akceptacyjne.
Stan technologii. System FRI END opierał się na technologiach bezprzewodowych i PDA,
które również stanowiły platformę dla prototypów. Mimo iż technologie te były już względnie
stabilne, były jednak nowością dla programistów, co wymagało ich dodatkowego szkolenia,
zanim zajęli się tworzeniem kodu produkcyjnego.
Lokalizacja projektu. Projekt skupiony był w jednej lokalizacji — wszyscy studenci mieli
dostęp do wspólnego laboratorium. Kontakt z klientem możliwy był „na telefon".
Czas trwania projektu. Początkowo projekt obejmował dwa miesiące przygotowań, po
których następowała czteromiesięczna iteracja rozwojowa. Po jej pomyślnym zakończeniu
zrealizowane zostały cztery dodatkowe projekty, których wynikiem była udoskonalona kon-
cepcja architektury systemu; ostateczny produkt zrealizowany został przez firmę spin o f f 3 .
Całość realizacji projektu zajęła trzy lata.
Ile planowania?
Ile powtarzalności?
3
Spin off— wydzielone ze struktury akademickiej przedsiębiorstwo, którego celem jest komercjalizacja
wiedzy naukowej. Patrz http://pl.wikipedia.org/wiki/Spin_off_(zarządzanie) —przyp. tłum.
4
Patrz http://pl.wikipedia.org/wiki/Newton_(komputer) — przyp. tłum.
748 Rozdział 16, ® Wszystko razem, czyli metodologie
Ile modelowania?
Tabela 16.6. Artefakty klienckie systemu FRIEND. Studenci otrzymali gotową deklarację problemu
Model cyklu życiowego obejmował trzy fazy. W fazie prerealizacyjnej opracowane zostały
wstępne wymagania i wstępny kształt architektury. Dokonano także wyboru infrastruktury,
między innymi studenci otrzymali własne pomieszczenie przeznaczone wyłącznie do pracy
nad projektem. W tę fazę włączeni zostali dodatkowo klient, menedżer projektu i trenerzy. Na
początku fazy realizacyjnej studenci zostali podzieleni na zespoły pracujące nad konstrukcją
systemu. Celem fazy realizacyjnej była walidacja architektury systemu i uświadomienie uczest-
nikom wszystkich aspektów iteracyjnego cyklu życiowego oprogramowania. Aktywności
przetwarzania wymagań, projektowania, implementowania i tworzenia przypadków testowych
prowadzone były przyrostowo. Opracowana została także podstawowa funkcjonalność systemu
— jej opcjonalne elementy dodane zostały w fazie postrealizacyjnej. Powodem takiego podej-
ścia był zamiar terminowego dostarczenia systemu, z ograniczoną (choć spełniającą wymagane
minimum) funkcjonalnością zamiast spóźnionego dostarczenia kompletnego systemu. W ta-
beli 16.9 zestawione są trzy fazy modelu cyklu życiowego projektu FRIEND w terminologii
standardu IEEE 1074.
Zauważmy, że cykl życiowy nie obejmował aktywności operacyjnych ani aktywności
wsparcia technicznego, ponieważ celem projektu było opracowanie jedynie prototypów
demonstracyjnych.
Ile kontroli?
Odniesienie
Faza Cel Aktywności
do IEEE 1074
Prerealizacyjna Inicjacja projektu Inicjowanie projektu 3.1 Inicjowanie
projektu
Eksplorowanie koncepcji 4.1 Eksploracja
koncepcji
Projektowanie 4.2 Alokacja systemu
wysokopoziomowe
Rysunek 16.2. Zespołowa organizacja projektu FRIEND w ramach 1. iteracji (Carnegie Mellon University,
kurs 15-413, jesień 1992). Białe prostokąty reprezentują zespoły podsystemów, szare — zespoły między-
funkcyjne. Liczby w nawiasach oznaczają liczebność zespołów
w czasie pierwszych dwóch miesięcy role w każdym zespole zmieniały się rotacyjnie, umożli-
wiając każdemu studentowi pełnienie roli facilitatora, łącznika architektonicznego i narzę-
dziowca. Rotacja ta miała zarówno cel pedagogiczny — każdy student praktycznie zapoznawał
się z większością ról — jak i selekcyjny: większość studentów spisujących się doskonale w danej
roli pełniło tę rolę do końca projektu.
Po drugim przeglądzie (przeglądzie projektu systemu) zarówno rygoryzm procesowy,
jak i zasady rotacji ról zostały rozluźnione. Studenci zostali zachęceni do zachowania tych
metody i narzędzi, które sprawdziły się w zastosowaniu i zarzucenia pozostałych. W efekcie
proces raportowania statusu pozostał prawie niezmieniony, lecz coraz więcej decyzji podej-
mowanych było lokalnie w miarę postępu w kodowaniu. Studenci wykazujący zdolności ko-
munikacyjne zostali obsadzeni w rolach łączników, studenci wykazujący kwalifikacje techniczne
przydzielani byli do zadań technicznych. Konflikty i problemy z interfejsami rozstrzygane były
w osobistych spotkaniach w laboratorium, jedynie poważniejsze problemy integracyjne powo-
dowały zwoływanie zebrań.
W rezultacie organizacja projektu ewoluowała ze ściśle hierarchicznej w stronę przy-
pominającej bardziej serię podprojektów XP dla każdego podsystemu. Taka organizacja była
jednak możliwa tylko dzięki wyraźnemu zdefiniowaniu koncepcji architektonicznej, czyli
w konsekwencji określeniu zakresu odpowiedzialności każdego zespołu.
Wynik
Owocem projektu stał się prototyp koncepcyjny demonstrujący, jak system informacji
geograficznej (GIS) może być wykorzystywany do organizowania i wyświetlania informacji
związanej z wypadkami. Sukces pierwszego projektu spowodował uruchomienie czterech
kolejnych iteracji eksplorujących rozmaite technologie i elementy funkcjonalności (patrz
rysunek 16.3).
16.5. Analizy przypadku 753
Wnioski
Szkolenie klienta. Na początku realizacji projektu klient nie tylko nie miał pojęcia o in-
żynierii oprogramowania, ale nawet nie miał obycia z komputerem. Zainwestował jednak
sporo czasu w naukę bezpośredniej komunikacji z programistami; przy czwartym prototypie
potrafił już rozumieć i krytykować wysokopoziomowe diagramy klas. Było to miła niespo-
dzianka dla programistów, bowiem klienci nie uwzględniają zwykle w infrastrukturze projektu
elementu samokształcenia; w przypadku długoterminowych problemów jest ono korzystne za-
równo dla klienta, jak i dla programistów.
Szkolenie programistów w zakresie dziedziny aplikacyjnej. Studenci dość szybko na-
uczyli się podstawowych koncepcji dziedziny aplikacyjnej, jako że klient, osiągalny na każde
wezwanie, wyjaśniał im wszelkie niejednoznaczności i nieporozumienia. W przypadku odda-
lonego klienta konieczne byłoby opracowanie innych metod walidacji wymagań i starannego
śledzenia wątpliwości, wieloznaczności i zmian.
754 Rozdział 16, ® Wszystko razem, czyli metodologie
z modelem kaskadowym, podobnie jak w projekcie FRIEND. Ustalone „kamienie milowe" na-
rzuciły ograniczenia na przetwarzanie wymagań, projektowanie systemu i jego implemento-
wanie. Dla odmiany iteracja 2. sama charakteryzowała się podejściem iteracyjnym — co miesiąc
prezentowane były prototypy coraz bogatsze funkcjonalnie. Zespoły w TUM i CMU pracowały
nad różnymi podsystemami, jednak w oparciu o tę samą architekturę.
Ile powtarzalności?
Ile modelowania?
Tabela 16.11. Aktywności projektu JAMES. Różnice w stosunku do projektu FRI END wyróżniliśmy kursywą
Odniesienie
Faza Cel Aktywności
d o IEEE 1 0 7 4
Tabela 16.11. Aktywności projektu JAMES. Różnice w stosunku do projektu FRI END wyróżniliśmy kursywę
— ciąg dalszy
Odniesienie
Faza Cel Aktywności
d o IEEE 1 0 7 4
Iteracja 2. przerodziła się więc w proces ukierunkowany na encje, czyli koncentrujący się
na prototypach, nierozwiązanych problemach i zmianach, a nie na aktywnościach (patrz sek-
cja 15.4) — w przypadku problemów związanych z środowiskiem JavaCard takie podejście
oznaczało po prostu mniejsze ryzyko.
Ile kontroli?
Podobnie jak projekt FRIEND, tak i projekt JAMES rozpoczął swój żywot od ściśle hierar-
chicznej organizacji. W trakcie 1. iteracji czterdziestu jeden uczestników podzielono na pięć ze-
społów (patrz rysunek 16.5) odpowiedzialnych za poszczególne podsystemy (Logbook, Mainte-
nance, Travel VIP i Vehicle). Dwa zespoły międzyfimkcyjne — Architecture i HCI — składające
się z łączników między zespołami funkcyjnymi —- odpowiedzialne były za koordynowanie
zagadnień związanych z (odpowiednio) architekturą systemu i interfejsem użytkownika. Każdy
zespół referował status swych prac i napotykane problemy w trakcie cotygodniowych zebrań.
Trenerzy zespołów spotykali się co tydzień z menedżerem projektu.
Rysunek 16.5. Zespołowa organizacja projektu JAMES w ośrodku w Pittsburgu w ramach 1. iteracji
(Carnegie Mellon University, kurs 15-413, jesień 1997). Białe prostokąty reprezentują zespoły pod-
systemów, szare — zespoły międzyfunkcyjne. Liczby w nawiasach oznaczają liczebność zespołów
Wynik
Wnioski
Edukowanie klienta. Współpraca z klientem okazała się trudniejsza, niż początkowo są-
dziliśmy, głównie z dwóch powodów.
Ile planowania?
programiści nie znani swych dziedzin wiedzy na tyle, by można było w ich kwestii cokolwiek
zaplanować. Zamiast tego uzgodniono daty przeglądów i prezentacji, pozostawiając duży mar-
gines elastyczności dla „kamieni milowych", których szczegóły przeznaczone były do uzupeł-
nienia w miarę postępów w projekcie i zdobywania niezbędnej wiedzy.
Generalnie nie powinno się podejmować szczegółowego planowania, zanim klient i pro-
gramiści nie uzgodnią elementów funkcjonalnych i architektury systemu. Jeśli czynniki te są
przedmiotem ciągłych zmian, szczegółowe ich planowanie możliwe jest co najwyżej w odnie-
sieniu do następnej iteracji. Tak czy inaczej konieczne jest włączenie klienta i programistów
w proces planowania oraz zapewnienie, że możliwości zmian w planowaniu zostaną wyraźnie
wyartykułowane.
Ile modelowania?
Zakres modelowania zależy od rozmiaru wiedzy, która musi zyskać jawną postać i do-
trzeć do wszystkich uczestników. W projekcie ATRACT uczestnicy konstruowali przypadki uży-
cia, aż do nabycia przekonania, że wystarczająco dobrze rozumieją wymagania klienta i że
klient jest w stanie stworzyć obraz systemu możliwego do realizacji. W dalszym ciągu projektu
modelowanie było już zbędne, bowiem wszyscy trzej uczestnicy pracowali nad projektem w tej
samej lokalizacji i efektywniejsza okazywała się nieformalna komunikacja między nimi.
W projekcie FRIEND skonstruowano szczegółowe modele dziedziny aplikacyjnej i doce-
lowego systemu; modele te wykorzystane zostały do generowania kodu. Dziedzina aplikacyjna
była dla programistów zdecydowanie bardziej obca niż w przypadku systemu ATRACT, większa
też była liczba uczestników, z myślą o większej szybkości realizowania projektu. Modele stano-
wiły głównie bazę dla projektowania i komunikacji, lecz nie były archiwizowane, ze względu na
zmieniającą się dynamicznie postać prototypów.
W rozproszonym projekcie JAMES, w związku z transferem wiedzy między ośrodkami,
objętość wiedzy, którą należało sprowadzić do jawnej postaci, była znacząco większa. Podobnie
jak w projekcie FRIEND, zrezygnowano z utrzymywania spójności między modelami systemu;
zamiast tego studenci odtworzyli model z 1. iteracji, w ramach inwentaryzacji. Tworzenie
szczegółowych modeli warte było zainwestowanego wysiłku, bo transferowano wiedzę między
kontynentami; było ono jednak znacznie utrudnione, ze względu na szybkie tempo zmian
i ograniczoność dostępnych zasobów. Co więcej, szczegółowe modelowanie odbierane było jako
zbędna aktywność — przynosząca korzyści tylko drugiemu ośrodkowi i powodująca sprzecz-
ności między nimi — nie było więc postrzegane jako aktywność krytyczna. Znacznie efektyw-
niejsze (i bardziej atrakcyjne) wydawało się podróżowanie uczestników między ośrodkami.
Generalnie, koszt formalizowania wiedzy i utrzymywania jej w aktualnym stanie jest zna-
czący. Może on być postrzegany jako inwestycja związana z:
Zwrot z tej inwestycji jest znikomy dla krótkich, nielicznych osobowo projektów; w ich
przypadku przeglądy partnerskie wydają się bardziej efektywnym sposobem transferowania
wiedzy.
764 Rozdział 16, ® Wszystko razem, czyli metodologie
Ile kontroli?
W typowym projekcie zakres kontroli zmienia się z czasem jego realizacji. W projektach
FRIEND i JAMES przez pierwsze dwa miesiące obowiązywała ścisła organizacja hierarchiczna,
umożliwiająca systematyczną rotację ról i zapewniająca duży zakres publikowanej informacji
na temat statusu projektu. Gdy rozpoczęło się kodowanie (mniej więcej w okolicy Święta
Dziękczynienia), studenci ze zdolnościami przywódczymi i umiejętnościami komunikacyjnymi
w naturalny sposób objęli role (odpowiednio) kierowników zespołów i łączników. Te spośród
praktykowanych dotąd procedur menedżerskich, które uznane zostały za pożyteczne (na przy-
kład protokołowanie zebrań), były utrzymywane przez studentów jako warte inwestowanego
w nie wysiłku. W naszej ocenie pozwalało to na rozluźnienie reguł i gdy studenci powrócili ze
świątecznej przerwy, dalsza realizacja projektu prowadzona była na sposób „zwinny", ukierun-
kowany na encje. Dyskusje o charakterze technicznym przeniosły się na fora poszczególnych
zespołów, także większość konfliktów rozstrzygana była na poziomie zespołów, zwykle w sposób
bardziej efektywny, niż miałoby to miejsce przy (hierarchicznym) udziale menedżera.
Innymi słowy, dwa pierwsze miesiące iteracji wykorzystane zostały na zbudowanie spój-
nej wizji wymagań i architektury i gdy ziarno to zostało posiane, należało pozwolić mu wykieł-
kować, rozluźniając reguły. Projekt zaczął wówczas ewoluować na wzór żywego organizmu,
wykorzystując naturalne mechanizmy selekcji i samoorganizacji. Struktura zespołu, ścieżki
komunikacyjne wyznaczane przez łączników i procedury zebrań przetrwały tę metamorfozę.
Nieustanna presja wynikająca z terminu testów akceptacyjnych (których nie można było prze-
sunąć) zapewniała pełne skoncentrowanie wszystkich zespołów na zmierzaniu do wspólnego
sukcesu. Tak więc, mimo iż kwalifikacje uczestników nie pozwalały początkowo na działanie
w warunkach samoorganizacji, jednak ta stała się możliwa dzięki początkowemu treningowi.
W przypadku systemu FRIEND nieograniczony dostęp do klienta zapewniał progra-
mistom spójny obraz dziedziny aplikacyjnej. Uczestnicy projektu JAMES mieli trochę gorzej
— rozproszenie projektu znacznie utrudniało spójną ewolucję w kierunku spełnienia kryteriów
akceptacyjnych klienta.
Generalnie „zwinne" organizacje spisują się znakomicie w sytuacji, gdy główni uczestnicy
współdzielą te same cele i tę samą koncepcję architektoniczną, dzięki prezentowaniu tej samej
wizji potrzeb klienckich lub nadzwyczaj klarownej koncepcji samego systemu. Organizacja hie-
16.5. Analizy przypadku 765
Heurystyki metodologiczne
Bądź przygotowany na zmiany w systemie. Zmiany w projektach informatycznych są nieuniknione,
czy to ze strony klienta (nieprzewidziane problemy z użytecznością, nowe wymagania), czy też ze
strony programistów (nieprzewidziane problemy techniczne, nowe decyzje architektoniczne). Za-
mrożenie specyfikacji może wydawać się uzasadnione z perspektywy zachowania przewidywalności
projektu, lecz ostatecznie prowadzi do kiepskiego produktu niespełniającego oczekiwań klienta i użyt-
kowników. Zamiast więc wzbraniać się przed zmianami, zdefiniuj procesy mające na celu radzenie
sobie z nimi.
Uwzględnij możliwość zmiany procesów. Doświadczenie i wspólna wizja systemu ułatwiają przysto-
sowywanie procesów cyklu życiowego. Model cyklu życiowego może ewoluować od procesów ukie-
runkowanych na aktywności do procesów bazujących na encjach — w tym drugim przypadku
przydział pracy opiera się na zmianach wprowadzanych do „linii bazowych". Ponieważ podstawowe
wymagania są ustalone, projekt może być sterowany czasem (czyli emisjami w określonych terminach)
zamiast funkcjonalnością (czyli emisjami po zakończeniu implementowania poszczególnych cech).
Skracaj czas podejmowania decyzji zależnych od klienta. Poważne zmiany w systemie (nowa funkcjo-
nalność, nowy plan emisji) nie mogą odbywać się bez udziału klienta. Skracanie czasu podejmowania
takich krytycznych decyzji jest niezbędne dla zapobieżenia zboczeniu projektu w niewłaściwym
kierunku. Wymaga to efektywnego mechanizmu komunikacji z klientem i rozwiązywania problemów
z udziałem kompetentnych uczestników. W tym kontekście idealny okazuje się typ lokalnego, samo-
dzielnego klienta. Gdy brakuje takowego w projekcie, konieczne jest ustanowienie kanałów sprawnej
komunikacji między (oddalonym) klientem a uczestnikami projektu.
Buduj zaufanie. Uczestnicy oporni są pod względem komunikowania złych wiadomości, szczególnie
spowodowanych własnymi pomyłkami, w obawie przed spodziewanymi konsekwencjami. Tymcza-
sem wszelkie pomyłki i błędy są tym mniej kłopotliwe, im szybciej staną się ogólnie wiadome; nie-
znajomość ukrytych usterek może być zagrożeniem na miarę „być albo nie być" projektu. Musisz więc
z jednej strony, unikać stwarzania atmosfery uzasadniającej żywienie wspomnianych obaw, z drugiej
natomiast, zapewnić uczestnikom dostateczne zasoby do wykrywania i raportowania usterek.
Wyciągaj prawidłowe wnioski — i nic ponadto. Odkładanie podejmowania decyzji może być postrze-
gane jako krótkotrwały sukces, stanowiący podstawę do wyciągania nadmiernie optymistycznych
wniosków. Niekiedy samodzielny wysiłek może okazać się krytyczny na miarę dotrzymania (albo
zawalenia) terminu, jednakże skoncentrowanie istotnej wiedzy w grupie ograniczonej liczby uczest-
ników może stanowić dla projektu poważne zagrożenie. Przechodząc z reżimu poleceń i kontroli do
organizacji przywództwa i współpracy, przestajesz być tylko menedżerem, a stajesz się także nauczy-
cielem. Tak to już jest, że trzeba popełniać błędy, aby naprawę się czegoś nauczyć.
16.6. Literatura uzupełniająca
1999]. H. Petroski zwraca uwagę na krytyczną rolę, jaką odgrywają błędy, pomyłki, awarie
i tym podobne w pomyślnym projektowaniu ([Petroski, 1994]). Uważa on, że nowatorskie
technologie są często reakcją na usterki istniejących produktów. Jegoksiążka pisana jest z per-
16.7. Ćwiczenia
czyli liczba uczestników, którzy opuścili projekt przed jego ukończeniem albo
dołączyli do projektu w trakcie jego realizacji. Wyobraź sobie, że zarządzasz projek-
tem, w którym wskaźnik ten jest wyjątkowo duży dla jednego z zespołów; spróbuj
Bibliografia
[AgileManifesto, 2001] http:/'/www. agilemanifesto. org.
[Aguanno, 2005] K. Aguanno Managing Agile Projects, Multi-Media Publications,
Ontario, 2005.
[Ambler, 2002] S. Ambler Agile Modeling: Effective Practices for Extreme Programming
and the Unified Process, John Wiley & Sons, 2002.
[Beck i Andres, 2005] K. Beck, C. Andres Extreme Programming Explained: Embrace Change,
wyd. drugie, Addison-Wesley, Reading, MA, 2005.
[Boehm i in., 2000] B. Boehm, E. Horowitz, R. Madachy, D. Reifer, B. K. Clark, B. Steece,
A. W. Brown, S. Chulani, C. Abts Software Cost Estimation with
COCOMOII, Prentice Hall, Upper Saddle River, NJ, 2000.
[Bonatti, 2001] W. Bonatti The Mountains of My Life, Modern Library, Random House,
New York, 2001.
[Buhl, 1956] H. Buhl Nanga Parbat Pilgrimage, Hodder & Stoughton, London, 1956.
[Cockburn, 2001] A. Cockburn Agile Software Development, Addison-Wesley, Reading,
MA, 2001.
[Cohn, 2006] M. Cohn Agile Estimating and Planning, Pearson, Upper Saddle River,
NJ, 2006.
[Cusumano i Selby, 1997] M. A. Cusumano, R. W. Selby How Microsoft Builds Software,
„Communications of the ACM", t. 40, nr 6, str. 53 - 61, 1997.
[Deming, 1982] E. W. Deming Out of the Crisis, MIT Press, Cambridge, MA, 1982.
wyd. drugie 2000.
[Fowler, 2005] M. Fowler The new methodology, http://www.martinfowler.com/
articles/newMethodology.html, zrewidowane w 2005.
[Gleick, 1987] J. Gleick Chaos — Making a New Science, Penguin Books Ltd,
Harmondsworth, Middlesex, 1987.
[Gladwin, 1964] T. Gladwin „Culture and logical process", w W. Goodenough (red.)
Explorations in Cultural Anthropology: Essays Presented to George
Peter Murdock, McGraw-Hill, New York, 1964.
768 Rozdział 16, ® Wszystko razem, czyli metodologie
Wzorce projektowe
Rozwiązanie Platforma (na przykład system okienkowy) reprezentowana jest jako zbiór
produktów abstrakcyjnych ( A b s t r a c t P r o d u c t ) , z których każdy reprezentuje
określoną koncepcję (przykładowo przycisk) realizowaną na każdej platformie.
W klasie AbstractFactory zdefiniowane są operacje tworzenia poszczególnych
produktów. Realizację konkretnej platformy stanowią: obiekt ConcreteFactory
i zbiór obiektów ConcreteProduct (po jednym obiekcie dla każdego produktu).
Obiekt C o n c r e t e F a c t o r y zależny jest tylko od „swego" zbioru produktów.
Klient (Cl i ent) zależny jest wyłącznie od klasy A b s t r a c t F a c t o r y , co umożliwia
wymianę platform w sposób dla niego niewidoczny.
Opis problemu Konwersja interfejsu przestarzałej klasy na inny interfejs oczekiwany przez obecnego
klienta, dzięki czemu klient będzie mógł współdziałać z przestarzałą klasą.
Rozwiązanie Klasa Adapter implementuje interfejs Cl i entlnterface oczekiwany przez
klienta (Cl i ent). Deleguje ona wywołania klienta do przestarzałej klasy
(LegacyCl ass), wykonując przy okazji niezbędne konwersje.
Konsekwencje Klient (Cl i ent) i przestarzała klasa (LegacyCl ass) współpracują ze sobą
bez potrzeby modyfikowania któregokolwiek z nich.
Adapter przydatny jest zarówno dla samej klasy LegacyCl ass, jak i dla
dowolnej jej subklasy.
Dla każdej specjalizacji interfejsu klienckiego (Cl i entlnterface)
wymagany jest nowy Adapter.
Przykłady Sortowanie instancji klasy Stri ng za pomocą metody sort () (patrz sekcja
8.4.2): klasa MyStri ngComparator jest adapterem wypełniającym lukę
między klasą Stri ng a interfejsem Comparator wykorzystywanym przez
metodę Array. sort ().
Powiązane Wzorzec projektowy Most (patrz sekcja A.3) wiążący interfejs z różnymi
koncepcje jego implementacjami.
774 Dodatek A • Wzorce projektowe
Rozwiązanie W klasie Abstraction definiowany jest interfejs widoczny dla klienta (Cl i ent).
Implementor to abstrakcyjna klasa definiująca m e t o d y niższego p o z i o m u
d o s t ę p n e dla klasy Abs tract i on. Klasa Abstraction u t r z y m u j e referencję
do powiązanego z nią obiektu subklasy Implementor. Każda z klas Abstraction
i Implementor może być rozwijana niezależnie.
Konsekwencje Klient (Cl i ent) wykorzystuje ten sam kod do operowania na liściach
i kompozytach.
Zachowanie specyficzne dla liści może być modyfikowane bez zmiany
hierarchii.
Dodawanie nowych klas liści może dokonywać się bez zmiany hierarchii.
Przykłady Wyświetlane elementy graficzne interfejsu mogą być organizowane w grupy,
obsługiwane (na przykład przesuwane) w sposób zintegrowany. Grupowanie
to może mieć charakter rekurencyjny — grupy mogą być elementami
większych grup.
W systemie plików katalogi mogą zawierać pliki lub inne katalogi (patrz
rysunek 2.23). Operacje przemianowywania, przesuwania i usuwania mogą
być takie same dla plików i katalogów.
Dekompozycja systemu na podsystemy (patrz rysunek 6.3): podsystem może
składać się z klas i innych podsystemów. Zauważmy jednak, że podsystemy
nie są implementowane jako kompozyty, do których dynamicznie dodawać
można nowe klasy.
Opis hierarchii zadań (patrz rysunek 6.8): każde zadanie może być utożsamiane
z kompozytem, podzadanie — z komponentem, a element działania — z liściem.
P o d o b n a zależność istnieje między fazami, aktywnościami i zadaniami
(patrz rysunek 15.6).
Powiązane Wzorzec projektowy Fasada (patrz sekcja A.6).
koncepcje
A.6. Fasada (Facade) — hermetyzacja podsystemów 111
Opis problemu Redukcja sprzężenia między zbiorem powiązanych klas a resztą systemu.
Rozwiązanie Publikator (Pub l isher), zwany także podmiotem (Subj ect— [Gamma i in., 1994]),
to obiekt, którego głównym zadaniem jest utrzymywanie pewnej informacji
o stanie — na przykład w formie macierzy. Jeden lub więcej subskrybentów
(Subscriber), zwanych także obserwatorami (Observer— [Gamma i in., 1994]),
wykorzystuje tę informację, na przykład do jej wyświetlania w formie wykresu.
Wprowadza to redundancję stanów publikatora i jego subskrybentów. W celu
rozwiązania tego problemu każdy z subskrybentów wywołuje metodę subscri be (),
powodującą zarejestrowanie u publikatora zapotrzebowania na powiadamianie
o każdej zmianie jego stanu. Każdy konkretny subskrybent (ConcreteSubscri ber)
definiuje także m e t o d ę update (), stanowiącą środek wspomnianego
powiadamiania — gdy publikator (Publisher) zmieni swój stan, wywołuje
swą metodę not i f y (), która z kolei powoduje wywołanie metody update ()
każdego zarejestrowanego subskrybenta.
Rozwiązanie Klient (Cl i ent) korzysta z usług dostępnych w danym kontekście (Context).
Każda z tych usług realizowana jest za p o m o c ą jednego z dostępnych
mechanizmów, wybranego przez obiekt Pol i cy. Abstrakcyjna klasa Strategy
opisuje interfejs wspólny dla wszystkich mechanizmów kontekstu. Konfiguracja
kontekstu jest zadaniem obiektu konkretnej strategii ( C o n c r e t e S t r a t e g y ) ,
tworzonego przez obiekt Pol i cy.
Powiązane Wzorce projektowe Adapter (patrz sekcja A.2) i Most (patrz sekcja A.3).
koncepcje
A.10. Heurystyki pomocne w wyborze wzorców projektowych 781
Prawdopodobny
Fraza
wzorzec projektowy
• „niezależność od dostawcy"
Fabryka abstrakcyjna
• „niezależność od platformy"
Bibliografia
S. W. Ambler Process Patterns: Building Large-Scale Systems Using
[Ambler, 1998]
Object Technology, Cambridge University Press, New York, 1998.
Objaśnienia haseł
B.1. Terminologia
Abstrakcja (abstraction) — Klasyfikacja zjawiska w kategoriach koncepcji. Patrz także
modelowanie.
Abstrakcyjny typ danych (abstract data type — ADT) — Typ danych definiowany w specyfi-
kacji niezależnej od konkretnej implementacji.
ACL — Patrz lista kontroli dostępu.
Adaptowalność (adaptability) — Zdolność systemu do radzenia sobie z dodatkowymi
koncepcjami dziedziny aplikacyjnej.
ADT — Patrz abstrakcyjny typ danych.
Agenda zebrania (meeting agenda) — Dokument związany z przygotowaniem i prowadze-
niem zebrania. Zawiera co najmniej trzy części:
• nagłówek określający czas i miejsce zebrania oraz jego uczestników,
• listę tematów zgłoszonych przez uczestników,
• listę zagadnień do przedyskutowania i rozstrzygnięcia.
Agregacja (aggregation) — Skojarzenie ukazujące relację „część-całość" między klasami.
Przykładem agregacji jest system składający się z podsystemów.
Agregacja kompozycyjna (composition aggregation) — Relacja agregacji, w ramach której
istnienie części uwarunkowane jest istnieniem całości. Przeciwieństwo agregacji współ-
dzielonej.
Agregacja współdzielona (shared aggregation) — Relacja agregacji, w ramach której część
może istnieć niezależnie od całości. Przeciwieństwo agregacji kompozycyjnej.
Agregat CM (CM aggregate) — To samo, co agregat zarządzania konfiguracją.
Agregat zarządzania k o n f i g u r a c j ą (configuration management aggregate — C M aggregate)
— Agregat powiązanych elementów konfiguracji.
784 Dodatek B • Objaśnienia haseł
p r e z e n t o w a n i e e l e m e n t ó w ilościowych w p o d e j m o w a n i u decyzji.
Decyzja (decision) — 1. W kontekście d i a g r a m u aktywności — rozgałęzienie przepływu
sterowania. Decyzja oznacza wybór j e d n e j ze ścieżek przepływu n a podstawie określonego
w a r u n k u . 2. W kontekście m o d e l o w a n i a zagadnień — rozstrzygnięcie zagadnienia.
Decyzja implementacyj na (implementation decision) — Decyzja projektowa nie wpływaj ąca
na interfejs klasy lub p o d s y s t e m u .
D e f e k t (defect) - Patrz usterka.
Definiowanie problemu (problem definition) — Planowe zdarzenie komunikacyjne, w ra-
m a c h k t ó r e g o klient i m e n e d ż e r p r o j e k t u definiują zakres f u n k c j o n a l n y systemu.
Deklaracja p r o b l e m u (problem statement) — D o k u m e n t s p o r z ą d z o n y wspólnie przez
klienta i menedżera projektu, opisujący skrótowo zakres systemu, między innymi wymagania
w y s o k o p o z i o m o w e , środowisko docelowe, p r o d u k t y finalne i kryteria akceptacyjne. Patrz
także u m o w a projektu.
D e k o m p o z y c j a hierarchiczna (hierarchical decomposition) — D e k o m p o z y c j a systemu,
której w y n i k i e m jest u p o r z ą d k o w a n y zbiór warstw.
Każdy p o d s y s t e m opisywany jest w kategoriach świadczonych przez niego usług (na etapie
projektowania systemu) i w formie API (na etapie projektowania obiektów). Dekompozycja
systemu n a p o d s y s t e m y jest częścią modelu projektu systemu.
B.1. Terminologia 787
Framework (framework) — Zbiór klas dostarczający ogólne rozwiązanie, które może być
przystosowywane do konkretnego zastosowania lub konkretnego podsystemu.
Framework aplikacyjny (application framework) — Wykorzystywana w sposób powta-
rzalny częściowa aplikacja, przez specjalizacje której konstruuje się konkretne aplikacje.
Patrz także biblioteka klas.
Framework aplikacyjny (enterprise application framework) — Framework przystosowany
do specyfiki aplikacji biznesowych.
Framework białoskrzynkowy (whitebox framework) — Framework bazujący na dziedzi-
czeniu i wiązaniu dynamicznym jako środkach rozszerzalności. Przeciwieństwo frame-
worku czarnoskrzynkowego.
Framework czarnoskrzynkowy (blackbox framework) — Framework, którego rozszerzal-
ność opiera się na dobrze zdefiniowanych interfejsach. Przeciwieństwo frameworku bia-
łoskrzynkowego.
Framework infrastrukturalny (infrastructure framework) — Framework wykorzystywany do
realizacji podsystemu infrastruktury, na przykład interfejsu użytkownika lub podsystemu
magazynowania danych.
Framework pośredniczący (middleware framework) — Framework wykorzystywany do
integrowania rozproszonych aplikacji i komponentów.
Funkcje projektowe (project functions) — Aktywności realizowane przez cały czas trwania
projektu.
Gałąź (branch) — W zarządzaniu konfiguracją równoległa ścieżka rozwojowa.
Generalizacja (generalization) — Aktywność modelowania skutkująca identyfikowaniem
abstrakcyjnych koncepcji na podstawie koncepcji niskopoziomowych.
Globalna tabela dostępu (global access table) — Reprezentacja macierzy kontroli dostępu
w formie zbioru krotek o postaci (aktor, klasa, operacja). Każda z tych krotek odzwierciedla
pojedyncze uprawnienie dostępu, odpowiada zatem pojedynczej komórce macierzy dostępu.
Główny facilitator (primary facilitator) — Patrz facilitator.
Graniczny przypadek użycia (boundary use case) — Przypadek użycia związany z warun-
kiem granicznym.
Groupware — Każde narzędzie programistyczne wspierające wymianę informacji w kręgu
uczestników. Rozproszone, jednoczesne groupware jest środkiem komunikacji synchronicz-
nej, natomiast rozproszone, niejednoczesne groupware wspiera komunikację asynchroniczną.
Grupa procesów (process group) — Zbiór powiązanych procesów. Przykładowe grupy
procesów to procesy menedżerskie, procesy prerealizacyjne i procesy postrealizacyjne.
Guillemets — Poziome znaki cytowania, ograniczające stereotyp języka UML.
Harmonogram (schedule) — Odwzorowanie modelu zadań w upływający czas, w kategoriach
czasu kalendarzowego.
IBIS — Patrz Issue-Based Information System.
B.1. Terminologia 791
Inżynier API (API engineer) — Rola koncentrująca się na definiowaniu API dla podsystemu.
Rola ta jest często łączona z rolą łącznika architektonicznego.
Inżynieria dziewicza — To samo, co inżynieria pierwotna.
Inżynieria interfejsu (interface engineering) — Projekt, którego celem jest ponowne za-
projektowanie lub ponowne zaimplementowanie interfejsu systemu, bez naruszania jego
podstawowej funkcjonalności. Patrz także inżynieria pierwotna, inżynieria wtórna.
Inżynieria odwracająca (reverse engineering) — Proces zastosowania transformacji do
zbioru elementów kodu źródłowego, dający w rezultacie odpowiedni zbiór elementów
modelu. Celem inżynierii odwracającej jest odtworzenie modelu istniejącego systemu, który
to model został zagubiony, stracił aktualność lub po prostu nigdy nie istniał. Przeciwieństwo
inżynierii postępującej.
Inżynieria pierwotna (greenfield engineering) — Tworzenie systemu „od zera". Patrz także
inżynieria wtórna, inżynieria interfejsu.
Inżynieria postępująca (forward engineering) — Proces zastosowania transformacji do
elementów modelu, dający w rezultacie odpowiedni fragment kodu źródłowego — deklaracje
klasy, wyrażenie lub schemat bazy danych. Przeciwieństwo inżynierii odwracającej.
Inżynieria wahadłowa (round-trip engineering) — Aktywność pielęgnowania modelu,
stanowiąca kombinację inżynierii postępującej i inżynierii odwracającej. Zmiany w imple-
mentacji propagowane są do modelu analitycznego i modelu projektu systemu w ramach
inżynierii odwracającej, zaś zmiany we wspomnianych modelach odzwierciedlane są w kodzie
źródłowym za pomocą inżynierii postępującej.
Inżynieria wtórna (reengineering) — Projekt, którego celem jest ponowne zaprojektowanie
lub ponowne zaimplementowanie systemu i towarzyszących mu procesów biznesowych.
Patrz także inżynieria pierwotna, inżynieria interfejsu.
Inżynieria wymagań (requirements engineering) — Aktywność obejmująca zbieranie
wymagań i ich analizę.
Issue-Based Information System — IBIS (Issue-Based Information System — IBIS) — Model
zagadnień zaproponowany przez Kunza Rittela, obejmujący trzy typy węzłów, reprezentujących
zagadnienia, propozycje (zwane „pozycjami" — position) i argumenty.
JAD — Patrz połączony projekt aplikacji
Jeden do jednego (one-to-one association) — Skojarzenie o krotności 1 na obu końcach.
Jeden na wiele (one-to-many association) — Skojarzenie o krotności 1 na jednym końcu i 0. .n
lub l . . n n a drugim.
Jednolity proces wytwarzania oprogramowania (Unified Software Development Process)
— Iteratywny model cyklu życiowego oprogramowania, charakteryzujący się czterema
fazami zwanymi Inception („prapoczątek"), Elaboration („opracowywanie"), Construction
(„tworzenie") i Transition („przenoszenie").
Jednoznaczne wymaganie (unambiguous requirement) — Patrz wieloznaczność.
Język imperatywny (imperative language) — Patrz język proceduralny.
B.1. Terminologia 793
Klient lokalny, samodzielny (local king client) — Klient pozostający w ścisłym kontakcie
z programistami, mający samodzielność decyzyjną i posiadający głęboką wiedzę z zakresu
dziedziny aplikacyjnej.
Klient pełnomocnik (proxy client) —- Uczestnik działający w imieniu rzeczywistego klienta,
posiadający wiedzę wystarczającą do wyjaśniania im problemów z dziedziny aplikacyjnej,
lecz niemający pełnej swobody decyzyjnej.
Klient-serwer (client!server architectural style) — Styl architektoniczny, zgodnie z którym
użytkownicy komunikują się, za pomocą prostych aplikacji, z centralnym programem
serwera świadczącego usługi.
Klucz główny (primary key) — W systemie zarządzania bazą danych — minimalny zbiór
atrybutów, z natury jednoznacznie identyfikujący poszczególne rekordy tabeli.
Klucz kandydacki (candidate key) — W systemie zarządzania bazą danych zbiór atrybutów,
który może być wykorzystywany w charakterze klucza głównego.
Klucz obcy (foreign key) — W systemie zarządzania bazą danych atrybut lub zbiór atry-
butów tabeli odwołujący się do klucza głównego innej tabeli.
Kluczowy obszar procesu (Key Process Area — KPA) — Zbiór aktywności zmierzających
do osiągnięcia celu uważanego za istotny dla osiągnięcia danego stopnia dojrzałości procesu.
Przykładami takich obszarów są zarządzanie konfiguracją, zarządzanie zmianami w wymaga-
niach i zarządzanie ryzykiem.
Kod źródłowy (source code) — Reprezentacja systemu w języku programowania.
Kolekcja OCL (OCL collection) — Abstrakcyjny typ języka OCL, reprezentujący grupę
obiektów.
Komitet kontrolny (change control board) — Zespół kontrolujący żądania zmian w postaci
formalnego procesu.
Kompletność (completeness) — Właściwość modelu określająca, czy wszystkie istotne
zjawiska zostały w modelowaniu uwzględnione w postaci odpowiednich koncepcji.
Komponent (component) — Fizyczna i zastępowalna część systemu, zgodna z określonym
interfejsem. Przykładami komponentów są biblioteki klas, frameworki i moduły binarne.
Komunikacja (communication) — Aktywność, w ramach której następuje wymiana infor-
macji między uczestnikami, w sposób synchroniczny lub asynchroniczny, spontanicznie
lub zgodnie z uprzednim planem.
Komunikacja partnerska (peer-based communication structure) — Struktura komunikacyjna,
w ramach której programiści należący do różnych zespołów komunikują się bezpośrednio.
Komunikat (message) — Mechanizm, za pomocą którego jeden obiekt żąda od innego
obiektu wykonania określonej operacji. Struktura komunikatu obejmuje jego nazwę i pewną
liczbę argumentów. Obiekt odbierający komunikat identyfikuje go z odpowiadającą mu
operacją, którą następnie wywołuje z użyciem argumentów otrzymanych w komunikacie.
Koncepcja (concept) — Abstrakcja zbioru zjawisk posiadających wspólne cechy. Przykładowo
ta książka, Fryderyk Chopin czy walijski klub wędkarzy to przykłady zjawisk, natomiast
książki o obiektowo zorientowanej inżynierii oprogramowania, kompozytorzy i kluby wędka-
rzy są przykładami koncepcji. Nie należy więc mylić koncepcji ze zjawiskami.
B.1. Terminologia 795
L i s k o v z a s a d a — P a t r z z a s a d a z a s t ę p o w a n i a Liskov.
Ł ą c z n i k (liaison) — R o l a k o m u n i k a c y j n a o d p o w i e d z i a l n a za p r z e p ł y w i n f o r m a c j i m i ę d z y
d w o m a zespołami. Przykładowo łącznik architektoniczny reprezentuje zespół f u n k c y j n y
przed zespołem architektonicznym.
M e t o d a (method) —- 1. W k o n t e k ś c i e t w o r z e n i a s y s t e m u — p o w t a r z a n a t e c h n i k a rozwiązy-
w a n i a specyficznego p r o b l e m u . P r z y k ł a d o w o p r z e p i s k u l i n a r n y s t a n o w i m e t o d ę s p o r z ą d z e n i a
o k r e ś l o n e j p o t r a w y 2. W k o n t e k ś c i e p r o g r a m o w a n i a o b i e k t o w e g o — i m p l e m e n t a c j a operacji.
P r z y k ł a d o w o S e t T i m e ( t ) jest m e t o d ą klasy Watch.
M e t o d o l o g i a (methodology) — K o l e k c j a m e t o d s ł u ż ą c y c h r o z w i ą z y w a n i u o k r e ś l o n e j klasy
p r o b l e m ó w . P r z y k ł a d o w o treść książki k u c h a r s k i e j dla c u k i e r n i k a jest m e t o d o l o g i ą w y p i e k u
ciast.
Model (model) — Abstrakcja systemu ułatwiająca jego zrozumienie poprzez pominięcie jego
szczegółów nieistotnych w danym kontekście. Przykładowo modelami systemu sprzedaży bi-
letów metra są: schemat okablowania dystrybutora biletów, podręcznik obsługi systemu
i model obiektowy jego oprogramowania.
Model akademicki (cathedral model) — Organizacja projektu opierająca się na planowaniu,
architekturze systemu i hierarchicznym przepływie informacji. Przykładem takiego modelu
jest organizacja głównego programisty. Przeciwieństwo modelu bazarowego.
Model analityczny (analysis model) — Model systemu, w założeniu poprawny, kompletny,
spójny i jednoznaczny. Model analityczny składa się z prostszych modeli — funkcjonalnego,
obiektowego i dynamicznego.
Model bazarowy (bazaar model) — Organizacja projektu oparta na dużej dynamice i rozpro-
szeniu współpracujących grup. Przeciwieństwo modelu akademickiego.
Model cyklu życiowego oprogramowania (software life cycle model) — Abstrakcja tworzenia
oprogramowania, której celem jest jego rozumienie, monitorowanie i kontrolowanie. Przy-
kładami modeli cyklu życiowego są model kaskadowy, V-model, model spiralny, jednolity
proces oraz model zagadnieniowy.
Model cyklu życiowego ukierunkowany na aktywności (activity-centered software life cycle
model) — Model cyklu życiowego oprogramowania reprezentujący przede wszystkim ak-
tywności związane z tworzeniem tego oprogramowania, w odróżnieniu od modelu cyklu
życiowego ukierunkowanego na encje.
Model cyklu życiowego ukierunkowany na encje (entity-centered software life cycle model)
— Model cyklu życiowego oprogramowania reprezentujący przede wszystkim produkty
wytwarzane w związku z realizacją projektu, w odróżnieniu od modelu cyklu życiowego
ukierunkowanego na aktywności.
Model dojrzałości organizacyjnej (Capability Maturity Model — CMM) — Framework
umożliwiający ocenę (pięciostopniową) stopnia dojrzałości organizacyjnej projektu.
Model dynamiczny (dynamie model) — Model opisujący te komponentu systemu, za pomocą
których manifestuje on swe zachowanie. W tej książce prezentujemy modele dynamiczne
w postaci diagramów stanów, diagramów sekwencji i diagramów aktywności.
Model funkcjonalny (functional model) — Model opisujący funkcjonalność systemu z per-
spektywy jego użytkownika. W tej książce reprezentujemy modele funkcjonalne w postaci
przypadków użycia.
Model katedralny — To samo, co model akademicki.
Model obiektowy (object model) — Model opisujący strukturę systemu w kategoriach
obiektów, atrybutów, skojarzeń i operacji. Na etapie zbierania i analizy wymagań model
obiektowy ma początkowo formę analitycznego modelu obiektowego, opisującego koncepcje
dziedziny aplikacyjnej odnoszące się do systemu. Na etapie projektowania systemu model
obiektowy rozszerzony jest do postaci modelu projektu systemu, obejmującej także opis
interfejsów poszczególnych podsystemów. Kolejnym etapem przeobrażenia modelu obiek-
towego jest model projektu obiektów, zawierający szczegółowy opis obiektów realizacyjnych.
798
Model projektu obiektów (object design model) — Szczegółowy model przedstawiający obiekty
aplikacyjne i obiekty realizacyjne będące częścią systemu. Zawiera szczegółowe definicje klas,
k o n t r a k t ó w , t y p ó w s y g n a t u r i z a k r e s ó w widzialności p o s z c z e g ó l n y c h a t r y b u t ó w i operacji.
QOC — Questions, Options, and Criteria — model zagadnień zaproponowany przez McLeana,
rozszerzający model IBIS o reprezentowanie informacji związanej z kryteriami i oceną
zagadnień.
Questions, Options, and Criteria — Patrz QOC.
Racjonalizacja (rationale) — W kontekście modelowania — uzasadnienie podejmowa-
nych decyzji. Przykładowo wybór myDBMS jako systemu zarządzania bazą danych to decyzja
związana z projektem systemu; argumenty, iż myDBMS jest niezawodny i wystarczająco reak-
tywny dla osiągnięcia celów projektowych, stanowią część racjonalizacji tej decyzji; nazywana
także racjonalizacją projektu.
RAD — Patrz dokument analizy wymagań.
Raportowanie statusu (status accounting) — W kontekście zarządzania konfiguracją —
śledzenie żądań zmian, aprobowanie propozycji zmian i kolekcjonowanie racjonalizacji
dla każdej zmiany.
Reaktywność (responsivity) — Zwana także responsywnością — własność systemu, mie-
rzona odwrotnością czasu odpowiedzi na żądanie użytkownika — krótki czas odpowiedzi
to duża reaktywność.
Redaktor dokumentu (document editor) — Rola związana z integrowaniem dokumentacji.
Redaktor racjonalizacji (rationale editor) — Rola odpowiedzialna za kolekcjonowanie i or-
ganizowanie informacji składającej się na racjonalizację.
Refaktoring — To samo, co refaktoryzacja.
Refaktoryzacja (refactoring) — Transformacja kodu źródłowego, wykonywana w celu po-
prawy jego czytelności lub modyfikowalności, bez wpływu na zachowanie systemu. Re-
faktoryzacja zmierza do poprawienia projektu działającego systemu poprzez koncentrowanie
się na wybranych polach lub metodach poszczególnych klas.
Reinżynieria — To samo, co inżynieria wtórna
Relacja „ogół-szczegóły" (generalization-specialization relationship) — Patrz relacja
dziedziczenia.
Relacja dziedziczenia (inheritance relationship) — Relacja wiążąca klasę ogólną z klasą
bardziej wyspecjalizowaną. Specjalizacja klasy dokonuje się poprzez dodanie semantyki
i funkcjonalności do klasy ogólnej. Klasa ogólna nazywana jest w tym kontekście superklasą,
zaś klasa specjalizowana — subklasą.
Relacja rozszerzania (extend relationship) — Relacja między przypadkami użycia, zgodnie
z którą jeden przypadek użycia stanowi rozszerzenie przepływu zdarzeń w ramach drugiego.
Relacje rozszerzania wykorzystywane są zwykle do modelowania zachowań wyjątkowych,
takich jak pomocnicze elementy funkcjonalne czy obsługa wyjątków.
Relacja zawierania (include relationship) — Relacja między przypadkami użycia, zgodnie
z którą jeden przypadek użycia dokonuje wywoływania innego. Wywołanie to jest analogią
wywołania metody w języku programowania.
Repozytorium (repository) — 1. W kontekście architektury repozytoryjnej — centralny
podsystem odpowiedzialny za zarządzanie trwałymi danymi. 2. W kontekście zarządzania
konfiguracją — biblioteka emisji.
806 Dodatek B • Objaśnienia haseł
R e s p o n s y w n o ś ć — T o s a m o , co r e a k t y w n o ś ć R o l a (role) — 1. W k o n t e k ś c i e o r g a n i z a c j i
— z a k r e s o d p o w i e d z i a l n o ś c i w r a m a c h p r o j e k t u , p r z y p i s y w a n y o s o b i e l u b zespołowi. D a n a
o s o b a m o ż e w y p e ł n i a ć kilka ról. P r z y k ł a d a m i ról są: analityk, a r c h i t e k t s y s t e m u , tester, p r o -
g r a m i s t a , m e n e d ż e r i w e r y f i k a t o r . 2. W k o n t e k ś c i e s k o j a r z e ń — ł a ń c u c h z n a k ó w o k r e ś l a j ą c y
z n a c z e n i e k l a s y dla s k o j a r z e n i a , w k t ó r e jest u w i k ł a n a .
R o l a m e n e d ż e r s k a (management role) — K a ż d a r o l a z w i ą z a n a z p l a n o w a n i e m , m o n i t o r o -
w a n i e m i k o n t r o l o w a n i e m p r o j e k t u . P r z y k ł a d a m i r ó l m e n e d ż e r s k i c h są m e n e d ż e r p r o j e k t u
i kierownik zespołu. Patrz także zarządzanie projektem.
R o l a m i ę d z y f u n k c y j n a (cross-functional role) — K a ż d a r o l a z w i ą z a n a z k o o r d y n o w a n i e
pracy kilku zespołów. Przykłady takich ról to m e n e d ż e r konfiguracji, łącznik architekto-
niczny, tester i redaktor dokumentacji.
R o z s t r z y g n i ę c i e (resolution) — P r o p o z y c j a w y b r a n a p r z e z u c z e s t n i k ó w w celu z a m k n i ę c i a
zagadnienia.
R o z w i d l e n i e (fork node) — N a d i a g r a m i e a k t y w n o ś c i U M L w ę z e ł k o n t r o l n y r e p r e z e n t u j ą c y
rozszczepienie sterowania n a kilka wątków.
R y z y k o (risk) — O b s z a r n i e p e w n o ś c i m o g ą c e j p r o w a d z i ć d o r o z b i e ż n o ś c i p r o j e k t u z p l a n e m
— opóźnień w harmonogramie, niespełnienia wymagań, przekroczenia budżetu i tym po-
d o b n y c h , a w k o n s e k w e n c j i załamania całego projektu.
S c e n a r i u s z (scenario) — I n s t a n c j a p r z y p a d k u użycia. S c e n a r i u s z r e p r e z e n t u j e k o n k r e t n ą
sekwencję interakcji między systemem a j e d n y m lub kilkoma aktorami.
Zdolność dostępu (capability) — Reprezentacja macierzy kontroli dostępu w formie listy par
(klasa-operacja) stowarzyszonej z aktorem. Każda ze wspomnianych par oznacza uprawnienie
tegoż aktora do wykonywania konkretnej operacji na konkretnej klasie. Materialnymi odpo-
wiednikami zdolności dostępu są: klucz do zamka, karta inteligentna i bilet do teatru.
Zebranie (meeting) — Synchroniczny mechanizm komunikacyjny obejmujący prezentowanie,
dyskutowanie, negocjowanie i rozstrzyganie zagadnień przez uczestników, w formie osobistego
spotkania, telefonicznej rozmowy wielostronnej lub wideokonferencji.
Zebranie statusowe (status meeting) — Planowe zdarzenie komunikacyjne, w ramach którego
kierownik zespołu monitoruje status prac prowadzonych przez ten zespół.
Zebranie uruchamiające projekt (kick-off meeting) —- Zebranie wszystkich uczestników
projektu oznaczające formalny koniec fazy inicjacyjnej projektu i wejście projektu w fazę
ustaloną.
Zespół (team) — Grupa uczestników wspólnie rozwiązujących problem projektowy.
Zespół funkcyjny — To samo, co zespół podsystemu.
Zespół międzyfunkcyjny (cross-functional team) — Zespół odpowiedzialny za wspieranie
zespołu funkcyjnego w wykonywaniu przezeń aktywności międzyfunkcyj nych, takich jak
zarządzanie konfiguracją, integrowanie i testowanie.
Zespół podsystemu (subsystem team) — Zespół odpowiedzialny za opracowanie danego
podsystemu. Przeciwieństwo zespołu międzyfunkcyjnego.
Zjawisko (phenomenon) — Fragment rzeczywistości postrzegany z perspektywy modelowania
jako obiekt. Modelowanie sprowadza się do wyboru zjawisk interesujących w danym kontek-
ście, identyfikowania ich wspólnych cech i abstrahowania tych zjawisk w formie koncepcji.
Złączenie (join node) — Na diagramie aktywności UML — węzeł kontrolny reprezentujący
synchronizację wielu wątków do jednego wątku.
Zmiana (change) — Adaptacja wybranego aspektu systemu, na przykład dodanie lub zmody-
fikowanie wymagania albo zastąpienie jednego komponentu innym. Patrz także delta.
Żądanie wyjaśnień (request for clarification) — Pozaplanowe zdarzenie komunikacyjne,
polegające na żądaniu przez uczestników dodatkowych informacji.
Żądanie zmiany (change request) — Pozaplanowe zdarzenie komunikacyjne, związane
z propozycją uczestnika dotyczącą zmodyfikowania pewnej cechy produktu lub dodania
nowej. W zarządzaniu konfiguracją — formalny raport żądający zmodyfikowania elementu
konfiguracji.
D ^ Clnmnil/ łnrmlnńin
u.z. MowniK terminów angieisKicn
action — Akcja
activity — Aktywność
#
application object - Obiekt aplikacyjny
branch — Gałąź
CM aggregate — Agregat CM
consistency — Spójność ^
control node - Węzeł kontrolny
control object - Obiekt sterujący
decision Decyzja
error — Błąd
event — Zdarzenie
event class — Klasa zdarzeniowa
event-driven control — Sterowanie oparte na zdarzeniach
exception - Wyjątek
failure - Awaria
falsification - Falsyfikacja
fault - Usterka
fork node — R o z w i d l e n i e
layer — Warstwa
object — Obiekt
performance — Wydajność
performance criterion — Kryterium wydajnościowe
performance testing — Testowanie wydajnościowe
persistent data — Trwałe dane
PERT chart — P E R T
phase — Faza
phenomenon — Zjawisko
pilot testing — Testowanie pilotażowe
pipe and filter architectural style — Filtry i p o t o k i
portability — Przenośność
postcondition — Warunek końcowy
postmortem review — Post mortem
precondition — Warunek wstępny
primary facilitator — Główny facilitator
primary key — Klucz główny
problem definition — Definiowanie problemu
problem domain — Dziedzina problemowa
problem inspection — Inspekcja problemu
problem presentation — Prezentacja problemu
problem solving — Rozwiązywanie problemu
process group — Grupa procesów
process management — Zarządzanie procesami
prototyping Prototypowanie
reporting structure — Struktura raportowania
repository — Repozytorium
repository architectural style — Architektura repozytoryjna
responsivity — Reaktywność
reviewer — Weryfikator
risk — Ryzyko
role - Roia
security — Zabezpieczenie
828 Dodatek B • Objaśnienia haseł
service — Usługa
stereotype — Stereotyp
task - Zadanie
task model- Model zadań
technical writer — D o k u m e n t a l i s t a
thread - Wątek
transition — Frzejscie
tupie — Krotka
type- Typ
Bibliografia
[Curtis i in., 1988] B. Curtis, H. Krasner, N. Iscoe Afield study of the software
design process for large systems, „Communications of the
ACM", t. 31, n r 11, str. 1268 - 1287, 1988.
[Gleick, 1987] J. Gleick Chaos — Making a New Science, Penguin Books Ltd,
Harmondsworth, Middlesex, 1987.
IEEE Std. 982.2-1988] IEEE Guide for the Use of IEEE Standard Dictionary of Measures
to Produce Reliable Software, IEEE Standards Board,
czerwiec 1988.
IEEE/EI A, 1996] IEEE/EIA 12207.0-1996, Industry Implementation of
International Standard ISO/IEC 12207:1995 Standard for
Information Technology — Software life cycle processes,
IEEE Computer Society & Electronic Industries Association,
marzec 1998.
Javadoc, 2009b] Sun Microsystems, How to write doc comments for Javadoc,
http://java.sun.com/j2se/javadoc/writingdoccomments/.
[Lions, 1996] J. L. Lions ARIANE 5 Flight 501 Failure: Report by the Inquiry
Board, http:/'/www.esrin.esa.it/htdocs/tidc/Press/Press96/
ariane5rep.html, 1996.
[Liskov i Guttag, 1986] B. Liskov, J. Guttag Abstraction and Specification in Program
Development, McGraw-Hill, New York, 1986.
[Liskov, 1988] B. Liskov Data abstraction and hierarchy, „SIGPLAN
Notices", t. 23, nr 3, m a j 1988.
[Lotus] Lotus http://www.lotus.com/.
L. Macaulay Requirements Engineering, Springer-Verlag,
[Macaulay, 1996] London, 1996.
A. MacLean, R. M. Young, V. Bellotti, T. Moran Questions,
[MacLean i in., 1991] options, and criteria: Elements of design space analysis,
„ H u m a n - C o m p u t e r Interaction", t.6, str. 201 - 250,1991.
[Mellor i Shlaer, 1998] S. Mellor, S. Shlaer Recursive Design Approach, Prentice Hall,
Upper Saddle River, NJ, 1998.
[Meyer, 1997] B. Meyer Object-Oriented Software Construction, wyd. drugie,
Prentice Hall, Upper Saddle River, NJ, 1997.
[Microsoft] Microsoft http://www.microsoft.com/.
[MIL Std. 480] MIL Std. 480, U.S. Department of Defense, Washington, DC.
[Miller, 1956] G. A. Miller The magical number seven, plus or minus two:
Some limits on our capacity for processing information,
„Psychological Review", t. 63, str. 81 - 97, 1956.
[Minsky, 1975] M. Minsky „A f r a m e w o r k for representing knowledge,"
w P. Winston (red.) The Psychology of Computer Vision,
McGraw-Hill, 1975.
[Moran i Carroll, 1996] T. P. Moran, J. M. Carroll (red.) Design Rationale: Concepts,
Techniques, and Use, Lawrence Erlbaum Associates, Mahwah,
NJ, 1996.
[Takeuchi i Nonaka, 1986] H. Takeuchi, I. Nonaka The New New Product Development
Game, „Harward Business Review", 1986.
[Taylor, 1911] F. W. Taylor The Principles of Scientific Management, Harper
Bros., New York, 1911.
[Telelogic] Telelogic, http://www. telelogic.se.
@see, 429 aktywności, 43, 47, 68, 100, 124, 640, 689
«boundary», 106 partycje aktywności, 103
«control», 106, 216 aktywności analizy wymagań, 217
«create», 224 aktywności etapu projektowania systemu, 305
«entity», 106 aktywności inżynierii oprogramowania, 49
« extent», 106 analiza, 51
«include», 106 implementowanie, 53
«invariant», 408 projekt systemu, 51
«postcondition», 408 projektowanie obiektów, 53
«precondition», 408 testowanie, 54
«sut», 540 zbieranie wymagań, 50
«testCase», 540 aktywności klasycznego zarządzania projektem, 653
«testComponent», 540 aktywności organizacyjne, 146
«testContext», 540 dołączanie do infrastruktury komunikacyjnej, 146
«testObjective», 540 dołączanie do zespołu, 146
udział w zebraniach zespołu, 147
aktywności projektowania systemu, 288, 303
A aktywności racjonalizacji, 567
aktywności realizacji celów projektowych, 306
Abstract Factory, 772 aktywności specyfikowania interfejsów, 416
Abstract Window Toolkit, 276 aktywności zbierania wymagań, 166
abstrakcyjne typy danych, 72 aktywności „zwinnej" realizacji projektu, 673
action items, 561, 646 aktywny przegląd projektu, 507
activities, 640, 646 ALAP, 650
activity-centered, 685 Albrecht A. J., 666
Ada, 606 alfa-testowanie, 530
adaptacyjne tworzenie oprogramowania, 737 algorytm szyfrowania, 318
Adapter, 365, 366, 371,773 alternatives, 551
delegowanie, 373 Ambler S., 739, 771
dziedziczenie, 373 analityczny model obiektowy, 64, 213, 214, 401
Adaptive Software Development, 737 analityk, 239
adaptowalność, 162 analiza, 48,49,51,212
agenda przeglądu klienckiego, 131 analiza opisu przypadków użycia, 219
agenda spotkania, 142 analiza wymagań, 159, 211, 236
agile, 637, 673 aktywności, 217, 237
Agile Alliance Manifesto, 737 analityczny model obiektowy, 214
agregacja, 92, 231 ARENA, 245
agregacja współdzielona, 231 cele, 212
kompozycyjna, 231 diagramy sekwencji, 224
agregat CM, 602, 603 dokument analizy wymagań, 238
agregat zarządzania konfiguracją, 602 dokumentowanie, 238
Airbus A320, 598 identyfikacja agregacji, 231
akceptacja systemu, 672 identyfikacja atrybutów, 232
akcje, 99 identyfikacja obiektów brzegowych, 220, 250
aktorzy, 79, 80 identyfikacja obiektów encji, 218, 245
848 Skorowidz
Beck K., 228, 258, 485, 633, 725 Carr M. J., 669
Beedle M., 674, 678, 725 Carroll J. M., 169, 205, 592
benchmark test, 530 CASE, 55, 452, 748
Bersoff E. H., 602 Catalysis, 49
beta-testowanie, 526, 530 cechy specyfikacji, 164
bezpieczeństwo, 36,162, 290, 568 cele analizy, 212
biblioteka, 603, 606 cele projektowe systemu, 290
biblioteka dynamiczna, 606 cele testowania, 540
biblioteka kontrolowana, 606 Centralized Traffic Control, 555
biblioteka statyczna, 606 Champty J., 166
biblioteki klas, 383 change request, 602
bieżące kolekcjonowanie racjonalizacji, 553 change set, 608
big-bang testing, 521 chaordic system, 766
Binder R. V., 542 Charette R. N., 669
Birrer E. T., 382 chief programmer organization, 679
blackboard systems, 280 Christerson M., 107
blackbox tests, 504 chroniona operacja, 405
Błaha M., 311, 348, 449, 472 chroniony atrybut, 405
blueprint, 46 chronometrażysta, 142
błąd roku 1900, 36 Chung L., 565
błąd roku przestępnego, 36 ciągi, 411,413
błędny stan, 494, 499, 500, 502 C l asS) Responsibilities i Collaborators, 228
błędy, 368,494 ClearCase, 610, 611
błędy w oprogramowaniu, 324 Clements P., 297, 348
BNF 6 0 9
> CM aggregate, 602
Boehm B., 590, 669, 677, 687, 701 C M M j 695
Booch G., 107,108,162, 215, 703 Cockburn A., 173, 206, 725, 737
Borghoff U. W., 151 Cocoa, 378
Borning A., 440 COCOMO II, 677, 727
bottom-up testing, 521, 522 C o h n M > 67?5 7 3 8
brak klienta, 718 Collection, 74
breakage, 668 Command, 775
Bridge, 368, 774 competitor testing, 530
Brooks F. P., 664, 678 Composite, 776
Brown W. J., 771 Computer Aided Software Engineering, 55
Bruegge B., 382 Concurrent Version System, 611, 633
brygady tygrysów, 529 configuration, 602
BSCW, 145 configuration item, 602
bucket theory of the mind, 41 configuration management aggregate, 602
budowanie infrastruktury, 643 Conklin J 592
budowanie wieloetapowe, 631 consequent issues, 557
budzet, 36 Constantine L. L., 107, 206, 296
bus 494
continuus integration, 630
Burgess-Yakemovic K. C„ 592 Contracts 440
buried association, 472 CORBA, 276, 277, 283
burn down chart, 676
core use cases, 703
burza mózgów, 133, 228, 241, 242, 333
° correction, 499
Buschmann F., 296, 394, 771 CRC 22g
criteria, 552
(] critical path, 649
cross reference, 429
cache'owanie wyników czasochłonnych obliczeń, 457 CruiseControl, 631
callback, 285, 383 Crystal Clear, 737
całościowe zarządzanie jakością, 740 CTC, 555, 568
Campbell R. H., 382 kontrola dostępu, 583
Capability Maturity Model, 632, 695 opis systemu, 569
850 Skorowidz
instancja klasy, 74
instancje aktorów uczestniczących, 86 J
int, 72 JAA, 599
integracja ciągła, 630, 633 Jacobson I., 107, 108, 162, 205, 215, 709
integrowanie, 553 JAD, 160, 185
integrowanie pionowe, 521, 525 agenda sesji, 185
integrowanie poziome, 521 badania, 185
interakcje między uczestnikami projektu, 120 definiowanie projektu, 185
interdyscyplinarność, 22 dokument końcowy, 185
interfejs API, 123 przygotowania, 185
interfejs podsystemów, 270 sesja, 185
interfejs programisty, 270, 357 słownik menedżera, 185
interfejs użytkownika, 378 wstępna specyfikacja, 185
interfejs wzorca, 365 wywiady, 185
interfejsy, 285, 399 JAMES, 136, 743, 754, 762
internacjonalizacja, 162 aktywności, 757
internal work products, 648 cel projektu, 754
intersection(), 414 iteracje, 756
inv:, 415 kontrola, 759
inżynier API, 123 modelowanie, 756
inżynieria, 35 planowanie, 755
inżynieria interfejsu, 165 powtarzalność, 756
inżynieria odwracająca, 427, 449, 452, 706 procesy cyklu życiowego, 757
inżynieria oprogramowania, 35, 38, 266, 716 środowisko projektu, 755
aktywności, 49 wnioski, 760
koncepcje, 43 wynik, 760
modelowanie, 38, 39 Java, 72, 258, 269
niepowodzenia, 36 klasy abstrakcyjne, 74
pozyskiwanie wiedzy, 38, 41 Java RMI, 276, 283
proces sterowany racjonalizacją, 38 JavaCard, 758
racjonalizacja, 42 Javadoc, 429, 440
rozwiązywanie problemów, 38, 40 j Contractor, 440
inżynieria pierwotna, 165 jeden do jednego, 90
inżynieria postępująca, 427, 448, 452, 706 jeden na wiele, 90
inżynieria wahadłowa, 706 jednokierunkowe skojarzenia „jeden do jednego", 459
inżynieria wtórna, 165 jednolity proces, 532, 725
inżynieria wymagań, 157 jednolity proces wytwarzania oprogramowania, 703
inżynierskie przepływy pracy, 704 jednostki pracy, 640
Islam N., 382 jednoznaczność specyfikacji, 164
issue, 551 Jensen R. W., 687
język
Issue-Based Information System, 562, 563 Ada, 606
issue-based life cycle model, 707 Eiffel, 440
iteracje modelu analitycznego, 241 Java, 72
burza mózgów, 242 język z wbudowaną kontrolą typów danych, 72
dojrzewanie, 242 OCL, 107, 359, 407
ustalanie, 242 SQL, 470
iteracje projektowania systemu, 333 UML, 43, 63, 64
iteracyjne modele ukierunkowane na aktywności, 701 Johnson R., 283
jednolity proces wytwarzania oprogramowania, Joint Application Design, 160,185
703 Jones T. C., 496
model spiralny, 701 Jonsson P., 107
iteracyjne planowanie, 738 JUnit, 538, 539
Skorowidz 855
866 Skorowidz
testy na dym, 632 UML, 21, 43, 63, 64, 65, 78, 607
testy objętościowe, 529 diagramy aktywności, 68, 79, 101
testy odtwarzania, 530 diagramy interakcji, 64, 67, 79, 95
testy pilotażowe, 530 diagramy klas, 64, 65, 78, 86
testy polowe, 530 diagramy przypadków użycia, 64, 65, 78, 79
testy produktu, 509 diagramy sekwencji, 67
testy prototypu, 509 diagramy stanów, 67, 79, 98
testy przeciążeniowe, 529 diagramy wdrażania, 304
testy regresyjne, 537 dziedziczenie, 93
testy scenariusza, 508 klasy, 75
testy tripletowe, 520 komponenty fizyczne, 269
testy uwarunkowań czasowych, 529 komponenty logiczne, 269
testy wzorcowe, 530 krotność, 90
TEX, 607 maszyna stanu, 98
tępe zliczanie, 684 model dynamiczny, 64
ThingLab, 440 model funkcjonalny, 64
Thompson K., 287 model obiektowy, 64
Tichy W., 633, 771 modelowanie, 63
TicketDistributor, 44 notacja, 71
aktywności, 47 notatki, 105
dekompozycja systemu, 53 obiekty, 74
model dynamiczny systemu, 51, 52 ograniczenia, 106
model obiektowy systemu, 52 organizacja diagramów, 104
produkty, 46 pakiety, 104
przypadki użycia, 51 rozszerzenia diagramów, 106
PurchaseOneWayTicket, 51 skojarzenia, 88
role, 45 stereotypy, 106
zadania, 47 tory pływackie, 103
zasoby, 47 U2TP, 539
TIR, 535 widzialność elementu, 406
tolerowanie usterek, 495 UML 2 Testing Profile, 539
Tonies C. C., 687 umowa projektu, 642, 664
top-down testing, 521, 522 Unified Modeling Language, 48
tory pływackie, 103 Unified Process, 162, 532, 703, 725
Total Quality Management, 740 Unified Software Development Process, 49, 166, 703
TP, 497 unikanie usterek, 495
TQM, 740 union(), 414
transformacja modelu, 447, 448, 449 unit testing, 510
dokumentowanie, 475 Universal Modeling Language, 21,43, 63
zarządzanie transformacjami, 475 UNIX, 287
zasady, 453 uprząż testowa, 539
trwałe dane, 303, 309 URPS, 163
Turner C. D.,516 uruchamianie na sucho, 150
tworzenie oprogramowania, 54 uruchamianie projektu, 643
tworzenie systemu, 692 usługi, 267, 270, 321,343
typ klienta, 717 usterki, 494, 499, 500
typed languages, 72 usterki maszyny wirtualnej, 502
typy atrybutów, 404 usterki wykryte podczas inspekcji kodu, 125
typy danych, 72 usterki wykryte podczas testowania, 125
utrzymanie systemu, 54
uwierzytelnianie, 313, 317
U uzgodnienie modelu analitycznego z klientem, 243
U2TP, 539, 540 uzgodnienie umowy projektu, 642
uczestnicy, 43,44, 116, 640 użyteczność, 158, 162, 568
udział w zebraniach zespołu, 147 użytkownik, 124, 239
użytkownik klasy, 403
868 Skorowidz
Notacje
D i a g r a m U M L a k t y w n o ś c i (68, 101) — r e p r e z e n t u j e z a c h o w a n i e g r u p y o b i e k t ó w w kategoriach ich ak-
tywności i z m i a n s t a n ó w .
D i a g r a m U M L klas (65, 86) — r e p r e z e n t u j e s t r u k t u r ę s y s t e m u w kategoriach p o d s y s t e m ó w , klas, atrybu-
tów, operacji i skojarzeń.
D i a g r a m U M L p r z y p a d k ó w u ż y c i a (65, 79) — r e p r e z e n t u j e f u n k c j o n a l n o ś ć s y s t e m u z p e r s p e k t y w y
aktora.
D i a g r a m U M L s e k w e n c j i (67, 95) — r e p r e z e n t u j e z a c h o w a n i e j a k o ciąg i n t e r a k c j i m i ę d z y o b i e k t a m i
określonej grupy.
D i a g r a m U M L s t a n ó w (67, 98) — r e p r e z e n t u j e z a c h o w a n i e p o j e d y n c z e g o o b i e k t u w kategoriach s t a n ó w
i przejść a u t o m a t u skończonego.
D i a g r a m w d r a ż a n i a U M L (304) — r e p r e z e n t u j e o d w z o r o w a n i e k o m p o n e n t ó w p r o g r a m u w w ę z ł y
sprzętowe.
G r a f P E R T (126) — r e p r e z e n t u j e p o d z i a ł p r a c y n a z a d a n i a i u w a r u n k o w a n i e c z a s o w e m i ę d z y t y m i
zadaniami.
M o d e l e z a g a d n i e ń (562) — r e p r e z e n t u j ą u z a s a d n i e n i e p o d e j m o w a n y c h d e c y z j i w k a t e g o r i a c h z a g a d -
nień, propozycji, a r g u m e n t ó w , kryteriów i rozstrzygnięć.
Przykładowe systemy
2 B W a t c h i SatWatch (161) 2BWatch jest zegarkiem c y f r o w y m p o s i a d a j ą c y m d w a przyciski. SatWatch
jest z e g a r k i e m s y n c h r o n i z u j ą c y m swe wskazanie z lokalną strefą czasową za p o m o c ą s y s t e m u
GPS, nie p o s i a d a j ą c y m ż a d n e j możliwości s t e r o w a n i a p r z e z u ż y t k o w n i k a — u ż y t k o w n i k m o ż e
jedynie odczytywać w s k a z a n i e czasu. O b a te systemy są proste, lecz wystarczająco d o w p r o w a -
dzenia w k o n c e p c j ę zbierania w y m a g a ń .
A R E N A (190, 245, 334, 390, 433, 478) to wieloużytkowy system webowy służący organizowaniu i rozgry-
w a n i u t u r n i e j ó w . System niezależny jest o d k o n k r e t n e j gry w t y m sensie, że jej autorzy, p o przy-
s t o s o w a n i u jej interfejsu d o w y m o g ó w systemu, m o g ą wysłać tę grę n a serwer i n a t y c h m i a s t zor-
g a n i z o w a ć turniej, o b e j m u j ą c y graczy i kibiców r o z p r o s z o n y c h w internecie. O r g a n i z a t o r z y
m o g ą wykorzystywać istniejące i d e f i n i o w a ć n o w e style rozgrywek, różniące się z a s a d a m i przy-
działu graczy d o poszczególnych meczów oraz decydowania o zwyc i ę s twi e. Elementem systemu są
m e c h a n i z m y r e k l a m o w e , u m o ż l i w i a j ą c e o p e r a t o r o m s y s t e m u r e k o m p e n s o w a n i e k o s z t ó w dzia-
łalności, poprzez płatne wyświetlanie b a n e r ó w dostarczonych przez zainteresowanych sponsorów.
System A R E N A zrealizowany został we w s p ó ł p r a c y U n i w e r s y t e t u T e c h n i c z n e g o w M o n a c h i u m
i U n i w e r s y t e t u w O t a g o w N o w e j Zelandii w latach 2002 i 2003.
C T C (568) p o w s t a ł w związku z m o d e r n i z a c j ą k o m u n i k a c j i miejskiej w Stuttgartcie, polegającą n a
s t o p n i o w y m z a s t ę p o w a n i u t r a m w a j ó w koleją miejską. U m o ż l i w i a scentralizowane s t e r o w a n i e
r u c h e m z p o z i o m u licznych nastawni, kontrolujących poszczególne sekcje komunikacyjne. W tej
książce wykorzystaliśmy m e c h a n i z m y k o n t r o l i d o s t ę p u o b o w i ą z u j ą c e w t y m systemie, j a k o ilu-
strację m e t o d z a r z ą d z a n i a racjonalizacją.
FRIEND (167, 219) to rozproszony system zarządzania sytuacjami kryzysowymi. Umożliwia f u n k c j o n a -
riuszom w terenie, d y s p o zyt o r o wi i a d m i n i s t r a c j i f e d e r a l n e j k o m u n i k o w a n i e się w celu przy-
działu z a s o b ó w d o obsługi i n c y d e n t u . System FRIEND jest n i e p o r ó w n a n i e bardziej z ł o ż o n y niż
systemy 2BWatch i SatWatch; jest o n p r z y k ł a d e m tego, jak zbieranie w y m a g a ń i m e t o d y ich a n a -
lizy skalują się d o rzeczywistych sytuacji. Z r e a l i z o w a n y został n a Uniwersytecie Carnegie M e l l o n
w latach 1992 - 1994.
m y C a r P a r t s (611) to w e b o w y katalog s a m o c h o d o w y c h części z a m i e n n y c h . U m o ż l i w i a przeglądanie,
w y s z u k i w a n i e i z a m a w i a n i e o k r e ś l o n y c h części z a r ó w n o w s p o s ó b u p r o s z c z o n y , p r z y d a t n y dla
nowicjuszy, jak i w s p o s ó b ekspercki, p r z y d a t n y p r o f e s j o n a l n y m m e c h a n i k o m . W y k o r z y s t a l i ś m y
t e n system j a k o ilustrację m e t o d a zarządzania k o n f i g u r a c j ą . System myCarParts z a i n s p i r o w a n y
został s y s t e m e m P A I D , r e a l i z o w a n y m we w s p ó ł p r a c y U n i w e r s y t e t u C a r n e g i e Mellon i U n i w e r -
sytetu T e c h n i c z n e g o w M o n a c h i u m w latach 1998 i 1999.
m y T r i p (288) jest s y s t e m e m w s p o m a g a j ą c y m p a n o w a n i e p o d r ó ż y i u m o ż l i w i a j ą c y m p o b i e r a n i e zdal-
nie z a p a m i ę t a n y c h tras d o k o m p u t e r a p o k ł a d o w e g o s a m o c h o d u , k t ó r y to k o m p u t e r p r o w a d z i
n a s t ę p n i e kierowcę d o celu. System ten jest w y n i k i e m inspiracji s y s t e m e m JAMES, k t ó r y realizo-
w a n y był we w s p ó ł p r a c y U n i w e r s y t e t u C a r n e g i e M e l l o n i U n i w e r s y t e t u T e c h n i c z n e g o w M o n a -
c h i u m w latach 1997 i 1998. System myTrip w y k o r z y s t a l i ś m y n a p o t r z e b y zilustrowania m e t o d
p r o j e k t o w a n i a systemu.