Kiedy zaczynałem pracę jako programista, zdarzało mi się patrzeć na zastany kod i zastanawiać, dlaczego ktoś zrobił coś w taki, a nie inny sposób.
Przecież były już nowsze rozwiązania. W C++ pojawiały się kolejne standardy, język dawał nowe możliwości, a ja znałem techniki, których w danym miejscu nie wykorzystywano. Dlaczego więc ludzie, którzy pracowali z tym kodem na co dzień i mieli większe doświadczenie ode mnie, nie korzystali z tych wszystkich dobrodziejstw?
Z dzisiejszej perspektywy brzmi to trochę jak rozumowanie cztero- czy pięciolatka. Skoro można zrobić coś lepiej, to dlaczego po prostu tego nie zrobimy?
Biznes nie płaci za ładny kod
W projektach zawsze było coś do zrobienia. Nowa funkcjonalność, poprawka, kolejny temat do dowiezienia. Czas był i jest ograniczony, a biznes oczekiwał i oczekuje nadal działającego oprogramowania. Trudno się temu dziwić – w końcu za to płaci.
Oczywiście nie rzucałem się od razu do przepisywania całego systemu.. Refaktoryzacja kodu tylko dlatego, że można go napisać nowocześniej, a przede wszystkim czytelniej, niekoniecznie miała wysoki priorytet. Zwłaszcza gdy istniejące rozwiązanie działało, a jego wymiana nie przynosiła użytkownikowi żadnej widocznej korzyści.
I tak powstaje dług techniczny. Nie zawsze dlatego, że ktoś nie znał dobrych praktyk albo nie nadążał za rozwojem języka. Czasami po prostu inne rzeczy były ważniejsze. Decyzje podejmowane pod presją czasu zostawały w kodzie na lata, a później dochodziły kolejne funkcje i kolejne zależności.
Nie oznacza to, że każdy stary fragment kodu jest dobry i można go zostawić w spokoju. Oznacza jedynie, że za jego obecnym kształtem może stać coś więcej niż brak umiejętności autora.
Najpierw trzeba zrozumieć, co właściwie się zmieni
Z czasem dochodzi jeszcze jeden problem: im bardziej zagmatwany jest kod, tym trudniej przewidzieć skutki pozornie niewielkiej zmiany.
Można zobaczyć coś, co aż prosi się o poprawienie. Można mieć pomysł, jak zrobić to czyściej, nowocześniej i wygodniej. Ale zanim zacznie się zmieniać istniejące rozwiązanie, trzeba jeszcze zrozumieć, z czym ono jest powiązane i co może od niego zależeć.
A to kosztuje. Nie tylko czas, lecz także wysiłek potrzebny do ogarnięcia całego kontekstu. Czasami samo prześledzenie zależności jest trudniejsze i bardziej czasochłonne niż napisanie nowego kodu.
Dlatego nie każda zmiana, która wygląda dobrze na poziomie pojedynczej funkcji czy klasy, jest równie dobrym pomysłem w skali całego systemu. Szczególnie jeśli nie mamy pewności, jakie konsekwencje przyniesie.
A warningi można poprawić przy okazji
Nie chcę jednak udawać, że po latach przestałem zauważać rzeczy, które można zrobić lepiej. Jeśli jest okazja, lubię na przykład ogarnąć warningi. Jakaś taka niepisana potrzeba posiadania porządku, a komunikat o braku ostrzeżeń na koniec procesu budowania projektu daje dodatkowy spokój i satysfakcję. Jeśli można coś poprawić bez niepotrzebnego ryzyka i przy okazji wykonywanej pracy to czemu nie? Robię więc rzeczy po swojemu tam, gdzie mogę. Korzystam z rozwiązań, które bardziej mi odpowiadają, i trochę liczę na to, że ktoś je zauważy, może się zainspiruje i sam zacznie stosować nowsze możliwości C++.
A jeśli nie ma na to przestrzeni, to trudno. Są rzeczy ważniejsze do dowiezienia.
Może właśnie na tym polega różnica między patrzeniem na kod wyłącznie z perspektywy programisty, a patrzeniem na niego w kontekście całego projektu. To, że potrafimy coś poprawić, nie oznacza, że powinniśmy robić to właśnie teraz.
I nie, nie oznacza to również, że trzeba bezrefleksyjnie akceptować każdy kawałek legacy. Po prostu zanim uznamy, że poprzednicy nie wiedzieli, co robią, warto sprawdzić w jakich warunkach podejmowali swoje decyzje.
Czasami rzeczywiście ktoś napisał coś kiepsko. A czasami po prostu miał inne zadania do dowiezienia. No bo nikt przecież nie idzie do pracy z myślą, że dzisiaj zrobię możliwie najgorzej jak się da.
I chyba warto umieć rozróżnić te dwie sytuacje.