czwartek, 23 czerwca 2011

Wprowadzenie do ciągłej integracji.

Czym jest ciągła integracja? Myśle że to pojęcie najlepiej oddaje cytat Martina Fowlera:

Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly. This article is a quick overview of Continuous Integration summarizing the technique and its current usage. 

Ciągła integracja jest praktyką z inżynierii oprogramowania w której integracja projektu odbywa się regularnie i często.Każda integracja jest weryfikowana przez automatyczne budowanie projektu
(włącznie z testami).Takie działanie ma na celu wczesne wykrycie błędów i ich usunięcie w etapie implementacji.


Wpływ CI na funkcjonowanie projektu

1. Zmniejsza się ryzyko w projekcie – dzięki wdrożeniu continuous integration projekt jest pod ciągłą kontrolą i monitoringiem.

2. Minimalizuje się ilość czynności, które należy wykonać w ramach procesu- dzięki automatyzacji budowania oprogramowania i czynności
wdrożeniowych.

3. W projekcie zawsze mamy do czynienia z oprogramowaniem gotowym do wdrożenia – dzięki zastosowaniu continuous integration, zespół jest zobligowany do tworzenia projektu, który umożliwia jego wdrożenie w dowolnym momencie.

4. Osoby odpowiedzialne za projekt mogą samodzielnie zbadać postęp prac w projekcie – wymiernym wskaźnikiem, który określa postęp projektu, jest stan oprogramowania, które można wdrożyć.

5. Większa pewność w odniesieniu do produktu – continuous integration wymusza, aby wytwarzane oprogramowanie weryfikować pod kątem za-implementowanych funkcji.


Budowanie z ciągłą integracją

Aby opisać proces ciągłej integracji posłużę się przykładem:
Rozpoczynając pracę musimy pobrać aktualną wersje (poprzez check out) naszego projektu z repozytorium
na maszynę na której będziemy pracować (Jest ona określana jako Mainline)
Po czym wykonujemy swoje zadanie, wciąż pracując na lokalnej kopi.
Piszemy lub zmieniamy automatyczne testy. Często określa się to jako kod samo testujący. ( Popularne xUnity) Gdy już zakończymy pracę. Uruchamiamy automatyczne budowanie projektu
Czyli komplikujemy, linkujemy do pliku wykonywalnego i odpalamy automatyczne testy.
Jeśli budowanie i testy przebiegły pomyślnie to możemy mieć nadzieję że nasz kod jest dobry.
Teraz pora na udostępnienie naszego nowego kodu w repozytorium.
Aby tego dokonać musimy wpierw uaktualnić naszą kopię o kod który został umieszczony przez innych programistów podczas naszej pracy i przebudować cały projekt.
Jeśli zmiany innych programistów nie współgrają z moimi zmianami,
poprzez problemy w kompilacji lub testach to konieczne jest dokonanie poprawek.
Robimy to dopóki nie uzyskamy prawidłowo działającej kopi zsynchronizowanej z mainline.
Po tym można wykonać commit, ale nie kończy on naszej pracy.
Musimy jeszcze raz zbudować cały projekt, lecz tym razem na serwerze do intergracji ( zwykle jest to maszyna na której znajduje się także repozytorium).
Gdy operacja się powiedzie możemy uznać że zakończyliśmy naszą pracę.
Ta operacja może zostać wykonana ręcznie przez programiste lub automatycznie przez narzędzia do integracji. Zaletą CI jest szybkie wyłapywanie błędów integracji.
Jeśli zdarzy się konflikt pomiędzy dwoma programistami to zwykle jest on szybko wyłapywany przez drugiego z nich.

Szybki przykład błędu






Dwóch programistów szybko po sobie commituje - pierwszy wprowadził poprawki A,
a drugi o tym nie wiedział i zrobił poprawki B. Pierwszy robi builda tylko z A. Commit zostaje zatwierdzony.
Drugi robi builda z A+B i jeśli były jakieś konflikty to wykrywany jest błąd.

Nawet jeśli nie będzie konfliktów to i tak błędy są wykrywane bardzo szybko.
Środowisko ciągłej integracji nie pozwala na przetrzymywanie przez dłuższy czas wadliwej wersji projektu.
Dobry team powinien mieć wiele poprawnych buildów na dzień.
Od czasu do czasu mogą się pojawić złe, ale będą one szybko poprawiane.Serwerem integracji będziemy nazywać maszynę na której przeprowadza się ten proces.Zwykle jest to maszyna na której jest przechowywane repozytorium.


Praktyki Ciągłej integracji.


Utrzymanie jednego źródła repozytorium.

Projekty oprogramowania składają się często z wielu plików które muszą być dokładnie zorganizowane.
Nie jest wieć niespodzianką że przez lata rozwoju oprogramowania powstało wiele narzędzi do zarządzania zbiorami plików. (Source Code Managment tools, Version Control Systems) Podstawą jest wybranie dobrego systemu. Najbardziej znanym i darmowym systemem kontroli wersji jest subversion, następca bardzo popularnego CVS'a).

Wszystko co jest potrzebne do wykonania buildu powinno się znajdować w repozytorium.
Włącznie z skryptami testowymi, plikami konfiguracyjnymi, schematami bazy danych,skryptami instalacyjnymi
czy dodatkowymi bibliotekami.Podstawową zasadą jest podejście projektu z "dziewiczą" maszyną, pobranie plików z repozytorium i poprawne zbudowanie całego systemu. Tylko minimalna ilość plików powinna znajdować się na maszynie developera. Zazwyczaj są to duże pliki lub trudne do zainstalowania lub skonfigurowania np: Środowisko uruchomieniowe czy system bazodanowy.

Automatyzacja budowania projektu.

Tradycyjnie budowaniem nazywamy compilacje, likowanie i dodatkowe rzeczy potrzebne
do stworzenia wykonywalnego programu.
Przekształcenie źródeł w działający system może być często skomplikowanym procesem w skład którego wchodzi
kompilacja, przenoszenie plików, załadowywanie schematów do baz danych.
Jednakże wiele tych zadań może zostać zautomatyzowanych.
np za pomocą Ant'a czy Ruby.
Zdecydowana grupa programistów używa ide które mają w sobie zintegrowany Build managment Proces.
Może ona tylko i wyłącznie służyć do indywidualnej pracy programisty.
Wersja na serwerze powinna używać do budowania skryptów.
W przypadku pluginów do eclipse musimy użyć techniki zwanej headless build.
Dzięki narzędziu PDE(Plug-in Development Environment) możemy uruchamiać pluginy poza środowiskiem (IDE)

Automatyczne testy.

Automatyczne testy stosujemy by możliwie szybko i efektywnie
wyłapać pojawiające się błędy oprogramowania.
Możemy to zrobić poprzez dołączenie ich do procesu budowania całej aplikacji.
Testowanie nie jest idealne, ale pozwala nam na wyłapywanie wielu błędów.
Kod który jest zaopatrzony w procedury testujące nazywamy Self Testing Code.
Wynik działania testów powinien jawnie wskazywać błąd.
Rodzina XUnit jako zestaw oprogramowania do przeprowadzania testów.

Każdy commituje każdego dnia.


CI pozwala deweloperowi powiadomić innych o zmianach które dokonał.
Dzięki częstemu commitowi można szybko wykrywać konflikty pomiędzy dwoma programistami
Konflikty które zostają niewykryte przez dłuższy okres mogą być ciężkie do rozwiazania.
Faktem jest że updatując swoją wersję przed commitowaniem jej do repo możemy wyłapywać konflikty integracji z taką samą łatwością jak konflikty tekstowe.
Gdy build jest zaopatrzony w  procedury testujące możemy także wyłapywać konflikty w działającym kodzie. Czym częstsze commity tym więcej szans na wyłapanie konfliktów i szybsze ich usuwanie.
Częste udostępnianie kodu dzieli pracę programisty na małe kawałki.Przeszkodą w realizacji tego założenia jest przeświadczenie o tym że wciągu tych paru godzin nie można zrobić niczego sensownego.

Każdy commit powinien budować kod na serwerze do intergracji.


Dzięki codziennym commitom, budowanie i testowanie naszego projektu przeprowadzane jest wiele razy dziennie.Najważniejszym jest by po zakończeniu każdego etapu prac mainline zostawało w zdrowym stanie.
W praktyce często jest to bardzo trudne.
Powodem tego może być brak dyscypliny. Programiści nie wykonują update'a i builda przed commitem
lub mogą to być różnice środowiskowe pomiędzy maszynami deweloperów.

Jeśli budowanie na serwerze do integracji zostanie przeprowadzone pomyślnie i testy nie wykarzą błędów
to takiego commita możemy uznać za prawidłowego. W przeciwnym razie muszą zostać dokonane poprawki.

Budowanie mainline można zapewnić na dwa sposoby, manualnie i używając CI server.
Manualnie czyli identycznie jak na swojej maszynie.
Programista zrzuca head'a na integration serwer i wykonuje budowanie, dokładnie śledząc cały proces.
(podobne do wizyt w pokoju wielkiego brata)
Budowanie automatyczne z użyciem CI tools jest bardziej skomplikowane ale to ono jest częściej wykorzystywane Serwer CI działa wtedy jako monitor repozytorium. Po każdym zakończonym commicie zrzuca aktualną wersję na integration serwer , inicjalizuje budowanie, i zawiadamia programistę o rezultacie całego procesu. Praca programisty kończy się gdy ten dostaje pozytywną wiadomość zwrotną. Zazwyczaj w formie emaila.


Istnieje wiele narzędzi pełniących funkcje serwera integracji.
Do najpopularniejszych z nich możemy zaliczyć Cruise Control, Hudson, Continuum
Wiele instytucji robi regularne buildy w ściśle określonym czasie, np w nocy.Nie ma to nic wspólnego z buildami ciągłej integracji.Nocne budowanie sprawdza czy w kodzie nie znajdują się bugi które nie zostały wykryte podczas dnia. Jeśli zostaną one nie wykryte przez dłuższy czas ich usunięcie może być bardzo trudne.

Spraw by system budował się szybko.


Czas budowania ma kluczowe znaczenie.
Podczas procesu ciągłej integracji wykonuje się wiele commitów, a co za tym idzie wiele budowań.
Często można je znacznie skrócić eliminując tzw. wąskie gardła.
W rozbudowanych projektach często proces integracji spowalniany jest przez testy,
które pracują na zewnętrznych źródłach np bazie danych.
Próby przyspieszania budowania mogą pociągać za sobą spadek wykrywania błędów.
Ważnym jest aby osiągnąć pewien złoty środek w tej materii.
Najlepszym rozwiązaniem przyspieszającym budowanie projektu jest wprowadzenie tzw. "staged build"

a) Two Staged build. 

Pierwsza część wykonuje kompilacje i najbardziej zlokalizowane zestawy testów
czyli takie które nie dotyczą zewnętrznych źródeł.
Używa się jej w głównym cyklu CI np jako commit do repozytorium (Commit Build).
Druga cześć obejmuje wszystkie testy, włączając w to testy na bazie danych i
jest ona wywoływana tylko wtedy gdy istnieje taka potrzeba lub co jakiś czas.
Jeśli druga część znajdzie błąd to powinniśmy rozważyć dodanie do commit build (pierwsza część)
dodatkowy test który ten błąd wychwyci.
Dzięki temu ten błąd zostanie poprawiony w commit build.

b) Rozszerzenie Staged Build.

Podstawowa zasada 2 faz budowania może być rozszerzona do dowolnej liczby późniejszych budowań.
Budowania po commicie mogą być wykonywane równolegle np przez dwie maszyny dokonywujące po połowie testów.
Używając równoległych budowań 2 fazy można wprowadzić wiele automatycznych testów,
włączając w to testy wydajności,do
regularnego procesu budowania.

Testuj w środowisku jak najbardziej zbliżonym do produkcyjnego


Platforma testowa powinna być identyczna jak platforma na której piszemy oprogramowania.
Dotyczy to zarówno wersji oprogramowania, jak i rodzaju (np systemu,bazy danych).
Od tej reguły odchodzi się przypadku aplikacji desktopowych w których zależy nam na przenośności rozwiązań.
W takim przypadku oprócz klonu systemu zaleca się testowanie projektu w różnych środowiskach.
np wykorzystując wirtualizację.

Zapewnij wszystkim dostęp do najnowszego skompilowanego projektu.


W każdym momencie trwania projektu istnieje potrzeba jego uruchamiania do demonstracji,
testów badawczych, czy obserwowania zmian.
By ułatwić to zadanie należy jawnie określić ścieżkę w której można znaleźć aktualne pliki wykonywalne.
Użytecznym jest umieszczenie kilku ostatnich skompilowanych wersji projektu.


Każdy widzi co się zdarzyło.

Każdy możne łatwo przeglądać aktualny stan systemu oraz zmiany które zostały wdrożone.
Dotyczy to szczególnie informacji o stanie mainline.
W zaawansowanych systemach CI ( Cruise, Hudson ) wszystkie informacje są dostępne z poziomu przeglądarki.
Najważniejszą z nich jest obecny stan systemu często sygnalizowany w postaci czerownej i zielonej lampy.
Ponadto Cruise pozwala na sprawdzenie kto ostatnio budował projekt, jakie zmiany zostały w nim wprowadzone.
Udostępnia on historię zmian systemu znacząco ułatwiając pracę kierowników projektu.

Automatyzacja przenoszenia plików pomiędzy maszynami.

Do ciągłej integracji potrzebujemy wielu środowisk.
Jednego do uruchomienia testów commitu,
i jednego lub więcej by uruchomić drugie testy.
W związku z tym pliki wykonywalne muszą być przemieszczane wiele razy dziennie.
Tą czynność można także zautomatyzować.
Ważnym jest by posiadać skrypty które pozwolą na proste i
szybkie rozmieszczenie aplikacji pomiędzy środowiskami.

Korzyści z Ciągłej Integracji.

Ciągła integracja nie uwalnia nas od błędów, tylko sprawia że ich wykrywanie
i usuwanie jest szybsze i wygodniejsze.
Zmieniamy tylko mały kawałek systemu. W przypadku błędu nie musimy się cofać.
Możemy także użyć tzw Diff Debugging -
wykrywanie błędów poprzez porównanie obecnej wersji z poprzednią która jego nie zawierała.
W projektach w których zastosowano CI znacząco spada ilość błędów.
Wszystko jednak zależy od jakości zestawów testowych.

Zalety:

    Kiedy natchniemy się na błąd, programista może bardzo łatwo wrócić do 
    poprzedniej wersji projektu, wolnej od błędów, bez konieczności straty czasu na debugowanie.
    Problemy integracji są wykrywane i naprawiane w sposób ciągły.
    Szybkie ostrzeganie o zepsutym lub niekompatybilnym kodzie.
    Szybkie ostrzeganie o konfliktowych zmianach.
    Natychmiastowe testowanie wszystkich zmian
    Stała dostępność aktualnego buildu dla testowania, demonstracji lub wydania.
    Brak odrębnych sesji integracyjnych
    Poprawa pracy zespołowej
    Ciągła integracja to jedna z podstawowych praktyk Extreme Programming.


   
Od czego zacząć ?

Pierwszym krokiem w Ci jest zautomatyzowanie builda.
Umieść wszystko co potrzebujesz w do wykonania builda w systemie kontroli wersji
i spraw by build mógł się wykonywać po napisaniu jednej komendy.
Na początek można spróbować budować projekty na żądanie lub wykonać automatyczny nocny build.

Kolejnym krokiem będzie wprowadzenie automatycznych testów.
Spróbuj zidentyfikować główne miejsca w których mogą występować błędy i
napisz testy eksponujące te nieprawidłowości.Spróbuj przyspieszyć commit build.
Kiedy startujesz z nowym projektem to od razu wprowadź do niego ciągłą integrację.

Na podstawie:
"Continuous integration" by Paul Duvall

Więcej informacji w

http://en.wikipedia.org/wiki/Continuous_integration
http://oreilly.com/catalog/0636920016489




Brak komentarzy:

Prześlij komentarz