Dokumentowanie kodu

Każda nowoczesna i rozwijająca się aplikacja internetowa powinna posiadać swoją dokumentację.

Dokumentacja w formie zbioru dokumentów przechowywanych bądź to w chmurze, bądź w wewnętrznej sieci firmy, opisuje aplikację w wielu jej aspektach: od najbardziej ogólnych, takich jak zastosowania biznesowe, poprzez funkcjonowanie interfejsów, aż po kwestie architektury i używanych technologii. Pełni ona pożyteczną rolę umożliwiając wszystkim interesariuszom, czyli np. nowo wdrażanym do zespołu programistom szybkie zapoznanie się z przeznaczeniem poszczególnych komponentów i lepsze zrozumienie działania właściwie każdego elementu systemu. Jednak najbardziej “niskopoziomowym”, choć służącym podobnym celom rodzajem dokumentacji jest dokumentacja kodu tworzona w stosowanym przez nas języku PHP za pomocą narzędzia o nazwie phpDocumentor. Taka dokumentacja nie jest umieszczona w osobnym pliku tekstowym, lecz w komentarzach.

 

Komentarz jako dokumentacja

 

W każdym języku programowania są komentarze, czyli specjalnie oznaczone fragmenty kodu, które mogą zawierać dowolny tekst wprowadzony przez programistę i który nie jest wykonywany jako seria instrukcji programu, lecz służyć ma właśnie udokumentowaniu jakiegoś innego fragmentu kodu: czy to jednej linijki (wtedy jest to tzw. komentarz liniowy, a jeśli zawiera więcej linijek – blokowy), czy to jednej metody albo nawet całej klasy. Można w nich umieścić istotne dla innych programistów informacje ułatwiające im zrozumienie naszego kodu lub sugerujące przyszłe poprawki. Przykładowy tego typu komentarz wygląda tak:

 

 

Takie komentarze, jakkolwiek nadal chętnie używane do opisu specyficznych sytuacji związanych z danym miejscem w pliku, z czasem zaczęły ujawniać swe wady. Albowiem możemy śmiało założyć, że prawie każda napisana przez nas metoda będzie wiele razy używana, przerabiana lub choćby tylko oglądana przez innych programistów. A że głównie interesują ich dwie rzeczy: jakie parametry ta metoda przyjmuje oraz co zwraca, toteż te właśnie informacje musielibyśmy za każdym razem podawać ręcznie, a byłoby to dość czasochłonne. Pojawia się zatem potrzeba standaryzacji i automatyzacji tworzenia takich dokumentujących kod komentarzy i tę potrzebę zaspokaja właśnie phpDocumentor.

 

phpDocumentor i PHPDoc

 

phpDocumentor jest biblioteką napisaną w języku PHP, dostępną np. poprzez repozytorium PEAR lub przez menedżera pakietów Composer, za pomocą której można wygenerować dokumentację, której struktura określona jest przez standard o nazwie PHPDoc.  phpDocumentor działa w ten sposób, że parsuje (odczytuje) plik PHP, wyodrębniając poszczególne elementy składniowe języka i “wkleja” pasujące do nich komentarze, zgodnie ze specyfikacją PHPDoca.

 

Pierwsza wersja phpDocumentora powstała w 2000r., a od 2012r. dostępna jest wersja nr 2. Każde kolejne aktualizacje obsługują kolejne wydania języka, choć zwykle mija trochę czasu, zanim phpDocumentor “nadąży” za najświeższą wersją PHP.

 

Stosowanie PHPDoca oczywiście nie jest wymagane do prawidłowego działania pisanych przez nas skryptów lub aplikacji, lecz zdobył on przez lata na tyle dużą popularność, że stał się nieformalnym standardem (tzw. standardem de facto). Zaś od 2013 roku, kiedy to PHP FIG – organizacja opracowująca standardy obowiązujące w świecie PHP zaczęła tworzyć formalną specyfikację PHPDoca (PSR-5), staje się on w coraz większym stopniu standardem de iure, nie mającym wyraźnej konkurencji.

 

Standard w praktyce

 

PHPDoc pozwala na opatrzenie komentarzem dokumentującym najważniejsze elementy strukturalne występujące w języku PHP, takie jak zmienne (w tym pola klas), metody, cechy (traits), interfejsy i klasy. Dokumentację danego elementu tworzy się poprzez umieszczenie jej pomiędzy znakami komentarza: otwierającym /** (z podwójnym znakiem asterisk) oraz zamykającym */. Może to wyglądać na przykład tak:

 

 

Widzimy tutaj zdefiniowaną metodę, która najprawdopodobniej służy do obrócenia pliku graficznego o zadany kąt. Dzięki dokumentacji o działaniu metody możemy dowiedzieć się od razu, bez wnikliwego analizowania jej “ciała”. Widzimy, że przyjmuje ona jako kolejne parametry: obiekt Image zawierający obrazek, liczbę całkowitą określającą kąt, wskazany kierunku obrotu oraz kolor tła, którym zostaną wypełnione te obszary nowego pliku, których pierwotny obraz nie obejmuje. Oczywiście w naszym przypadku dane te możemy też wywnioskować z domyślnych wartości przyjmowanych parametrów, lecz nie zawsze zdarza się, że są one ustawione.  Oprócz tego możemy szybko zorientować się, że metoda zwraca ten sam obiekt Image z obróconym już obrazem. Tak więc rzut oka wystarczy do tego, by wiedzieć, jak skorzystać z takiej metody i czego możemy się po niej spodziewać.

 

phpDocumentor i PHPStorm

 

Wspomniany “rzut oka” wciąż jest jednak potrzebny do tego, by sprawdzić, co oferuje dana metoda. Trzeba zatem podkreślić, że zalety PHPDoca nie objawiałyby  się nam w pełni, gdyby nie jego integracja ze środowiskiem IDE, czyli oprogramowaniem do tworzenia kodu (edytorem tekstu poszerzonym o wiele przydatnych funkcji i narzędzi), którym jest w naszym przypadku PHPStorm. PHPStorm potrafi “skatalogować” wszystkie składniki napisanego przez nas kodu w postaci specjalnego indeksu, który stanowi bazę dla funkcji autouzupełniania. Dzięki temu pracując np. na zmiennej zawierającej obiekt, po wpisaniu kilku początkowych liter otrzymamy listę z podpowiedziami metod zawartych w klasie tego obiektu. Nie musimy zatem zaglądać do tej klasy.

 

PHPStorm oprócz tego posiada wbudowaną obsługę PHPDoca w postaci odpowiednich opcji, kontrolek i skrótów klawiaturowych, dzięki czemu możemy szybko wygenerować, uzupełnić lub zmodyfikować dokumentację każdego elementu pliku, nad którym pracujemy. Wspomaga to pracę indeksu poprzez utworzenie dodatkowych podpowiedzi na podstawie tak wygenerowanej dokumentacji. PHPStorm sygnalizuje też błędy, jeśli “wrzuciliśmy” do metody argument typu innego niż zadeklarowany. Łącznie sprawia to, że rozwijanie aplikacji, pod warunkiem dostatecznego opanowania wszystkich tych narzędzi, staje się znacząco szybsze i wygodniejsze.

 

PHPDoc vs DocBlock

 

PHPDoc jest standardem nie tylko przydatnym, ale i dość prostym, intuicyjnym w użyciu, dzięki czemu stanowi nieodłączne narzędzie pracy programistów. Są oni tak przyzwyczajeni do jego codziennego stosowania w mocno zautomatyzowanym środowisku PHPStorma, że często lekceważą stosowanie właściwego nazewnictwa opisującego poszczególne elementy dokumentacji. W sytuacji, gdy w pracy nad projektem zespół kładzie spory nacisk na jej poprawne i systematyczne tworzenie, może to niekiedy prowadzić do pewnych nieporozumień. Jedno z nich miało miejsce niedawno w naszym zespole IT zajmującym się rozwijaniem systemu do likwidacji szkód majątkowych i komunikacyjnych, kiedy to doszło do pewnego interesującego, choć raczej teoretycznego sporu. Otóż jedni uważali, że komentarz dokumentujący metodę nazywa się “PHPDoc”, natomiast inni byli przyzwyczajeni do używania określenia “DocBlock”. Tak naprawdę obie strony sporu miały na myśli to samo, jednak siła przyzwyczajenia prowadziła do intensywnej wymiany opinii przy okazji składania próśb lub poleceń o “dodanie PHPDoca” (“DocBlocka”, jak chciał interlokutor) lub przekazywaniu informacji o “brakującym PHPDocu/DocBlocku”. Zwolennicy “PHPDoca” argumentowali, że tak zwykle podpowiada PHPStorm, np. w opcji “Generate PHPDoc blocks” (a nie: “Generate DocBlocks”). Natomiast ci, którzy opowiadali się za stosowaniem nazwy “DocBlock” powoływali się na specyfikację PHPDoca. Warto zatem przyjrzeć się jej bliżej i wyjaśnić znaczenie podstawowych pojęć określających poszczególne elementy dokumentacji, gdyż różnice znaczeniowe między nimi okazują się dość subtelne.

 

Otóż w dokumentacji pojedynczej metody możemy wyróżnić 3 składniki czy też aspekty, które w jakiejś części się na siebie nakładają i są sobie bliskie, a ich nazwy to: DocComment, PHPDoc i DocBlock. Gdybyśmy chcieli napisać ją ręcznie, zaczęlibyśmy od wstawienia pustego DocComment, czyli specjalnego typu komentarza (widoczne na obrazku podkreślenia są utworzone przez PHPStorma, który informuje o brakujących elementach):

 

 

Teraz możemy wypełnić ten komentarz, wpisując tam PHPDoca, czyli jeden lub kilka tzw. tagów, takich jak np. @param, @return, @throws lub @property, które najczęściej występują razem z deklaracją typu oraz nazwą zmiennej i informują o poszczególnych aspektach działania metody: jakie argumenty przyjmuje, co zwraca, jakie wyrzuca wyjątki, jakie pola przechowuje itp. Oprócz tagów w DocComment można umieścić także podsumowanie (summary – zazwyczaj jedna linijka opisująca przeznaczenie metody) oraz opis (description – własny, nieformalny opis metody zawierający różne uwagi). Dopiero razem taki zwarty komentarz wraz ze składowymi PHPDoc możemy nazwać DocBlockiem (dobrym jego przykładem jest ten przedstawiony wcześniej dla metody rotateImage()). Tak więc DocBlock jest to DocComment wypełniony treścią w postaci dokumentacji PHPDoc.

 

Możemy zauważyć, że określenie “PHPDoc” występuje w co najmniej dwóch znaczeniach, pomiędzy którymi różnice są bardzo subtelne: raz może to być po prostu zawartość DocBlocka albo tylko pojedynczy tag, np. @param string $name, a innym razem może to oznaczać nazwę standardu PHPDoc (PHP Documentation). Niektórzy sądzą, że “PHPDoc” to też skrót od “phpDocumentor”, co należy uznać za interpretację błędną. Pozostaje pytanie, czy PHPDoc w rozumieniu “zawartość DocBlocka” oznacza tylko tagi, czy też podsumowanie i opis? Niestety ani dokumentacja phpDocumentora zawarta na stronie https://docs.phpdoc.org/, ani dokumentacja standardu PSR-5: https://github.com/php-fig/fig-standards/blob/master/proposed/phpdoc.md nie precyzują tej kwestii w wystarczającym stopniu. Wątpliwości można też mieć co do tego, czy naprawdę konieczne było wprowadzenie określenia “DocBlock”, skoro dla użycia słowa “DocComment” raczej nie będzie miało dla nas znaczenia, czy jest on wypełniony, czy nie, a nawet posługiwanie się samym tylko pojęciem “PHPDoc” w zupełności wystarcza większości programistom. Można jednak podejrzewać, że istnieją sytuacje, które wymagają tego rozróżnienia, zważywszy na to, że DocComment jest specyficznym rodzajem komentarza oznaczanym w odmienny sposób i inaczej interpretowanym np. przez PHPStorma – nawet nie posiadając treści (a może szczególnie wtedy) zasługuje więc na osobną nazwę, jakkolwiek w codziennej praktyce rzeczywiście nie będzie to miało znaczenia.

 

Jak więc widzimy, dyskusja na ten temat jest dość scholastyczna. Czy ostatecznie jednak mówić: “dodaję PHPDoca” czy “dodaję DocBlocka”? Osobiście stosuję następującą konwencję, która wydaje mi się najbliższa specyfikacji PHPDoca: jeśli w danym pliku nic jeszcze nie jest udokumentowane lub plik wymaga znaczących uzupełnień w kilku miejscach, mówię o “uzupełnieniu PHPDoca” w znaczeniu “dokumentacji zgodnej ze standardem”. Jeśli pojedyncza metoda nie jest udokumentowana, proponuję “dodanie DocBlocka”. Jeśli do metody dodano już DocComment, lecz jest on pusty lub zawiera niewiele informacji (np. własne komentarze lub podsumowanie) lub brakuje choćby tylko jednego taga, mogę zdecydować się na “uzupełnienie PHPDoca” – tutaj już w znaczeniu jednego lub kilku elementów wewnątrz DocBlocka.

 

PHPDoc, a PHP7

 

Wersja 7 języka PHP wprowadziła kilka bardzo istotnych zmian. Najbardziej znaną jest ścisłe typowanie (ang. strict type). Oznacza to, że możemy (choć nie musimy – nadal nie jest to wymóg) zadeklarować typ przyjmowanych w metodzie parametrów. Co jeszcze bardziej interesujące, możemy też zadeklarować typ zwracanych przez nią danych. Czy to oznacza, że PHPDoc przestaje być użyteczny? Możemy przecież z samej deklaracji zorientować się o podstawowym sposobie działania funkcji. Po co duplikować te informacje w DocBlocku?

 

Sprawa budzi liczne kontrowersje. Jedni rezygnują ze stosowania DocBlocków wtedy, gdy potrzebne informacje można łatwo odczytać z definicji metody. Zazwyczaj zdarza się tak, gdy jest ona dość prosta. Decydują się zaś na ich wprowadzenie tylko w wyjątkowych sytuacjach, gdy np. metoda korzysta z tablicy elementów o określonym typie, np. string[].

 

Drudzy uważają, że warto konsekwentnie tworzyć kompletną dokumentację PHPDoc dla każdego elementu strukturalnego. Ścisłe typowanie nie oznacza bowiem, że w przypadku użycia niewłaściwego typu przekonamy się o tym poprzez zatrzymanie działania programu. PHP7 wymusza zadany przez nas typ poprzez rzutowanie, czyli jego zamianę, a nie poprzez rzucenie błędu, tak jak to ma miejsce w przypadku zadeklarowania parametru typu obiektowego. Stąd, według przedstawicieli tej opinii, istnieje potrzeba, aby PHPStorm ostrzegał nas przed próbą wywołania metody z wartościami niezgodnymi z zadeklarowanymi.

 

W naszym projekcie niedawno przyjęliśmy tę pierwszą konwencję i stosujemy PHPDoca wtedy tylko, gdy jest to naprawdę potrzebne. Wyszliśmy z założenia, że występują w nim licznie małe metody lub takie, które nic nie zwracają, toteż takich sytuacji nie będzie nazbyt wiele, a odpowiednie komunikaty PHPStorma można dodatkowo skonfigurować.

 

Ostatecznie pozostaje to w gestii każdego osobnego zespołu przyjęcie własnych zasad stosowania PHPDoca, odpowiadających stylowi jego pracy i specyfice realizowanego przezeń projektu.

 

Autor: Kamil Polikowski


Opublikowano:

Mentax na Facebook'u