Skąd się wzięło wymuszanie przestrzegania najdrobniejszych (…) // drobiazgów // w kodzie?

0

Pisz otwierający nawias klamrowy na osobnej linii. Albo pisz go na tej samej linii, co poprzednią deklarację. A przede wszystkim: bądź konsekwentny, jeśli w projekcie pisze się na osobnej linii, to ZAWSZE pisz na osobnej linii, a jeśli pisze się na tej samej, to ZAWSZE pisz na tej samej. ( https://softwareengineering.stackexchange.com/questions/2715/should-curly-braces-appear-on-their-own-line )

Nie, wróć. Pisz na osobnej linii nawiasy klamrowe otaczające definicje funkcji, klas, itp. Otwierające nawiasy klamrowe przy instrukcjach sterujących (if, for, etc) mają być na tej samej linii, co instrukcja. (Tak bodajże domyślnie formatował kod MonoDevelop dołączony do Unity. To mi się spodobało, i zacząłem to stosować gdzie indziej, i dostałem po łapach, bo „nieważne, czy będę pisał na tej samej, czy na osobnej linii – mam ZAWSZE pisać tak samo).

Zawsze muszą być spacje wokół operatora przypisania =. Nie, wróć, ma nie być spacji jeśli oznacza on domyślną wartość parametru funkcji ( https://www.python.org/dev/peps/pep-0008/#other-recommendations ) I gdzie tu zasada, że nieważne, jak czynisz, masz ZAWSZE czynić tak samo?

Przy formułach matematycznych można zaznaczać asocjację spacjami, np. 2*x + 3*y ( https://www.python.org/dev/peps/pep-0008/#other-recommendations ) Nie, wróć, to jest „chimera”, nie wolno tak czynić, należy zawsze dawać spacje i pisać tak: 2 * x + 3 * y ( https://caml.inria.fr/resources/doc/guides/guidelines.en.html )

Etc, etc.


Tak, wiem, że moja niechęć do przestrzegania tych wszystkich reguł i moje niezrozumienie dla nich wynika pewnie z tego, że wciąż jestem studentem i w związku z tym nigdy nie zajmowałem się utrzymywaniem większego codebase’u. Tak, wiem, że skoro mądrzejsi ode mnie twierdzą, że to, której spośród dwóch równoważnych konstrukcji użyję, i kiedy należy a kiedy nie wolno stawiać spacji, nowych linii, etc, ma kardynalne znaczenie, to pewnie ma.

Tym niemniej, nic nie poradzę, ale obecnie dla mnie jest to jakiś totalitaryzm. Wymuszanie najdrobniejszych pierdół z pedanterią i uporem godnym lepszej sprawy. Jak dla mnie to, czy otwierający nawias klamrowy jest na osobnej, czy poprzedniej linii, jest W NAJWYŻSZYM STOPNIU BEZ ZNACZENIA. To wcięcie ułatwia czytanie, a nie klamry. Mało tego: wymuszanie, by w całym projekcie było tak samo, uniemożliwia rozróżnienie między większą, poważniejszą funkcją (każda klamra na osobnej linii) a małą funkcyjką pomocniczą (klamry w tych samych linijkach, co kod). Tak kiedyś zacząłem robić, bo wydawało mi się, że jest to sensowne. I dostałem po łapach. BO MA BYĆ WSZĘDZIE TAK SAMO.

Sprzeczne zalecenia w różnych też nie pomagają. A przede wszystkim: jeszcze raz: Nijak nie rozumiem, jak można WYMUSZAĆ na ludziach, by takich PIERDÓŁ przestrzegali. To jakiś totalitaryzm.

Dla mnie to są opary absurdu przypominające wymaganie, by w kościele:

siedzieć prosto, nie krzyżując nóg, opierając stopy całą powierzchnią o podłogę. Kolana kobiet powinny się stykać, a kolana mężczyzn powinny być w odległości od siebie o kilka centymetrów.

( http://wojciech.bialystok.pl/index.php?option=com_content&task=view&id=514 )


Skąd taki nacisk na przestrzeganie podobnych wymogów?

4

A chciałbyś prowadzić samochód w mieście, gdzie na pewnych skrzyżowaniach pierwszeństwo ma prawa strona a na innych lewa? Gdzie farba na drodze jest czasem biała, a czasem czarna? Gdzie niektóre sygnalizatory mają kolory ZŻC, a inne CŻZ? Gdzie niektóre ulice mają ruch prawostronny, a niektóre lewostronny?

Kod to nie literatura, różnorodność nie jest w cenie. Jeśli się zgadzasz z daną konwencją to nie wiem jaki masz problem z trzymaniem się jej? Więcej wysiłku wymaga stawianie klamry w nowej linii? A jeśli się nie zgadzasz to walcz o zmianę konwencji albo zmień projekt.

I gdzie tu zasada, że nieważne, jak czynisz, masz ZAWSZE czynić tak samo?

ZAWSZE oznacza "ZAWSZE w danym kontekście w danym projekcie".

3

Zawsze muszą być spacje wokół operatora przypisania =. Nie, wróć, ma nie być spacji jeśli oznacza on domyślną wartość parametru funkcji

Wtedy nie jest to operator przypisania jako tako. Tak samo jak np. w C++ klamra { raz oznacza blok kodu, a raz inicjalizator.

I gdzie tu zasada, że nieważne, jak czynisz, masz ZAWSZE czynić tak samo?

Powołujesz się na dwa różne dokumenty i dziwisz się, że każą formatować inaczej? ;-)

Mało tego: wymuszanie, by w całym projekcie było tak samo, uniemożliwia rozróżnienie między większą, poważniejszą funkcją (każda klamra na osobnej linii) a małą funkcyjką pomocniczą (klamry w tych samych linijkach, co kod).

Jak zdefiniujesz większą, poważną funkcję, a jak małą funkcyjkę?
Czy pomocnicza pętelka for powoduje, że funkcyjka przestaje być funkcyjką?
Czy wywoływanie innych, pomocniczych funkcyjek powoduje, że funkcyjka przestaje być funkcyjką?
Gdzie leży jednoznaczna granica i dlaczego wielka, poważna funkcja nie zostanie po ludzku zrefaktoryzowana?

Sprzeczne zalecenia w różnych też nie pomagają.

Nie ma sensu tworzenie uniwersalnego poradnika how to format my code, bo należy się dostosować do projektu, w którym się pracuje (aby utrzymać jednorodność).
Jeśli z kolei zaczynasz nowy projekt, na ogól możesz sobie dobrać taki styl, jaki Ci się podoba (choć przeważnie wypadałoby się dostosować do ogólnych zasad w firmie).

Skąd taki nacisk na przestrzeganie podobnych wymogów?

Aby nie skończyć tak jak format PSD #pdk ;-)
Załóżmy, że dwóch inżynierów buduje komputer - wolałbyś, aby każda śrubka wymagała innego rodzaju śrubokręta, czy wszystkie były identyczne?

0
twonek napisał(a):

A chciałbyś prowadzić samochód w mieście, gdzie na pewnych skrzyżowaniach pierwszeństwo ma prawa strona a na innych lewa? Gdzie farba na drodze jest czasem biała, a czasem czarna? Gdzie niektóre sygnalizatory mają kolory ZŻC, a inne CŻZ? Gdzie niektóre ulice mają ruch prawostronny, a niektóre lewostronny?

Patryk27 napisał(a):

Załóżmy, że dwóch inżynierów buduje komputer - wolałbyś, aby każda śrubka wymagała innego rodzaju śrubokręta, czy wszystkie były identyczne?

Ale w mieście jak jeden jedzie lewą stroną to uniemożliwia innym jechanie prawą, i na odwrót.I różne rodzaje śrubokrętów też wymagają za każdym razem zastanawiania się, który pasuje.

Natomiast w przeciwieństwie do tego to, że jeden programista postawi spację dookoła operatora dodawania, w żaden sposób nie przeszkodzi drugiemu programiście tej spacji nie postawić.

Patryk27 napisał(a):

Gdzie leży jednoznaczna granica

A po co doszukiwać się jednoznacznej granicy, przecież tu nie chodzi o kwestie obiektywne, tylko o intencję piszącego, która jest subiektywna z definicji.

0

Ale w mieście jak jeden jedzie lewą stroną to uniemożliwia innym jechanie prawą,

To zmieniłoby się zasady, aby nie uniemożliwiał. Ale tylko w piątki od 7 do 9 rano. Oraz w soboty. Oraz w nieparzyste dni roku. No i oczywiście w adwent.

A po co doszukiwać się jednoznacznej granicy, przecież tu nie chodzi o kwestie obiektywne, tylko o intencję piszącego, która jest subiektywna z definicji.

Przez co w efekcie otrzymasz kod:

Node* findNodeByName(Node* node, string name) { Node* tmpNode = node; while (tmpNode) { if (!strcmp(tmpNode->name, name.c_str())) { return tmpNode; } tmpNode = tmpNode->next; } return nullptr; }

bool doSomething(Node* nodeA, Node* nodeB) {
	if (findNodeByName(nodeA, nodeB->name)) {
		return doSomething(nodeA->next, nodeB->name);
	} else {
		if (nodeA->value == nodeB->value) {
			return true;
		}
		
		return doSomething(nodeA->parent->next, nodeB->name);
	}
}

Bo dla tego, który pisał findNodeByName funkcja będzie tylko pomocnicza, a z kolei dla osoby piszącej doSomething kod już będzie robił coś poważnego.

4

Tym niemniej, nic nie poradzę, ale obecnie dla mnie jest to jakiś totalitaryzm.
Wymuszanie najdrobniejszych pierdół z pedanterią i uporem godnym lepszej sprawy.

Hmm... a czemu napisałeś tak:

Wymuszanie najdrobniejszych pierdół z pedanterią i uporem godnym lepszej sprawy.

a nie tak:

"Wymószanie najdrobniejszyh pierduł z pedanterio i óporem godnym lepszej sprawy"

albo tak:
"Vymušanie najdrobniešyh pierduv z pedanteriou i uporem godnym lepšej spravy" (na czeską modłę).
?

Po prostu dlatego, że zaakceptowałeś pewien standard ortografii obowiązujący w języku polskim. Standard, który jest subiektywny (mnie się np. lepiej podobają daszki niż sz, cz - ale tak się pisze już i trudno).

W NAJWYŻSZYM STOPNIU BEZ ZNACZENIA.

jeśli jest bez znaczenia, to o co ten ból d**y? Ja np. preferuję indentację 4 spacjami - ale jak ktoś mi każe powiedzmy robić 2 spacje czy taby, to whatever.

BO MA BYĆ WSZĘDZIE TAK SAMO.

jest takie słynne powiedzenie w informatyce "kod się pisze głównie po to, żeby ludzie go czytali i tylko czasami po to, żeby komputer go uruchamiał". Spójny styl w całym projekcie i spójne konwencje (formatowanie to tylko wierzchołek góry lodowej! Nazewnictwo zmiennych, struktura plików, stosowane wzorce projektowe itp. itd.) poprawia czytelność i przewidywalność całego projektu. Czasem też chodzi o diffy w Gicie (np. jeśli masz długą tablicę to jeśli zrobisz tak, że każdy element będzie w nowej linii (JS):

[
  'pierwszy element tablicy',
  'drugi element tablicy',
  'trzeci element tablicy',
]

sprawi, że ktoś będzie mógł wyedytować linię z "drugi element tablicy" bez ruszania pozostałych (co ma wpływ na czytelność diffów i zmniejsza ryzyko wystąpienia konfliktu wersji w Git). Jeśli byś miał taką tablicę:

[  'pierwszy element tablicy',  'drugi element tablicy',  'trzeci element tablicy']

to ruszenie dowolnego elementu sprawiało by, że wg Gita (czy również wg różnych GUI obsługujących pod spodem Gita) ruszyłbyś wszystko (czyli mniej czytelne commity i większe ryzyko wystąpienia konfliktów). A w pracy zespołowej to jest ważne, bo jak diffy są nieczytelne to potem traci się czas na code review. Wolisz się stosować do zasad czy słuchać potem uwag przez pół godziny, że masz źle, a potem ktoś by się ogarnął i powiedział "eee, przepraszam, jednak masz dobrze, ale formatowanie się rozjechało i myślałem, że napisałeś XYZ a napisałeś XZA (miewałem tak, że nieporozumienia wynikały ze złych diffów czy formatowania/*/).

Czyli nie zawsze to jest czyste widzimisię.

Tak kiedyś zacząłem robić, bo wydawało mi się, że jest to sensowne. I dostałem po łapach. BO MA BYĆ WSZĘDZIE TAK SAMO.

To powinno być wymuszane z automatu przez linter. Jeśli dostałeś po łapach od kolegi to raz, że twoje ego ucierpiało, dwa, że być może straciłeś czas na poprawianie (ja też dostawałem po łapach, i w sytuacji kiedy te zmiany wypływały z czyjegoś widzimisię "ej, ja bym to zrobił inaczej, zrób tak i tak" traciłem w sumie dużo czasu na poprawki). Z drugiej strony jak masz linter, to jesteś w stanie z automatu narzucić pewien styl pisania, i masz na żywo podgląd, czy robisz błędy formatowanie czy nie. Więc zamiast tracić z pół godziny na poprawki formatowania w commicie (więcej czasem traciłem), tracisz z minutę.

/*/ może kiedyś pojawią się bardziej semantyczne systemy kontroli wersji operujące np. na drzewach składni (AST) a nie na tekście, wtedy przestałoby może mieć to takie znaczenie

0

A po co doszukiwać się jednoznacznej granicy, przecież tu nie chodzi o kwestie obiektywne, tylko o intencję piszącego, która jest subiektywna z definicji.

Po to jest wspólna konwencja by można było było zgadnąć co autor miał na myśli. Bez tego nie jest zgadywanie tylko ciuciu babka.

0
LukeJL napisał(a):

"Wymószanie najdrobniejszyh pierduł z pedanterio i óporem godnym lepszej sprawy"

Nie, nie. Ten tekst się nie kompiluje. To, co piszesz, to jest raczej analogia do pytania, czemu mam pisać bool w C++ ale boolean w Javie, bo ja chcę sobie pisać bool w Javie.

Analogią z języka naturalnego do tego, o czym ja piszę, jest raczej, gdyby ktoś wymuszał, by jego podwładny ZAWSZE pisał „jeżeli” w służbowych notatkach, a nigdy nie śmiał napisać „jeśli”. Albo na odwrót, gdyby ktoś kazał ZAWSZE pisać „jeśli”, nigdy zaś – „jeżeli”.

Albo gdyby ktoś za chwilę dał mi po łapach, że w zdaniu wyżej napisałem „nigdy zaś”, bo obowiązkowo powinienem był napisać: „natomiast nigdy”,

2

Dobrą praktyką jest odgórne zdefiniowanie konwencji. Mam tu na myśli zdefiniowanie jej w IDE i wgranie tej samej konfiguracji u wszystkich. Pisz sobie jak chcesz, a przed pushem IDE przeformatuje z automatu kod zgodnie z konwencją. Tak samo u wszystkich.

O ile wiem, taką możliwość ma InteliJ i klony (jak np Android Studio), VS niestety nie (tzn, ma ale sam przed pushem tego nie zrobi, trzeba ręcznie)

3

"Clean Code: A Handbook of Agile Software Craftsmanship" - ta książka odpowiada na wszystkie twoje pytania. Jeśli poważnie pytasz, a nie trollujesz z nudów, to bierz się do lektury i wróć do dyskusji po przeczytaniu.

Na marginesie - wcale nie ma obowiązku bycia dobrym programistą. Nie chcesz to nie.

2

Tak jest łatwiej, przecież zazwyczaj nie pracujesz sam. Do tego niektórych irytuje niechlujstwo. Mnie np. robi się słabo jak widzę różne style w tym samym pliku ;)

0
aurel napisał(a):

"Clean Code: A Handbook of Agile Software Craftsmanship" - ta książka odpowiada na wszystkie twoje pytania. Jeśli poważnie pytasz, a nie trollujesz z nudów, to bierz się do lektury i wróć do dyskusji po przeczytaniu.

Czytam. ALe nie mogę się powstrzymać, by nie komentować na poczekaniu.

Second, the smallest bit of sloppy construction, of the door that does not close tightly or the slightly crooked tile on the floor, or even the messy desk, completely dispels the charm of the larger whole. That is what clean code is about.

The Seiton quote from above flowed from the pen of an Ohio minister who literally viewed neatness “as a remedy for every degree of evil.” How about Seiso? Cleanliness is next to godliness. As beautiful as a house is, a messy desk robs it of its splendor.

Did we Do our Best to “leave the campground cleaner than we found it”?

Having completed this exercise in lofty insights, I am off to clean my desk.

Akurat porównania do uporządkowanego biurka są zabawne, gdyż wygląda na to, że podług P.T. Naukowców bałagan na biurku jest powiązany z twórczym, kreatywnym myśleniem: http://www.dailymail.co.uk/sciencetech/article-2385384/University-Minnesota-study-finds-working-cluttered-environment-makes-creative.html

The name of a variable, function, or class, should answer all the big questions. It should tell you why it exists, what it does, and how it is used. If a name requires a comment, then the name does not reveal its intent.
int d; // elapsed time in days
The name d reveals nothing. It does not evoke a sense of elapsed time, nor of days. We should choose a name that specifies what is being measured and the unit of that measurement:
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;

Ha. W takim razie cin i cout to bardzo złe nazwy. W zasadzie całe tradycyjne nazewnictwo unixowe jest do śmieci. Sorry, ale pthread_mutex_unlock to nowe wymysły. Jak to się ma do takiego np. semctl?

Według Linux kernel coding style:

C is a Spartan language, and so should your naming be. Unlike Modula-2 and Pascal programmers, C programmers do not use cute names like ThisVariableIsATemporaryCounter. A C programmer would call that variable tmp, which is much easier to write, and not the least more difficult to understand.

Wracając do książki:

With modern Java environments we enjoy automatic code completion. We write a few characters of a name and press some hotkey combination (if that) and are rewarded with a list of possible completions for that name. It is very helpful if names for very similar things sort together alphabetically and if the differences are very obvious, because the developer is likely to pick an object by name without seeing your copious comments or even the list of methods supplied by that class.

LOL. kiedyś tam próbowałem coś zrobić w Unity3D. MonoDevelop rzekomo miał code completion. Ale wkurzyłem się i wyłączyłem ten “feature” w cholerę. Dlaczego? Bo dla przyczyny dla mnie dotąd niepoznanej code completion blokował możliwość normalnego pisania czasem nawet tak podstawowych słów kluczowych jak int, zamiast tego wstawiając tam jakieś funkcje biblioteczne zaczynające się od liter int. Nie pamiętam, może nawet dało się zostawić podpowiedzi przy wyłączeniu autouzupełniania. Uff, jak denerwująca była ta plakietka, która uniemożliwiała patrzenie na to, co jest linijkę niżej… Wraz z wyłączeniem code completion spadła moja chęć do używania wielowyrazowych nazw zmiennych.

EDIT: W zasadzie, czytając ten rozdział o nazewnictwie dalej, nie mogę się oprzeć wrażeniu, że grep, cat, itp, to też bardzo złe nazwy. Shame on you, UNIX!

2

No co do unixowego nazewnictwa to w pełni się zgadzam - durne. Ale, ale że powstało w czasach "glinianych tabliczek" to nie wynika tylko z czystej głupoty i złośliwości. (Ale np. z tego, że na cudach takich jak PDP-7 nie za bardzo dało się pisać elaboraty :-) ).

0

Teraz z kolei się dowiaduję, że funkcje mają mieć 3-4 linijki kodu tylko, i że to jest bardzo ważne, bo ta zasada jest ściśle powiązana z dogmatem, że

FUNCTIONS SHOULD DO ONE THING. THEY SHOULD DO IT WELL. THEY SHOULD DO IT ONLY.

Całe kilka stron autor poświęca na to.

Uff... Myślę, że pan LInux TOrvalds nie jest złym koderem:

static void freeze_enter(void)
{
	spin_lock_irq(&suspend_freeze_lock);
	if (pm_wakeup_pending())
		goto out;

	suspend_freeze_state = FREEZE_STATE_ENTER;
	spin_unlock_irq(&suspend_freeze_lock);

	get_online_cpus();
	cpuidle_resume();

	/* Push all the CPUs into the idle loop. */
	wake_up_all_idle_cpus();
	pr_debug("PM: suspend-to-idle\n");
	/* Make the current CPU wait so it can enter the idle loop too. */
	wait_event(suspend_freeze_wait_head,
		   suspend_freeze_state == FREEZE_STATE_WAKE);
	pr_debug("PM: resume from suspend-to-idle\n");

	cpuidle_pause();
	put_online_cpus();

	spin_lock_irq(&suspend_freeze_lock);

 out:
	suspend_freeze_state = FREEZE_STATE_NONE;
	spin_unlock_irq(&suspend_freeze_lock);
}

https://github.com/torvalds/linux/blob/master/kernel/power/suspend.c

Mamy tutaj 8 sekcji kodu w tej funkcji. Przypuszczam, że autor książki kazałby zatem wydzielić z tej funkcji co najmniej 8 mniejszych funkcji.

A ciekawe jest, że kernel coding style też pisze, iż:

Functions should be short and sweet, and do just one thing.

https://www.kernel.org/doc/html/latest/process/coding-style.html

Edit: @datdata, czemu usunąłeś post? Akurat Twój komentarz pod postem rzeczywiście dał mi do myślenia, na to już nie miałem prostej odpowiedzi :) Szkoda.

EDIT2: Według książki:

Side effects are lies. Your function promises to do one thing, but it also does other hidden things. Sometimes it will make unexpected changes to the variables of its own class. Sometimes it will make them to the parameters passed into the function or to system globals. In either case they are devious and damaging mistruths that often result in strange temporal couplings and order dependencies.

No dobrze, ale w takim razie jak zrobić np. cache’owanie? Przenieść odpowiedzialność za cache’owanie na każdego, kto woła funkcję? Wygląda na beznadziejny pomysł.

Weźmy np. liczenie długości ciągów Collatza:

unsigned int NextCollatzValue(unsigned int value) {
    if(value%2 == 0)
        return value/2;
    else
        return 3*value+1;
}

unsigned int CollatzSequenceLength(unsigned int value) {
    if(cache[value-1] == 0)
        cache[value-1] = CollatzSequenceLength(NextCollatzValue(value));
    return cache[value-1];
}

Kto to ma cache’ować? Kazać każdemu, kto woła tę funkcję, cache’ować rezultat, to doprowadzić do szału wszystkich, którzy mogą funkcji używać.


Wydzielenie NextCollatzValue było dlatego, że tylko podzielenie tej funkcji na dwie stosuje b. rygorystyczne wymogi książki, by funkcja robiła TYLKO JEDNĄ RZECZ. W zasadzie, czy jednak nie prościej i czytelniej napisać tak?

unsigned getCollLength(unsigned n) {
    if(cache[n-1]) == 0)
        cache[n-1] = getCollLength(n%2==0 ? n/2 : 3*n+1);
    return cache[n-1];
}

EDIT: Kolejny fragment książki, który zdaje się zabraniać cache’owania:

Functions should either do something or answer something, but not both. Either your function should change the state of an object, or it should return some information about that object. Doing both often leads to confusion.

2

@kmph, Mam do ciebie gorącą prośbę. Dziel się tymi swoimi przemyśleniami na rozmowach rekrutacyjnych :)

Uff... Myślę, że pan LInux TOrvalds nie jest złym koderem:

Akurat ta funkcja wpasowuje się pięknie w przykłady z Clean Code. Chyba nie doczytałeś dokładnie. Takie przykłady są też w książce i są wyjaśnione. W funkcji freeze_enter nie ma kolejnych stopni logiki. Jeśli żeby zrobić freeze_enter, musisz zrobić kilka innych rzeczy, to to jest OK, póki są one na tym samym poziomie. Nie jest ok, jeżeli byłoby to coś takiego:

static void freeze_enter(void)
{
    spin_lock_irq(&suspend_freeze_lock);
    if (pm_wakeup_pending())
        goto out;
	else
		if (x == 2) goto out;
		else if (x == 3) xxxx(); else yyyy();
		else goto out;
	
	for (i = 0; i < x; i++) {
    suspend_freeze_state = FREEZE_STATE_ENTER;
    spin_unlock_irq(&suspend_freeze_lock);
 
    if (get_online_cpus()) 
	{
		if (cpuidle_resume())
			cpuidle_resume();
	}
 
    /* Push all the CPUs into the idle loop. */
    if (wake_up_all_idle_cpus())
	{
		goto out;
	}
	
	while (x--) {
     pr_debug("PM: suspend-to-idle\n");
    /* Make the current CPU wait so it can enter the idle loop too. */
    wait_event(suspend_freeze_wait_head,
           suspend_freeze_state == FREEZE_STATE_WAKE);
    pr_debug("PM: resume from suspend-to-idle\n");
    }
	
    cpuidle_pause();
    put_online_cpus(); }
 
    spin_lock_irq(&suspend_freeze_lock);
 
 out:
    suspend_freeze_state = FREEZE_STATE_NONE;
    spin_unlock_irq(&suspend_freeze_lock);
}

Co, dalej jest ładnie?
Jak nie widzisz różnicy, to daj se spokój.
Jesteś na etapie, w którym powinieneś się uczyć, a nie kontestować coś, o czym nie masz pojęcia.

No dobrze, ale w takim razie jak zrobić np. cache’owanie?

Może po prostu nazwać funkcję DoSomethingAndCacheTheResult?

0

Kod danej funkcji nie musi robić tylko jednej rzeczy, ale może też robić jedną, ale jego złożoność cyklomatyczna nie powinna być zbyt duża, aby szło łatwo przetestować wszystkiego jego funkcjonalności.

Clean code to dodatek do jakości kodu, ale do jakości oprogramowania liczy się trochę więcej funkcjonalności.

0

W projektach mamy takie powiedzenie: "Jasno płonie... szybko zgaśnie" :-/

A poważniej, praca z innymi różni się w poważnym stopniu od pisania kodu dla siebie/na zaliczenie/hobbystycznie. Są rzeczy ważne i są rzeczy ważniejsze. Tak dla Ciebie jak i dla Innych. Akceptujesz zasady kultury danego społeczeństwa aby w nim egzystować, akceptuj więc konwencje obowiązujące w danym projekcie. Artykułowanie sugestii zmiany czegoś możliwe jest poza dwoma skrajnościami "to jest bez sensu, głupie, niespójne ... " lub "biernym oporem: będę robił jak będę chciał".
Proszę przeczytaj "Clean Code". Jeszcze lepiej zerknij na filmy z udziałem Wujka. Przekonasz się że naturalna skłonność umysłu do wyszukiwania "ale" oraz wyjątków, ma znaczenie na etapie odkrywania a nie w tych obszarach gdzie liczy się dobra komunikacja i zaspokajanie potrzeb klienta (wiem że możesz jeszcze tego nie ... odczuwać, ale to ON płaci :-))

1

99% takich glupot jak whitespace czy gdzie klamry sie maja otwierac mozna latwo wymusic konfiguracja IDE i/lub po prostu robic autoformatting jesli dostajesz kod po programiscie ktory ma za malo wyczucia estetyki, doswiadczenia i empatii w stosunku do kolegow.
praca programisty to glownie czytanie kodu wiec formatowanie ma znaczenie, ale przyznam ze w praktyce nie zdarzylo mi sie borykac z takimi problemami, bo to serio jest zwykle do zalatwienia jednym skrotem klawiszowym.
wiekszymi problememami wynikajacymi z niedbalstwa sa np tajemnicze/kretynskie nazewnictwo czy duplikowanie kodu.

0
Mokrowski napisał(a):

Proszę przeczytaj "Clean Code".

Czytam, czytam, wczoraj do czwartej nad ranem czytałem, aż mi się tak oczy zamgliły, że przestałem rozumieć literki… ale dzisiaj już chyba dam sobie spokój, bo mam inne rzeczy do roboty… Ale wrócę do lektury co prędzej.

aurel napisał(a):

@kmph, Mam do ciebie gorącą prośbę. Dziel się tymi swoimi przemyśleniami na rozmowach rekrutacyjnych :)

LOL, mam nadzieję, że żaden z potencjalnych pracodawców nie ogarnie się, że ja mam tutaj nick @kmph… bo inaczej chyba wylecę zanim mnie przyjmą ;P

aurel napisał(a):

Jesteś na etapie, w którym powinieneś się uczyć, a nie kontestować coś, o czym nie masz pojęcia.

Tak wiem, że masz rację. Tyle, że ta to kontestuję z powodów… filozowicznych :) A ja tak mam, że jak mi coś filozoficznie nie pasuje, to drążę w nieskończoność, denerwując wszystkich dookoła w cholerę. Dlatego też np. w czasach podstawówkowych kontestowałem konieczność wypisywania danych i szukanych. I mimo to nauczyłem się rozwiązywać zadania z treścią.

aurel napisał(a):

Może po prostu nazwać funkcję DoSomethingAndCacheTheResult?

No ale to jest przecież ten, jak to się nazywa… Tajemnica Implementacji, czyż nie? Tego, kto woła tę funkcję, nie obchodzi, czy funkcja dla celów optymizacyjnych będzie coś tam cache’ować, czy nie. Tego, kto woła tę funkcję, obchodz tylko wynik. Informowanie go, że pod spodem zachodzi jakieś cache’owanie, to tylko hałas.

Mokrowski napisał(a):

A poważniej, praca z innymi różni się w poważnym stopniu od pisania kodu dla siebie/na zaliczenie/hobbystycznie.

LOL. Ile to już miałem pomysłów na hobbystyczny projekt… I żaden niezrealizowany jak dotąd. ALe to inny temat.

0

@kmph kluczem w tym wszystkim jest jednolitość. Nie ważne jak ktoś stawia te cholerne klamry, ale jak w całym projekcie jest tak samo to patrząc na taki kod masz poczucie porządku i łatwiej się go czyta i o to w tym wszystkim chodzi.

Są rzeczy typu editorconfig, czy eslint które załatwiają to za Ciebie. U nas w projekcie udało mi się wymusić, żeby ustalić jeden styl i eksportować go dzięki ficzerowi PHPStorma (Copying Code Style Settings). Teraz każdy importuje te same ustawienia, robi ctrl + alt + l i po sprawie :)

0

Moja osobista opinia - programiści to drogie bydlęta których jest niestety bardzo ograniczona liczba. To z definicji wymusza presję na ciągły wzrost wynagrodzeń. To z kolei jest niepożądane dla firm które ich zatrudniają - dają więc sygnał w dół żeby jakoś to ograniczyć. A jak to zrobić tak żeby przypadkiem programista nie czuł się niedocieniony i odszedł? To proste, trzeba obniżyć jego samoocenę, wytknąć mu błędy i niedopatrzenia :)

Co z tego że dowozi taski na czas, że jego kod ma statystycznie mniej błędów niż u reszty - nie postrzega jakichś tam dobrych praktyk więc musi popracować nad tym żeby dostać podwyżkę :D

1

Kod danej funkcji nie musi robić tylko jednej rzeczy,

Kod funkcji powinien robić jedną rzecz, co nie znaczy że musi to być rzecz niepodzielna, bo takich praktycznie nie ma.

Przykładowo, jeżeli wystrzelenie rakiety nuklearnej składa się z otwarcia wyrzutni, uzbrojenia głowicy i odpalenia silnika, to są to „trzy rzeczy”, ale konceptualnie można je łącznie nazwać «wystrzeliwaniem rakiety», co jest „jedną rzeczą”.
Z drugiej strony, ta sama funkcja nie powinna uzbrajać głowicy i jednocześnie zamawiać frytek, bo to nie jest „jedna rzecz”.

ale może też robić jedną, ale jego złożoność cyklomatyczna nie powinna być zbyt duża,

Nie jestem fanem fanatycznego redukowania złożoności cyklomatycznej, uważam to za sztuczny wyznacznik który wcale nie determinuje jakości kodu.

EDIT: przykład bardziej z życia: prawidłowa inicjalizacja OpenGL (w wersji 3+) pod Windows oznacza potrzebę wykonania kolejno (pseudokod):

RegisterClass()
CreateWindow()
GetDC()
ChoosePixelFormat()
SetPixelFormat()
wglCreateContext()
wglMakeCurrent()
wglGetProcAddress()
wglMakeCurrent()
wglDeleteContext()
DestroyWindow()
CreateWindow()
GetDC()
wglChoosePixelFormatARB()
SetPixelFormat()
wglCreateContext()
wglMakeCurrent()
glViewport()

Serio. To jest absolutne minimum, bez ustawiania parametrów sceny. Życzę powodzenia komuś, kto ściśle upiera się przy robieniu jednej rzeczy.

1
kmph napisał(a):

Teraz z kolei się dowiaduję, że funkcje mają mieć 3-4 linijki kodu tylko, i że to jest bardzo ważne, bo ta zasada jest ściśle powiązana z dogmatem, że

FUNCTIONS SHOULD DO ONE THING. THEY SHOULD DO IT WELL. THEY SHOULD DO IT ONLY.

Całe kilka stron autor poświęca na to.

Widocznie autor ma nadzieję, że jak powtórzy tak drastyczna opinię wystarczającą ilość razy, to nawet największe matoły będą pisały funkcje na 20 linijek, a nie na 800. A to już byłby spory postęp w programowaniu, prawdopodobnie nawet większy niż wynalezienie komputera.

"Clean code" to zbiór dość radykalnych wskazówek. Nie sądzę, żeby dało się napisać sensowny program trzymając się ich wszystkich. Kod może być ładny nawet z częstymi odstępstwami od tych wskazówek, tylko wszystko trzeba robić świadomie i z głową.

Kto to ma cache’ować? Kazać każdemu, kto woła tę funkcję, cache’ować rezultat, to doprowadzić do szału wszystkich, którzy mogą funkcji używać.

No nie możesz tak zrobić, bo 80% konsumentów nie będzie niczego keszowała. Jeśli jakiś algortym/ficzer działa lepiej z cache, to Ty jako autor musisz o to zadbać.

Wydzielenie NextCollatzValue było dlatego, że tylko podzielenie tej funkcji na dwie stosuje b. rygorystyczne wymogi książki, by funkcja robiła TYLKO JEDNĄ RZECZ. W zasadzie, czy jednak nie prościej i czytelniej napisać tak?

Może i prościej, ale raczej nie czytelniej. Mamy tu dwie czynności, co szkodzi utworzyć dwie funkcje? I do tego ta okropna rekurencja.

EDIT: Kolejny fragment książki, który zdaje się zabraniać cache’owania:

Functions should either do something or answer something, but not both. Either your function should change the state of an object, or it should return some information about that object. Doing both often leads to confusion.

Nikt niczego nie zabrania, wystarczy mieć jedną funkcje do obliczeń, drugą do cache, oraz trzecią wystawiającą te operacje publicznie. W tej zasadzie głównie chodzi o to, żeby nie mieć funkcji w rodzaju "ObliczWynik", które zwracają void, a wynik wyświetlają na konsoli.

0
somekind napisał(a):

I do tego ta okropna rekurencja.

Iteracyjnie trzeba robić własny stos, jeśli chce się cache’ować. Co jest złego w rekurencji?

somekind napisał(a):

wystarczy mieć jedną funkcje do obliczeń, drugą do cache, oraz trzecią wystawiającą te operacje publicznie.

Koniec końców mamy więc coś takiego:

unsigned int getNextCollatzValue(unsigned int value) {
    if(value%2 == 0)
        return value/2;
    else
        return 3*value+1;
}

void cacheCollatzSequenceLength(unsigned int value) {
    if(cache[value-1] == 0)
        cache[value-1] = getCollatzSequenceLength(unsigned int value) + 1;
}
 
unsigned int getCollatzSequenceLength(unsigned int value) {
    cacheCollatzSequenceLength(value);
    return cache[value-1];
}

Razem: 16 linijek

Alternatywnie:

unsigned int CollLength(unsigned int value) {
    if(cache[value-1] == 0)
        cache[value-1] = ColLength( value%2 == 0 ? value/2 : 3*value+1 ) + 1;
    return cache[value-1];

Razem: 4 linijki

Nawet, jeśli to powyższe jest trochę czytelniejsze, to zastanawiam się, czy przy czytaniu czas spędzony na rozumieniu tej krótszej wersji nie wyrówna się z czasem spędzonym na przeczytaniu tej dłuższej wersji (włącznie z wielowyrazowymi elaboratami w nazwach).

PS. Świadomie napisałem: ColLength( value%2 == 0 ? value/2 : 3*value+1 ) . Albowiem jeśli w argumencie funkcji są jakieś obliczenia, wtedy oddzielenie tego spacją od nawiasu wydaje mi się być czytelniejsze. Ale oczywiście autoformaterka kodu, wymuszona przez obowiązujący standard w projekcie, mi to obowiązkowo wywali.

1

Razem: 16 linijek
Razem: 4 linijki
Nawet, jeśli to powyższe jest trochę czytelniejsze, to zastanawiam się, czy przy czytaniu czas spędzony na rozumieniu tej krótszej wersji nie wyrówna się z czasem spędzonym na przeczytaniu tej dłuższej wersji (włącznie z wielowyrazowymi elaboratami w nazwach).

A można zapisać to w jednej linijce! Będzie jeszcze lepiej, nie?
No właśnie nie. Od dawna już nie mamy problemu z deficytem kilobajtów, dzięki czemu możemy sobie nazywać zmienne jak chcemy i nie musimy usuwać białych znaków.
Natomiast co do zysku czasowego - chyba rozumiesz, że twój przykład to bieda-przydkład? Zobaczysz kiedyś prawdziwe programy, prawdziwe klasy i prawdziwe metody i sam się przekonasz, czy czas się wyrówna. Ja tylko mogę z doświadczenia powiedzieć, że TAK, warto stosować dobre praktyki programowania.

@Shalom w komentarzu słusznie zauważył, to nie znaczy, że należy się ich ślepo trzymać. Ale łamanie tych zasad powinno być świadome i powodowane czymś więcej niż bunt nastolatka ;)

Albowiem jeśli w argumencie funkcji są jakieś obliczenia, wtedy oddzielenie tego spacją od nawiasu wydaje mi się być czytelniejsze.

Ta linijka jest nieczytelna.

2
kmph napisał(a):

Nawet, jeśli to powyższe jest trochę czytelniejsze, to zastanawiam się, czy przy czytaniu czas spędzony na rozumieniu tej krótszej wersji nie wyrówna się z czasem spędzonym na przeczytaniu tej dłuższej wersji (włącznie z wielowyrazowymi elaboratami w nazwach).

W studenckim przykładzie tego nie widać, ale w rzeczywistym świecie nie muszę czytać implementacji w ogóle, jeśli nazwa funkcji opisuje dokładnie, co ona robi. Dzięki temu oszczędzam czas.

PS. Świadomie napisałem: ColLength( value%2 == 0 ? value/2 : 3*value+1 ) . Albowiem jeśli w argumencie funkcji są jakieś obliczenia, wtedy oddzielenie tego spacją od nawiasu wydaje mi się być czytelniejsze. Ale oczywiście autoformaterka kodu, wymuszona przez obowiązujący standard w projekcie, mi to obowiązkowo wywali.

No tak, bo przecież wpieprzając obliczenia do wywołania funkcji oszczędzamy pamięć, którą zajęłaby zmienna. :P
I jakież to ułatwienie przy debugowaniu! :D

A ludzi, którzy stawiają spacje po ( i przed ), niezależnie czy w tekście pisanym, czy w kodzie programu, zwyczajnie się boję. To muszą być psychopaci, nikt normalny czegoś takiego by nie zrobił.

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