Archive for the ‘code’ Category

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

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”;

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

Карта на интернет

Tuesday, June 3rd, 2008

Нещо ме е хванала скуката. Пробвах да уча по Компютърни Архитектури, но резултата беше следобедна дрямка :)
Така че за да се измъкна за малко от творческата дупка, упражних малко PHP и регулярни изрази.
Резултата е налице - скрипт, който прави карта на ‘интернет’ :D
По-точно приема като параметър URL и тръгва по изходящите от там връзки. Изходяща е връзка към домейн различен от домейна на URL-то. Не се следят броя връзки, нито въпросното URL се crawl-ва до всяка под-страница. Така от всеки домейн се преглежда само по едно URL, което означава че картата е далееече от точност :) Ама я си представете от някой голям портал като dir.bg колко връзки навън има… и как се представят графично. За графичното представяне използвам Graphviz.
Вижда се че тук-таме субдомейните се представят като отделни сайтове. Примерно според скрипта idg.bg и www.idg.bg са две различни неща. Това е така, защото субдомейна www наистина може да е съвсем друг сайт :) Скрипта не проверява съдържанието буква по буква за съвпадение.
И естествено целия паяк има ‘ограда’, за да не тръгне да прави наистина карта на Интернет. Това което се вижда е на разстояние до 2 хопа от ivan.tu-plovdiv.info.
Извинявам се на сайтовете, които се виждат вътре за спамопободния трафик към тях.
Ето я й самата карта (не съм си играл с настройките за шарении):
out.jpg

А тук има същата карта, но този път се вижда малко по-далече - на 3 хопа разстояние. Всичко се върти около google, picasa, youtube, myspace… Хмм, виждат се и няколко бъга, които имат нужда оправяне :)

Нищо интересно

Friday, May 16th, 2008

Ами в последната седмица няма нищо интересно, за което да се пише. Заверките и изпитите са тук, всичко живо е изнервено. Курсовите работи и проектите тровят живота до дупка. Жегата в Пловдив и следобедното слънце блеснало в стаята ми допълнително нажежава атмосферата.
Който не е видял котката на Ебаси, lol-ната от мен - може да го стори тук.
Драснах едно тъпо PHP скриптче за смяна на тапета - можете да си го свалите от тук. Това което прави е да сваля случайно дупе от babene.ru в temp директория и да ви го лепва на десктопа. Можете да си го пъхнете в crontab и всеки ден да сте с изненадващ нов тапет.
FreeBSD-то на виртуалната машина все още върви. Разкарах му Х-а и почна да се държи по-добре :)
Виртуалната машина перманентно превзе един от десктопите ми с Windows XP и си направих 7-ми десктоп във Fluxbox-a. Чудя се как нормалните хора живеят само с един десктоп в Windows.
Открих топлата вода с Last.FM - можете да видите моя профил тук.

Имената на функциите всъщност били указатели

Wednesday, March 26th, 2008

Днес ни показаха един пиниз, според който имената на функциите в С са всъщност указатели към началния адрес на функцията като алгоритмична структура в кодовия сегмент на програмата. Т.е. като имаш адреса можеш да стартираш функцията.
Ето една програма, която показва файдата от цялата работа:

#include <stdio.h>
int test (int a){
printf(”A: %d\n”,a);
return a;
}
int druga (int a){
printf(”B: %d\n”,a);
return a-1;
}
int plqk (int (*test) (int a)){
printf(”Rez ot test(%d)\n”,(*test) (3));
return 0;
}
int main(void){
plqk(test);
plqk(druga);
plqk(main);
int * p = (int *) test;
printf(”test: %p\n”,test);
printf(”druga: %p\n”,druga);
printf(”p: %p\n”,p);
return 0;
}

За неразбралите - функцията plqk() извиква някоя от другите функции, като точно коя се записва във формалния параметър на бляк() :)

Асемблер за линукс

Thursday, March 13th, 2008

Днес доста учудващо ни накараха да пишем на асемблер, че и за x86 линукс. Сорса почти ни го метнаха на готово, ама се оказа че е доста елементарно. Което ме вкарва в малко размисъл относно природата на ‘машинната инструкция’ и ‘асемблера’, ама тези размишления са в разрез на всякакви правила и заучени положения и ако ги спомена някой разбирач ще ме насмели :)

$ vim test.asm
section .data
msg db ‘hello world’,0xA ; зареждаме текстов низ “здрасти” като променливата msg е указател към началния адрес (ех, това С), 0хА е знак 10, който познайте какво прави
len equ $-msg ; променливата $ (долар) указвала текущия адрес, така че дължината на низа “здравей” ще се сметне лесно
section .text
global _start
_start: ; входна точка
mov EAX, 0×04 ; изписването на текст на конзолата ставало през syscall от кърнела - функция с параметри. В ЕАХ се зарежда номера на функцията, а в следващите регистри параметрите. Функция номер 4 е изписване, която приема следните параметри:
mov EBX, 0×01 ; файлов дескриптор където ще се изписва
mov ECX, msg ; съобщението
mov EDX, len ; дължината му
int 0×80 ; а самото извикване на функцията става през прекъсване на 80h. Единственото възможно прекъсване (wtf)
mov EAX, 0×01 ; пак ще извикваме функция, но този път за край на програмата (функция 1 - return)
int 0×80
$ nasm -f elf test.asm # асемблираме кода
$ ld -o test test.o # свързваме
$ ./test # изпълняваме
hello world
$ ls -lh test* # да видим общия размер на всичко току що създадено
-rwxr-xr-x 1 ivanatora users 757 2008-03-14 20:26 test*
-rw-r–r– 1 ivanatora users 193 2008-03-14 20:30 test.asm
-rw-r–r– 1 ivanatora users 704 2008-03-14 20:30 test.o

Да видим същия резултат постигнат на С:

$ vim hello.c
#include <stdio.h>
int main(void){
printf(”Hello world\n”);
return 0;
}
$ gcc -o hello hello.c
$ ./hello
Hello world
$ ls -lh hello*
-rwxr-xr-x 1 ivanatora users 6.2K 2008-03-14 20:37 hello*
-rw-r–r– 1 ivanatora users 74 2008-03-14 20:37 hello.c

Десет пъти по-голям изпълним файл. Ако същото се компилира пък в M$ Visual Studio, няма да говоря за размера :)

ПП. Егх тоя гаден Wordpress, нито шрифта е хубав нито индентациите са си на мястото, а и на всичкото отгоре се опитва да ми затвори тага <stdio.h>