Błędy, testy i okolice

Jakość oprogramowania

Zapewnienie odpowiedniej jakości oprogramowania (QA) wcale nie sprowadza się do stworzenia odpowiednich procedur związanych z testowaniem. QA to zbiór procesów: właściwe standardy kodowania, sposób dokumentacji kodu, określenie odpowiedzialności (kto i w jakim momencie przygotowuje procedury testowe). QA powinno określać, w jaki sposób przeciwdziałać błędom. Można powiedzieć, że poprawny przebieg testów jest świadectwem, iż QA funkcjonuje prawidłowo.

Przy mierzeniu i badaniu jakości oprogramowania bardzo ważne są narzędzia, które ułatwiają menedżerowi analizę postępów projektu. Równocześnie mogą one wspierać pracę testerów. Różnego typu systemy zgłaszania błędów, nadzoru nad procesem usuwania błędów czy nadzorem nad wykonywaniem kolejnych podzadań projektu pozwalają sprawdzać, czy zakładany poziom "QA" jest zachowany. Ze względu na model rozwoju oprogramowania dużo systemów open source przyczyniło się do powstania interesujących narzędzi do "śledzenia błędów i poprawek".

GNATS to zestaw narzędzi przeznaczonych do gromadzenia w jednym miejscu informacji o błędach. Problem może być zgłaszany na wiele sposobów: wypełniony formularz na WWW, specjalny e-mail itp. Dużą zaletą GNATS jest elastyczność. Praktycznie nie ma tam jednego interfejsu użytkownika (zarówno testera, programisty, jak i użytkownika zgłaszającego błędy). Może to być linia poleceń, e-mail, daemon czy plik tekstowy, który pojawi się w określonym miejscu w sieci.

Pewną pomocą w pomiarze jakości oprogramowania mogą być także narzędzia do analizy kodu źródłowego. Błędy popełniane przez programistów są dosyć podobne. Narzędzia, takie jak ASSENT, TrueJ czy SSW Code Auditor, przeprowadzają audyt kodu. Mierzone są wskaźniki metryczne kodu (np. średnia długość zmiennej itp.). Można także "uczulić" systemy na często popełniane błędy.

Epilog

Źródeł licznych problemów związanych z bezpieczeństwem kodu należy przynajmniej po części szukać w edukacji programistów. Zarówno program studiów, jak i kursy kładą nacisk na naukę różnych sposobów rozwiązania problemów. Są prezentowane różne sposoby konstruowania algorytmów, optymalnego projektowania aplikacji czy wykorzystania konkretnych narzędzi. Bardzo rzadko są przedstawiane sposoby bezpiecznego pisania kodu, np. w kursach o algorytmach za dobre rozwiązanie uważa się takie, które przy danych wejściowych spełniających założone kryteria daje prawidłowy wynik. Niewielu asystentów czy wykładowców, sprawdzając prace studenta, analizuje, co się stanie, jeżeli do funkcji, która wymaga bufora 100 bajtów, przekażemy bufor 10-znakowy. Jeżeli na uczelniach mówi się o bezpieczeństwie, to tylko w kontekście administracji sieci, a nie tworzenia oprogramowania.

Języki na językach

Pod koniec lat 70. Departament Obrony USA wybrał język ADA jako ten, który gwarantuje tworzenie niezawodnego oprogramowania. Na bazie tego języka w 1983 r. powstał standard, który zyskał olbrzymią popularność.

Za pomocą języka ADA powstawały aplikacje do obsługi kontroli lotów, sterowania itp. Przez długi czas brakowało jednak rozsądnej implementacji kompilatora czy interpretera ADA. Obecnie przemysł oprogramowania praktycznie zapomniał o tym języku. Dostępna jest w zasadzie tylko implementacja ADA 95 opracowana w ramach GNU - GNAT.

Warto dodać, że w momencie wyboru języka przez Departament Obrony firma AT&T nawet nie próbowała zaproponować swojego języka C. Jak twierdzą złośliwi, szukanie błędów w programach C zajmuje wielokrotnie więcej czasu niż napisanie kodu. Jeżeli teraz, po doświadczeniach co najmniej 10-15 lat popularności C/C++, ktoś stanąłby przed zadaniem ustalenia na nowo standardu tych języków, z pewnością włączyłby do niego uniwersalną klasę do zarządzania łańcuchami i bezpieczny mechanizm manipulowania pamięcią. Dzięki obu rozwiązaniom zostałyby wyeliminowane podstawowe przyczyny tysięcy błędów wynikających bezpośrednio lub pośrednio z przepełnienia bufora. Kosztem nieznacznego zmniejszenia wydajność języka można by ustrzec się kłopotów związanych z niewłaściwym zarządzaniem pamięcią i koniecznością dokładnego pilnowania przekazywanych parametrów, wielkości buforów itp.

Obiektowe podobieństwa

Przyglądając się obecnym nurtom "przemysłowym" w programowaniu, można dojść do wniosku, że w zasadzie triumf święcą imperatywne języki strukturalno-obiektowe. Java, C++, Object Pascal (Delphi Borlanda) czy C#, mimo że generalnie są językami obiektowymi, w szerokim zakresie umożliwiają również wykorzystywanie stylu programowania strukturalnego, znanego np. z C. Wszystko po to, by programiści nie musieli zmieniać przyzwyczajeń.

Co więcej, języki te stają się podobne. Oczywiście różnią się składnią, np. sprawiają, że określone konstrukcje językowe mogą być zapisane w krótszy sposób w C# niż w Javie, ale generalnie programista nie ma kłopotów z migracją między nimi.

Java i C# od razu są wyposażane w mechanizmy automatycznego zarządzania pamięcią. Obecnie trudno sobie wyobrazić, by zaprojektowano język, w którym byłyby dostępne niczym nie skrępowane wskaźniki, tak jak w C czy C++, czy brakowałoby mechanizmów zarządzania pamięcią.

Język akademicki

Alternatywą dla nurtów komercyjnych są projekty rozwijane w środowiskach akademickich. Trwają tam prace nad rozmaitymi językami, które byłyby z jednej strony proste w użyciu, z drugiej, pozwalały pisać niezawodne oprogramowanie. Ciekawym przykładem jest seria języków ML (SML, Objective Caml). W nich zapewniono automatyczne zarządzanie pamięcią, wiele mechanizmów eliminuje często spotykane błędy oprogramowania, a równocześnie składnia pozwala na bardzo elastyczne tworzenie tzw. ulotnych struktur danych (typów algebraicznych). SML ma bardzo rozbudowany mechanizm wzorców i parametryzowane moduły. Wszystko to sprawia, że w programie udaje się dość dobrze odwzorować "obiekty" matematyczne, co z kolei przekłada się na łatwiejszą implementację konkretnego algorytmu.

Innym ciekawym przykładem języka jest Scheme - język, którego jednym z celów powstania było testowanie algorytmów.

Scheme pozwala na krótkie i zwięzłe zapisanie algorytmu i przetestowanie go.

Duża liczba języków ma rozbudowane mechanizmy pozwalające na tzw. programowanie współbieżne i rozproszone. W językach "popularnych" mechanizmy obsługi wątków są wykonywane za pośrednictwem specjalnych bibliotek (w C# są wspomagane pewnymi elementami składni).

Czwarta stagnacja

Stagnacja panuje w rozwoju tzw. języków 4. generacji - 4GL, choć jeszcze kilka lat temu wydawało się, że w tej dziedzinie nadal będą powstawać bardzo ciekawe rozwiązania. Upraszczają one "rysowanie" i generowanie interfejsu użytkownika oraz pewnych szczegółowych elementów systemu. Prawdziwymi narzędziami 4GL są takie produkty, jak Clarion (obecnie wersja 5. jest przygotowywana następna) czy Magic. Informix opracował własny język 4GL, wyspecjalizowany do pisania aplikacji bazodanowych, ale po przejęciu firmy przez IBM przyszłość języka nie jest jasna.

Jeśli nawet powstaną nowe języki 4GL, to musi upłynąć trochę czasu, zanim wejdą w skład programów dydaktycznych. Na razie po kursie uczelnianym programista powinien znać podstawy obiektowości, kilka języków trzeciej generacji (głównie imperatywnych), elementy RAD, a w nielicznych przypadkach zasady projektowania systemów.

Skrypty i prototypy

Coraz większą popularność zyskują różnego rodzaju języki skryptowe. Skoro i tak spora część aplikacji powstaje przy użyciu gotowych komponentów, to może nie warto tworzyć "statycznej" aplikacji, lecz do łączenia odrębnych składników w jeden produkt wykorzystać język skryptowy? Stawia to wprawdzie nowe wyzwania przed testerem, ale jednocześnie upraszcza wdrożenie aplikacji. Języki, takie jak Perl, Python czy VBScript, są stosowane jako mechanizmy do wywoływania żądanej funkcjonalności z komponentów. Mogą jednocześnie służyć jako język makrodefinicji wewnątrz aplikacji.Ciekawym pomysłem są tzw. języki oparte na prototypach.

To języki obiektowe, w których nowa instancja klasy jest klonowana z istniejącego, "żyjącego" prototypu. Nie ma tam w zasadzie pojęcia "konstruktora". Jest to bardzo wygodne rozwiązanie do projektowania interfejsu GUI. W pewnym sensie językiem opartym na prototypach jest także JavaScript.

Tomasz Kopacz


TOP 200