PDA

Просмотр полной версии : [Мануал] Создание чистого и читаемого кода



DCL
16.08.2015, 10:26
Автор: CalvinC
Ссылка на оригинальную тему: http://forum.sa-mp.com/showthread.php?t=563078
Перевод: translate.ru, DCL


***

Я вижу много людей, у которых не читаемый и не оптимизированный код, поэтому я решил создать эту тему, чтобы помочь вам.

Описание:
Прочитав эту тему, вы научитесь писать более чистый и оптимизированный код, а так же возьмете себе что - нибудь на заметку.

Часть 1 - табуляция
Вы вероятно знаете, что такое табуляция и как ей пользоваться. Но я решил включить это в тему, т.к. так или иначе люди иногда допускают ошибки при компилировании (warning 217), или вообще отключают их. Даже если игнорировать все предупреждения, ваш код будет неудобно читать. Вот один из примеров:



CMD:toggle(playerid, params[])
{
if(sscanf(params, "s[14]", params))
{
SendClientMessage(playerid, -1, "/toggle [option]");
SendClientMessage(playerid, -1, "Options: PM");
}
if(!strcmp(params, "pm", true))
{
switch(pm[playerid])
{
case 0:
{
pm[playerid] = 1;
SendClientMessage(playerid, -1, "You have toggled PM's off.");
}
case 1:
{
pm[playerid] = 0;
SendClientMessage(playerid, -1, "You have toggled PM's on.");
}
}
}
return 1;
}


Множество людей, использующих это обычно ставят фигурные скобки в ряд ({, }), тем самым иногда нельзя понять - какую из скобок вы закрыли, а какую нет. Но если же использовать табуляцию, вы сможете видеть, закрываются скобки или нет.



CMD:toggle(playerid, params[])
{
if(sscanf(params, "s[14]", params))
{
SendClientMessage(playerid, -1, "/toggle [option]");
SendClientMessage(playerid, -1, "Options: PM");
}
if(!strcmp(params, "pm", true))
{
switch(pm[playerid])
{
case 0:
{
pm[playerid] = 1;
SendClientMessage(playerid, -1, "You have toggled PM's off.");
}
case 1:
{
pm[playerid] = 0;
SendClientMessage(playerid, -1, "You have toggled PM's on.");
}
}
}
return 1;
}


После каждой открытой скобки вы должны нажать 4 раза клавишу пробел (или 1 раз клавишу TAB).
После каждой закрытой скобки вы должны сделать 4 пробела назад.


От меня: мне кажется, тут проще будет сделать табуляцию через notepad++, вот тема, которая наглядно показывает весь процесс: http://***********.ru/showthread.php?t=249112

Если вам необходимо передвинуть много кода в одну из сторон, выделите его, чтобы передвинуть вперед - нажмите TAB, назад - SHIFT

Часть 2 - использование скобок (1/2)
Вы конечно можете использовать табуляцию для расстановки скобок и они даже могут быть расставлены правильно, но может быть, они вам не нужны совсем?



CMD:pm(playerid, params[])
{
new targetid, message[128];
if(sscanf(params, "us", targetid, message))
{
SendClientMessage(playerid, -1, "/pm [playerid] [message]");
return 1;
}
if(pm[playerid] == 0)
{
SendClientMessage(playerid, -1, "Your PM's are turned off.");
}
else if(pm[targetid] == 1)
{
SendClientMessage(playerid, -1, "Your PM's are turned on.");
}
else
{
SendClientMessage(targetid, -1, "PM Received.");
SendClientMessage(playerid, -1, "PM Sent");
}
return 1;
}


Как Вы видите, это будет работать, но нет никакой необходимости во всех тех скобках.
Поэтому давайте попытаемся убрать этот код немного.
Давайте смотреть на первую часть кода:



if(sscanf(params, "us", targetid, message))
{
SendClientMessage(playerid, -1, "/pm [playerid] [message]");
return 1;
}


Мы возвращаем 1, когда можем просто вернуть SendClientMessage - одно и то же, но плюс к оптимизации.



if(sscanf(params, "us", targetid, message))
{
return SendClientMessage(playerid, -1, "/pm [playerid] [message]");
}


Код выше будет работать точно так же, как и в случае с возвращением 1. Но мы можем обойтись вообще без скобок, потому что нам не обязательно даже возвращать SendClientMessage.



if(sscanf(params, "us", targetid, message)) return SendClientMessage(playerid, -1, "/pm [playerid] [message]");


Как вы видите, мы из 5 строк сделали 1. И это осталось так же работоспособным. Такое же действие мы можем сделать и с остальной командой, поскольку мы заключаем 1 - 2 функции в скобки.



CMD:pm(playerid, params[])
{
new targetid, message[128];
if(sscanf(params, "us", targetid, message)) return SendClientMessage(playerid, -1, "/pm [playerid] [message]");
if(pm[playerid] == 0) SendClientMessage(playerid, -1, "Your PM's are turned off.");
else if(pm[targetid] == 1) SendClientMessage(playerid, -1, "Your PM's are turned on.");
else
{
SendClientMessage(targetid, -1, "PM Received.");
SendClientMessage(playerid, -1, "PM Sent");
}
return 1;
}


Как вы видите, это намного короче, чем первый пример. Но мы можем еще сократить все это, используя 2 функции в одной строчке.



else
{
SendClientMessage(targetid, -1, "PM Received.");
SendClientMessage(playerid, -1, "PM Sent");
}


Мы можем сделать так:



else SendClientMessage(targetid, -1, "PM Received."); SendClientMessage(playerid, -1, "PM Sent");


Это не будет работать, поскольку компилятор увидит его следующим образом:



else SendClientMessage(targetid, -1, "PM Received.");
SendClientMessage(playerid, -1, "PM Sent");


Поэтому в игре, если выполнится условие, то вам напишет "PM Received", а "PM Sent" останется независимым и не будет принадлежать к условию.


От меня: можно поставить запятую и как раз таки вместить 2 функции в 1 строчку, при этом условие будет выполнятся.



else SendClientMessage(targetid, -1, "PM Received."), SendClientMessage(playerid, -1, "PM Sent");


Часть 3 - использование скобок (2/2)
Скобки могут использоваться по разному. Один из способов представляет собой что-то вроде этого:



CMD:pm(playerid, params[])
{
new targetid, message[128];
if(sscanf(params, "us", targetid, message)) return SendClientMessage(playerid, -1, "/pm [playerid] [message]");
if(pm[playerid] == 0) SendClientMessage(playerid, -1, "Your PM's are turned off.");
else if(pm[targetid] == 1) SendClientMessage(playerid, -1, "Your PM's are turned on.");
else
{
SendClientMessage(targetid, -1, "PM Received.");
SendClientMessage(playerid, -1, "PM Sent");
}
return 1;
}


До этого мы уже разбирали с вами использование скобок и табуляцию, но вы можете сделать по другому:



CMD:pm(playerid, params[]) {
new targetid, message[128];
if(sscanf(params, "us", targetid, message)) return SendClientMessage(playerid, -1, "/pm [playerid] [message]");
if(pm[playerid] == 0) SendClientMessage(playerid, -1, "Your PM's are turned off.");
else if(pm[targetid] == 1) SendClientMessage(playerid, -1, "Your PM's are turned on.");
else {
SendClientMessage(targetid, -1, "PM Received.");
SendClientMessage(playerid, -1, "PM Sent"); }
return 1; }


Как вы видите, этот способ делает код визуально меньше, но при этом он усложняет чтение кода и вы можете пропустить незакрытые скобки.

Часть 3 - сравнения "==, >, !, &&, ||"
Кратко об этом:

(что-то) == (что-то еще) - Что-то равняется чему-то еще

(что-то) > (что-то еще) - Что-то больше, чем что-то еще

(что-то) < (что-то еще) - Что-то меньше, чем что-то еще

(что-то) && (что-то еще) - Что-то и что-то еще

(что-то) || (что-то еще) - Что-то или что-то еще

"!" это специальный знак, может использоваться как "больше", но обычно его используют как "не"

(что-то) != (что-то еще) - Что-то не равняется чему-то еще

Использование: !(переменная/функция)

Некоторые люди создают длинные коды, вместо того, чтобы сделать маленький код. Особенно использование "!" в функции strcmp может значительно сократить ее.

Без "!":



if(strcmp(params, "pm", true) == 0)


С "!":



if(!strcmp(params, "pm", true))


Часть 4 - пользовательские функции
Есть функции, которые a_samp дает вам по умолчанию, например GivePlayerMoney. Но вы так же можете создавать и свои функции, что существенно сокращает код, особенно если вы используете один и тот же код в нескольких местах.
Вот пример своей функции:



SetPlayerMoney(playerid, amount)
{
ResetPlayerMoney(playerid);
return GivePlayerMoney(playerid, amount);
}


Теперь если мы хотим установить деньги игрока, мы просто используем эту функцию:



SetPlayerMoney(playerid, 100);


Это, конечно, не может быть самым совершенным примером, но я вас натолкнул на идею.

Часть 5 - define
Использование define позволит вам сделать код более красивым и читаемым. Define определяет что - то к чему то еще (по принципу макросов).
На примере define можно сделать, допустим, цвет сообщений, например, вместо этого:



CMD:redmessage(playerid, params[]) return SendClientMessage(playerid, 0xFF0000AA, "This message is red");


Как вы видите, тут мы снова не используем скобки, но суть не в этом.
Если вы используете много одного и того же цвета в сообщениях, то вам необходимо больше запоминать цвет, вы можете просто его "задефайнить"



#define COLOR_RED 0xFF0000AA // Добавьте вверх своего мода

CMD:redmessage(playerid, params[]) return SendClientMessage(playerid, COLOR_RED, "This message is red");


Таким образом, если вам нужно будет изменить цвет во всех сообщениях, просто измените его в define.
Это - все, что я имею на данный момент, я знаю много людей, которые хотят писать чистый и оптимизированный код, я надеюсь что данный урок поможет вам. Я обновлю это учебное руководство, если я найду какие-либо ошибки или другие улучшения.

wAx
16.08.2015, 12:15
есть подобная тема (http://pro-pawn.ru/showthread.php?8347-%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%80%D0%B5%D0%BA%D0%BE%D0%BC%D0%B5%D0%BD%D0%B4%D0%B0%D1%86%D0%B8%D0%B8-%D0%BF%D0%BE-%D0%BD%D0%B0%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8E-%D0%BA%D0%BE%D0%B4%D0%B0&highlight=%D1%80%D0%B5%D0%BA%D0%BE%D0%BC%D0%B5%D0%BD%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+%D0%BD%D0%B0%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8E+%D0%BA%D0%BE%D0%B4%D0%B0), после прочтения которой, в твоей я не увидел ничего нового...

Desulaid
16.08.2015, 15:11
Не знаю как вам, но мне вариант


CMD:redmessage(playerid, params[]) return SendClientMessage(playerid, COLOR_RED, "This message is red");

видится не очень читаемым :( Лучше делать с блоками :i-m_so_happy:


CMD:redmessage(playerid, params[])
{
return SendClientMessage(playerid, COLOR_RED, "This message is red");
}

SliM
17.02.2016, 12:52
если честно автор(оригинальный), втирает какую-то дичь:) из всех стилей слепил стиль CalvinC'a, уж если писать так уж в одном стиле. Лично я предпочитаю стиль Олмана.

vovandolg
18.02.2016, 00:16
есть подобная тема (http://pro-pawn.ru/showthread.php?8347-%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D1%80%D0%B5%D0%BA%D0%BE%D0%BC%D0%B5%D0%BD%D0%B4%D0%B0%D1%86%D0%B8%D0%B8-%D0%BF%D0%BE-%D0%BD%D0%B0%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8E-%D0%BA%D0%BE%D0%B4%D0%B0&highlight=%D1%80%D0%B5%D0%BA%D0%BE%D0%BC%D0%B5%D0%BD%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+%D0%BD%D0%B0%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8E+%D0%BA%D0%BE%D0%B4%D0%B0), после прочтения которой, в твоей я не увидел ничего нового...

Это не подобная, это понятная и круче чем эта писанина)
Кто то походу сделал прорыв на ги который сделали миллион лет тому назад на этом прекрасном форуме:smoke: