Pod koniec lutego byłem na targach i konferencji Embedded World 2019. Poza relacją z samego wydarzenia (do przeczytania pod tym linkiem) postanowiłem opisać tematy poruszane na prezentacjach z części konferencyjnej. Było już więc o Embedded Security i o systemach operacyjnych czasu rzeczywistego. Dzisiaj pora na kolejny duży temat jakim jest jakość oprogramowania. Będzie więc o standardzie MISRA C, statycznej analizie i zwinnym podejściu do wytwarzania systemów safety-critical. Każdy z tych tematów posiadał oddzielną ścieżkę podczas konferencji. W przeciwieństwie do wpisu o RTOSach nie będę opisywał każdej prezentacji po kolei. Zamiast tego opiszę konkluzje płynące z każdej ze ścieżek.

MISRA C

MISRA C to zestaw reguł pisania programów w języku C zmniejszający ryzyko popełnienia błędów. Został on stworzony dla branży samochodowej, ale przyjął się szeroko we wszystkich aplikacjach safety-critical pisanych w C. Standard wskazuje konstrukcje językowe, które mogą łatwo zostać błędnie zrozumiane, są nieintuicyjne, wykonują operacje, które nie powinny być dozwolone, albo są z jakiś innych przyczyn podejrzane.

Istnieją dwa rodzaje zasad – Rules i Directives. Directives są bardziej opisowe i zależne od kontekstu. Zgodność z nimi można zapewnić jedynie przez code review. Rules natomiast są bardziej precyzyjne i możliwe do wymuszenia przez statyczną analizę kodu. Istnieją trzy poziomy restrykcyjności:

  • Mandatory
  • Required
  • Advisory

Najlepiej trzymać się reguł MISRA C od początku projektu, a nie poprawiać kod w późniejszym czasie. Poza tym MISRA C najlepiej sprawdza się w parze z dobrze zdefiniowanym procesem zgodnym z V-modelem. Odstępstwa od MISRA C należy dokumentować wraz z uzasadnieniem.

MISRA C w zdecydowanej większości opisuje ogólnie przyjęte dobre praktyki. Jest jednak kilka punktów spornych np. funkcja może zawierać tylko jeden return na końcu. Te sporne reguły wpływają na odbiór całego standardu i generują dużo krytyki mimo, że zdecydowana większość punktów jest bezdyskusyjna.

Stosowanie MISRA C daje korzyści nawet w projektach nie spełniających norm safety-critical. Po prostu ułatwia znajdowanie i zapobieganie błędom.

Analiza Statyczna

O analizie statycznej było bardzo dużo prezentacji – dwa albo trzy całe bloki. Każda z nich była prowadzona przez firmy rozwijające soft do statycznej analizy, jednak nie skupiały się one tylko na pokazywaniu zalet własnych produktów, a raczej na ogólnych poradach przy używaniu tego typu narzędzi.

Statyczna analiza łatwo wyłapuje pewne rodzaje błędów trudne do wykrycia w inny sposób np. przy pomocy testów. Są to najczęściej udefined behavior, czyli np. niezainicjalizowane zmienne, niezwolniona pamięć, dangling pointery, błędy rzutowania. Każdy tool ma swoją własną strategię wykrywania błędów. Jedne skupiają się na znalezieniu wszystkich błędów i one mają więcej false positive. Inne zgłaszają błąd tylko kiedy są go pewne na 100% – te mają więcej niewykrytych błędów (false negative). Płatne narzędzia zapewniają dogłębną analizę i wiele opcji konfiguracyjnych. Zwykle skupiają się na znalezieniu wszystkich możliwych błędów. Do tego generują np. grafy przebiegów funkcji i posiadają różne inne bajery.

Za pomocą narzędzi do analizy kodu możemy nie tylko znajdować konkretne miejsca występowania błędów, ale również zbierać metryki pozwalające nam wychwycić inne problemy z kodem. Dosyć prostą, ale bardzo przydatną metryką jest złożoność cyklomatyczna (cyclomatic complexity – CC). Pozwala ona nam określać fragmenty kodu trudne do utrzymania. Pokazuje ilość możliwych ścieżek przejścia przez daną funkcję. Jeżeli wartość dla funkcji jest wyższa niż 10, prawdopodobnie jest ona zbyt skomplikowana. Im większa złożoność cyklomatyczna tym trudniej developerowi analizować i modyfikować kod. Za każdym razem kiedy natrafi on na takie skomplikowane miejsce, musi stracić dodatkowy czas, żeby zrozumieć co się dzieje w kodzie. Czasem zdarzają się konstrukcje mające duże complexity, które jednak nie są tak skomplikowane. Np switch – case. Miejsca wskazane przez tool powinny być więc zrewidowane przez programistów i to oni powinni podjąć decyzję, czy złożoność danej funkcji utrudnia pracę, czy nie.

Agile w safety-critical

Zwinne metody wytwarzania oprogramowania w ciągu ostatnich lat zyskały ogromną popularność. Zastosowanie ich bezpośrednio w systemach safety-critical jest jednak utrudnione ze względu na restrykcje, jakie nakładają normy. Dlatego wiele zespołów developerskich korzysta z części dobrodziejstw iteracyjnych metod zarządzania projektem, ale nie są one dobrze opisane i ustandaryzowane.

Jedna z prezentacji w tym bloku przedstawiała case study wprowadzania Agile w kilku projektach safety-critical wraz z próbą generalizacji zasad tak, aby można je było stosować w kolejnych. Autor pokazał dwa możliwe podejścia:

  • Agile V-model – czyli wyjście od V-modelu i próba dostosowania go do iteracyjnego rozwoju projektu.
  • Safety Scrum – czyli wyjście od Scruma i próba dodania do niego cech wymaganych przez normy safety-critical.

Podczas prac w pierwszym podejściu zauważono, że są pewne elementy, których nie opłaca się „uzwinniać” i dobrze działają w swojej sekwencyjnej formie. Są to elementy wykonywane na początku prac nad projektem, czyli tworzenie ogólnej koncepcji, zbieranie wymagań i tworzenie koncepcji architektury. Najlepiej więc zrobić te kroki po kolei i dopiero potem przejść na proces iteracyjny.

Zaproponowany proces iteracyjny polega na podziale jednego dużego V-modelu na wiele małych V-modeli posiadających swoje własne fazy planowania, implementacji i weryfikacji. Autorowi udało się rozwijać projekty w taki sposób, ale nie był do końca zadowolony z tego rozwiązania.

Drugą możliwością jest Safety Scrum, czyli modyfikacja powszechnie wykorzystywanego Scruma. Minimalistyczne podejście do dokumentacji i analizy ryzyka przekreśla wykorzystanie tej metody w sposób niezmieniony w systemach safety-critical. Trzeba więc je w jakiś sposób dodać. Wprowadzono więc nowe role odpowiedzialne za te zadania takie jak Risk Owner, Validation Owner, Assesment Owner równoległe do Product Ownera.

Zmodyfikowano również sprinty. Podczas każdego sprintu należy wykonać dodatkowe zadania związane z Analizą bezpieczeństwa i walidacją. Rozszerzają one standardowe scrumowe spotkania takie jak Sprint Planning i Sprint Review.

Jednak powstały w ten sposób proces tworzy się dosyć skomplikowany. Dodatkowe elementy stoją w sprzeczności z ideą Scruma, czyli z lekkością i prostotą procesu. Dlatego to rozwiązanie wydaje się gorsze od Agile V-modelu.

Innym ciekawym tematem jaki poruszono podczas tej ścieżki jest wykorzystanie ruchu DevOps w projektach safety-critical. Celem jest automatyzacja wielu czynności wykonywanych w projekcie związanych na przykład z generowaniem dokumentacji. Wykorzystać do tego można narzędzia ALM (Application Livecycle Management).

I to już koniec opisu prezentacji z Embedded World. Tematy, które tutaj opisałem to tylko mała cząstka – jednocześnie trwało zawsze 8 prezentacji. Jednak nadzieję, że się podobało i pozwoliło Ci wyrobić sobie opinię na temat tego wydarzenia.