Code slicing: Droga do lepszego rozumienia kodu źródłowego

Transkrypt

Code slicing: Droga do lepszego rozumienia kodu źródłowego
Code slicing:
Droga do lepszego rozumienia kodu źródłowego
(część druga)
Bartosz Bogacki
Poznan University of Technology, Institute of Computing Science
ul. Piotrowo 2, 60-965 Poznan, Poland
[email protected]
Streszczenie. Kod źródłowy skomplikowanych programów komputerowych
może być lepiej zrozumiany przez programistów, gdy zostanie podzielony na
mniejsze fragmenty. Poniższy tekst przedstawia podstawowe pojęcia z zakresu
statycznej analizy kodu koncentrując się na slicingu kodu. Slicing kodu to metoda służąca do podziału kodu z zachowaniem jego poprawności w ramach
rozważanej funkcjonalności. Przedstawiony jest zarys historyczny, znane metody, narzędzia oraz praktyczne zastosowania slicingu kodu. W części
pierwszej artykułu przedstawiono podstawy oraz charakterystykę tej popularnej
techniki. Część druga prezentuje praktyczne aspekty, narzędzia oraz
przykładowe case-study z wykorzystaniem narzędzi Indus/Kaveri.
1 Wprowadzenie
Slicing kodu jest stosowany w praktyce w wielu obszarach inżynierii oprogramowania. Najważniejsze obszary przedstawiane w literaturze to zrozumienie kodu źródłowego (ang. code comprehension), debugging, refactoring, inżynieria wsteczna
(ang. reverse engineering) oraz metryki związane ze spójnością funkcjonalną kodu.
Kosztowna faza utrzymania systemu (ang. maintanance) rozpoczyna się przeważnie
od pracy nad zrozumieniem kodu źródłowego. Naturalne jest, iż obniżenie kosztów
związanych ze zrozumieniem kodu spowoduje znaczne obniżenie kosztów utrzymania systemu. Wykazano [1], że koszt ponoszony na zrozumienie kodu źródłowego to
aż 50-90% kosztu utrzymania. W celu obniżenia tych kosztów należy wspomagać
analizę kodu dodatkowymi narzędziami umożliwiającymi szybsze zrozumienie roli
oraz zależności poszczególnych fragmentów programu. W pierwszej części artykułu
opisane zostały podstawy techniki upraszczającej strukturę kodu źródłowego programu zwanej slicingiem kodu. Pokazano krótko zarys metody zgodnie z pracą [3] oraz
istniejące odmiany slicingu. W drugiej części przedstawione zostały przykładowe
praktyczne zastosowania tej techniki. Zaprezentowane zostały narzędzia pozwalające
programistom szybciej wydobywać wiedzę o programie poprzez wizualizację wycinków kodu zgodnie z zadanym kryterium slicingu.
2 Narzędzia
Wiele narzędzi służących do analizy kodu źródłowego wykorzystuje mechanizm
slicingu kodu. Najpopularniejsze dwa programy to komercyjny CodeSurfer firmy
Grammatech ([5]) oraz akademicki Indus/Kaveri rozwijany przez Kansas State
University ([6], [7]). CodeSurfer służy do analizy programów napisanych w języku
C. Posiada bogaty zestaw funkcji umożliwiających zarówno wizualizację zależności
w kodzie w postaci grafu wywołań funkcji (ang. call graph) jak i dopuszczalnych
wartości zmiennych wynikających ze statycznej analizy kodu. Narzędzie to jednak
skrupulatnie ukrywa szczegóły slicingu, podając programiście gotową interpretację.
Inaczej jest w przypadku programu Kaveri, będącego zestawem plug-in’ów dla
środowiska Eclipse i wykorzystującego silnik o nazwie Indus. Program ten prezentuje
bezpośrednio wycinki kodu powstałe w wyniku zastosowania wybranej metody
slicingu oraz zadanego kryterium.
3.1 CodeSurfer (ANSI C)
Program CodeSurfer powstał w wyniku rozwijania akademickiego narzędzia o nazwie Wisconsin Program-Slicing Tool. O ile w akademickiej postaci narzędzie to
umożliwiało jedynie tworzenie wycinków (zarówno metodą slicingu „w przód” jak i
slicingu wstecz), o tyle komercyjna wersja zawiera dodatkowo pewne mechanizmy
dostarczające dodatkowej interpretacji. Rysunek 1 przedstawia kod źródłowy w języku C oraz wycinek utworzony przez Wisconsin Program-Slicing Tool metodą statycznego slicingu wstecz i kryterium slicingu dla zmiennej "i" występującej w wyrażeniu:
printf("Sum %d, i %d, Add %d\n", sum, i, Count);
Kod należący do wycinka oznaczony jest kolorem czerwonym. Wykorzystując tę
funkcjonalność, program CodeSurfer dostarcza kolejne interpretacje uzyskanych
informacji. Rysunek 2 przedstawia przykładowy graf wywołań funkcji uzyskany za
pomocą programu CodeSurfer. Graf ten wizualizuje wywołania poszczególnych
funkcji wykonywane w ciele funkcji main. Nawigacja po kodzie odbywa się z wykorzystaniem węzłów grafu wyołań funckji. Dostępne są również funkcje służące do
sprawdzenia prawdopodobnych wartości zmiennej w danym miejscu kodu na podstawie wcześniejszych odwołań do zmiennej, sprawdzenia wyrażeń warunkowych w
których wykorzystywana jest modyfikowana zmienna, itp. Dodatkową funkcjonalnością programu jest możliwość obliczenia ponad 20 popularnych metryk kodu (m.in.
złożoności cyklomatycznej czy złożoności Halsteada).
Rysunek 1. Kod źródłowy oraz wycinek utworzony za pomocą Wisconsin Program-Slicing Tool
Rysunek 2. Graf wywołań funkcji utworzony przez program CodeSurfer.
3.2 Indus/Kaveri (Java)
Program Indus/Kaveri pozwala na wizualizację wycinka kodu zgodnie z zadaną
metodą oraz kryterium slicingu. W wyborze odpowiednich parametrów pomaga bogate menu przedstawione na rysunku 3.
Rysunek 3. Wybór parametrów w programie Indus/Kaveri.
Tworząc konfigurację należy podjąć m.in. decyzję jakiego typu slicing zostanie zastosowany. Istnieją dwie podstawowe metody: slicing „do przodu” (oznaczone jako
forward slice) oraz slicing wstecz (backward slice). Można też wybrać połączenie
obu tych metod (complete slice), dające w wyniku unię wycinków utworzonych przez
obie te metody. Dodatkowo można zażądać, aby utworzony wycinek był wykonywalny (ang. executable slice). Dokładny opis opcji można znaleźć w dokumentacji
programu [8] [9].
Program Indus tworząc wycinki działa na skompilowanym programie, a następnie
dokonuje odwzorowania na pierwotny kod źródłowy napisany w języku Java. Wykorzystanie bajtkodu? jako podstawy do analizy programu ma oczywiście zarówno
zalety, jak i wady. Podstawową zaletą takiego podejścia jest prostota analizy
i uniknięcie wielu problemów wynikających z paradygmatu programowania obiektowego. Wadą jest natomiast uzyskanie wyniku, który może okazać się nieprecyzyjny
(np. w skutek przekształceń optymalizacyjnych). Ponieważ prezentacja wyników
odbywa się na poziomie kodu źródłowego, a analiza w warstwie bajtkodu, dlatego
czasem pojawia się sytuacja, w której fragmenty kodu należące do wycinka nie tworzą kompletnego zbioru wyrażeń w kodzie źródłowym. W programie Indus takie
częściowo pokryte wyrażenia są oznaczane kolorem żółtym i nazywane częściowymi
elementami wycinka (ang. partial slice element). Wyrażenia, które w całości występują w wycinku, nazywane są całkowitymi elementami wycinka (ang. complete slice
element) i oznaczane kolorem zielonym. Rysunek 4 przedstawia przykładowy wycinek dla statycznego slicingu wstecz i kryterium slicingu <8, i> utworzony przez
program Indus.
Rysunek 4. Przykładowy wycinek utworzony przez program Indus
Całkowite elementy wycinka oznaczone zostały na zielono w liniach 1, 3, 6 oraz 8.
Częściowe elementy wycinka w liniach 5 i 7 zostały oznaczone na żółto. Wyrażenia z
linii 9 nie należą do wycinka.
4 Analiza kodu źródłowego z wykorzystaniem statycznego slicingu
Po krótkim wprowadzeniu nadszedł czas na prosty przykład. Rysunek 5 przedstawia
kod źródłowy w języku Java. Klasa MaturityOracle ma tylko 1 metodę zawierającą całą logikę biznesową. Metoda ta pobiera argument z linii poleceń, będący liczbą
symbolizującą wiek i informuje o tym, czy użytkownik jest osobą dojrzałą. Jeśli liczba lat mieści się w przedziale <16; 18), to powinien pojawić się dodatkowo komunikat informujący, że już niedługo dana osoba będzie dojrzała. Jeśli natomiast liczba lat
mieści się w przedziale <0, 16>, wówczas system powinien podać za ile lat osoba
stanie się osobą dojrzałą.
Rysunek 5. Przykładowy kod w języku Java
Programista analizujący tak prostą klasę prawdopodobnie nie straci dużo czasu na
określenie wpływu poszczególnych wyrażeń na wartość zmiennej matureCounter. Niemniej jednak może ułatwić sobie zadanie wydając zapytanie do programu
Indus o wycinek powstały w wyniku statycznego slicingu wstecz dla kryterium <25, matureCounter>. Wynik takiego zapytania przedstawia rysunek 6.
Rysunek 6. Wycinek kodu dla kryterium slicingu <25, matureCounter>.
Wycinek obliczony przez program oznaczony jest kolorami zielonym i żółtym. Łatwo
zauważyć, że na wartość zmiennej matureCounter w linii 25 nie ma wpływu
warunek znajdujący się w linii 21, czyli wyrażenie: if (matureCounter < 2),
ponieważ linia 21 nie należy do wycinka. Oznacza to, iż niezależnie od wartości
uzyskanej w tym warunku zostanie wypisany komunikat informujący ile lat pozostało
użytkownikowi do osiągnięcia wieku dojrzałego. Co więcej, informacja o tym, że
wyrażenia z linii 7 należą do wycinka, sygnalizuje możliwość, iż zmienna w tym
miejscu może mieć wartość początkową uzyskaną w wyniku przypisania znajdującego się w linii 7, czyli że w przypadku, gdy użytkownik wprowadzi liczbę lat większą
od 18, system zawsze poinformuje, że do uzyskania dojrzałości pozostało 0 lat. Rysunek 7 przedstawia wycinek wykonany na kodzie źródłowym poprawionym tak, aby
spełniał zadane wcześniej wymagania.
Rysunek 7. Wycinek poprawionego kodu dla kryterium slicingu <26, matureCounter>
Po dokonaniu poprawki wyrażenie warunkowe z linii 21 należy już do wycinka.
Natomiast linia 7 zawierająca przypisanie wartości początkowej przestała należeć do
wycinka, gdyż zawsze jego wartość będzie wynikała z wartości wyliczanej w linii 19.
3 Podsumowanie
W części pierwszej artykułu przedstawiono podstawy popularnej techniki usprawniającej proces zrozumienia i analizy kodu źródłowego zwanej slicingiem kodu. Wprowadzono pojęcie kryterium slicingu oraz wycinka. Zademonstrowano cztery popularne metody slicingu: statyczny, dynamiczny, warunkowy oraz bezkształtny. Metody
te omówiono krótko na przykładzie kodu źródłowego napisanego w języku Java. W
części drugiej artykułu przedstawione zostały 2 przykładowe implementacje narzędzi
służących do przeprowadzania slicingu kodu. Krótko omówiono komercyjny program operujący na kodzie źródłowym w języku ANSI C – CodeSurfer oraz akademicki zestaw plugin’ów dla Eclipse’a o nazwie Indus/Kaveri działający na kodzie
źródłowym napisanym w języku Java. Zademonstrowane zostało działanie statycznego slicingu kodu w praktyce z użyciem narzędzia Indus/Kaveri.
Literatura
1.
2.
3.
4.
5.
6.
7.
8.
9.
De Lucia, A., Fasolino A.: Understanding Function Behaviors through Program Slicing, Proceedings of the 4th International Workshop on Program Comprehension
(WPC '96), 1996.
Erlikh, L. : Leveraging legacy system dollars for E-business. (IEEE) IT Pro,
May/June 2000, 17-23.
Weiser, M.: Program Slicing. Proceeding of the Fifth International Conference in
Software Engineering, pages 439-449, 1981.
Business Week 3051 (9) : The software trap – automate or else., 142-154.
CodeSurfer: http://www.grammatech.com/products/codesurfer/
Indus: http://indus.projects.cis.ksu.edu/
Kaveri: http://freshmeat.net/projects/kaveri/?branch_id=53420&release_id=197620
Indus, Dokumentacja: http://projects.cis.ksu.edu/docman/view.php/12/71/slicer-ug.pdf
Kaveri, Dokumentacja: http://projects.cis.ksu.edu/docman/view.php/12/90/Kaveri-ug.pdf

Podobne dokumenty