Mateusz Mazurek – programista z pasją

Python, architektura, ciekawostki ze świata IT

Felietony/inne Inne

O spłacaniu długu, niekoniecznie tylko technicznego

Cześć.

Kto z Was nie słyszał o mitycznym długu technicznym? Temat czasem pojawia się na konferencjach, meetup’ach czy w wywiadach. Mądrzy ludzie opowiadają z uśmiechem o swoim success story, pokazując co, dlaczego i jak zrobili, aby wygrać tę nierówną walkę z długiem albo odwrotnie, opowiadają swoje fail story i mówią czego nie powinni nigdy robić, bo to u nich się nie sprawdziło. Obie sytuacje to cenna lekcja dla każdego, kto podejmuje się dług spłacić.

Ten artykuł to propozycja modelu/frameworku pozwalającego usystematyzować myślenie o długu technicznego. Bardzo mi zależy na dyskusji, więc będę wdzięczny, jeśli zostawisz komentarz. Jeśli nie chcesz czytać moich dywagacji o długu, to możesz kliknąć w ten link i skoczyć od razy do mojej propozycji modelu. Polecam jednak przeczytać całość.

Zacznijmy więc…

Kiedy pojawia się dług?

Dług pojawia się wtedy, kiedy musimy zrezygnować z jakiegoś aspektu trójkąta projektowego:

gdzie:

  • jakość to wszelkie działania dążące do utrzymania projektu zgodnie ze standardami jakości,
  • czas to wszelkie działania dążące do dostarczenia projektu na czas,
  • zakres to wszelkie działania dążące do realizacji każdego wymagania biznesowego.

Czasem zdarza się, że musimy wybrać dwa elementy z trzech, czyli:

  • dostarczamy projekt na czas z zachowaniem standardów jakościowych, ale obcinając częściowo zakres, albo
  • dostarczamy projekt na czas z zachowaniem pełnej funkcjonalności, ale pomijamy aspekt jakości, albo
  • dostarczamy projekt zgodny ze standardami jakości z pełna funkcjonalnością, ale po zadanym terminie.

Proszę, nie zrozumcie mnie źle, taka droga na skróty nie zawsze jest zła. Czasem naprawdę opłaca się napisać brzydki kod, który wyjdzie produkcyjnie za 2 miesiące i już zacznie ściągać klientów, zamiast dopracowywać wszystko latami, co może skutkować tym, że po prostu konkurencja przejmie rynek. Biznes nie jest grą łatwą i często w tej grze trzeba wybierać „mniejsze zło”. A to właśnie te wybory generują dług.

Dobry projekt

Dobry projekt to oczywiście taki, w którym jesteśmy w stanie dowieźć pełną funkcjonalność w określonym czasie i zachowując przy tym standardy jakości. Czy to możliwe? Jasne, że tak, ale wymaga znacznie więcej dobrze działających trybików, niż tylko ogarniętych programistów. Powiem więcej, nawet jeśli na czele takiego zespołu stanie dobry lider, to dalej nie ma pewności pełnego sukcesu.

Proces dostarczania oprogramowania zaczyna się od pomysłu. I już tu, na samym początku, mogą pojawić się problemy, jeśli pomysł nie będzie rzetelnie przeanalizowany i przemyślany przez PO. Im dłużej problem nie zostanie rozwiązany, tym większy jest jego wpływ na faktyczną implementację. Bardzo łatwo sobie wyobrazić sytuację, kiedy pytania developerów są na tyle niewygodne, że osoba decyzyjna musi zrobić krok w tył, bo jednak o czymś nie pomyślała. Albo pytanie rzuciło światło na owe pomysły pod takim kątem, że przestają one mieć sens. I pół biedy, jeśli osoba decyzyjna jest na tyle otwarta, że po prostu przeanalizuje problem jeszcze raz i wróci z rozwiązaniem. Gorzej, jeśli tak nie jest. Ale istnieje też druga strona medalu – bo przecież PO nie jest nieomylny – i tu wchodzą developerzy i ich analiza tematu. Jeśli oni oleją sprawę, to może ruszyć projekt, który od samego początku… Nie ma sensu.

Uwierzcie mi, dochodzi do takich sytuacji częściej niżby się mogło wydawać.

Inny problem to „pozorna zgodność wizji”. Czyli sytuacja kiedy developer i PO myślą, że się rozumieją ale tak naprawdę widzą przed oczami zupełnie inny cel. Problem jest o tyle skomplikowany, że wraz z postępem prac, rozjazd pomiędzy celem a efektem się zwiększa. Można z tym walczyć, organizując warsztaty, przygotowując słowniczki pojęć, tak, żeby każdy znał definicje słów używanych w firmie, a nawet stosując metodę potwierdzenia, czyli gdy PO coś Ci opowiada to Ty potem opowiadasz jemu jak to zrozumiałeś – tak, żeby upewnić się, że patrzycie w tę samą stronę. Możliwości jest wiele, a droga do sukcesu to świadoma praca nad komunikacją.

Moje doświadczenie z długiem

Celowo na razie unikam w tym artykule łączenia słowa „dług” ze słowem „techniczny”, bo na przestrzeni lat zauważyłem, że istnieje znacznie więcej rodzajów długu. Jako lider techniczny nie raz biorę się za spłacanie zaciągniętych pożyczek, nie zawsze są to spektakularne sukcesy, ale też rzadko są to kompletne katastrofy. Patrząc wstecz, widzę, że ciężko jest jednoznacznie określić sposób spłacania długu tak by… nie zaciągnąć nowego. Pół biedy, jeśli ten nowy będzie mniejszy ale gorzej, jeśli będzie większy. Naprawdę nie zawsze da się jednoznacznie przewidzieć efekty swoich decyzji, a na konkretny feedback często czeka się długo.

Oczywiście, nie jednokrotnie podejmowałem decyzje zaciągające dług, ale zawsze szły za tym solidne argumenty, typu:

  • pracujemy nad tym, aby zdobyć klienta,
  • pracujemy nad tym, żeby nie stracić klienta,
  • sprawnie naprawiamy awarię aplikacji, tak, żeby klienci mogli z niej korzystać,
  • itp

Warto pamiętać, że pieniądze generowane są przez kod, który działa. Nie koniecznie musi on być idealny.

Wszędzie ważny jest zdrowy rozsądek. Może zdarzyć się, że klient którego próbujemy zdobyć, będzie przynosił firmie tak mało pieniędzy, że późniejsza spłata długu okaże się wielokrotnie droższa. Oczywiście nie ode mnie zależy, czy firma podejmie ryzyko, ale zawsze można dać znać, że właśnie radosnym krokiem wchodzimy na minę i za pól roku wcale nie będzie nam do śmiechu.

Przy spłacaniu długu trzeba też zastanowić się jak podzielić go na etapy. To naprawdę ważne. Bez tego wpadniemy w tak zwaną spiralę refactoringu, czyli sytuacji w której jedna zmiana pociąga za sobą inną, ta wymusza kolejną i tak dalej, aż w końcu przepiszemy pól systemu, a w tym czasie np. zmienią się wymagania co do działania tego kawałka kodu i nasza praca pójdzie na marne. Innym zagrożeniem jest to, że mimo wszystko, nie zawsze uda nam się bezboleśnie przejść z kodu brzydkiego na ładny, jednym słowem może okazać się, że bezawaryjna praca klientów zostanie zaburzona naszymi zmianami. Takiej sytuacji łatwiej uniknąć, jeśli poprawiamy mniejsze kawałki kodu. Oczywiście, podstawowym narzędziem, które może nam pomóc są testy. A dokładniej solidny i wyczerpujący zestaw testów. Pamiętajmy o nich.

Idąc dalej, apel ode mnie: nie wierzcie programistom którzy mówią „eee to trzeba wszystko przepisać”. Z mojego doświadczenia wynika, że mało jest sytuacji kiedy aplikację naprawdę trzeba przepisać. Oczywiście czasem trzeba, ale lwia część przypadków to po prostu… lenistwo. Programistom nie chce się zrozumieć co i kiedy doprowadziło ten kod do takiego stanu, jakie decyzje technologiczne spowodowały problemy, gdzie jest zgrzyt w mapowaniu biznesu na technikalia i tak dalej. A brak tej wiedzy często sprawia, że wymieniamy aplikację z „brzydkiej, ale działającej” na „niewiele ładniejszą i nie działającą”. Bo popełniamy podobne błędy i dokładamy nowe.

Klasyczny problem ze spłacaniem długu to „jak przekonać PO/PM, że wartościowym jest danie mi 2 dni na coś, co nie zmieni działania aplikacji„. Bo skoro działało wcześniej, to po co angażować w to czas? Tutaj nie ma prostej odpowiedzi. Po prostu punkt widzenia tych ludzi jest inny. Wyobraź sobie, że masz auto. Dzwoni do Ciebie mechanik i mówi, że za 1000 zł zamontuje Ci nowe lusterka. No to pytasz go „ale ja już mam lusterka, co zmieni ich wymiana?”. On odpowiada: nic. Ale będziesz mieć nowe lusterka. Czy dałbyś się przekonać? Pewnie nie. W tym temacie trzeba pracować nad zaufaniem – PM/PO musi wierzyć Ci, że to jest naprawdę potrzebne, a Ty masz tego nie wykorzystywać. Nie dziw się, że jeśli weźmiesz na sprint temat na 1 dzień, a zajmie Ci to miesiąc, to w przyszłości PO/PM dwa razy zastanowi się czy Ci zaufać. Jeśli natomiast widzisz już, że temat jest poważniejszy niż sądziłeś (to się zdarza i jest w pełni naturalne) to dawaj znać, że taka sytuacja nastąpiła. Zaproponuj podział tematu na etapy, może zaangażuj inny zespół. Ciężko dać tu jedna słuszną radę, która zawsze będzie działać. Oczywiście, są osoby którym nigdy nie wytłumaczysz, że coś koniecznie trzeba zrobić. Wtedy problemem nie jest dług techniczny, a dług organizacyjny. Ale o tym będzie dalej.

Walka z długiem to coś, co dotyka każdego programistę. Żeby to jakoś poukładać w głowie, stworzyłem model który nazwałem five levels of debt – który organizuje i grupuje dług na pięć poziomów, biorąc pod uwagę całą organizację, a nie tylko jej techniczną część.


Czekaj, stop!

Podoba Ci się to co tworzę? Jeśli tak to zapraszam Cię do zapisania się na newsletter:
a w ramach prezentu otrzymasz całkowicie za darmo, dwa dokumenty PDF „6 (nie zawsze oczywistych) błędów popełnianych podczas nauki programowania” który jest jednym z efektów ponad siedmioletniej pracy i obserwacji rozwoju niejednego programisty oraz „Wstęp do testowania w Pythonie”, będący wprowadzeniem do biblioteki PyTest.
Jeśli to Cię interesuje to zapraszam również na swoje social media.

Jak i do ewentualnego postawienia mi kawy :)
Postaw mi kawę na buycoffee.to

Five levels of debt

Model ten rodził się z mojej głowie przez jakiś czas. Potrzebował jednak przejść przez kilka faz rozwoju, żebym uznał, że mogę się nim podzielić publicznie. Zakłada on podział długu na 5 poziomów:

  1. Technologiczny
  2. Techniczny
  3. Architektoniczny
  4. Organizacyjny
  5. Produktowy

Każdy z tych 5 poziomów jest spójny pod względem sprawczości, trudności spłacenia i typu zaangażowania. Nim przejdę do omawiania spójności, popatrzmy najpierw na typu długu.

Dług technologiczny

Ten typ długu nie dotyczy naszego kodu bezpośrednio. Jest on związany natomiast z całym jego ekosystemem, czyli z systemem wersjonowania, aktualnością paczek, procesem CI/CD, procesem dostarczania do klienta, procesem separacji środowisk i tak dalej. Mówiąc inaczej, dług ten dotyczy elementów technologii w której się obracamy jak i elementów, które sami do tej technologii dokleiliśmy.

Dług techniczny

Najpopularniejszy typ długu. To tutaj są umieszczone wszystkie problemy z kodem, które chcemy poprawić. Możemy umieścić tutaj zarówno łamanie zasad SOLIDu jak i niejednoznaczność w nazewnictwie zmiennych. Ogólnie każdy refactor pojedynczych aplikacji znajdzie się w tej grupie.

Dług architektoniczny

Tutaj znajdą się wszystkie problemy ,które widać dopiero jak na system popatrzy się z góry. Chodzi mi o powiązania między komponentami, o dbanie o to, by były one ze sobą luźno związane i tak dalej. Jednym słowem: w tej grupie lądują problemy z architekturą.

Dług organizacyjny

Ten typ długu to problemy organizacyjne, występujące w firmie. Może to być bezsensowny proces dogadywania urlopów czy zły podział na zespoły. Trzeba uważać, bo spłacając taki dług, można bardzo łatwo zaciągnąć kolejny – wystarczy, że tworząc nowy proces nie zadba się o jego spójność i jednoznaczność, np przez tak banalne, mógłby się wydawać, elementy, jak brak jasno określanych definicji słów, których proces używa. Nic tak nie zatapia procesów jak pozwolenie na to, by pozostało coś, co można zinterpretować niejednoznacznie.

Dług produktowy

Tutaj wchodzimy na poziom samego produktu. Ten typ długu zakłada wszystkie „pójścia na skróty” w opracowywaniu nowych funkcjonalności. Znajdzie się tutaj każdy bezsensowny ficzer który wpadł na sprint. Drogą do brania tego typu pożyczek są wszystkie sytuacje w stylu „zostawmy to na razie, później się pomyśli”, „zrób na razie tylko w tym elemencie systemu, potem poprawimy”, „dokumentacja? To potem zrób, bo teraz klient czeka” i tak dalej.

Ten typ dług spłaca się bardzo trudno, bo walczymy nie tylko ze swoim przyzwyczajeniem ale i przyzwyczajeniem klientów, najprościej mówiąc, z biegiem czasu, coraz bardziej oswajamy się z tym co widzimy i przestaje nam przeszkadzać to, że wchodzimy do auta przez bagażnik. Pierwszy punkt konieczny do spłacenia długu: poczuj wartość tego, że dobry produkt = spójny produkt. Drugi punkt: zauważ problem. Trzeci: przekonaj siebie i klientów, że to potrzebne.

Warto walczyć o to by produkt był możliwie najprostszy i najspójniejszy, bo przekłada się to bezpośrednio na niższe typy długów.

Spójność modelu

Model zapewnia spójność na, już wcześniej wspomnianych, czterech płaszczyznach:

  • sprawczość,
  • trudność spłacenia długu,
  • typ zaangażowania,

Sprawczość

Czyli jak bardzo jesteś władny w kontekście wiążącej decyzji.

Jeśli pełnisz w zespole rolę leadera / tech leadera to z dużą dozą pewności możesz podejmować decyzje odnośnie długu technologicznego i technicznego. Często możesz w takiej sytuacji decydować który z elementów długu chcesz spłacić i kiedy. Jako developer zawsze możesz zasugerować leaderowi swoje pomysły co zapewne zapunktuje na przyszłość. Oczywiście nadal nad Tobą jest sposób pracy czyli np podział na sprinty i ich pojemność, ale w tym przypadku chodzi o samą sprawczość. A tu jesteś w stanie sprawić, żeby rzecz zaczęła się dziać.

Spójrz z perspektywy techlead’a – wyższe typy długu są nierozerwalnie związane z malejącą sprawczością. Trudniej techleadowi zmienić architekturę aplikacji bo musi uzyskać akceptację innych zespołów, tak, żeby ich komponenty były gotowe na ewentualne zmiany. Konieczność organizacji sprawia, że tracimy częściowo moc sprawczą. Jesteśmy uzależnieni od innych.

Kolejne typy długu będą już oderwane od technikalii, co sprawia, że Twoja sprawczość maleje jeszcze bardziej, bo nie jesteś w stanie zrobić roszad w zespołach bez konsultacji z osobami które w hierarchii są ponad Tobą. Podobnie ma się sprawa z produktem, nie jesteś w stanie podjąć decyzji o usunięciu jakiegoś ficzera bez konsultacji i akceptacji ze strony właściciela produktu.

Oczywiście, że zdarzają się sytuacje patologiczne, kiedy PO mówi, że trzeba zreafactoryzować jakiś kawałek kodu albo programistę, który będzie chciał usunąć „nikomu niepotrzebny” ficzer. Nie zrozum mnie źle, sugestie są zawsze mile widziane, ale ostateczna sprawczość nie zależy od osoby sugerującej. Inny przykład patologii to wymuszanie sprawczości terroryzmem, czyli np. praca nad innymi zagadnieniami niż przewiduje sprint, co sprawia, że poziom zaawansowania projektu który miał się nigdy nie zacząć jest na tyle duży, że nie ma sensu go stopować. Takie wymuszanie powinno spotkać się z szybką i stanowczą reakcją osób decyzyjnych.

Trudność spłacania długu

Im wyższy typ długu tym zazwyczaj trudniej go spłacić. Wynika to wprost z zakresu zmian, który jest dość wąski przy dwóch pierwszych typach i zwiększa się znacząco przy kolejnych. Po prostu łatwiej dobrze przepisać dużą funkcję niż zmienić organizacje zespołów na lepszą.

Typ zaangażowania

Model gwarantuje spójność z konkretnej perspektywy. Będąc developerem i chcąc spłacić dług organizacyjny, Twoje działania będą znacząco inne niż w porównaniu do np. długu architektonicznego. Będziesz potrzebował więcej rozmów a mniej faktycznego działania. Więcej ustaleń i kompromisów niż faktycznego postępu. Mówiąc prościej, im wyższy typ długu, tym Twoja praca nad jego spłaceniem będzie inna. Podobnie ma się sprawa z perspektywy PO, chcąc zmienić produkt będzie miał dużo faktycznej pracy, natomiast jak będzie chciał zmienić architekturę to proporcja rozmów do realizacji się zmieni.

Cechy modelu

Prace nad poszczególnymi typami długów będą oddziaływać na siebie. W idealnym świecie oddziaływanie powinno promieniować tylko w dół. Mówiąc prościej, praca nad produktem sprawi, że może zmienić się każdy z długów niższego typu. Może, ale nie musi. I nie musi zostać on spłacony, ba, może zostać nawet zaciągnięty nowy. Zmiany techniczne mogą wymagać zmian technologicznych a zmiany organizacyjne mogą wymusić konieczność innego podziału komponentów.

Zastosowanie modelu

Ten model, tak jak wszystkie inne modele pracy służą do tego, aby uporządkować swój styl myślenia i określić strefy wpływów. Mi osobiście pomaga to robić sobie w głowie taki bigpicture tego, jakie kroki trzeba podjąć, żeby było znacząco lepiej. Pozwala mi to oszacować na grubo ile jakiego typu pracy będą te kroki wymagały, jak dużo trzeba dogadać i jak dużo problemów będzie „po drodze”. Mi to pomaga. A Tobie pomoże?

Feedback

No własnie. Wymyśliłem sobie coś, opisałem a teraz proszę Ciebie czytelniku, żebyś napisał komentarz i powiedział co o tym sądzisz? Czy wydaje Ci się to wartościowe, czy nie? Jeśli czegoś Ci brakuje albo coś byś zmienił, to nie krepuj się, zostaw po sobie ślad.

Dzięki za wizytę,
Mateusz Mazurek

A może wolisz nowości na mail?

Subskrybuj
Powiadom o
guest

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.

0 komentarzy
Inline Feedbacks
View all comments