Kto z nas nigdy nie zaliczył wpadki w pracy, niech pierwszy rzuci kamieniem – to się po prostu zdarza, zwłaszcza na początku kariery zawodowej i zwłaszcza w branży IT. Trzej doświadczeni developerzy zgodzili się wrócić pamięcią do swoich początków i opowiedzieć nam smakowite historie ich fuck-upów.
Swoje historie opowiedzieli nam:
- Marcin Dryka. CTO w Brainhubie i część domeny Technical Advice, ale przede wszystkim backend developer o szerokim doświadczeniu z wieloma różnymi językami programowania, typami architektury, bazami danych i najlepszymi praktykami. Od 15 lat buduje aplikacje w firmach o różnej wielkości i strukturach.
- Benedykt Dryl. Solution Architect w Brainhubie i pragmatyczny fullstack JS developer z doświadczeniem obejmującym rozmaite technologie i frameworki. Nie ma personalnych preferencji co do warstwy czy frameworku, które wybiera – ważna jest dla niego biegłość w programowaniu. Lubi uczyć i dzielić się wiedzą, nie tylko jako Technical Advisor.
- Mateusz „Koniu” Konieczny. Senior fullstack developer, aktualnie koncentrujący się na JavaScripcie, na co dzień pracujący z Reactem, React Nativem i Node.js. W przeszłości sporo siedział w .Net i C#. W Brainhubie jest częścią domeny Technical Advice, w której doradza zespołom jak rozwiązywać problemy techniczne. Jego materiały szkoleniowe można znaleźć na https://socialshub.net/koniudev.
Pamiętacie swoje pierwsze fuck-upy w pracy? Przybliżycie nam ich genezę?
Marcin Dryka: Pewnie. Tak się składa, iż najwięcej fuck-upów znalazłem właśnie w jednej z pierwszych firm, w której pracowałem. Byliśmy grupą zebraną “z ulicy”, wrzuconą do jednego zespołu. O projektach dowiadywaliśmy się tak, iż przedstawiano nam ich opisy, zakończone krótkim “radźcie sobie”. Nie mieliśmy żadnego podejścia, planu, metodyk, choćby książek z tymi metodykami nie mieliśmy Domyślacie się, iż efekt nie był idealny. Ta firma przez cały czas istnieje, dziś ma się dobrze, funkcjonuje zupełnie inaczej. Po prostu wtedy wszyscy, łącznie z jej założycielami, uczyliśmy się zupełnie nowych dla siebie rzeczy.
Benedykt Dryl: Ja też nie robiłem żadnego planowania developmentu – przychodziłem do pracy, szef rozdawał zadania i gość, który znał się na tym najlepiej, rozbijał te zadania ad hoc, a my składaliśmy z tego jakiś pomysł na cały dzień. Finalnie ten projekt okazał się sromotną porażką. Ta firma również istnieje do teraz.
Mateusz “Koniu” Konieczny: U mnie większych fuck-upów nie było – poza sytuacją, w której klient naciskał na nas, żebyśmy puścili coś na produkcję, mimo pewności wystąpienia błędów. On po prostu mówił, iż na pewno to wszystko da się potem naprawić. Nie zgadniecie – nie dało się. Co tu dużo mówić, to było szkodliwe działanie na własne życzenie.
Zaczyna się nieźle Pamiętacie jeszcze jakieś historie? Jakie konsekwencje miały te wpadki?
Benedykt Dryl: W jednej z pierwszych firm, w których pracowałem, zajmowałem się produkcją systemu do obsługi szkoleń. Siłą rzeczy – bo był to projekt finansowany z UE – musiały się zgadzać i pieniądze, i dedlajny. Jedno tworzone przez nas oprogramowanie miało dużo ukrytych błędów, o których żaden z nas nie wiedział. Te błędy wyszły na jaw po kilku tygodniach, gdy ludzie już z niego korzystali na pełnej. Błędy były wręcz podstawowe – na przykład kalendarz, który odpowiadał za lokowanie różnych zasobów w różne dni i godziny, nie uwzględniał takich oczywistych rzeczy, jak zmiana czasu. Nie wzięliśmy tego pod uwagę z punktu widzenia obliczeń.
Ciekawostka: oprogramowanie zostało wyprodukowane w Qooxdoo – frameworku wymyślonym osiem lat temu, wyglądającym jak desktop, który miał CSS-a w JS-ie. To był framework, który zdecydowanie wyprzedzał swoje czasy, taki Mootools “na sterydach”. Qooxdoo był w stu procentach MVC, miał komponenty à la React, stylowało się go w JavaScripcie. Ten framework istnieje do dzisiaj. Problemem było właśnie to, iż jako niezwykle ciężkie i rozbudowane narzędzie, znacznie wyprzedzał swoje czasy. Poza nami nikt w Polsce nie miał o nim pojęcia. Nigdzie nie mogliśmy znaleźć pomocy, a pamiętajmy, iż były to czasy sprzed GitHuba. Wymienialiśmy tylko maile z jego twórcami i zgłaszaliśmy im issues, a oni na tej podstawie wprowadzali ulepszenia. I na tym Qooxdoo wyprodukowaliśmy całe oprogramowanie – ogólnie było to naprawdę fajne narzędzie, choć kompletna porażka jeżeli chodzi o maintainability. Ale, całkiem szczerze – to właśnie wtedy nauczyłem się JavaScriptu.
Natomiast porażka indywidualna, z której jestem szczególnie “dumny”, to rozminięcie się z estymacją systemu o dwa lata. Pojechałem do klienta do USA, w siedem intensywnych dni ustaliliśmy wszystkie szczegóły współpracy. Nie wziąłem wtedy pod uwagę ogromu rzeczy, wiele uprościłem. Wiecie, mieliśmy jakieś analizy pod estymację, to nie był zupełny freestyle, ale dziś wiem, iż podszedłem wtedy do tematu zbyt optymistycznie. Były tam dwa stare stacki frontendowe, dwa różne niezgodne ze sobą API, które w dodatku były pisane przez Ruby developerów, nie było do tego testów automatycznych… Pełniłem w tym projekcie rolę team leadera, nie uwzględniłem żadnej z tych rzeczy. Osobiście sknociłem to zadanie, i to nie po miesiącu, a po dwóch latach. Tego najbardziej się wstydzę. Co interesujące – klient był bardzo zadowolony z mojej pracy. Od tej pory przeczytałem MNÓSTWO książek na temat estymacji.
Marcin Dryka: Mój kolejny fail też był w jednej z pierwszych firm, w których pracowałem. Jeden z pierwszych dużych klientów – serwerownia – świetna ekipa, super projekt, ogrom fuck-upów. Pisaliśmy na przykład powiadomienia smsowe, które wbudowywaliśmy w system, a były to czasy, kiedy telefon nie był w stanie przyjąć dużej liczby wiadomości. Zapętlił nam się skrypt z wysyłaniem smsów i niestety, stało się to już przy pierwszym użytkowniku, którym był… prezes naszej firmy. Wszystkie te smsy wysyłały mu się non stop, w ciągu tej jednej nocy dostał około dwóch tysięcy wiadomości. Po każdym czyszczeniu skrzynki napływały kolejne wiadomości i zawieszały mu telefon. Co ciekawe, prezes największe pretensje miał nie o to, iż wysyłaliśmy te smsy na koszt firmy, ale o to, iż nie mógł korzystać z telefonu – zamiast tego ciągle kasował wiadomości.
Drugi fuck-up: ta sama firma, pisaliśmy system do automatyzacji, którego jednym z elementów była automatyzacja płatności. W projekcie był typowy spaghetti code – skrypt do płatności, którego wszyscy bali się ruszać, który działał tylko na PayPalu i umożliwiał płatności jedynie po 8 tysięcy euro. Niestety, zmiany były niezbędne, więc dwóch kolegów zabrało się za kod i wprowadzili w nim pętlę. Pech chciał, iż jeden wymyślił, iż będzie inkrementował zmienną, a drugi, iż będzie ją dekrementował, no i w efekcie jedna pętla była w drugiej pętli. Z tego, co pamiętam, to zastosowali też mechanizm obrony przed kolizją zmiennych, żeby nie nazywała się tak samo. Kto wybiera Z jako nazwę zmiennej do iterowania?! Nikt, a tu obaj wpadli na ten pomysł symultanicznie, pewnie poznali go na tych samych laborkach.
Jak się ten skrypt zapętlił, to leciał z tymi płatnościami albo po 8 tysięcy euro, albo po wysokości faktury, i kasował je cały czas, aż dobijał do limitu konta. Tym sposobem dobiliśmy do limitu konta klienta, wynoszącego 250 tysięcy euro. Na szczęście mogliśmy te środki zwrócić.
Mateusz Konieczny: A ja dwa razy w życiu spowodowałem, iż firma przestała działać na jeden dzień. Pierwsza historia jest nieprogramistyczna, ale przez cały czas śmieszna, i można wyciągnąć z niej pewne wnioski.
A było to tak: podczas spotkania w salce bawiłem się kablem ethernetowym. Na stole były dwa gniazda ethernetowe, do których pod koniec spotkania wsadziłem oba końce kabla i spokojnie poszedłem do swoich zajęć. Gdy wróciłem do pokoju, w którym robiliśmy projekt, dowiedziałem się, iż w całej firmie odcięło internet, ale nie powiązałem obu faktów do momentu, gdy dział IT zaczął chodzić po pokojach i pytać, czy ktoś przypadkiem nie zrobił „pętli”. Dopiero wtedy zorientowałem się, iż na parę godzin spowodowałem brak internetu w całej firmie. Byłem juniorem i wystraszyłem się, iż mnie zwolnią. Na szczęście to był known issue i nie byłem pierwszym, który coś takiego zrobił, ale sieć dalej nie była na taki wypadek zabezpieczona.
Druga wpadka była już mocno programistyczna i projektowa. Nie mieliśmy akurat nowych feature’ów do zrobienia, więc zaczęliśmy czyścić backlog z bugów, a potem doszliśmy do improvementów. Był tam jeden wspaniały improvement, który polegał na wprowadzeniu modułów DI (Dependency Injection). Przy okazji polegał on na przepisaniu kodu tak, aby nie używał Singletonowych Fasad (co było potężnym antypatternem) i gdzie trzeba było manualnie przekazywać zależności poprzez konstruktory w tych fasadach. Rozwiązaniem było wykorzystanie kontenera DI, w którym rejestrujemy zależności, a następnie ten kontener sam instancjonował te fasady, odpowiednio inicjalizując zależności. W teorii wyglądało to prosto, ale minusami tego improvementu był rozmiar projektu, całkiem duża liczba klas do przepisania oraz duży team developerski (około 30 devów), który w tym samym czasie wykonywał inne prace, co dawało ryzyko dużej liczby konfliktów podczas mergowania kodu. Na niedomiar złego okazało się, iż w projekcie występuje wiele zależności cyklicznych, które – mówiąc w uproszczeniu – były „hackowane” i które również należało rozwiązać.
Jak dobrze pamiętam, cały task zajął mi około tygodnia-dwóch, uwzględniając Code Review, na którym nie było praktycznie żadnych komentarzy, co nie było dziwne przy tej wielkości zmienionego kodu. Następnie wykonywane były wszystkie rodzaje testów, począwszy od QA, poprzez unit testy, testy integracyjne, testy automatyczne – żadne błędy nie zostały znalezione. Z racji rozmiaru zmian, były wykonane również testy regresji, które również nie wykazały żadnych błędów bezpośrednio związanych z moimi zmianami. Ostatecznie zmiany poszły na deploy, który przeciągnął się do momentu, kiedy mnie już nie było w projekcie. Co mogło pójść nie tak…?
Po jakimś czasie odezwał się do mnie lead dev z tamtego projektu, pytając, czy wprowadzałem zmiany w obszarze liczenia pieniędzy dla pracowników. Wykryty problem polegał na tym, iż dla pierwszego na liście pracownika suma pieniędzy były wyliczana prawidłowo, a dla kolejnych suma wyglądała tak, jakby brała pod uwagę sumy od poprzednich pracowników. Momentalnie wiedziałem, gdzie jest błąd: “usuń wywoływanie SingleInstance na tej fasadzie!”. Błąd był bardzo trywialny i wynikał z tego, iż podczas rozwiązywania względnie złożonej zależności cyklicznej na Singleton’owych Fasadach nie zauważyłem, iż ta jedna konkretna nie była Singletonem, a z automatu wywołałem tryb SingleInstance.
Przez tą jedna linijkę kodu spowodowałem, iż duża liczba danych na bazie stała się niepoprawna i odkręcenie ich było dość karkołomnym zadaniem. Na szczęście codziennie robiliśmy backupy bazy i zasugerowaliśmy, iż tańszym i znacznie pewniejszym rozwiązaniem będzie przywrócenie backupu z poprzedniego dnia i zdeployowanie prostego fixa, co przekładało się na to, iż firma miała dodatkowy dzień wolnego. Z racji rozmiarów firmy, strata spowodowana przez ten błąd mogła iść dalej w miliony.
Pojawia się zatem pytanie: gdzie zawiedliśmy? Przyczyna była bardzo trywialna – wszystkie testy były wykonywane prawidłowo, ale ich minusem było to, iż każdy z nich był wywoływany tylko raz – i mówię tutaj o każdym rodzaju testów. A wystarczyłoby wykonać któryś z nich dwa razy na tym samym stanie i błąd zostałby od razu zauważony.