Pamiętacie swoje pierwsze błędy w pracy? Przybliżycie nam ich genezę?

Marcin Dryka: Pewnie. Tak się składa, że najwięcej błędów przypomniałem sobie z 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, że przedstawiano nam ich opisy, zakończone krótkim “radźcie sobie”. Nie mieliśmy żadnego podejścia, planu, metodyk, nawet książek z tymi metodykami nie mieliśmy. Domyślacie się, że efekt nie był idealny. Ta firma nadal 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 Konieczny: U mnie większych dramató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ł, że 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: W jednej z pierwszych firm, w których pracowałem, zajmowałem się produkcją oprogramowania do obsługi szkoleń. Siłą rzeczy – bo był to projekt finansowany z UE – musiały się zgadzać i pieniądze, i deadline'y. 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, że 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, że 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śli 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ą oprogramowania 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, że 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 ciekawe – klient był bardzo zadowolony z mojej pracy. Od tej pory przeczytałem MNÓSTWO książek na temat estymacji. 

Marcin: 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 błędó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, że wysyłaliśmy te smsy na koszt firmy, ale o to, że nie mógł korzystać z telefonu – zamiast tego ciągle kasował wiadomości. 

Druga wpadka: 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ł, że jeden wymyślił, że będzie inkrementował zmienną, a drugi, że 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: A ja dwa razy w życiu spowodowałem, że firma przestała działać na jeden dzień. Pierwsza historia jest nieprogramistyczna, ale nadal ś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ę, że 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ę, że na parę godzin spowodowałem brak internetu w całej firmie. Byłem juniorem i wystraszyłem się, że 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 ręcznie 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ę, że w projekcie występuje wiele zależności cyklicznych, które – mówiąc w skrócie – 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, że 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, że podczas rozwiązywania względnie złożonej zależności cyklicznej na Singleton’owych Fasadach nie zauważyłem, że ta jedna konkretna nie była Singletonem, a z automatu wywołałem tryb SingleInstance.

Przez tą jedna linijkę kodu spowodowałem, że 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, że 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, że 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, że 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.

Marcin: Pamiętam robienie projektów w czasach, kiedy praca wyglądała następująco: siadaliśmy z klientem na kwadrans, zbieraliśmy wymagania, a potem przez pół roku tworzyliśmy demo z nadzieją, że wymagania klienta zostały spełnione. Tak było i w tym projekcie dla klienta z Warszawy, naprawdę sporej firmy. W końcu nadszedł wielki dzień – prezentacja demo. Zorganizowaliśmy telekonferencję, opowiadamy o tym, jak to wszystko działa, co ma ten system, jak go obsługiwać. Byliśmy zadowoleni i dumni, nic się nie wysypało, wszystko poszło idealnie. Tymczasem usłyszeliśmy ciszę, po której padło: “Jesteście jutro w pracy? Tak? To ja przyjadę, bo to kompletnie nie ten serwis”. Okazało się, że zrobiliśmy coś, czego on w ogólne nie potrzebował. To nie były czasy, kiedy nadzorowało się projekt w jego trakcie. Klient płacił pieniądze, programiści coś robili i na końcu była prezentacja gotowego już produktu.

Inna historia. Niegdyś typowym rozwiązaniem używanym przy pracy nad projektem było to, żeby ten projekt był na jednym serwerze. To były czasy starych serwerów – nikt w mojej ówczesnej firmie dobrze nie ogarniał praw dostępu do nich, każdy puszczał chmod 777./ A da się w tym zrobić literówkę – gdy zapomni się tej jednej kropki. Wówczas zmienia się działanie tej komendy: z katalogu, w którym się jest, na “root” katalog serwera. I jak się to puści na całym katalogu serwera, to nie da się zalogować. Nawet po przywróceniu wszystkich praw dostępu jest praktycznie niemożliwe – jedyne wyjście to reinstalacja całego serwera. I to właśnie kiedyś mi się przydarzyło. 

Jeszcze jedna historia. Pracowałem niegdyś dla dużej serwerowni, gdzie serwery znajdują się w szafach rackowych, te w rzędach, a te z kolei mają swoje adresy. Nasz serwer był pod adresem GH. Pewnego dnia piszemy, programujemy, zapisujemy i nagle zorientowaliśmy się, że nie ma naszego komputera. Akurat ja miałem najbliżej do drzwi, poszedłem więc zobaczyć, co się z tym serwerem stało. Byłem przekonany, że po prostu coś się zacięło i wystarczy zrobić restart. Wchodzę do serwerowni, otwieram szafę, patrzę – a naszego serwera nie ma. Wchodzę do kanciapy adminów, a tam admin ze śrubokrętem stoi nad serwerem i zaczyna go rozkręcać. Na pytanie, co robi odpowiedział, że dokłada RAM, bo dostał takie zlecenie od klienta. Po chwili wyjaśnień okazało się, że nasz serwer miał adres GH, a klient – HG i nastąpiła pomyłka. 

Jednak największy błąd, jaki mi się przytrafił, dotyczył tego samego serwera, który zaginął. Siedzimy sobie w pracy, przychodzi nasz przełożony i mówi: “Słuchajcie, dostaliśmy zgłoszenie, że jest phishing strony internetowej instytucji finansowej w naszej serwerowni, musimy zlokalizować ten serwer”. Po krótkich poszukiwaniach okazało się, że chodzi o nasz serwer. No i rzeczywiście – była na tym serwerze strona phishingowa, nawet stosunkowo łatwo udało się nam odkryć, jak cyberprzestępcy się tam dostali. Wiecie jak? Były tam ustawione domyślne hasła, których po prostu ktoś się domyślił. Osoba, której zostało założone konto, nawet się nie zalogowała – po raz pierwszy zrobił to dopiero ten, kto się włamał. Podeszliśmy do problemu profesjonalnie – stwierdziliśmy, że skoro ktoś się tam dostał, to nie wiadomo, gdzie siedzi. Sprawdziliśmy dokładnie co się tam działo, ale cały serwer trzeba było reinstalować. W trakcie tej reinstalacji prace zostały wstrzymane i jeden z naszych programistów z nudów rzucił: “Ciekawe, gdzie była ta strona phishingowa, sprawdzę to w internecie”. Wpisał adres w wyszukiwarkę i znalazł jeden wynik – zagraniczne forum, na którym był plik z URL-em. Po otwarciu zbledliśmy – tam było wszystko, co tylko może być tajne w serwerowni, wszystkie hasła do serwerów, do systemu reinstalacji, hasła do naszych prywatnych skrzynek… Jednym klikiem każdy mógł przejąć naszą serwerownię.

Nasza serwerownia miała bardzo wysoki scoring – wszystko było zabezpieczone na milion sposobów na wypadek braku prądu czy internetu. Ale takie parametry, które są tam utrzymywane, dają około 5 minut niedostępności w ciągu roku. Nie wiedziałem, że jest taki guzik w serwerowni, który odłącza internet od wszystkiego. Ten guzik został wciśnięty przez jednego gościa, który mógł o tym zadecydować. Udało się usunąć ten plik z forum. Pech chciał, że to się już zaindeksowało w Google’u, ale to też udało się załatwić. Pozostało tylko to, że serwerownia dalej była wyłączona. Nastąpiło włączanie wszystkiego po kolei, a następnie dochodzenie, co się stało, zlecono zewnętrzny audyt, przeszukiwano którędy ktoś się włamał. Ostatecznie nie zostały podjęte próby odszukania autorów włamania, jest to zbyt złożone, a wskazanie palcem autora nic nie zmienia.

Dziękujemy za rozmowę! Chyba możemy z tych historii wysnuć wniosek, że na błędach można nauczyć się naprawdę wiele. Jak najlepiej podsumować te historie?

Benedykt: Na pewnym etapie „kariery” trzeba po prostu mieć pojęcie, co się robi. A do tego momentu nie panikować ;)

Swoje historie opowiedzieli nam:

  • 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.
  • Marcin Dryka - Senior Fullstack Developer, 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.
  • 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.

Tekst został oryginalnie opublikowany na portalu JustGeekIT.

Bądź na bieżąco z tym co u nas!

Dziękujemy!
Oops! Something went wrong while submitting the form.