Uwaga! Trwają prace nad nową wersją serwisu. Mogą występować przejściowe problemy z jego funkcjonowaniem. Przepraszam za niedogodności!

🔥 Webinar Q&A na temat IT – pytaj, o co chcesz! już 24.11.2022 (czwartek) o 20:30

Czym jest CI/CD?

Wprowadzenie do zagadnień DevOps

Jerzy Wickowski opowiada o Continuous Integration (CI), Continuous Delivery (CD) oraz Continuous Deployment (CD). Temat jest ściśle powiązany z DevOps i niekoniecznie niezbędny dla osoby wchodzącej do branży IT. Jak się jednak okazuje, może to być idealny sposób na wyróżnienie się na tle konkurencji.

Poruszane tematy

  • Czy mógłbyś się przedstawić i opowiedzieć o swoich początkach w świecie IT?
  • Czym obecnie się zajmujesz?
  • Czy mógłbyś wyjaśnić czym jest CI oraz CD?
  • Jakie korzyści płyną z tego typu rozwiązań?
  • Czy w każdym projekcie rekomendujesz używanie CI/CD?
  • Jak efektywnie wdrożyć CI/CD?
  • Kto w firmie zajmuje się tego typu zadaniami? Jak wygląda tego typu praca?
  • Jaką wiedzę powinna mieć osoba zaczynająca przygodę z frontend-em?
  • Jakie platformy polecasz do wdrażania CI/CD na początek?
  • Czy masz zestaw dobrych rad, które pozwolą efektywnej wejść w świat CI/CD?
  • Jeśli miałbyś wybrać jeden pozytywny i negatywny moment w swojej karierze w IT, który najbardziej zapadł Ci w pamięć to co to by było?
  • Jaką Twoim zdaniem książkę powinien przeczytać każdy kto jest w branży IT, albo kto zamierza w nią wejść i dlaczego?

Transkrypcja

Cześć. Z tej strony Mateusz Bogolubow z serwisu devmentor.pl. Dziś mój gość będzie opowiadać o tajemniczo brzmiącym akronimie CI/CD. Jerzy, dziękuję, że przyjąłeś moje zaproszenie na rozmowę.

Cześć, Mateusz. Dziękuję również. Bardzo mi miło, że mogę tutaj gościć.

 

Czy mógłbyś się przedstawić i opowiedzieć o swoich początkach w świecie IT?

Oczywiście. Jestem Jórek Wickowski. Jako programista pracuję już od ponad 10 lat. Głównie wywodzę się ze świata .NET-owego, więc to są rzeczy, w których czuję się bazowo najpewniej. Lecz ze względu na to, że rynek się zmienia, ja też troszkę zmieniłem swój profil – poszedłem w stronę webówki, czyli JavaScriptu, ale również z tego względu, że praca w IT to nie jest tylko programowanie. W pewnym momencie przesunąłem się w stronę tak zwanego DevOpsa, czyli w stronę Continuous Integration, Continuous Delivery i tak naprawdę od 2-3 miesięcy nie pracuję na etacie, tylko robię inne rzeczy związane z oprogramowaniem.

 

Właśnie chciałem Cię o to zapytać. Co obecnie robisz?

Obecnie zajmuję się dwoma, może nawet trzema rzeczami. Jedna, która już działa to szkolenie na platformie DeployAcademy.pl. To jest moja własna platforma, gdzie szkolę ludzi z zakresu Continuous Integration i Continuous Delivery. Pokazuję, jak taki cały proces teoretycznie powinien wyglądać, po co jest, dlaczego właśnie tak wygląda oraz jak go skonfigurować w praktyce na platformie Azure Pipelines. To jest jedna rzecz.

Druga rzecz, którą z dopiero ruszam i jeszcze nie działa, to SzkolaCzystegoKodu.pl, gdzie szerzę ideę, wizję tego, jak refraktorować w sposób ciągły. Ja sam lubię refaktorować i chcę pokazać ludziom, że to jest fajne, że to jest dobre i że można to robić w sposób efektywny.

A co to jest ta refaktoryzacja? Część osób, które nas słuchaj, mogą nie do końca wiedzieć, o co chodzi.

Oczywiście. Refaktoryzacja to część pracy programisty, kiedy zmieniamy dany kod, żeby był lepiej utrzymywalny, żeby miał lepszą strukturę wewnętrzną, ale żeby wciąż działał tak samo – czyli czasem wprowadzamy różne wzorce projektowe, zmieniamy nazwy zmiennych, zmieniamy strukturę tego kodu w taki sposób, żeby było nam łatwiej utrzymywać go w przyszłości.

Myślę, że teraz jest to już jasne.

Tak że to jest refaktoryzacja. A trzecia rzecz, w którą teraz się wgryzam, to: próbuję swoich sił jako freelancer, czyli planuję tworzyć oprogramowanie dla ludzi biznesu sam, niekoniecznie jako część jakiegoś większego sofware house’u. Jest to na razie na etapie eksperymentów i prób. Czy mi to wyjdzie, zobaczymy.

 

Dzięki za to wprowadzenie. To może wrócilibyśmy do akronimu CI/CD, o którym już wspominałeś. Czym jest CI/CD i jak wygląda jego wdrożenie?

Można nawet powiedzieć CI/CD/CD, ponieważ tutaj mamy tak naprawdę trzy rzeczy, trzy wyrażenia, które łączą się w te akronimy. CI to dzisiaj jest Continuous Integration, czyli ciągła integracja. Następnie mamy CD, które możemy rozwinąć jako Continuous Delivery bądź Continuous Deployment. Continuous Delivery to jest ciągłe dostarczanie, Continuous Deployment to jest ciągłe wdrażanie.

Zacznijmy od tego pierwszego. Continuous Integration też jest bardzo fajne, bardzo ciekawe, bo możemy je rozumieć w dwóch aspektach. Continuous Integration możemy rozumieć jako jakiś kawałek oprogramowania czy jakiś kawałek konfiguracji, jakiś pipeline, jakiś potok – zależy od użytych słów – który bierze automatycznie kod commitowany do repozytorium. Następnie odpala na nim serię rzeczy. Na przykład odpala analizę statyczną, żeby sprawdzić, czy dany wbity kod jest zgodny z naszymi wymaganiami. Następnie odpala testy jednostkowe, żeby sprawdzić, czy wszystko przechodzi. Następnie buduje tę aplikację – i wtedy wiemy, że wszystko jest OK. Tak że to może być jedno rozumienie Continuous Integration – proces, który nam automatycznie sprawdza i buduje kod wrzucany do repozytorium zawsze po każdym commicie.

Continuous Integration ma też drugie rozumienie, które jest trochę mniej popularne. To jest pewien sposób pracy, pewien sposób współpracy programistów, aby bardzo często integrowali swój kod. Ciągła integracja jest przeciwieństwem ciągłej dezintegracji, a dezintegrację możemy rozumieć w taki sposób, że kiedy mamy kod w naszym repozytorium na dwóch różnych branchach przez długi czas, to wtedy kod ten jest zdezintegrowany, ponieważ branche, które żyją osobno, nie są ze sobą połączone, czyli nie są ze sobą zintegrowane.

W kwestii integracji – jest tam już masa praktyk, bo może tam wchodzić podejście do tego, w jaki sposób będziemy tworzyć duże funkcjonalności. Tam musimy brać pod uwagę to, w jaki sposób tworzymy branche, w jaki sposób je merge’ujemy, w jaki sposób rozwijamy duże zadania na małe kroki, żebyśmy mogli tę integrację przeprowadzać często. Mówiąc szczerze, kiedy konfigurujemy te pipeline’y, to jest to część trudniejsza niż część techniczna, ponieważ często musimy zmienić bądź dostosować model pracy czy sposób pracy zespołów programistycznych.

 

To czas teraz na CD. Wspomniałeś, że można to rozwinąć na dwa sposoby.

Continuous Delivery to ciągłe dostarczanie. Jest to również z jednej strony pewien sposób pracy i też trochę konfiguracja pipeline’ów, ale one łączą się ze sobą w jedną rzecz, żebyśmy byli w stanie w każdej chwili wdrożyć oprogramowanie dla produkcji. To wcale nie znaczy, że my będziemy je wdrażać co 15 minut albo codziennie, ale powinniśmy być gotowi, żeby je wdrożyć w sposób stabilny. Łączy się z tym wiele rzeczy: jak zapewnić stabilność, żeby to działało zawsze, jak przeprowadzić proces testowania, jak rzeczywiście tworzyć duże funkcjonalności albo jak robić refactoring, żebyśmy jednak ciągle byli w stanie nasz kod – mimo, że jest czasem częściowo nieskończony – wdrożyć na produkcję i żebyśmy zawsze byli do tego gotowi.

Continuous Deployment natomiast to już jest czasem taki złoty Graal, ponieważ w większości zespołów nie jest potrzebny. Continuous Deployment używają duże firmy, jak Google, Facebook, Microsoft. Oni tego potrzebują. W Polsce raczej mniej.

Continuous Deployment to już jest sytuacja, kiedy my automatycznie bez ingerencji człowieka po wrzuceniu kodu do repozytorium mamy stworzone mechanizmy, które przepchną nam ten kod od razu na produkcję. Ten temat jest bardzo skomplikowany, bo w sposób automatyczny musimy zapewnić, że ten kod będzie działał, że będzie stabilny, że nie zepsuje tego, co już tam jest, a jeżeli zepsuje, to mamy jakiś mechanizm, który nam automatycznie przywróci wersję poprzednią. Tak że Continuous Deployment jest rzeczą już bardziej zaawansowaną. Wrzucamy kod do repozytorium, a on już sam leci na produkcję.

 

Jakie korzyści płyną z tego typu rozwiązań?

Pierwsza zaleta to na pewno oszczędność czasu, bo jeżeli automatyzujemy cokolwiek, to robimy to po to, żeby zrobić raz. Być może włożymy więcej pracy, ale następnie oszczędzamy czas, ponieważ rzeczy robią się same. Właśnie to w każdym z tych kroków jest aktualne. Możemy oszczędzać ten czas na wiele sposobów.

Weźmy na początek Continuous Integration. Zacznijmy od tego, że konfigurujemy ten pipeline do ciągłej integracji – czyli chcemy odpalić tam testy jednostkowe, chcemy odpalić analizę statystyczną i zbudować naszą aplikację – i robimy to po każdym commicie. W związku z tym mamy pewność, że każda zmiana, którą ktoś wbije do repozytorium, będzie przetestowana, że będzie zgodna z jakimiś standardami, które opracowaliśmy. Dodatkowo, jeżeli my tam wepniemy mechanizm sprawdzania pull questów, to automatycznie dany pull quest może zostać odrzucony, jeżeli na przykład nie przechodzi testu lub jeżeli aplikacji się nie buduje.

Gdzie tu jest oszczędność czasu? Przychodzę, przykładowo, w poniedziałek do pracy, pobieram najnowszą wersję, a ona mi nie działa. Czasem się tak zdarza, ale jeżeli mamy wdrożony proces Continuous Integration i ten pull quest zostanie odrzucony od razu, to wtedy ja nie tracę czasu – nie pobieram wersji, która mi nie działa.

Myślę, że to też działa w drugą stronę: osoba, która robi takiego pull requesta, od razu będzie wiedziała, że coś nie działa i że trzeba to poprawić.

Dokładnie tak. I wtedy nie czeka na telefon od kolegi: „Ej, weź tam popraw, bo mi nie działa”, tylko widzi to od razu i dodatkowo nie psuje pracy innym. Tak że to jest jedna bardzo fajna rzecz.

Druga to to, że od razu widzimy wyniki testów. Czasem, zwłaszcza jak aplikacja jest większa, to jest dużo grup grup testów i nie zawsze odpalamy wszystkie. A tutaj, jak wrzucamy kod do repozytorium, to te testy zostają automatycznie odpalone i zawsze mamy informacje.

Kolejna rzecz: zerknijmy na Continuous Integration z tej strony miękkiej. Jeżeli myślimy o tym, żeby często integrować kod, wtedy również będziemy oszczędzać czas, choć na samym początku nie jest to takie intuicyjne. Często nam się wydaje, że skoro jakiś programista przez tydzień będzie pracował na swoim branchu i drugi programista też tak będzie robił, to będzie fajnie, bo nie będą sobie przeszkadzać. To na pierwszy rzut oka jest bardzo fajne, a tak naprawdę jest bardzo zgubne – z tego względu, że jeżeli ci programiści nie będą integrować kodu między sobą często i szybko, to potem mogą się zakopać na kolejny tydzień na merge’owaniu tego wszystkiego, jeżeli będą jakieś konflikty. Natomiast jeżeli będą dążyć do tego, żeby kod merge’ować szybko, na przykład co 4 godziny, co 6 godzin, to wtedy w najgorszym wypadku będą mieli konflikt po 4 godzinach. Jeżeli mają konflikt po 4 godzinach, to nawet, jeżeli muszą zrivertować (odrzucić) swoje zmiany, to nie jest to tak duża strata czasu, jak odrzucenie pracy dwutygodniowej albo tygodniowej.

Od razu mi się nasunęło takie porównanie z pisaniem testów. Wiele osób może na początku nie do końca lubi pisać testy i uważa, że to jest strata czasu, ale potem przy dużym projekcie – jeżeli mamy sprawdzić, czy wszystko działa – okazuje się, że te testy naprawdę robią robotę i dają radę i warto było je pisać od początku po to, żeby potem na późniejszym etapie nie mieć tego typu problemów. Przeklikanie za każdym razem jakiejś funkcjonalności to strata mnóstwa czasu, a można to zrobić automatycznie.

Dokładnie tak. Zróbmy coś raz, żeby nam się to sprawdzało później. Testy musimy się nauczyć pisać, żeby nas chroniły, ale tak samo musimy nauczyć się często integrować nasz kod i tworzyć go w taki sposób, żeby to działało i żeby rzeczywiście przyspieszało naszą pracę. Bo jeżeli na dzień dzisiejszy jakiś zespół ma branche, które żyją tydzień, i teraz powie: „OK. Od przyszłego tygodnia merge’ujemy się dwa razy dziennie”, to prawdopodobnie przez tydzień albo przez dwa tygodnie tam będzie Armagedon. Aplikacja nie będzie działać w ogóle. Ale jeżeli przebrną przez ten etap i nauczą się pracować w taki sposób, nauczą się tworzyć tak zwane feature switche, czyli będą w stanie wrzucać kod niedziałający, ale niepsujący aplikacji, to wtedy zobaczą: „ej, ale to naprawdę nam przyspiesza”, „rzeczywiście mamy dużo mniej zależności”, „ja rzeczywiście nie muszę czekać, aż ktoś skończy, bo możemy zastosować pewną abstrakcją”. Tak że to rzeczywiście przyspiesza.

Kolejny etap (myślę, że możemy do niego już przejść), to to, w jaki sposób ciągłe dostarczanie przyspiesza nam wytwarzanie oprogramowania i oszczędza czas. W ciągłym dostarczaniu bardzo często tworzymy kilka środowisk, gdzie będziemy wdrażać naszą aplikację. Na początku po commicie zawsze aplikacja przechodzi przez proces Continuous Integration – gdzie jest budowana, odpalają się testy jednostkowe – i potem tworzymy paczkę, czyli zbiór DLL-ek, które będą instalowane na kolejnych środowiskach.

Na początku taka aplikacja jest wdrażana na pierwsze środowisko, tak zwany dev, którego nikt tak naprawdę nie używa. Chodzi tylko o sprawdzenie, czy my jesteśmy w stanie daną paczkę, daną aplikację zainstalować w jakimś środowisku. Jeżeli jesteśmy w stanie, to spoko. Paczka wtedy „awansuje”, jest promowana na kolejne środowisko, na które już mogą mieć dostęp testerzy. I to już jest dla nich przyspieszenie pracy, ponieważ jeżeli my aplikacje wdrażamy ręcznie, a nie automatycznie, to albo taki tester musi ściągnąć sobie paczkę z repozytorium, zbudować, wrzucić na jakieś środowisko (i to trwa), albo może być jeszcze gorzej – tester podchodzi do programisty i mówi: „Ej, Jurek wrzuć mi na środowisko tę najnowszą wersję, którą ostatnio robiłeś”. Taki tester musi się oderwać na 5 minut, żeby poinformować programistę, musi zmienić kontekst na 5 minut, żeby to wdrożyć. Potem przez 10 minut wraca do tego, co robił. To strasznie wybija z pracy. Jeżeli ten etap działa automatycznie, czyli programista wrzuca kod do repozytorium, a tester całkiem automatycznie dostaje nową wersję na serwer lub być może ma przycisk: „Hej wrzuć mi teraz nową wersję”, to oszczędzamy czas – bo nikt nie musi ręcznie wchodzić na żadne serwery. Nikt nie musi sprawdzać, czy tam jest najnowsza wersja czy nie. To działa i jest automatyczne.

Następną sprawą jest dostarczanie kodu do klienta – kod również może automatycznie lecieć na środowisko demo, które pokażemy klientowi. Nie musi więc on czekać kolejnego tygodnia albo dwóch, tylko zawsze ma dostępną najnowszą wersję. Tylko tutaj rzeczywiście musimy z klientem wypracować to, że aplikacja, którą mu wrzucamy, jeszcze nie jest tą, która idzie na produkcję – że jest jeszcze w fazie, być może, developmentu, że coś tam może jeszcze nie działać. Klient jednak od razu widzi, jak ta aplikacja wygląda. W związku z tym możemy oszczędzić tak naprawdę tygodnie pracy. Jeżeli on odpali tę aplikację i powie: „Ej, ale to nie tak miało być. Ja coś innego miałem na myśli”, to w takiej sytuacji nie brniemy w tę stronę, nie brniemy w błędną implementację następny tydzień czy dłużej.

Kolejna rzecz – jeżeli mówimy o tym, że chcemy być zawsze gotowi, żeby wdrażać aplikacje w Continuous Delivery – to często instalacja aplikacji na różnych środowiskach: cały czas ją wrzucamy na deva, często ją wrzucamy na środowisko testowe i na demo. Proces ten jest tak zautomatyzowany, że już nikt nie musi ręcznie wchodzić i sprawdzać, jak to rzeczywiście zdeployować. W związku z tym, jeżeli nadchodzi czas deploymentu (wdrożenia aplikacji) na produkcję, to my mamy już wszystko oskryptowane. Już nie robi się nagle jakiś panic mode – „o nie piątek, co my teraz zrobimy. Armagedon, wszystko płonie” – tylko wdrożenia na produkcję stają się w pewnym sensie rutyną, która jest zautomatyzowana i przetestowana dziesiątki razy dziennie czy dziesiątki razy tygodniowo, kiedy wdrażamy tę aplikację często.

Gdy wspominałeś o tym kliencie, to sobie pomyślałem, że klient też czuje się bezpieczniejszy, bo widzi, co się dzieje, i nie musi pisać do programisty: „Słuchaj, pokaż mi, co macie, bo zastanawiam się, czy się wyrobicie”. Wtedy taki klient od razu widzi, jak to wygląda. Może sprawdzić, może nawet powiedzieć: „Słuchajcie, ja tutaj myślałem o czymś innym” – jak to często bywa z klientami. Naprawdę super rozwiązanie. Czy dodałbyś coś jeszcze do tej listy korzyści?

Tak. Właściwie to, o czym teraz powiedziałeś, niektórzy mogą postrzegać jako wadę. Czasem się z tym spotykam, że ludzie mówią: „Ale jak mam to już dawać to do klienta, jak to jeszcze jest niegotowe? On zobaczy, że to jest nie tak”. To jest ten ważny moment, w którym musimy nauczyć klienta i powiedzieć mu, że my to rzeczywiście wdrażamy cały czas, że to jest troszkę inny model pracy niż ten, do którego być może on jest przyzwyczajony. Wtedy też zaczyna się pojawiać większe obustronne zaufanie: klient widzi, co to jest, ale i my zmieniamy podejście. Myślenie człowieka, który pracuje nad tym kodem, jest inne – wie, że ten kod, który wrzuca po przejściu testów może już być odpalony u klienta. W związku z tym mentalnie programiści inaczej podchodzą do tej pracy. To nie jest tak, że to jeszcze będzie szło przez siedem sit, tylko już to ktoś może zobaczyć.

Czyli ograniczamy liczbę komunikatów z niezbyt dobrą treścią?

Musimy to lepiej ukrywać albo rzeczywiście zdawać sobie sprawę z tego, że ktoś to może tak naprawdę zobaczyć.

 

Z tego, co mówisz, dużo jest procesów, które trzeba przejść, żeby osiągnąć odpowiednią konfigurację tej całej automatyzacji. Czy w każdym projekcie rekomendujesz tego typu rozwiązania? Gdzie jest punkt, w którym należy uznać, że „OK. Wdrażamy CI/CD”, a gdzie nie?

Jestem wielkim zwolennikiem tego, że CI/CD powinno być to wdrożone zawsze, ale z pewnym zastrzeżeniem. Nie zawsze potrzebujemy wszystkich elementów.

Powiedzmy jeszcze o korzyściach płynących z Continuous Deploymentu. Oszczędzamy dzięki niemu czas – po każdym commicie dostarczamy kod automatycznie już bezpośrednio do użytkowników końcowych. Wówczas jesteśmy w stanie dużo szybciej reagować na zmiany rynkowe. Dużo szybciej możemy sprawdzać, jak zachowują się nasi klienci. W ten sposób możemy modyfikować kurs, w którym idziemy.

W związku z tym Continuous Deployment jest nam potrzebny w bardzo małej liczbie aplikacji. Bardzo często wdrożenia raz na tydzień są wystarczające. Bardzo często wdrożenia raz na 2, na 3 tygodnie są wystarczające. W związku z tym nie zawsze potrzebujemy Continuous Deploymentu. Continuous Deploymentu potrzebujemy, kiedy tworzymy aplikację SaaS-ową, w której rzeczywiście użytkownicy używają cały czas, a my ją dynamicznie rozwijamy, jeżeli np. jest to jakiś start-up.

 

To jeszcze może powiedz, czym jest SaaS.

Jasne. SaaS to jest tak zwany Software as a Service, czyli serwis jako usługa. Tak naprawdę SaaS to jest jakakolwiek usługa, z której my korzystamy przez przeglądarkę. Możemy powiedzieć, że Gmail jest SaaS-em. Możemy powiedzieć, że Dropbox jest SaaS-em. Możemy powiedzieć, że Spotify jest SaaS-em. To jest aplikacja, która działa w Internecie. My do niej wchodzimy poprzez jakiś adres. W związku z tym, jeżeli rzeczywiście tworzymy taką aplikację, zwłaszcza na początku, jeżeli bardzo szybko chcemy gonić rynek i chcemy badać, jak nasi klienci się zachowują, to wtedy Continuous Deployment jest wspaniały. Tylko jak często robimy takie aplikacje? Niezbyt często. W związku z tym Continuous Deploymentu prawdopodobnie nie potrzebujemy aż tak często.

Natomiast jestem wielkim fanem Continuous Integration i uważam, że wdrożenie automatycznego odpalania testów po każdym commicie, automatycznego budowania aplikacji i nawet odpalania analizy statycznej to jest tak mało pracy, że powinniśmy to mieć zawsze, ponieważ daje to nam gwarancję dużo większej stabilności. Polecam to i uważam, że powinno się to robić zawsze niezależnie od tego, nad jaką aplikacją pracujemy.

 

Jest wiele platform, które umożliwiają wdrożenie CI/CD. Czy istnieje gotowa konfiguracja, która pozwoli nam wdrożyć CI na minimalnym poziomie? Żeby to faktycznie fajnie działało, ale nam jako programistom nie zajmowało dużo czasu lub było dostępne dla osoby, która się na tym nie zna.

Do tego możemy podejść na dwa sposoby. Większość narzędzi, jak Azure Pipelines, GitLab, TeamCity, ma już coś takiego, że po połączeniu naszego serwera CI z repozytorium, możemy powiedzieć, a często nawet wskazać w UI: „Zbuduj ten projekt i odpal testy z tego projektu przy commicie”. Możemy to zrobić bez najmniejszego problemu.

Tak samo możemy zrobić z aplikacjami na front endzie typu Angular i React, ale jeżeli mamy Angulara bądź Reacta, to tam testy i tak odpalamy na lokalnej maszynie z poziomu linii komend. W związku z tym, jeżeli wpisujesz npm build albo npm run test, to tak naprawdę konfiguracja Twojego CI może wyglądać w taki sposób: po commicie odpal skrypt npm build, a w drugim kroku odpal skrypt npm test. To jest coś, co my i tak, i tak zawsze robimy na naszych maszynach deweloperskich, w związku z tym konfiguracja na CI może się ograniczyć do odpalenia 2 komend.

 

To super. W takim razie dużo rzeczy nam odchodzi i mamy w zasadzie gotowe rozwiązanie. A jeżeli miałbyś wybrać jedną jedyną rzecz, która jest najważniejsza z perspektywy efektywności wdrożenia CI/CD, to co by to było?

To jest coś, co się sprawdza zarówno w programowaniu, jak i w konfiguracji oraz w wielu innych rzeczach: powinniśmy robić to krokami. Jeśli zaczynamy aplikację, zaczynamy konfigurację CI, to nie musimy od razu konfigurować Continuous Delivery albo Continuous Deploymentu, nie musimy już od pierwszego dnia mierzyć pokrycia kodu i odpalać testów integracyjnych. Zacznijmy od rzeczy prostych.

Na początku niech się nam buduje ta aplikacja. Jak się buduje, to wtedy już poznajemy narzędzie, widzimy, jak to działa. Zobaczymy, jak do tego podejść, nawet jeżeli nie znamy tych narzędzi. Podziała nam to przez 3 dni i mówimy: „Jest fajnie. Zróbmy krok drugi”. Róbmy to iteracyjnie. W drugim kroku po 3 dniach możemy powiedzieć: „OK. Odpalam sobie test jednostkowy”. Jak się nam odpalą testy jednostkowe, mówimy: „OK. Jest spoko. To potem zróbmy analizę statyczną”. Dodajmy to iteracyjnie. Nie musimy od razu wdrażać aplikacji na cztery środowiska i odpalać testów integracyjnych.

W kolejnym kroku możemy naszą aplikację, która się zbuduje, wrzucić na jakieś środowisko, żebyśmy po prostu byli w stanie ją zdeployować. Tak że to, co ja zdecydowanie również tutaj polecam: róbmy to iteracyjnie. Dodawajmy kroki po kolei – z kilku powodów. Po pierwsze nauczymy się tego narzędzia w sposób naturalny, przyrostowy. Druga rzecz: podczas konfiguracji CI bardzo często dużo jest takiej zabawy – prób i błędów. „Nie odpalają mi się testy. Dlaczego? Może brakuje mi jakiegoś średnika? Może jakiś minus, może jakaś paczka się nie instaluje?”. W związku z tym im dłużej ten proces jest konfigurowany, tym jest on stabilniejszy, bo cały czas coś tam musimy poprawiać.

 

Kto takimi rzeczami zajmuje się w firmie? Jak ta praca wygląda?

Tutaj są dwa podejścia, które możemy rozważyć. Pierwsze podejście, którego ja nie jestem fanem, to: jest zespół programistyczny, a w nim jakaś jedna dedykowana osoba, która zajmuje się automatyzacją tego całego procesu. Można podejść do tego w ten sposób, tylko że wtedy jest pewien problem – zespół programistyczny tak naprawdę nie wie, jak ta aplikacja żyje po tym, jak zostanie wrzucona do repozytorium.

W związku z tym ja wolę model drugi: każdy programista powinien umieć skonfigurować CI w podstawowy sposób, czyli powinien rozumieć proces, jaki się za tym kryje, jak to powinno wyglądać i dlaczego, oraz żeby umiał zbudować aplikację, przetestować, wrzucić to na jakieś środowisko. Czyli żeby to działało od etapu developmentu po dostarczanie dema do klienta.

A jeżeli dochodzimy już do momentu, gdy wrzucamy tę aplikację na produkcję, to wtedy rzeczywiście dobrze mieć eksperta, który to dopieści, który zadba o rzeczy związane z bezpieczeństwem (z security), zrobi trochę rzeczy administracyjnych, żeby otwierać odpowiednie firewalle, żeby tam wszystko było szyfrowane i tak dalej.

W związku z tym, jeżeli już to idzie na produkcję, to wtedy dobrze jest mieć eksperta, który albo zrobi z tego audyt, albo to podrasuje, żeby było dużo bezpieczniejsze, być może szybsze. Natomiast jeżeli pracujemy na początku i to konfigurujemy, to uważam, że każdy w zespole programistycznym powinien wiedzieć, jak to się robi.

 

Czy osoba, która zaczyna pracę jako JavaScript developer, powinna mieć umiejętności z tego zakresu?

Co powinien umieć i czy powinien umieć? Według mnie jeszcze nie musi znać kwestii praktycznej, bo to jest osoba początkująca, która jeszcze prawdopodobnie nie wdrażała nigdzie żadnej aplikacji. W związku z tym ciężko jest zautomatyzować jakiekolwiek proces, którego się nie zna, którego nigdy nie zrobiło się nawet ręcznie.

W związku z tym dobrze jest, żeby ktoś taki wiedział, czym jest Continuous Delivery i po co to jest, ale niekoniecznie musi umieć to skonfigurować. Natomiast uważam, że konfiguracja rzeczy podstawowych – czyli żeby to się automatycznie zbudowało i żeby odpaliły się testy – nie jest aż tak zaawansowana, żeby tego nie znać.

Tak że na pewno warto znać koncepcję i wiedzieć, o co chodzi. Natomiast w praktyce warto znać podstawowe rzeczy, żeby chociaż – tak jak mówię – budowały się i odpalały testy. To na sam początek. Jeżeli ktoś zaczyna, to to i tak jest całkiem sporo.

 

Co powinien poznać junior JavaScript developer, żeby wejść w temat CI/CD?

Jeżeli już taka osoba rzeczywiście programuje i wie, o co chodzi, to to co jest na początek potrzebne (od strony JavaScriptu), to umiejętność działania z linią komend. Ale jeżeli ktoś działa już w Angularze czy w Reakcie, to na pewno już tę linię komend zna. Być może nie zna wszystkich argumentów do webpacka, ale już zna podstawy. W związku z tym nawet jeszcze przed konfiguracją CI dobrze jest zaprzyjaźnić się z linią komend, żeby nie odpalać wszystkiego z narzędzia programistycznego, z IDE, tylko żeby umieć te testy odpalić bez tego narzędzia albo żeby zbudować aplikację bez tego narzędzia – dzięki temu później migracja na CI będzie łatwiejsza.

Następnie warto poznać cały ten koncept – jak to działa, że jest serwer CI, który obserwuje repozytorium, że po każdym commicie może on ten kod wziąć i zbudować. Warto iść w tę stronę, że skoro my i tak budujemy i testujemy tę aplikację u siebie lokalnie, to przenosimy to dalej. To też mówiłem wcześniej: warto do tego podejść iteracyjnie.

 

To w takim razie może mógłbyś nam polecić jakąś platformę, która pozwoliłaby nam wdrożyć tego typu rozwiązania.

To jest o tyle dobre albo złe, że z jednej strony nie ma jednej dobrej, a z drugiej strony wszystkie są dobre. Na początek na pewno bym polecał coś darmowego. Może to być Azure Pipelines, który jest na początku darmowy. Ja go lubię. Może ktoś używać Travis CI, może ktoś używać CircleCI, może ktoś używać Jenkinsam który jest trochę stary, ale jest jak najbardziej OK. Ktoś może używać TeamCity. To, co wybierzemy na początek, nie robi aż tak dużej różnicy, ponieważ pierwsze kroki i tak będą proste, i tak będziemy chcieli na początku odpalić tylko proste rzeczy.

Natomiast jeżeli ktoś zrozumie koncepcję i będzie wiedział, do czego dąży i powie: „OK, ja będę potrzebować wdrażać aplikację rozproszoną, składającą się z 6 serwisów i z czegoś tam innego i będę chciał robić automatyczne backupy” i tak dalej, to wtedy może dojśc do wniosku: „OK. To ja mam teraz bardziej zawężony dobór narzędzi”. Tak że na początku jest to obojętne, a jeżeli to już jest temat bardziej zaawansowany, to wtedy i tak wybieramy to rozwiązanie, które nam spełni te zaawansowane wymagania.

 

To może warto też powiedzieć, żeby tak nie zniechęcać ludzi, że wiele z tych narzędzi umożliwia po prostu wyklikanie dużej liczby konfiguracji. Może to też ludzi zachęcić do tego, żeby jednak wypróbowali którąś z platform. Na początku powiedziałeś o tej linii komend, ale można to też wyklikać, prawda? To znaczy przy wykorzystaniu tych narzędzi jesteśmy w stanie wiele rzeczy po prostu powybierać sobie z listy i poprzesuwać te, które chcemy wykonać przy danym rozwiązaniu, prawda?

Jak najbardziej. Zwłaszcza że bardzo często narzędzia CI mają właśnie graficzny interfejs użytkownika, gdzie możemy wyklikać to, co chcemy zrobić. Ja zdecydowanie więcej siedzę w Azure Pipelines, więc o tym będę mówił. Mamy tam nawet taką opcję, że Azure Pipelines sam nam podpowiada, w jaki sposób powinniśmy coś zrobić – czyli gdy mówimy mu, że to jest npm (na przykład aplikacja React, Angular, Vue), to on nam powie: „OK. To tu wskaż na katalog, w którym jest plik package.json, i potem powiedz mi, co mam odpalić”. Bardzo więc w tym pomaga.

To jest jedna rzecz – czyli mamy GUI – a druga rzecz, z czym na pewno się każdy spotka, to pliki YAML. Plik YAML to plik tekstowy, w którym opisujemy poszczególne kroki mające się wydarzyć w danym pipelinie, w danym bildzie. Ten plik może na początku wyglądać strasznie, bo go nie rozumiemy, ale tak naprawdę, jeżeli zerkniemy na niego w taki sposób, że tam po kolei opisane są kroki, które chcemy zrobić, to może już nie będzie aż taki straszny.

Powiedzmy, że może jest on dość podobny do pliku JSON-owego. Jest taki bardziej ludzki niż inne pliki konfiguracyjne.

Tak. Dodatkowo na pewno i Azur Pipelines, i Travis CI też posiadają generator YAML-a, w związku z czym mamy opjcę wyklikać coś w UI i otrzymać kawałek pliku tekstowego, który możemy dołożyć do naszego pliku – i to działa.

 

Czy miałbyś jakiś zestaw dobrych rad dla osób, które chcą wejść w świat CI/CD?

Myślę, że miałbym dwie rady. Pierwsza: po prostu zacznij to robić. Jeżeli pracujesz nad projektem, to spróbuj skonfigurować CI – niech to działa. To naprawdę nie jest jakaś magia. To nie są rzeczy związane z wystrzeliwaniem rakiety w kosmos. To nie jest nowa koncepcja. Musimy zrozumieć nowy proces, którego nie znaliśmy do tej pory. W związku z tym to może być trudne, ale po prostu to zrób.

A druga rzecz: nie optymalizuj tego na początku, nie przekombinowywuj. Zrób rzeczy proste. Niech te rzeczy w pipelinie będą zahardkodowane, ale niech będą, niech to działa, niech już Ci daje wartość od pierwszego dnia, w którym to skonfigurujesz. A jeżeli będziesz chciał to rozwijać, robić bardziej elastycznie, optymalizować, żeby było szybsze, to wtedy dopiero się warto z tym bawić.

Jeszcze jedna rzecz, na którą każdy na pewno się natknie, zwłaszcza jak robi w aplikacjach front-endowych: to krok npm install. Będzie on trwał długo, bo musi ściągnąć pakiety. Nie przejmuj się na początku tym, że to trwa. Na początku niech to działa. Jeżeli zacznie trwać za długo, jeżeli dodasz kolejnych kilka kroków, to dopiero potem zacznij myśleć o tym, jak zmniejszyć ten czas. Na razie niech to będzie nieważne. Na razie niech działa. Ulepszajmy z czasem.

To od razu porównanie programowaniem: tutaj też nie ma co się zastanawiać, tylko trzeba zacząć pisać, a dopiero potem usprawniać kod.

Dokładnie tak. Żeby nauczyć się programować, trzeba programować. Żeby programować lepiej, trzeba programować więcej. Tu jest dokładnie tak samo – jeżeli nigdy nie usiądziesz do tego, żeby skonfigurować CI, to nie będziesz wiedzieć, jak to zrobić. A jeżeli usiądziesz, to prawdopodobnie zaskoczy Cię to, że to nie jest aż tak skomplikowane, jak się wydawało na początku.

 

Jaki jest jeden pozytywny i jeden negatywny moment w Twojej karierze IT, który Ci najbardziej zapadł w pamięć?

Pozytywnym na pewno to jest to, że kiedyś pracowałem on-site w Szkocji nad refactoringem aplikacji legacy jeszcze w starej technologii, która tam żyła 15 lat. I rzeczywiście byłem tam sam, bezpośrednio gadałem z klientem, sam ustalałem, co on chce, jak dana aplikacja ma działać. I to, co było świetne, to że udało mi się to zrobić, będąc samemu na placu boju, z czego byłem bardzo dumny. A po drugie, jak zobaczyłem potem archiwum Gitam, to ja tam usuwałem, już nie pamiętam, 200 czy 400 linii dziennie. Dużo kodu było tam nakopiowane, tak że rzeczywiście po 3 miesiącach pracy udało mi się zmniejszyć ilość kodu chyba o 70%.

To bardzo ładny wynik, ale z drugiej strony też sobie wyobrażam, jaka to była ciężka praca – żeby wdrożyć się w taki kod i potem go zrefaktoryzować. Pewnie nie było to łatwe. Ile czasu Ci zeszło na wdrażaniu się w ten program?

Tak naprawdę w 3, może w 4 miesiące udało mi się to skończyć. To też nie była bardzo duża aplikacja, raczej mniejsza. Plus był jeszcze taki, że miałem bezpośredni dostęp do klienta. Siedziałem razem z nim w pokoju, w związku z czym mogłem powiedzieć: „Hej, Steve, a po co jest to? A jak to działa? A w jakiej sytuacji Wy tego używacie?”. On mi tłumaczył, jak to powinno działać i jak to działa. To akurat była destylarnia, firma, która produkuje whisky. Jechaliśmy gdzieś na produkcję i Steve tłumaczył: „OK. Tu mamy beczki, które wyładowujemy, ktoś idzie i bierze je tam. Tam są rozlewane, tam są butelkowane”. W związku z tym ja doskonale wiedziałem, jak ten proces wygląda i dlaczego tak i łatwo było mi rzeczywiście zmieniać kod tej aplikacji, refaktorować go, bo wiedziałem, jak to ma działać.

Dobra. To mamy wspomnienie pozytywne. Niestety musimy przejść do tego negatywnego. Uczmy się na błędach.

Negatywna rzecz, która tak naprawdę zdarzyła mi się nie raz, ale jest to dość częste: muszę czasem współpracować z ludźmi, którzy bardzo bronią się przed zmianami. Nawet jeżeli mamy argumenty, nawet jeżeli mamy liczby, to ci ludzie wciąż obstają przy swoim, mówiąc, że tak jest i tak było zawsze i my nie chcemy tego zmieniać.

Pracowałem nad aplikacją, która korzystała z jakiejś bazy danych. Ta baza miała już swoje lata i nadszedł moment, w którym trzeba było zrobić w tej bazie zmiany. Aplikacja jest wdrażana i nie działa. Ja mówię: „ale jak? Przecież mamy kopię i tak dalej”. Potem okazało się, że nie byliśmy w stanie w końcu dostać nawet nie, że kopii bazy danych, ale kopii struktury bazy danych, żebyśmy wiedzieli, jak ona wygląda. Więc te zmiany były tak troszkę na ślepo. A druga rzecz, która była gorsza, to to, że dokładnie tej samej bazy danych, tej samej instancji używały 3 zespoły, które siebie nie znały. W związku z tym w jakimś zespole ktoś dodał kolumnę, która była nienullowalna i aplikacja nam przestawała działać. To było trochę uciążliwe i to była rzeczywiście duża, zabetonowana instytucja, w której prośba o kopię struktury bazy danych musiała przejść przez cztery szczebelki akceptacji plus security, plus coś tam.

 

Jaką Twoim zdaniem książkę powinien przeczytać każdy, kto chce wejść do branży albo ktoś, kto jest już w branży?

Czysty kod wujka Boba. Jest to książka, która pokazuje, w jaki sposób wygląda zły kod i czysty kod i opisuje, dlaczego to jest dobre. Tę książkę warto przeczytać na początku. Jak ja ją przeczytałem, gdy zaczynałem programować, to tak patrzę: „Nie, niemożliwe. To są jakieś przykłady akademickie. Tak nie da rady tworzyć kodu”. Potem po 3 czy 4 latach napisałem już trochę swojego kodu. Trochę musiałem wyrzucić do kosza. Wtedy tę książkę czytałem drugi raz i patrzę: „Aha. To on o tym pisał. Teraz już wiem, o co chodzi. Spoko”. Jak ją czytam po 10 latach, to już mogę polemizować: „OK. To, co on mówi, jest spoko, w tym kontekście jest dobre, ale w innym jest złe”. Tak że to jest książka, którą warto czytać tak naprawdę przez cały rozwój, przez całą swoją karierę programistyczną. Na początku i na końcu ona daje wartość.

Tak, potwierdzam. Nawet jeżeli czytasz jakąś książkę i jej nie rozumiesz, to warto do niej wrócić za jakiś czas, bo wtedy pewnie perspektywa Ci się zmieni i trochę inaczej podejdziesz do tematu, pewnie lepiej go zrozumiesz. Nie rezygnujmy więc od razu z książek, które na początku wydają nam się trudne, bo może się okazać, że po prostu nasza wiedza jeszcze nie jest dostosowana do tej książki.

Dokładnie tak. Wiedza wiedzą, jest jeszcze praktyka – jeszcze nie spotkaliśmy tego, o czym ktoś tam pisze.

 

Jerzy, bardzo dziękuję Ci za rozmowę. Mam nadzieję, że jeszcze będzie okazja spotkać się w podcaście. Może za parę miesięcy, za parę lat też nam się zmieni perspektywa.

Z pewnością świat będzie inny, my będziemy inni. Tak że pewnie, że tak.

To dziękuję Ci. Do usłyszenia.

Dziękuję Ci ślicznie. Do usłyszenia. Cześć.

Polecana książka

Czysty kod. Podręcznik dobrego programisty
Robert C. Martin

Zwiększ swoje szanse na znalezienie pracy!

Wiedza ogólna z obszaru IT oraz obycie się ze słownictwem będzie dużym atutem podczas rekrutacji. Dlatego zachęcam Cię do odsłuchania wszystkich odcinków podcastu oraz zapisania się do newslettera, dzięki któremu nie przegapisz żadnego nowego odcinka!

Słuchaj także na:

Udostępnij ten artykuł:

Polecana książka

Czysty kod. Podręcznik dobrego programisty
Robert C. Martin

Mentoring to efektywna nauka pod okiem doświadczonej osoby, która:

  • przekazuje Ci swoją wiedzę i nadzoruje Twoje postępy w zdobywaniu umiejętności,
  • uczy Cię dobrych praktyk i wyłapuje złe nawyki,
  • wspiera Twój rozwój i zwiększa zaangażowanie w naukę.