… aneb honba za nulovou chybovostí
Aktuálně dělám na projektu, který je zajímavý z několika pohledů. Jedná se o software pro medical devices, kde jsou kladeny vysoké nároky na zajištění kvality. A neméně zajímavou skutečností je střet historicky vodopádového korporátního přístupu se sílícím vlivem agilních technik. Rád bych popsal zajímavé oblasti naší práce s důrazem na postupy, které nám pomáhají zajišťovat požadovanou kvalitu.
Co vlastně děláme
Na úvod stručně ke kontextu naší práce. Máme v Olomouci tříčlenný vývojový tým a pracujeme pro německou zdravotnickou korporaci Maquet. Konkrétně spolupracujeme se softwarovým oddělením na vývoji systému Tegris. Ten integruje ovládání různých zařízení používaných na operačním sále do jedné aplikace. Ovládat se dají například chytré operační stoly, speciální světla, HD kamery, endoskop a další. Systém má mnoho pokročilých funkcí pro nahrávání a streamování multisource videa. Zajišťuje také různé agendy potřebné při operacích. Jedná se o softwarové řešení dodávané spolu se speciálním hardware, kvůli vysokým nárokům na systém a požadavkům na mnoho speciálních karet a portů. Prostě být operován na sále s tak moderním vybavením musí být snem každého pacienta. Nebo raději ne. ;)
Prvním naším projektem byla integrace ovládání videokonferenčních systémů. Zjednodušeně řečeno jsme vyvíjeli modul, který umožňuje při operaci provádět videokonferenční hovory a ovládat je z Tegrisu.
Aktuálním druhým projektem je ovládání zařízení, která jsou připojená k nové hardwarové sběrnici. Na tu lze nyní připojit chytré světelné hlavy a HD kamery používané na operačním sále. Každé zařízení má své vlastní hardwarové ovládací panely. Nově tato zařízení půjdou ovládat také přes systém Tegris. A to je naším úkolem.
Vývoj pro medical devices
Vývoj software pro medical devices má svá specifika. Pokud chcete software dodávat do států EU, pak musíte být kompatibilní s hromadou direktiv sjednocených pod MDD. Jedná se o tak složitou byrokracii, že je jen pár lidí na světě, kteří ji mají kompletně nastudovanou a nechají si zaplatit slušný peníz za základní proškolení. Když chcete prodávat do USA, pak musíte být zase kompatibilní s direktivami vydávanými americkou FDA. Ve výsledku to vypadá tak, že potřebujete ve firmě alespoň jednoho člověka na plný pracovní úvazek, který zkoumá, co musí jednotlivé softwarové komponenty splňovat a jaké nároky jsou kladeny na samotný vývojový proces. Takovému člověku opravdu nezávidím. ;)
Pro nás to znamená, že veškeré vývojové fáze musí být standardizované. Všechny meziprodukty vývojového procesu (požadavky, návrh, kód, testovací případy, …) musí být revidovány někým nezúčastněným. Američané vyžadují navíc diskutabilní 100% pokrytí testy. Velký důraz je kladen na fázi akceptačního testování, testuje se v různých podmínkách (laboratorní, reálné) a před každým release. Veškerá snaha je cílena na dosažení co nejmenší chybovosti v produkci.
Medical devices jsou navíc klasifikovány do několika tříd podle závažnosti následků v případě poruchy takového zařízení. Třeba class I jsou zařízení, jejichž výpadek neohrožuje zdraví pacienta. Class III jsou naopak zařízení, jejichž špatná funkčnost může vést k těžkým následkům nebo smrti pacienta. Např. bylo by hodně nepříjemné, kdyby vynechával kardiostimulátor se speciálním software nebo kdyby se zasekl endoskop pro mozkové operace. Náš projekt řeší světla na operačním sále, ty jsou class II. Kdyby světla zhasla nechtěným zásahem obsluhy nebo z důvodu chyby software, asi by na operačním sále nebylo příliš veselo.
Zadání a estimace projektu
Součástí zadání je více jak stovka různě pracných funkcionálních a systémových požadavků na vyvíjený modul, podrobný popis komunikačního protokolu pro hardwarovou sběrnici a vizualizace UI. Z centrály jsme si dovezli reálné železo, které nám zabírá jednu stěnu naší malé kanceláře.
Bylo potřeba se seznámit s problémem, udělat si jednoduchý prototyp pro komunikaci se zařízeními a rychle dodat orientační estimaci, aby byl hlavní projekťák spokojený. Využili jsme agilní techniku odhadování v abstraktních story points. Poměřovali jsme nejdříve jednotlivé requirementy relativně podle předpokládané pracnosti a oceňovali je s využitím čísel od pana Fibonacciho - 1, 2, 3, 5, 8, 13, 21. Nakonec byl každý bod vynásoben bulharskou konstantou, která měla promítnout abstrakci do reálnějších člověkodnů.
Specifikace architektury
Jeden ze systémových požadavků si vynutil, aby většina business logiky ovládání (nízkoúrovňová komunikace, řízení přístupu, zjišťování stavu zařízení, synchronizace, apod.) byla oddělena od hlavního systému do samostatné aplikace. Tato aplikace musela být zpřístupněna jako služba, kterou mělo mít možnost využívat více klientů. Požadavek zásadně ovlivňoval architekturu řešení. Nakonec bylo potřeba navrhnout několik konceptů, ze kterých byl vybrán ten nejvhodnější.
Vítězný koncept se musel rozpracovat do několika různě abstraktních UML diagramů. Hlavní struktura systému je zachycena pomocí komponentového diagramu. Jednotlivé komponenty pak mají své poddiagramy stále ještě na úrovni poměrně abstraktních podkomponent. Specifikace musela obsahovat popis dalších technických aspektů zvoleného řešení.
Z pohledu agilních technik je použití UML vhodné pro lepší vzájemné porozumění při diskuzi o problému. Zároveň se ale nedoporučuje trávit kreslením diagramů příliš času. Důležitá zpětná vazba přichází totiž až ze samotné implementace. Čím je feedback pozdější, tím jsou případné změny dražší. S ohledem na typ našeho projektu jsme ale při realizaci nuceni používat UML poměrně často.
Rozdělení do etap
Rozplánovali jsme celý projekt na menší etapy, které vzdáleně připomínají agilní iterace. Liší se však zásadně tím, že nemají pevný časový rámec. Vybrané requirementy se musí vyřešit všechny. To je opět úlitba centrálnímu projektovému managementu. Nevýhodou je, že se celá etapa natahuje, nejde vrátit nevyřešené úkoly do backlogu a práce tolik neodsýpají. Paralelní práce na více etapách současně nám navíc moc nefungovaly. I tak ale považujeme rozdělení do etap za lepší přístup než čistě vodopádový model. Zpětnou vazbu o postupu prací dostáváme poměrně rychle a případné “vracečky” nejsou tak bolestivé. Etapa v ideálním případě trvá tak 15 pracovních dnů a prochází všemi níže popsanými fázemi.
Analýza požadavků
Rozdělení požadavků do etap bylo provedeno na začátku projektu. Přesun požadavků mezi etapami není příliš oblíbená činnost u centrálního managementu. Někdy ale není zbytí. Stává se poměrně často, že požadavek je potřeba upřesnit nebo zcela změnit. Pak je dobré, abychom měli “zákazníka” komunikačně co nejblíže. “Změnová řízení” jsou někdy otázkou hodin, jindy zase dnů. Někdy se musí chování upřesňovat s výrobním oddělením ve Francii.
Abychom si mohli naše domněnky rychle potvrdit nebo vyvrátit, pomáháme si prototypováním. Věříme, že s dostatkem informací o problému můžeme udělat lepší návrh. Navíc jsme záměrně naplánovali nejrizikovější požadavky do prvních etap realizace, kdy bylo prototypování nejvíc.
Návrh
Každá etapa má návrhovou fázi, kdy mapujeme řešené požadavky na use cases. Iterativním způsobem rozšiřujeme stávající design. Přidáváme (sub)komponenty a jejich vzájemné vztahy. Rozkreslujeme chování komponent do sekvenčních diagramů. Pokud je potřeba, pomůžeme si stavovým nebo aktivitním diagramem. Snažíme se držet na co nejvyšší nutné úrovni abstrakce. Až na úroveň diagramu tříd chodíme jen zřídka. Designové tasky většinou děláme ve dvojici. Je to pro nás efektivnější metoda, kdy nápady okamžitě diskutujeme, připomínkujeme a případně zahazujeme.
Vytvořený návrh musí projít přes design review, které se provádí za přítomnosti softwarového architekta z Německa. Někdy přímo v Německu a v poslední době se nám také daří dělat review i vzdáleně. Dostáváme zpětnou vazbu a rady od kolegů, kteří mají s podobnými systémy mnohem více zkušeností než my. Někdy sice s jejich argumenty úplně nesouhlasíme, ale to je v software development asi normální. Mnohdy je to bazírování na zdánlivých maličkostech, ale je v tom cítit německá preciznost, která se mi ve výsledku hodně líbí.
Implementace
Pokud se dostaneme přes design review, pak se celí natěšení vrháme do vlastní implementace. Snažíme se o TDD přístup, kterým zajišťujeme fázi návrhu na té nejnižší úrovni. Využíváme také Behavior-Driven Development techniku, která zahrnuje outside-in přístup, zlepšuje dokumentační aspekty testů a elegantně řeší problém jednoho assertu na test.
Jednotkové testy musí testovat třídy v izolaci. Používáme proto různé adaptéry abstrahující třídy frameworku, např. ISerialPortAdapter, ITcpClientAdapter, ITimerAdapter, ITaskAdapter. Asynchronní zpracování musí být v jednotkových testech převedeno na synchronní.
Hodně našich tříd musí být thread-safe. Snažíme se proto psát integrační testy, které testují třídy při paralelním přístupu z více vláken. Zatím nemáme příliš zkušeností se zátěžovým testováním, ale snažíme se to změnit.
Tegris je poměrně rozsáhlý systém, který má vysoké výkonnostní požadavky a jsou nutné značné optimalizace na straně implementace (vlákna, pooling, lazy). Error handling je samostatná kapitola, která nám zabrala jednu celou etapu. Systém se musí umět vzpamatovat sám z některých chybových stavů. A především chyba v jednom modulu nesmí ohrozit činnost systému jako celku.
Co se týče UI, tak děláme pouze dummy verzi, která je později nahrazena verzí finální dodávanou od designérské firmy. Systém je přizpůsoben pro dotykové ovládání. Myši nejsou na operačních sálech vítanou havětí. ;)
Code review
Code review si děláme nejdříve interně sami. Snažíme se, aby se vlastní implementace rozpadala na malé úkoly, které zaberou maximálně několik hodin práce. Takto granulované úkoly se ještě rozumně revidují. Ve větších úkolech se už revidující dost ztrácí. Review nám přináší velkou přidanou hodnotu. Občas odhalíme problém v implementaci nebo problematický design, připomínkujeme (ne)čistý kód, vysokou komplexitu, nešikovnou terminologii, apod. Velkou výhodou je to, že se v našem týmu udržuje povědomí o změnách, učíme se jeden od druhého dobré postupy a zvyšujeme vzájemnou zastupitelnost. Refaktoring není u nás sprostým slovem. Praktikujeme společné vlastnictví kódu. Bohužel se nám nedaří ve větší míře dělat pair-programming. Ale není všem dnům konec.
V závěru etapy je kód revidován kolegy z Neměcka. Dozvíme se zajímavé připomínky a dostaneme zpětnou vazbu od někoho, kdo se přímo na implementaci nepodílel. Za sebe opět hodnotím tento postup velice kladně.
Pokud dojde v rámci implementace ke změnám v designu, zanášíme je průběžně do UML modelu.
Testovací případy
Testovací případy (test cases) jsme si nejdříve psali sami, ale teď to rádi přenecháváme specialistům od našich západních sousedů. Každý požadavek musí být mapovaný na nějaký testovací případ. Testovací případy jsou zjednodušeně řečeno soupisy prerequisities, test steps a expected results. Měl by je psát někdo z QA oddělení a jsou prováděny ručně před každým vydáním aplikace. My si je musíme také projít před akceptací každé etapy.
Znám i zajímavější práci než psát testovací případy, ale na druhou stranu je to užitečný pohled na systém očima uživatele.
Zajímavostí je, že jsme v rámci projektu museli vyvinout poměrně komplexní simulační nástroj. Jedná se o chytrý fake, který se chová jako reálná zařízení. Umí simulovat chybové stavy, odebírat a přidávat zařízení za běhu a další situace, které by bylo drahé a někdy i velmi problematické navodit se skutečným zařízením. Tento simulační nástroj je určen na primární otestování testovacích případů před vlastním testováním v reálných podmínkách. Ani pro testery totiž není vždy možné se rychle dostat k drahému fyzickému zařízení.
Infrastruktura
Centrální projektový management používá pro podporu vývojového procesu systém Polarion, kterému se naše jednotka snaží spíše vyhýbat. ;) Náš tým si většinu času vystačí s nástrojem YouTrack, ve kterém uděláme rozpad celé etapy do malých tasků. Používáme něco na způsob Kanbanu se stavy Backlog, Ready to Dev, Dev in Progress, Ready for Review, Review in Progress, Finished. Každý task musí mít jasně daná akceptační kritéria. Žádné nekonkrétní, problematicky revidovatelné formulace.
Pro kreslení UML byl vybrán Enterprise Architect, který se nám podařilo postupně ochočit tak, aby pracoval pro nás a ne proti nám. Některé jeho features jsou ale opravdu pouze pro otrlé jedince.
Správu zdrojových kódů řešíme přes Mercurial, nad kterým kmitá TeamCity. Buildovací skripty jsou napsané v Rake (Ruby Make).
Pracujeme ve Visual Studio 2012 s ReSharper 7. Aplikace je napsaná v C# nad .Net 4.0, UI je ve WPF a služba je typu WCF. Jako testovací framework je využit NUnit a pro mockování RhinoMocks. Pokrytí testy měříme přes dotCover. Kódovací standardy nám hlídá policajt StyleCop a jiný policajt FxCop zase provádí statickou analýzu kódu.
Pár slov na závěr
Ještě nevíme, jak celý projekt dopadne. Netušíme, jaká bude výsledná chybovost v produkci. Doufáme však, že minimální. Děláme pro to maximum. Snažíme se využívat všech nám známých technik pro zajištění kvality. Získáváme tím už od začátku větší pocit jistoty a práce není stresující. Navíc je docela fajn pracovat pro firmu, která má v Programming Guidelines jako první uvedeno pravidlo:
“It is more important to write correct and maintainable code than supposedly quickly programmed code.”
Můžete se mrknout na komerční videa představující systém Tegris a novou generaci světel Volista.