Sposoby komentowania kodu

0

Witam

Ostatnio zastanowiło mnie, w jaki sposób komentujecie swoje kody. Chodzi mi m.in. o to w jakiej osobie piszecie komentarza (a może bezosobowo)?

Pozdrawiam.

0

Dobre pytanie. Tak się właśnie przyglądam aktualnemu projektowi i... chyba bezosobowo.

// długość i możliwe znaki losowo generowanych haseł, dowzolone wartości znaków
// alnum (alfanumeryczne), numeric (liczby), unique (33 znakowy unikatowy GUID)

czy też

function index()
	{
		//łączenie z bazą danych
		$this->load->database();
				
		// tutaj powinna być ładowana z bazy lista kategorii głównych
		$cdata = $this->category_model->get_main_category_list(-1);
		
		// ładowanie z bazy danych komunikatów
		$ndata = $this->news_model->get_news();

A już tak swoją drogą to stosuję phpDoc do opisywania wszystkich plików, klas i ich metod/właściwości. Wygodna sprawa.

0

Ja zazwyczaj komentuję tak (chociaż zdarza się, że piszę "raz tak-raz tak"):

function index()
        {
                //łączymy się z bazą danych
                $this->load->database();
                               
                // tutaj ładujemy z bazy listę kategorii głównych
                $cdata = $this->category_model->get_main_category_list(-1);
               
                // ładujemy z bazy danych komunikaty
                $ndata = $this->news_model->get_news();
0

Ja chyba zawsze w ten sposob:

function index() //main function, retrieving cetagories and news
        {
                //sets database connection
                $this->load->database();
                               
                // gets main categories list
                $cdata = $this->category_model->get_main_category_list(-1);
               
                // gets news list
                $ndata = $this->news_model->get_news();
0

Ja piszę zazwyczaj podobnie jak Ktos - bezosobowo.

0

W komentarzach tryb rozkazujący, bo jest chyba najkrótszy z możliwych.
Przy większych kodach dodatkowo dopisuję złożoność (oczywiście jeżeli ma to sens)

0

U mnie idzie to mniej więcej tak:

#include<cośtam>

/*---------------------------------------------------------
Zmienne globalne
---------------------------------------------------------*/
int zmienna_glogalna1; /* wyjaśnienie zmiennej */
int  zmienna_glogalna2; /* wyjaśnienie zmiennej */
/*---------------------------------------------------------
deklaracje funkcji
---------------------------------------------------------*/
void funkcja1(); /* funkcja służy ...*/
void funkcja2(); /* funkcja służy ...*/
/*---------------------------------------------------------
definicje funkcji
---------------------------------------------------------*/
int main()
{
  funkcja1();
  funkcja2();
  return 0; /* wyjaśnienie */
}
/*-------------------------------------------------------*/
void funkcja1()
{
  zmienna_glogalna1++; /*zwiększ ilość o 1*/
}
/*-------------------------------------------------------*/
void funkcja2()
{
  zmienna_glogalna2++; /*zwiększ ilość o 1*/
}
0

Komentarze w kodzie piszę bezosobowo w formie krótkich poleceń

// add user
user=new User("kapustka");
stickerSystem.addUser(user);

// add rules
RuleBuilder builder=new RuleBuilder();
builder.addSubject("ProductionOrder");
subjectRule=builder.getRule();
user.addRule(subjectRule);
	
// do what parser should do (however without filling params and events)
Subject subject=new SubjectProductionOrder();

Staram się też krótko opisać co robi klasa w następujący sposób:

/**
 * The target of event
 * - get target data (for example by sql query)
 * - go to details screen
 * - cache target data
 * 
 * If you want to trace events that have no target (like logout event maybe)
 * then use SubjectNothing subclass.
 * @author maciek
 */
public abstract class Subject implements Cloneable {

pozdrawiam</b>

0

OOP:

ja natomiast przekonalem sie do nieco innego podejscia do komentarzy w kodzie

..nie stosowac ich w ogole!

dlaczego?
bo nie da sie ukryc ze zasmiecaja cztylnosc samego kodu (pomijam tutaj ew. uzycie foldingu)

w jakich warunkach?
w warunkach kiedy stawiamy na logiczna implementacje generujac metody tak specjalistyczne i tak krotkie, ze zadne wyjasnienia nie sa potrzebne

kiedy jednak?

  • wyjatkowa zawile, nieczytelene dla ludzkiego oka perlowe herezje
  • metody klas serwisowych o dlugiej liscie parametrow (dokumentacja listy argumentow)
0

Ja zazwyczaj po prostu opisuje metode/klase (co robi, itp) + parametry, bo staram sie robic kilkulinijkowe. Opis tylko po to, zeby nie trzeba bylo sie wczytywac w te kilka linijek, bo mimo wszystko jest krocej.

0

Np. Jeśli poprawny wynik wywołania danej metody jest zależny od wcześniejszego wywołania innej metody danego obiektu,warto moim zdaniem napisać o tym.

jak to bedzie sytuacja?
mozesz podac przylad? (jakis prosty)

//Ktoś tu mi się w posta nieładnie wpie***lił :)
//wybacz chcialem dac odpowiedz a dalem edytuj :)

0

Jeśli poprawne wykonanie jakiejś metody jest zależne od wcześniejszego wywołania innej metody, to jest to moim zdaniem błąd (projektowy, logiczny, czy jak tam go nazwać). Moim zdaniem, podprogram (metoda, procedura itd.) nie powinna być zależna od wywoływania jej w okreslonym "towarzystwie".

0

jak to bedzie sytuacja?
mozesz podac przylad? (jakis prosty)

W dużym uproszczeniu.

Wyobraż sobie ,ze w projekcie powstaje moduł odpowiedzialny za zakup danego towaru oraz moduł odpowiedzialnyz a walidację danych podawanych przez klienta(połączenie z systemami zewnętrznymi).
Teraz pomyślność procesu zakupu zależy od pomyślności wykonania metody walidacji, zas aby ta metoda została wywołana prawidłow ,obiekt musi zostać zainicjalizowany (np. poprzez odczytanie danych z pliku konfigutacyjnego), jeśli inicjalizacji sie nie powiedzierównież brakiem sukcesu zakonczy się wywołanie metody odpowiedzialnej za "dowiezienie" procesu zakupu do końca.

Wtedy mozna jakies zdanie o tym napsiać dla potomnych ,ktorzy będa musieli modyfikować w przyszłości nasz kod.

pozdrawiam

0

ja natomiast przekonalem sie do nieco innego podejscia do komentarzy w kodzie
..nie stosowac ich w ogole!

Coś w tym jest ! Ostatnio zmierzam w tą stronę. Postanowiłem przenieść większy nacisk na czytelność kodu. Częściej rozbijam metody, stosuję Compose Method, daję dłuższe nazwy - w efekcie komentarze wyparowują.

Komentarze tekstowe mają pewien problem. Bardziej ogólnie to dokumentacja tekstowa ma pewien problem który strasznie fajnie nazwał mój kolega z pracy, Tomek Struczyński:
"dokumentacja zawsze jest jeszcze nie kompletna albo już nieaktualna"

dzięki Tomek !

0

Ja komentuję tylko, gdy - tak jak na forum - podaję kawałek kodu albo piszę dla kogoś kto się kompletnie nie zna.

Zwykle tylko na początku pliku zaznaczam do czego on służy i co można w nim znaleźć. Unikam komentarzy, stosując dłuższe i intuicyjne nazwy. Czasem tylko w wyjątkowych sytuacjach coś opiszę (ostatnio na przykład miałem przypadek, że o poprawności działania programu decydowała kolejność deklaracji uses w Delphi - to warto było podkreślić).

Ale widzę, że wielu osobom, które potem czytają taki kod, takie podejście się nie podoba.. Wolą wszystko mieć pokomentowane. Szkoda.

W C# natomiast często nazywam regiony i zwijam kod - łatwiej oddzielić zamknięte całości.

0

A, temat wątku skusił mnie by drugi raz w życiu zajrzeć do tego działu :)

Pomijając projekty na 20 linii, to staram się opisać każdą funkcję (metodę, procedurę, whatever) przed jej definicją.
Dodatkowo czasem dorzucam sporadyczne komentarze oddzielając jakieś logiczne części funkcji bądź opisy poszczególnych linijek.

W C# włączam w opcjach wywalanie błędu gdy element publiczny nie posiada komentarza w formie /// - czyli umieszczanego w kodzie i potrzebnego do automatycznej dokumentacji. Dzięki temu nie odkładam na później opisu nowego fragmentu kodu.

W PHP już nie mam nawyku komentowania każdej funkcji - chyba, że piszę dla kogoś lub wspólny projekt - wtedy uważam to za dobry ton, bo nie ma nic gorszego, niż wgryzanie się w czyjś nieopisany kod.

Co prawda akurat w Delphi nie pisałem od 6 lat, ale obecnie piszę projekcik i jako najświeższy kod z niego podam przykład, jak mniej więcej wygląda każda funkcja. [kod do poprawiania, bo wspomniane w komentarzach braki SDK zostały uzupełnione ;) gwoli informacji]

//funkcja wywoływana z AQQ gdy użytkownik próbuje połączyć się z siecią
//UID: identyfikator sieci
//Login: login ustawiany w opcjach AQQ
//Pass: hasło ustawiane w opcjach AQQ
//CustomServer: adres serwera ustawiany w opcjach AQQ
//CustomPort: port, na którym serwer oczekuje naszego zgłoszenia - ustawiany w opcjach AQQ
//CallID: początkowy status użytkownika (odpowiada statusowi, który użytkownik wybrał z menu sieci)
procedure Login(UID, Login, Pass, CustomServer: ShortString; CustomPort, CallID: Integer); register;
//var
//  xml: IXMLTag;
begin
  MyJID := Login + '@' + CustomServer;
  if CallID = JABBER_OPTIONS_NO then begin  //omijamy braki SDK AQQ - wyświetlenie okna opcji
    if not Assigned(fOptions) then fOptions := TfOptions.Create(nil);
    fOptions.Show;
    Exit;
  end;

  if CallID = JABBER_CONSOLE_NO then begin  //omijamy braki SDK AQQ - wyświetlenie okna konsoli
    if not Assigned(fConsole) then fConsole := TfConsole.Create(nil);
    fConsole.Show;
    Exit;
  end;

  if CallID = JABBER_OFFLINE_NO then begin  //wybrano rozłączenie więc nie wykonujemy czynności
    MyActualState := JABBER_OFFLINE_NO;
    ShowMessage('logout wew. login()'); //TODO: wyglada na to, ze to sie nigdy nie odpala [czyli AQQ czuwa, git] - do wywalenia
    Exit;
  end;

//  ShowMessage('[Login] UID: ' + UID + #13 + 'Login: ' + Login + #13 + 'Pass: ' + Pass + #13
//              + 'CustomServer: ' + CustomServer + #13 + 'CustomPort: ' + IntToStr(CustomPort) + #13
//              + 'CallID: ' + IntToStr(CallID));

// zaczynamy się logować do sieci i wywołujemy PluginOnConnecting w AQQ (AQQ zacznie migać ikoną sieci)
  OnConnecting(PLUGIN_UID);

  dmMain.JabberSession.Server := CustomServer;
  dmMain.JabberSession.Port := CustomPort;
  dmMain.JabberSession.Username := Login;
  dmMain.JabberSession.Password := Pass;
  dmMain.JabberSession.Resource := Options.Resource;
//  dmMain.JabberSession.Status := 'status poczatkowy';  //kpina.. skad to brac?  //TODO: z rejestru [niestety]
  dmMain.JabberSession.Priority := Options.Priority;
  dmMain.JabberSession.UseSSL := Options.Crypt;
  dmMain.JabberSession.Available := True;

  case CallID of
    JABBER_ONLINE_NO: begin
         dmMain.JabberSession.ShowType := jshowNone;
       end;
    JABBER_FREEFORCHAT_NO: begin
         dmMain.JabberSession.ShowType := jshowChat;
       end;
    JABBER_AWAY_NO: begin
         dmMain.JabberSession.ShowType := jshowAway;
       end;
    JABBER_XA_NO: begin
         dmMain.JabberSession.ShowType := jshowXA;
       end;
    JABBER_DND_NO: begin
         dmMain.JabberSession.ShowType := jshowDND;
       end;
  end;
  MyActualState := CallID;
  dmMain.JabberSession.DoConnect(False, jatAuto);  //zacznij się łączyć
end;
0

Ja co do komentarzy w kodzie to jestem dość dziwny, tzn. na początku każdego pliku (unit, header, sourcefile, rc, cokolwiek) umieszczam na samej górze po kolei:

-Program bazowy (czyli na potrzeby czego to coś powstało, ostatnio mój projekt miał unity z kilku i to nawet śmiesznie wyglądało)
-Prawdopodobna wersja pliku (znaczy jak sobie przypomnę że to tu jest i coś zmieniałem to się zmienia wersja)
-Autor (+ ewentualna lista autorów w kolejności modyfikacyjnej, czyli ten co tworzył jest zawsze na początku)
-Po cholerę to coś, co to robi i z czym to sie jje
-jakieś dodatkowe informacje czy coś takiego co może być potrzebne komuś, np. że to używa GNU C lib i borlandowski bcb6 niewiele zakuma, a jak zakuma tow cholerę trza będzie poprawiać...

Potem często tak bywa że przy includach (czy usesach) rzadziej używanych wyjaśniam po jaką cholerę, zwykle pisząc np.

#include <cmath> //GNU StdLibC math.h: sqrtf, powf

czy jakoś tak, ale zawsze to wyjaśnia, jak by ktoś chciał coś z kodem kombinować, albo ja bym czegoś zapomniał, a pamiętał bym że kiedyś takie coś robiłem.

Na domiar złego ;) nazwy zmiennych, stałych, funkcji itp. są zawsze dobrane tak żeby były opisowe, ale krótkie i łatwe do zapamiętania lub wymyślenia w dokładnie takim samym zapisie, np "insertUser". Jeszcze dla pewności przy definicji funkcji czy makra czy czegoś tam wymagającego parametrów, zawsze podaje składnie, spodziewane wyniki i sposób odwołania w dość zwięzły sposób, np:

//insertUser: insert suUser before user no. iPos and return position(usually same as iPos), -1 for error
int insertUser(sUser suUser, int iPos)

To był tylko przykład, nie brane z rzeczywistego projektu, ale daje mniej więcej pojęcie jak dziwnie to robie.

Dodatkowo nie opisuje wszystkich zmiennych, ale raczej te, których użycie, czy deklaracja w danym punkcie może być niejasne.

W treści funkcji/procedury/klasy/struktury robie podobnie, tzn opisuje tylko to co wymaga opisania, ale separuje kod dla ułatwienia czytania, tzn pomiędzy inicjalizacją a alteracją daje linijkę odstępu.

ps. Ważny może być też styl kodowania, tabulacji itp (ja używam podobnego do GNU)

0

Jeżeli nazwa procedury\funkcji jest adekwatna do tego co dana robi i jest krótka to komentarz pomijam.

procedure TData.LoadFromFile(const FileName: string);
var
  FS :TFileStream;
begin
  FS := TFileStream.Create(FileName, fmOpenRead);
  FS.ReadBuffer(Buffer, SizeOf(Buffer));
  FS.Free();
end; // TScrap.LoadFromFile

Jeżeli dana funkcja wymaga komentarza to jest on w definicji klasy

type
  TDaySheet = class(TForm)
    // ustawia odpowiednie wartości nawigatora na starcie programu
    procedure SetDate;
    // oblicza wyniki wporwadzane przez usera w czasie rzeczywistym
    procedure CalcResults;
    procedure SaveToFile(const FileName :string);
    procedure LoadFromFile(const FileName :string);
    // obliczenie położenia arkusza w pliku
    // dla przyspieszenia działania z pliku odczytywany i zapisywany jest
    // tylko edytowany arkusz a nie cała struktura
    function CalcFilePos(const AShift, ADay, AMonth, AMachineNr,
                        AMachineType: Word) :LongWord;
  public
    { Public declarations }
  end;

Pary begin..end, zawsze. Za end w komentarzu daję początek bloku begin, dzięki temu wiem który end jest do kótrego begina

procedure TDaySheet.cbMachineTypeChange(Sender: TObject);
begin
  case cbMachineType.ItemIndex of
    0 :begin // wtryskarka
         pMachineType.Color := clLime;
         pMachineType.Caption := 'Injection moulding press';
       end; // case 0:
    1 :begin // drukarka
         pMachineType.Color := clYellow;
         pMachineType.Caption := 'Printer';
       end; // case 1:
  end; // case cbMachineType

  UpdateData(cbMonth.ItemIndex+1, cbYear.ItemIndex+2006);
end; // TDaySheet.cbMachineTypeChange;

Jeżeli procedura jest dość długa i zawiera istotne sekcje, oddzielam je komentarzem lub kilkoma pustymi wierszami

procedure TDaySheet.Parser;
var
 SL           :TStringList;
 i, j, k, m   :Byte;
 sSurf, sCode :string[20];
 rB, rE       :Word; // zakresy Range.begin i Range.end;
 DelimPos     :Byte; // pozycja znaku '-'
 Temp         :Word; // zmienna pomocnicza
begin
  SL := TStringList.Create();
  with SL do
  begin
    Delimiter := '/';
    if Memo1.Lines.Count < 1 then Exit;

    for m := 0 to Memo1.Lines.Count-1 do
     begin
       if Memo1.Lines.Strings[m] <> '' then
          DelimitedText := Memo1.Lines.Strings[m];
       if Count < 2 then Continue;
       sSurf := '';

       // 1. ostatnia pozycja zarezerwowana dla kodu złomu
       // Wartość po przypisaniu usuwamy
       sCode := Strings[Count-1];
       Delete(Count-1);

       // 2. Szukanie czy jest podana powierzchnia na przedostatniej pozycji
       // Identyfikacja na podstawie znaku '+'. Jeżeli jest to usuwamy z listy
       // znak '+' pomijamy
       if Pos('+', Strings[Count-1]) <> 0 then
          begin
            sSurf := Strings[Count-1];
            System.Delete(sSurf, 1, 1);
            Delete(Count-1);
          end; // if Pos

       // 3. szukamy w pętli zakresów rB-rE. Znakiem identyfikującym jest '-'
       // po ustaleniu zakresów usuwamy
       for i := 0 to Count-1 do
         begin
           DelimPos := Pos('-', Strings[i]);
           if DelimPos <> 0 then
           begin
             // rB - wszystko na lewo od '-'
             // rE - wszystko na prawo od '-'
             // znak '-' jest pomijany
             rB := StrToIntDef(Copy(Strings[i], 1, DelimPos-1), 0);
             rE := StrToIntDef(Copy(Strings[i], DelimPos+1, Length(Strings[i])), 0);
             if (rB > rE) then
                begin
                  Temp := rB;
                  rB := rE;
                  rE := Temp;
                end; // if rB
             if ((rB <> 0) and (rE <> 0)) then
                 for k := rB to rE do
                   with xsgArkusz do
                   begin
                     Cells[2, k] := 'N';
                     if sSurf <> '' then Cells[3, k] := sSurf;
                     Cells[4, k] := sCode;
                   end; // for k
             Delete(i);
           end; // if DelimPos
         end; // for j

       // 4. Teraz pojedyncze wartości
       if Count > 0 then
          for i := 0 to Count-1 do
            begin
              j := StrToIntDef(Strings[i], 0);
              if j <> 0 then
              with xsgArkusz do
                begin
                  Cells[2, j] := 'N';
                  if sSurf <> '' then Cells[3, j] := sSurf;
                  Cells[4, j] := sCode;
                end; // with xsgArkusz
            end; // for i
     end; // for m
  end; // with SL
 SL.Free();
end;

Generalnie staram się pisać na tyle krótkie procedury o takich nazwach aby móc pominąć komentarz

function TDaySheet.CalcFilePos(const AShift, ADay, AMonth, AMachineNr,
                               AMachineType: Word) :LongWord;
begin
  Result := (SizeOf(TSheet)          * AShift) +
            (SizeOf(TDayReport)      * ADay) +
            (SizeOf(TMonthReport)    * AMonth) +
            (SizeOf(TYearReport)     * AMachineNr) +
            (SizeOf(TMachineReport)  * AMachineType);
end; // TDataStream.SetFilePos
0

Ja ogólnie tworzę komentarze dla siebie - więc komentuję to co zapisałem w skrócie (np. jeśli chodzi o jakieś operacje arytmetyczne), by potem za jakiś czas wiedzieć o co mi wtedy chodziło. Moje komentarze są w różnych osobach: procedury opisuje w 3 os. lp, inne komentarze bezosobowo, a jeszcze inne w 3 os. lm, ale żadnej prawidłowości raczej w tym nie ma...

Ostatnio w jednym programie zapisuje loga na samym początku kodu, czyli co robiłem dokładnie tego dnia o dokładnie tej godzinie, by potem sprawdzić jak długo coś wykonywałem (i ogólnie odkąd trwa praca nad programem - i okazuje się, że nie zauważyłem jak ten czas leci i jak bardzo olewałem sobie ten program xD) i ew. wiedzieć czy nie miałem jakichś błędów przy rozumowaniu, a czasem także mogę się pośmiać, gdy napisałem przez przypadek coś głupiego.

Zazwyczaj także używam komentarzy, by zapisać aktualne założenia programu, np. gdy mam coś zrobić, a brak mi czasu, to gdy wrócę za jakiś czas do programu nie zapomnieć, co muszę zrobić; i gdy to zrobię usuwam to.

Także raczej nie mam żadnej zasady przy komentowaniu kodu, bo nie wypuszczałem żadnego programu w świat i komentuję wszystko dla siebie, ale mogę stwierdzić, że na pewno jest potrzebne.

Pozdrawiam.

0

Ja żadnych zmian nie opisuję w nagłówku pliku. I tak pliki mam pod kontrolą svn, więc jak chcę sprawdzić co się zmieniło, to mam dokładne zmiany jak również własne opisy dostępne przez svn (a dokładniej trac, bo tam również śledzę błędy, zmiany i pomysły).

Co do stylu komentowania.
Kiedyś komentowałem bardzo dużo. Teraz w miarę jak rośnie doświadczenie, coraz więcej rzeczy wydaje mi się oczywistych i nie komentuję. Inaczej też piszę. Czasem wprost przesadzam z rozbijaniem na funkcje i robią one niewielkie rzeczy, ale zato opisują co robią. Jeszcze jeden argument przeciwko komentowaniu to to, że komentarze za szybko się starzeją :P

Co do formy osobowej.
W komentarzach, które piszę w programach tylko dla siebie, to nie dość, że się zmienia forma to czasem i język :P Nie polecam naśladować, chyba, że ktoś chce język poćwiczyć :)
W komentarzach przy projektach wspólnych, nie bardzo mam wyjście. Staram się pisać w takiej formie, w jakiej już komentarze występują. Ew. jeżeli jeszcze takich nie ma, to zazwyczaj piszę w 1 osobie liczby mnogiej. Ale w takich projetach też dokumentuję każdą funkcję w javadoc (lub analogicznym).

1 użytkowników online, w tym zalogowanych: 0, gości: 1