Jak ułatwić zrozumienie dużej bazy kodu

104

Załóżmy, że rozwijam stosunkowo duży projekt. Udokumentowałem już wszystkie moje klasy i funkcje w Doxygen, jednak wpadłem na pomysł, aby umieścić „uwagi programisty” na każdym pliku kodu źródłowego.

Ideą tego jest wyjaśnienie laikom, jak działa określona klasa (i nie tylko dlaczego, jak większość komentarzy). Innymi słowy, aby dać innym programistom inne spojrzenie na działanie klasy.

Na przykład:

/*
 * PROGRAMMER'S NOTES:
 *
 * As stated in the documentation, the GamepadManager class 
 * reads joystick joystick input using SDL and 'parses' SDL events to
 * Qt signals.
 *
 * Most of the code here is about goofing around the joystick mappings.
 * We want to avoid having different joystick behaviours between
 * operating systems to have a more integrated user experience, since
 * we don't want team members to have a bad surprise while
 * driving their robots with different laptops.
 *
 * Unfortunately, we cannot use SDL's GamepadAPI because the robots
 * are interested in getting the button/axes numbers, not the "A" or
 * "X" button.
 *
 * To get around this issue, we created a INI file for the most common 
 * controllers that maps each joystick button/axis to the "standard" 
 * buttons and axes used by most teams. 
 *
 * We choose to use INI files because we can safely use QSettings
 * to read its values and we don't have to worry about having to use
 * third-party tools to read other formats.
 */

Czy byłby to dobry sposób na ułatwienie nowym programistom / współpracownikom zrozumienia, jak to działa? Czy oprócz utrzymywania spójnego stylu kodowania i „standardowej” organizacji katalogów istnieją jakieś „standardy” lub zalecenia dotyczące tych przypadków?

Alex Spataru
źródło
32
Piekło nie Jeśli twój kod jest nieczytelny, dokumentacja nie pomoże.
Telastyn
35
@jeffo - problem polega na tym, że poświęcenie czasu na to może się zdarzyć raz. Czas utrzymywania czytelności kodu zdarza się z czasem. Byłem w miejscach z tego rodzaju dokumentacją, zrobioną, gdy projekt był młody, lub kiedy Joe Perfekcjonista wciąż był w zespole. Potem został porzucony, a komentarze pozostały, nie były już dokładne.
Telastyn
25
Przynajmniej na wyższym poziomie nieoceniony jest opis prozy poza kodem tego, co robi projekt, jak działa i jakie kompromisy zostały dokonane w architekturze. Ten rodzaj dokumentu jest obowiązkowy dla początkujących, zanim udadzą się na wycieczkę po kodzie. W sieci jest wiele moich metodologii-jest-zbyt-radykalnych-na-doktorzy-koleś gówno, i chociaż prawdą jest, że początkowy arch dokument i ewoluujący arch dokument nie pasują do siebie, konieczny jest opis prozy aby każdy mógł szybko uchwycić dużą, nietrywialną bazę kodów. Oto (słaby) przykład: zxq9.com/erlmud/html/001-002_architecture.html
zxq9
11
@Telastyn: To nie ma nic wspólnego z tym, czy kod jest czytelny, czy nie (i mam nadzieję, że tak jest). Dokumentowanie uzasadnienia projektu jest absolutnie ważne.
Wyścigi lekkości na orbicie
7
@Telastyn: Tak, może. Osobiście napisałbym to w osobnym dokumencie. Ale bloki komentarzy na górze plików źródłowych nie są takie złe.
Wyścigi lekkości na orbicie

Odpowiedzi:

139

To jest niesamowite. Chciałbym, aby więcej programistów poświęciło temu czas i wysiłek. To:

  • Stwierdza w prostym języku angielskim, co robi klasa (tj. To jej odpowiedzialność),
  • Zapewnia przydatne dodatkowe informacje o kodzie bez powtarzania dosłownie tego, co kod już mówi,
  • Przedstawia niektóre decyzje projektowe i powody ich podjęcia, oraz
  • Podkreśla niektóre problemy, które mogą spotkać następną osobę czytającą Twój kod.

Niestety, wielu programistów wpada w obóz „jeśli kod jest napisany poprawnie, nie trzeba go dokumentować”. Nie prawda. Istnieje wiele domniemanych związków między klasami kodu, metodami, modułami i innymi artefaktami, które nie są oczywiste po samym czytaniu samego kodu.

Doświadczony programista może starannie zaprojektować projekt o przejrzystej, zrozumiałej architekturze, która jest oczywista bez dokumentacji. Ale ile takich programów rzeczywiście widziałeś?

Robert Harvey
źródło
15
I dlaczego „Miesiąc mitycznego człowieka” staje się samospełniającą się przepowiednią, nikt nie poświęcił czasu na napisanie tego wszystkiego dla nowego dewelopera, kiedy było to dla nich świeże, a projekt nie pozostawał w tyle.
JeffO
3
Zgadzam się z każdą poruszoną tu kwestią. Nie podoba mi się termin użyty przez OP w jego poście how a class works. Zmienia się to z czasem i konserwacją. Chociaż mój zespół nie podaje powyższego źródła. Prowadzimy wiki z decyzjami i kopiujemy dyskusję luzu na temat decyzji projektowych w formie surowej do dokumentu (udostępniamy link od podsumowania decyzji i wniosków do surowych notatek, abyśmy nie musieli ponownie haszować starych decyzji). Wszystko wykonane starannie w github (więc wszystko jest w jednym miejscu).
Martin York,
1
Moim jedynym problemem jest stosowanie tego na całym świecie. Ta klasa jest wystarczająco złożona, z pewnymi dostępnymi gotchami, oczywiście jest naprawdę przydatna (chociaż nadal masz do czynienia z Comment Rot). Gdy klasa jest bardziej oczywista, komentarz może być nieco zbędny.
deworde
1
„Doświadczony programista może starannie zaprojektować projekt o przejrzystej, zrozumiałej architekturze, który jest oczywisty bez dokumentacji. Ale ile takich programów rzeczywiście widziałeś”. Chociaż jest to prawda, jakość dokumentacji nigdy nie jest lepsza niż jakość kod. Dobrze skonstruowany kod zazwyczaj ma dobrą, choć bezcelową, dokumentację. Źle
skonstruowany
3
Absolutnie zgadzam się z tą odpowiedzią i gdybym znalazł coś takiego jak przykład OP w kodzie, byłbym bardzo szczęśliwy. Tylko jeden dodatek: rozważ dodanie daty do komentarza, aby dać ewentualnym czytelnikom wskazówkę co do świeżości opisu i aktualizuj go za każdym razem, gdy aktualizujesz tekst.
Svalorzen,
36

Kluczem do pracy z dużą bazą kodu nie jest konieczność czytania całej bazy kodu, aby dokonać zmiany. Aby umożliwić programistom szybkie znalezienie poszukiwanego kodu, kod powinien być zorganizowany, a organizacja widoczna. Oznacza to, że każda jednostka logiczna w kodzie, od pliku wykonywalnego, biblioteki, przestrzeni nazw, aż po indywidualną klasę, powinna mieć wyraźnie widoczną odpowiedzialność. Dlatego nie tylko dokumentowałbym pliki źródłowe, ale także katalogi, w których się znajdują.

Notatki twojego programisty dają również podstawy do decyzji projektowych. Chociaż może to być cenna informacja, oddzieliłbym ją od deklaracji odpowiedzialności (aby umożliwić czytelnikowi wybór, czy chce on przeczytać o odpowiedzialności klasy lub jej uzasadnieniu projektowym) i przenieść ją tak blisko źródła, które opisuje jak to możliwe, aby zmaksymalizować prawdopodobieństwo aktualizacji dokumentacji, gdy kod jest (dokumentacja jest użyteczna tylko wtedy, gdy możemy ufać jej dokładności - nieaktualna dokumentacja może być gorsza niż żadna!).

To powiedziawszy, dokumentacja powinna pozostać SUCHA, tzn. Nie powtarzać informacji, które mogłyby zostać wyrażone w kodzie lub zostały już opisane gdzie indziej (wyrażenia takie jak „jak stwierdza dokumentacja” są znakiem ostrzegawczym). W szczególności przyszli opiekunowie będą biegli w języku programowania projektu, tak jak w języku angielskim; sparafrazowanie implementacji w komentarzach (które widzę całkowicie zbyt często, gdy ludzie są dumni ze swojej dokumentacji) nie przynosi żadnych korzyści i prawdopodobnie odbiega od implementacji, w szczególności jeśli dokumentacja nie znajduje się w pobliżu opisanego kodu.

Wreszcie, struktura dokumentacji powinna zostać ujednolicona w całym projekcie, aby każdy mógł ją znaleźć (to królewski bałagan dokumentów Piotra w narzędziu do śledzenia błędów, Sue na wiki, Alan w pliku readme i John w kodzie źródłowym ...) .

meriton
źródło
Twoje pierwsze zdanie jest dokładnie tak, jak ja to widzę. Duże bazy kodowe powinny składać się z kilku mniejszych komponentów, w których nowy programista może niezawodnie zmienić jeden bez narażania żadnego z pozostałych.
Jon Chesterfield
1
przenieś go jak najbliżej opisanego źródła, aby zmaksymalizować szansę aktualizacji dokumentacji, gdy kod jest . To cenne doświadczenie.
laike9m,
SUSZENIE jako wytyczne dla dokumentacji jest bardzo dobrym punktem! To automatycznie ustawia ostrość i zabrania słynnych wstrętnych komentarzy „// przyrost x o 1”.
Hans-Peter Störr,
13

Nie zgodziłbym się, że jest to bardzo dobre podejście, głównie ze względu na

  1. Kiedy refaktoryzujesz projekt, przenosisz metody, dokumentacja się psuje.

  2. Jeśli dokumentacja nie zostanie odpowiednio zaktualizowana, spowoduje to więcej zamieszania niż pomoże w zrozumieniu kodu.

Jeśli masz testy jednostkowe dla każdej metody / testy integracyjne dla każdego modułu, byłaby to dokumentacja własna, łatwiejsza w utrzymaniu i łatwiejsza do zrozumienia niż komentarze do kodu.

Tak, posiadanie odpowiedniej struktury katalogów zdecydowanie pomoże.

Nisko latający pelikan
źródło
+1 za testy to najlepszy sposób na zrozumienie podstawy kodu. Testy jednostkowe, testy integracyjne, testy akceptacyjne opowiadają o tym, jak aplikacja powinna działać i jak powinna być używana.
BZink,
7

Osobiście jestem fanem dokumentu projektowego wysokiego poziomu - najlepiej napisanego PRZED jakimkolwiek kodem - który zawiera przegląd projektu oraz listę klas i zasobów. Odgórna konstrukcja znacznie upraszcza rzeczy - może to być „silnik gry -> sprzęt -> kontrolery -> joystick”; dlatego nowy programista powiedział, że „napraw” przycisk „a” na kontrolerze „xyz” będzie przynajmniej wiedział, od czego zacząć.

Zbyt wiele współczesnych języków ma tendencję do dzielenia kodu na setki małych plików, więc znalezienie odpowiedniego pliku może być wyzwaniem nawet dla umiarkowanego projektu.

DWalker
źródło
16
20 lat temu cały mój kod był w jednym wielkim pliku. Teraz jest w tysiącach małych plików i plikach testowych. Jest ku temu dobry powód i odzwierciedla on 20 lat rozwoju oprogramowania (ogólny ekosystem, nie moja wiedza). Ale zbyt długo na komentarz.
Michael Durrant
4
ah, stara metoda wodospadu polegająca na pisaniu jednej, obejmującej, niezmiennej Prawdy przed kodowaniem nawet się zaczyna i uniemożliwia odstępstwo w implementacji od wspomnianej Prawdy.
jwenting
2
@jwenting: Nie musisz tego tak daleko posuwać. Ale to jeszcze dobrze mieć jakiś pomysł co jesteś budynku.
Robert Harvey
1
Z pewnością bez zastrzeżenia, jak właściwie to rozbić i gdzie złamać zasady, bardzo szybko uzyskasz dokument, który jest nieaktualny lub kamień milowy. „Muszę dodać nową klasę; do Documanto, Behemota, który zjada czas!”
deworde
2
@deworde: Przeczytałem to jako „zbyt leniwe, by prowadzić dokumentację”.
Robert Harvey
6

Jeśli podstawa kodu jest duża - staram się dostarczyć dokument projektowy, który odwzorowuje kluczowe elementy jego projektu i implementacji . Nie chodzi tu o wyszczególnienie żadnej z używanych klas, ale o dostarczenie klucza do kodu i myśli, która pojawiła się w projekcie. Daje nadrzędny kontekst systemowi, jego komponentom i ich zastosowaniu.

Dokumenty projektowe powinny zawierać następujące elementy;

  • Architektura aplikacji
  • Logiczna struktura kodu
  • Przepływy danych
  • Zastosowane kluczowe wzorce i motywacja ich użycia
  • Struktura źródła kodu
  • Jak go zbudować (daje to wgląd w ukryte zależności i strukturę źródła kodu fizycznego)

Następnie dokumentacja klas oraz funkcje / metody powinny zostać odpowiednio uzupełnione . W szczególności publiczny interfejs API; powinno być jasne, co następuje w każdym przypadku;

  • Warunki wstępne
  • Efekty
  • Niezmienniki
  • Warunki wyjątkowe (rzuty)
Niall
źródło
+1 Lepsze niż opisywanie każdej klasy, ponieważ będzie to nieaktualne znacznie szybciej niż ogólny projekt.
Lode,
4

Najważniejszą zasadą, którą znalazłem, aby ułatwić nowym programistom zrozumienie bazy kodu, że idealna zgoda jest droga.

Jeśli nowi programiści muszą doskonale rozumieć system, nad którym pracują, zapobiega to wszelkim możliwościom uczenia się w miejscu pracy. Myślę, że notatki programisty są doskonałym początkiem, ale poszedłbym dalej. Spróbuj napisać kod, który, jeśli podejdzie się na nowo, pozwoliłby programistom dowiedzieć się, co robią w locie, zamiast wymagać od nich uczenia się przedtem. Małe rzeczy, takie jak twierdzenia o przypadkach, o których wiesz, że nigdy nie mogą wystąpić, wraz z komentarzami wyjaśniającymi, dlaczego twierdzenie jest ważne, idą daleko. Podobnie dzieje się z pisaniem kodu, który kończy się niepowodzeniem, a nie segregowaniem, jeśli zrobisz coś źle.

Cort Ammon
źródło
Zasadą jest, że komentarze powinny dotyczyć DLACZEGO , a nie JAK . Kod opisuje JAK.
user11393,
3

Widziałem duże klasy z dokumentacją i po przeczytaniu dokumentacji nie mam pojęcia, do czego ta klasa powinna być dobra i dlaczego ktokolwiek miałby z niej korzystać! Jednocześnie potrzebowałem pewnej funkcjonalności i byłem absolutnie pewien, że musi istnieć klasa, która by sobie z tym poradziła, i nie mogłem jej nigdzie znaleźć - ponieważ nie było dokumentacji, która prowadziłaby mnie od tego, czego potrzebowałem do klasy robić to.

Pierwszą rzeczą, której chciałbym w dokumentacji, było tylko kilka zdań na temat tego, co robi klasa i dlaczego chciałbym jej użyć. Komentarze w pierwotnym pytaniu pod tym względem mają się całkiem dobrze. Po przeczytaniu tych komentarzy, gdybym miał joystick, który nie działa dobrze, ponieważ nie mogę zinterpretować dostarczanych wartości, wiedziałbym, jaki kod sprawdzić.

gnasher729
źródło
0

Podobnie do tego, co powiedział @meriton, podziel kod na osobne komponenty. Co więcej, podziel bazę kodu na osobne pakiety (pliki JAR, klejnoty, jajka itp.), Aby jeszcze bardziej wyjaśnić, w jaki sposób składniki są rozdzielone. Jeśli występuje błąd, programista musi tylko znaleźć pakiet, w którym znajduje się błąd i (mam nadzieję) tylko tam go naprawić. Nie wspominając o tym, że łatwiej jest przeprowadzać testy jednostkowe, a Ty możesz skorzystać z zarządzania zależnościami.

Inne rozwiązanie: zmniejsz bazę kodów. Im mniej kodu, tym łatwiej go zrozumieć. Refaktoryzuj nieużywany lub zduplikowany kod. Użyj deklaratywnych technik programowania . To oczywiście wymaga wysiłku i często nie jest możliwe ani praktyczne. Ale to jest godny cel. Jak napisał Jeff Atwood: najlepszy kod w ogóle nie ma kodu

Sam Jones
źródło
-1

W przypadku złożonych systemów może być warto nie tylko dokumentować każdy plik, ale także ich interakcje i hierarchię, a także strukturę programu i dlaczego.

Na przykład silnik gry jest zwykle dość złożony i trudno jest zdecydować, co nazywa się po stu warstwach abstrakcji. Może warto utworzyć plik taki jak „Architecture.txt”, aby wyjaśnić, w jaki sposób i dlaczego kod ma taką strukturę, i dlaczego jest tam ta bezcelowa warstwa abstrakcji.

akaltar
źródło
-7

Może to częściowo wynikać z faktu, że pojedynczy programista ma trudności z napisaniem go, ponieważ każdy rozumie tylko swoją część projektu.

Czasami możesz uzyskać te informacje z notatek kierownika projektu, ale to wszystko, co dostaniesz, ponieważ rzadko zapisują swoje notatki w tym formacie.

Ilqar Rasulov
źródło
7
Jeśli spojrzysz na github, w pliku README.md znajdziesz wiele projektów, które mają taką notatkę. Stało się tak bardzo częścią kultury git, a projekty javascript w szczególności dla większości ludzi nie będą korzystać z biblioteki, która nie ma tego rodzaju dokumentacji na wysokim poziomie. Nie jest więc prawdą, że „żaden programista nie napisałby tego”, ponieważ wystarczy spojrzeć na coś takiego jak jQuery lub socket.io i znaleźć programistów, którzy piszą takie rzeczy. Stało się również kulturą, że pliki README, które nie są dokładne, generują raporty o błędach.
slebetman
1
Wydaje się, że nie odpowiada to na pytanie, które szukało powodów, dla których proponowany styl dokumentacji działałby lub nie, a także standardów dokumentacji.
user52889,
5
Jeśli masz zespół programistów pracujących nad produktem, a każdy programista rozumie tylko konkretny kod, nad którym pracowali, to nie tylko twój zespół jest niesamowicie dysfunkcyjny z absurdalnym współczynnikiem magistrali, ale jeden kwestionuje jakość kodu. Jak integruje się kod z produktem, nie rozumiejąc reszty kodu w tym samym systemie?!?
Wyścigi lekkości na orbicie