W świecie oprogramowania pięć lat może oznaczać zarówno system wciąż bardzo dobrze przygotowany do dalszego rozwoju, jak i technologiczny problem, który z każdym kolejnym miesiącem będzie kosztował coraz więcej.
Sam wiek aplikacji nie jest jednak powodem do jej wymiany.
To jedna z najważniejszych rzeczy, które warto powiedzieć na początku.
Nie istnieje uniwersalna granica, po której aplikację należy przepisać od nowa. Są systemy działające kilkanaście lat, które nadal mają sensowną architekturę, aktualne zależności, dobrą dokumentację i sprawdzony proces wdrożeń. Są też znacznie młodsze aplikacje, których rozwój został utrudniony przez błędne decyzje architektoniczne, brak testów, niekontrolowane zależności albo kolejne szybkie poprawki.
Problemem nie jest więc liczba lat.
Problemem jest zdolność systemu do dalszej zmiany.
Najważniejsze pytanie nie brzmi: "Czy aplikacja jest stara?"
Lepsze pytanie brzmi: "Ile kosztuje nas kolejna zmiana?"
Jeżeli dodanie nowej funkcji wymaga coraz większej liczby godzin, angażowania kilku zespołów, ręcznych testów i obchodzenia ograniczeń starej architektury, system zaczyna generować koszt, którego nie widać w samym kodzie.
To właśnie jeden z praktycznych objawów narastającego technical debt.
Technical debt można rozumieć jako koszt przyszłych zmian wynikający z wcześniejszych decyzji technicznych. Martin Fowler opisuje go jako dodatkowy wysiłek, który trzeba ponosić przy modyfikowaniu systemu, gdy jego wewnętrzna jakość utrudnia rozwój.
I właśnie dlatego aplikacja może nadal działać poprawnie, a jednocześnie być coraz trudniejsza do rozwijania.
10 funkcji później system wygląda zupełnie inaczej
Początek projektu często jest prosty.
Powstaje MVP.
Potem dochodzą kolejne wymagania:
- integracja z CRM,
- płatności online,
- panel administracyjny,
- aplikacja mobilna,
- nowe role użytkowników,
- raportowanie,
- automatyzacje,
- API,
- integracje z zewnętrznymi usługami,
- kolejne wersje językowe.
Każda zmiana z osobna może być uzasadniona.
Problem pojawia się wtedy, gdy architektura nie była projektowana z myślą o takim kierunku rozwoju.
Wtedy kolejne funkcje nie są już dokładane do stabilnej konstrukcji.
Są dokładane do poprzednich wyjątków, obejść i kompromisów.
Po czym poznać, że system zaczyna się starzeć?
Nie trzeba czekać na całkowitą awarię.
Sygnały ostrzegawcze pojawiają się dużo wcześniej.
1. Nowa funkcja trwa coraz dłużej
Kiedyś funkcja zajmowała kilka dni. Dzisiaj podobna zmiana wymaga kilku tygodni.
Nie musi to oznaczać wolniejszego zespołu.
Może oznaczać, że coraz więcej czasu pochłania zrozumienie istniejącego systemu i zabezpieczenie go przed skutkami zmiany.
2. Każda zmiana uruchamia efekt domina
Modyfikacja jednego modułu powoduje problemy w kilku innych miejscach.
To sygnał, że komponenty są zbyt mocno powiązane albo granice odpowiedzialności między nimi zostały źle określone.
3. Testy są głównie ręczne
Jeżeli każda większa zmiana wymaga ręcznego sprawdzania dziesiątek funkcji, koszt wdrożenia rośnie.
Problemem nie jest sam brak automatyzacji.
Problemem jest brak możliwości szybkiego uzyskania wiarygodnej informacji, czy zmiana czegoś nie zepsuła.
4. Zespół boi się ruszać określone fragmenty systemu
To bardzo praktyczny wskaźnik.
Jeżeli istnieją moduły, których programiści unikają, bo "nikt dokładnie nie wie, co się stanie po zmianie", ryzyko techniczne jest już realnym kosztem biznesowym.
5. System zależy od przestarzałych technologii
Stary framework sam w sobie nie oznacza problemu.
Problem pojawia się wtedy, gdy:
- nie jest już wspierany,
- trudno znaleźć specjalistów,
- zależności nie mogą być bezpiecznie aktualizowane,
- środowisko uruchomieniowe jest problematyczne,
- integracja z nowymi rozwiązaniami jest utrudniona.
Wtedy technologia zaczyna ograniczać możliwości biznesowe.
Czy zawsze trzeba pisać aplikację od nowa?
Nie.
To jeden z najczęstszych błędów w podejściu do legacy software.
Pełny rewrite może być uzasadniony, ale jest przedsięwzięciem wysokiego ryzyka.
Stary system często zawiera dziesiątki lub setki reguł biznesowych, wyjątków i zachowań, których nie ma w dokumentacji. Przepisując go od zera, można bardzo łatwo stworzyć system technologicznie nowy, ale biznesowo niekompletny.
Dlatego w wielu przypadkach lepszym rozwiązaniem jest modernizacja etapowa.
Jedna część systemu pozostaje aktywna, a kolejne obszary są stopniowo zastępowane nowymi komponentami.
Takie podejście jest znane m.in. jako wzorzec Strangler Fig. Pozwala modernizować system krok po kroku, dostarczać wartość wcześniej i ograniczać ryzyko jednorazowej migracji całego rozwiązania.
Kiedy modernizacja ma sens?
Warto ją rozważyć, gdy:
- system nadal realizuje istotne procesy biznesowe,
- architektura pozwala wydzielić przynajmniej część funkcjonalności,
- dane można bezpiecznie migrować lub integrować,
- problem dotyczy konkretnych obszarów, a nie całej konstrukcji,
- aplikacja generuje wartość i jej całkowita wymiana byłaby ryzykowna,
- można modernizować system etapami.
To szczególnie dobre rozwiązanie w przypadku systemów, których nie można po prostu wyłączyć na kilka miesięcy.
Kiedy modernizacja może nie mieć sensu?
Są też sytuacje, w których dalsze ratowanie starego systemu przestaje być ekonomiczne.
Na przykład gdy:
- architektura jest fundamentalnie niezgodna z obecnymi wymaganiami,
- kluczowe technologie są niewspierane,
- system nie ma wiarygodnych testów ani dokumentacji,
- bezpieczeństwo wymaga gruntownej przebudowy,
- każda większa zmiana wymaga ingerencji w niemal cały system,
- brakuje ludzi, którzy rozumieją jego działanie,
- koszty utrzymania i rozwoju przewyższają wartość dalszego wykorzystania.
Wtedy warto policzyć nie tylko koszt modernizacji.
Trzeba policzyć również koszt pozostania przy obecnym rozwiązaniu.
Najdroższa aplikacja to nie zawsze ta najdroższa w utrzymaniu
Można mieć system, którego miesięczne utrzymanie kosztuje relatywnie niewiele.
A jednocześnie każda nowa funkcja kosztuje wielokrotnie więcej niż powinna.
To właśnie dlatego sama faktura za hosting, serwer czy support nie mówi jeszcze, ile kosztuje technologia.
Prawdziwy koszt systemu obejmuje również:
- czas developmentu,
- czas testowania,
- koszt błędów,
- czas wdrażania,
- koszt przestojów,
- trudność rekrutacji,
- ryzyko bezpieczeństwa,
- koszt utraty wiedzy,
- opóźnienie nowych funkcji,
- ograniczenia biznesowe wynikające z technologii.
W pewnym momencie technologia przestaje być narzędziem wspierającym biznes.
Zaczyna być ograniczeniem biznesu.
Jak podejść do decyzji?
Zanim zapadnie decyzja "piszemy od nowa", warto przeprowadzić techniczny audyt.
Powinien obejmować przynajmniej:
Architekturę - jak system jest podzielony i jak komunikują się jego elementy.
Kod - jakość, złożoność, powtarzalność i miejsca szczególnie trudne w utrzymaniu.
Zależności - frameworki, biblioteki, wersje i ich wsparcie.
Bezpieczeństwo - podatności, sposób zarządzania dostępem i ryzyka wynikające z przestarzałych komponentów.
Testy - zakres automatyzacji i możliwość bezpiecznego wprowadzania zmian.
CI/CD - sposób budowania, testowania i wdrażania aplikacji.
Dane - strukturę bazy, migracje, integracje i zależności.
Monitoring - czy wiadomo, co dzieje się z systemem po wdrożeniu.
Proces rozwoju - ile rzeczywiście kosztuje dostarczenie kolejnej funkcji.
Dopiero na tej podstawie można racjonalnie rozważyć trzy scenariusze:
- utrzymujemy i rozwijamy,
- modernizujemy etapami,
- budujemy nowy system.
Nie ma jednej właściwej odpowiedzi. Jest natomiast właściwy sposób dojścia do odpowiedzi.
Technologia powinna umożliwiać rozwój, a nie go blokować
Dobra architektura nie polega na tym, że system wygląda nowocześnie.
Polega na tym, że można go zmieniać wtedy, kiedy wymaga tego biznes.
Dlatego warto patrzeć na aplikację nie tylko przez pryzmat tego, czy działa dzisiaj.
Trzeba również sprawdzić, ile będzie kosztowało dodanie kolejnych funkcji za rok, dwa albo pięć lat.
Bo system, który działa, ale uniemożliwia sprawny rozwój, może być znacznie większym problemem niż system, który po prostu wymaga modernizacji.



