Jakość oprogramowania, również w systemach embedded

Opublikowane: 2021-10-22

Autor: Piotr Strzałkowski (Expert, Embedded Domain)

Do tej pory wielokrotnie spotkałem się z nieprawidłowym rozumieniem pojęcia jakości oprogramowania – czy to ogólnie, czy też stricte w branży systemów embedded. Tym artykułem chciałbym rozwiać pewne mity i przybliżyć to pojęcie czytelnikom zainteresowanym tematem wytwarzania oprogramowania, szczególnie oprogramowania wbudowanego (embedded). Czym zatem tak naprawdę jest jakość?

Co specjalista, to inna definicja jakości kodu

Definicje różnią się drastycznie w zależności od tego, kogo o nie pytamy. Specjaliści często przyjmują te, które pasują do ich konkretnych obszarów kompetencji. Na przykład, deweloper może stwierdzić, że jakość to dobry, czysty kod, z jasną konwencją nazewnictwa, spójnym formatowaniem i najlepiej bez błędów. Z drugiej strony, projektant UX najprawdopodobniej skupi się na przejrzystym i skutecznym frontendzie, dopracowanym w zakresie dostępności i współczesnych trendów graficznych. Które podejście jest więc słuszne?

Definicja jakości kodu według norm

Po definicję jakości kodu możemy sięgnąć do najnowszej normy dotyczącą inżynierii systemowej i programowej ISO 25010, która w jednej ze swoich części adresuje to zagadnienie, podsumowując je następującym schematem:

Jak można zauważyć na powyższym rysunku, jakość oprogramowania została przedstawiona jako zespół charakterystyk i pod-charakterystyk, jakie musi ono spełnić, aby mogło otrzymać status produktu wysokiej jakości.

Trzeba jednak pamiętać, że ślepe dążenie za jak najwyższymi metrykami dla wszystkich charakterystyk może być katastrofalne – jak to zwykle bywa, rozsądny balans jest najlepszy. W przypadku systemów embedded nie jesteśmy w stanie spełnić wszystkich charakterystyk, na przykład wtedy, gdy nasz system nie bazuje na systemie operacyjnym lub nie współpracuje z innymi systemami. 

Poniżej znajdziesz skrócone opisy haseł opisywanych przez normę z powyższego rysunku:

  • Functional Suitability – cecha opisująca sposób funkcjonowania oprogramowania.
    • Functional completeness – podcecha opisująca, w jakim stopniu aplikacja zapewnia spójność ze specyfikacją.
    • Functional correctness – podcecha opisująca, w jakim stopniu aplikacja zapewnia poprawne wyniki z wymaganym stopniem precyzji (czy wyniki są spójne z założeniami).
    • Functional appropriateness – podcecha opisująca, w jakim stopniu aplikacja spełnia swoją funkcję.
  • Performance efficiency – cecha opisująca, w jakim stopniu aplikacja wykorzystuję optymalną ilość zasobów.
    • Time behavior – podcecha opisująca, w jakim stopniu czas przetwarzania, przepustowość aplikacji podczas działania oprogramowania lub systemu spełnia założone wymagania.
    • Resource utilization – podcecha opisująca, w jakim stopniu ilość zasobów wykorzystywanych przez aplikację lub system podczas jego działania spełnia założone wymagania.
    • Capacity – podcecha opisująca, w jakim stopniu maksymalne limity wydajnościowe lub parametry spełniają założone wymagania.
  • Compatibility – cecha opisująca w jakim stopniu aplikacja może wymieniać informacje z innym systemem lub komponentami współdzieląc ten sam sprzęt.
    • Co-existence – podcecha opisująca, w jakim stopniu aplikacja może wydajnie działać zgodnie z założeniami współdzieląc środowisko i zasoby z innym systemem lub komponentami bez szkodliwego wpływu na resztę.
    • Interoperability – podcecha opisująca, w jakim stopniu dwie aplikacje lub więcej systemów, komponentów może wymieniać dane i wykorzystywać wymienione dane.
  • Usability – cecha opisująca, w jakim stopniu aplikacja może być używana przez określonych użytkowników do osiągnięcia wybranych celów.
    • Appropriateness recognizability – podcecha opisująca, w jakim stopniu użytkownicy mogą rozpoznać, czy aplikacja jest odpowiednia do ich potrzeb.
    • Learnability – podcecha opisująca, w jakim stopniu nauka działania aplikacji jest łatwa dla użytkownika.
    • Operability – podcecha opisująca, w jakim stopniu obsługa i kontrola aplikacji jest łatwa dla użytkownika (czy aplikacja posiada cechy ułatwiające obsługę).
    • User error protection – podcecha opisująca, w jakim stopniu aplikacja zabezpiecza użytkowników przed popełnianiem błędów.
    • User interface aesthetics – podcecha opisująca, w jakim stopniu interfejs użytkownika w aplikacji jest przyjemny i satysfakcjonujący w użytkowaniu.
    • Accessibility – podcecha opisująca, w jakim stopniu aplikacja może być użytkowana przez osoby o wszystkich cechach i możliwościach (daltoniści, ludzie ślepi, z różnym kolorem skóry, itd.).
  • Reliability – cecha opisująca, w jakim stopniu aplikacja spełnia określone funkcje w określonych warunkach przez określony czas.
    • Maturity – podcecha opisująca, w jakim stopniu aplikacja spełnia wymagania niezawodności w warunkach normalnej pracy (jak jest stabilna w warunkach codziennej pracy).
    • Availability – podcecha opisująca, w jakim stopniu aplikacja jest sprawna i dostępna do użycia w momencie, kiedy użytkownicy tego potrzebują.
    • Fault tolerance – podcecha opisująca, w jakim stopniu aplikacja działa zgodnie z przeznaczeniem pomimo pojawiających się błędów HW i SW.
    • Recoverability – podcecha opisująca, w jakim stopniu aplikacja jest w stanie odzyskać dane i przywrócić żądany stan pracy (sprzed awarii) w przypadku wystąpienia awarii systemu/aplikacji.
  • Security – cecha opisująca, w jakim stopniu aplikacja chroni informacje i dane tak, aby osoby o odpowiednich poziomach autoryzacji miały dostęp do adekwatnych danych.
    • Confidentiality – podcecha opisująca, w jakim stopniu aplikacja zapewnia, że dostęp do danych mają tylko upoważnieni użytkownicy.
    • Integrity – podcecha opisująca, w jakim stopniu aplikacja zapobiega nieuprawnionemu dostępowi do aplikacji/systemu i modyfikacji danych.
    • Non-repudiation – podcecha opisująca, czy aplikacja posiada funkcjonalność logowania specyficznych działań aplikacji/systemu i możliwość późniejszego ich odtworzenia.
    • Accountability – podcecha opisująca, czy aplikacja posiada funkcjonalność śledzenia działania poszczególnej jednostki (np. użytkownika) i możliwość jednoznacznego przypisania tych działań do tej jednostki.
    • Authenticity – podcecha opisująca, czy aplikacja posiada mechanizm umożliwiający udowodnienie tożsamość podmiotu (np. użytkownika) lub zasobu.
  • Maintainability – cecha opisująca, w jakim stopniu skutecznie i wydajnie można modyfikować program lub system w celu jego ulepszenia lub dostosowania do zmian wymagań.
    • Modularity – podcecha opisująca, w jakim stopniu aplikacja lub system został podzielony ma podmoduły tak, że ich zmiana nie ma wpływu na inne podmoduły.
    • Reusability – podcecha opisująca, w jak dużym stopniu aplikacja lub moduł może być używany w innej aplikacji lub systemie.
    • Analysability – podcecha opisująca, jak w efektywnym stopniu można analizować aplikację lub system pod względem konsekwencji zmian lub przyczyn awarii.
    • Modifiability– podcecha opisująca, w jak efektywnym stopniu można modyfikować oprogramowanie lub system bez wprowadzania nowych defektów wpływających na jakość.
    • Testability – podcecha opisująca, jak w efektywnym stopniu można przygotować kryteria testów  dla aplikacji, systemu czy modułu i wykonać egzekucję testów w celu ich weryfikacji.
  • Portability – cecha opisująca, w jakim stopniu skutecznie i wydajnie można przenosić aplikację pomiędzy różnymi systemami operacyjnymi lub HW.
    • Adaptability – podcecha opisująca, jak w efektywnym stopniu można dostosowywać aplikację lub system do ewoluującego HW, aplikacji lub systemu operacyjnego.
    • Installability – podcecha opisująca, jak w efektywnym stopniu można zainstalować lub odinstalować aplikację lub system w danym środowisku.
    • Replaceability – podcecha opisująca, w jakim stopniu dana aplikacja lub system może zastąpić inny system lub aplikację wykonując to samo zadanie w tym samym środowisku.

Jak mierzyć jakość – metryki

Aby móc ocenić, jak wysoką jakością cechuje się oprogramowanie, musimy wdrożyć do projektu odpowiednie metryki numeryczne dla poszczególnych cech opisanych w normie. Prawie każdy parametr projektu można potraktować jako metrykę i na jej bazie monitorować status projektu czy development. Jednak tak jak w przypadku charakterystyk jakościowych ważne jest, aby zachować zdroworozsądkowy balans w ilości i typie wdrożonych metryk. Popularną metodyką wyboru metryk jest technika SMART.

Dobre metryki do naszego projektu to takie, które są:

  • konkretne (Specific) – bezpośrednio odnoszące się do cech jakościowych kodu,
  • mierzalne (Measurable) – umożliwiające numeryczny pomiar cech jakościowych kodu,
  • osiągalne (Attainable) – ustalone wartości numeryczne/jakościowe, jakie chcemy osiągnąć powinny w założonym okresie czasu być osiągalne,
  • istotne (Relevant) – istotne dla projektu lub całej organizacji patrząc z perspektywy krótko i długoterminowej,
  • ograniczone czasowo (Time-bound) – wprowadzone metryki powinny posiadać realne cele czasowe.

Jakie metryki wybrać?

Skoro wiemy już, czym są metryki, to pora wybrać te odpowiednie do danego projektu. Jest wiele typów metryk opisujących proces developmentu, testowania oprogramowania i samego kodu, więc wybranie odpowiedniego ich zestawu nie jest łatwe. Możemy mierzyć pokrycie kodu testami, liczyć linie kodu (CLOC),  liczbę błędów w kodzie na moduł, wywołania funkcji, liczbę wyjść z funkcji, liczbę wołanych funkcji w funkcji, a nawet poziom komentarzy na plik.

Wybór konkretnych metryk to trudna sztuka znalezienia równowagi między cechami jakościowymi kodu, jakie chcemy monitorować a pracochłonnością związaną z ich monitorowaniem. Dodatkowo, w niektórych przypadkach wybrany poziom liczbowy danej metryki, jaki chcemy osiągnąć, powinien być dobrany do skomplikowania rozwiązania architektonicznego, jakie musi zostać wprowadzane w kodzie, aby dany poziom jakości zapewnić.

Przykładowymi metrykami reprezentującymi wspomniane wcześniej charakterystyki jakościowe mogą być:

Reliability
  • liczba i dotkliwość błędów
  • MTBF
  • MTTR
Maintainability
  • ostrzeżenia ze statycznej analizy kodu pod kątem jego spójności, struktury i skomplikowania
  • złożoność Halsteada
  • złożoność cyklomatyczna McCaba
Portability
  • ostrzeżenia z kompilatora (ustawiony najwyższy poziom ostrzeżeń)
  • ostrzeżenia ze statycznej analizy kodu pod kątem standardu kodowania
Reusability
  • ostrzeżenia ze statycznej analizy kodu pod kątem ilość spójności pomiędzy funkcjami „LCOM”

Warto także wspomnieć, że metryki mogą swoim działaniem dopełniać w pewnym stopniu większą gamę charakterystyk jakościowych.

Jak wdrożyć charakterystyki opisujące jakość kodu do projektu?

Jakość kodu jest zdecydowanie jednym z najważniejszych obszarów determinujących jakość oprogramowania, w związku z czym powinna być jednym z naszych pierwszych zmartwień jeśli chcemy przejść z teorii do praktyki. W tym przypadku niektóre metryki możemy wdrożyć za darmo i bez wysiłku. Wystarczy włączyć odpowiednie opcje w kompilatorze i przygotować proces ich cyklicznego monitorowania. Inne wymagają wdrożenia odpowiedniego oprogramowania na przykład CppChecka – do analizy statycznej kodu i procesu przeglądu kodu, a także odpowiedniej konfiguracji oprogramowania, w celu monitorowania metryk odpowiadających cechom jakościowym kodu, o które chcemy dbać.

Oba typy są warte wykorzystania, szczególnie jeśli mogą zapewnić dodatkowe korzyści bez dodatkowych kłopotów. Na przykład, posiadając analizę statyczną kodu możemy monitorować jakość składni kodu, a zarazem wspomóc się dowolnym standardem kodowania – na przykład MISRĄ.

Kolejnym etapem wdrażania metryk jest wprowadzenie testów jednostkowych i stworzenie odpowiedniego procesu testowania funkcjonalnego i niefunkcjonalnego oprogramowania z podziałem na odpowiednie poziomy. Oczywiście ten etap jest zależny od wielkości projektu i potrzeb związanych z jakością kodu.

Jakość kodu

Podsumowując, odpowiednio dobrane techniki pomiaru, testy i analizy, mogą generować metryki, które liczbowo opisują wybrane przez nas charakterystyki i pod-charakterystyki jakościowe oprogramowania lub systemu. Dzięki nim możemy monitorować, jak bardzo wysokiej jakości jest rozwijane przez nas oprogramowanie.

Należy jednak pamiętać, że jakość oprogramowania to nie tylko jakość jego kodu z niską zawartością błędów czy jakość estetycznie zarysowanego interface’u graficznego. Nie jest to też tytuł, który otrzymuje się na zawsze w momencie, kiedy oprogramowanie spełni wszystkie stawiane mu wymogi. Są to ciągłe i nieustające przez cały okres rozwoju monitoring i analiza bieżących parametrów i trendów.

Jak łatwo zauważyć, wprowadzenie niektórych metryk może być więc kosztowne, szczególnie gdy sposób, w jaki uwypuklają one znaczenie mierzonych obszarów wywołuje w zespole deweloperskim tendencję do priorytetyzowania tychże obszarów. Dlatego wprowadzenie metryk do procesu wytwarzania oprogramowania o wysokiej jakości powinno być poprzedzone dogłębną analizą wykraczającą poza zespół deweloperski. Celem powinna to być synergia między potrzebami biznesowymi, które produkt ma spełniać oraz dojrzałością i przyjaznością procesu rozwoju.

Warto również pamiętać, że podczas każdego procesu tworzenia oprogramowania najważniejsi są ludzie. Bez ich zaangażowania i przeszkolenia, nawet najlepsze rozwiązania i procesy zawiodą. Dlatego zgrany i doświadczony zespół deweloperów i testerów to połowa sukcesu.

Chcesz żebyśmy sprawdzili jakość Twojego kodu? Szukasz partnera ze zgranym zespołem, który jest w stanie wytworzyć oprogramowanie safety-critical i wbudowane dla każdej branży? Skontaktuj się z nami!

SKONTAKTUJ SIĘ
Wypełnij
formularz.
Skontaktujemy się z Tobą,
żeby umówić rozmowę
w dogodnym dla Ciebie terminie.