powrót do spisu treści

Rozdział 1

Wstęp

Programy komputerowe podlegają zmianom podczas swego istnienia. Zwykle są modyfikowane z powodu zmieniających się wymagań bądź pojawiania się nowych. Często jednak zmiana dotyczy jedynie wewnętrznej struktury programu, bez wpływu na zewnętrzne skutki jego działania. Przykładowo, programista zmienia nazwę klasy, by lepiej opisać jej przeznaczenie, zastępuje powtarzający się kod wywołaniem metody lub zmienia interfejs klasy, by uczynić ją bardziej elastyczną i użyteczną w innych częściach systemu. Zdarza się, że programiści modyfikują jakąś część programu po to, by uprościć jej zagmatwaną logikę bądź nawet jedynie ze względu na poczucie elegancji [19]. Taka modyfikacja kodu źródłowego programu, która nie zmienia jego działania jest znana pod nazwą refaktoryzacji (ang. refactoring). Termin refaktoryzacja oznacza zarówno pojedynczą transformację, jak i wieloetapowy proces przekształcania programu. Przedmiotem niniejszej pracy jest refaktoryzacja w kontekście popularnego obiektowego języka programowania - języka Java.

Refaktoryzacje można łączyć ze sobą. Wykonując wiele następujących po sobie, niewielkich przekształceń, z których każde ma tę właściwość, że nie zmienia działania programu, można zmodyfikować budowę programu w znaczący sposób - nie zmieniając jego zachowania [5, 17, 16, 19, 21].

Jest to jednak często proces żmudny i podatny na błędy. Zdarza się, że program pozostaje w swojej obecnej, niepożądanej postaci jedynie dlatego, że wprowadzenie koniecznych zmian (i testowanie ich poprawności) jest zbyt czasochłonne. Przykładowo, zła nazwy klasy prawdopodobnie nie zostanie ulepszona, jeżeli w programie istnieje bardzo wiele odwołań do tej klasy. Dlatego istotne jest, by tam, gdzie to możliwe, refaktoryzację automatyzować.

Do tego, by narzędzia do refaktoryzacji mogły być powszechnie używane, niezbędna jest ich niezawodność. Refaktoryzacja to proces głęboko ingerujący w strukturę programu - zmiana nazwy metody czy klasy często oznacza konieczność aktualizacji kodu w setkach miejsc. Z koncepcyjnego punktu widzenia, refaktoryzacja polega na wykonywaniu wielu niewielkich kroków. Każda kolejna zmiana wprowadzana do diagramów UML jest, być może, prawie niezauważalna. Faktyczna modyfikacja kodu, wymagana do wprowadzenia zmiany w życie, może być jednak bardzo znacząca. Narzędzie, któremu mamy powierzyć wprowadzenie tego rodzaju zmian w kodzie źródłowym programu musi być niezawodne.

Przed wykonaniem refaktoryzacji niezbędna jest analiza warunków wstępnych (ang. preconditions). Tylko wtedy, gdy są one spełnione, można bezpiecznie przeprowadzić określoną modyfikację kodu źródłowego. Możliwie pełna analiza warunków wstępnych jest konieczna do zagwarantowania poprawności refaktoryzacji i, tym samym, do osiągnięcia niezawodności narzędzi. Java jest językiem programowania o złożonej składni i semantyce. Wielu konstrukcji występujących w tym języku (przykładowo wielokrotne dziedziczenie, czy typy zagnieżdżone), nie rozważano, do tej pory, w kontekście refaktoryzacji. Jednym z celów tej pracy jest ukazanie znacznego wpływu niektórych cech języka Java na ten proces. Pokazujemy, że prawidłowe przeprowadzenie refaktoryzacji (w szczególności analiza warunków wstępnych) jest niemożliwe bez wzięcia tego pod uwagę. Następnie omawiamy problemy związane z występowaniem omawianych cech języka w refaktoryzowanych programach i możliwe sposoby ich rozwiązania.

Brak wyczerpujących opracowań dotyczących refaktoryzacji w języku Java może być, według nas, jedną z ważnych przeszkód w tworzeniu niezawodnych narzędzi. Kolejnym z celów tej pracy jest przedstawienie opisu kilku refaktoryzacji wraz ze szczegółową, obejmującą całość języka, analizą warunków wstępnych.

Kolejnym celem niniejszej pracy jest prezentacja projektu i implementacji zbudowanego przez nas narzędzia do automatycznego wspierania refaktoryzacji programów w języku Java. Jest ono integralną częścią IBM WebSphere Studio Workbench - środowiska programistycznego do budowy programów w języku Java. Narzędzie to jest używane na codzień przez wielu programistów. Jest dostępne (wraz z kodem źródłowym) pod adresem [24].

Zagadnienie włączenia wsparcia refaktoryzacji do środowiska programistycznego opisaliśmy w pracy [1] (wspólnie z dr Erichem Gammą i dr Dirkiem Baeumerem).

Dalsza część pracy jest zorganizowana w następujący sposób: