W poprzednim wpisie poruszaliśmy między innymi temat standaryzacji kodu. Tym razem przytoczymy subiektywnie dobrane najpopularniejsze standardy języka C++.
Standardy języka C++
Istnieje wiele standardów oraz zbiorów reguł dotyczących języka C++. Niektóre z nich definiują tak podstawowe elementy jak formatowanie kodu oraz konwencja nazewnictwa. Inne standardy zawierają zalecenia dotyczące wybranych cech oraz konstrukcji języka. Przyjrzyjmy się kilku z tych standardów.
ISO C++ Core Guidelines
Jest to zestaw rekomendacji utrzymywany przez ważnych członków społeczności C++: Bjarne Stroustrup oraz Herb Sutter. Rekomendacje zostały opublikowane między innymi tutaj. Celem dokumentu jest pomoc w wydajnym używaniu nowoczesnego wydania języka C++ oraz pomoc programistom w pisaniu prostszego, wydajniejszego i łatwiejszego w utrzymaniu kodu. Opracowanie skupia się na koncepcjach wysokiego poziomu takich jak interfejsy, zarządzanie pamięcią czy współbieżność. Autorzy w mniejszym stopniu skupili się na podstawowych aspektach jak nazewnictwo czy formatowanie kodu. Najistotniejsze rekomendacje to:
- Ponieważ programiści zazwyczaj nie czytają komentarzy, więc kod powinien być samo-dokumentujący. Dodatkowo kod, w porównaniu do komentarzy, jest sprawdzany przez kompilatory oraz inne narzędzia.
- Przenośność jest ważna, zatem zaleca się unikanie rozszerzeń języka oraz rozwiązań zależnych od wykorzystywanych platform.
- Wyrażanie intencji jest ważne. Do tego mogą służyć odpowiednie konstrukcje języka takie jak pętle range-for, algorytmy biblioteki standardowej itp.
- Weryfikacja na poziomie kompilacji powinna być preferowana nad weryfikacją podczas wykonania kodu.
- Niezmienne dane (immutable) powinny być preferowane w porównaniu do danych zmiennych (mutable).
- Interfejsy powinny być jawne, precyzyjne oraz silnie typizowane.
- Niepowodzenie w wykonaniu wymaganego zadania powinno być sygnalizowane wyjątkiem (exception).
- Funkcja powinna realizować pojedyncze zadanie, być krótkie oraz proste.
- Jeżeli funkcja jest bardzo krótka oraz ma krytyczne znaczenie czasowe, wówczas powinna być oznaczona jako inline.
- Czyste funkcje (pure functions1) są preferowane.
- W przypadku zwracania przez funkcję wielu wartości najlepiej zwrócić je w formie struktury.
W standardzie zawarto wiele innych ważnych i pomocnych wskazówek. Każdy programista C++ powinien je poznać zwłaszcza, że zdecydowana większość z tych reguł nie stoi w sprzeczności z innymi wytycznymi.
Google C++ Style Guide
Firma Google opracowała własny zestaw porad opublikowany na następującej stronie. We wstępie do reguł autorzy opracowania wskazali motywy, cele oraz wyjaśnienie doboru reguł. Najważniejsze z nich to:
- każda nowa reguła powinna mieć wymierny wpływ kod źródłowy (reguły do rzadko stosowanych niepoprawnych praktyk są pomijane),
- usprawnianie kodu pod kątem czytania, utrzymania oraz debugowania jest ważniejsze od usprawnień w pisaniu kodu,
- każdy nieoczywisty lub zaskakujący fragment kodu powinien zawierać objaśniający komentarz,
- spójność jest istotna, ale nie powinna być uzasadnieniem do stosowania starego stylu,
- unikanie konstrukcji kodu, które mogłyby być trudne w zrozumieniu dla przeciętnego programisty,
- unikanie dodawania nowych elementów do globalnej przestrzeni nazw,
- jeżeli optymalizacja kodu jest wymagana, wówczas może łamać reguły.
Przykładowe reguły
Następnie w dokumencie wymieniane są kolejno sugerowane reguły. Przykładowo:
- nagłówki (header files) powinny być samodzielne: zawierać wszystkie wymagane dowiązania (#include),
- pliki źródłowe i nagłówkowe powinny zawierać dowiązania do wszystkich używanych elementów,
- funkcje typu inline powinny być stosowane wyłącznie dla krótkich funkcji,
- pliki nagłówkowe powinny być dowiązywane (#include) grupami w odpowiedniej kolejności:
- nagłówek główny (np. deklaracja implementowanej klasy),
- nagłówki systemowe języka C,
- biblioteka standardowa C++,
- nagłówki pozostałych bibliotek,
- nagłówki projektu.
- domniemana konwersja powinna być unikana – dyrektywa „explicit” powinna być używana dla jednoargumentowych konstruktorów oraz operatorów konwersji,
- preferowane są struktury w porównaniu do par i krotek jeżeli elementy mogą mieć nazwę,
- kompozycja powinna być preferowana zamiast dziedziczenia, wielodziedziczenie implementacji jest wysoce odradzane,
- parametry domyślne (default arguments) są zakazane w przypadku metod wirtualnych,
- wyjątki (exceptions) nie są używane,
- należy unikać instrukcji RTTI (typeid oraz dynamic_cast),
- odradza się używanie typów stałoprzecinkowych bez znaku tylko dlatego, aby wyrazić, że zmienna nie może przyjmować ujemnych wartości,
- dedukcja typów (również dyrektywa auto) powinna być używana jedynie, gdy poprawia czytelność kodu dla osób niezaznajomionych z kodem projektu,
- skomplikowane szablony powinny być unikane,
- dyrektywa switch powinna zawsze mieć domyślną alternatywę w przypadku wartości nieenumerowanych,
- pomimo, że najlepszy kod jest samo-dokumentujący, należy stosować komentarze, gdy jest to pomocne,
- oczywiste komentarze powinny być unikane, komentarze nie powinny opisywać działania kodu a powody, dla których komentowany kod działa,
- przestrzeganie zasad nie jest wymagane, jeżeli byłoby niespójne z konwencją edytowanego kodu.
Standard Google zawiera rady dotyczące wysokiego poziomu oraz rady skupiające się na formatowaniu i organizacji kodu. Niektóre z tych reguł są adresują specyficzne problemy projektów firmy, a inne wynikają z wieloletniej praktyki i mogą być rozumiane jako dobre praktyki.
LLVM Coding Standards
Standard kodu projektu LLVM został opublikowany na stronie. Głównym celem wytycznych jest zwiększenie czytelności i łatwości utrzymania kod źródłowego. LLVM kładzie nacisk przede wszystkim na spójność:
Jeśli rozszerzasz, ulepszasz lub naprawiasz błędy w już zaimplementowanym kodzie, użyj stylu, który jest już używany. Dzięki temu kod źródłowy będzie jednolity i łatwy do zrozumienia.
Następnie w dokumencie zawarto rady oraz reguły. Najważniejsze z tych reguł to:
- Komentarze są ważne z powodu czytelności oraz utrzymania kodu. Komentarz powinien opisywać co dany kod wykonuje oraz dlaczego. Opisywanie w kodzie jak kod działa jest odradzane.
- Każdy plik powinien w nagłówku zawierać komentarz wyjaśniający cel pliku. Każda klasa, pod warunkiem, że nie jest trywialna, powinna zawierać przeznaczenie klasy oraz jak klasa powinna być wykorzystywana. Komentarze dotyczące funkcji oraz metod powinny zawierać co funkcja realizuje oraz przypadki brzegowe. Interfejs (parametry) funkcji powinien być samo-dokumentujący.
- Komentowanie bloków jest odradzane. Zamiast tego taki kod powinien być otoczony przez „
#if 0
” oraz „#endif
”. - Ciekawą sugestią dotyczącą komentarzy jest wskazywanie nazw argumentów w wywołaniach funkcji na wzór argumentów w języku Python. Przykład:
Object.emitName(/*Prefix=*/nullptr);
- Dołączanie nagłówków (include) powinno przebiegać w następującej kolejności:
- nagłówek główny,
- nagłówki lokalne i prywatne,
- biblioteki,
- nagłówki systemowe.
- kod powinien być przenoszalny i niezależny od platformy,
- ze względu na rozmiar plików wykonywalnych wyjątki oraz instrukcji RTTI (typeid oraz dynamic_cast) nie są używane,
- używanie konstruktorów i destruktorów statycznych, np. zmiennych globalnych, których typy mają konstruktor lub destruktor, jest zabronione,
- dyrektywa auto powinna być używana jedynie, gdy poprawia czytelność kodu,
- nagłówki (header files) powinny być samodzielne: zawierać wszystkie wymagane dowiązania (include),
- używanie wczesnego zakończenia funkcji oraz pętli sprzyja upraszczaniu kodu,
- dyrektywa assert powinna być używana bez ograniczeń.
Standard LLVM kieruje przede wszystkim wagę w stronę spójności oraz czytelności kodu. W niewielkim zakresie definiuje formatowanie oraz styl kodu.
Linux kernel coding style
Standard programowania jądra systemu Linux dotyczy języka C i jest opublikowany na następującej stronie. Jak sam autor wskazuje, zbiór zawiera osobiste preferencje autora. Jest to ciekawa lektura ze względu na zawarte silne przekonania. Autor na wstępie zachęca do wydrukowania oraz spalenia standardu GNU. Następnie dokument zawiera listę reguł. Najciekawsze z nich to:
- wcięcie kodu wynosi 8 znaków,
- kod nie powinien zawierać więcej niż 3 poziomów wcięcia,
- nazewnictwo powinno być spartańskie, używanie mieszanych nazw jest niedopuszczalne za wyjątkiem zmiennych globalnych, które powinny mieć opisową nazwę,
- kodowanie typu w nazwie jest niedopuszczalne, ponieważ kompilator zna typ,
- komentarze są dobre, ale należy uważać na nadmierne komentowanie,
- komentarz nigdy nie powinien wyjaśniać jak kod działa, komentarz powinien wyjaśniać co kod realizuje oraz dlaczego,
- modyfikator inline nie powinien być stosowany dla funkcji dłuższych niż 3 linie,
- instrukcje warunkowe preprocesora nie powinny by stosowane w plikach źródłowych – jeżeli jest taka potrzeba to należy je stosować do definicji funkcji w plikach nagłówkowych.
Ze względu na mniejszą złożoność języka C w porównaniu do C++ standard ten skupia się głównie na regułach dotyczących formatowania oraz stylu.
AUTOSAR oraz MISRA
Celem standardu MISRA oraz AUTOSAR jest zapewnienie bezpieczeństwa, niezawodności, przenośności oraz interoperacyjności w zastosowaniach w systemach krytycznych, głównie w przemyśle samochodowych. Najważniejsze reguły:
- unikanie dynamicznej alokacji pamięci,
- unikanie używania wyjątków (exceptions),
- zakaz używania niejawnej konwersji typów,
- silna typizacja powinna być preferowana.
Standardy te zawierają subiektywnych reguł dotyczących takich kwestii jak formatowania kodu, nazewnictwo, używnanie komentarzy czy wcięć w kodzie. Największa uwaga skupiona jest na ograniczeniach cech języka C++.
Podsumowanie
Standardy języka C++ są ważne. Cechą wspólną standardów jest dbałość o czytelność oraz utrzymanie kodu, ponieważ kod jest częściej czytany niż pisany. Te cele mogą być osiągnięte zarówno poprzez odpowiednie formatowanie kodu, odpowiednie nazewnictwo oraz używanie możliwie nieskomplikowanych cech języka. Dodatkowo, niezależnie od zestawu reguł, ważna jest spójność kodu.
Przytoczone standardy przemysłowe skupiają się na poprawności działania kodu oraz ograniczaniu używaniu cech języka powodujących potencjalnie niebezpieczne problemy.
Twój zespół jest zbyt zajęty lub nie wie jak wdrożyć powyższe techniki?
Leave a Reply