Kontinuální integrace: lék na lidské chyby v deploymentu

2. 11. 2016
Doba čtení: 7 minut

Sdílet

Kontinuální integrace je nutný doplněk vývoje, který za pomocí automatizace a standardizace pomáhá efektivně předcházet chybám při nasazování aplikací do provozu.

Co je kontinuální integrace a jaké má fáze

Člověk není robot, ale v IT praxi se opakuje řada kroků, které stojí za automatizaci. Při vývoji aplikací se stále opakují kroky, které jsou nudné – a lidé pak dělají chyby, stroje nikoliv. Kontinuální integrace je lék na takové neduhy. Na co všechno ji lze využít?

Kontinuální integrace považuji za nutný doplněk vývoje, často adrenalin a občas i zábavu. Mým nejoblíbenějším nástrojem je Jenkins CI, se kterým mám největší zkušenosti. Podobných nástrojů sloužících kontinuální integraci  a automatizaci sestavení a nasazení lze najít celou řadu. Každý z nich má své výhody a také nevýhody. Kritéria pro výběr mohou být různá od ceny přes uživatelskou přívětivost až po možnost integrace na jiné nástroje a systémy. Než však nahlédneme na konkrétní nástroje, pojďme si nejdříve povědět něco o kontinuální integraci obecně.

Vývoj aplikací prochází různými fázemi od návrhu přes vývoj až po testování. Některé mohou běžet paralelně a zvláště ve vývoji se stává, že více pracovníků tvoří paralelně více či méně provázané části aplikace.

Ty je pro zákazníka potřeba spojit do funkčního celku, a to nemusí být úplně jednoduché. Jednotliví členové týmu odevzdávají snad tu nejlepší práci, kterou si otestovali a dali by za ni ruku do ohně. Nežijeme však v ideálním světě a mezi příspěvky různých lidí nám občas vznikají konflikty, případně někdo nepozorností nebo nedbalostí zanese do projektu chybu.

Aby se klient nebo uživatelé nějakého systému nesetkali s nějakou chybou, je možné tomu předcházet za pomoci principů kontinuální integrace (průběžnou integrací, v anj. continuous integration), což zahrnuje využití různých nástrojů k tomu určených a také zavedení procesů omezujících chybovost.

Ve větším i menším vývojovém týmu je potřeba opakovaně sestavovat projekt.

To znamená, že z jednotlivých částí, které vyvíjí samostatné týmy (jednotlivci) je třeba sestavit funkční projekt či aplikaci, kdy jednotlivé moduly spolu navzájem bez problému komunikují. Zároveň je nutné, aby v případě, že se vyskytne nějaká chyba, byly odpovědné osoby o této chybě včas informovány (tzn. fungoval systém notifikací na pověřené osoby).

Přece jenom by byl problém, kdyby například uživatelé internetového bankovnictví najednou nemohli posílat platby, protože některý z vývojářů udělal chybu při implementaci a nikdo z odpovědných osob o tom nevěděl. A právě nástroje pro kontinuální integraci hlídají, aby se tak nestalo a vše proběhlo hladce jako po másle.

Proto by proces kontinuální integrace měl obsahovat i automatizované testování.

Pozn. autora: Samozřejmě lze sestavení a deployment aplikace provést teoreticky i ručně, potom by bylo otázkou zda jde o “kontinuální” integraci. Nehledě na možnou chybovost (a časovou náročnost) není žádoucí mít procesy závislé na přítomnosti vyškoleného personálu a je výhodné využít nějaký existující nástroj.

Takovými nástroji jsou Jenkins CI, Atlassian Bamboo, Teamcity, Travis CI, aj. Výběr konkrétního je otázkou osobních preferencí, všechny vyjmenované zvládnou vyřešit dílčí úkoly nastíněné v tomto článku.

První fáze kontinuální integrace – stažení aktuálního zdrojového kódu

Prvním krokem u kontinuální integrace je stažení aktuálního kódu ze source code management (SCM) systému.

Pozn. autora: SCM systém řeší následující:

  • hosting – fyzické umístění repositářů kódu použitého verzovacího systému,
  • centralizaci vyvíjeného kódu pro odevzdávání a kontrolu,
  • nastavení bezpečnosti (nastavení přístupu ke konkrétním repositářům určitým uživatelským skupinám),
  • kontrola kódu,
  • na SCM mohou být napojené další nástroje (trackování požadavků, dokumentace,…).

Proto je pro nás použití SCM naprostou nutností. Podrobnější úvaha by vydala na samostatný článek, zmíním jen nejdůležitější detaily.

Osobně používám verzovací systém Git, vy možná používáte Mercurial SCM nebo Apache Subversion. Koho zajímají podrobnosti, může čerpat ze samostatném článku k využití verzovacích systémů.

Výjimkou z verzování by měla být konfigurace specifická pro konkrétní běhové prostředí. Přihlašovací údaje pro připojení k produkční databázi, klíče pro připojení k API apod. by z bezpečnostního hlediska neměl mít k dispozici každý vývojář a také by neměly putovat “veřejným prostorem”.

Kromě otázky bezpečnosti můžeme potřebovat na určité instanci nastavit specifickou úroveň debugování nezávisle na obecném standardu a toho dosáhneme právě využitím nezaverzované lokální konfigurace.

Každopádně zaverzovaný kód nám ještě pro běh aplikace nemusí ve své “surové podobě” stačit, protože po stažení zdrojového kódu musíme kód přetransformovat do spustitelné podoby.

Druhá fáze kontinuální integrace – sestavení projektu

Teoreticky může malý projekt vystačit s několika třídami a být sám o sobě jednoduchou aplikací. V praxi ale nechceme psát kód úplně na zelené louce a naopak je účelné využít jako základ nějaký z frameworků (Zend, Nette, Spring MVC,…), kdy máme jednak vyřešené základní předpoklady jako je bezpečnost, oddělení programové logiky oproti prezentační části a samozřejmě každý framework obsahuje věci, které máme připravené k opakovanému použití namísto stavění projektu úplně od nuly.

Frameworků a knihoven můžeme používat opravdu spoustu. Jejich definici a následné stahování potřebujeme řešit systematicky. Proto zde přichází na řadu akce jako composer install / update (PHP), maven install (Java), gradle build, které slouží právě ke stažení souvisejících knihoven a tím kompletaci projektu.

Třetí fáze – sestavení front-end kódu

Kromě vlastního programového kódu má aplikace nějaký front-end (interface) pro uživatele a v dnešní době front-end kodér běžně připraví styly pro less/sass preprocesor. Stejně jako v předchozím případě u programového kódu potřebujeme less/sass podklady kompilovat do CSS (do publikovatelné a použitelné podoby) a na to využíváme nástroje jako Grunt (The JavaScript Task Runner) a/nebo Bower (A package manager for the web).

Čtvrtá fáze – úpravy front-end kódu

Jak jsem zmiňoval výše, nedostáváme kód obvykle v cílové podobě. Kromě toho je naším druhotným cílem šetřit data a výkon (na serveru i na straně uživatele), a proto se snažíme front-end kód (CSS, JavaScripty, obrázky) převést do komprimované podoby.

Na front-end kód se hodí stejná pravidla jako na programový kód, měla by na něj být aplikována kontrola syntaxe a otestování potenciální (ne)chybovosti.

Takové operace jako minifikace, kompilace a testování mají u nás na starosti již výše zmiňované nástroje Grunt anebo Bower.

S výše uvedenými nástroji jsme schopni dostat hotovou podobu aplikace v potenciálně nasaditelném stavu. Před publikováním mezi reálné uživatele bychom si ji měli ještě otestovat. I nejsvědomitější vývojář může občas udělat chybu. Pokud spolu pracuje více vývojářů, může se stát, že odvedená práce každého z nich je sama o sobě funkční, ale vzájemná kombinace vykazuje nestandardní chování nebo chyby. A proto je třeba věnovat se kontrole kódu a testování.

Kontrola a testování u kontinuální integrace

Testy lze podle časového okamžiku spuštění rozdělit do skupin:

  • pre-commit (před odevzdáním),

  • pre-deploy (před nasazením),

  • post-deploy (po nasazení do cílového prostředí). 

V závislosti na povaze testu resp. strategii integrace mohou být spuštěny ještě předtím, než bude vývojářova změna integrována- pre-commit (viz např. npm pre-commit package, SonarQube pre-commit analýza) případně až po integraci – post-commit.

Testy v prvotní fázi nespojujeme s nástrojem kontinuální integrace, testování kódu probíhá již u vývojáře. Využíváme SonarQube a pre-commit testování probíhá přímo v IDE vývojáře za pomocí pluginů pro Eclipse nebo InteliJ. Pre-commit testy se vztahují ke zdrojovému kódu tzn. netestujeme běžící aplikaci, jde o kontrolu syntaxe, dodržených kódovacích konvencí, duplicity v navrhovaných třídách a obecně kontrolu kvality kódu.

V pre-deploy testování využíváme unit testy, kontrolujeme funkčnost a správnou implementaci určitých jednotek systému v podobě tříd nebo funkcí. Zde se dotýkáme problematiky “programování řízené testy” (Test-driven development), kdy testy byly napsány dříve než samotný kód a jsou v nich promítnuté všechny požadavky na funkcionalitu, bez jejichž splnění není možné pokračovat. V případě kladného výsledku můžeme dokončit deployment a následně přejít k post-deploy testům.

Po úspěšném nasazení pouštíme post-deploy testy:

  • Automatizované uživatelské testy –  vytvořené v nástroji Selenium IDE a spouštěné CI nástrojem v prostředí Selenium server.

  • Integrační testy ověřující funkčnost systému.

Některé projekty mají takovou povahu, že je chceme testovat i ručně.

Takovými jsou například elektronické bankovnictví a podobně zabezpečené aplikace, do kterých se mimo lidského uživatele nikdo nepřihlásí, některé operace mají kupříkladu dvoufaktorou autentizaci, kterou chceme otestovat reálným lidským testerem.

Kromě toho však existuje celá řada komponent jako formulářů a kalkulaček, které automatizovaně testovat lze. Základní test, že aplikace po updatu funguje a chová se dle očekávání, může být spuštěn automatem.

ict ve školství 24

Automatizované testování v dlouhodobém měřítku přináší:

  • opakovatelnost – testy probíhají podle stále stejného scénáře, za víceméně stejných podmínek,

  • časovou úsporu – oproti náročnému uživatelskému testování.

I přes veškerou snahu vývojového týmu může sestavení nebo testy skončit neúspěchem. O negativním výsledku se vždy musí někdo dozvědět (o tom kladném to není nutné vždy). Toto řešíme systémem notifikací, jemuž se budu věnovat v dalším článku.

Autor článku

IT konzultant společnosti Lundegaard se zaměřením na verzování, kontinuální integraci, správu nástrojů Jenkins CI, JIRA, Confluence a podpoře jejich provozu.