Участник
Пользователь
- Сообщения
- 496
- Реакции
- 621
- Помог
- 16 раз(а)
Перед тем как начнём, хочу сказать что эта статья подойдёт для программиста любой квалификации. Если вы начинающий, то статья поможет избежать ряда потенциально вредных привычек. Для продвинутых - избавиться от уже приобретённых, можно хорошо писать код, но непонятно для остальных.
Научиться хорошему стилю в программировании полезно. Автор сам в начале карьеры писал, плохо оформляя код, в итоге ему пришлось со временем избавляться от вредных привычек, что было непросто. Некоторые из рекомендаций 100% верны, другие субъективны и могут быть оспорены. В таких случаях будет даваться несколько вариантов оформления.
Лучше всего в начале плагина написать комментарии, объясняющие что этот плагин делает. Туда же поместить пояснения к настройкам, авторство, благодарности и.т.п.
Типичный блок примерно таков:
Плюсы для постороннего человека, открывшего ваше творение:
Наиболее важным в блоке комментариев является подача информации пользователю, как именно её расписать - дело ваше.
Данная секция включает в себя заголовки включений (a.k.a. "#include") и определения компилятора (a.k.a. "#define"). Здесь мало что можно испортить, но важно помнить, что все макросы должны быть прописаны заглавными буквами. Пример:
смотрится гораздо приятнее нежели
Подобный стиль позволяет нам избежать ошибки принятия макросов за переменные и является общепризнанным. Исключение только одно:
Подобное приемлемо, потому что макрос по существу действует как функция, а не просто хранит данные в памяти.
Не стоит подключать лишнее. Например, если не используете функции модуля
Код в теле условия следует табулировать(проставлять отступы). Будет видно где что находится.
Некоторые программисты ставят пробелы и перед макросами. Оба варианта приемлемы, но автор считает, что перед макросами пробел лучше не ставить, так как можно визуально потерять тело условия.
Также правильным является оставление комментариев к каждому
Табуляция должна делаться каждый раз, когда Вы открываете блок кода (в деталях - чуть позже). Обычно табуляция проставляется при помощи кнопки "Tab" либо 4 пробелов. Реже используют 1, 3 или 8 пробелов. Чаще встречается именно "Tab" потому что удобнее в текстовых редакторах.
Насчитывается несколько стилей интервалов, но автору кажется лучшим добавлять пробел:
Это не является стандартом и вполне обсуждаемо, но логично для читабельности кода. Также имеет смысл добавление 2 переводов каретки вместо одного между функциями.
Важно для переменных и функций. Эта глава неоднозначна и может быть оспорена, однако автор верит что стиль написания "camel case" наиболее предпочтителен.("camel case" - дословно "верблюжий регистр". Здесь автор имеет в виду двугорбых верблюдов в качестве примера перемежающихся букв верхнего и нижнего регистров. Например, сокращение "СортСемОвощ", - прим.переводчика)
Ниже представлен упрощённый вариант "camel case", называемый "mixed case"("смешанный регистр"), автору такой стиль нравится больше.
В именах функций первую буква каждого слова делайте заглавной
С переменными почти так же, но заглавной пишется первая буква каждого слова после первого.
В полном варианте "camel case" следует с большой буквы писать каждую первую букву каждого слова, независимо от того, переменная перед нами или нет.
Проблема в том, что подобная запись не позволяет с ходу отличить локальные переменные от функций. Уж больно похоже называются.
Аналогом можно считать нижнее подчёркивание вместо слитного написания, однако согласитесь, что выглядит несколько странно
Хотя и жизнеспособно. Используйте одно из двух - camel/mixed case или подчёркивание, но не смешивайте их.
Как отмечено ранее, макрос всегда пишется в верхнем регистре.
Много ошибок может быть из-за незнания что что-то глобально. Все глобальные переменные должны быть обозначены буквой g.
Либо через префикс g_
Каждую такую переменную следует писать с новой строки и с добавлением перевода каретки для облегчения поиска
приятнее глазу, нежели
Многие помечают название переменной в зависимости от её типа(так называемая Венгерская запись или HN). Сейчас от подобного отходят, однако вполне может встретиться.
Если вы не пользуетесь HN, автор советует применять "g" вместо "g_".
С точки зрения технического анализа Венгерская запись актуальна только для указателей и глобальных переменных. Pawn не содержит типов и поэтому не коррелирует с к актуальными типами данных. Префикс для Boolean бессмысленен, типы float и cell конвертируются виртуальной машиной AMXX при надобности.
Такие блоки отделяются фигурными скобками. Не всегда, есть ситуации, когда фигурные скобки могут быть опущены, но автор предпочитает использовать во всех случаях ради унификации.
Обратимся к интервалам. Существует 2 способа их проставления: с новой строки и в той же.
либо
Первый удобнее, так как закрывающая скобка расположена вертикально над открывающей, мы можем визуально провести линию сверху вниз и понять какой именно блок выделен.
Есть несколько ситуаций, когда скобки всё же можно игнорировать.
2.
Оба способа жизнеспособны и не вызывают проблем при компиляции.
В целом отбрасывание скобок в исключениях субъективно. Находится масса аргументов за и против. С одной стороны, пишем меньше кода. С другой, код менее читабелен. Временами встречается промежуточное решение - табуляция вместо скобок. Так или иначе, все эти варианты приемлемы.
Оставление комментариев - важная составляющая хорошего стиля.
Большие тексты вне функций должны быть закомментированы с использованием операторов "/*" и "*/" , первый открывает блок, второй закрывает.
В случае однострочных комментариев используйте знак // . Учтите, что Pawn не поддерживает вложенные комментарии, то есть вот так делать не надо
Обратите внимание на цвет последнего "*/". Интерпритатор не понимает что мы от него хочем.
Если не обойтись без вложенных комментов, то это можно сделать при помощи препроцессора
Выглядит не очень и больше подходит для ситуаций когда надо что-то быстро проверить/отладить.
Старайтесь, чтобы длина любой строки не превышала 80 символов, не у всех широкоформатные мониторы. К тому же слишком большую длину может жаловаться компилятор. Некоторые добавляют в начало комментария 1-2 пробела для повышения читабельности.
Комментарий должен быть максимально нагляден и отражать суть: что делается и каков ожидается результат.
Например, вот этот бесполезен, так как из его содержания ничего не понять
Гораздо лучше описать следующим образом:
Комментарии следует размещать также между большими отдельными блоками программы. Например, в форме заголовков или мини-описаний
Пробелы и разделители имеют большое значение в программировании, так как позволяют лучше понять код. Существует много различных стилей, автор предпочитает добавлять разделитель для отделения общих по смыслу частей функций.
set_pcvar_num, устанавливающий значение, имеет мало что общего с нахождением игрока и убийством, поэтому отделён.
Как показывает опыт, имена переменных и функций должны быть максимально описательными. Ниже пример плохого имени
Ясно одно, это нечто временное, но непонятно для чего используется
Сравните с таким
Название говорит нам всё что нужно знать. Можно даже предположить что переменная целочисленного типа.
Желательно проставлять тэги, например "Event" у события или "Forward" у форварда.
Часто вы увидите краткую пометку, то есть не "Forward", а "Fwd", так тоже можно. Важно отделить подобные функции от остальных служебных.
Здесь то, что по смыслу не вошло в предыдущие главы.
По возможности пользуйтесь константами
нагляднее, нежели
Знак ";" полезен если вы планируете переходить с Pawn на другой язык(C/C++/PHP), но часто допускаете ошибки в его использовании. Например, многие не знают, что в конце цикла "do...while" должна стоять одна ";" . Опытному программисту не составит труда переключаться между наличием и отсутствием ";" . Так как Pawn позволяет не использовать ";" , то нет смысла проставлять лишний раз. Заставить компилятор требовать обязательного расставления ";" в конце строк можно директивой
Иногда, при записи API или заголовка, вам придётся документировать свои функции таким образом, чтобы другие могли их понять. Doxygen (исходный код, документирующий пакет программного обеспечения) использует определенный формат, который AMXX начал использовать после добавления SQLx. Вероятно, это является лучшим способом, потому что такая запись наиболее читабельна. Вот пример Doxygen-задокументированной служебной функции:
В совместных проектах имеет смысл указывать автора конкретной части кода
Освоение вышеперечисленных нехитрых приёмов сделает ваш код удобнее для изучения как вам, так и сторонним пользователям. Автор надеется, что читатель в дальнейшем будет пользоваться хотя бы некоторыми из них. Часто люди находят простые правила оформления кода излишними, трудоёмкими, но поверьте, копаться в коде без комментариев и выдержанной стилистики - удовольствие ниже среднего, не говоря уже о затраченном на понимание времени.
1. Касательно "camel case"/"mixed case" в регистрах.
Спорно. Как правило там, где нету явного указания области видимости, различают именно по первой букве. Если большая то переменная глобальная, иначе локальная. В python-е принято обозначать приватные свойства через "_" в начале.
2. На скорость выполнения кода наличие или отсутствие скобок и комментариев никак не влияет, поэтому в первую очередь думайте о читабельности.
3. Хорошей практикой является самодокументированый код. Это такой код, где из названия переменной сразу понятно для чего она предназначена и в коментировании не нуждается. Также стоит сохранять баланс между коментариями и без них. Наилучший вариант - самодокументированный код и комментарии в тех местах, которые сложно понять с первого взгляда.
4. Автор пишет, что не стоит в конце каждой строки проставлять знак ";". Так говорили в начале 2000-ых касательно JavaScript. В итоге понадобились годы дабы убедить всех использовать везде ";". То, что компилятор AMXX сам их проставляет вовсе не означает, что он не может ошибиться. Потому лучше добавлять, благо наличие либо отсутствие ";" никак не сказываеться на производительности.
Автор оригинальной статьи Hawk552
Плагин, соответствующий хорошему стилю, размещён на AlliedMods.
Отдельное спасибо fantom за критику и современные реалии.
Все права на перевод принадлежат Dev-CS.ru TEAM. При копировании материала активная ссылка обязательна.
Научиться хорошему стилю в программировании полезно. Автор сам в начале карьеры писал, плохо оформляя код, в итоге ему пришлось со временем избавляться от вредных привычек, что было непросто. Некоторые из рекомендаций 100% верны, другие субъективны и могут быть оспорены. В таких случаях будет даваться несколько вариантов оформления.
Вступительный блок с комментариями
Лучше всего в начале плагина написать комментарии, объясняющие что этот плагин делает. Туда же поместить пояснения к настройкам, авторство, благодарности и.т.п.
Типичный блок примерно таков:
Код:
/*
Copyleft 2008
Plugin thread: http://forums.alliedmods.net/showthread.php?p=633284
DUEL MOD
========
Description
This mod is designed to allow dueling, where players challenge each
other and engage in battle. It is designed for the mod "The Specialists",
but can be used on other mods.
Commands
say /duel - Will challenge the player being looked at to a duel.
say /accept - Will accept a challenge. Note that you can also use /duel,
but you must be looking at the person who challenged you. With /accept,
the last person to challenge you will be accepted.
say /punchingbag - Turns the player into a punching bag
(requires amx_duel_punchingbag to be set to 1).
Credits
Havoc9 Community - Testing help (specifically SaderBiscut and Jimmy Striker).
Lord_Destros - Testing help.
Steely - Testing help.
sawyer - Testing help.
Frost - Testing help.
coderiz - New semiclip method.
Charming - Encouragement.
Changelog:
Jun 1, 2008 - v1.0 - Initial release
Jun 2, 2008 - v1.1 - [FIXED] Some repeated variables
[FIXED] Message printing incorrectly
[FIXED] Duel off not working properly
[ADDED] Punching bag mode
[ADDED] True semiclip
[ADDED] Attack blocking between
duelists <-> players
[ADDED] God mode to normal players
Jun 4, 2008 - v1.2 - [ADDED] Deny command
[ADDED] Pair command
[ADDED] Name parameter to /duel command
[ADDED] Glow cvar
[FIXED] Messages printing incorrectly
*/
Плюсы для постороннего человека, открывшего ваше творение:
- Чётко описаны функционал и тематика
- Указано для какой игры
- Расписаны команды. Опционально, можно описать и в теле плагина, но здесь гораздо удобнее для пользователя.
- Благодарности. Указывайте не только в теме, где постите плагин, но и в исходнике.
- Информативный лог изменений дабы пользователи знали чего ждать от какой версии
Наиболее важным в блоке комментариев является подача информации пользователю, как именно её расписать - дело ваше.
Макросы и препроцессор
Данная секция включает в себя заголовки включений (a.k.a. "#include") и определения компилятора (a.k.a. "#define"). Здесь мало что можно испортить, но важно помнить, что все макросы должны быть прописаны заглавными буквами. Пример:
Код:
#define MAX_ITEMS 10
Код:
#define max_items 10
Код:
#define MyNewIsUserAlive(%1) is_user_alive( %1 )
Не стоит подключать лишнее. Например, если не используете функции модуля
FakeMeta
, то не надо добавлять fakemeta.inc
.Код в теле условия следует табулировать(проставлять отступы). Будет видно где что находится.
Код:
PunishUser( id )
{
#if defined KILL_USER
user_kill( id )
client_print( 0, print_chat, "[Kill] The user has been killed")
#else // KILL_USER
user_slap( id, 0 )
client_print( 0, print_chat, "[Kill] The user has been slapped")
#endif // KILL_USER
}
Также правильным является оставление комментариев к каждому
#else
, #elseif
и #endif
.Отступы, табуляция и интервалы
Табуляция должна делаться каждый раз, когда Вы открываете блок кода (в деталях - чуть позже). Обычно табуляция проставляется при помощи кнопки "Tab" либо 4 пробелов. Реже используют 1, 3 или 8 пробелов. Чаще встречается именно "Tab" потому что удобнее в текстовых редакторах.
Насчитывается несколько стилей интервалов, но автору кажется лучшим добавлять пробел:
- при взятии параметра в скобки
- сразу после условия и ключевого слова
- до и после каждого оператора с 2 параметрами
- После запятой
Код:
if ( !cmd_access( id, level, cid ) )
Код:
for ( new i; i < 10; i++ )
Регистр
Важно для переменных и функций. Эта глава неоднозначна и может быть оспорена, однако автор верит что стиль написания "camel case" наиболее предпочтителен.("camel case" - дословно "верблюжий регистр". Здесь автор имеет в виду двугорбых верблюдов в качестве примера перемежающихся букв верхнего и нижнего регистров. Например, сокращение "СортСемОвощ", - прим.переводчика)
Ниже представлен упрощённый вариант "camel case", называемый "mixed case"("смешанный регистр"), автору такой стиль нравится больше.
В именах функций первую буква каждого слова делайте заглавной
Код:
public EventDeathMsg()
Код:
new gMyVariable
new myVariable
new userKills
Код:
new MyVariable
new UserKills
Аналогом можно считать нижнее подчёркивание вместо слитного написания, однако согласитесь, что выглядит несколько странно
Код:
new My_Variable
Как отмечено ранее, макрос всегда пишется в верхнем регистре.
Глобальные переменные и Префиксы типов
Много ошибок может быть из-за незнания что что-то глобально. Все глобальные переменные должны быть обозначены буквой g.
Код:
new gMyVariable
Код:
new g_MyVariable
Код:
new gMyVariable
new gMyOtherVariable
Код:
new gMyVariable, gMyOtherVariable
- g or g_ - глобальные переменные (global)
- p or p_ - указатели (Pointer. Приемлемо. А вот обозначений ниже лучше избегать)
- i - целое число (integer)
- f or fl - число с плавающей точкой (float)
- sz - строковые переменные (string)
- b - логические типы (boolean)
- h - дескрипторы (handlers. Могут использоваться вместо тэга указателя, что технически не является ошибкой)
- v - векторы (Vector. Не стандарт, но всё ещё полезно). К примеру, такая запись векторов/ координат
new Float: g_fvOrigin[3];
- fn - функции (Fubction. устарело даже по меркам HN)
Код:
// глобальная переменная
new g_iKills
// глобальная переменная типа float
new Float:g_flSpeed
// логическая переменная
new bool:bFlag
// функция
public fnEventResetHUD()
// указатель
new g_pCvar
С точки зрения технического анализа Венгерская запись актуальна только для указателей и глобальных переменных. Pawn не содержит типов и поэтому не коррелирует с к актуальными типами данных. Префикс для Boolean бессмысленен, типы float и cell конвертируются виртуальной машиной AMXX при надобности.
Блоки кода
Такие блоки отделяются фигурными скобками. Не всегда, есть ситуации, когда фигурные скобки могут быть опущены, но автор предпочитает использовать во всех случаях ради унификации.
Обратимся к интервалам. Существует 2 способа их проставления: с новой строки и в той же.
Код:
MyFunction()
{
Код:
MyFunction() {
Есть несколько ситуаций, когда скобки всё же можно игнорировать.
- В блоке только один вызов функции или одна операция. Например,
log_amx( "%d", get_user_kills( id ) )
- There is a single code block inside it, even if it contains a lot more code that does not fit in a single function call.
Код:
MyFunction( id )
user_kill( id )
Код:
MyFunction( id )
if( is_user_alive( id ) )
{
client_print( 0, print_chat, "We are now killing %d", id )
user_kill( id )
}
В целом отбрасывание скобок в исключениях субъективно. Находится масса аргументов за и против. С одной стороны, пишем меньше кода. С другой, код менее читабелен. Временами встречается промежуточное решение - табуляция вместо скобок. Так или иначе, все эти варианты приемлемы.
Комментирование
Оставление комментариев - важная составляющая хорошего стиля.
Большие тексты вне функций должны быть закомментированы с использованием операторов "/*" и "*/" , первый открывает блок, второй закрывает.
В случае однострочных комментариев используйте знак // . Учтите, что Pawn не поддерживает вложенные комментарии, то есть вот так делать не надо
Код:
/*
this is the first comment
/* this is a nested comment */
*/
Если не обойтись без вложенных комментов, то это можно сделать при помощи препроцессора
#if
с условием 0
Код:
#if 0
первый
#if 0
вложенный
#endif
#endif
Старайтесь, чтобы длина любой строки не превышала 80 символов, не у всех широкоформатные мониторы. К тому же слишком большую длину может жаловаться компилятор. Некоторые добавляют в начало комментария 1-2 пробела для повышения читабельности.
Комментарий должен быть максимально нагляден и отражать суть: что делается и каков ожидается результат.
Например, вот этот бесполезен, так как из его содержания ничего не понять
Код:
// Start the for loop.
for ( new i; i < 7; i++ )
Код:
// There's a strange memory corruption bug in this function.
// As such, we have to loop through each of the 7 elements
// in the array and set them to the value that they should be.
for ( new i; i < 7; i++ )
Код:
//////////////////////////////////
// HELPER FUNCTIONS //
//////////////////////////////////
Разделители
Пробелы и разделители имеют большое значение в программировании, так как позволяют лучше понять код. Существует много различных стилей, автор предпочитает добавлять разделитель для отделения общих по смыслу частей функций.
Код:
// Ignore the fact that this function would bear no real
// useful results when actually used in a server.
MyFunction()
{
new id = random_num( 1, 13 )
user_kill( id )
set_pcvar_num( p_MyCvar, 9 )
}
Переменные и функции
Как показывает опыт, имена переменных и функций должны быть максимально описательными. Ниже пример плохого имени
Код:
new temp
Сравните с таким
Код:
new KillsSinceLastSpawn
Желательно проставлять тэги, например "Event" у события или "Forward" у форварда.
Код:
register_forward( FM_Spawn, "ForwardSpawn" )
register_event( "DeathMsg", "EventDeathMsg", "a" )
Дополнительно
Здесь то, что по смыслу не вошло в предыдущие главы.
По возможности пользуйтесь константами
Код:
return PLUGIN_CONTINUE
Код:
return 0
Знак ";" полезен если вы планируете переходить с Pawn на другой язык(C/C++/PHP), но часто допускаете ошибки в его использовании. Например, многие не знают, что в конце цикла "do...while" должна стоять одна ";" . Опытному программисту не составит труда переключаться между наличием и отсутствием ";" . Так как Pawn позволяет не использовать ";" , то нет смысла проставлять лишний раз. Заставить компилятор требовать обязательного расставления ";" в конце строк можно директивой
Код:
#pragma semicolon 1
Иногда, при записи API или заголовка, вам придётся документировать свои функции таким образом, чтобы другие могли их понять. Doxygen (исходный код, документирующий пакет программного обеспечения) использует определенный формат, который AMXX начал использовать после добавления SQLx. Вероятно, это является лучшим способом, потому что такая запись наиболее читабельна. Вот пример Doxygen-задокументированной служебной функции:
Код:
/**
* Print command activity.
* @param id Calling admin's id
* @param key[] Language key
* @param any:... Arguments to the format function (w/out the id/lang key)
* @return True on success, False on fail
**/
stock UTIL_PrintActivity(const id, const szLangKey[],any:...)
Код:
// Hawk552: Added this function to gather and store player
// names, then sort them alphabetically.
SortNames( Names[][], NumNames, MaxLength )
Заключение
Освоение вышеперечисленных нехитрых приёмов сделает ваш код удобнее для изучения как вам, так и сторонним пользователям. Автор надеется, что читатель в дальнейшем будет пользоваться хотя бы некоторыми из них. Часто люди находят простые правила оформления кода излишними, трудоёмкими, но поверьте, копаться в коде без комментариев и выдержанной стилистики - удовольствие ниже среднего, не говоря уже о затраченном на понимание времени.
Уточнения от сообщества Dev-CS
1. Касательно "camel case"/"mixed case" в регистрах.
Спорно. Как правило там, где нету явного указания области видимости, различают именно по первой букве. Если большая то переменная глобальная, иначе локальная. В python-е принято обозначать приватные свойства через "_" в начале.
2. На скорость выполнения кода наличие или отсутствие скобок и комментариев никак не влияет, поэтому в первую очередь думайте о читабельности.
3. Хорошей практикой является самодокументированый код. Это такой код, где из названия переменной сразу понятно для чего она предназначена и в коментировании не нуждается. Также стоит сохранять баланс между коментариями и без них. Наилучший вариант - самодокументированный код и комментарии в тех местах, которые сложно понять с первого взгляда.
4. Автор пишет, что не стоит в конце каждой строки проставлять знак ";". Так говорили в начале 2000-ых касательно JavaScript. В итоге понадобились годы дабы убедить всех использовать везде ";". То, что компилятор AMXX сам их проставляет вовсе не означает, что он не может ошибиться. Потому лучше добавлять, благо наличие либо отсутствие ";" никак не сказываеться на производительности.
Автор оригинальной статьи Hawk552
Плагин, соответствующий хорошему стилю, размещён на AlliedMods.
Отдельное спасибо fantom за критику и современные реалии.
Все права на перевод принадлежат Dev-CS.ru TEAM. При копировании материала активная ссылка обязательна.
Последнее редактирование: