Wprowadzenie w problematykę jakości oprogramowania
W niniejszym rozdziale zawarto wprowadzenie w problematykę badania jakości oprogramowania. W podrozdziale 1.1 przedstawiono sposób rozumienia cyklu życia oprogramowania i jego wpływ na plan zapewniania jakości oprogramowania. Podrozdział 1.2 zawiera klasyfikację agregatów jakości oprogramowania. Przedstawiona w tym miejscu klasyfikacja stanowi podstawę prowadzonych rozważań. Podrozdział 1.3 stanowi przegląd ważnych aktów normatywnych regulujących ogólnie rozumianą tematykę jakości oprogramowania. W treści podrozdziału 1.4 zamieszczono przegląd najciekawszych metod metrykowych stosowanych w ocenie jakości oprogramowania, a także wyniki badań faktycznego ich wykorzystywania na rynku producentów oprogramowania. W podrozdziale 1.5 zamieszczono tezę realizowanej rozprawy.
Cykl życia systemu informatycznego
Pojęcie cyklu życia systemu informatycznego jest kluczowe dla zarządzania pracami wytwórczymi oprogramowania systemów informatycznych. Norma [IEC 300-3-6] przedstawia cykl życia oprogramowania według schematu, przedstawionego na rysunku 1.1. Nakładanie się na siebie niektórych elementów z rysunku 1.1 oznacza, że kolejne fazy cyklu życia są częściowo realizowane w tym samym czasie, a także to, że pomiędzy tymi fazami może istnieć sprzężenie zwrotne. Kolejność faz cyklu życia jest oznaczone umowną osią czasu i symboliką przesłaniania prostokątów, w których umieszczono nazwy poszczególnych faz.
Oprogramowanie jest szczególnym rodzajem wyrobu, którego wytwarzanie wymaga specjalnych procedur. Są one specyficzne dla każdego etapu cyklu życia. Dla każdego z tych etapów potrzebna jest specyficzna specjalizacja członków zespołu zarządzającego i realizacyjnego. Inne są też procedury kontroli jakości na poszczególnych etapach cyklu życia. Są one elementem tzw. planu zapewniania jakości [Maz95]. Opiera się on na zaplanowanych i doraźnych kontrolach aktualnego stanu prac wytwórczych. Plan zapewniania jakości powinien być skonstruowany tak, aby możliwe było wykazanie, że:
prace projektowe zostały zorganizowane zgodnie z zatwierdzonym cyklem życia oprogramowania,
zespół projektowy ma określone zadania i sposób rozliczania prac,
wdrożone zostały zasady dokumentowania prac,
zostały wdrożone zatwierdzone standardy dotyczące fazy implementacji,
archiwizowane są wyniki badań jakości oprogramowania w zakresie metryk projektu i produktu programowego,
przeprowadzane są kontrole i audyty,
istnieje specyfikacja testów, które są rygorystycznie przestrzegane,
zaistniałe problemy są dokumentowane i usuwane,
do prac projektowych są wykorzystywane zatwierdzone narzędzia, techniki i metody,
oprogramowanie jest archiwizowane w odpowiednio zarządzanych bibliotekach dokumentacji,
archiwizacja oprogramowania jest bezpieczna (trwała i chroniona przed niepożądanym dostępem osób trzecich),
oprogramowanie wytworzone u podwykonawców podlega przyjętym standardom,
personel został odpowiednio przeszkolony,
zagrożenia projektu zostały zminimalizowane,
przewidziano odpowiednie procedury wdrażania i pielęgnacji oprogramowania.
Jak widać lista żądań jest pokaźna, a jej realizacja jest zadaniem skomplikowanym. Żądania te stawiają wiele problemów jakie musi rozwiązać wytwórca oprogramowania, który dąży do wdrożenia programu zarządzania jakością w swojej organizacji. Każdy z punktów powyższej listy może stanowić temat oddzielnych rozważań. Niejednorodność zakresu programu zarządzania jakością wymaga różnych metod kontroli jakości. Konieczne jest tutaj odpowiednie przystosowanie metod badania jakości do poszczególnych etapów cyklu życia, a na tych etapach do konkretnych zaleceń programu zapewniania jakości. Część z tych wymagań została w ogólnej formie przeniesiona do zaleceń normatywnych, część natomiast wciąż stanowi przedmiot badań. Istotne jest, aby określając koszt cyklu wytwórczego oprogramowania pamiętać o zjawisku piramidy propagacji błędów, które polega na tym, że nie usunięte błędy z wcześniejszych faz cyklu życia mogą powodować dużo większą liczbę błędów w kolejnych fazach (patrz: rys.1.2). Takie zjawisko jest niepożądane, ponieważ zwiększa ono stopień trudności zarządzania pracami wytwórczymi, utrudnia późniejszą pielęgnację oprogramowania, skutkuje niższym poziomem jakości przy zwiększonych kosztach produkcji oprogramowania. Wynika to przede wszystkim ze zwiększonej liczby sprzężeń zwrotnych powstałych z konieczności usunięcia błędów wykrytych zbyt późno - o ile można takie błędy jeszcze usunąć.
Norma [PKN ISO 8492] określa jakość jako ogół cech i właściwości wyrobu lub usługi decydujących o zdolności tego wyrobu lub usługi do zaspokojenia stwierdzonych lub przewidywanych potrzeb użytkownika produktu. To ogólne sformułowanie zostało sprecyzowane w toku dalszych rozważań. W treści podrozdziału 1.2 zostało przedstawione własne podejście do klasyfikacji agregatów jakości oprogramowania, które jest jednym z rodzajów wyrobu. W głównym nurcie rozważań znajduje się oprogramowanie współbieżne systemów informatycznych. W związku z tym szczególną uwagę poświęcono tym jego właściwościom, które są charakterystyczne szczególnie dla tej klasy oprogramowania.
Agregaty jakości oprogramowania
Jakość oprogramowania jest traktowana jako podstawowa właściwość oprogramowania. Oprogramowanie jest analizowane na poziomie modelu logicznego bez zwracania uwagi na postać kodu wynikowego [Bli97a]. Ważne są również efekty funkcjonowania oprogramowania, bowiem „sprawne” funkcjonowanie oprogramowania stanowi najczęściej o poziomie jego jakości dla potencjalnego użytkownika.
Zanim zostaną przedyskutowane poszczególne agregaty jakości oprogramowania, należałoby skomentować rozumienie pojęcia komponent oprogramowania, które jest dość mocno eksploatowane w dalszym toku rozważań prowadzonych w niniejszej rozprawie.
Komponent oprogramowania jest podstawowym elementem, z którego to oprogramowanie jest budowane. Identyfikacja komponentu może nastąpić na przykład na skutek zastosowania metody dekompozycji i abstrakcji w procesie wytwórczym oprogramowania. W ogólnym zarysie dekompozycja polega na wyodrębnieniu z większej całości oprogramowania pewnych jego elementów, które w rozumieniu prowadzonych rozważań nazywane są właśnie komponentami. Każdy z tych komponentów może podlegać dalszej dekompozycji na kolejne komponenty - o ile jest to konieczne z punktu widzenia realizacji oprogramowania. Mówi się wtedy o tzw. kolejnych poziomach analizy i projektu oprogramowania. Widać więc, że komponent oprogramowania jest pojęciem skalowalnym. Jego wielkość i znaczenie w procesie wytwórczym oprogramowania jest zależne od przyjętej metody analizy, projektowania i implementacji oprogramowania, jak również od etapu, na jakim znajduje się cykl wytwórczy oprogramowania.
Wprowadzone w tym miejscu pojęcie komponentu oprogramowania jest więc pewnym uniwersalizmem. Aby wskazać na konkretne przykłady interpretacji tego pojęcia, należy się odnieść do sposobu rozumienia pojęcia struktura oprogramowania w konkretnym przypadku oprogramowania. W ogólnym rozumieniu można powiedzieć, że struktura dowolnego obiektu jest pojmowana jako zbiór pewnych jego elementów i relacji pomiędzy nimi. Struktura wyraża więc pewien sposób widzenia, pojmowania tego obiektu przez człowieka. I tak na przykład, gdyby analizować dekompozycję oprogramowania w sensie jego struktury funkcjonalnej [Brk96], to komponentem oprogramowania należy nazwać funkcję będącą podstawowym elementem tej struktury. Jeżeli oprogramowanie zostało zdekomponowane w sensie jego struktury przetwarzania opartego na aktywnościach funkcji nazywanych procesami [Brk96, DeMar79], to komponentem oprogramowania jest proces. W ogólnym rozumieniu, jeżeli procesy pracują zależnie w nierozłącznych przedziałach czasu, to są one nazywane procesami współbieżnymi, jeżeli zaś są one zależne, ale pracują w rozłącznych przedziałach czasu, to są to procesy sekwencyjne. Kontynuując przykłady rozumienia pojęcia komponent oprogramowania, w przypadku zastosowania w procesie wytwórczym podejścia obiektowego jego podstawowymi komponentami są klasa i obiekt, będący egzemplarzem klasy [Sub97]. Dla modułowej struktury oprogramowania podstawowym komponentem jest moduł, zaś dla oprogramowania zaimplementowanego w klasycznym podejściu strukturalnym jego komponentem jest podprogram. W przypadku implementacji programów współbieżnych jako podstawowy rodzaj komponentu tej klasy oprogramowania rozumiany jest proces współbieżny.
Komponenty oprogramowania stanowią więc elementy odpowiednio określonej struktury oprogramowania. Aby tworzyć tę strukturę powinny one pozostawać względem siebie w określonych relacjach. Znaczenie relacji, podobnie jak rozumienie pojęcia komponent oprogramowania, jest uzależnione od rodzaju konkretnej struktury oprogramowania. I tak na przykład dla struktury funkcjonalnej oprogramowania relacje pomiędzy komponentami odzwierciedlają hierarchię funkcji [Brk96] (funkcje nadrzędne, podrzędne). W strukturze procesowej oprogramowania relacje mogą odzwierciedlać wzajemne interakcje pomiędzy procesami [DeMar79, Bari89, Brk96]. Dla rozkładu obiektowego oprogramowania relacje mogą wyrażać hierarchię klas lub interakcje pomiędzy nimi [Sub97]. W przypadku podejścia strukturalnego, relacje mogą oddawać hierarchię modułów czy podprogramów albo strukturę ich wzajemnych wywołań.
W szczególnym przypadku implementacja relacji w strukturze funkcjonalnej oprogramowania może być rozumiana jako realizacja wzajemnych wywołań poszczególnych funkcji oprogramowania czy też jego modułów [Brk96] (w zależności od aktualnego etapu cyklu wytwórczego oprogramowania) jak również wzajemnych wywołań klas czy obiektów z podejścia obiektowego. W oprogramowaniu współbieżnym najczęściej pojmowane relacje wyrażają interakcje pomiędzy procesami współbieżnymi. Interakcje te mogą wynikać z konieczności synchronizacji procesów współbieżnych w dostępie do współdzielonych zasobów lub wymiany danych pomiędzy procesami. Zdefiniowane relacje mogą być różnie implementowane w konkretnych przypadkach oprogramowania. Wymiana danych pomiędzy procesami, na przykład, może być realizowana poprzez współdzielone zasoby, co jest charakterystyczne dla nierozproszonego oprogramowania współbieżnego [Bari89] albo przy pomocy mechanizmu przesyłania komunikatów, co jest często stosowane w oprogramowaniu rozproszonym [Tann95]. W ogólnym rozumieniu można powiedzieć, że komunikat jest identyfikowalną paczką informacji przesyłaną na drodze od wskazanego nadawcy do wskazanego adresata. Rejestracja faktu przejścia komunikatu jest realizowane przez specjalizowaną warstwę oprogramowania (nazywaną przeważnie warstwą komunikacyjną oprogramowania). Najczęściej przytaczanymi rodzajami komunikatów ze względu na sposób ich przesyłania są:
komunikaty synchroniczne, które wymagają synchronizacji czasowej nadawcy i adresata komunikatu [Bari89, Tann95],
komunikaty asynchroniczne, które nie wymagają czasowej synchronizacji nadawcy i adresata komunikatu [Bri78, Tann95].
Każdy z komunikatów może być wysyłany do pojedynczego adresata lub do ich zdefiniowanej grupy. Można również rozsyłać komunikaty w trybie potwierdzania ich odbioru przez adresata lub bez takiego potwierdzania.
Rysunek 1.3 przedstawia schemat klasyfikacji dotyczący jakości oprogramowania. Wyodrębnionych zostało 44 właściwości szczegółowych, zgrupowanych w 5-ciu podgrupach. Każda podgrupa stanowi uszczegółowienie klasyfikacji dla głównych składowych jakości. Są to: poprawność, niezawodność, złożoność, adekwatność i pielęgnacyjność oprogramowania.
Poprawne (poprawność - ang. correctness) oprogramowanie współbieżne powinno być bezpieczne, żywotne i czytelne. Bezpieczeństwo (ang. safety) jest rozumiane jako potencjalna możliwość uzyskania poprawnych wyników obliczeń po uruchomieniu tego oprogramowania. Jest to tzw. statyczna właściwość oprogramowania [Bari89], o której istnieniu orzeka się na podstawie analizy tekstu źródłowego programu lub postaci jego modelu formalnego. O dowolnym programie współbieżnym mówi się, że jest on bezpieczny wtedy, gdy każde zgłoszenie konieczności dostarczenia konkretnej informacji ze strony dowolnego komponentu współbieżnego lub też żądanie dostępu do zasobu ma potencjalną możliwość poprawnej obsługi. Potencjalna możliwość poprawnej obsługi nie musi oznaczać, że z całą pewnością będzie ona miała miejsce. Należy jednak wykazać, że oprogramowanie (w jego założeniach lub realizacji) przewiduje zapewnianie takiego wymogu.
Warto nadmienić, że właściwość bezpieczeństwa wywodzi się z częściowej poprawności algorytmu sekwencyjnego. Częściowo poprawny algorytm sekwencyjny, o ile zakończy swoje działanie, to z pewnością wygeneruje poprawny rezultat. Wymagania programowania współbieżnego komplikują rozumienie pojęcia częściowej poprawności algorytmów. Oznaczają one często, że uzyskanie poprawnych wyników nie musi być warunkowane trwałym wstrzymaniem obliczeń. Wynika to na przykład z faktu, że w grupie systemów współbieżnych pracujących w trybie ciągłym zatrzymanie działania systemu jest traktowane jako błąd. Nie można więc tutaj analizować algorytmów wyłącznie w taki, jaki stosuje się przy algorytmach sekwencyjnych, gdzie jedną z podstawowych metod jest badanie zachodzenia określonych warunków logicznych na wejściu i na wyjściu wskazanych bloków w tych algorytmach.
Bezpieczeństwo oprogramowania może być również rozpatrywane w kategoriach jego poprawności formalnej. Jest ona rozumiana jako spełnienie wymagań przyjętej metody projektowania (modelowania) oprogramowania - o ile obligacje dowodzenia w tej metodzie dowodzą właściwości statycznego bezpieczeństwa algorytmów czy programów. Czynniki określające spełnienie konkretnych wymagań metody projektowania wynikają z jej aksjomatów. W związku z tym zagadnienie formalnej poprawności programów współbieżnych powinno być omawiane w aspekcie konkretnej metody projektowania (modelowania) oprogramowania.
Przedstawione powyżej rozumienie bezpieczeństwa oprogramowania jest składową szeroko pojętej problematyki bezpieczeństwa systemów strategicznych (odpowiedzialnych), o której traktują między innymi zacytowane w podrozdziale 1.3 normy IEC 1508 i IEC/TC 56, a także zalecenia jakościowe z [Blo94].
Żywotność (ang. liveness) jest to jedna z podstawowych właściwości dynamicznych [Bari89, Tann95] oprogramowania współbieżnego. Jej dynamika wynika z faktu, iż własność ta objawia się dopiero wtedy, gdy oprogramowanie zostało uruchomione. Dowolny program współbieżny można określić jako żywotny wtedy, gdy jednorazowo lub cyklicznie zachodzą w nim zjawiska oczekiwane z punktu widzenia określonych wymagań na sposób jego funkcjonowania.
Interpretacja cechy żywotności programów współbieżnych wywodzi się z definicji właściwości całkowitej poprawności algorytmów sekwencyjnych mówiącej, że całkowicie poprawny algorytm sekwencyjny zakończy swoje działanie (posiada właściwość stopu) i wygeneruje poprawny rezultat. Żywotność programu oznacza, że jest on reaktywny, odporny na zagłodzenia i zakleszczenia.
Reaktywność (ang. reactivity) (skuteczność, nadążność, efektywność) jest szczególnie istotna dla oprogramowania systemów czasu rzeczywistego. Dowolne oprogramowanie można określić jako reaktywne wtedy, gdy realizuje ono sensowne czynności z zachowaniem narzuconych na nie rygorów czasowych. Jest to bardzo ważna cecha oprogramowania systemów uwarunkowanych czasowo. Jej spełnienie powinno stanowić kryterium akceptacji tej klasy oprogramowania. Reaktywność oprogramowania jest uzależniona od następujących czynników:
- konfiguracji tzw. komponentów oprogramowania (modelu statycznego oprogramowania),
- szybkości wykonywania czynności przez poszczególne komponenty współbieżne,
- wydajności struktury komunikacji komponentów,
- konfiguracji wymuszeń wewnętrznych i zewnętrznych.
Model statyczny oprogramowania powstaje na etapie projektowania systemu. Powinien on być kompletny i spójny logicznie, a co za tym idzie: zapewniać spełnienie właściwości bezpieczeństwa oprogramowania. W procesie wytwórczym oprogramowania współbieżnego dla systemów czasu rzeczywistego można przyjąć założenie, że program, który nie jest bezpieczny w większym stopniu jest narażony na utratę reaktywności niż taki program, dla którego wykazano, że spełnia on ograniczenia wynikające z bezpieczeństwa.
Szybkość wykonywania czynności przez procesy w systemie istotnie wpływa na dynamikę pracy całego systemu. Istotna jest tu szybkość realizacji obliczeń przez poszczególne procesy, co może mieć również związek z szybkością współpracy pomiędzy komponentami oprogramowania w przypadku, gdy jest ona konieczna w trakcie realizacji obliczeń. W przypadku oprogramowania rozproszonego istotna jest również wydajność podsystemu komunikacji. Brak wydolności tego podsystemu z całą pewnością może być przyczyną utraty reaktywności oprogramowania.
Konfiguracja wymuszeń wewnętrznych i zewnętrznych w systemie jest rozumiana w dwóch płaszczyznach:
- statyki wymuszeń, wynikającej z modelu (np. specyfikacji) oprogramowania,
- dynamiki wymuszeń, na którą wpływają dwa czynniki:
-- częstotliwość wymuszeń,
-- czasu oczekiwania wymuszenia na identyfikację i obsługę.
Zagłodzenie (ang. starvation) w [Bari89] jest rozumiane jako przypadek lokalnego braku żywotności programu współbieżnego. W przypadku zagłodzenia można zidentyfikować w oprogramowaniu zadanie, które wykonuje sensowne czynności, podczas gdy inne zidentyfikowanie zadanie jest trwale wstrzymywane. Dla potrzeb dalszych rozważań przyjęto, że o dowolnym komponencie współbieżnym oprogramowania mówi się, iż uległ on zagłodzeniu wtedy, gdy bezskutecznie usiłuje uzyskać dostęp do konkretnego zasobu i pomimo to nie zatrzymuje on swojego działania. Zasobem systemu oprogramowania może być składnik sprzętu, systemu operacyjnego albo inny komponent systemu, z którym komponent ten usiłuje nawiązać współpracę. Posługując się przykładem pięciu filozofów E.Dijkstry [Dij71] można stwierdzić, że komponent, który uległ zagłodzeniu jest w stanie aktywnego oczekiwania na udostępnienie zasobu/komponentu. Aktywne oczekiwanie polega na tym, że co pewien czas wykonywane jest sprawdzenie, czy żądany zasób/komponent jest dostępny. W międzyczasie komponent wykonuje pewne czynności, które nie powoduje postępu wykonywanych przezeń obliczeń poza to miejsce w algorytmie, które wymaga współpracy z określonym zasobem/komponentem.
Blokada (ang. blockade) jest w [Bari89] określana jako przypadek globalnego braku żywotności programu współbieżnego. O blokadzie mówić się wtedy, gdy w systemie nie można zidentyfikować przynajmniej jednego zadania wykonującego sensowną pracę. Ben-Ari wskazał na bardzo niekorzystne zjawisko globalnej blokady. Jednak bardzo groźne dla poprawnego funkcjonowania programów współbieżnych może się okazać występowanie tzw. lokalnych zakleszczeń (ang. deadlock), których konsekwencją może być globalna blokada (np. na skutek stopniowego blokowania się kolejnych komponentów oprogramowania). W klasycznym rozumieniu zakleszczenie wymaga udziału co najmniej dwóch komponentów i dwóch zasobów. Zakleszczenie powstaje na przykład w sytuacji, gdy:
pierwszy komponent uzyskał dostęp na wyłączność do pierwszego z zasobów,
w tym samym czasie drugi komponent otrzymał dostęp na wyłączność do drugiego z zasobów,
w tym samym czasie pierwszy komponent bezskutecznie żąda dostępu do drugiego zasobu,
również w tym samym czasie drugi komponent bezskutecznie żąda dostępu do pierwszego zasobu.
Blokadę należy rozpatrywać już na poziomie lokalnym. Jest ona w swojej naturze podobna do zagłodzenia. Jest to blokada komponentu, który bezskutecznie żąda dostępu do zasobu/komponentu i w tym czasie komponent nie wykonuje żadnych czynności. Jedynym bodźcem, który uaktywni go ponownie, jest uzyskanie oczekiwanego dostępu. Symptomem blokady może być zagłodzenie. Takie zjawisko może mieć miejsce wtedy, gdy dla funkcjonowania komponentu określono maksymalną dopuszczalną liczbę prób dostępu do zasobu/komponentu. Do czasu przekroczenia tej liczby komponent jest w stanie zagłodzenia. Po przekroczeniu ustalonej liczby dostępów komponent przechodzi w stan blokady. Od tej chwili jedynym sposobem na przywrócenie jego aktywności jest udostępnienie mu żądanego zasobu/komponentu. W dalszym toku rozważań blokada będzie rozumiana w taki właśnie sposób. Oznaczenie takiej też blokady zostało umieszczone na rysunku 1.3. Istotne jest, że w przedstawionych rozważaniach rozróżnia się blokadę zwykłą od blokady po zakleszczeniu (ang. lock, tackle). Blokada po zakleszczeniu występuje na przykład w zacytowanym scenariuszu zakleszczenia. Polega ona na tym, że komponent posiadający na wyłączność dostęp do określonego zasobu blokuje dostęp do tego zasobu innym komponentom. Tak więc zasób został zablokowany i inne komponenty, które w czasie trwania blokady po zakleszczeniu będą chciały z niego skorzystać, są potencjalnie zagrożone utratą żywotności. W tym przypadku mogą one ulec zakleszczeniu, blokadzie lub zagłodzeniu.
Czytelność (ang. legibility) może dotyczyć postaci tekstu źródłowego oprogramowania. Jest ona określona w zasadach dobrego stylu programowania. Współczesne rozważania rozszerzają zakres analizy czytelności oprogramowania na postać zapisu jego koncepcji, projektu. W zasadzie bada się postać udokumentowania całego cyklu wytwórczego oprogramowania. Oprogramowanie czytelne powinno być zwięzłe (ang. conciseness), a więc zawierać w swojej treści tylko takie słowa, które wnoszą istotne informacje. Oprogramowanie czytelne powinno być jednoznaczne (ang. explicitness), czyli zapisane w sposób wyraźnie sugerujący znaczenie tekstu dokumentu/programu. I wreszcie, oprogramowanie czytelne powinno być dostępne (ang. accessibility). Dostępność testu jest rozumiana w aspekcie sprawności przyswajania i zrozumienia jego zawartości przez potencjalnego czytelnika.
Zaprezentowane w [Kor86] podejście do niezawodności obiektów technicznych zostało potwierdzone w normach, dotyczących niezawodności oprogramowania, tj. w [IEC 300-3-6]. Niezawodność obiektu technicznego jest określana jako właściwość obiektu charakteryzująca jego zdolność do wykonywania określonych funkcji, w określonych warunkach i w określonych przedziałach czasu. Jest ona właściwością kompleksową, w której skład wchodzi nieuszkadzalność, obsługiwalność i utrzymywalność.
Przy omawianiu nieuszkadzalności (ang. reliability) oprogramowania skorzystano z rozważań zawartych w [Kop80]. Należy jednak nadmienić, że pojęcie nazywane w tej pozycji „niezawodnością”, w [Kor86] i w [IEC 300-3-6] nazywane jest „nieuszkadzalnością”. W niniejszych rozważaniach zastosowano podejście z norm IEC. Ogólne pojęcie nieuszkadzalności systemu (technicznego) jest rozumiane jako dwuargumentowa relacja pomiędzy systemem i czasem jego funkcjonowania. Można ją zdefiniować następująco:
Nieuszkadzalność systemu jest to prawdopodobieństwo zdarzenia polegającego na tym, że w zadanym z góry przedziale czasowym, przy określonych warunkach, system zachowa zdolność do wykonywania zadań, do których został przeznaczony.
W przypadku oprogramowania utrata zdolności do funkcjonowania może być spowodowana awarią platformy sprzętowo-programowej, na której zostało ono uruchomione albo wystąpieniem błędu programowego. Błąd programowy jest rozumiany jako przypadek wystąpienia niepoprawnej danej wyjściowej (niezgodnej z założeniami, specyfikacją), wygenerowanej dla dopuszczalnych zestawów danych wejściowych. Ze względu na przyczynę swojego wystąpienia, błędy programowe można podzielić na następujące rodzaje:
błędy projektowe powstające na etapie analizy i projektu oprogramowania,
błędy starzenia powstające w wyniku eksploatacji oprogramowania,
błędy danych objawiające się w czasie funkcjonowania oprogramowania.
Błędy projektowe mają naturę statyczną (błędy statyczne). Powstają one na etapie analizy i projektu oprogramowania. Ważne jest więc, aby przyjęta metoda projektowania oprogramowania minimalizowała ryzyko powstawania takich błędów. Z uwagi na to, że oprogramowanie uruchamiane na poprawnie działającym sprzęcie jest systemem technicznym, który się nie starzeje, nie są brane pod uwagę błędy starzenia się systemu. Błędy danych mają naturę dynamiczną. Powstają w czasie funkcjonowania systemu. Mogą one wynikać z błędów projektowych, a także z niekompletności założeń projektowych względem warunków i sposobu funkcjonowania systemu, czyli błędów analizy systemu.
Rozważając pojęcie błędu programowego należy zaznaczyć, że najbardziej kłopotliwe do wykrycia i usunięcia są tzw. przypadkowe błędy dynamiczne. Są to takie błędy, które występują chwilowo i nieregularnie, ale ich oddziaływanie na funkcjonowanie systemu może doprowadzić do jego upadku. Łatwiejsze do wykrycia, aczkolwiek równie niepożądane, są tzw. trwałe błędy dynamiczne oprogramowania. Są to takie błędy, które występują stale, bądź objawiają się systematycznie w określonych warunkach.
Obsługiwalność (ang. maintainability) jest właściwością oprogramowania określaną dla etapu jego eksploatacji, charakteryzującą zdolność oprogramowania do utrzymywania stanu prawidłowego funkcjonowania dla poprawnych i niepoprawnych zestawów danych wejściowych, jak również do wielokrotnego przywracania stanu prawidłowego funkcjonowania (stanu zdatności - [Kor86]) oprogramowania dla przypadku upadku systemu. Na obsługiwalność składają się odporność, odnawialność i powtarzalność.
Odporność (ang. durability) oprogramowania jest rozumiana jako cecha poprawności funkcjonowania oprogramowania w odniesieniu do niepoprawnych danych wejściowych. W ogólnym pojęciu odporność oprogramowania rozumiana jest jako zdolność oprogramowania do wykonywania swoich zadań pomimo otrzymywania niepoprawnych danych wejściowych czy uszkodzeń sprzętu.
Odnawialność (ang. self-containednesss) oprogramowania jest rozumiana jako zdolność systemu do ponownego, autonomicznego, prawidłowego uruchomienia się oprogramowania po jego uprzednim upadku. W przypadku systemów uwarunkowanych czasowo o upadku oprogramowania mówi się wtedy, gdy nie spełnia ono wymagań reaktywności. Należy rozróżniać właściwość odnawialności od naprawialności związanej z etapem pielęgnacji oprogramowania. Naprawialność oprogramowania ma wprawdzie związek z niezawodnością oprogramowania, ale ze względu na określenie cyklu życia oprogramowania [IEC 300-3-6], została ona określona jako jeden ze składników właściwości pielęgnacyjności oprogramowania.
Niezmienności zachowań (ang. consistency) jest rozumiana jako zjawisko powtarzania przez oprogramowanie identycznych czynności dla tych samych zestawów danych wejściowych podawanych w rozłącznych przedziałach czasu funkcjonowania oprogramowania. Niezmienność zachowań może być rozważana w dwóch aspektach:
- dla oprogramowania uruchamianego w jednorodnym środowisku sprzętowo-programowym,
- dla oprogramowania uruchamianego w różnych środowiskach sprzętowo-programowych.
Kolejną składową niezawodności jest utrzymywalność (ang. maintenance support). Jest to właściwość oprogramowania grupująca cechy związane z etapami testowania i przechowywania oprogramowania. Są to: testowalność i przechowywalność.
Testowalność (ang. testability) jest rozumiana w kontekście podatności oprogramowania na testy. Podatność na testy jest rozumiana jako możliwość wygenerowania pełnego, tj. uwzględniającego wszystkie warianty zachowań zestawu danych testowych, wprowadzonych do testowanego oprogramowania, uzyskania sensownych rezultatów przeprowadzonych testów, interpretacji wyników testowania i wprowadzania wniosków z wyników testów do oprogramowania.
Przechowywalność (ang. easiness of storage) jest właściwością systemu określającą zdolność oprogramowania do poprawnego funkcjonowania w warunkach przechowywania i co najmniej bezpośrednio po zakończeniu okresu jego przechowywania. W przypadku wyprodukowanego oprogramowania przechowywalność jest bezpośrednio określana poprzez jakość nośników danych, w których przechowywany jest kod oprogramowania, w uzależnieniu od liczby sporządzonych kopii zapasowych oprogramowania.
Złożoność (ang. complexity) oprogramowania jest rozumiana jako miara skomplikowania jego struktury. Złożoność może być rozpatrywana w kontekście struktury funkcji systemu, komunikacji w systemie, struktury procesowej, zadaniowej i modułowej, a także złożoności struktury wewnętrznej tekstu oprogramowania. W odniesieniu do algorytmów stosuje się pojęcie tzw. złożoności obliczeniowej. Duża złożoność oprogramowania może wpływać na zmniejszenie jego niezawodności.
Ze względu na ludzką percepcję najczęściej stosowanym sposobem analizy problemów jest ich rozkład hierarchiczny. W teorii programowania jest to wyrażone w postaci zasad dekompozycji i abstrakcji. W przypadku oprogramowania współbieżnego zasada dekompozycji powinna uwzględniać przypadek równoczesnej i zależnej pracy komponentów współbieżnych oprogramowania.
Złożoność funkcjonalna (ang. functional complexity) jest rozpatrywana na płaszczyźnie struktury funkcjonalnej oprogramowania. Funkcje systemu mają z natury rzeczy strukturę hierarchiczną. Postać hierarchii funkcji jest analizowana na podstawie wyników analizy systemu. Analiza złożoności funkcjonalnej oprogramowania może być realizowana po to, aby stwierdzić czy np. funkcje systemu nie są zaprojektowane w sposób zbyt skomplikowany powodujący istotne utrudnienie realizacji i użytkowania oprogramowania.
Złożoność komunikacyjna (ang. communicational complexity) jest szczególnie istotna dla oprogramowania współbieżnego. Jest rozumiana jako złożoność struktury komunikacji komponentów oprogramowania. Komunikacja w systemie jest rozumiana jako współpraca poszczególnych jego elementów ze względu na dane lub ze względu na sterowanie. Może być rozpatrywana na następujących płaszczyznach:
Komunikacja pomiędzy procesami realizującymi konkretną funkcję systemu. Jest ona rozpatrywana na płaszczyźnie związków komunikacyjnych pomiędzy różnymi zadaniami współpracującymi ze sobą w celu zrealizowania konkretnej funkcji systemu. Komunikacja międzyzadaniowa jest istotna dla przypadku współbieżnej dekompozycji systemu.
Komunikacja w odniesieniu do zadań. Rozpatrywana jest tutaj zadaniowa struktura oprogramowania, która najczęściej jest rozpatrywana w odniesieniu do struktury funkcjonalnej oprogramowania.
Więź międzymodułowa jest rozpatrywana wtedy, gdy moduły programowe współpracują ze sobą. Ten aspekt komunikacji ma związek ze złożonością modułową oprogramowania.
Komunikacja w obrębie modułu programowego. Aspekt ten jest istotny wtedy, gdy poszczególne podprogramy (które mogą stanowić implementację funkcji lub zadań) współpracują ze sobą w ramach tego samego modułu programowego.
Złożoność obliczeniowa (ang. computational complexity) [Aho83] jest określana w kontekście czasu realizacji obliczeń (złożoność czasowa algorytmów) lub w aspekcie ilości pamięci potrzebnej na realizację obliczeń (złożoność pamięciowa algorytmów). Złożoność czasowa algorytmu jest to czas realizacji obliczeń wyznaczony jako funkcja głównie rozmiaru zadania. Złożoność pamięciowa algorytmu jest to wielkość pamięci niezbędnej dla zrealizowania algorytmu, wyznaczona jako funkcja rozmiaru zadania. Rozmiar zadania jest specyficznie zdefiniowaną liczbą naturalną określoną dla konkretnego zadania. Może to być na przykład liczba krawędzi czy wierzchołków grafu dla zadania z teorii grafów, rozmiary tablic w realizacji zadania mnożenia macierzy itd.
Złożoność modułowa (ang. modular complexity) ma ścisły związek z postacią kodu źródłowego oprogramowania i jest określana na podstawie hierarchicznej struktury modułów programowych składających się na realizowane oprogramowanie.
Złożoność zadaniowa (ang. task-complexity) jest rozumiana w odniesieniu do współbieżnej dekompozycji problemu, dla którego powstało analizowane oprogramowanie. Rozpatrywana jest z dwóch punktów widzenia:
złożoność struktury wewnętrznej poszczególnych zadań rozpatrywana w aspekcie ich budowy, a także struktury ich miejsc komunikacyjnych,
złożoność zadań z punktu widzenia całego systemu rozpatrywana na płaszczyźnie złożoności struktury zadaniowej systemu w odniesieniu do jego struktury funkcjonalnej, jak również ze względu na złożoność struktury komunikacji międzyzadaniowej, co ma związek ze złożonością komunikacyjną.
Złożoność struktury wewnętrznej tekstu oprogramowania (ang. source code complexity) jest określana dla konkretnej postaci realizacji oprogramowania. W literaturze podaje się tzw. metryki złożoności struktury wewnętrznej oprogramowania [Jun87, Bli90, Bli98].
Adekwatność (ang. adequacy) oprogramowania jest miarą oceny czy wytworzone oprogramowanie jest odpowiednie dla zadanego problemu lub sprecyzowanych wymagań użytkownika. Na adekwatność oprogramowania wpływają: kompletność, racjonalność funkcjonalna i komunikacyjna oraz spójność funkcjonalna i komunikacyjna.
Kompletne (kompletność - ang. completeness) oprogramowanie powinno uwzględniać wszystkie założenia projektowe. Oprogramowanie spełniające tylko część tych założeń może funkcjonalnie nie odpowiadać przyszłemu użytkownikowi oprogramowania, a co za tym idzie - może nie być dopuszczone do wdrożenia. Kompletność jest cechą statyczną oprogramowania.
Racjonalność funkcjonalna (ang. functional rationality) jest rozpatrywana w aspekcie faktycznego wykorzystania w działającym oprogramowaniu zaprojektowanej w procesie wytwórczym struktury funkcjonalnej. Oprogramowanie kompletne nie musi być w pełni racjonalne. Aby orzec o racjonalności systemu należy zbadać wykorzystywanie w praktyce poszczególnych funkcji oprogramowania. Jeżeli w wyniku takiego badania stwierdzono, że częstość wykorzystywania kolejnych funkcji mieści się w przyjętych tzw. zakresach racjonalności oprogramowania, to badane oprogramowanie można określić jako racjonalne.
Racjonalność komunikacyjna (ang. communicational rationality) jest rozpatrywana w kontekście faktycznego wykorzystania w działającym systemie zaprojektowanych mechanizmów komunikacyjnych. Analizując tę cechę należy prześledzić dynamikę zjawiska komunikacji w oprogramowaniu i stwierdzić, czy wszystkie zaprojektowane w oprogramowaniu mechanizmy komunikacyjne są wykorzystywane z oczekiwaną intensywnością. W przeciwnym wypadku, a szczególnie gdy stwierdzimy, że istnieją w oprogramowaniu mechanizmy komunikacyjne w ogóle nie wykorzystywane, należy rozważyć możliwość zmiany modelu statycznego mechanizmów komunikacji komponentów oprogramowania.
Zwartość funkcjonalną (ang. functional cohesion) rozważa się w aspekcie dekompozycji głównych funkcji oprogramowania na podfunkcje realizujące czynności pośrednie, które po złożeniu dają w efekcie wyniki działania podstawowych funkcji oprogramowania. Jeżeli stwierdzono, że w czasie działania systemu nie są uruchamiane funkcje wynikające z założeń projektowych lub nie kończą się sukcesem ze względu na niemożność poprawnego zakończenia innych funkcji uzupełniających, to można stwierdzić, że system nie jest zwarty funkcjonalnie. W przypadku oprogramowania systemów uwarunkowanych czasowo spełnienie wymagań zwartości funkcjonalnej może mieć istotny wpływ na reaktywność systemu.
Zwartość komunikacyjna (ang. communicational cohesion) jest rozpatrywana w aspekcie dynamiki zjawiska komunikacji komponentów oprogramowania. Spełnienie wymagań na bezpieczeństwo statyczne jest warunkiem koniecznym, aczkolwiek niewystarczającym dla zachowania przez oprogramowanie zwartości komunikacyjnej. Oprogramowanie jest zwarte komunikacyjnie wtedy, gdy wszystkie zawarte w nim mechanizmy komunikacyjne są zdolne do funkcjonowania zgodnego z oczekiwaniami. Nie powinna zaistnieć sytuacja, w której jakiś komunikat z przyczyn od niego niezależnych nie może dotrzeć od nadawcy do adresata, wskutek czego powstaje zjawisko zanikania żywotności w systemie.
System oprogramowania powinien być podatny na pielęgnację, a więc spełniać właściwość pielęgnacyjności (ang. software maintenance). Cecha ta ma silny związek z przyjętą metodą wytwarzania oprogramowania. Oprogramowanie, spełniające wymagania pielęgnacyjności powinno być łatwe do wdrożenia, progresywne, modyfikowalne, przenośne i naprawialne.
Łatwość wdrożenia (ang. easiness of application) jest rozumiana zarówno w aspekcie technicznej, jak i ekonomicznej łatwości uruchomienia systemu u użytkownika. Kryterium łatwości ekonomicznej wdrożenia systemu określane jest mianem tzw. kryterium optimum kosztu [Cal93]. Istotne jest ponadto wewnętrzne przygotowanie samego użytkownika do przyjęcia oprogramowania. Nawet oprogramowanie, które nie sprawia większych problemów technicznych i jest dopuszczalne ze względu na czynnik ekonomiczny, może napotkać niezmiernie trudną do pokonania barierę nieprzychylności bądź nieprzystosowywalności użytkownika do przyjęcia tego oprogramowania.
Progresywność (ang. augmentability) jest rozumiana jako możliwość rozwijania systemu na bazie aktualnej postaci jego projektu, jak i postaci oprogramowania wdrożonego. Z tą tematyką związane są badania dotyczące ponownego użycia projektu w cyklu życia oprogramowania.
Modyfikowalność (ang. modifialibity) jest rozumiana jako ocena łatwości modyfikacji oprogramowania w kierunku indywidualnych potrzeb użytkownika. Zakłada się, że w wyniku tych modyfikacji nie powstaje zupełnie nowy system, lecz jego kolejna wersja.
Przenośność (ang. portability) oznacza zdolność uruchamiania systemu w jego aktualnej postaci na różnych platformach aplikacyjnych. Przenośność może dotyczyć zarówno wyników analizy i projektu, jak również gotowej implementacji oprogramowania.
Naprawialność (ang. repairability) jest natomiast rozumiana jako podatność oprogramowania na wielokrotne usuwanie awarii w określonych warunkach jego eksploatacji. Usuwanie awarii nie powinno wpływać na spadek sprawności oprogramowania.
Z powyższych rozważań wynika, że jakość oprogramowania jest cechą złożoną, która zależy od wielu, często odmiennych od siebie czynników. Pomimo tego każda licząca się firma informatyczna w swojej strategii pozyskania rynku powinna założyć wdrożenie i przestrzeganie polityki jakości. W podrozdziale 1.3 został zamieszczony syntetyczny przegląd ważniejszych aktów normatywnych związanych z jakością oprogramowania.
Stan aktów normatywnych
Norma [PKN ISO 9001] omawia zasady zapewniania przez dostawcę zgodności wyrobu lub usługi z ustalonymi wymaganiami podczas projektowania, prac rozwojowych, produkcji, instalowania i serwisu. Norma [PKN ISO 9002] przedstawia zalecenia w zakresie zapewniania przez dostawcę zgodności wyrobu lub usługi z ustalonymi wymaganiami podczas produkcji, instalowania i serwisu. Norma [PKN ISO 9003] dotyczy jedynie etapu kontroli i badań szczegółowych dostarczanego wyrobu lub usługi. Zalecenia wymienionych norm uzupełniają wymagania techniczne dotyczące wyrobu. Ustalają one wymagania określające istotne elementy systemu jakości. Nie odnoszą się one do określonej branży lub określonego sektora gospodarczego. Wynika to z tego, że na określone potrzeby związane z projektowaniem i wdrażaniem systemów jakości mają wpływ specyficzne potrzeby różnych organizacji produkujących różne wyroby.
Norma [PKN ISO 9000-1] stanowi zbiór zaleceń dotyczących dostosowywania norm podstawowych do potrzeb poszczególnych rodzajów organizacji powołujących systemy jakości. Zawarty jest w niej zestaw definicji pojęć związanych z systemem jakości. Aby w ogóle mówić o wytwarzaniu zgodnym z zaleceniami ISO 9000 należy stworzyć system jakości, będący odpowiednio zbudowaną strukturą organizacyjną z jednoznacznym podziałem odpowiedzialności, określeniem procedur, procesów i zasobów, umożliwiających wdrożenie tzw. zarządzania jakością. Zarządzanie jakością jest związane z aspektem całości funkcji zarządzania organizacji, który jest decydujący w określaniu i wdrażaniu polityki jakości. Stanowi ona ogół zamierzeń i kierunków działań organizacji dotyczących jakości, w sposób formalny wyrażony przez najwyższe kierownictwo organizacji, będącej systemem jakości. Zapewnienie jakości jest związane między innymi z pojęciem audytu jakości. Audyt jakości jest systematycznym i niezależnym badaniem, mającym określić, czy działania dotyczące jakości i ich wyniki odpowiadają zaplanowanym ustaleniom i czy te ustalenia są skutecznie realizowane, i czy umożliwiają osiągnięcie odpowiedniego poziomu jakości. Audyt jakości może być przeprowadzany przez kontrole wewnętrzne lub zewnętrzne. Może on być przeprowadzany w odniesieniu do:
całego systemu jakości - „audyt systemu jakości”,
procesów - „audyt jakości procesu”,
wyrobów - „audyt jakości wyrobu”,
usług - „audyt jakości usługi”.
Audyty jakości powinny być przeprowadzane przez osoby, które nie ponoszą bezpośredniej odpowiedzialności za dziedziny przedmiotowe, poddawane audytowi, ale najlepiej we współpracy z personelem odpowiedzialnym za tę dziedzinę. Wyniki audytów powinny być dokumentowane i archiwizowane. Nie należy jednak mylić audytu z „nadzorowaniem” lub „kontrolą”, będącymi działaniami mającymi na celu sterowanie procesem zapewniania jakości. Zadaniem audytu jakości jest ocena potrzeby korekty wykonania obiektu poddanego audytowi. Należy więc jednoznacznie ocenić poziom jakości badanej dziedziny bez podejmowania decyzji o tym, w jaki sposób przeprowadzić działania korygujące, nadzorcze czy kontrolne. Jest to w gestii systemu jakości, w którym przeprowadzane są audyty jakości.
Norma [PKN ISO 9000-3] zawiera wytyczne ułatwiające organizacjom opracowującym, dostarczającym i obsługującym oprogramowanie stosowanie normy ISO 9001. Celem normy jest określenie zalecanych sposobów zarządzania i metod produkcji oprogramowania spełniającego wymagania nabywcy. Zalecenia te nie odnoszą się jednak do konkretnych etapów cyklu życia oprogramowania. Mają one charakter ogólny pozostawiając swobodę w ich wyborze organizacjom stosujących tę normę. Cytowany dokument rozszerza definicję pojęć podstawowych z normy ISO 9000-1 o kwestie dotyczące oprogramowania. Tak więc oprogramowanie jest rozumiane jako efekt pracy ludzkiego umysłu, obejmujący programy, procedury, zasady i wszelkie dokumenty z nim związane, dotyczące obsługiwania systemu przetwarzania danych. Oprogramowanie jest niezależne od nośnika, na którym jest ono zapisane. Wyrób programowy, to kompletny zestaw programów komputerowych, procedur i dokumentów związanych oraz danych, dostarczany użytkownikowi. Jednostka programowa jest określona jako dowolna część wyrobu programowego identyfikowalna podczas pośredniego lub końcowego etapu opracowywania. Opracowywanie jest ogółem działań prowadzących do stworzenia wyrobu programowego. W niniejszych rozważaniach pojęcie opracowywania jest używane zamiennie z pojęciami wytwarzanie i proces wytwórczy. Weryfikacja oprogramowania, to proces oceny wyrobów danego fragmentu pracy, tj. etapu w celu zapewnienia prawidłowości i zgodności, w odniesieniu do wyrobów i norm dostarczonych jako dane wejściowe do tego etapu. Zatwierdzanie oprogramowania jest procesem jego oceny w celu zapewnienia zgodności z określonymi wymaganiami. Dalej norma przedstawia znaczenie polityki jakości, systemu jakości. Nie wykracza w tym istotnie poza zakres normy ISO 9000-1. Zwraca się uwagę na to, że w procesach opracowywania należy przewidzieć miejsce dla nabywcy, który na bieżąco powinien współpracować z wytwórcą oprogramowania. Mowa tutaj o bieżących dwustronnych konsultacjach i o wspólnych przeglądach stanu prac wytwórczych. Dalsze zalecenia normy ISO 9000-3 pokrywają się w zasadzie z przedstawionymi w podrozdziale 1.1 zaleceniami normy IEEE-730 odnośnie zawartości planu zapewniania jakości.
Ważnym umotywowaniem podjęcia niniejszej pracy jest zapis z normy ISO 9000-3, w którym zaleca się stosowanie pomiarów jakości wyrobu programowego. W zakresie miar jakości wyrobu programowego zaleca się, aby informacje dotyczące stosowanych miar były przekazywane i wykorzystywane do zarządzania procesem jego opracowywania i dostarczania. Równocześnie zaleca się, aby zastosowane miary były odpowiednie dla danego wyrobu. W tekście normy zamieszczono ponadto bardzo ważne z punktu widzenia prowadzonych w rozprawie rozważań spostrzeżenie, które mówi, że nie ma obecnie powszechnie akceptowanych jednostek miar dotyczących jakości oprogramowania. Niemniej, jako minimum zaleca się stosowanie miar, które umożliwiłyby określenie błędów i wad występujących w opisywanym obszarze z punktu widzenia odbiorcy. Zaleca się, aby stosowane miary były tak opisane, by ich wartości mogły być porównywalne. Ponadto zaleca się, aby dostawca oprogramowania gromadził dane ilościowe dotyczące jakości wyrobów programowych. Ma to na celu:
gromadzenie danych i przekazywanie informacji dotyczących wartości wynikających ze stosowanej miary,
określanie aktualnego poziomu wykonania pomiarów w odniesieniu do każdej stosowanej miary,
podejmowania działań naprawczych w przypadku stwierdzenia, że poziom ten odbiega od założonego,
określenie i wyrażenie w jednostkach, wynikających z przyjętych miar, celów, jakie mają być osiągnięte w procesie doskonalenia.
W prowadzonych rozważaniach pojęcie poziom wykonania jest używane zamiennie z poziomem jakości. Zaleca się, aby przyjęte miary jakości odzwierciedlały:
prawidłowość opracowywania, co powinno być weryfikowane na podstawie harmonogramu realizacji poszczególnych etapów osiągania celów jakościowych w trakcie tego procesu,
efektywność opracowywania w zakresie zmniejszenia prawdopodobieństwa wprowadzenia lub niewykrycia wprowadzonego błędu.
Akty normatywne nie podają jednoznacznego określenia miar jakości. Istotne jest, aby umożliwiały one odpowiednie sterowanie procesem wytwórczym w kierunku osiągania oczekiwanego poziomu jakości procesu i wyrobu.
Norma [IEC/TC-56] wyszczególnia istotę oprogramowania systemów uwarunkowanych czasem rzeczywistym. Przyjęto w niej założenie, że jest ono zrealizowane z wykorzystaniem współbieżnej współpracy jego komponentów. Według IEC/TC-56 oprogramowanie współbieżne, to takie oprogramowanie, dla którego należy przeanalizować następujące czynniki:
konieczność kontrolowania współpracy współbieżnych komponentów programu,
czytelność definicji funkcjonalności oprogramowania,
definicja przepływów informacyjnych (współbieżnych i niewspółbieżnych) pomiędzy komponentami,
wyodrębnienie atomowych sekwencji programowych agregujących system współbieżny i określenie uwarunkowań czasowych dla aktywności tych sekwencji,
identyfikacja współbieżności we współpracy wymienionych wyżej sekwencji atomowych (należy wskazać okoliczności powodujące takie współbieżności i metody synchronizacji i komunikacji w tych współbieżnościach),
definicja struktur danych, w oparciu o które jest realizowane przetwarzanie i sterowanie.
Problematykę zaleceń odnośnie stosowania metod badania jakości oprogramowania poruszają normy IEC 1508 [Sach97] i [IEC/TC 56]. Norma IEC 1508 zawiera zestaw zaleceń dotyczących metod opracowywania oprogramowania systemów sterujących instalacjami potencjalnie niebezpiecznymi. Zawartość normy definiuje między innymi podstawową terminologię problemu, ustala ilościowe miary bezpieczeństwa systemowego, określa ogólny schemat postępowania podczas projektowania oprogramowania systemów bezpiecznych. Norma IEC/TC 56 jest normą pokrewną dotyczącą niezawodności systemów potencjalnie niebezpiecznych (strategicznych, krytycznych). Definiuje ona podstawowe pojęcia związane z niezawodnością oprogramowania systemów krytycznych, zawiera systematykę metod kontroli niezawodności oprogramowania w odniesieniu do poszczególnych etapów cyklu życia oprogramowania. Norma IEC 1508 wprowadza do opisu bezpieczeństwa systemowego pojęcie tzw. hazardu i ryzyka. Hazard definiowany jest jako zajście sytuacji mogącej spowodować śmierć lub obrażenia ludzi. Sytuacje takie mogą występować w wyniku błędnego sterowania. Ryzyko jest miarą stopnia zagrożenia stwarzanego przez sterowany system. Wyraża ono zarówno stopień szkodliwości hazardu, jak i prawdopodobieństwo jego wystąpienia. Norma wprowadza ponadto pojęcie poziomu integralności zabezpieczeń - SIL (and. safety integrity level). Jest ono wyrażane typową dla nieuszkadzalności miarą prawdopodobieństwa wystąpienia uszkodzenia systemu sterującego.
Inne miary bezpieczeństwa podaje norma IEC/TC 56. Wprowadza się w niej miarę SFRER bazującą na prawdopodobieństwie wystąpienia błędu w odniesieniu do kilolinii kodu programu (KLOC). Druga grupa zalecanych miar odnosi się do funkcjonowania
Tabela 1.1. Klasyfikacja poziomów bezpieczeństwa w IEC 1508
Klasyfikacja SIL |
Praca start-stopowa |
Praca ciągła |
|
p-stwo błędu |
p-stwo błędu |
4 |
<=10-5 |
<=10-5 |
3 |
[10-5,10-3) |
[10-5,10-3) |
2 |
[10-3,10-1) |
[10-3,10-1) |
1 |
>=10-1 |
>=10-1 |
oprogramowania. Mowa tutaj o prawdopodobieństwie prawidłowych przebiegów oprogramowania bez błędów krytycznych, czasów pracy bezawaryjnej albo czasów upadku systemu (dla systemów odnawialnych lub naprawialnych). Tabela 1.2 ilustruje klasyfikację poziomów bezpieczeństwa systemowego SL (safety level) w zależności od prawdopodobieństwa wystąpienia błędu funkcjonowania oprogramowania.
Tabela 1.2. Klasyfikacja poziomów bezpieczeństwa w IEC/TC 56
Klasyfikacja SL |
Nazwa kwalifikacji |
Wartość SFRER |
3 |
Poziom bardzo wysoki |
<10-9 |
2 |
Poziom wysoki |
[10-9,10-6) |
1 |
Poziom średni |
[10-6,10-3) |
0 |
Poza kwalifikacją |
>=10-3 |
Dla pozyskiwania wartości miar jakości normy zalecają stosowanie metod przeglądów i analizy wyników kolejnych faz cyklu wytwórczego. Wśród metod w normie IEC 1508 dla etapu specyfikacji wymagań, analizy, projektu i implementacji zaleca się stosowanie metod semi-formalnych, takich jak diagramy funkcji, diagramy przepływu danych, diagramy przepływu sterowania, automaty skończone czy sieci Petriego. Wśród metod formalnych wyszczególnia się tutaj rachunek CCS, języki formalne CSP, VDM, Z, a także logiki temporalne. Mocno podkreślono również celowość wspomagania wytwarzania oprogramowania systemami CASE. W zakresie weryfikacji i analizy bezpieczeństwa systemowego norma zaleca stosowanie między innymi metod analizy hazardu, formalnych dowodów poprawności dla kolejnych etapów cyklu wytwórczego, metod analizy statycznej, analizy dynamicznej i metryk złożoności oprogramowania. Ogólny zamysł metod analizy statycznej obejmuje kontrolę jakości struktury projektu i struktury kodu programu. Może być ona stosowana zarówno podczas badania oprogramowania, które jeszcze nie uzyskało gotowej postaci, jak i takiego, które można już wdrażać. Wśród metod kontroli statycznej można wskazać różnego rodzaju nieformalne przeglądy wewnętrzne, inspekcję Fagana [Fag76] czy metody estymacji oprogramowania. Metryki oprogramowania umożliwiają ocenę jakości kolejnych etapów cyklu życia oprogramowania. Zasadniczą ich cechą jest to, że nie zastępują one ekspertów, a jedynie istotnie ich wspomagają w wypracowaniu własnej oceny poziomu jakości badanego oprogramowania. Norma IEC zaleca również stosowanie formalnych dowodów poprawności dla kolejnych postaci oprogramowania, tj. od wyników analizy do wyników implementacji. Jedną z nich jest VDM [Jon86, Bliz97b]. Metody analizy dynamicznej bazują na modelu oprogramowania lub jego prototypie. Ich ideą jest przeprowadzenie badań eksperymentalnych posiadanego obiektu badawczego, którym jest właśnie jego model lub prototyp. Taki model określa się jako model wykonalny oprogramowania. Wśród zalecanych modeli można wyróżnić modele symulacyjne i symboliczne. Zgodnie z zaleceniami normy ważne jest, aby podczas badań modeli lub prototypów przykryć całość zidentyfikowanej przestrzeni wariantów testowych z zastosowaniem metody zasiewania błędów (error sending). Norma IEC przykłada dużą wagę do metod analizy hazardu. Podkreśla się w niej, że powinna być ona wykonana na początku cyklu życia oprogramowania w fazie specyfikacji wymagań, analizy i projektu. W tym przypadku faza projektu jest uważana za mocno zaawansowaną realizacyjnie, co może oznaczać, że rozpoczęcie analizy hazardu dopiero na etapie projektu może być zbyt późne. Jest to związane przede wszystkim z istotnie wzrastającymi kosztami usunięcia błędów wykrytych na tym etapie, jest to zjawisko piramidy propagacji błędów (patrz rysunek 1.2). Jako metody badania zjawiska hazardu norma IEC 1508 zaleca między innymi analizę drzewa zdarzeń ETA (ang. event tree analysis) [Lim87], analizę drzewa niezdatności FTA (ang. fault tree analysis) z normy [PKN-IEC 1025], analizę rodzajów i skutków uszkodzeń FMECA (ang. failure mode, effect and criticality analysis) z normy [PKN-IEC 812], metody symulacji Monte-Carlo [Fish81] (zalecenia normy IEC/TC 56 są w zasadzie zbieżne z IEC 1508). Jakkolwiek zakres metod kontroli jakości jest wspólny, to ich przyporządkowanie względem kolejnych etapów cyklu życia oprogramowania jest nieco odmienne. W normie IEC/TC 56 dokonano szczegółowego przydziału metod z zestawu 38. metod zacytowanych według normy IEC 65A. Norma IEC/TC 56 definiuje pojęcie weryfikacji oprogramowania jako proces wykonywany równolegle do poszczególnych etapów procesu wytwórczego oprogramowania. Ma to na celu badanie zgodności kolejnych efektów prac wytwórczych z założeniami na oprogramowanie. Istotna jest zgodność zarówno z wymaganiami funkcjonalnymi jak i niefunkcjonalnymi. Istotą weryfikacji jest to, że jest ona realizowana wtedy, gdy oprogramowanie jeszcze nie zostało zaimplementowane i uruchomione. Wynik weryfikacji oprogramowania jest warunkiem koniecznym dla dokonania jego walidacji, która jest rozumiana jako proces klasyfikacji oprogramowania względem określonej skali poziomu bezpieczeństwa oprogramowania. W tym celu zaleca się między innymi stosowanie metod symulacyjnych.
Zacytowane akty normatywne zalecają przeprowadzanie kontroli jakości oprogramowania. Trwają obecnie prace nad specjalizacją norm w kierunku poszczególnych klas oprogramowania, czego dowodem są zacytowane normy dla oprogramowania współbieżnego uwarunkowanego czasowo. Specjalizacja norm dotyczy również konkretnych faz cyklu wytwórczego oprogramowania, zagadnień programu niezawodności zdefiniowanego między innymi w normach IEC/TC 56, IEC 60300-3-6, programu obsługiwalności będącego jednym z elementów programu niezawodności, o którym traktują między innymi normy [PKN-IEC 706-1, PKN-IEC 706-2]. Norma [PKN-IEC 1160] porusza zagadnienia związane z formalnym przeglądem projektu.
Zaprezentowany przegląd normatywów pokazuje ogrom prac, jaki można aktualnie zaobserwować w uporządkowaniu dziedziny badania i kontroli jakości oprogramowania. Prace te są wciąż kontynuowane a wiele zagadnień wymaga ciągłego rozwoju i prac komitetów normalizacyjnych (ciekawe w tej materii są między innymi studia pozycji [Boe89, Gór93, Blo94, Maz95, Kul96a, Kul96b, Kul 96c, Kan96, Kul97a, Gór99]).
Wobec powyższego można stwierdzić, że podjęte w rozprawie badania są potrzebne i celowe. Dziedzina badania miar jakości oprogramowania jest ciągle otwarta i potrzebna. Należy podejmować badania, które mogą być pomocne w opracowaniu norm zawierających zestawy miar jakości dla konkretnych klas oprogramowania. Rozważania przedstawione w pracy dotyczą szczególnego rodzaju produktu programowego, a mianowicie oprogramowania współbieżnego systemów informatycznych. Współbieżność oprogramowania jest właściwością wymuszającą przyjęcie określonego sposobu podejścia do klasyfikacji agregatów jego jakości, co zostało pokazane w podrozdziale 1.2, a także konieczność odrębnego spojrzenia na jego miary jakości i metody pozyskiwania wartości tych miar.
Zagadnienia związane z planem zapewniania jakości zostały omówione w normie IEEE-730.
W tekście rozprawy zamiennie używane są pojęcia: jakość i jakość oprogramowania.
W wielu metodach projektowania oprogramowania i w wielu narzędziach typu CASE, funkcje oprogramowania są implementowane w postaci modułów. Ciekawe studia możliwości zaplanowania implementacji funkcji w moduły przedstawia pozycja [Brk96]. Przedstawione tam propozycje zostały zaimplementowane w narzędziu CASE Oracle/Designer 2000.
Wysyłanie komunikatów bez potwierdzania ich odbioru przez adresatów jest realizowane tylko dla komunikatów asynchronicznych. W przypadku komunikatów synchronicznych mechanizm synchronizacji komponentów wymusza potrzebę potwierdzania przez adresata otrzymania komunikatu. Jest to zgodne z założeniami tzw. spotkań synchronicznych opisanych np. w [Bari89].
Na rysunku 1.3 nazwy niektórych właściwości zostały oznaczone gwiazdką. Są to nazwy tych cech, które są charakterystyczne w głównej mierze dla oprogramowania współbieżnego. Dyskusyjne może się wydawać zaklasyfikowanie do tej grupy bezpieczeństwa statycznego. Jest to wynik nowej interpretacji właściwości częściowej poprawności algorytmów sekwencyjnych, przeniesionej na grunt oprogramowania współbieżnego. Dokładniej na ten temat w dalszej części podrozdziału 1.2.
W tekście rozprawy zamiennie używa się pojęć bezpieczeństwo i bezpieczeństwo statyczne.
W dalszym toku rozważań przyjęto tutaj metodę VDM+ będącą przedstawicielem dość licznej grupy metod specyfikacji formalnej oprogramowania współbieżnego.
Jest to problematyka bezpieczeństwa systemowego oprogramowania systemów strategicznych (odpowiedzialnych, krytycznych).
Rozumienie pojęcia komponent oprogramowania przyjęte dla potrzeb opracowanej metody zostało sprecyzowane w 2-gim rozdziale rozprawy. W tradycyjnym rozumieniu tego pojęcia komponentem może być np. podprogram, moduł, proces sekwencyjny, proces współbieżny, zadanie (ang. task) - jest to uzależnione od sposobu widzenia struktury oprogramowania. W przypadku oprogramowania współbieżnego przyjmuje się najczęściej, że jego podstawowym komponentem jest proces współbieżny.
Aktywność komponentu jest nazywana procesem. Dla programów sekwencyjnych są to procesy sekwencyjne, natomiast dla oprogramowania współbieżnego - procesy współbieżne.
Potocznie o takim komponencie mówi się, że uległ on „zawieszeniu”.
Jest to zależne od scenariusza zachowania komponentów.
Oprogramowanie systemów informatycznych stanowi jeden z przypadków obiektów technicznych.
Struktury zadaniowa i funkcjonalna mogą mieć względem siebie następujące odniesienia: jedna funkcja może oznaczać realizację jednego bądź wielu zadań, jedno zadanie może obejmować więcej niż jedną funkcję. Związek tych pojęć można zilustrować diagramem: , którego notacja została zapożyczona z CASE*Method[Brk96a]. Encja oznaczona jako Z oznacza zadanie, natomiast encja F - funcję.
Pojęcie to zostało zdefiniowane w treści podrozdziału 1.3.
O audytach jakości traktują normy [PKN ISO 10011-1, PKN ISO 10011-3].
Czynnik ten jest niezależny od klasy oprogramowania.
Zależności czasowe są szczególnie istotne dla oprogramowania uwarunkowanego czasem rzeczywistym.
Obszerny przegląd metryk oprogramowania został zawarty w [Bliz98]
1
35
Jakość
oprogramo-wania
Poprawność
Niezawodność
Złożoność
Adekwatność
Pielęgnacyjność
Bezpieczeństwo*
Żywotność
Czytelność
Reaktywność
Zakleszczenie*
Zagłodzenie*
Blokada*
Dostępność
Jednoznaczność
Zwięzłość
Kompletność
Racjonalność funkcjonalna
Racjonalność komunikacyjna
Zwartość komunikacyjna
Zwartość funkcjonalna
Nieuszkadzalność
Obsługiwalność
Utrzymywalność
Odporność
Odnawialność
Niezmienność zachowań
Testowalność
Przechowywalność
Funkcjonalna
Komunikacyjna
Modułowa
Zadaniowa
Obliczeniowa
Struktury wewnętrznej tekstu programu
Procesowa
Dla zadań
Więź międzymodułowa
Pamięciowa
Czasowa
Łatwość wdrożenia
Progresywność
Modyfikowalność
Przenośność
Naprawialność
Rys. 1.3. Schemat agregacji jakości oprogramowania.
Cykl życia wyrobu
Koncepcja,
Definicja
Projekt,
Technologia
Produkcja,
Instalacja
Działanie,
Konserwacja
Zniszczenie
Analiza
wymagań
Specyfikacja
systemu
Projekt wstępny
Projekt szczegółowy
Kodowanie,
Testy
komponentów
Testy
integracyjne
Testy
systemu
Testy
akceptacyjne
Wdrożenie
oprogramow.
Utrzymywanie,
ulepszanie
oprogramowania
Dezaktua-lizacja
oprogra-mowania
Cykl życia
oprogramowania
upływ czasu
Rys.1.1. Cykl życia oprogramowania (według [IEC 60300])
Wymagania
Analiza
Projekt
Implementacja
Rys.1.2. Piramida propagacji błędów
Pielęgnacja
Z
F