Idealny projekt
Jakiś czas temu spotkałem się ze stwierdzeniem, że każdy system informatyczny który nie jest odpowiednio zaprojektowany przed rozpoczęciem prac programistycznych jest z góry skazany na "zatarcie się" w ciągu dwóch lat (znaczny wzrost kosztu wprowadzania zmian, "wypalanie się" zespołu). Programista, który te słowa wypowiedział (a z którym mam przyjemność pracować nad jednym z systemów), hołduje zasadzie, że najbezpieczniej jest zaprojektować wszystkie możliwe rozszerzenia systemu na początku, dzięki czemu unika się kosztownego procesu refaktoryzacji. Jeśli zaś znajdziemy się w sytuacji kiedy prace już ruszyły to nie ma już nadziei na płynny rozwój systemu.
Takie podejście do tworzenia systemów trąci aż zanadto metodą Waterfall (model kaskadowy), gdzie kolejne etapy powstawania systemu są uszeregowane w czasie (wymagania, projekt, implementacja, testy). Istnieje w nim ukryte założenie, że jest możliwe nieomylne wyznaczenie pełnych celów i zadań systemu na początku oraz zaprojektowanie odpowiedniej struktury która te cele i zadania spełni. Właśnie: założenie nieomylności jest chyba najtrudniejsze do spełnienia.
Dlaczego niektórzy programiści wierzą w idealny projekt? Zapewne wiele razy mieli do czynienia z systemami w których musieli rozszerzać funkcjonalność a napotykali na konieczność ingerencji w wewnętrzną strukturę aplikacji i związaną z tym konieczność pełnego przetestowania systemu (wprowadzone zmiany mogły zaburzyć działanie istniejącej funkcjonalności). "Gdybyśmy zaprojektowali wszystko wcześniej" - myślą - "nie było by takich kłopotów z nową funkcjonalnością". Czy aby na pewno?
Alternatywa: przyrost
Jako alternatywę dla Waterfall proponowane są metody przyrostowe (razem z modnych w ostatnich latach ruchem Agile). Zakłada się w nich, że dokładniejszą wiedzę na temat pożądanego działania systemu można uzyskać w serii kroków przybliżających do celu. Klient po każdej iteracji dostaje do dyspozycji system który niesie już jakąś wartość użytkową. Dzięki temu wcześnie można zbadać zdolność zespołu do realizacji projektu (tzw. velocity) i dokonywać korekt kierunku i priorytetów bazując na informacji uzyskanej z działających wersji systemu.
Jednakże taki sposób działania (pominięcie etapu projektowania na korzyść przyrostowego tworzenia kodu systemu) ma bardzo złą sławę. Ponieważ nie ma dobrej architektury kod jest trudny w utrzymaniu, co wiąże się z dużą rotacją programistów i z naturalnym w takim przypadku zniechęceniu. Jeśli jesteś, Czytelniku, osobą która kiedykolwiek miała do czynienia z systemami spadkowymi pozostawionymi po poprzedniuku zapewne wiesz o czym mówię.
Czy więc będziemy zawsze skazani na rolę wróżki przepowiadającej przyszłość która jest podstawą modelu kaskadowego?
Bezpieczny przyrost
Podstawowym ryzykiem związanym z przyrostowym rozwojem systemu jest duże prawdopodobieństwo zagmatwania struktury kodu w trakcie dodania nowej funkcjonalności. Zagmatwana struktura jest bardzo podatna na błędy i błędy takie są trudne do wyśledzenia i usunięcia (nie mówiąc już o pro aktywnym zapobieganiu defektom). Aby na bieżąco poprawiać strukturę systemu stosuje się refaktoryzację. Polega ona na takiej modyfikacji struktury by istniejąca funkcjonalność nie została naruszona. Ale sam proces refaktoryzacji nie jest pozbawiony ryzyka. Zmiany w strukturze mogą spowodować wstrzyknięcie nowych błedów które będą niwelować pozytywny efekt poprawienia struktury.
Aby refaktoryzacja była bezpieczna z punktu widzenia jakości systemu należy zastosować środki zapobiegawcze w postaci automatycznych testów. Dlaczego od razu zaznaczam, że powinny być one zautomatyzowane? Przeprowadzenie kompletu testów przez zespół testowy oznacza czas i koszty. Jeśli udaje się proste błędy wyłapać w sposób automatyczny (np. regresję na podstawie zapisanych i uruchamianych automatycznie scenariuszy) to jest to znaczny zysk.
Przyrostowy rozwój oprogramowania wymaga zastosowania dodatkowych technik mających na celu minimalizowanie ryzyka związanego z poplątaną strukturą systemu i z możliwymi błędami. Podstawowymi narzędziami są: refaktoryzacja i testy jednostkowe.