środa, 30 stycznia 2019

Dług techniczny - czym jest a czym nie jest

Ostatnio w moim otoczeniu często stykam się z tematem „długu technicznego”. Ale podczas rozmów z różnymi ludźmi zauważyłem, że termin ten jest czasami przez różnych ludzi rozumiany w różny sposób. Stąd pomysł na ten tekst.

Wstęp

Termin „dług techniczny” (lub „dług projektowy”) stworzył Ward Cunningham (twórca pierwszego wiki) we wczesnych latach 90’ (patrz: https://www.youtube.com/watch?v=pqeJFYwnkjE). Wywodzi się on z analogii do kredytu, jaki zaciąga się w banku w celu szybszego uzyskania korzyści. W uproszczeniu: zbudowanie rozwiązania nieoptymalnego (na skróty) odpowiada zaciągnięciu kredytu. Dzięki kredytowi okazja rynkowa jest wykorzystana (korzyść mamy dzisiaj), koszt budowy rozwiązania o optymalnej jakości jest odroczony w czasie ale pojawiają się też odsetki. Te odsetki, to w uproszczeniu zmniejszona łatwość zmiany i/lub zmniejszona efektywność lub zwiększone ryzyko działania systemu. Z kolei rozliczenie kredytu równa się doprowadzeniu „zadłużonego” rozwiązania do optymalnej jakości poprzez jego refaktoring lub zastąpienie nowym.

Objawy

Dług techniczny może się objawiać na wiele różnych sposobów dla wielu różnych interesariuszy:
  • Użytkownicy mogą być niezadowoleni z użyteczności aplikacji
  • Ludzie od infrastruktury i utrzymania mogą być niezadowoleni z powodu wysokich kosztów operacyjnych aplikacji
  • Menedżerowie biznesowi mogą być sfrustrowani kosztem i powolnym tempem dostarczania zmian w aplikacji a przez to w procesach biznesowych
  • Ludzie z bezpieczeństwa i zarządzania ryzykiem zauważają, że aplikacja nie nadąża ze spełnianiem standardów bezpieczeństwa

Dług techniczny akumuluje się, jeśli nie jest zmniejszany. Z czasem może nawet przewyższyć możliwości firmy do poradzenia sobie z nim. Jednak, aby zmniejszać (spłacać) dług techniczny, trzeba go najpierw dobrze zrozumieć. Czym on zatem jest?

Definicja

Spotkałem się z wieloma definicjami terminu „dług techniczny” (przytaczam je w oryginale):
  • "The residual cost of completing technology tasks left undone in the race to be agile, innovative, or from lack of funding".
  • "The ongoing costs of inconvenience, inconsistencies, and lost opportunities".
  • "Unfunded critical technical liabilities".
  • "A design or construction approach that is expedient in the short term but that creates a technical context in which the same work will cost more to do later than it would cost to do now (including increased cost over time)".
  • "Delayed technical work that is incurred when technical short cuts are taken, usually in pursuit of calendar-driven software schedules".
  • "A trade-off between the short-term benefit of rapid delivery and long-term value".

Zgadzam się z powyższymi definicjami ale wciąż są one dla mnie zbyt ogólne. Z tego powodu najbardziej podoba mi się definicja Gartnera, która określa, o jakie braki techniczne chodzi (a o jakie nie), gdy mówimy o długu technicznym. Wg Gartnera dług techniczny jest „odchyleniem systemu od jego wszelkich wymagań niefunkcjonalnych”. Proste. Z tej definicji wynika na przykład, że:

  • dług techniczny nie dotyczy funkcjonalności - brak wymaganej funkcji aplikacji nie jest długiem technicznym,
  • dług techniczny jest względny - może się zmienić w jednej chwili jedynie poprzez zmianę wymagań niefunkcjonalnych (np. dostępność systemu wynosi dzisiaj 8/5 ale wymaganie też było 8/5 --> długu nie ma; ale jak tylko zmienimy wymaganie na 12/6, to w tej samej chwili dług się pojawi).

7 obszarów negatywnego wpływu

Skoro więc dług techniczny jest odchyleniem od wymagań niefunkcjonalnych, to do dokładniejszego zrozumienia i oceny poziomu tego długu będzie nam potrzebna klasyfikacja wymagań niefunkcjonalnych. Prosty model takiej klasyfikacji można znaleźć w standardzie ISO/IEC 25010, który jest ulepszona wersją lepiej znanego ale starszego ISO/IEC 9126. Standard ISO/IEC 25010 określa 8 cech jakości oprogramowania, z czego 1 dotyczy funkcjonalności a pozostałe 7 dotyczą cech niefunkcjonalnych aplikacji:

  1. „Niezawodność” (ang. „Reliability”) - obejmuje atrybuty niższego poziomu, takie jak „Stabilność” (ang. „Stability”), „Dostępność” (ang. „Availability”) i „Możliwość odzyskania” (ang. „Recoverability”).
  2. „Użyteczność” (ang. „Usability”) - obejmuje obszary, takie jak "szybkość uczenia się" a także „łatwość obsługi”.
  3. „Wydajność” (ang. „Performance efficiency”) - ilość zasobów obliczeniowych potrzebnych do zapewnienia odpowiedniego poziomu wydajności.
  4. „Utrzymywalność” (ang. „Maintainability”) - odnosi się do tych cech oprogramowania, które ułatwiają (lub utrudniają) wprowadzanie zmian w funkcjonalności, naprawianie błędów i zapewnienie jakości usług.
  5. „Przenośność” (ang. „Portability”) - obejmuje przenośność między urządzeniami i systemami operacyjnymi a także łatwość, z jaką aplikacja może być zlokalizowana pod kątem specyficznych cech geograficznych, takich jak język czy podatek obrotowy.
  6. „Bezpieczeństwo” (ang. „Security”) - obejmuje wszystkie atrybuty bezpieczeństwa systemu.
  7. „Zgodność” (ang. „Compatibility”)  - określa łatwość i wydajność integracji zapewnianej przez oprogramowanie.

Wg definicji Gartnera dług techniczny może mieć negatywny wpływ w ww. 7 obszarach i nigdzie więcej. Oznacza to, że w przyrodzie występuje dokładnie 7 rodzajów długu technicznego:
  1. Techniczny dług niezawodności (ang. „Reliability Technical Debt”).
  2. Techniczny dług użyteczności (ang. „Usability Technical Debt”).
  3. Techniczny dług wydajności (ang. „Performance efficiency Technical Debt”).
  4. Techniczny dług utrzymywalności (ang. „Maintainability Technical Debt”).
  5. Techniczny dług przenośności (ang. „Portability Technical Debt”)
  6. Techniczny dług bezpieczeństwa (ang. „Security Technical Debt”).
  7. Techniczny dług zgodności” (ang. „Compatibility Technical Debt”).

4 możliwe powody

Wg Gartnera dług techniczny może w systemie powstać z 4 powodów:
  1. Dług planowany - zespół projektowy wie, że istnieje pewne wymaganie niefunkcjonalne N, ale z jakiegoś powodu zdecydowano się go nie realizować i wszyscy interesariusze o tym wiedzą. Np. wymaganie odtwarzalności – w przypadku utraty całego data center aplikacja powinna być odtworzona w ciągu 15 minut; niestety okazuje się to za drogie, więc będzie zapewnione odtworzenie w ciągu 4 godzin. Albo sytuacja, w której z powodu braku czasu (potrzeby dostarczenia rozwiązania szybko) rozwiązanie realizuje się bez zaimplementowanych znanych i wymaganych zabezpieczeń. Wszelkie rodzajów PoC’ów (ang. „Proof of Concept”) także się mieszczą w tej kategorii – w zamian za krótki czas budowy i naukę powstaje rozwiązanie o nie-docelowej jakości.
  2. Dług dostarczony - zespół projektowy wiedział, że wymaganie niefunkcjonalne N istnieje i planował je zrealizować. Ale się nie udało. Np. system miał móc obsłużyć 200 równoległych użytkowników. Zaprojektowano pod to 6 serwerów. Ale po wdrożeniu okazało się, że te 6 serwerów wystarcza do obsłużenia 100 równoległych użytkowników. 200 równoległych użytkowników będzie wymagać 40 serwerów.
  3. Dług odkryty - zespół projektowy spełnił wszystkie określone wymagania, ale po tym, jak system został dostarczony okazało się, że istnieją wymagania, które wcześniej nie zostały określone. Na przykład nie było wymogu "przenośności" językowej, ale po dostarczeniu systemu firma stwierdziła, że aplikacja musi również obsługiwać inne języki, bo firma zamierza otworzyć oddziały w innych krajach. Odkrywamy nowe wymagania niefunkcjonalne (przenośności językowej), które wcześniej nie były wyartykułowane.
  4. Dług nabyty - dług, który system nabywa z biegiem czasu, czasami po wielu latach, z dwóch powodów:
    1. Zmiana biznesowa – system pracuje dobrze przez wiele lat, ale w wyniku przeglądu bezpieczeństwa powstaje nowa polityka bezpieczeństwa, wcześniej nieistniejąca, która wymaga „single-sign-on” dla wszystkich aplikacji. Albo aplikacja pracuje dobrze w trybie 8/5, ale biznes rozszerza zakres czasowy swojej pracy i aplikacja musi pracować 12/6. W takim momencie aplikacja „nabyła dług”, który jest efektem zmiany wymagań niefunkcjonalnych.
    2. Entropia oprogramowania - z czasem, wraz z dodawaniem nowych funkcji do aplikacji, aplikacja staje się coraz trudniejsza do zmiany z powodu wzrostu złożoności. Lub po prostu wzrósł wolumen przetwarzanych danych i aplikacja zaczęła działać wolniej.

Zaniechanie czynności utrzymaniowych nie jest długiem technicznym!

Ww. rodzaje długu są generalnie wynikiem decyzji co do sposobu realizacji lub wynikiem zmiany wymagań niefunkcjonalnych. Natomiast wg Gartnera nie odnoszą się one do sytuacji, w której nie wykonano wymaganych upgrade’ów i w efekcie używana technologia przestała być wspierana. Np. nie dokonaliśmy upgrade’u systemu operacyjnego lub bazy danych na wersję wspieraną, bo budżet, bo priorytety, bo byliśmy zajęci czymś innym. Według ww. definicji to nie jest dług techniczny, gdyż nie jest wynikiem decyzji projektowej, błędu w tej decyzji, zmiany wymagań niefunkcjonalnych, wzrostu złożoności czy wzrostu wolumenu transakcji. Jest wynikiem zaniechania czynności utrzymaniowych.
Dług utrzymaniowy (doprowadzenie do braku wsparcia) wynika zawsze z konfliktu zasobów - z decyzji, na co je przeznaczyć: na nową funkcjonalność, czy na upgrade bazy danych. Nowa funkcjonalność zamiast koniecznego upgrade’u, to odłożenie zobowiązania utrzymaniowego na później. Trzeba jednak zdawać sobie sprawę, że dokonując takiego odłożenia wcale nie oszczędzamy pieniędzy. Odraczamy jedynie nasze zobowiązanie na przyszłe pokolenia a w zamian za te pieniądze (i/lub czas) budujemy nowy feature dzisiaj. Prędzej czy później jednak to zobowiązanie trzeba będzie spłacić. Z długiem technicznym jest inaczej - można go zlikwidować np. poprzez rezygnację z wymagań niefunkcjonalnych.

Ten rodzaj długu - utrzymaniowego - Gartner nazywa „Długiem IT” i definiuje następująco: „Dług IT, to koszt obsługi opóźnionej lub odroczonej konserwacji portfela aplikacji”. Czyli dług IT, to wg Gartner’a ilość pieniędzy potrzebna na doprowadzenie wszystkich naszych systemów do stanu supported.


Podsumowując:
  • Twórcą terminu „dług techniczny” jest Ward Cunningham i dotyczy on odchylenia systemu od jego wszelkich wymagań niefunkcjonalnych. Może się pojawić w wyniku decyzji podjętej podczas projektowania i budowy rozwiązania lub w skutek zmiany / nowych wymagań niefunkcjonalnych.
  • „Dług techniczny” nie dotyczy odraczania czynności utrzymaniowych na później. Twórcą nazwy dla tego rodzaj długu jest Gartner, który nazywa ten dług „Długiem IT” (ang. „IT Debt”) i definiuje go jako koszt doprowadzenia portfela aplikacji do stanu supported.

Skutki długu technicznego

Wróćmy do długu technicznego, który jest odchyleniem od wszelkich wymagań niefunkcjonalnych. Generalnie celem definiowania wymagań niefunkcjonalnych jest zapewnienie wymaganej „ilości” danej usługi IT - tzn. jej stabilności, dostępności, wydajności, bezpieczeństwa, itd. (usługa IT wg ITIL v3, to funkcjonalność dostarczana w określonej „ilości”). Istnienie długu technicznego tę „ilość” zmniejsza, co z kolei powoduje zwiększenie kosztu i/lub ryzyka operacji, której tej wymaganej „ilości” usługi IT potrzebują. Na przykład:
  • Aplikacja z długiem w obszarze utrzymywalności (ang. „Maintainability”) będzie miała wyższe koszty aktywności utrzymaniowych i czynności wprowadzania zmian.
  • Aplikacja, która nie osiąga swoich celów w zakresie wydajności (ang. „Performance efficiency”), będzie powodowała wyższy poziom kosztów operacyjnych, gdyż procesy biznesowe przez nią wspierane również będą za mało wydajne.
  • Aplikacja, która nie jest w stanie spełnić swoich celów związanych z odzyskiwalnością (ang. „Recoverability”) stwarza wysoki stopień ryzyka biznesowego ze względu na potencjał przedłużających się (tzn. dłuższych, niż dopuszczalne) przestojów w przypadku awarii systemu.
  • Aplikacja, która nie jest w stanie spełnić swoich wymagań dotyczących użyteczności (ang. „Usability”), może powodować zwiększenie kosztów biznesowych spowodowanych niezdolnością jej użytkowników do skutecznego wykonywania swoich zadań.

Zarządzenie długiem technicznym jest szczególnie istotne w metodach agile’owych

W metodach waterfal’owych dług techniczny pojawia się zwykle z powodu objawiających się w trakcie projektu ograniczeń czasowych i budżetowych. Jeśli się pojawią (a im większym projekt, tym większe prawdopodobieństwo ich wystąpienia), to w ich efekcie obcina się zakres: nie dostarczymy dokumentacji potrzebnej do utrzymania, nie zoptymalizujemy bazy danych, nie będzie szyfrowania, zahardkodujemy, zamiast zbudować coś konfigurowalnego, itd. Te wszystkie rzeczy, których nie dostarczymy, przekłada się później na „fazę drugą”, na którą z reguły jednak już nie ma budżetu, nie ma zasobów, nie ma planu, … Innymi słowy w metodach waterfall’owych dług techniczny tworzymy w wyniku problemów ale później przeważnie nim nie zarządzamy.

Inaczej to wygląda w metodach agilowych, w których tworzenie długu technicznego jest integralną częścią: kiedy tworzymy MVP (ang. „Minimum Viable Product”), to z definicji tworzymy również dług techniczny, bo rozwiązanie z definicji nie jest docelowe! (to jest tak, jakbyśmy w każdym sprincie robili coraz lepszy PoC :-). Dlatego zarządzenie długiem technicznym jest wtedy szczególnie istotne. W dobrze wdrożonych metodach agile’owych stworzony dług techniczny zapisuje się backlogu. Oznacza to, że zobowiązujemy się do jego usunięcia. W ten sposób dług techniczny jest jawnie zarządzany.

Metody radzenia sobie z długiem technicznym

Wg Gartnera istnieją trzy metody radzenia sobie z istnieniem długu technicznego w aplikacjach legacy:
  1. Pierwsza wynika z faktu, że dług techniczny jest względny – zależy od istnienia wymagań niefunkcjonalnych. Więc pierwsza metoda, to zrezygnować z wymagania niefunkcjonalnego. Np. mamy aplikację która działa 8/5 i postawiono przed nią wymaganie dostępności 12/7 (dług się pojawił). Teraz - jeśli z tego wymagania zrezygnujemy i pozostaniemy przy dostępności 8/5 – dług znika. Jeśli jednak wymaganie niefunkcjonalne jest naprawdę ważne i nie możemy z niego zrezygnować, to mamy dwie następne opcje:
  2. Zrefaktoruj aplikację, napraw problem – usuń dług. Jednak z wymaganiami niefunkcjonalnymi jest tak, że nie można w ich przypadku mówić o bug’u, więc poprawa kilku linii kodu nie pomoże. Realizacja wymagań niefunkcjonalnych przeważnie zależy od struktury, od projektu całego rozwiązania lub jego dużych elementów, zależy od jego architektury, od decyzji, co jest przetwarzane wsadowo a co jest przetwarzane real-time, co jest zakodowane a co jest konfigurowalne. Innymi słowy naprawienie problemu z wymaganiem niefunkcjonalnym wymaga przeprojektowania aplikacji lub rozwiązania. Co z kolei wymaga uruchomienia dedykowanego projektu i nie da się naprawić w trybie utrzymaniowym.
  3. Wreszcie, jeśli zrefaktorowanie aplikacji jest nieopłacalne, to ostatnią opcją jest jej wymiana na taką bez długu, na którego usunięciu nam zależy (i co też przeważnie niestety wprowadzi inny rodzaj długu, o czym prędzej czy później się dowiemy :-)

Zakończenie

Po pierwsze: mam nadzieję, że udało mi się uporządkować pojęcia dot. długów w IT:
  • Dług techniczny jest odchyleniem systemu od jego wszelkich wymagań niefunkcjonalnych i jest wynikiem decyzji projektowych lub zmiany tych wymagań.
  • Dług wynikający z zaniechania czynności utrzymaniowych Gartner nazywa długiem IT. Jest on wynikiem konfliktujących decyzji o przeznaczeniu zasobów: na utrzymanie czy na rozwój.
Ww. długi są powodowane czymś innym i inaczej usuwane. Warto je więc odróżniać.

Po drugie: Biznes przeważnie nie chce rozmawiać od długu technicznym uważając ten temat za sprawę IT. Zmiana przedmiotu tej konwersacji z dialogu o „długu” (= sprawa IT) na dialog o „wymaganiach” (= sprawa Biznesu) może tę rozmowę uczynić skuteczniejszą. Zamiast mówić o pieniądzach na spłatę długu można mówić o pieniądzach na realizację zmieniających się wymagań niefunkcjonalnych. Np. "Changability" (składnik "Maintainability" wg ISO 25010) - to jest ważne, czy nieważne wymaganie Biznesu? Jeśli ważne, to wymaga sfinansowania. Jeśli nie ważne, to zapomnijmy o skracaniu Time To Market.

Wreszcie po trzecie: ww. klasyfikacja wymagań niefunkcjonalnych i wynikająca z niej klasyfikacja typów długu technicznego (np. dług niezawodności, dług utrzymywalności itd.) może pozwolić na priorytetyzowanie usuwania tego długu. Jest to o tyle istotne, że dług techniczny jest jak problem - jak zaczniesz szukać, to na pewno go znajdziesz, ale nie zawsze akurat ten najważniejszy. Stąd mechanizm priorytetyzacji może być przydatny.


Materiały źródłowe