Inżynieria oprogramowania

Ciągła integracja




Wstęp


W raz z rozwojem metodyk programowania zwinnego zaistniała potrzeba stworzenia narzędzi wspomagających automatyzację niektórych procedur związanych z budowaniem, testowaniem i dokumentowaniem kodu. Choć istniały narzędzia takie jak maven, a znakomita większość IDE wspierała m.n. zarządzanie projektem to brakowało narzędzia pozwalającego na jeszcze lepszą automatyzację procesów.
Takim narzędziem są systemy ciągłej integracji.

Motywacja


W każdym projekcie informatycznym możemy wyróżnić kilka powtarzalnych kroków wykonywanych przez wszystkich programistów uczestniczących w projekcie. Te kroki to:

  • stworzenie interfejsu dla danego elementu (klasy, modułu).
  • stworzenie zestawu testów jednostkowych dla tego interfejsu.
  • kodowanie interfejsu i uruchamianie testów jednostkowych.
  • uzupełnienie dokumentacji.
  • wysłanie kodu do wspólnego repozytorium.

Każdy z tych kroków dotyczy zazwyczaj kodu nad którym pracuje dany programista. Bardziej rozbudowane zadania takie jak uruchamianie wszystkich testów jednostkowych w celu weryfikacji poprawności kodu, uruchamianie testów integracyjnych czy też generowanie dokumentacji są zazwyczaj przerzucane na jednego z uczestników projektu lub też zaniedbywane i wykonywane w trakcie wdrażania do testów akceptacyjnych.
Wynika to z faktu, że zadania te są czasochłonne, monotonne, powtarzalne i mało ciekawe. Jednym słowem nudne. Można je zatem wykonywać automatycznie stosując odpowiednie narzędzia.
Automatyzacja pozwala też na zaoszczędzenie czasu osób biorących udział w projekcie. Jeżeli narzędzie będzie potrafiło cyklicznie wykonywać zadania związane z weryfikacją kodu to rola odpowiedzialnego za to programisty będzie ograniczać się tylko do sprawdzenia rezultatów zadania. W przypadku niepowodzenia narzędzie będzie też wstanie wysłać informację do osób związanych z projektem o problemie. Samo niepowodzenie może zostać zdefiniowane na wiele sposobów. Począwszy od błędów kompilacji, poprzez niepoprawne rezultaty testów, a skończywszy na zbyt niskim pokryciu kodu testami czy brakach w dokumentacji. Narzędzie takie, czyli właśnie serwer ciągłej integracji (CI), pozwala ponad to na skupieniu w jednym miejscu informacji dotyczących wielu projektów. Oznacza to kolejne oszczędności i ujednolicenie sposobu zarządzania projektami w ramach firmy.  
Podsumowując możemy powiedzieć, że chcąc:

  • oszczędzić czas programistów
  • zautomatyzować zadania związane z weryfikacją kodu
  • ułatwić zarządzanie kodem

należy użyć narzędzi CI.

Co w chodzi w skład CI


Serwer CI choć jest najważniejszym elementem nie jest jedynym, który wchodzi w skład systemu CI. Inne elementy to:

  • repozytorium kodu
  • serwer (zazwyczaj web) przechowujący m.n. wygenerowaną dokumentację, rezultaty testów czy skompilowany kod.
  • opcjonalny serwer poczty albo komunikatora służący do rozsyłania informacji.

Omówmy teraz każdy z tych elementów

Repozytorium kodu


Jest to serwer, na którym znajduje się kod źródłowy projektów. Kod do repozytorium wysyłają programiści w miarę postępu prac. Dobra praktyka zalecana przez m.n. Martina Fowlera1 mówi, że każdy programista powinien przynajmniej raz dziennie wysłać kod do repozytorium. W systemie CI repozytorium jest zazwyczaj najważniejszym elementem, na którym opiera się proces budowy kodu.

Repozytorium wyników


Zazwyczaj jest ono zintegrowane z serwerem CI. Warto jednak pamiętać, że może istnieć konieczność udostępnienia wyników na innym serwerze. Specyficzną odmianą repozytorium wyników są repozytoria zależności, z których korzysta np. Maven. Należy zatem pamiętać, że zarówno skompilowany kod jak i wygenerowana dokumentacja mogą zostać umieszczone poza serwerem CI.

Serwer komunikacyjny


W praktyce wszystkie systemy CI udostępniają informacje o wynikach za pomocą agregatorów treści takich jak RSS czy Atom. Warto jednak zadbać o to by serwer CI był wstanie jak najszybciej poinformować programistów o wynikach. Jest to szczególnie ważne w przypadku gdy dane zadanie zakończy się niepowodzeniem. Idealnie w tej roli sprawdza się  komunikator sieciowy np. Jabber albo serwer pocztowy ze skonfigurowanym oprogramowaniem grup dyskusyjnych. Serwer CI wysyła wtedy informację do zainteresowanych.

Ogólne zasady działania CI


Każdy z serwerów CI działa w trochę inny sposób, ale ogólna zasada działania jest taka sama dla wszystkich rozwiązań. Mówiąc o projekcie w systemie CI mamy na myśli pojedyncze zadania. Zadaniem może być proste przeprowadzenie kompilacji, uruchomienie testów, wygenerowanie dokumentacji. Może też być bardziej złożone na przykład kompilacja, uruchomienie testów i wdrożenie na serwerze testowym. Zadania mogą od siebie zależeć tworząc całe łańcuchy, które odzwierciedlają kolejne kroki bardziej skomplikowanych procedur.
Zadania mogą być uruchamianie ręcznie przez programistę, ale zazwyczaj istnieje możliwość skonfigurowania cyklicznego uruchamiania z uwzględnieniem różnych warunków. Przykładowo zadanie kompilacji i przetestowania kodu może być uruchamiane tylko wtedy gdy w repozytorium pojawią się zmiany. Samo odpytywanie repozytorium będzie już realizowane cykliczne w zadanych odstępach czasu. Dopiero gdy zmiany pojawią się w repozytorium zostanie uruchomiony proces kompilacji.
Wynika z tego, że co do zasady zadania rozpoczynają się od sprawdzenia stanu repozytorium. Oczywiście nie jest to konieczne przy niektórych rodzajach zadań, ale te są zazwyczaj rzadko spotykane. Po pobraniu kodu z repozytorium serwer CI przystępuje do głównego zestawu czynności czyli kompilacji, testowania bądź np. generowania dokumentacji. Po zakończeniu tych zadań wyniki są agregowane do zainteresowanych osób lub też są uruchamiane kolejne zadania owiązane z tym zadaniem.

Jaki powinien być kod by CI miało sens


Istnieje kilka zasad dotyczących kodu oraz pracy, które ułatwiają wdrożenie CI w projekcie.

Kod z repozytorium powinien się kompilować


Nie jest to oczywiste. Wielu programistów traktuje repozytorium jak miejsce, w którym wygodnie składuje się kopię zapasową kodu. Bez względu na to czy dany kod się kompiluje czy też nie. Jest to zła praktyka. Kod, który nie kompiluje się powinien zostać wydzielony do osobnej gałęzi w repozytorium i dopiero po wprowadzeniu wszystkich zmian powinien zostać z powrotem dołączony do głównego repozytorium.
Jeżeli kod nie będzie się kompilował serwer CI zgłosi błąd i będzie powtarzał zgłoszenie do czasu poprawienia kodu. Może to powodować np. wstrzymanie publikacji działającej wersji na serwerach. W dodatku będzie blokowało prace innych programistów.

Kod powinien wykorzystywać narzędzia do automatycznej kompilacji


Głównym założeniem CI jest automatyzacja zadań. Jeżeli kod wymaga dodatkowych prac przed kompilacją, które nie mogą zostać zautomatyzowane, to wdrożenie go w ramach CI nie ma sensu.

Kod powinien być samotestujacy


Podobnie jak w przypadku kompilacji testy powinny być integralną częścią kodu. Po kompilacji powinna być możliwość ich uruchomienia w ramach tego samego zadania. Pozwala to na weryfikację kodu pod kątem poprawności działania.

Wszystkie zmiany wprowadzamy do określonej godziny


Skoro każdy programista powinien codziennie wysyłać swój działający kod do repozytorium to ważne jest by zmiany były dokonywane do pewnej ustalonej godziny. Pozwala to na zaplanowanie kolejki zadań na serwerze CI co przekłada się na niższe koszty jego eksploatacji.

Zadania powinny być małe


Oczywiście w miarę możliwości. Chodzi tu generalnie o tworzenie prostych zadań, które nie zawierają wielu skomplikowanych kroków. Pozwoli to na szybsze wyłapywanie błędów oraz ułatwi zarządzanie zadaniami.

Każdy widzi rezultaty ostatniego zadania


Jest to o tyle ważne, że dzięki tej zasadzie każdy z programistów zainteresowanych danym projektem wie jaki jest aktualny stan prac. Pozwala to na lepsze zaplanowanie innych zadań z uwzględnieniem stanu danego projektu.

Powinna być możliwość automatycznego zdrożenia


Jeżeli kompilacja i testy zakończą się powodzeniem powinna być możliwość automatycznego wdrożenia nowej wersji oprogramowania na serwerach lub w repozytorium. Pozwala to na oszczędzenie czasu programistów.

Wady


Systemy CI mają kilka istotnych wad:

  • wymagają konfiguracji i utrzymania.
  • wymagają kodu dobrej jakości. Szczególnie kodu z odpowiednią ilością testów by móc korzystać z zalet automatyzacji testów.
  • mogą wymagać znacznych nakładów sprzętowych.

Szczególnie wymieniona w ostatnim punkcie cecha może okazać się dużym zagrożeniem. Wraz z rozwojem systemu CI w firmie pojawia się zapotrzebowanie na coraz to mocniejsze serwery zdolne prowadzić wiele zadań związanych z kompilacją na raz oraz na coraz większe dyski w celu przechowywania wyników. Pomimo to warto jednak  zainwestować w serwer CI ponieważ ułatwia on pracę oraz obniża koszty związane z testami i wdrożeniem oprogramowania.


[1] http://martinfowler.com/articl[...]acticesOfContinuousIntegration

2 komentarze

Koziołek 2011-09-29 21:16

@kadoel, dostawców CI jest od cholery i ciut ciut. Przykłady raczej w tekstach o konkretnych rozwiązaniach.

kadoel 2011-09-29 14:59

Spodziewałem się dłuższego artykuł z przykładami.