{"id":21671,"date":"2020-10-29T17:07:54","date_gmt":"2020-10-29T16:07:54","guid":{"rendered":"https:\/\/altkomsoftware.com\/jak-zarzadzac-dlugiem-technologicznym-za-pomoca-analizy-kodu\/"},"modified":"2025-04-01T10:53:03","modified_gmt":"2025-04-01T08:53:03","slug":"jak-zarzadzac-dlugiem-technologicznym-za-pomoca-analizy-kodu","status":"publish","type":"post","link":"https:\/\/stg.altkomsoftware.com\/pl\/blog\/jak-zarzadzac-dlugiem-technologicznym-za-pomoca-analizy-kodu\/","title":{"rendered":"Jak inteligentnie zarz\u0105dza\u0107 d\u0142ugiem technologicznym za pomoc\u0105 behawioralnej analizy kodu?"},"content":{"rendered":"<p>Czym jest d\u0142ug technologiczny? Najlepsze wyja\u015bnienie tego terminu, ukutego przez Warda Cunninghama, dostarczy\u0142 <a href=\"https:\/\/martinfowler.com\/bliki\/TechnicalDebt.html\" target=\"_blank\" rel=\"nofollow noopener\">Marin Fowler<\/a>. Nie potrafimy perfekcyjnie rozwija\u0107 system\u00f3w informatycznych. Ka\u017cda dodana lub zmodyfikowana funkcjonalno\u015b\u0107 wprowadza niewielkie braki w jako\u015bci oprogramowania. Te braki kumuluj\u0105 si\u0119 z czasem i utrudniaj\u0105 nam utrzymanie tempa, w jakim dostarczamy nasze systemy na produkcj\u0119.<\/p>\n<p>We\u017amy pod uwag\u0119 system z d\u0142ugiem technologicznym. Bez d\u0142ugu, wdro\u017cenie danej funkcjonalno\u015bci zaj\u0119\u0142oby nam 4 dni, z powodu zad\u0142u\u017cenia &#8211; 6 dni. Oznacza to, \u017ce te dodatkowe 2 dni to odsetki, kt\u00f3re musimy zap\u0142aci\u0107. Je\u015bli czas potrzebny na napraw\u0119 kodu i usuni\u0119cie d\u0142ugu technologicznego wynosi 3 dni, to ca\u0142a zmiana zajmie nam 7 dni i usuni\u0119cie d\u0142ugu nie jest op\u0142acalne. Je\u015bli jednak wiemy, \u017ce nie jest to jedyna zmiana, jak\u0105 musimy wprowadzi\u0107 w danym elemencie oprogramowania, to sp\u0119dzenie tych dodatkowych 3 dni szybko si\u0119 zwr\u00f3ci. Nale\u017cy te\u017c pami\u0119ta\u0107, \u017ce d\u0142ug technologiczny ma tendencj\u0119 do kumulowania si\u0119. Przysz\u0142e zmiany w komponencie z d\u0142ugiem spowoduj\u0105 tylko jego wzrost, a czas potrzebny na rozw\u00f3j nowych funkcji wzro\u015bnie z 6 do 10 lub 15 dni.<\/p>\n<p>Jakie s\u0105 przyczyny powstawania d\u0142ugu technologicznego? We\u017amy pod uwag\u0119 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Lehman%27s_laws_of_software_evolution\" target=\"_blank\" rel=\"nofollow noopener\">prawa Lehmana<\/a> dotycz\u0105ce ewolucji oprogramowania:<\/p>\n<p><strong>Prawo ci\u0105g\u0142ych zmian<\/strong><\/p>\n<blockquote><p>\u201cSystem musi by\u0107 stale dostosowywany lub staje si\u0119 stopniowo mniej u\u017cyteczny\u201d\u200b<\/p><\/blockquote>\n<p><strong>Prawo o rosn\u0105cej z\u0142o\u017cono\u015bci\u200b<\/strong><\/p>\n<blockquote><p>\u201cW miar\u0119 jak system ewoluuje, jego z\u0142o\u017cono\u015b\u0107 ro\u015bnie, chyba \u017ce prowadzone s\u0105 prace maj\u0105ce na celu jego utrzymanie lub ograniczenie tego trendu.\u201d\u200b<\/p><\/blockquote>\n<p>Z jednej strony, musimy dodawa\u0107 nowe funkcje, modyfikowa\u0107 istniej\u0105ce, aby system pozosta\u0142 aktualny i u\u017cyteczny. Z drugiej strony, nasze prace nad rozwojem systemu zwi\u0119kszaj\u0105 jego z\u0142o\u017cono\u015b\u0107 i je\u015bli nie podejmiemy odpowiednich dzia\u0142a\u0144 naprawczych, z\u0142o\u017cono\u015b\u0107 ta ostatecznie uniemo\u017cliwi ewolucj\u0119 systemu z powodu rosn\u0105cych op\u00f3\u017anie\u0144 i nadmiernych koszt\u00f3w. Jak wszyscy wiemy, rozw\u00f3j oprogramowania jest do\u015bwiadczeniem edukacyjnym. Oznacza to, \u017ce rozpoczynaj\u0105c nowy projekt posiadamy bardzo ma\u0142\u0105 wiedz\u0119 na temat rzeczywistego problemu, kt\u00f3ry staramy si\u0119 rozwi\u0105za\u0107 oraz dziedziny biznesu, w kt\u00f3rej pracujemy. Uczymy si\u0119 po drodze i za\u0142o\u017cenia oraz rozwi\u0105zania architektoniczne, kt\u00f3re przyjeli\u015bmy na pocz\u0105tku projektu, szybko staj\u0105 si\u0119 nieaktualne. Zmieniaj\u0105 si\u0119 wymagania biznesowe, zbli\u017caj\u0105 si\u0119 terminy. Cz\u0119sto po\u015bwi\u0119camy jako\u015b\u0107, aby jak najszybciej wprowadzi\u0107 kod na produkcj\u0119. R\u00f3wnie\u017c dob\u00f3r technologii nierzadko nie jest optymalny i oparty na \u201enowych\u201d trendach, a nie na dopasowaniu danej technologii do prowadzonego przez nas projektu. Wszystkie te i wiele innych czynnik\u00f3w powoduj\u0105 powstanie d\u0142ugu technologicznego<br \/>\n<a class=\"anchor\" name=\"managing\"><\/a><\/p>\n<h2><span lang=\"EN\">Zarz\u0105dzanie d\u0142ugiem technologicznym<\/span><\/h2>\n<p>Jak mo\u017cemy poradzi\u0107 sobie z d\u0142ugiem technologicznym? Moim zdaniem, istniej\u0105 trzy kluczowe elementy, o kt\u00f3re musimy zadba\u0107, je\u015bli nie chcemy aby nasz projekt zbankrutowa\u0142: architektura systemu, zesp\u00f3\u0142 i organizacja procesu. Jak wiemy z <a href=\"https:\/\/en.wikipedia.org\/wiki\/Conway%27s_law\" target=\"_blank\" rel=\"nofollow noopener\">prawa Conway&#8217;a<\/a> (a raczej z jego konsekwencji) &#8211; wszystkie one musz\u0105 dzia\u0142a\u0107 razem, w przeciwnym razie jeste\u015bmy skazani na pora\u017ck\u0119.<\/p>\n<p>Architektura systemu na ka\u017cdym poziomie, od podzia\u0142u na komponenty\/modu\u0142y po wewn\u0119trzn\u0105 struktur\u0119 pakiet\u00f3w i klasy powinny oddziela\u0107 rzeczy, kt\u00f3re maj\u0105 r\u00f3\u017cne powody do zmiany lub zmianiaj\u0105 si\u0119 w r\u00f3\u017cnym tempie. Jak zobaczymy w trakcie lektury tego postu, jest to niezwykle istotne. Mieszanie r\u00f3\u017cnych obowi\u0105zk\u00f3w w tym samym komponencie zwi\u0119ksza prawdopodobie\u0144stwo wyst\u0105pienia wad i dodatkowo wzmacnia trend spadku jako\u015bci.<br \/>\nArchitektura musi by\u0107 r\u00f3wnie\u017c kompatybilna z organizacj\u0105 zespo\u0142\u00f3w, aby zminimalizowa\u0107 straty zwi\u0105zane z dodatkow\u0105 komunikacj\u0105 i koordynacj\u0105 oraz wyeliminowa\u0107 kosztowne \u0142\u0105czenie kodu z wielu ga\u0142\u0119zi rozwojowych.<\/p>\n<p>Nie jeste\u015bmy w stanie stworzy\u0107 &#8222;idealnej&#8221; architektury i organizacji, kt\u00f3ra b\u0119dzie odpowiednia przez ca\u0142y cykl \u017cycia projektu. Oznacza to, \u017ce musimy stale monitorowa\u0107 stan naszej architektury, jako\u015b\u0107 kodu, wzorce komunikacji, organizacj\u0119 zespo\u0142u, aby w\u0142a\u015bciwie reagowa\u0107 i planowa\u0107 usprawnienia w obszarach, w kt\u00f3rych przynosi to najwi\u0119ksze korzy\u015bci.<\/p>\n<p>Wielu mened\u017cer\u00f3w ignoruje potrzeb\u0119 takich dzia\u0142a\u0144. Maj\u0105 tendencj\u0119 do obwiniania zespo\u0142\u00f3w programistycznych za braki w jako\u015bci oraz kwestionowania ich umiej\u0119tno\u015bci i zaanga\u017cowania. Nie jest to oczywi\u015bcie prawd\u0105. Akumulacja d\u0142ugu technologicznego jest naturalnym procesem i wszyscy uczestnicy projektu s\u0105 cz\u0119\u015bciowo za ni\u0105 odpowiedzialni.<\/p>\n<p>W\u0142a\u015bciwy monitoring, ewolucja architektury systemu oraz organizacja zespo\u0142u s\u0105 szczeg\u00f3lnie wa\u017cne w projektach wykorzystuj\u0105cych metodyki agile. W takich projektach staramy si\u0119 doprowadzi\u0107 nasz kod do produkcji tak szybko, jak to mo\u017cliwe. Cz\u0119sto zespo\u0142y zapominaj\u0105, \u017ce nale\u017cy to robi\u0107 bez po\u015bwi\u0119cania jako\u015bci kodu. W miar\u0119 jak przechodzimy do produkcji, nasz kod jest obecnie poddawany konserwacji, a jak pokazuj\u0105 ostatnie badania naukowe, 40 do 80% koszt\u00f3w projektu informatycznego jest wydawane na utrzymanie oprogramowania. Brak dzia\u0142ania w przypadku zwi\u0119kszonej z\u0142o\u017cono\u015bci systemu ma konsekwencje dla wszystkich zainteresowanych stron projektu. Dla kierownictwa oznacza to niedotrzymanie termin\u00f3w, wyd\u0142u\u017cenie czasu realizacji, brak przewidywalno\u015bci procesu rozwoju. Dla u\u017cytkownik\u00f3w oznacza to wiele b\u0142\u0119d\u00f3w, kt\u00f3re sprawiaj\u0105, \u017ce ich codzienna praca jest ci\u0119\u017csza i frustruj\u0105ca, obni\u017caj\u0105c efektywno\u015b\u0107 biznesow\u0105. Dla ca\u0142ej organizacji oznacza to dodatkowe koszty i utrat\u0119 przewagi konkurencyjnej.<\/p>\n<p>Istnieje wiele narz\u0119dzi i technik, kt\u00f3rych obecnie u\u017cywa wi\u0119kszo\u015b\u0107 organizacji do walki z d\u0142ugiem technicznym. Wymie\u0144my te najpopularniejsze i ich braki:<\/p>\n<ul>\n<li><strong>Testy:<\/strong> testy jednostkowe, integracyjne, testy e2e &#8211; wwszystkie one pomagaj\u0105 nam znale\u017a\u0107 b\u0142\u0119dy przed przej\u015bciem na produkcj\u0119. S\u0105 one r\u00f3wnie\u017c bardzo wa\u017cne, poniewa\u017c bez nich rozw\u00f3j systemu na du\u017c\u0105 skal\u0119 jest prawie niemo\u017cliwy. Mo\u017cliwo\u015b\u0107 wykonywania test\u00f3w automatycznych pozwala nam na zmian\u0119 struktury naszych system\u00f3w w celu u\u0142atwienia ich rozwoju i utrzymania oraz zmniejszenia zad\u0142u\u017cenia technologicznego. Bez test\u00f3w jeste\u015bmy skazani na wysokie koszty r\u0119cznych test\u00f3w regresji ca\u0142ego systemu. Ale testy zautomatyzowane s\u0105 kodem. Oznacza to, \u017ce mo\u017ce on akumulowa\u0107 zad\u0142u\u017cenie technologiczne. \u0179le zaprojektowane i utrzymywane testy szybko stan\u0105 si\u0119 bardziej obci\u0105\u017ceniem ni\u017c pomoc\u0105.<\/li>\n<li><strong>Statyczna analiza kodu:<\/strong> : mo\u017ce odkry\u0107 wiele narusze\u0144 najlepszych praktyk i wzorc\u00f3w w naszym kodzie. Mo\u017ce nam ona powiedzie\u0107, ile mamy technicznego d\u0142ugu, ale nie, kt\u00f3ra jego cz\u0119\u015b\u0107 stanowi dla nas rzeczywiste ryzyko. Nie bierze te\u017c ona pod uwag\u0119 kontekstu historycznego i ludzkiego. Nie pozwoli nam ona prze\u015bledzi\u0107 rozwoju zad\u0142u\u017cenia i nie u\u0142atwi znalezienia rzeczywistych przyczyn naszych problem\u00f3w.<\/li>\n<li><strong>Metryki z\u0142o\u017cono\u015bci:<\/strong> wiele z nich zale\u017cy od j\u0119zyka programowania i jest kosztownych w obliczeniach, nie uwzgl\u0119dniaj\u0105 one r\u00f3wnie\u017c kontekstu ani informacji spo\u0142ecznych, kt\u00f3re, jak poka\u017cemy p\u00f3\u017aniej, s\u0105 kluczowe dla zrozumienia, czy dany fragment z\u0142o\u017conego kodu jest dla nas problemem, czy te\u017c nie.<\/li>\n<li><strong>Przegl\u0105dy kodu: <\/strong>: k: kosztowny proces r\u0119czny, kt\u00f3ry anga\u017cuje naszych najlepszych in\u017cynier\u00f3w, ale jest bardzo wa\u017cny, poniewa\u017c promuje dzielenie si\u0119 wiedz\u0105 i wczesne wykrywanie problem\u00f3w. Jak wida\u0107 w praktyce, przegl\u0105dy cz\u0119sto skupiaj\u0105 si\u0119 na danej zmianie, wprowadzonej przez dewelopera, a nie na stanie kodu po zmianie.<\/li>\n<\/ul>\n<p><a class=\"anchor\" name=\"behavioral\"><\/a><\/p>\n<h2>Analiza behawioralna kodu<\/h2>\n<p>Wszystkie te narz\u0119dzia s\u0105 u\u017cyteczne, ale potrzebujemy wi\u0119cej informacji, aby w\u0142a\u015bciwie zarz\u0105dza\u0107 d\u0142ugiem technologicznym. W naszym zespole R&amp;D znale\u017ali\u015bmy bardzo ciekawe nowe podej\u015bcie opracowane przez Adama Tornhilla &#8211; analiz\u0119 behawioraln\u0105 kodu. Swoj\u0105 koncepcj\u0119 opisa\u0142 on w dw\u00f3ch ksi\u0105\u017ckach: oraz <a href=\"https:\/\/www.amazon.com\/Your-Code-Crime-Scene-Bottlenecks-ebook\/dp\/B00ZB5XWBI\/ref=sr_1_2?dchild=1&amp;keywords=tornhill&amp;qid=1600426250&amp;sr=8-2\" target=\"_blank\" rel=\"nofollow noopener\">\u201cSoftware Design X-Rays\u201d<\/a>.. Jego podej\u015bcie poszerza statyczn\u0105 analiz\u0119 o dwa nowe wymiary: czasowy i ludzki. Tak jak lekarz nie mo\u017ce skutecznie zdiagnozowa\u0107 pacjenta tylko na podstawie jego aktualnego stanu i objaw\u00f3w, ale potrzebuje informacji historycznych oraz informacji o jego aktywno\u015bci (historia choroby pacjenta, ryzyko genetyczne, aktywno\u015b\u0107 fizyczna, nawyki \u017cywieniowe itp.), aby zdiagnozowa\u0107 nasz system, potrzebujemy informacji o ewolucji kodu w czasie oraz o sposobach interakcji tw\u00f3rc\u00f3w z kodem. Na szcz\u0119\u015bcie dla nas, przez lata gromadzimy wszystkie wymagane informacje w naszych systemach kontroli \u017ar\u00f3de\u0142, takich jak git czy svn.<br \/>\nPrzeanalizujmy, jakie informacje mo\u017cemy uzyska\u0107 z naszych repozytori\u00f3w za pomoc\u0105 analizy behawioralnej kodu oraz w jaki spos\u00f3b pomaga nam to w zarz\u0105dzaniu d\u0142ugiem technologicznym.<\/p>\n<p><a class=\"anchor\" name=\"hotpspots\"><\/a><\/p>\n<h3>Analiza hotspot\u00f3w<\/h3>\n<p>Pierwszym krokiem, jaki musimy zrobi\u0107, aby w\u0142a\u015bciwie upora\u0107 si\u0119 z d\u0142ugiem technologicznym, jest znalezienie miejsc w kodzie, gdzie usprawnienia dadz\u0105 nam najwi\u0119ksz\u0105 korzy\u015b\u0107.<\/p>\n<p>W du\u017cych projektach, z setkami tysi\u0119cy linii kodu, tworzonych w r\u00f3\u017cnych j\u0119zykach programowania, nie jest to \u0142atwe zadanie przy u\u017cyciu tradycyjnych narz\u0119dzi. Ale analiza hotspot\u00f3w jest w\u0142a\u015bciwym narz\u0119dziem, kt\u00f3re pomo\u017ce nam w tym zadaniu. Hotspot jest elementem naszego kodu (plikiem \/ klas\u0105), kt\u00f3ry jest jednocze\u015bnie z\u0142o\u017cony i cz\u0119sto zmieniany w analizowanym okresie. Jako miar\u0119 z\u0142o\u017cono\u015bci wykorzystamy najprostsz\u0105 z mo\u017cliwych &#8211; ilo\u015b\u0107 linii kodu. Jako miar\u0119 cz\u0119stotliwo\u015bci zmian u\u017cyjemy liczby commit\u00f3w zmieniaj\u0105cych dany plik. Poni\u017cszy rysunek przedstawia jedn\u0105 z mo\u017cliwych wizualizacji hotspot\u00f3w: im wi\u0119kszy okr\u0105g, tym bardziej z\u0142o\u017cony jest dany element, im bardziej czerwony tym wi\u0119ksza cz\u0119stotliwo\u015b\u0107 zmian.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-10789 size-full\" src=\"https:\/\/altkomsoftware.com\/wp-content\/uploads\/2022\/09\/image2.jpg\" alt=\"code hotspot visualisation - circles\" width=\"704\" height=\"527\" \/><\/p>\n<p>Czy taka prosta metoda pomiaru mo\u017ce zadzia\u0142a\u0107? Badania oparte na setkach projekt\u00f3w, r\u00f3\u017cnej wielko\u015bci, opracowanych w r\u00f3\u017cnych technologiach przy u\u017cyciu r\u00f3\u017cnych proces\u00f3w rozwojowych, wszystkie prowadz\u0105 do tego samego rozk\u0142adu cz\u0119stotliwo\u015bci zmian.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-10791 size-full\" src=\"https:\/\/altkomsoftware.com\/wp-content\/uploads\/2022\/09\/image4.jpg\" alt=\"code change frequency\" width=\"785\" height=\"406\" \/><\/p>\n<p>Tylko niewielka cz\u0119\u015b\u0107 kodu jest cz\u0119sto zmieniana. Wi\u0119kszo\u015b\u0107 kodu jest stabilna i rzadko zmieniana. Statystyki dowodz\u0105, \u017ce stabilny, niezmodyfikowany kod jest znacznie mniej podatny na b\u0142\u0119dy ni\u017c kod ostatnio zmieniony. Na przyk\u0142ad prawdopodobie\u0144stwo wyst\u0105pienia usterki w kodzie stabilnym przez rok jest o \u2153 mniejsze ni\u017c w kodzie ostatnio zmienianym. Oznacza to, \u017ce stabilny, ale z\u0142o\u017cony kod nie jest naszym zmartwieniem (chyba, \u017ce wiemy, \u017ce planowane s\u0105 prace, kt\u00f3re b\u0119d\u0105 wymaga\u0142y zmian w takim kodzie). Inne badania potwierdzaj\u0105 korelacj\u0119 mi\u0119dzy cz\u0119stotliwo\u015bci\u0105 zmian, a spadkiem jako\u015bci. Bazuj\u0105c na statystykach, po\u0142\u0105czenie liczby linii kodu i cz\u0119stotliwo\u015bci zmian okaza\u0142o si\u0119 lepsze w przewidywaniu wska\u017anika b\u0142\u0119d\u00f3w ni\u017c jakakolwiek inna kombinacja bardziej z\u0142o\u017conych metryk.<\/p>\n<p>Mog\u0119 tylko potwierdzi\u0107, \u017ce taki sam rozk\u0142ad zaobserwowali\u015bmy w projektach, kt\u00f3re rozwijamy i utrzymujemy tutaj w Altkom Software &amp; Consulting.<\/p>\n<p><strong>Analiza hotspot\u00f3w pomaga nam wyeliminowa\u0107 ponad 90% kodu z naszych dalszych poszukiwa\u0144.<\/strong> Ale musimy kopa\u0107 g\u0142\u0119biej, poniewa\u017c istnienie hotspotu nie musi oznacza\u0107 problemu. Oczywi\u015bcie, skomplikowany komponent o du\u017cej cz\u0119stotliwo\u015bci zmian jest najprawdopodobniej problemem, ale zmiany mog\u0105 by\u0107 wynikiem ju\u017c rozpocz\u0119tych ulepsze\u0144.<\/p>\n<p>Jak ju\u017c powiedziano, w wi\u0119kszo\u015bci przypadk\u00f3w hotspot oznacza, \u017ce mamy problem, kt\u00f3ry przynajmniej wymaga dalszego badania. Du\u017cy, cz\u0119sto zmieniany plik gromadzi prawdopodobnie wiele odpowiedzialno\u015bci i powinien zosta\u0107 podzielony na mniejsze, bardziej sp\u00f3jne komponenty.<\/p>\n<p>Aby zdecydowa\u0107, czy dany hotspot stanowi problem, czy nie, musimy zag\u0142\u0119bi\u0107 si\u0119 w jego szczeg\u00f3\u0142y. Pierwsza heurystyka, kt\u00f3r\u0105 powinni\u015bmy zastosowa\u0107 jest bardzo prosta, musimy sprawdzi\u0107 nazw\u0119 klasy, kt\u00f3ra zosta\u0142a oznaczona jako hotspot. Nie opisowe, og\u00f3lne nazwy, nazwy z przyrostkami daj\u0105 nam wskaz\u00f3wk\u0119, \u017ce powinni\u015bmy dok\u0142adnie przeanalizowa\u0107 przypadek. Nazwy takie jak State, Helper, Service, Manager s\u0105 zazwyczaj znakiem, \u017ce dana klasa ma wi\u0119cej ni\u017c jedn\u0105 odpowiedzialno\u015b\u0107 i prawdopodobnie powinna by\u0107 podzielona na mniejsze, bardziej sp\u00f3jne cz\u0119\u015bci. Nazywanie rzeczy w kodzie jest kluczowe dla jego czytelno\u015bci i \u0142atwo\u015bci utrzymania. Kod jest o wiele cz\u0119\u015bciej czytany ni\u017c modyfikowany, a pami\u0119\u0107 robocza naszych m\u00f3zg\u00f3w jest ograniczona, dlatego o wiele \u0142atwiej jest ludziom nawigowa\u0107 po kodzie, je\u015bli nazwy s\u0105 opisowe i uchwyc\u0105 cel klasy lub funkcji. Badania wykaza\u0142y, \u017ce my, ludzie, zaczynamy budowa\u0107 mentalny model kodu od nazw klas i funkcji. Nazwy nie opisowe lub zbyt og\u00f3lne stanowi\u0105 przeszkod\u0119 na naszej drodze do zrozumienia kodu.<\/p>\n<p>Nast\u0119pnym krokiem jest sprawdzenie trend\u00f3w z\u0142o\u017cono\u015bci naszego hotspotu. Tym razem b\u0119dziemy bardziej szczeg\u00f3\u0142owo oblicza\u0107 z\u0142o\u017cono\u015b\u0107. B\u0119dziemy liczy\u0107 g\u0142\u0119boko\u015b\u0107 wci\u0119\u0107 w kodzie. W ten spos\u00f3b b\u0119dziemy mogli \u0142atwo wykry\u0107 kod o skomplikowanych strukturach, kod zawieraj\u0105cy z\u0142o\u017cone wyra\u017cenia logiczne oraz z\u0142o\u017cone struktury kontrolne. Takie konstrukcje s\u0105 zazwyczaj \u017ar\u00f3d\u0142em wielu b\u0142\u0119d\u00f3w. <strong>Dla przyk\u0142adu, z\u0142o\u017cone wyra\u017cenia logiczne s\u0105 odpowiedzialne za oko\u0142o 20% wszystkich b\u0142\u0119d\u00f3w.<\/strong> Patrz\u0105c na trend z\u0142o\u017cono\u015bci mo\u017cemy si\u0119 upewni\u0107, \u017ce programi\u015bci ju\u017c zacz\u0119li zajmowa\u0107 si\u0119 d\u0142ugiem technicznym i z\u0142o\u017cono\u015b\u0107 zacz\u0119\u0142a si\u0119 zmniejsza\u0107. Je\u015bli z\u0142o\u017cono\u015b\u0107 wci\u0105\u017c ro\u015bnie, zw\u0142aszcza je\u015bli ro\u015bnie szybciej ni\u017c ca\u0142kowita liczba linii, mamy sytuacj\u0119, kt\u00f3ra wymaga naszej interwencji.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-10793 size-full\" src=\"https:\/\/altkomsoftware.com\/wp-content\/uploads\/2022\/09\/image5.jpg\" alt=\"code complexity chart\" width=\"457\" height=\"266\" \/><\/p>\n<p>Musimy zajrze\u0107 do wn\u0119trza danej klasy i znale\u017a\u0107 obszary, kt\u00f3rymi musimy si\u0119 zaj\u0105\u0107. Mo\u017cemy skorzysta\u0107 z analizy hotspot\u00f3w na poziomie funkcji. Dzi\u0119ki niej dowiemy si\u0119, kt\u00f3re funkcje s\u0105 najbardziej z\u0142o\u017cone, a kt\u00f3re najcz\u0119\u015bciej zmieniane.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-10795 size-full\" src=\"https:\/\/altkomsoftware.com\/wp-content\/uploads\/2022\/09\/image1.jpg\" alt=\"x-ray code analysis\" width=\"650\" height=\"262\" \/><\/p>\n<p>Stosujemy podej\u015bcie jak w przypadku hotspot\u00f3w na poziomie plik\u00f3w. Je\u015bli mamy z\u0142o\u017con\u0105 funkcj\u0119, kt\u00f3ra nie by\u0142a zmieniana przez miesi\u0105ce, nie musimy wykonywa\u0107 \u017cadnych dzia\u0142a\u0144. Ale znalezienie funkcji z\u0142o\u017conej, kt\u00f3ra jest cz\u0119sto modyfikowana, jest znakiem, \u017ce wymaga ona refaktoringu. By\u0107 mo\u017ce funkcja jest zbyt du\u017ca i mo\u017ce by\u0107 zmodularyzowana. Mo\u017ce zawiera pewne z\u0142o\u017cone wyra\u017cenia, kt\u00f3re mog\u0105 by\u0107 przekszta\u0142cone w osobne funkcje. Analiza Hotspotu mo\u017ce r\u00f3wnie\u017c pokaza\u0107 nam, kt\u00f3re funkcje maj\u0105 tendencj\u0119 do zmiany jednocze\u015bnie. Mo\u017ce to by\u0107 znak kopiowania i wklejania lub brakuj\u0105ca abstrakcja.<\/p>\n<p>Po sprawdzeniu podejrzanych funkcji, mo\u017cemy zaplanowa\u0107 nasze ulepszenia.<\/p>\n<p>Analiza Hotspotu pomaga nam podejmowa\u0107 \u015bwiadome decyzje, bazuj\u0105c na danych i badaniach naukowych oraz inteligentnie zarz\u0105dza\u0107 d\u0142ugiem technologicznym.<\/p>\n<p>Jak wida\u0107, mo\u017cemy w pewnym sensie przeskalowa\u0107 analiz\u0119 hotspot\u00f3w &#8211; mo\u017cemy zastosowa\u0107 j\u0105 na poziomie pliku\/klasy, mo\u017cemy wej\u015b\u0107 g\u0142\u0119biej i przeanalizowa\u0107 funkcje wewn\u0105trz danego pliku\/klasy. Ale mo\u017cemy te\u017c zastosowa\u0107 j\u0105 na poziomie architektonicznym. Potrafimy wyszukiwa\u0107 hotspoty w\u015br\u00f3d komponent\u00f3w architektury systemu. B\u0119dzie to niezwykle przydatne w przypadku budowania system\u00f3w opartych na mikrous\u0142ugach lub wszelkiego rodzaju system\u00f3w modu\u0142owych. Dzi\u0119ki analizie hotspot\u00f3w, mo\u017cemy znale\u017a\u0107 modu\u0142y (us\u0142ugi), kt\u00f3re s\u0105 zbyt du\u017ce i cz\u0119sto si\u0119 zmieniaj\u0105. Ponownie, w wi\u0119kszo\u015bci przypadk\u00f3w przyczyn\u0105 takiej sytuacji jest fakt, \u017ce kod w danym module bierze na siebie zbyt wiele obowi\u0105zk\u00f3w.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-10797 size-full\" src=\"https:\/\/altkomsoftware.com\/wp-content\/uploads\/2022\/09\/image6.jpg\" alt=\"module health code analysis \" width=\"684\" height=\"557\" \/><\/p>\n<p>Powinni\u015bmy analizowa\u0107 takie modu\u0142y i stara\u0107 si\u0119 dzieli\u0107 je na mniejsze i bardziej sp\u00f3jne elementy, tak jak na poziomie klasy. Jak wspomnieli\u015bmy na pocz\u0105tku tego postu, niezwykle wa\u017cne dla zdrowia systemu jest, aby oddzieli\u0107 od siebie kod, kt\u00f3ry mo\u017ce si\u0119 zmienia\u0107 z r\u00f3\u017cnych powod\u00f3w i z r\u00f3\u017cn\u0105 cz\u0119stotliwo\u015bci\u0105. Jak widzieli\u015bmy na wykresach rozk\u0142adu cz\u0119stotliwo\u015bci zmian &#8211; oddzielenie stabilnego kodu od zmiennego kodu zmniejsza obszar, w kt\u00f3rym nagromadzenie d\u0142ugu technicznego jest najbardziej niebezpieczne.<br \/>\n<a class=\"anchor\" name=\"temporal\"><\/a><\/p>\n<h3>Sprz\u0119\u017cenie czasowe (Temporal coupling)<\/h3>\n<p>Inn\u0105 wa\u017cn\u0105 koncepcj\u0105, kt\u00f3ra mo\u017ce by\u0107 analizowana przy u\u017cyciu naszych nowych narz\u0119dzi, jest sprz\u0119\u017cenie czasowe (alias. Change coupling). Sprz\u0119\u017cenie czasowe oznacza, \u017ce dwa elementy X i Y zmieniaj\u0105 si\u0119 razem. Mo\u017cemy analizowa\u0107 jak cz\u0119sto si\u0119 to zdarza. Dzi\u0119ki danym o sprz\u0119\u017ceniu czasowym mo\u017cemy poszukiwa\u0107 nieoczekiwanych zale\u017cno\u015bci pomi\u0119dzy elementami systemu oraz zale\u017cno\u015bci, kt\u00f3re staj\u0105 si\u0119 zbyt silne.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-10799 size-full\" src=\"https:\/\/altkomsoftware.com\/wp-content\/uploads\/2022\/09\/image7.jpg\" alt=\"temporal coupling - dependencies\" width=\"884\" height=\"483\" \/><\/p>\n<p>W niekt\u00f3rych przypadkach sprz\u0119\u017cenie czasowe jest naturalne i nie ma w nim nic z\u0142ego. Na przyk\u0142ad, gdy dodajemy now\u0105 funkcj\u0119 do komponentu, zwykle dodajemy test do jego modu\u0142u testowego. Jest to przyk\u0142ad sprz\u0119\u017cenia czasowego, kt\u00f3re jest po\u017c\u0105dane. Je\u015bli jednak zaobserwujemy, \u017ce wiele zmian w szczeg\u00f3\u0142ach implementacji danego komponentu powoduje r\u00f3wnie\u017c zmiany w jej kodzie testowym, oznacza to, \u017ce kod testowy prawdopodobnie zale\u017cy od szczeg\u00f3\u0142\u00f3w implementacji, co jest bardzo z\u0142e.<\/p>\n<p>Je\u015bli dwa elementy, kt\u00f3re powinny by\u0107 niezale\u017cne od siebie, wykazuj\u0105 oznaki wysokiego sprz\u0119\u017cenia czasowego, musimy zbada\u0107 ten przypadek: znale\u017a\u0107, kt\u00f3re klasy i funkcje maj\u0105 tendencj\u0119 do zmian razem. Mo\u017ce brakuje nam abstrakcji lub nale\u017cy wyodr\u0119bni\u0107 ca\u0142y nowy, oddzielny komponent. Mo\u017ce najwy\u017cszy czas zrewidowa\u0107 nasze za\u0142o\u017cenia architektoniczne i wyznaczy\u0107 nowe architektoniczne granice pomi\u0119dzy komponentami, aby lepiej wspiera\u0107 dalsz\u0105 ewolucj\u0119 systemu.<\/p>\n<p>Sprz\u0119\u017cenie czasowe jest r\u00f3wnie\u017c w du\u017cym stopniu zwi\u0105zane z prawdopodobie\u0144stwem wyst\u0105pienia b\u0142\u0119d\u00f3w. Wysoki poziom sprz\u0119\u017cenia czasowego zwykle skutkuje wysokim wsp\u00f3\u0142czynnikiem b\u0142\u0119d\u00f3w. Badania pokazuj\u0105, \u017ce sprz\u0119\u017cenie czasowe jest lepsze do przewidywania defekt\u00f3w ni\u017c jakakolwiek metryka z\u0142o\u017cono\u015bci.<\/p>\n<p>Wiedza na temat sprz\u0119\u017cenia czasowego pomaga nam w planowaniu refaktoringu, a tak\u017ce w planowaniu test\u00f3w. Wiedz\u0105c, \u017ce zmiany w funkcjonalno\u015bci X powoduj\u0105 zmiany w kodzie zwi\u0105zane z Y, mo\u017cemy zaplanowa\u0107 test regresji obu modu\u0142\u00f3w w przypadku, gdy kt\u00f3rykolwiek z nich ulegnie zmianie.<\/p>\n<p>Najlepszym miejscem do rozpocz\u0119cia analizy sprz\u0119\u017cenia czasowego s\u0105 modu\u0142y o najwy\u017cszej cz\u0119stotliwo\u015bci zmian.<\/p>\n<p>Analiza sprz\u0119\u017cenia czasowego, tak jak analiza hotspot\u00f3w, mo\u017ce by\u0107 wykorzystana do przej\u015bcia z poziomu modu\u0142\u00f3w na poziom klasy, a nast\u0119pnie na poziom funkcji.<\/p>\n<p>Badanie sprz\u0119\u017cenia czasowego rozszerza nasz\u0105 analiz\u0119 z poszczeg\u00f3lnych komponent\u00f3w na relacje mi\u0119dzy nimi i pomaga nam znale\u017a\u0107 kod, kt\u00f3ry pozostawiony bez nadzoru mo\u017ce prowadzi\u0107 do nieoczekiwanych i trudnych do zdiagnozowania b\u0142\u0119d\u00f3w. Wszyscy znamy te sytuacje, gdy kto\u015b dodaje funkcjonalno\u015b\u0107 do modu\u0142u A, modu\u0142 A jest testowany i dzia\u0142a doskonale, wchodzimy do produkcji, aby dowiedzie\u0107 si\u0119, \u017ce modu\u0142y B i C niespodziewanie przesta\u0142y dzia\u0142a\u0107.<\/p>\n<p><a class=\"anchor\" name=\"other\"><\/a><\/p>\n<h3>Hotspoty, Temporal Coupling, Code Ownership i wzorce komunikacji<\/h3>\n<p>Wszyscy pami\u0119tamy prawo Brooksa z &#8222;The Mythical Man-Month&#8221;: &#8222;dodawanie ludzi do op\u00f3\u017anionego projektu op\u00f3\u017ania go jeszcze bardziej&#8221;. Dzieje si\u0119 tak ze wzgl\u0119du na dodatkowy koszt komunikacji i koordynacji, kt\u00f3ry jest wy\u017cszy ni\u017c warto\u015b\u0107 pracy tworzonej przez nowych cz\u0142onk\u00f3w zespo\u0142u. Kolejn\u0105 rzecz\u0105 jest to, \u017ce architektura systemu ogranicza liczb\u0119 programist\u00f3w, kt\u00f3rzy mog\u0105 efektywnie pracowa\u0107 nad projektem. Zbyt wielu programist\u00f3w lub programist\u00f3w niepoprawnie przypisanych do komponent\u00f3w architektonicznych spowoduje jednoczesn\u0105 prac\u0119 nad tym samym kawa\u0142kiem kodu, wykonywan\u0105 przez r\u00f3\u017cnych programist\u00f3w i zespo\u0142y. Istnieje korelacja pomi\u0119dzy liczb\u0105 autor\u00f3w, kt\u00f3rzy jednocze\u015bnie modyfikuj\u0105 ten sam komponent, a liczb\u0105 wad w danym komponencie. Badania nad kodem \u017ar\u00f3d\u0142owym Linuksa pokazuj\u0105, \u017ce modu\u0142y o liczbie autor\u00f3w wi\u0119kszej ni\u017c 9 maj\u0105 16 razy wi\u0119cej defekt\u00f3w ni\u017c pozosta\u0142a cz\u0119\u015b\u0107 bazy kodu.<\/p>\n<p>Mo\u017cemy wykorzysta\u0107 analiz\u0119 behawioraln\u0105 kodu do wykrycia takich problem\u00f3w. Widzieli\u015bmy ju\u017c analiz\u0119 hotspot\u00f3w. W projektach z nieoptymaln\u0105 organizacj\u0105 zespo\u0142\u00f3w, istnieje silny zwi\u0105zek pomi\u0119dzy hotspotami a modu\u0142ami modyfikowanymi przez wielu programist\u00f3w. Wykorzystuj\u0105c dane z git czy svn mo\u017cemy sprawdzi\u0107 ilu programist\u00f3w modyfikowa\u0142o dany modu\u0142 w analizowanym okresie. Je\u015bli jest wielu programist\u00f3w modyfikuj\u0105cych kod hotspota, istnieje szansa, \u017ce ma on zbyt wiele obowi\u0105zk\u00f3w, co w zwi\u0105zku z cz\u0119stymi modyfikacjami dokonywanymi przez r\u00f3\u017cne osoby prawdopodobnie spowoduje, \u017ce kod b\u0119dzie mia\u0142 gorsz\u0105 jako\u015b\u0107, niesp\u00f3jno\u015bci, wady i wiele czasu zostaje straconego na kosztowne merge. Po raz kolejny widzimy znaczenie zasady pojedynczej odpowiedzialno\u015bci (<a href=\"https:\/\/blog.cleancoder.com\/uncle-bob\/2014\/05\/08\/SingleReponsibilityPrinciple.html\" target=\"_blank\" rel=\"nofollow noopener\">single responsibility principle<\/a>.).<\/p>\n<p>Adam Tornhill w swoich ksi\u0105\u017ckach przedstawia trzy typowe wzorce w\u0142asno\u015bci kodu i opisuje ich konsekwencje.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-10801 size-full\" src=\"https:\/\/altkomsoftware.com\/wp-content\/uploads\/2022\/09\/image3-3.png\" alt=\"three typical patterns of code ownership\" width=\"426\" height=\"165\" \/><\/p>\n<p>W pierwszym przypadku ca\u0142o\u015b\u0107 lub wi\u0119kszo\u015b\u0107 kodu w danym komponencie zosta\u0142a opracowana przez jedn\u0105 osob\u0119. W tym przypadku nie mamy \u017cadnych dodatkowych koszt\u00f3w zwi\u0105zanych z komunikacj\u0105 i koordynacj\u0105. Kod komponentu jest sp\u00f3jny, a jego jako\u015b\u0107 jest w du\u017cej mierze zwi\u0105zana jest z umiej\u0119tno\u015bciami technicznymi autora.<\/p>\n<p>W drugim przypadku mamy wielu programist\u00f3w pracuj\u0105cych nad komponentem, ale jeden z nich wykona\u0142 wi\u0119kszo\u015b\u0107 pracy. W tym przypadku, procent kodu stworzonego przez g\u0142\u00f3wnego tw\u00f3rc\u0119 jest dobrym predyktorem jako\u015bci. Badania pokazuj\u0105, \u017ce im wi\u0119kszy procent kodu stworzonego przez g\u0142\u00f3wnego autora, tym mniejsza liczba b\u0142\u0119d\u00f3w. Istnieje r\u00f3wnie\u017c jeszcze silniejsza zale\u017cno\u015b\u0107 mi\u0119dzy b\u0142\u0119dami a liczb\u0105 innych autor\u00f3w. Liczba b\u0142\u0119d\u00f3w zwi\u0119ksza si\u0119 wraz z liczb\u0105 dodatkowych autor\u00f3w.<\/p>\n<p>Ostatnim przypadkiem jest du\u017ca fragmentacja &#8211; wielu autor\u00f3w z ma\u0142\u0105 ilo\u015bci\u0105 zmienionego kodu. Kod ten b\u0119dzie wymaga\u0142 starannej analizy i test\u00f3w, poniewa\u017c b\u0119dzie \u017ar\u00f3d\u0142em wielu b\u0142\u0119d\u00f3w.<\/p>\n<p>Mo\u017cemy r\u00f3wnie\u017c \u0142\u0105czy\u0107 informacje o autorach i sprz\u0119\u017ceniu czasowym. Po pierwsze, musimy znale\u017a\u0107 g\u0142\u00f3wnego autora ka\u017cdego modu\u0142u. Mo\u017cemy to zrobi\u0107 poprzez znalezienie dewelopera, kt\u00f3ry doda\u0142 wi\u0119kszo\u015b\u0107 kodu do modu\u0142u. Cz\u0119sto lepsz\u0105 heurystyk\u0105 jest szukanie ilo\u015bci usuni\u0119tych linii. W ten spos\u00f3b prawdopodobnie znajdziemy programist\u0119, kt\u00f3ry opiekuje si\u0119 danym komponentem i redukuje z\u0142o\u017cono\u015b\u0107 za pomoc\u0105 technik refaktoringu. Mo\u017cemy po\u0142\u0105czy\u0107 list\u0119 g\u0142\u00f3wnych autor\u00f3w dla ka\u017cdego modu\u0142u lub komponentu z wynikami analizy sprz\u0119\u017cenia czasowego. Je\u015bli modu\u0142y czasowo sprz\u0119\u017cone maj\u0105 tego samego g\u0142\u00f3wnego autora lub autora pracuj\u0105cego blisko siebie (np. s\u0105 w tym samym ma\u0142ym zespole), to nie mamy \u017cadnych problem\u00f3w. Je\u015bli nie s\u0105, to prawdopodobnie znale\u017ali\u015bmy kosztowny wzorzec komunikacji i koordynacji, gdy programi\u015bci z r\u00f3\u017cnych zespo\u0142\u00f3w musz\u0105 pracowa\u0107 nad \u015bci\u015ble sprz\u0119\u017conym kodem.<\/p>\n<p><a class=\"anchor\" name=\"summary\"><\/a><\/p>\n<h2>Podsumowanie<\/h2>\n<p>Jak wspomnia\u0142em na pocz\u0105tku tego postu, d\u0142ug technologiczny nie jest problemem tylko deweloper\u00f3w. Wp\u0142ywa on na efektywno\u015b\u0107 ca\u0142ej organizacji. Je\u015bli nie walczymy z nim to rezultatem tego s\u0105: zwi\u0119kszone koszty, brak przewidywalno\u015bci naszego procesu dostarczania, systemy o wysokim wska\u017aniku b\u0142\u0119d\u00f3w, kt\u00f3re nie pomog\u0105 Ci w osi\u0105gni\u0119ciu Twoich cel\u00f3w biznesowych.<\/p>\n<p>D\u0142ug technologiczny powinien by\u0107 stale monitorowany i obs\u0142ugiwany na bie\u017c\u0105co. Powinni\u015bmy nim zarz\u0105dza\u0107 w oparciu o rzeczywiste dane i opinie ekspert\u00f3w.<\/p>\n<p>D\u0142ug technologiczny jest w kodzie naszych system\u00f3w, ale aby si\u0119 nim zaj\u0105\u0107, powinni\u015bmy spojrze\u0107 poza sam kod. Kluczowe znaczenie ma architektura systemu i organizacja zespo\u0142u. Powinni\u015bmy monitorowa\u0107 i dostosowywa\u0107 j\u0105 do potrzeb projektu. Architektura i organizacja musz\u0105 ewoluowa\u0107, aby zapewni\u0107 optymalne wsparcie dla ewolucji systemu.<\/p>\n<p>Tradycyjne narz\u0119dzia bardzo nam pomagaj\u0105 i przynosz\u0105 cenne informacje na tematy techniczne, ale nie pomagaj\u0105 nam znale\u017a\u0107 miejsc, gdzie inwestycje szybko si\u0119 zwr\u00f3c\u0105. Nie pomog\u0105 nam te\u017c w znalezieniu problem\u00f3w organizacyjnych. Powinni\u015bmy doda\u0107 behawioraln\u0105 analiz\u0119 kodu do listy naszych codziennych praktyk, aby inteligentnie zarz\u0105dza\u0107 d\u0142ugiem technologicznym.<\/p>\n<p>Ten post przedstawia niekt\u00f3re z technik analizy behawioralnej kodu opisanych przez Adama Tornhilla: hotspoty, sprz\u0119\u017cenie czasowe, w\u0142asno\u015b\u0107 kodu. Jest ich wi\u0119cej: mo\u017cemy u\u017cywa\u0107 map wiedzy do monitorowania wiedzy o naszym systemie, zwr\u00f3ci\u0107 uwag\u0119 na code churn aby przeanalizowa\u0107 sposoby, w jaki programi\u015bci wchodz\u0105 w interakcj\u0119 z kodem, i wiele innych. Istniej\u0105 narz\u0119dzia, kt\u00f3re automatyzuj\u0105 ten proces. Jednym z nich jest <a href=\"https:\/\/codescene.io\/\" target=\"_blank\" rel=\"nofollow noopener\">Code Scene<\/a>, produkt komercyjny stworzony przez Adama na podstawie jego ksi\u0105\u017cek. Korzystamy z niego na co dzie\u0144 w Altkom Software and Consulting, jest on zintegrowany z naszymi \u015brodowiskami CI\/CD i pomaga na wiele sposob\u00f3w tworzy\u0107 lepsze systemy. Je\u015bli chcesz spr\u00f3bowa\u0107 tych nowych technik, gor\u0105co polecam zacz\u0105\u0107 od ksi\u0105\u017cek Adama i pobawi\u0107 si\u0119 <a href=\"https:\/\/github.com\/adamtornhill\/code-maat\" target=\"_blank\" rel=\"nofollow noopener\">Code Maat<\/a>, darmowym narz\u0119dziem open-source, kt\u00f3re towarzyszy tym ksi\u0105\u017ckom.<\/p>\n<p>Autor: <strong>Wojciech Suwa\u0142a, Head Architect<\/strong><br \/>\nAltkom Software &amp; Consulting<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Czym jest d\u0142ug technologiczny? Najlepsze wyja\u015bnienie tego terminu, ukutego przez Warda Cunninghama, dostarczy\u0142 Marin Fowler. Nie potrafimy perfekcyjnie rozwija\u0107 system\u00f3w informatycznych. Ka\u017cda dodana lub zmodyfikowana funkcjonalno\u015b\u0107 wprowadza niewielkie braki w jako\u015bci oprogramowania. Te braki kumuluj\u0105 si\u0119 z czasem i utrudniaj\u0105 nam utrzymanie tempa, w jakim dostarczamy nasze systemy na produkcj\u0119. We\u017amy pod uwag\u0119 system z [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":20720,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"topic":[],"blog-author":[],"class_list":["post-21671","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-bez-kategorii"],"acf":[],"_links":{"self":[{"href":"https:\/\/stg.altkomsoftware.com\/pl\/wp-json\/wp\/v2\/posts\/21671","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/stg.altkomsoftware.com\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/stg.altkomsoftware.com\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/stg.altkomsoftware.com\/pl\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/stg.altkomsoftware.com\/pl\/wp-json\/wp\/v2\/comments?post=21671"}],"version-history":[{"count":2,"href":"https:\/\/stg.altkomsoftware.com\/pl\/wp-json\/wp\/v2\/posts\/21671\/revisions"}],"predecessor-version":[{"id":39718,"href":"https:\/\/stg.altkomsoftware.com\/pl\/wp-json\/wp\/v2\/posts\/21671\/revisions\/39718"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/stg.altkomsoftware.com\/pl\/wp-json\/wp\/v2\/media\/20720"}],"wp:attachment":[{"href":"https:\/\/stg.altkomsoftware.com\/pl\/wp-json\/wp\/v2\/media?parent=21671"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/stg.altkomsoftware.com\/pl\/wp-json\/wp\/v2\/categories?post=21671"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/stg.altkomsoftware.com\/pl\/wp-json\/wp\/v2\/tags?post=21671"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/stg.altkomsoftware.com\/pl\/wp-json\/wp\/v2\/topic?post=21671"},{"taxonomy":"blog-author","embeddable":true,"href":"https:\/\/stg.altkomsoftware.com\/pl\/wp-json\/wp\/v2\/blog-author?post=21671"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}