Niedawno pisałem o systemach kontroli wersji kodu źródłowego. Dziś będzie o integracji kodu. A konkretnie - o Ciągłej Integracji (Continuous Integration). W skrócie CI.
(Tradycyjnie już uprzedzam, że jeżeli Czytelnik jest w temacie Continuous Integration, nie znajdzie tutaj niczego nowego. Lepiej spędzić ten czas grając kulki. Można też wyprowadzić dziecko na spacer)
Duże rozwiązania informatyczne są zazwyczaj skonstruowane na bazie wielu różnych technologii. Przykładowo, interfejs może być serwowany jako applet Javy z serwera www, dane mogą zalegać na serwerze SQL, logika biznesowa może być osobnym serwerem napisanym w, dajmy na to, Pythonie, a komunikacja między tymi wszystkimi komponentami może odbywać się za pośrednictwem warstwy middleware napisanej w C#.NET. Takie rozwiązania są całkiem popularne i - jak widać - nawet w najprostszym przypadku mamy 5 różnych technologii (Java, Apache, SQL, Pythin, C#) współpracujących ze sobą.
Nad rozwojem takiego projektu pracuje na ogół spora grupa (a w zasadzie kilka grup) programistów. Każdy pobiera swój kod z repozytorium VCS, wprowadza zmiany i wysyła je z powrotem do repozytorium. Po pewnym czasie zmiany względem wersji oryginalnej są na tyle duże, że prędzej czy później dochodzi do sytuacji, w której kolejna (niewielka) zmiana powoduje niezamierzony efekt uboczny w całkiem innym zakątku projektu. I tu zaczynają się schody - albo trzeba wycofać dużą ilość zmian i napisać kupę kodu od nowa, albo aplikuje się łaty programowe żeby obejść problem - innymi słowy, bałagan, zamieszanie i strata czasu (a czas to pieniądz).
W sukurs przychodzi tu właśnie Ciągła Integracja, czyli CI.
CI to nic innego jak dokładna kopia środowiska produkcyjnego sprzężona z systemem kontroli wersji kodu - być może dodatkowo okrojona do rozsądnych rozmiarów. Jeżeli w środowisku produkcyjnym mamy 500 TB danych z ostatnich 20 lat, wykonanie kopii tego środowiska na potrzeby CI byłoby raczej kosztowne - tak więc redukuje się te 500 TB do 5TB z ostatnich dwóch miesięcy - a cała reszta pozostaje bez zmian, jest więc dokładną kopią środowiska produkcyjnego.
CI potrafi wykryć zmianę w repozytorium kodu a następnie w automatyczny sposób skompilować nową wersję, po czym wysłać kompilat w miejsce docelowe i wykonać serię automatycznych testów. Dodatkowo, może uruchomić serię testów w modułach zależnych od tego właśnie zmodyfikowanego, co minimalizuje szanse wystąpienia nieoczekiwanych błędów w innych częściach systemu.
Po początkowym skonfigurowaniu CI cały proces odbywa się w zasadzie automatycznie. Wyniki CI są na bieżąco dostępne (zazwyczaj jako strona www w lokalnym intranecie). Dodatkowo, po prawidłowym zakończeniu cyklu CI dla jakiegoś modułu, pojawia się kilka dodatkowych opcji: można pobrać aktualną wersję kodu źródłowego tego modułu, można zainicjalizować wykonanie kompilatu w zadanym środowisku (testowym, developerskim, produkcyjnym, integracyjnym lub jakimkolwiek innym aktualnie dostępnym), można przeglądać logi CI (to ostatnie jest szczególnie przydatne przy wystąpieniu błędów) i tak dalej.
Wszystko pięknie, ale jak to wygląda od strony praktycznej?
Ano, najbardziej bolesne jest początkowe skonfigurowanie CI. Również należy pamiętać o tym, że żeby CI miało sens, musimy mieć serię testów jednostkowych ("unit tests") skonstruowanych dla każdego elementu naszego rozwiązania - o ile pisanie Unit Testów jest solidnie wspierane (i w miarę zautomatyzowane) dla większości współczesnych środowisk programistycznych, o tyle np. dla języków typu SQL czy MDX nadal trzeba rzeźbić wszystko na piechotę.
Drugą (i w zasadzie ostatnią) wadą CI jest początkowy koszt sprzętu i licencji. Trzeba bowiem zbudować dokładną kopię systemu produkcyjnego. Można (i na ogół się to robi) sobie zwirtualizować całe środowisko, dzięki czemu zaoszczędzi się na sprzęcie.
Trzeba również pamiętać, żeby CI faktycznie odwzorowywało środowisko produkcyjne a nie deweloperskie. Serwery deweloperskie są na ogół lekko "zabałaganione" i kod, który na serwerze deweloperskim działa poprawnie, może pójść w maliny na produkcji.
Trzeba również stworzyć proces odtwarzania "odchudzonego" środowiska produkcyjnego w środowisku CI, i aplikować ten proces w regularnych odstępach czasu (na ogół co kilka miesięcy, czasem raz na rok) w celu utrzymania środowiska CI w "świeżej" kondycji. Wynika to z faktu, że każdy restart środowiska CI powoduje przywrócenie początkowej wersji produkcyjnej, a następnie przyrostowe zaaplikowanie wszystkich zmian. Po kilku miesiącach ilość zmian do zaaplikowania przy każdym restarcie powoduje, że czas oczekiwania na pełną gotowość CI staje się zbyt długi.
A dalej? Dalej to już sama przyjemność. Aplikujemy zmiany w kodzie do repozytorium kodu, czekamy kilka sekund i sprawdzamy w CI czy wszystko się poprawie skompilowało i przetestowało. Chcemy zapuścić zmiany na produkcji? Kilka kliknięć w CI i gotowe. Ostatnia zmiana spowodowała totalną katastrofę? Dezaktywujemy ją w CI, restartujemy i gotowe. Ogólnie rzecz biorąc, miód, malina.
Na koniec, tradycyjnie...
- Pani się nie boi. Ten pies nie gryzie.
- Biedny... To co on jada? Owsiankę?
Jeżeli chcesz do komentarza wstawić kod, użyj składni:
[code]
tutaj wstaw swój kod
[/code]
Jeżeli zrobisz literówkę lub zmienisz zdanie, możesz edytować komentarz po jego zatwierdzeniu.