Każdy zespół inżynierów ma dług technologiczny. Większość zespołów radzi sobie z tym z ciągłym poczuciem winy i niejasnym zamiarem „wpadnięcia w sprint za zadłużenie technologiczne”, który nigdy do końca nie kończy się sukcesem. Skutek: dług, który powinien był zostać spłacony pięć sprintów temu, nadal istnieje, dług, który tak naprawdę nie ma znaczenia, pochłania godziny czasu refaktoryzacji i nikt nie jest w stanie stwierdzić, który jest który.
To jest praktyczna wersja. Czym właściwie jest dług technologiczny. Trzy kategorie wymagające innego podejścia. Zgrubna kalkulacja, która decyduje, czy warto spłacić dany dług. Pięć anty-wzorców, które marnują Twój budżet na dług technologiczny. I jak dużą część sprintu powinno stanowić zaciąganie długów; naprawdę, z liczbami.
Czym właściwie jest dług technologiczny
Słowo jest przeciążone. Długem technologicznym nazywane są trzy różne rzeczy:
- Celowe, podjęte świadomie, aby wysłać przesyłkę szybciej. „Potrzebujemy tego w wersji produkcyjnej do piątku; pominiemy narzędzia do migracji i posprzątamy później”. To jest oryginalna metafora: pożyczka, która nalicza odsetki do czasu spłaty.
- Przypadkowo, z driftu. „Nie zauważyliśmy, że ta część bazy kodu stawała się coraz bardziej bałaganiarska z każdym sprintem, aż zamieniła się w bagno”. Nie zastosowano żadnego konkretnego skrótu; system po prostu zgnił.
- dług wiedzy; zamaskowany jako dług kodowy. „Nikt, kto to zbudował, nie jest nadal w zespole”. Kod może być w porządku; brakuje tylko ludzi, którzy rozumieją, dlaczego tak jest.
Każdy rodzaj wymaga innego traktowania. Nie wrzucaj ich do jednego worka. Pozostała część tego posta dotyczy głównie (1) i (2): dług wiedzy to osobny problem z osobnymi poprawkami (lepsza dokumentacja, rotacja par, ADR).
Zgrubna kalkulacja: kiedy warto płacić?
W przypadku każdej konkretnej części długu trzy pytania:
- Jak bardzo spowalnia to teraz zespół na sprint? (oszacowanie jako procent utraconej prędkości; 5%, 10%, 30%)
- Ile czasu zajmie spłata? (w punktach lub osobodniach)
- Jaki jest okres półtrwania; po jakim czasie ten kod zniknie? (3 miesiące? 2 lata? Nieskończoność?)
Jeśli cost-of-paying < (slowdown-per-sprint × number-of-sprints-until-it-goes-away), zapłać.
Działający przykład:
Powolne migracje baz danych pochłaniają ~15% szybkości zespołu w każdym sprincie. Naprawienie środowiska migracji wymagałoby ~20 punktów (przeważnie jeden inżynier, jeden sprint). Zespół planuje zachować tę bazę kodu co najmniej przez następny rok; powiedzmy 24 sprinty.
Całkowite spowolnienie, jeśli nie zostanie dotknięte: 15% × 24 sprinty = ~3,6 tygodni sprintu utraconej prędkości.
Koszt naprawy: 20 punktów = ~1 sprint wydajności.Zapłać. Matematyka jest przytłaczająca.
Kontrprzykład:
Niektóre starsze widoki administracyjne korzystają z przestarzałego narzędzia do tworzenia formularzy. Są powolne w utrzymaniu (~5% oporu prędkości dla inżyniera, który nad nimi pracuje). Naprawienie ich wymagałoby ~15 punktów. Menedżer produktu twierdzi, że cała sekcja administracyjna zostanie przepisana w trzecim kwartale (8 sprintów dalej).
Całkowite spowolnienie, jeśli nie zostanie dotknięte: 5% × 8 sprintów = 0,4 tygodnia sprintu utraconej prędkości.
Koszt naprawy: 15 punktów = ~0,75 tygodni sprintu.Nie płać. Przepisanie eliminuje dług za darmo.
Obliczenia nie powinny być dokładne. Ma to sprawić, że decyzja będzie widoczna. Kiedy jest to przytłaczające, działaj. Kiedy sytuacja jest na granicy, koszt debaty w obu przypadkach przewyższa oszczędności; wybierz coś łatwego do przywrócenia i przejdź dalej.
Trzy kategorie, które wymagają innego podejścia
Po wykonaniu obliczeń posortuj każdą część długu:
Dług złożony; płacić agresywnie
Dług, który dostaje droższe ponieważ zespół nad tym pracuje. Objawy: każda nowa funkcja w tym obszarze wymaga dotknięcia zgniłej części. Testuj środowisko wykonawcze, które rośnie szybciej niż baza kodu. Niestabilność CI, która pochłania więcej czasu w każdym sprincie.
Dług składany jest niebezpiecznym rodzajem zadłużenia. Kalkulacja kosztów jest myląca, ponieważ spowolnienie narasta w czasie. Zespół zwykle zdaje sobie z tego sprawę sześć miesięcy za późno.
Obsługa: budżet na to wyraźnie. Często nawet jeden inżynier i jeden sprint wystarcza, aby rozbić mieszankę. Nie czekaj na „sprint zadłużeniowy technologii”; to wersja, która nigdy się nie zdarza.
Dług statyczny; płacić oportunistycznie
Dług jest irytujący, ale nie pogarsza się. Stary kod, który działa dobrze, ale nie tak, jak ktokolwiek by go teraz napisał. Zależność z trzema mniejszymi wersjami.
Obsługa: Skaut – rządzi. Kiedy już znajdujesz się w pliku przeznaczonym do pracy nad funkcjami, pozostaw go nieco przejrzystszy. Nie otwieraj dedykowanych historii dla długu statycznego, chyba że obliczenia wskazują, że warto skoncentrować się na naprawie.
Zamrożony dług; zostaw to w spokoju
Zadłużenie w kodzie, którego zespół rzadko dotyka i które jest stabilne. Skrypt administracyjny z 2018 r., który działa co noc bez reklamacji. Starszy CSS w sekcji, której nikt już nie stylizuje. Zaplanowano usunięcie kodu.
Obsługa: ignorować. Dotykanie zamrożonego kodu stwarza ryzyko i przynosi znikomy zysk. Inżynierowie, którzy nie mogą się oprzeć refaktoryzacji zamrożonego kodu, to zazwyczaj inżynierowie, którzy chcą czuć się produktywni; zamiast tego przekieruj ich do łączenia długu.
Błąd popełniany przez większość zespołów: traktowanie całego długu tak, jakby się nasilał. Wypalają pojemność statycznego i zamrożonego długu, podczas gdy dług kumulujący gromadzi się w kącie.
Pięć anty-wzorców, które marnują Twój budżet na dług technologiczny
1. „Sprint za dług technologiczny”, który niczego nie rozwiązuje
Cały sprint pracy związanej wyłącznie z długiem technologicznym. Brzmi produktywnie; zwykle nie jest. Bez dyscypliny zakresu zespół wybiera łatwy dług (dług statyczny o niskim ryzyku i niskiej stopie zysku) i unika strasznego długu (stary proces uwierzytelniania, którego nikt nie chce dotykać). Koniec sprintu: wiele małych zatwierdzeń, brak faktycznego uzyskania dźwigni.
Rozwiązanie: budżetowy dług technologiczny jako procent każdego sprintu (10–20%), a nie jako własny sprint. Spłacaj dług w sposób ciągły, a nie partiami.
2. Gambit przepisywania
„Przepiszmy cały moduł od zera.” Czasem trafnie, zazwyczaj katastrofalnie. Przepisanie wymaga 3-5-krotności szacunkowej wartości. W połowie przepisywania, zmieniają się priorytety biznesowe. Stan na wpół przepisany jest gorszy niż stary lub nowy.
Poprawka: migracja przyrostowa przy uruchomionych obu wersjach. Wzór dusiciela. Osiągnij stan, w którym nowy prawdopodobnie obsługuje X% ruchu przed usunięciem starego. Tak, oznacza to nakładanie się złożoności na miesiące. Alternatywą jest przepisanie w połowie, które nigdy się nie kończy.
3. Refaktoryzacja bez celu
„Zamierzam wyczyścić ten plik”. Po co? Refaktoryzacja bez używać mając na uwadze, ma tendencję do optymalizacji pod kątem estetyki inżyniera, a nie szybkości zespołu. Plik staje się ładniejszy; nic nie działa lepiej.
Poprawka: refaktoryzacja w obsłudze następnej funkcji. Jeśli masz zamiar dodać funkcjonalność do funkcji, wykonaj refaktoryzację tę funkcję aby dodatek był czystszy. Nie refaktoryzuj funkcji, których nie masz zamiaru rozszerzać.
4. Perfekcjonista zabijający szacunki
Jeden inżynier zamienia każdą historię w misję związaną z długiem technologicznym. zadanie 3-punktowy staje się refaktorem 13-punktowym, ponieważ „Zauważyłem, że ten plik wymaga pracy”. Sprint się poślizgnął; oryginalna funkcja jest dostarczana z opóźnieniem.
Poprawka: refaktoryzacja w historii funkcji jest w porządku jeśli nie zmieni to oszacowania o więcej niż ~30%. Poza tym to osobna historia, która powinna być widoczna dla zespołu.
5. Dług, który tak naprawdę nie jest długiem; to „Napisałbym to inaczej”
Zaskakująco duża część „długu technologicznego” to preferencje jednego inżyniera w porównaniu z wyborem drugiego. ORM vs surowy SQL. Reagowanie klasowe a haki. Tabulatory a spacje w YAML. Żadne z nich nie jest dług w sensie kosztowym; są to nieporozumienia stylistyczne.
Poprawka: fragment kodu jest długiem tylko wtedy, gdy kosztuje prędkość zespołu teraz lub będzie się składać. Osobiste preferencje nie kwalifikują się. Decyzje zespołu dotyczące lintera i architektury uwzględniają rozbieżności stylistyczne; nie traktuj ich ponownie jako długu.
Jak duży sprint powinien stanowić praca nad długiem?
Uczciwy zakres: 10–25%, w zależności od wieku bazy kodu i aktualnej presji wysyłkowej zespołu.
- 5%: zespół znajduje się w aktywnym trybie gaśniczym (reakcja na incydent, pilna funkcja presji). Dług się kumuluje, ale zespół akceptuje to świadomie.
- 10-15%: zdrowy stan stabilny dla 2-3-letniego kodu źródłowego z aktywnym rozwojem produktu.
- 20-25%: tryb konserwacji lub baza kodu, którą zespół odziedziczył i którą przejmuje pod kontrolę.
- >30%: coś jest nie tak. Albo baza kodu jest tak zła, że praca w trybie czysto funkcjonalnym jest niemożliwa, albo zespół wykorzystuje „dług technologiczny” jako przykrywkę dla braku wysyłki.
Przekaż informację procentową zainteresowanym stronom. „Wydajemy ~15% każdego sprintu na infrastrukturę, którą odczujemy dopiero za sześć miesięcy” jest odpowiedzią, którą można obronić. „Spłacamy dług w razie potrzeby” nie jest.
Sygnał, że zadłużenie jest źle zarządzane
Trzy wzorce, na które warto zwrócić uwagę:
„Potrzebujemy sprintu zadłużeniowego”
Mówione raz na rok, wykonywane może w połowie przypadków. Jeśli zespół potrzebuje sprintu zadłużeniowego, pozwolono mu na akumulację długu znacznie powyżej punktu, w którym powinien był zostać spłacony. Napraw przydział, nie naprawiaj symptomu.
„Nie możemy dostarczyć tej funkcji bez uprzedniego refaktoryzacji”
Tłumaczy się jako: plik, którego musimy dotknąć, leżał tak długo sam, że nie może bezpiecznie przyjąć nowej pracy. Jest to dług złożony, który nie został złapany. Teraz płacisz zarówno refaktorowi i funkcja, szeregowo.
„Nasz refaktor stał się kolejnym refaktorem”
Wzorzec „Szybko to uprzątnę”, który zamienia się w 5-dniową wyprawę refaktoryzacyjną. Albo agresywnie określ ramy czasowe (jeden dzień, a następnie zatwierdź lub cofnij), albo przekształć je w prawdziwą historię z prawdziwymi szacunkami.
Kiedy dług technologiczny nie jest problemem
Powszechne zamieszanie: obwinianie długu technologicznego za problemy, których tak naprawdę dotyczy proces lub oprzyrządowanie.
- Powolny CI? Może to być dług technologiczny (wzdęcie testowe) lub może to być oprzyrządowanie (niewłaściwy rozmiar modułu CI, nie skonfigurowana równoległość). Diagnozuj przed refaktoryzacją.
- Przesunięcie zasięgu w połowie sprintu? Nie dług. To jest obsługa zmiany zakresu.
- Prędkość spadła? Może to być dług, mogą być zmiany w ludziach, może to być ponowna kalibracja punktu widzenia. (Patrz prędkość spadła; co robić.)
- „Kod jest trudny do zrozumienia”? Może to być dług, brak dokumentów, brak możliwości wdrożenia.
Zdiagnozuj zanim zapłacisz. Dług technologiczny jest wygodną odpowiedzią; często nie jest to właściwe.
Konkluzja
Dług technologiczny nie jest trwałym upadkiem moralnym; to obliczenia, które powinny skutkować decyzją na poziomie sprintu.
Sortuj: składane (płać agresywnie), statyczne (oportunistyczne), zamrożone (zostaw w spokoju). Wykonaj przybliżone obliczenia: koszt vs spowolnienie × czas do usunięcia tego kodu. Przeznacz 10–25% każdego sprintu na zadłużenie w sposób ciągły, a nie w sprintach wsadowych.
Nie refaktoryzuj bez celu. Nie pisz całości. Nie traktuj osobistych preferencji jako długu. Nie pozwól perfekcjonistowi zjeść sprintu.
Zespoły, które osiągnęły ten cel, pływają nieprzerwanie przez lata. Zespoły, które nie oscylują pomiędzy tworzeniem nowych funkcjonalności a ratowaniem długu technologicznego, nigdy nie osiągają dobrych wyników.
Wybierz numer. Broń tego. Dostosuj co kwartał.