Krzysztof Olszewski
Dyrektor Technologii i Architektury Oprogramowania
Krzysztof Olszewski
Dyrektor Technologii i Architektury Oprogramowania
Przez lata kariery zawodowej, pełniąc różne role, podejmując się różnych wyzwań i w efekcie kończąc z różnymi wynikami, uczciwie to ujmując, było raz lepiej, raz gorzej a wyciszając fałszywą skromność może to pierwsze „raz” zdarzało się jednak częściej. A więc przez te lata – i tu postaram się niczego nie wyciszać – wpadałem w różnego rodzaju pułapki prywatne (pominę), mentalne, zawodowe, architektoniczne, organizacyjne i … w zasadzie każde. Wszystkie te sytuacje miały podobny schemat. Zaczyna się od myślenia, że „ja wiem, ja umiem, ja mam rację”, potem jest zazwyczaj chęć przekonania do tego innych, jak się uda to dochodzi do etapu realizacji i tu już zależy, jak „łeb” jest mniej „zakuty” to przychodzi szybka refleksja, można się w miarę bez kosztów wycofać a jak bardziej „zakuty” to … no trudno, wpadamy w pułapkę. Postaram się poniżej opowiedzieć możliwie zwięźle o kilku takich sytuacjach, a może nie dokładnie sytuacjach – bo nie chciałbym być zobligowany do pisania wstawek „zbieżność imion i nazwisk jest całkowicie przypadkowa” – a bardziej schematach, które rozpoznaję jako pułapkę w którą może wpaść każdy. Katalog pułapek rozpoczynam od tego, co mi przychodzi pierwsze do głowy, więc kolejność będzie przypadkowa.
Na wszystko musi być test
TDD (Test Driven Development) jak huragan przetoczył się nad światem IT, o ile pamiętam, wiać zaczęło około 20 lat temu. Nagle dowiedzieliśmy się – mnie oświeciło na wykładzie niejakiego Robert C. Martin’a, zwanego „Uncle Bob”, czyli luźno tłumacząc na nasz „wujka dobra rada” – „twój (specjalnie małą literą, bo poczułem się bardzo malutki) kod jest wart dokładnie ZERO jeżeli nie masz do niego napisanego testu”, uff, co? jak to! Zastanów się, co Ci (dużą literą, bo szacunek dla programistów, nawet tych co piszą kod warty ZERO, od zawsze mam najwyższy) pozostaje po takim podsumowaniu? To co tworzyłeś od lat, nie ma wartości, oczywiście, gdzieś tam w kodzie zawsze znalazły się wstawki pełniące rolę weryfikatora, wiadomo, w naturalny sposób każdy z nas trochę tak robił, ale TDD jest bezlitosne, najpierw test potem implementacja. To co wydarzyło się dalej jest klasycznym przykładem „wpadłem w pułapkę”. Zaczynamy od frustracji – tworzę rzeczy bezwartościowe – dalej, muszę coś z tym zrobić, potem, nie umiem i dalej, to się dokształcę, w konsekwencji, już wiem, już umiem i wtedy, muszę wszystko przerobić, a na pewno to co teraz będę tworzył musi już być „warte więcej niż ZERO”. Jak to wpływa na produktywność – która potrafi w takiej sytuacji zmaleć prawie do ZERA (to jest inne zero niż tamte?) – łatwo się domyślić. Pominę cały środek, przejdę od razu do etapu wychodzenia z pułapki.
Okazuje się, że to co mówił Robert, to co powtórzyli po nim „prelegenci”, „konsultanci” jest słuszne ale tylko w pewnym kontekście – tego już nie mówili. Prawda jest bardziej złożona:
- kod który wymaga posiadania testu a go nie posiada jest wart MNIEJ NIŻ ZERO, jest niebezpieczny, może przynieść straty materialne na małą skalę (kod gry, gracze wybaczcie:) ), ale także na ogromną skalę (kod aplikacji bankowej, podatkowej), albo straty niedające się wycenić, nieakceptowalne w żadnym wypadku (kod oprogramowania samolotu),
- test do kodu który tego testu nie wymaga, jest wart MNIEJ NIŻ ZERO, jest wyłącznie niepotrzebnym kosztem,
- przypisanie wartości „ZERO” dla kodu bez testu jest niebezpiecznym i nieprawdziwym uproszczeniem (pozdrowienia dla wujka), wartość taką ma tylko „brak kodu”, a każdy istniejący kod ma wartość dodatnią lub ujemną, i to nie zależy wyłącznie od faktu posiadania testu czy nie,
- nie na wszystko opłaca się mieć test, zawsze, zawsze należy tworzyć testy tam gdzie jest to w danym kontekście opłacalne i co z tego dalej wynika, jest uzasadnione,
- aby „mieć test” nie wystarczy go napisać, trzeba pisać kod tak aby „móc mieć test”, takie „pisanie” tworzy dodatkowy, znaczący koszt (trzeba to uwzględniać w kalkulacjach) ale także w pewnych sytuacjach przynosi znaczący zysk (czasem większy niż korzyści z posiadania testu),
Gdyby ktoś miał wątpliwości, zastanówcie się nad takim przypadkiem. Startup, który wie, że realizuje pomysł, który za ok 6 miesięcy nie będzie już nowy ani odkrywczy, mają mało czasu, muszą mieć szybko prototyp. Wiedzą, że jak to chwyci, to inwestor który ich przejmie sypnie kasą i tak wszystko będzie zakodowane od nowa. Podejmują decyzję „napiszemy to w PHP”, bo w tym są doświadczeni, na szybko, z minimalną ilością testów, bez wielkiej architektury. Ma działać na prezentacjach i pokazywać siłę pomysłu. Czujecie, temat? Sądzę, że tak.
Sens ma tylko pisanie wysokiej jakości kodu
Wzorce Projektowe, czy bardziej Reguły Projektowe a także wynalazki w rodzaju SOLID czy książki jak „Czysta architektura”, to wszystko jest nasz ogromny IT‘inżynieryjny dorobek z którego jesteśmy dumni. Prawie każdy – ja także – wpada w pułapkę napakowania sobie do głowy tego wszystkiego i potem siadając do kompa, zaczynamy pisać kod. Tak, no na pewno to się uda … mijają godziny i nic. Narasta statystyka usunięć fragmentów kodu, pisania ich i usuwania bo nie są „good enough” i tak w kółko. Narasta frustracja, maleje produktywność i zadowolenie z tego co robimy, w konsekwencji, powoli mentalnie się kończymy. Byłem w tej pułapce. Wyzwoliłem się w pewnym sensie sam, chęć tworzenia byłą silniejsza. Zacząłem po prostu pisać, tak jak potrafiłem, trudno, nie idealnie. Pomógł mi pewien wykład na jakiejś konferencji, gdzie usłyszałem historię pewnego miejsca na dużej, słonej pustyni w USA, gdzie corocznie zjeżdżają się ludzie pod hasłem „tworzymy tu to co zawsze chcieliśmy a nie mieliśmy odwagi”. Nie „manie” odwagi – robi się filozoficznie – to jest ten hamulec właśnie, który z różnych przyczyn blokuje nas przed działaniem. Nie dajmy się, czytajmy, rozwijajmy świadomość, to bardzo ważne, ale twórzmy jak umiemy, twórzmy jak najwięcej. Nic złego się nie stanie, są mechanizmy (powinny być), które pomogą nam wzrastać w iteracyjny sposób, mentoring wewnątrz zespołów, przeglądy kodu, programowanie w parach, czy inne podobne i co najważniejsze, informacja zwrotna z tego co tworzysz. Im więcej tworzysz, tym więcej się uczysz. Sens ma pisanie kodu, takiego jak potrafisz a nie tylko tego najwyższej jakości.
Dbanie o wydajność na początku projektu nie ma sensu
W bardzo rzadkich przypadkach założenie takie jest prawdziwe. Przypadek startup’u opisany wyżej może być tu dobry, tak, tworząc prototypy funkcjonalne możemy abstrahować od wydajności. Często jest to jednak nieprawda. Popularyzacja opinii, że tak trzeba robić zawsze jest bardzo szkodliwa. Jak czytam gdzieś w wątkach „użyj JPA a potem na końcu sobie zoptymalizujesz” to mi się przysłowiowy „nóż” w kieszeni otwiera. Aby nie popełnić tego błędu, wystarczy zrozumieć, że każdy projekt/produkt ma zbiór wymagań. Tworząc software realizujemy wymagania z tego zbioru. Aby ten zbiór był pełny powinien zawierać wymagania funkcjonalne („jak dodam produkt do koszyka który już w nim jest, to … ”, itp.) oraz niefunkcjonalne („spodziewamy się 100 zamówień na dobę … ”, „spodziewamy się 10 mln zamówień na dobę … ”, itd.). Zabieranie się do pracy z pominięciem wymagań niefunkcjonalnych … prowadzi do tworzenia czegoś innego niż oczekuje klient. Często się tak dzieje bo przecież uczą nas, że mamy się skalą, wydajnością, optymalizacją nie zajmować. Skala i wydajność potrafią tak mocno wpłynąć na projekt, że wręcz całkowicie go zmienić, nie kupujcie bajek, że admini dołożą rdzeni, zwiększą przepustowość łącza. Po prostu od samego początku zwracajcie uwagę na wymagania dotyczące skali i wydajności. Jak wyraźnie widać, że nie ma sensu się tym zajmować, to dopiero wtedy uznajemy, że jest to do pominięcia. Nie mogę też nie napisać o tym, że pewne architektury nadają się do przyszłego skalowania lepiej a inne gorzej. To szczególnie ważne, kiedy się spotkamy z wymaganiem „nie wiemy ile będzie zamówień, może sto a może milion”, czyli w zasadzie nic nie wiemy o skali i celowe było by ponieść niskie koszty implementacji wstępnej (bo jak biznes nie zaskoczy, będą mniejsze straty) ale zadbać o skalowalność jak się jednak biznes uda (będą mniejsze koszty ew wyskalowania się). W takiej sytuacji dobór odpowiedniej architektury ma sens a wręcz wydaje się być kluczowy, a już na pewno nie jest do pominięcia.
Im więcej spotkań to lepszy przepływ informacji
Złych duch covida krąży wkoło i dotarł także do IT a w sumie do całego biznesu i w postaci zmian w sposobie komunikacji. Odkryliśmy, że można współpracować będąc nie tylko blisko obok siebie, ale także daleko, bardzo daleko. Widoczny efektem tej transformacji jest narastająca ilość spotkań a także ilość osób w nich uczestniczących. Jak się spotykaliśmy „na żywo”, były pewne naturalne hamulce limitujące ilość i rozmiar takich wydarzeń. Dostanie się fizycznie w określone miejsce, osobiste uczestnictwo, konieczność skupienia uwagi bo przecież wszystkich widać itd. Te czynniki powodowały, że postrzegaliśmy spotkania jako wydarzenie kosztowne a naturalna tendencja do redukcji kosztów limitowała ich ilość i rozmiar. Aktualnie „zorganizowanie” spotkania to tylko kilka kliknięć i każdego kto aktualnie nie uczestniczy w innym spotkaniu można „dodzwonić”. Efekty: uczestniczenie pasywne, nie włączanie kamerek, bo będzie widać, że robię równolegle coś innego, uczestniczenie nadmiarowe, dodawanie osób bo dobrze jakby wiedziały albo może coś powiedzą, a w końcu używanie nadmiarowych spotkań, nadmiarowych uczestników do kompensacji braków komunikacyjnych i organizacyjnych. Pamiętajmy, że spotkanie nie jest jedyną formą komunikacji, a duże spotkanie nie jest jedyną formą „dobrej” komunikacji a na pewno jest formą najkosztowniejszą, z kosztem rosnącym mocniej niż liniowo wraz czasem trwania i ilością uczestników. Prosty wzór na koszty spotkania:
koszt = czas trwania * (średnie wynagrodzenie uczestnika + zysk utracony z tego czego nie zrobi bo jest na spotkaniu) * ilość uczestników
działa tylko dla małych, krótkich zebrań. W tym zakresie wzór jest liniowy, ale wraz ze wzrostem ilości uczestników maleje zdolność do przekazywania informacji, gdyż tylko jedna osoba może mówić w jednej chwili, a N osób musi słuchać, komunikacja odbywa się szeregowo, mamy jeden kanał informacji dla N chętnych. W dodatku zmiana mówiącego nie jest procesem łatwym (context switch), ktoś komuś wchodzi w słowo, ktoś nie może się dostać do głosu itd. Szansa na dobranie uczestników tak, że każdy jest w 100% zainteresowany tematem, albo ma dużo wartościowych treści do przekazania, także maleje wraz z ich ilością. Podobnie jest przy wydłużaniu czasu, uczestnicy się męczą, tracą skupienie, ich obecność ma coraz mniejszy sens. W efekcie tych procesów powyższy wzór można uznać za poprawny tylko dla małych 2,3 osobowych spotkań o krótkim czasie trwania do kilkudziesięciu minut. Powyżej tych parametrów koszy wykładniczo rosną. Kiedy zatem spotkanie jest wartościowe a kiedy nie? Wtedy, kiedy nie spotkanie się albo zawężenie grona uczestników lub skrócenie czasu, spowodowało by, że nie osiągnięto by założonego celu.
Z małym ryzykiem pomyłki możemy stwierdzić, że duża ilość zebrań z dużą ilością uczestników jest zazwyczaj oznaką problemów komunikacyjnych w organizacji. Rozmyte kompetencje, brak ustalonej odpowiedzialności, mikro-zarządzanie, brak zaufania do specjalistów, brak ustalonych procedur/automatów raportowania i powiadamiania, to wszystko mogą przyczyny wpadania w w/o pułapkę.
Ekspert zazwyczaj wie najlepiej
Czy ktoś z Was miał sytuację w której dopiero rozmowa z ludźmi z przysłowiowej „produkcji” daje prawdziwe i sensowne informacje, a tak zwana „kadra” coś tam niby wie ale nie do końca? W żadnym wypadku nie umniejszam roli „kadry”, a jednak stawiam takie pytanie. A czy ktoś z Was miał sytuację w której ekspert z danej dziedziny okazał się być ekspertem, co prawda, ale wyłącznie od sytuacji z którymi się spotkał w swojej praktyce a nie z całej dziedziny z której się tym ekspertem mianował? Nie żebym umniejszał rolę „ekspertów”, ale jednak stawiam takie pytanie. Mnie spotkały obie sytuacje i to z obu stron. Tak, musiałem schodzić „na produkcję” bo „kadra” nie wiedziała a także spotkałem w/o klasy „ekspertów”. Pełniłem także rolę takiej nie do końca świadomej „kadry” a także eksperta z zbyt wąskimi horyzontami. Więc znam sytuację dosyć dokładnie. Nawet teraz będąc autorem tego tekstu wypowiadam opinie, które pewnie są jakimś zawężeniem, uproszczeniem i wynikają wprost z mojej wiedzy ale i niewiedzy, z moich doświadczeń ale i braku doświadczeń.
Gdzie w tym wszystkim pułapka? Zacznę od tego jak w nią nie wpaść. Podchodźmy z rozsądkiem do wszelkiego rodzaju ekspertów, trenerów, „wszystkowiedów”, są oni nam w stanie zaoferować dość dużo, ale nie wszystko, szanujmy to, ale zaufajmy sobie, zaufajmy także tym osobom które działają „na froncie”, tworzą a nie doktoryzują się z tworzenia. To właśnie kreatywna praktyka w danej dziedzinie dostarcza najświeższej, najcenniejszej wiedzy. Dystansowanie się i refleksyjność na początku przynosi zyski, z większej odległości widać lepiej, jednak potem, z czasem, wiedza się dezaktualizuje, wspomnienia dawnych doświadczeń rozmijają się ze zmiennymi wymogami teraźniejszości. Zbytnie zaufanie ekspertom (pozdrowienia dla wujka Boba), tym niepraktykującym w szczególności, jest tą pułapką, przed która przestrzegam.
Im więcej tym lepiej
W mojej opinii, jest to jedna z największych pułapek w które na co dzień wpadamy. Bierze się ona z tego, że notorycznie zapominamy, że „optymalnie” jest dużo lepsze niż „idealnie”. Łatwo uznajemy (choć błędnie), że zjawiska wszelkiego rodzaju mają charakter liniowy, to znaczy, wartość korzyści (y) wraz z zmianą czynnika (x) rośnie cały czas, aż do nieskończoności. Przykłady. Te wszystkie pułapki opisane powyżej, każda z nich jest dobrym przykładem. Wiara, że im więcej testów tym lepiej jest naiwna, bo to nie prawda, najlepiej jest mieć optymalną liczbę testów. I dalej analogicznie, lepiej mieć optymalną jakość kodu, dbać o wydajność tak jak to jest wymagane ani lepiej ani gorzej, spotykać się wtedy kiedy trzeba a nie za mało ani za dużo, nie jest lepiej jak mamy więcej i więcej opinii ekspertów tylko tyle ile potrzebujemy, itd. Krzywa o której wspominałem (x i y) nie jest zatem prostą linią a raczej czymś podobnym do
Krzywa ta reprezentuje rozkład normalny. Abstrahując do znaczenia tego pojęcia, widzimy, że dla małych wartości na osi x, wartości funkcji (y) są małe, po czym rosną wraz ze wzrostem x osiągając maksimum, po czym … dla dalszego wzrostu x, y już nie rożnie, tylko spada.
Co z tego wynika? W zasadzie wszystko. Pomijając powyższe przykłady – Ile najlepiej jest pić wody? Nie jak najmniej (po kilku dniach bez wody umieramy), nie jak najwięcej (ok 5 litrów wody wypite naraz zabija), tylko tyle ile trzeba. Z jaką intensywnością się ruszać, nie wcale (bo dotkną nas choroby wynikające z bezruchu), ale nie za dużo (bo dotkną nas kontuzje, urazy), trzeba dobrać optymalną ilość ruchu do swojego organizmu. Można tak wymieniać w nieskończoność. Podsumowując pułapka idealizmu, niezrozumienia pięknej idei optymalizmu, jest matką wielu innych pułapek.
Na zakończenie, unikania tych i wszystkich innych pułapek, ale nie idealnie tylko tak rozsądnie, optymalnie i bez przesady, życzę wszystkim, którzy dotarli do końca tego tekstu. Pozdrawiam.