Mala škola programiranja - Addendum
Razbesneo sam Peđu prethodnim postom, pa je u svojoj noveli (pored ruganja pa i omalovažavanja iz njemu poznatih razloga) počeo da me “secira” i kroz negiranje mojih stavova izneo dosta nebuloznih izjava. Ne bih da se nastavljam na tom nivou, nemam ništa lično protiv njega što već nisam rekao, a i nemam vremena da odgovaram tekstom na 10 strana, samo ću da odgovorim na par najočiglednijih zabluda.
Pošto je ideja prvog članka očigledno svhaćena pogrešno, moram na početku i to da razjasnim. Ne pišem knjigu o programiranji, niti priručnik ni tutorial. Članak je služio samo da se ukaže na najčešće greške, a ne SVE greške. On me proziva kako sam “izostavio” dosta toga, što je tačno, ali sam i u samom tekstu rekao da ću da pišem o “istim greškama koje se stalno ponavljaju” a ako bude nastavak - biće kada stignem, ako stignem i ako budem imao potrebu. Članak nije namenjen početnicima i onima koji tek planiraju da uče programiranje, čak sam na kraju i rekao “ko ne može da čita i ovaj osnovni kod, neka čita Gloriju ili Politikin Zabavnik” jer ovo nije njemu namenjeno.
Nisam pisao o stilu jer je sam “ja navikao ovako”, naprotiv, ja sam posle jako puno godina menjao stil po potrebi timskom rada. Pored toga, loše napisanim kodom, pored loše preglednosti, izvršavaju se i nepotrebne instrukcije pa onda nije ni čudo da neki “programeri” čim puste sajt sa localhost na online server, imaju velike probleme sa performansama i sajtovi im se vuku. Obično je za to onda kriv provajder, hardware, project manager, Baba Kurana… svi osim onih koji napišu takav kod.
Koliko je glupo i pisati o stvarima tipa “ne izvršavajte SQL queries u petljama”? Da li ima svrhe pričati o tim stvarima? Kako uopšte autor takvog koda može za sebe da kaže da je programer. Zašto bih pisao o tome? To je kao da pričaš fudbaleru da ne trči unazad jer čak i ako i na taj način stigne tamo gde je krenuo - tamo više nije ni malo lepo za njega
Kada već pričamo o stilu, postoje značajne razlike koje dolaze sa iskustvom. Ako ste položili vožnju, setite se kako ste vozili na polaganju. Migavac, pogled u retrovizor, pogled levo, pogled preko desnog ramena, … pa lagano skrećeš, maksimalna brzina 10km/h. Posle nekog vremena vozačkog iskustva, vozite opuštenije, i efikasnije. Isto tako je i u programiranju, kada stekneš određeno iskustvo nećeš da pišeš:
$i = 1;
while ($i < 100)
{
// uradi nesto
$i++;
}
nego isto to napišeš skraćeno:
$i = 1;
while ($i++ < 100)
{
// uradi nesto
}
ili ako više voliš ovako:
$i = 1;
while (++$i <= 100)
{
// uradi nesto
}
I to što koristiš ++ operator ne samo da nije pogrešno, nego je i poželjno. I to je svakom programeru jasno. Kome nije jasno, neka čita jednostavniju literaturu. I da… TO JE ŠKOLSKI primer. Ako ti je, Peđa, neko nekada objasnio da se tako ne radi jer nije školski - imao si pogrešnog tutora.
Osmislio je i malo takmičenje “ko će da napiše najkraći kod za faktorijal funkciju”. Sorry, ali to su prvi koraci u programiranju, školovanom programeru je smešan taj “izazov”, ja sam se time bavio pre 25 godina, kada smo još uvek kod pisali u svesci i na tabli. Ne znam koja je ideja iza toga i šta pokušava da dokaže, ali nije ni bitno Dalje me ispravlja Peđa i kaže da je ovo pogrešno:
if ($a == 1)
{
return true;
}
return false;
A ovo ispravno:
if ($a == 1)
{
$result = true;
}
else
{
$result = false;
}
return $result;
Ako ćemo baš tačno po mom stilu ja bih, u ovom slučaju kada od vrednosti jedne varijable zavisi return koji je boolean, pre napisao ovako:
return $a == 1;
Zatim, ne vidim ni jedan razlog zašto bih uvodio novu varijablu $return koja služi samo da joj dodelim vrednost koju vratim iz funkcije. Osim što svaka nova varijabla oduzima memoriju (koliko - toliko, ako ima puno takvih - onda oduzima i puno memorije), usporava se i izvršenje funkcije jer umesto da se uradi return čim je ispunjen uslov: if ($a == 1), mi u peđinom slučaju imamo i dodatne instrukcije:
$return = true;
return $return;
Da li i jedan programer piše ovakav kod? Kada već imaš tako, zašto onda ne:
return true;
Naravno, ovo su prosti primeri, ponekad je potrebno da se izvrši nešto i pre return, ali takve situacije su izuzeci.
Kaže kako je “zabranjeno” imati 2 return komande? Ko ti je to objasnio? Kaže Peđa da mora da se piše ovako:
function nekaFunkcija ($var1)
{
if (!empty($var1))
{
if ($var1 > 0)
{
$data = DB::fetch ('SELECT ...');
if (!empty($data))
{
foreach ($data as $row)
{
// uradi nesto
}
$return = true;
}
else
{
$return = false;
}
}
else
{
$return = false;
}
}
else
{
$return = false;
}
return $return;
}
I to je školski? Priča nešto o blokovima kao “ako ima jedan ulaz, mora da ima i jedan izlaz”. Žao mi je, ali neko ti je jako pogrešno objasnio. Da li je čitkije to ili ovo dole uz jednu “malu” prepravku:
function nekaFunkcija ($var1)
{
if (!empty($var1))
{
if ($var1 > 0)
{
$data = DB::fetch ('SELECT ...');
if (!empty($data))
{
foreach ($data as $row)
{
// uradi nesto
}
// OVDE JE SAVRŠENO JASNO da je tu izlaz, kraj... i vraća se TRUE
return true;
}
}
}
return false;
}
Pored toga što je kraći kod, onome ko čita je savršeno jasno da tu odmah ide return. Ako ti umesto return true; dodeliš varijablu $return = true; onda prvo ne znaš šta sad sa tom varijablom, gde se ona koristi (osim ako nisi rezervisao baš tu varijablu sa tim imenom da uvek bude return), što je manji problem. Veći problem je što umesto da bude očigledno da je tu izlaz iz funkcije i koja vrednost se vraća, ti moraš da ideš do kraja funkcije da nađeš gde je taj famozni return $return; a ako si prvo nabasao tu, blage veze nemaš šta je vrednost $return. Da li je bilo true ili false? Hajde opet gore, traži gde se to desilo. To je naravno manji problem na kratkim funkcijama, ali na dužim procedurama, treba da se scroll-uje gore - dole.
Pošto ne volim da uvlačim previše u dubinu, ja bih ga napisao ovako:
function nekaFunkcija ($var1)
{
if (empty($var1))
{
return false;
}
if ($var1 <= 0)
{
return false;
}
$data = DB::fetch ('SELECT ...');
if (empty($data))
{
return false;
}
foreach ($data as $row)
{
// uradi nesto
}
return true;
}
a lično preferiram ovakav stil, koji nije školski ali je pregledniji (volim da poravnavam, šta ću)
function nekaFunkcija ($var1)
{
if (empty($var1)) { return false; }
if ($var1 <= 0) { return false; }
$data = DB::fetch ('SELECT ...');
if (empty($data)) { return false; }
foreach ($data as $row)
{
// uradi nesto
}
return true;
}
I koji je kod čitkiji? Osim toga, kada bi imalo još IF - ELSE, kod bi mogao da ode u dubinu … do desetog nivoa, a to je jedna od školskih “no - no” lekcija. Čak su i neki jako poznati programeri odavno govorili da ako ti kod ide dalje od 3. nivoa uvlačenja, onda taj kod treba prepraviti.
Nije ispunjen uslov? Odmah se vrati iz funkcije (return) šta ima dalje da kreiraš varijable, radiš novo else da bi do kraja funkcije izvršio još dve potpuno nepotrebne instrukcije. Output funkcije zavisi samo od IF - ELSE? Prvo gledaj da li su ispunjeni svi uslovi da se izvrši kod, ako nisu - vrati grešku i get the hell out of there, ako jesu - ide nastavak koda. To je prava logika. Jedan od retkih izuzetaka ovde je validacija formulara, kada hoćeš da proveriš šta je sve uneto pogrešno i vratiš sve od jednom, a ne jednu po jednu stvar.
Programiranje ne treba mistifikovati, i koristiti prirodan tok. Šta je prirodan tok? Zamisli da imaš goste na ručku, i treba da odeš na pijacu, u prodavnicu, spremiš klopu, postaviš sto, dočekaš ih, ugostiš i ispratiš. Kako ide prirodni sled događaja?
Jesi bio na pijaci? Nisi?
Pa šta ćeš da kuvaš, grdan? Vrati se odmah, nemoj ništa ni da proveravaš dalje, obavi kupovinu pa idi dalje. return false;
Jesi bio u prodavnici? Nisi?
Nećeš valjda da im služiš vodu sa česme? return false;
… i tako dalje (da ne gušim, jasna je logika)…
Tek ako su ispunjeni svi preduslovi (sve varijable su validne), možeš da dočekaš, ugostiš i ispratiš goste.
Kazaće neko “pa dobro, to je nekoliko linija koda”. Jeste, nekoliko linija u JEDNOJ funkciji, ali svaka iole ozbiljnija klasa ima nekoliko stotina linija koda, pa ako ima i nekoliko desetina klasa, to je velika ušteda ako ništa drugo samo u dužini koda, da ne pričamo o gomilama instrukcija koje se nepotrebno izvršavaju.
u 06:38
A mogao si i čitljivije:
if(empty($var1) or $var1
:)
u 03:51
Tekst je sasvim ok, samo bih hteo jos da dodam da je resenje sa preinkrementom za dlaku brze, ako cemo da cepidlacimo:
$i = 1;
while (++$i
u 03:54
jbni wordpress
Preinkrement je bolji kad god je to moguce iz razloga sto ne pravi bespotrebno jos jednu kopiju objekta na koji se primenjuje taj operator, dok postinkrement pravi…
u 04:12
Nisam znao za to da se pravi još jedna kopija objekta. Tnx