Z jednym tylko nie potrafię się zgodzić. Mianowicie nie potrafię wyobrazić sobie nazywania parametrów w taki sposób jak:
float FactorBetweenZeroAndOne
float YawInRadians, float PitchInRadians, float RollInRadians
float RadiansBetweenZeroAndTwoTimesPi
MyClass *Object_CanBeNull
unsigned Index_MaxUintMeansNotInitialized
itp.
A takie rzeczy jak dopuszczalny zakres, jednostki, specjalne wartości jakie może przyjmować czy fakt że jakiś wskaźnik może pozostać zerowy a inny nie powinien trzeba jednak gdzieś określić.
Nazwy nie muszą być gramatycznie poprawne.
float radians_0to2pi
zamiast
float RadiansBetweenZeroAndTwoTimesPi
czy
float factor_0to1
zamiast
float FactorBetweenZeroAndOne
Ale i tak najważniejsze to.. Rozsądek.
Jak zwykle to kwestia umiaru. 20-znakowe identyfikatory to niezbyt dobry pomysł.
W moim poście nie wyraziłem się precyzyjnie.
Nie miałem na myśli sytuacji, w których trzeba dodawać do identyfikatorów piękny opis "BetweenZeroAndTwoTimesPi" znacząco je wydłużając.
Nie myślałem również o "kwiatkach" typu "float radians_0to2pi", które często bardziej zaciemniają kod niż poprawiają jego czytelność.
Takie informacje jak zakres, specjalne wartości, itp. oczywiście muszą być zapisane w komentarzach.
Skoro nie o tym, to o czym pisałem w tym poście?
O przypadkach, w których wystarczy znaleźć inne słowo (lub dwa), aby identyfikator przekazywał znacznie więcej informacji.
Często jest to łatwe i nie ma wcale dużo więcej pisania.. a mimo to nagminnie spotykam się ze identyfikatorami "str", "ptr", itp.
A, IMHO, naprawdę w łatwy sposób można przekazać niektóe informacje dobrym doborem nazw, np:
void funkcja( float yaw, float pitch, float roll );
void funkcja2( float x, float y, float z );
void funkcja3( std::string str1, std::string str2 );
vs.
void funkcja( float yawRadians, float pitchRadians, float rollRadians );
void funkcja2( float eyeX, float eyeY, float eyeZ );
void funkcja3( std::string title, std::string description );
Wiele IDE po rozpoczęciu pisania wywołania funkcji np. "
funkcja(" podpowiada tooltipem sygnaturę tej funkcji "
void funkcja( float yawRadians, float pitchRadians, float rollRadians );"
Przy dobrze nazwanych parametrach nie muszę przechodzić do odpowiedniego pliku nagłówkowego z jej deklaracją i sprawdzać w komentarzach "to stopnie czy radiany?".
Ondo: ale nie zawsze jest sens wydzielac dany kawalek w oddzielna f-cje, bo np bedzie uzywana tylko w jednym miejscu(f-cja z ktorej zostala wydzielona) i jak sie chce dokladnie przejrzec kod trzeba skakac.
Zgadzam się. To znów kwestia rozsądku i umiaru.
Niekiedy rozdzielenie na funkcję tylko zaciemni kod.
IMHO, nie ma to sensu, gdy:
A) funkcja jest krótka i logiczne fragmenty na jakie można ją podzielić są krótkie
Dokładnie tak jest w podanym przez Ciebie przykładzie.
B) trudno podzielić funkcję na fragmenty, bo (mimo iż przydługawa) stanowi jedną zwartą całość i nawet ciężko określić na jakie kawałki ją podzielić.
Najczęściej objawia się to tym, że wyodrębnione funkcje musiały by przyjmować wiele argumentów i zwracać wiele wartości. Większość tymczasowych, przekazywanych z jednej funkcji do drugiej. Często również trudno wymyślić nazwy dla takich funkcji.
Jednak w wielu przypadkach rozdzielenie na kilka funkcji można łatwo przeprowadzić. IMHO należy to robić, gdy (A) i (B) nie jest spełione, oraz:
1. Któryś z fragmentów jest używany (lub z dużym prawdopodobieństwem będzie) w innym miejscu.
To chyba jasne. Lepiej funkcja niz kopiuj+wklej.
2. Funkcja jest bardzo długa* i fragmenty jakie można wydzielic są długie*.
Ja wydzielam nawet, gdy taki fragment jest wykorzystywany tylko raz, wiec funkcja będzie wywołana tylko z tego miejsca. Taka sytuacja zdarza mi się rzadko. Najczęściej prędzej czy później ta wydzielona funkcja jest użyta w innym miejscu (niekiedy z niewielkimi przeróbkami, ale jednak).
*, ** - jak zwykle problem: Co oznacza "długa funkcja", "długi fragment"? Zależy od kontekstu - co ta funkcja robi i jak. Nie ma jednej najlepszej wartości. (Ale funkcja długa na 200 liniek
na pewno jest za długa.)
Gdyby było tak prosto, to było by pięknie. Oczywiście nie jest. Są wyjątki od każdej reguły.
Niekiedy należy przeprowadzić jeszcze dalej idącą dekompozyję.. nie tylko wydzielić funkcje, ale wydzielić nową klasę, która będzie reprezentowała dane pojęcie i zawierała w sobie całą logikę wykonywaną przez daną funkcję. Często przydługa funkcja kończy jako wywołanie jednej metody z nowej klasy.. bo reszta jest zaszyta gdzieś w konstruktorze i destruktorze (vide: uproszczenie niektórych fragmentów dzięki inteligentnym wskaźnikom).
Niestety kiedy, co i jak stosować oraz gdzie zrobić wyjątek.. tego nie da się opisać. To kwestia doświadczenia. Trzeba kodzić, kodzić, kodzić

Zgadzam sie ze przydlugawe f-cje to tez bez sens, ale osobiscie preferuje krotkie komentarze przed blokiem kodu cos robiacym. Ma to dodatkowa zalete, bo komentarze maja inny kolor i latwo je odroznic od reszty kodu. Z przykladu(
link) ktory podalem, mozna szybko nawet nie przegladajac kodu wyciagnac komentarze:
To idealy przykład jak powinno się robić komentarze. Nie za dużo, nie za mało.
Mam na myśli te wewnątrz funkcji. Te opisujące funkcje i klasy - kwestia gustu i tego czy (i jakie) ktoś stosuje narzędzia do generowania dokumentacji.
Oczywiscie, IMHO, dobry kod to nie kod bez komentarzy "bo sam się komentuje" (chociaż takie wnioski mogli by niektórzy wysnuc z mojego poprzedniego posta). Tymbardziej nie jest to kod z dużą ilością komentarzy i nic_nie_mówiących nazw zmiennych.
Dobry kod to połączenie obu. Taki, w którym identyfikatory wskazują swoje zastosowanie i co przechowują (co, tzn. np. "title", a nie jak np. "str" lub "sTitle"), a komentarze (w razie potrzeby!) uściślaja to wskazując niedozwolone wartości, zakresy i dokładne przeznaczenie. Takie jest moje zdanie na ten temat.
Co do spacji/wciec itd to juz kwestia gustu jak napisali przedmowcy. Jedna rzecz mi sie tylko spodobala jak przegladalem zrodla hl2. Przy b. prostych f-cjach pisze definicje w jednej linii, cos takiego:
struct float3{
float3(){}
float3(const float2 ¶m, float _z=0.0f) :x(param.x), y(param.y), z(_z){ }
float3(const float3 ¶m) :x(param.x), y(param.y), z(param.z){ }
[..]
Hmm.. też często piszę w jednej lini takie funkcje (głównie operatory i funkcje typ set*, get*), ale nie z takimi wcięciami. Będę musiał zobaczyć jak to wygląda u mnie w edytorze

, bo wydaje mi się troche rozdmuchane (za dużo spacji/tabów).
infernus - podobnie umieszczam nawiasy klamrowe, ale "wewnątrz" (np. for(..)) daję kilka spacji. A ?: też dość często używam.
P.S.
Ondo: Witaj na forum. Gdyby każdy kto tutaj przychodzi zaczynał pisanie od postów na takim poziomie jak Ty to forum byłoby lepsze

Może im dalej tym gorzej. Zobaczymy jak będę pisał przy setnym poście
