Testowałem na produkcji i się tego nie wstydzę!
Cześć!
Testy na produkcji zwykle pojawiają się w niezbyt chlubnych, ale za to śmieszkowatych historiach. A to dostaniemy powiadomienie z MBanku, a to dzwoni do nas klient i pyta się co to jest za typ słownika “twoja stara ubiera się u Prady” (prawdziwa historia z mojego projektu). Karuzela śmiechu się nie zatrzymuje. Jest to nawet po części dobre, że tolerancja dla tego typu bylejakości staje się w naszej branży czymś raczej wstydliwym. Chociaż jak wiemy - ciągle się to zdarza.
Doświadczenie i praktyka i ilość przerobionych problemów uczą nas, że życie nie jest czarno białe. Zaczynamy się coraz bardziej lubować w odcieniach szarości. Często okazuje się, że coś co za dobry wzorzec potem już byśmy kijem nie tknęli i odwrotnie. Tak jest np. z zasadami SOLID. Jakoś tak jest, że większość z nas przeżywa niewinną miłość do nich w okresie młodości programistycznej. Potem perspektywa zmienia się, że “no fajnie, fajnie, ALE…“.
W skrócie, żeby wiedzieć kiedy czegoś nie używać lub używać musimy to dobrze poznać.
Cały ruch związany z CI, CD, TDD dąży do tego, żeby mieć jak nawiększą pewność, że to co wdrażamy kolokwialnie “nie jebnie”. Jestem jak najbardziej zwolennikiem tych podejść, ale patrząc z boku obserwuję, że często (szczególnie testy) są stosowane dosyć dogmatycznie. Co gorsza - one są stosowane na zasadzie “Tata, a Marcin powiedział”. Jest to wiedza bardzo często anegdotyczna.
Przykład Code Coverage. Czy posiadanie 100% pokrycia kodu testami świadczy o tym, że wszystkie scenariusze mamy pokryte? Skądże - oznacza to tyle, że mechanicznie pokryliśmy wszystkie ify, rzucone wyjątki itd. Ta metryka weryfikuje nam to czy testy sprawdzają to co nasz kod robi. Nie dają nam pewności czy robi to co powinien. Jeżeli autor kodu i testów nie wpadli na jakiś scenariusz albo szli tym samym tropem myślowym to mogli coś ominąć. Nie każdy scenariusz kończy się tak tragicznie jak samosterujący samochód Ubera potrącający śmiertelnie osobę (https://www.nbcnews.com/tech/tech-news/self-driving-uber-car-hit-killed-woman-did-not-recognize-n1079281). Ot programiści Ubera nie wpadli na to, że ktoś mógłby przechodzić na czerwonym świetle, albo poza pasami…
Często nasze sytuacje są bardziej banalne - nie wiemy jak działa metoda “biblioteczna” i piszemy kod i testy pod nasze wyobrażenie o niej, a nie faktyczne jej zachowanie. Albo klasyczny .NETowy przykład Linq. Jeśli nie używamy bazy prawdziwej w testach, a wersji “in-memory”. To może się okazać, że testy jednostkowe wszystkie “where’y” pięknie zapalają na zielono, a odpalamy to na prawdziwej bazie i jest kłopotek.
W Martenie zachęcamy, żeby wszystkie testy Martena robić na prawdziwej bazie. No może prawie prawdziwej. W dzisiejszych czasach odpalenie Dockera to żaden wielki wysiłek. Obraz Postgresa jest tak lekki i ma małe wymagania, że nawet na przeciętnym lapku te testy będą latać akceptowalnie. Spora część założeń związanej z testami jednostkowymi i systemowej niechęci do testów integracyjnych. Duża część tych założeń była tworzona w momencie gdy postawienie środowiska lokalnego było czymś bardzo problematycznym. Dodatkowo integracje faktycznie miały duży narzut. Czasy się zmieniają. Mamy 21 rok, 21 wieku. Zacznijmy rewidować stare poglądy.
Chmury, systemy rozproszone, Kubernetesy i inne tego typu zabawki wnoszą dodatkowy stopień skomplikowania. Co prawda możemy sobie dzięki Dockerowi postawić nawet klaster Kubernetesa lokalnie na lapku, możemy sobie nawet jakiś emulator chmury odpalić, ale to są ciągle elementy zastępcze. To tak jak kupujemy ciuchy. Niby rozmiar kołnierzyka ten sam, niby eMka to eMka, rozmiar buta niezmienny, a i tak za każdym razem trzeba przymierzyć bo każdy producent ma to trochę inaczej.
Dopóki nie odpalimy tego na środowisku docelowym to nie będziemy wiedziec jak nasz system się zachowa. Będą to inne maszyny, inna topologia sieci, inne wersje środowiska uruchomieniowego, load balancery, gatewaye itd. itp. Przede wszystkim inne obciążenie i inny ruch. No i żywi użytkownicy, którzy nie chodzą po tak wydeptanych ścieżkach jak my się poruszamy.
Klasyczną receptą był “pre-prod”. Stawiamy sobie środowisko, tam wdrażamy, testujemy i jak jest dobrze to wdrażamy na proda. Tylko, że jakoś zawsze się okazywało, że ten pre-prod był nieco inny. Zwykle w pewnym momencie orientujemy się, że to nam kompletnie nic nie daje. Co najwyżej dodatkowy elementy procesu, który tylko nas opóżnia.
Dlatego w obecnych czasach tak ważne jest, żeby działać reaktywnie - podejmować działania gdy coś się zepsuło i dostaliśmy zgłoszenie, ale by być proaktywnym. Elementami takiej proaktywności są np. metryki i alarmy. Ich dobre ustawienie to podstawa. Ale tego też często jest mało.
W poprzednim projekcie stosowaliśmy testy syntetyczne (Synthetic tests). Czyli coś w stylu testów end-to-end. Ogólnie symulują one działanie prawdziwych użytkowników systemu. My mieliśmy skonfigurowanego na prodzie testowego “klienta”, w którego te testy nawalały regularnie co 5 minut porcją zachowania. Dzięki temu w połączeniu z metrykami można było wychwycić anomalie działania systemu. Np. że po wdrożeniu któregoś mikroserwisu coś zaczęło się sypać, albo działać wolniej. Często udawało się dzięki temu coś wychwycić zanim jeszcze klient to zgłosił. Oczywiście przygotowanie takiego zestawu testów wymaga pomyślunku, czasu i konfiguracji, ale to tak naprawdę daje nam szybką i rzetelną informację o naszym systemie. Zobacz np. tutaj: https://raygun.com/blog/synthetic-testing/.
Innym ciekawym sposobem, który spopularyzował Netflix (ja nie używałem osobiście) jest Chaos Monkey (https://github.com/Netflix/chaosmonkey). Czyli małpa, która losowo wyłącza nam usługi na produkcji i pozwala nam sprawdzić jak odporny na błędy jest nasz system. Może nam to dużo powiedzieć o tym czy mamy rozproszony monolit czy jednak nie. Niedawno AWS wprowadził to “as a service”: https://techcrunch.com/2020/12/15/aws-introduces-new-chaos-engineering-as-a-service-offering/.
Jeśli temat Cię zaciekawił polecam jeszcze śledzenie Charity Majors, dosyć kontrowersyjnej, ale bardzo mądrej osoby.
- tutaj Jej wpis: https://increment.com/testing/i-test-in-production/
- odcinek podcastu Corecursive z Nią: https://corecursive.com/019-test-in-production-with-charity-majors/
Jak to wygląda u Ciebie i jakie są Twoje przemyślenia? Bluźnię?
Pozdrawiam! Oskar
p.s. podrzucam jak co tydzień kolejne wydanie Architecture Weekly - https://github.com/oskardudycz/ArchitectureWeekly#11th-january-2021 - sporo o Kafka kontra Rabbit p.s.2. mój wpis na blogu “Bring me problems, not solutions!” - https://event-driven.io/en/bring_me_problems_not_solutions/. Możliwe, że Ci już znany, bo jakiś czas temu był po polsku w newsletter.