Archive for June 11th, 2008

Грижа за очите и душата

Wednesday, June 11th, 2008

През мен са минали доста сорсове, писани от различни хора. Целта на този пост не е да ви уча как да пишете професионално (къде дават дипломи за програмисти 🙂 ), а да пишете разбираемо. Винаги пишете с идеята, че някой друг след вас ще трябва да ви променя кода. Още по-добре – пишете с идеята, че вие самия ще трябва да си променяте кода след месеци… и няма да разберете какво сте написал.
Защо това е важно? Ъпгрейди винаги се налагат – хората искат добавяне на функции. Бъгове винаги се получават, колкото и безгрешно да пишете. Условията на средата се променят, входните параметри се променят, и накрая нещо ще трябва да се фиксва.
Рано или късно всеки сорс минава през преразглеждане. Мислете за колегата, на когото ще му се наложи да се оправя из вашите сорсове. Не ви е направил нищо лошо – не му тровете нервите. Не го карайте да ви псува.

Ето няколко основни правила за писане на четим код.
– Научете български. Научете и английски. Нека програмата ви да е поне граматически правилна.
– Пишете коментари – по много. Знам че в момента на писането всичко ви е ясно и програмата ви е в главата. След седмица или месец няма да помните че сте писал съответния код.
– Пишете документация. Поне описание на файловете и на включените библиотеки. Ако използвате функции, които са описани в други файлове, добре е да пишете кое от къде идва.

....
include("../../../../sys.php");
include("../../../lib.php");
include("../../../../../pre.php');
....
check($alpha);

От къде е дошла check()? Какво прави? Идете и преровете горните файлове, които може да са по сто хиляди реда код, а може и да include()-ват още сто файла.
– Именувайте променливите и функциите според това какво правят. Използвайте кратки имена, не по-дълги от 3-4 думи. Използвайте долни черти между думите, или пишете думите заедно, но всяка следваща дума да започва с главна буква. Не използвайте едносрични имена – не се опитвайте да пишете ‘бързо’ – пишете ‘четимо’. Не използвайте имена с номерация – ако имате няколко променливи, които имат еднаква фукция, може би е по-добре да ги вкарате в масив?
Лоши наименования:

check() //какво се проверява?
dosomeprettyboringstuffandmore() //опитайте се да го напишете няколко пъти
test_directories_check_users_update_db_on_exist() //ако една функция трябва да прави много неща, може би е по-добре да я разделите на няколко функции
$var //ами вижда се че е променлива
$var1, $var2, $var3 //още по-зле

Добри наименования:

run_query()
$thumb_path

– В много езици можете да използвате return value от една функция, като го пуснете като параметър на следващата функция и така навържете верига, която ви дава краен резулатат. НЕ ГО ПРАВЕТЕ! Удобно е, бързо е, изкушаващо е… и е убиец на мозъчни клетки. Особено ако работите със ваши функции.

$tmp .= (int $result[$_]). " (" .(sprintf "%.2f", 100 * $result[$_]/$votes). "%) " . "$inquiry{answer}[$_]
\n" for(0..$#{$inquiry{answer}});

– В същата връзка – избягвайте да пишете if then else на един ред, както и оператори за цикли.

foreach (array_keys($outbond) as $urlname) if (preg_match($short_name_regex, $urlname, $m)) $output{"\"$shorturl\" -> \"{$m[1]}"} = true;
else if ($debug) print "CATCH :: $urlname\n";

Колкото и засукано да го напишете, няма да станете по-добър програмист, ако ще и сто оператора да наредите на един ред. Горното написано както трябва:

foreach (array_keys($outbond) as $urlname){
if (preg_match($short_name_regex, $urlname, $m)){
$imeto = $m[1];
$output{"\"$shorturl\" -> \"$imeto\""} = true; //wsichko se typche v hasha $output
}
else {
if ($debug) print "CATCH :: $urlname\n"; //neshto kato nepredvidena situaciq
}
}

– Троичния оператор (ternary operator) е хитър и удобен, и както всичко хитро и удобно описано до тук – с него не трябва да се злоупотребява. Няма да ви заболи ако си го напишете с if-then-else.
Лош код:

while() { $_ =~ / (\?)?(pts\/0)?[ ]+\w+[ ]+\w+:\w+ perl/ && !($_ =~ /bin/) && !($_ =~ /lost/) ? print "found! $`$'" : print "";
$_ =~ /lost/ ? print "found .. self\n" : print "";}

– Не редете дълги и много условия в един if. Ако все пак се налага – разбийте ги на редове. Например:

if (
!preg_match('!^/!', $one_link) &&
!preg_match("!^(http://)?$shorturl!", $one_link) &&
!preg_match("!^\?!", $one_link) &&
!preg_match("!^#!", $one_link) &&
!preg_match("!^[\w\d_-]+?\.php\?!", $one_link) &&
!preg_match("!mailto!", $one_link) &&
preg_match("!^http://!", $one_link)
){.....


– Не смесвайте PHP/Perl + HTML + JavaScript + CSS !!! Няма нищо по-гадно от това да видиш променливи, напъхани измежду двойни, escape-нати кавички, цели блокове код затворени в if-switch блокове. Ако се налага да пишете уеб, особено ако става дума за нещо по-голямо от 2-3 странички – използвайте template система.

$tmp = "<form action=\"$ENV{SCRIPT_NAME}\" method=\"post\"><div>
<label>$inquiry{title}</label><br/><br/>\n";
$tmp .= "<input type=\"radio\" name=\"answer\" value=\"$_\"/> $inquiry{answer}[$_]<br/>\n" for(0..$#{$inquiry{answer}});
$tmp .= "<br/><input type=\"submit\" name=\"button\" value=\"Send\"/></div>\n".
"</form>\n";

Горните сорсове са писани както от мен така и от други хора. Предварително не се извинявам ако някой се засегне.