Śledzenie zależności pozwala określać relacje pomiędzy różnymi artefaktami (wymaganiami, elementami modelu, dokumentacji, implementacji) tworzonymi podczas cyklu rozwoju oprogramowania. W rozdziale omówiono różne rozwiązania problemów śledzenia zależności. Przedstawiono koncepcję polegającą na identyfikacji obszarów zależności (zbiorów zależnych elementów) związanych z wymaganiami lub elementami modelu UML. Uwzględniono problemy niespójności i niekompletności projektów UML w odniesieniu do śledzenia zależności. Odpowiadające fragmenty kodu są przypisywane do zależnych elementów podczas generacji kodu. Technika ta może wspomagać wybór kodu dla eksperymentów z programowymi symulatorami błędów sprzętowych lub dla innych analiz programów obiektowych.
Spis treści
- Śledzenie propagacji zależności w projekcie obiektowym
- 1. Wstęp
- 2. Motywacja – eksperymenty SWIFI
- 3. Strategie śledzenia zależności
- 4. Koncepcja śledzenia zależności w projekcie obiektowym
- 4.1. Struktura projektu
- 4.2. Podstawowe pojęcia
- 4.3. Identyfikacja regionu zależności
- 4.4. Przypisywanie fragmentów kodu
- 5. Środowisko wspomagające śledzenie zależności
- 6. Podsumowanie
- Bibliografia
1. Wstęp#
Śledzenie zależności (ang. traceability) pomiędzy różnymi artefaktami projektu zyskuje coraz bardziej na znaczeniu w procesie rozwoju oprogramowania [EBNE2000, EGYE2003, INSF2002, SPAN2002]. Zagadnienie to zajmuje się śledzeniem zależności pomiędzy wszystkimi elementami, od celów wymagań i odpowiedzialności, przez różne fazy modelowania, dokumentację, przypadki testowe, aż do implementacji w kodzie (oraz w odwrotnym kierunku od kodu do wymagań). Może ono wspomagać zrozumienie modelu, jego transformację, generację kodu, inżynierię odwrotną (ang. reverse engineering), weryfikację spójności oraz utrzymanie (pielęgnację) oprogramowania.Ten rozdział poświęcony jest identyfikacji zbiorów zależnych elementów dla danego artefaktu w projekcie obiektowym. Rozpatrywanym artefaktem może być wymaganie lub dowolny element z różnych faz rozwoju modelu programu. Korzystając z propagacji relacji śledzenia, określany jest zbiór zależnych elementów modelu. Zbiór jest ograniczany o ile dostępne są bardziej precyzyjne relacje pomiędzy elementami modelu. Biorąc pod uwagę elementy, które mają bezpośredni wpływ na generowany kod, wybrane obszary implementowanego kodu są przypisywane do danych artefaktów.
Identyfikacja wymaganych obszarów kodu wspomaga przygotowanie programu do eksperymentów wstrzykiwania błędów. Eksperymenty te pozwalają wyznaczyć wpływ zmian wymagań lub elementów modelu na odporność badanego programu na błędy.
Omawiane podejście oparte na śledzeniu zależności jest przeznaczone dla programów obiektowych modelowanych w języku UML [WWW2003a]. Reguły propagacji śledzenia korzystają z pojęć śledzenia obecnych w modelach UML oraz wspomaganych przez narzędzia typu CASE. Zalecana struktura modelu powinna spełniać wymogi systematycznego modelowania np. zgodnego z metodyką RUP (Rational Unified Process) [KRUC2000]. Projekty jednak często nie są w praktyce zgodne z bardzo sztywnymi zasadami, dlatego strategia śledzenia zależności powinna uwzględniać obecność niespójnych i niekompletnych relacji.
Struktura rozdziału jest następująca. Po zaprezentowaniu motywacji dla niniejszej pracy, omówiono problemy śledzenia zależności oraz przykładowe rozwiązania. Następnie przedstawiona jest proponowana koncepcja śledzenia. Punkt 5. prezentuje architekturę środowiska wspierającego omawiane podejście. Na zakończenie podano uwagi o innych możliwościach zastosowań.
2. Motywacja – eksperymenty SWIFI#
Wśród technik badania wiarygodności systemów za pomocą wstrzykiwania błędów wyróżniamy trzy podstawowe podejścia: wymuszanie błędów sprzętowych w rzeczywistym systemie, analizę symulowanego modelu systemu oraz wprowadzanie błędów symulowanych do rzeczywistego systemu. Dwa pierwsze rozwiązania, chociaż dostarczają wartościowych rezultatów, wiążą się z istotnymi ograniczeniami (trudność wprowadzania i obserwacji błędów dla współczesnych układów wysokiego stopnia integracji, koszt realizacji wiarygodnych symulatorów systemów). Najbardziej elastyczne i obiecujące jest ostatnie podejście – wykorzystanie programowo implementowanych symulatorów błędów (ang. SWIFI Software Implemented Fault Injector) [SOSN2003]. Techniki SWIFI pozwalają modelować błędy fizyczne różnych bloków funkcjonalnych systemu docelowego. Mogą być również użyte dla emulacji i analizy błędów oprogramowania [MADE2000]. W każdym przypadku eksperymenty wstrzykiwania błędów służą do weryfikacji odporności aplikacji na błędy, określenia słabych punktów badanego projektu i ich naprawy.Narzędzia SWIFI wykorzystują zwykle instrukcję pułapki programowej w badanej aplikacji dla przekłamania bitów w komórkach rejestrów i pamięci operacyjnej oraz dla emulacji błędnego wykonania instrukcji. Pod nadzorem symulatora wykonywany jest wzorcowy przebieg aplikacji (ang. golden run), zbierane są odpowiednie stany wewnętrzne oraz dane wyjściowe. Następnie wykonuje się wstrzykiwanie błędów i porównuje zachowanie zakłóconej aplikacji z sytuacją bezbłędną. Przed każdym eksperymentem należy określić specyfikację typów błędów i miejsca ich wstrzykiwania.
W Instytucie Informatyki PW zrealizowano narzędzia SWIFI przeznaczone dla jedno i wielowątkowych aplikacji [SOSN2003]. Przy ich użyciu wykonano wiele eksperymentów. Zebrane doświadczenia wskazują na szereg istotnych problemów w organizacji eksperymentów oraz na ich ograniczenia. Planując eksperymenty istotne jest określenie obszarów wstrzykiwania błędów. Jest to obsługiwane na różne sposoby we wspomnianych symulatorach błędów. W wielu eksperymentach najbardziej efektywne było bezpośrednie specyfikowanie obszarów wstrzykiwania przez wstawianie odpowiednich znaczników (początkowych i końcowych) do kodu źródłowego aplikacji. Obszar wstrzykiwania może składać się ze zbioru niezależnych obszarów ograniczonych znacznikami. Błędy wstrzykiwane są podczas wykonywania instrukcji znajdujących się wewnątrz tych obszarów.
Odpowiedni dobór obszarów wstrzykiwania jest szczególnie krytyczny ze względu na ograniczenia wydajnościowe oraz efektywność wstrzykiwania. Zależnie od implementacji, czas przebiegu aplikacji ze wstrzykiwaniem może znacznie przewyższać czas wykonania tego samego programu w normalnym trybie. Ponadto dla dużych obszarów pojawia się problem przechowywania znacznych ilości informacji zgromadzonych podczas wykonania wzorcowego. Z drugiej strony wybór reprezentatywnych scenariuszy testujących wraz z odpowiednimi obszarami kodu pozwala osiągnąć dobre pokrycie bloków i ścieżek w analizowanym kodzie [DERE2002].
Przygotowanie aplikacji przez wstawienie odpowiednich znaczników wymaga dobrej znajomości kodu. Znaczniki są interpretowane podczas wykonania wzorcowego i powinny tworzyć sparowaną strukturę w dynamicznym przebiegu programu. Wskazane obszary mogłyby odpowiadać zadanym elementom z projektu, modelu analizy, a nawet wymagań systemu. Uzasadnia to śledzenie zależności na wszystkich etapach rozwoju oprogramowania aż do kodu źródłowego. Realizacja wybranych elementów oraz ich zmiany mogłyby być bezpośrednio śledzone w aplikacji i analizowane przez symulator błędów. Korzystne byłoby zatem posiadanie narzędzi wspomagających określenie i utrzymanie relacji śledzenia oraz wstawianie znaczników na odpowiednich pozycjach w kodzie programu.
3. Strategie śledzenia zależności#
Podstawowym celem większości strategii śledzenia zależności jest poprawa jakości systemów informatycznych i procesu produkcji oprogramowania. Relacje śledzenia mogą być wykorzystywane do:
- Weryfikacji, czy system spełnia zadane wymagania.
- Określenia wpływu zmian w artefaktach systemu (np. specyfikacji wymagań) na inne artefakty.
- Zrozumienia ewolucji artefaktów oprogramowania podczas inżynierii do przodu i inżynierii odwrotnej (ang. forward and reverse engineering), np. w systemach “spadkowych” (ang. legacy systems).
- Poprawy kompletności projektu.
- Poprawy pielęgnowalności projektu (korzyści w długiej perspektywie czasowej).
Istnieją różne podejścia do śledzenia zależności oraz różne problemy ich realizacji. W dalszej części tego punktu przedstawiono wybrane rozwiązania, w szczególności dla śledzenia zależności prowadzących aż do kodu źródłowego. Różnice w podejściach mogą dotyczyć:
- Sposobów pozyskiwania relacji śledzenia: definiowanie ręczne przez wytwórców oprogramowania, wprowadzenie pośrednie wynikające z rygorystycznego procesu wytwarzania, generacja automatyczna.
- Zakresu zależnych artefaktów (wiele rozwiązań dotyczy relacji pomiędzy wymaganiami a odpowiednimi elementami modelu).
- Realizacji relacji śledzenia: bezpośrednie powiązania skrośne (ang. cross reference links), hiperpowiązania, znaczniki (ang. pointing tags), wspólne nazwy.
- Poziomu szczegółowości śledzonych artefaktów np. cała klasa czy metoda klasy.
- Sposobów utrzymywania (pielęgnacji) relacji śledzenia.
Ręczne określanie relacji śledzenia często nie jest wymuszane ani wspierane przez proces wytwarzania oprogramowania. Zadanie to jest czasochłonne i podatne na błędy, a bilans pomiędzy wymaganą dodatkową pracą a oczekiwanymi korzyściami jest trudny do oszacowania [EBNE2000]. Ponadto, bez automatycznego utrzymywania relacje śledzenia mogą nie być aktualizowane i staną się przestarzałe.
Innym problemem jest walidacja relacji śledzenia, identyfikacja i rozstrzyganie niespójności. Jest to szczególnie istotne dla relacji tworzonych automatycznie. Istnieją różne źródła niejednoznaczności w relacjach śledzenia zależności. Jednym z nich jest niedopasowanie pomiędzy specyfikację wymagań a pojęciami projektowania obiektowego. Wspomaganie pojedynczej jednostki wymagań (celu, funkcji, własności) jest rozrzucone po różnych elementach projektu, a odniesienie do wielu wymagań może być scalone w jednym elemencie projektu. Nawet szeroko używane pojęcie przypadków użycia może być w różny sposób łączone z jednostkami wymagań z jednej strony oraz elementami obiektowymi z drugiej strony. Późniejsza dekompozycja zorientowanego obiektowo, statycznego modelu (klasy, atrybuty, operacje) może być zgodna z kodem w obiektowym języku programowania, określając w ten sposób związki pomiędzy projektem i kodem.
Jednoznaczne powiązania od wymagań poprzez projekt aż do kodu źródłowego są wprowadzane podczas rygorystycznego procesu przedstawionego w [INSF2002]. Model wymagań zawiera deklarację misji, drzewo uszczegóławiania zadań oraz model przypadków użycia. Drzewo reprezentuje hierarchiczną dekompozycję biznesowych zadań systemu. Korzeniem hierarchii jest ogólna funkcja systemu (deklaracja misji). Liście drzewa reprezentują podstawowe zadania. Każdy przypadek użycia odpowiada węzłowi liścia w drzewie zadań. Relacja ta jest definiowana ręcznie przez wstawienie znacznika odwołań (ang. cross-reference tag) w specyfikacji przypadków użycia.
Specyfikacja dla każdego przypadku użycia obejmuje opisy podstawowego oraz alternatywnych przebiegów. Opis zawiera numerowane kroki występujące w danym przypadku użycia. Dla tych przebiegów tworzone są diagramy sekwencji. Dla każdego kroku w specyfikacji przypadków użycia identyfikowany jest zakres odpowiedzialność (ang. responsibility) lub ich zbiór, a następnie reprezentowany w postaci interakcji z wiadomościami. Interakcje są klasyfikowane za pomocą stereotypów UML <<signal>>, <<service>>, <<query>>, <<select>>. Można przypuszczać, że zasadniczy proces analizy i projektowania koncentruje się w tym rozwiązaniu na stopniowym uszczegóławianiu diagramów sekwencji.
Następnie zbiory klas z operacjami, asocjacjami i agregacjami są wyprowadzane z ww. diagramów sekwencji. W rezultacie powstaje strukturalna relacja śledzenia, w której wiadomo jaka klasa i które operacje są odpowiedzialne za dany przypadek użycia. Dodatkowo, alokacja przypadków użycia do klas może być reprezentowana przez tablicę dekompozycji zadań. Dla każdej klasy tworzony jest diagram stanów, czyli relacja zależności jest bezpośrednia. Model dynamiczny jest uzupełniony opisem określającym każdą zmianę stanu obiektu. Na tej podstawie może być wygenerowana kompletna specyfikacja formalna (przy pomocy narzędzia OASIS). Aplikacja funkcjonalnie równoważna dla tej specyfikacji może powstać automatycznie przy wykorzystaniu wzorców z zadanego środowiska wytwarzania oprogramowania.
Inne podejście odnosi relacje śledzenia do pokrycia kodu obserwowanego podczas wykonania programu [EGYE2003]. Na podstawie dostarczonych przez użytkownika reprezentatywnych scenariuszy testowych oraz początkowych, hipotetycznych zależności, w sposób automatyczny generowane są kolejne zależności. Podczas wykonania przez program (lub symulator) scenariuszy testowych obserwowane są wykorzystywane linie kodu. Nakładanie się linii kodu jest interpretowane jako zależności pomiędzy scenariuszami. Z początkowych, hipotetycznych zależności wyprowadzane są nowe zależności zgodnie z wieloma regułami propagacji i uszczegóławiania grafu zależności. Zależności definiują relacje pomiędzy elementami projektu, scenariuszami testowymi oraz wycinkami kodu. Jeśli zbiór scenariuszy jest niewystarczający, mogą być wykryte niekompletne relacje. Kolejne wykonanie programu z dodatkowymi testami może poprawić wyniki śledzenia zależności. Identyfikowane są również niespójne relacje, wskazujące na to że podano konfliktowe (niezgodne) warunki wejściowe.
Praca [EBNE2000] poświęcona jest śledzeniu zależności w ponownej inżynierii systemów “spadkowych”. W inżynierii odwrotnej w sposób automatyczny występują zależności wskazujące od istniejącego kodu do modelu i dalej do wymagań, następnie od zmodyfikowanych wymagań do nowego projektu i nowego kodu podczas wytwarzania systemu “następcy”. Przyjęty poziom szczegółowości przypisuje znaczniki śledzenia dla każdej procedury kodu źródłowego, każdej tablicy itp. Śledzenie pomiędzy artefaktami w specyfikacji wymagań oraz w projektach starym i nowym jest realizowane za pomocą hiperpołączeń w narzędziu RETH (Requirements Engineering Through Hypertext). Wspomaga ono półautomatyczną generację połączeń. Może być również wykorzystana generacja połączeń słownikowych opartych na odwołaniach tekstowych.
Inne rozwiązania dla łączenia opisów tekstowych i elementów modelu są rozwijane w oparciu o techniki przetwarzania języków naturalnych [CERB2000]. Pojęcia techniczne są identyfikowane w nieformalnej dokumentacji opisującej wymagania w dziedzinie problemu. Budowana jest hierarchia tych pojęć wraz z realizowanymi przez hiperpołączenia odwołaniami do wystąpień w dokumentach. Na podstawie hierarchii pojęć generowane są szkielety klas, w których każda klasa jest bezpośrednio powiązana z pojęciem.
Relacje śledzenia pomiędzy elementami wymagań wyrażonymi w strukturalnym języku naturalnym (opisy wymagań lub przypadków użycia) oraz od wymagań do modeli w UML mogą być automatycznie generowane przy pomocy heurystycznych reguł śledzenia [SPAN2002]. Reguły te specyfikują sposoby dopasowywania syntaktycznie powiązanych składników w tekstowej części wymagań z powiązaniami elementami w modelu obiektowym (np. klasy, atrybuty, operacje, wiadomości). Dla znalezionego dopasowania tworzone są różne typy relacji śledzenia. Relacje syntaktyczne użyte w regułach są definiowane w kontekście wzorców słów, które mają specyficzne gramatyczne role w tekście (np. rzeczownik, czasownik, przymiotnik, itp.). Z uwagi na heurystyczną naturę reguł, nie jest zapewniona poprawność generowanych relacji śledzenia oraz nie wiadomo, czy dany artefakt spełnia regułę. W celu rozwiązania tego problemu, wygenerowane relacje śledzenia są porównywane z relacjami podanymi bezpośrednio przez zbiór użytkowników. Użytkownik może wskazać, czy wygenerowana relacja jest poprawna czy nie, przyjmując że nie jest jej autorem. Rezultaty porównań są użyte do obliczeń związanych z regułami funkcji przekonania (ang. belief functions) wzorowanych na teorii Dempstera-Shafera oraz do podjęcia wiarygodnych decyzji o stosowaniu tych reguł.
Generacja relacji śledzenia jest wspierana również przez narzędzie TOOR [PINH1996], wykorzystywane szczególnie do śledzenia wymagań. Zależności mogą być dedukowane z aksjomatycznych definicji. Jednakże, zależności śledzenia pomiędzy różnymi artefaktami nie mogą być generowane ani sprawdzane, o ile artefakty te nie są kompletne oraz zdefiniowane w sposób formalny.
4. Koncepcja śledzenia zależności w projekcie obiektowym#
4.1. Struktura projektu#
Podstawowym celem prezentowanej koncepcji jest śledzenie zależności prowadzących do elementów bezpośrednio odpowiedzialnych za generację kodu. Śledzenie zależności wszystkich elementów pomiędzy sobą, przypadków testowych, dokumentacji itp. wykracza poza ramy omawianego podejścia. Podstawową ideą jest wykorzystanie notacji śledzenia obecnych w modelu UML i/lub wspomaganych przez narzędzia typu CASE. W ogólności śledzenie zależności może być wprowadzone do projektu przez regulacje lub wewnętrzne standardy procesu (np. RUP [KRUC2000]). W innych przypadkach wynikają one z dobrych praktyk konstrukcji modelu. Jednakże w rzeczywistych projektach nie można wykluczyć niespójnych oraz niepoprawnych relacji. Powoduje to obniżenie jakości i wiarygodności uzyskanych rezultatów. Pożądana jest wówczas identyfikacja wykrytych w projekcie niekonsekwencji. Poniżej dyskutowane będą wskazówki dotyczące akceptowanej, możliwej struktury projektu.Możliwe są różne sposoby odwzorowania pomiędzy specyfikacją wymagań a modelem w UML [SPEN2000]:
- Model przypadków użycia jest jedyną specyfikacją wymagań.
- Cele (potrzeby), własności (ang. features) są udokumentowane oraz związane z przypadkami użycia tworząc kompletną specyfikację wymagań.
- Własności (o ile wyodrębnione) są związane z dokumentem specyfikacji wymagań. Wymaganiu odpowiadają bezpośrednio przypadki użycia (rozumiane jako interpretacja wymagań).
We wszystkich tych sytuacjach model przypadków użycia jest centralną strukturą porządkującą związki pomiędzy przestrzenią wymagań a późniejszymi pojęciami projektowania obiektowego. Inną (czwartą) możliwością jest sytuacja, gdy nie rozważany jest ani model przypadków użycia ani specyfikacja wymagań. Może to czasem dotyczyć ponownej inżynierii systemów.
Do przykładów dobrych praktyk organizujących strukturę modelu UML można zaliczyć:
- Przypisywanie diagramów z uszczegółowioną specyfikacją do odpowiadających artefaktów (wspomagane często przez hiperpołączenie w narzędziu), np.:
- diagramy interakcji, diagramy czynności do przypadku użycia,
- diagramy stanów do klas,
- diagramy klas do kooperacji (ang. collaboration).
- Użycie uporządkowanej struktury z elementami organizującymi np.:
- podział projektu na różne modele odpowiadające kolejnym stopniom rozwoju projektu,
- grupowanie części modelu zgodnie z logiczną lub implementacyjną strukturą,
- wykorzystanie hierarchii pakietów do przechowywania zgrupowanych części modelu.
- Używanie konwencji znaczących nazw np.:
- nazwa pakietu grupującego artefakty implementacyjne zgodna z nazwą realizowanego elementu,
- nazwa kooperacji zgodna z realizowanym przypadkiem użycia, realizowaną funkcją.
- Zastosowanie relacji realizacji (——⊳), łączącej np.:
- kooperację z realizowaną operacją,
- klasę o stereotypie <<implementationClass>> z klasą o stereotypie <<type>>,
- klasę z jej interfejsem.
- Specyfikowanie podsystemów, pakietów z symbolem (ang. fork), i przypisywanie odpowiednich elementów do sekcji podsystemu (ang. compartments), np.:
- operacje do interfejsu,
- przypadki użycia do sekcji specyfikacji,
- kooperacje, diagramy zachowań do sekcji realizacji.
- Użycie ww. relacji realizacji do odwzorowania elementów z sekcji realizacji względem elementów z innych sekcji podsystemu lub elementów zewnętrznych.
- Stosowanie relacji zależności (——->) z predefiniowanymi stereotypami (zwłaszcza trace, ale również use, refine, access, bind, derive, import) lub ze specjalizowanymi do projektu stereotypami zdefiniowanymi przez użytkownika; łącząc np.:
- pakiety (klasy) z różnych poziomów znaczeniowych (analiza, projektowanie, implementacja),
- komponent z interfejsem innego komponentu.
Łatwo zauważyć, że można wyrazić podobną lub nawet taką samą relację w różny sposób. Dlatego potrzebna jest weryfikacja zgodności oraz rozstrzyganie możliwych konfliktów. Jednakże większym problemem jest brak dobrych praktyk i pomijanie wszelkich notacji śledzenia zależności.
4.2. Podstawowe pojęcia#
Podczas analizy relacji śledzenia wykorzystywane będą następujące ogólne pojęcia.Artefakt x – wymaganie lub element z dowolnego modelu (analizy, projektu, implementacji). Elementem modelu UML może być przypadek użycia, klasa, atrybut, operacja, pakiet, komponent, stan, obiekt, kooperacja itp.
Region R – podzbiór elementów modelu UML.
Potencjalny region zależności artefaktu x – PD(x) obejmuje wszystkie możliwe elementy wynikające z reguł śledzenia dla danego artefaktu w określonym modelu.
Region zależności artefaktu x – D(x) jest podzbiorem PD(x) wykorzystującym dostępne informacje do ograniczenia potencjalnego regionu.
Region zależności zbioru artefaktów X– D(X) definiuje wszystkie możliwe elementy wynikające z reguł śledzenia dla wszystkich artefaktów ze zbioru X w danym modelu, przy wykorzystaniu dostępnych informacji do ograniczenia tego regionu.
D(X) = ∪x∊X(D(x)), gdzie ∪jest sumą zbiorów.
Region generacji dla danego regionu zależności R przy założeniu strategii S – GS(R) jest podzbiorem elementów regionu R, które mają wpływ na generowany kod przy użyciu zadanej strategii generacji. Strategia generacji decyduje o transformacji elementów modelu do kodu źródłowego w wybranym języku implementacyjnym.
Dla danego regionu zależności region generacji zależy od przyjętej strategii generacji, gdyż standard UML nie definiuje ścisłego odwzorowania do żadnego języka implementacji. Typowo region generacji tworzy model klas tzn. klasy z atrybutami, operacjami, ich typami, parametrami itp. oraz relacje pomiędzy klasami. Kod może być również generowany na podstawie opisu zachowań – diagramów sekwencji, kooperacji i stanów, przy założeniu odpowiedniego poziomu szczegółowości, np. obiekty mają przypisane klasy.
Znaczniki kodu dla programu są zbiorem par znaczników (znacznik początkowy, znacznik końcowy), które są umieszczane w kodzie źródłowym.
Znaczniki kodu dla danego regionu R przy założeniu strategii generacji S – C(GS(R)) są zbiorem znaczników kodu umieszczonych w kodzie źródłowym wygenerowanym z modelu. Położenia znaczników są zdefiniowane na podstawie regionu generacji.
4.3. Identyfikacja regionu zależności#
Przypisanie regionu zależności do danego artefaktu jest oparte na następujących ogólnych zasadach:
- Jeśli dla artefaktu x istnieje jednoznaczna zależność śledzenia prowadząca do elementu y lub jeśli x jest realizowany przez y; a ponadto nie istnieje więcej szczegółowych informacji dotyczących innych relacji pomiędzy x i y (lub składnikami i cechami y), wówczas y w całości należy do regionu zależności x – D(x). Jeśli takie informacje istnieją, to tylko bezpośrednio wyspecyfikowane części y należą do tego regionu.
Zasada ta może być wyjaśniona na prostym przykładzie. Załóżmy, że z rozważanym przypadkiem użycia (artefakt x) związane są dwa diagramy potomne (1. dobra praktyka) oraz nie ma innych zależności. Na jednym z tych diagramów występują 3 klasy A, B, C (rysunek 1). Obiekty klas B, C występują też na drugim diagramie dołączonym do tego przypadku użycia – diagramie sekwencji. Na diagramie tym występują również operacje wywołane z obiektów klas B, C, D. W omawianym przykładzie potencjalny region zależności PD(x) składa się z całych klas A, B, C, D oraz powiązań (ang. associations) pomiędzy nimi. Do regionu zależności danego przypadku użycia D(x) przypisane będą tylko następujące elementy: klasa A, atrybuty klas B i C, operacje klas B, C, D użyte w interakcji, powiązania pomiędzy klasami A, B i C. Dodatkowo, ostrzeżenie wskazuje na klasę D śledzoną z x jako na możliwą, brakującą klasę na poddiagramie klas danego przypadku użycia.Druga ogólna zasada dotyczy problemu wielokrotnych zależności śledzenia.
- Jeśli dla danego artefaktu x istnieją różne rodzaje zależności śledzenia prowadzące do tych samych elementów, to elementy te oraz elementy pośredniczące należą do regionu zależności D(x) (przy założeniu spełnienia warunków zasady I). W przeciwnym razie, jeżeli zależności są niespójne rozstrzygnięcie przynależności do regionu D(x) oparte będzie na priorytetach.
Reguły użycia priorytetów próbują w ogólności wydobyć intencje wytwórcy oprogramowania. Najwyższy priorytet jest nadawany tym rozwiązaniom, które wymagały największego wysiłku ze strony twórcy modelu i są zgodne ze specyfikacją UML. Na przykład bezpośrednie połączenia (pochodzące z dobrych praktyk 4., 5., 6.) są nadrzędne nad innymi rozwiązaniami. Jeśli jest wiele relacji o tym samym priorytecie dotyczących tego samego artefaktu, można zastosować ważone głosowanie większościowe.
Zasadę II ilustrują poniższe przykłady. W modelu przypadków użycia występuje przypadek użycia x. W innym pakiecie tego projektu zawarta jest kooperacja o nazwie x. Kooperacja ta jest połączona relacją realizacji z przypadkiem użycia x (rysunek 2.a). Dla tego prostego przykładu relacja śledzenia prowadzi do tego samego elementu na podstawie dwóch wskazań: konwencji nazewnictwa (3. dobra praktyka) oraz relacji realizacji (4. praktyka). Wskazania są zgodne i kooperacja x należy do regionu zależności przypadku użycia x.
Jeśli kooperacja związana z przypadkiem użycia x ma nazwę y oraz nie ma innych kooperacji o nazwie x, to kooperacja y należy do D(przypadek użycia x) (rysunek 2.b). Ewentualne ostrzeżenie może informować o niespójnym nazewnictwie, zwłaszcza gdy nazwa y nie ma nic wspólnego z nazwą x. Identyczny wynik będzie otrzymamy w przypadku zastosowania w sposób jednoznaczny innej relacji, np. relacji zależności lub relacji połączenia (z ewentualnymi stereotypami) (rysunek 2.c).Czwarta sytuacja dotyczy dwóch kooperacji – jednej o nazwie x (ale nie połączonej z przypadkiem użycia x) oraz drugiej o nazwie y połączonej relacją realizacji z przypadkiem użycia x (rysunek 2.d). Zgodnie z przyjętymi priorytetami kooperacja y należy do D(przypadek użycia x) a kooperacja x nie należy. Sytuacji może towarzyszyć ostrzeżenie o niejednoznaczności projektu. Podobnie dla przykładu z rysunku 2.e kooperacja ynależy do D(przypadek użycia x), a kooperacja z nie należy.
W ostatnim przykładzie istnieje kooperacja x, oraz żadna kooperacja nie jest połączona z przypadkiem użycia x(rysunek 2.f). Na podstawie konwencji nazewnictwa, kooperacja x należy do D(przypadek użycia x).
Wymienione powyżej ogólne zasady I i II są uszczegóławiane w postaci reguł dla poszczególnych typów elementów modelu. Dokładna specyfikacja reguł jest wyrażona w postaci zbioru odpowiednich tablic decyzyjnych. Zdefiniowany jest również porządek priorytetów dla niejednoznacznych sytuacji. Pełna specyfikacja algorytmu wykracza poza ramy tego artykułu.
Prototypowego narzędzia do analizy zależności (por. punkt 5.) użyto do wstępnej weryfikacji sposobu identyfikacji regionów zależności. Zbadano 6 niedużych projektów w języku UML (obejmujących analizę i projekt dla 20-40 przypadków użycia). Wszystkie projekty wzorowane były na schemacie zalecanym dla RUP w narzędziu Rational Rose, ale żaden z nich nie odpowiadał ściśle zalecanej postaci. Różnice dotyczyły struktury hierarchii pakietów, zależności wskazujących na realizację przypadków użycia, klas, interfejsów, zasad dołączania poddiagramów interakcji itp.
Identyfikowano regiony zależności dla wymagań związanych z przypadkami użycia. W 4 projektach możliwe było wskazanie zgodnych z oczekiwaniami klas lub ich części odpowiedzialnych za dane wymaganie. W różnych projektach dla przypadków użycia wystąpiły zależności odpowiadające przykładom a), b), c) oraz f) z rysunku 2. W dwóch pozostałych projektach brakowało bezpośrednich relacji wskazujących na realizację przypadków użycia, hiperpołączeń, zależności diagramów czy pakietów. W rezultacie otrzymano puste regiony zależności. Istniejące zależności wyrażone były poprzez bardzo podobne (ale nie identyczne) nazwy elementów: np. potwórzone nazwy z dodanym przyrostkiem, nazwy w których spację oddzielającą słowa zastąpiono podkreśleniem. Po modyfikacji takich nazw oczekiwane regiony zależności mogły być zidentyfikowane.
Otwarty problemem pozostaje potrzeba bardziej rozwiniętej analizy nazw elementów modelu. Pokrewne nazwy często zawierają się w sobie lub mają wspólną część. Jednak takie proste relacje pomiędzy nazwami nie są wystarczające dla automatycznej identyfikacji zależności, gdyż występują one również pomiędzy wieloma innymi elementami modelu związanymi zwykle z dziedziną reprezentowaną w danym modelu. Szczególnym przypadkiem są też nazwy prawie identyczne np. różniące się odstępami pomiędzy wyrazami, liczbą pojedynczą i mnogą, błędami literówek itd. Jednak ich utożsamianie może również prowadzić do niejednoznaczności projektu. Generalnie podobieństwo (identyczność) nazw może wspomagać śledzenie zależności ale nie jest wystarczające dla uzyskania jednoznacznych rozwiązań.
4.4. Przypisywanie fragmentów kodu#
Przypisywanie fragmentów kodu jest oparte na elementach należących do regionu generacji (p.4.2). Zakłada się, że istnieje automatyczny generator kodu, który tworzy co najmniej szkielety klas. Dla poszczególnych rodzajów elementów należących do regionu generacji określone są reguły wstępnego przypisania znaczników kodu. Na przykład:
- Operacja w klasie – znacznik początkowy na początku operacji i znacznik końcowy na końcu (każdym z możliwych końców).
- Użycie operacji na diagramie sekwencji – znacznik początkowy przed wywołaniem operacji przez obiekt danej klasy, znacznik końcowy po wywołaniu.
- Klasa – znacznik początkowy na początku każdej operacji (włącznie z konstruktorem i destruktorem), znaczniki końcowe na końcach. Znaczniki dla widocznego użycia atrybutów klasy poza operacjami tej klasy.
Ponadto ustawienie znaczników jest uściślane w celu unikania zagnieżdżonych wystąpień, o ile to możliwe. Wszystkie potencjalne znaczniki pozostają w kodzie, ale tylko ich podzbiór jest wskazywany jako znaczniki obowiązujące. Problem jest porównywalny do symbolicznego wykonania programu i nie jest satysfakcjonująco rozwiązywalny w ogólnym przypadku (np. wskaźniki do funkcji, rekurencja, zaprzyjaźnienia). W zależności od aplikacji możliwe są dwa podstawowe podejścia: pozostawienie znaczników dla możliwie najmniejszych (wewnętrznych) obszarów, lub pozostawienie dla największych (zewnętrznych) obszarów.
5. Środowisko wspomagające śledzenie zależności#
Przygotowanie kodu w oparciu o śledzenie zależności może być wspomagane przez rozszerzenie narzędzia typu CASE przeznaczonego do projektowania modeli w języku UML. Podstawowy przebieg czynności realizowanych przy wytwarzaniu oprogramowania jest pokazany na rysunku 3. Dwa kroki (zaznaczone przez * i **) mogą być automatyzowane. Etykiety zależności w modelu jak również znaczniki w kodzie mogą być również modyfikowane ręcznie.Zgodnie ze wskazanym artefaktem (zbiorem artefaktów), albo po wykryciu zmiany danego artefaktu, propagowana jest relacja śledzenia zależności i elementy należące do regionu zależności są etykietowane. Mogą także zostać wskazane miejsca występowania niekompletności i niezgodności. Wytwórca ma możliwość (nie musi) poprawić model. Narzędzie powinno również dostarczać dodatkowe funkcje:
- Usuwanie etykiet zależności z modelu.
- Identyfikacja wielokrotnych etykiet pochodzących od różnych początkowych artefaktów.
- Łączenie regionów zależności dla różnych artefaktów.
- Generacja znaczników kodu dla wszystkich lub tylko dla wybranych regionów zależności (w przypadku identyfikacji różnych etykiet).
Prototypowe narzędzie oparte na przedstawionym podejściu jest obecnie w fazie realizacji. Jest ono rozszerzeniem komercyjnego narzędzia Rational Suite Enterprise. [WWW2003b]. Składa się z 2 głównych modułów: Analizatora zależności realizującego czynność zaznaczoną symbolem (*) na rysunku 3., oraz Generatora kodu dla czynności zaznaczonej przez (**). Prototyp współpracuje z narzędziem do zarządzania wymaganiami Rational Requisite Pro oraz do modelowaniu w UML Rational Rose. Użytkownik może tworzyć 2-kierunkowe połączenia pomiędzy przypadkami użycia w Rational Rose a odpowiadającymi opisami wymagań w Requisite Pro. Dodatkowy moduł prototypu wspomaga identyfikację tych wymagań, które zostały zmienione. Ogólna architektura modułów systemu CASE jest przedstawiona na rysunku 4.
Zalecana struktura modelu odpowiada tej z RUP [KRUC2000], (ale nie jest do niej ograniczona). Określenie regionów zależności jest implementowane za pomocą notacji stereotypów UML. Prototyp korzysta z własnego modułu generacji kodu dla języka C++. Pierwsza wersja generuje kod w typowy sposób z modelu klas. Kolejne wersje mają generować kod również z diagramów interakcji i diagramów stanów.
6. Podsumowanie#
W rozdziale przedstawiono wykorzystanie pojęć śledzenia zależności w rozwoju projektu zorientowanego obiektowo. Opisano koncepcję identyfikacji regionów zależności dla wymagań oraz elementów modelu UML. Spodziewane korzyści dotyczą: zrozumienia pochodzenia fragmentów kodu i ich wyróżnienia w odniesieniu do danego artefaktu projektowego oraz detekcji wpływu zmian artefaktu na model i generowany kod.Niedostateczny stopień formalizacji projektów w języku UML oraz szerokie, realistyczne założenia o strukturze modelu mogą ograniczać zastosowanie dyskutowanych rozwiązań. Prezentowane podejście wymaga dalszych eksperymentów z bardziej złożonymi projektami w celu walidacji sugerowanych sposobów rozstrzygania niejednoznaczności oraz przyjętych priorytetów. Pożyteczne może okazać się wykorzystanie nie tylko reguł ogólnego zastosowania, ale również reguł specjalizowanych dla różnych strategii modelowania. Krytycznym zadaniem jest możliwość ograniczania regionów zależności. Dla rozwiązania tego problemu proste reguły mogłyby być wspomagane przez rozwiązanie oparte na językowych własnościach opisów tekstowych (w tym analizy nazw elementów modelu).
Przypisywanie kodu oparte na śledzeniu zależności może być wykorzystane dla przygotowania eksperymentów z programowym symulatorem błędów sprzętowych (SWIFI), ale również podczas wyboru obszarów dla innych technik wstrzykiwania błędów. Na przykład, wpływ zmian wymagania lub innego elementu modelu może być analizowany przez mutacje programowe zastosowane tylko we wskazanych obszarach kodu [WONG2001].
W przypadku inżynierii odwrotnej śledzenie zależności może wspomagać zrozumienie i modyfikację istniejącego programu. Jest to szczególnie istotne dla systemów “spadkowych”, nie posiadających udokumentowanych wymagań ani projektu.
Bibliografia#
[CERB2000] | F Cerbah i J Euzenat, Using Terminology Extraction to Improve Traceability from Formal Models to Textual Requirements, Proceeding of NLDB 2000, LNCS 1959, Springer, 2001, 115-126. |
[DERE2002] | A Derezińska i J Sosnowski, Experimental Checking of Fault Susceptibility in a Parallel Algorithm, Proc. of Inter. Conf. on Parallel Comput. in Electr. Engin. Parelec’02, Warsaw, Poland, 22-25 Sept. IEEE Comp. Soc., 2002, 33-38. |
[EBNE2000] | G Ebner i H Kaindl, Tracing all around, Proceeding of CAiSE 2000, LNCS 1789, Springer, 2000, 355-368. |
[EGYE2003] | A Egyed, A Scenario-Driven Approach to Trace Dependency Analysis, IEEE Trans. on Software Engineering, vol. 29, no. 2, Feb 2003, 116-132. |
[INSF2002] | E Insfran, O Pastor i R Wieringa, Engineering-Based Conceptual Modelling, Requirements Eng., vol 7, Springer, 2002, 61-72. |
[KRUC2000] | P Krutchen, The Rational Unified Process An Introduction, Addison-Wesley, 2000. |
[MADE2000] | H Madeira i D Costa, On the Emulation of Software Faults by Software Fault Injection,Proceeding of the Int. Conf on Dependable Systems and Networks, DSN 2000, IEEE, 2000, 417-426. |
[PINH1996] | F.A.C Pinheiro i J.A Goguen, An object-oriented Tool for Tracing Requirements, IEEE Software, vol. 13. no. 3., March 1996, 52-64. |
[SOSN2003] | J Sosnowski, A Lesiak, P Gawkowski i P Włodawiec, Software Implemented Fault Inserters,Proceeding of IFAC Workshop on Programmable Devices and Systems, Ostrava, 2003, 427-432. |
[SPAN2002] | G Spanoudakis, Plausible and Adaptive Requirement Traceability Structures, Proceeding of SEKE’02 July 15-19, Ischia, Italy, ACM, 2002, 135-142. |
[SPEN2000] | I Spence i L Probasco, Traceability Strategies for Managing Requirements with Use Cases,Rational Software, 2000, http://www.rational.com/products/ whitepapers/022701.jsp. |
[WONG2001] | W. E Ed. Wong, Mutation Testing for the New Century, Kluwer Acad. Publ., June 2001. |
[WWW2003a] | OMG Unified Language Specifiation – ver. 1.5, OMG, March 2003, www.omg.org. |
[WWW2003b] | Rational Suite, www.rational.com/products. |