Общий стиль написания кода на SourcePawn

DENFER

Пишу плагины за два биг тести и картошку фри..
Сообщения
260
Реакции
289
Доброе время суток, товарищи! В данной теме мне хотелось затронуть довольно обширную, но совершенно на первый взгляд незаметную тему в скриптинге. Да-да, именно общий стиль написания кода на таком языке, как SourcePawn. Казалось бы, какая разница, как писать код - главное, что работает, но как-только дело доходит до командной работы, анализа чужого кода или вы возвращаетесь к своим старым проектам именно с этого момента начинаются огромные проблемы. Данный урок (пару рекомендаций) базируются на моем чисто-сугубом мнение и другим статьям, которые были взяты с официальной документации SourceMode.

Перед тем, как окунуться в просторы моей статьи, пробегусь по паре тезисов, а именно:

1. На данном этапе развития, мы имеем два различных синтаксиса, первый - это до версии 1.7 языка SourcePawn, а второй - после.
* на сам деле, совместимость двух синтаксисов это хорошо, но с другой стороны вносит определенную путаницу и непонимание у новичков, а иногда и профессионалов своего дела *

2. Язык SourcePawn, как и многие другие: С++, D, Java, Objective C, C#, PHP, Perl, Nemerle - является Си-подобным, а значит наследует их особенности, такие как:
- Чувствительность к регистру.
- Количество пробелов, табуляция и переводы строки не влияют на семантику нигде, кроме строковых литералов. Это, в частности, значит, что возможен перевод строки в любом удобном месте.
- Бинарные операторы имеют инфиксную форму.
- и т.д.
* набор данные постулатов, говорит о том, что следует придерживаться четкому "Си" правилу написания кода, о котором поговорим дальше *

3. SourcePawn - процедурный скриптовый язык, не стоит опираться на него, как на объектно-ориентированный используя methodmap и размышлять объектами (это клево, если у вас есть способность представлять и мыслить ими, но в данном случае лучше абстрагироваться), пишите простой и четкий, одним словом - лаконичный код.

4. Комментарии - это наше все, как и в любом другом языке, просто оставляйте их, да хоть они будут излишне и в избытке, просто оставляйте и учитесь пояснять свой код правильно, в будущем они помогут вам прокачать свои способности, а хороший комментарий многого стоит, уделите этому определенные силы, тем более, пока мысли свежи - это сыграет огромную роль, как для вас, так и для других людей, которые будут анализировать и разбираться в вашем коде.
* есть целая наука, название, которой я забыл. Полистать хабр и прочесть пару статей по данной теме, никогда не помешает даже Гуру *

5. Структура! Уделите внимание структуре исходника, где лучше находиться глобальным переменным, директивам и различным функциям.
* не мало важный критерий, который в разы облегчит, как чтение кода, так и обрадует ваши глаза *

Опираясь на данные тезисы (да, я знаю, что звучат они многословно), давайте перейдем к сути дела и по ходу будем обращаться к выше стоящим 5 аксиомам.

Не зря, я обратил внимание на структуру файла, так как код считывается сверху вниз, то более логично начать с верхушки файла, и что нас там ждет? Директивы! Именно, начнем, пожалуй, с них.

1. Директивы препроцессора.

Чаще всего встречаются такие директивы, как:
- #include
- #define
- #pragma
- #if / #else

Обычно, это типичная схема, она очень простая: сначала мы включаем в исходный файл основные библиотеки и прочие вторичные файлы, потом обзаводимся "константами" и только после - устанавливаем свои правила чтения данного файла, чтобы правила подключенного другого исходника не мешали вашему. 4 пункт с #if / #else он более спонтанный и может присутствовать совершенно в разных местах, но главное, чтобы все было по делу.

1. #include - ничего сложного тут нет, для обычных библиотек, находящихся в папке .inc используйте, исключительно, только угловые скобочки <name> (без формата файла) и двойные кавычки "directory/name.sp", если файл находится непосредственно в другой папке.
SourcePawn:
// основные библиотеки SourceMod
#include <sourcemod>
#include <cstrike>
#include <sdktools>

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

// дополнительные файлы
#include "DENFER/AutoBalance/others.sp"
#include "DENFER/AutoBalance/algorithms.sp"
#include "DENFER/AutoBalance/forwards.sp"

* пути к файлам не должны содержать пробелов *

2. #define - определяет идентификатор и последовательность символов на которые он будет заменяться, в простонародье их еще называют константами препроцессора или макросами. Обычно, идентификатор, то бишь название стоит писать заглавными буквами, чтобы ярко выделить в коде.
SourcePawn:
#define PI                    3.141592653589793238462643 // что по памяти вспомнил
#define EXP                   2.71828182
#define PLUGIN_VERSION        "1.0.0"
#define AUTHOR                "DENFER"

3. #pragma - определяет функции компилятора. Стоит использовать после всех инклюдов, чтобы быть уверенным, что ваш плагин компилируется, исключительно, с данными настройками.


4. #if / #else - условия препроцессора. Тут стоит обратить внимание на ветвление, в принципе ничего больше не добавить.
SourcePawn:
#if (константное выражение)
    ...
    #elif (константное выражение)
        ...
        #elif (константное выражение)
            ...
       #else
            ...
    #endif
        ...

С дополнительной информацию о директивах препроцессора, вы сможете ознакомиться тут.
- Википедия
- Microsoft

2. Глобальные переменные.

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

Глобальная переменная должна иметь:
- Яркое, самоговорящее название.
- Иметь префикс g_ (что расшифровывается, как global_).
- Содержать тип самой переменной (вы же помните, что хоть мы и пользуемся новым синтаксисом, указанный тип переменной в её название, облегчит вашу совместную жизнь с ней в разы).

Приведу примеры и тем самым сформулирую некоторое правило для написания глобальных переменных.
SourcePawn:
// StringMaps
StringMap gh_smTree;

// ArrayLists
ArrayList gh_alPlayers;

// DataPacks
DataPack gh_dpDetails;

// ConVars
ConVar gc_bPlugin;

// Handles
Handle g_hTimer;

// Strings
char g_szPrefix[32];

// Floats
float g_flSpeed;

// Integers
int g_iFrags;

// Booleans
bool g_bIsAlive;

Как вы можете заметить, во-первых, переменные имеют префикс, указывающий, что переменная находится в глобальной области видимости и вы ее уже никогда не спутаете с локальной,
во-вторых, ее тип и при использование переменной, вы четко знаете ее тип и сможете осуществлять операции куда более разумнее, ну и конечно, простое, но понятное название, которое говорит само за себя.
Хотелось бы выделить пару особенностей, таких как:
- Консольные переменные или еще их обзывают кварами - имеют особый вид наименования, так как любую консольную переменную можно представить разными типами, то лучше всего использовать в название - основной тип представления.
- Производным от типа Handle лучше к префиксу приписывать h, тем самым получая gh_ и указывать соответствующее наименования производного типа, лично по мне, лучше использовать 1-2 буквы от производного типа в начале, чтобы на всякий случай спастись от пересечения имен.

И вот мы получили пару исключений и строгий набор правил для написания глобальных переменных, скажите же, что так читается намного проще и приятнее?

Ссылка по данной теме.
- Википедия

3. Локальные переменные

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

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

Вот вам и пример с использованием локальных переменных:
SourcePawn:
// обычная функция, которая содержит вашу реализацию
void Foo()
{
    // используем верблюжий регистр, но заметьте, что если переменная содержит одно слово,
    // то мы пишем, его строчными буквами и выглядит все по феншую, все информативно и понятно.
    int amountHealth;
    float coordinatesPlayer[3];
    char name[MAX_NAME_LENGHT];
 
    // дальше идет ваша реализация функции
    ...
}

Ссылка по данной теме.
- Википедия

4. Функции.

В прошлом примере мы использовали функцию, они тоже содержат свои особенности в наименование, давайте пробежимся по ним.
- Название функций в SourcePawn содержит такой стиль, как ПаскальныйРегистр.
- Название должно быть, как и любая переменная - самоговорящая за свое назначение.
- Если функция является колбеком, то лучше добавить соответствующий префикс, пробежимся по некоторым из них:
SourcePawn:
// Наименование функции имеет префикс - означающий, что функция является колбеком
// определенного ивента, и громкое название - сообщающее, что событие является началом раунда.
Action Event_RoundStart (Event event, const char[] name, bool dontBroadcast)
{
    ...
}

// Наименование функции имеет префикс - означающий, что функция является обработчиком,
// а само название, говорит о том, что обрабатывает основное меню плагина.
int Handler_MainMenu (Menu menu, MenuAction action, int param1, int param2)
{
    ...
}

// Наименование функции, так же содержит префикс, который сообщает, что это обратный вызов,
// а само название, предупреждает, что данный колбек вызывается при вводе консольной команды.
Action CallBack_ConsoleCmd (int client, int args)
И по таком принципу вы можете наименовывать свои функции. Согласны, что так выглядит намного проще и приятнее для чтения, не нужно гадать, что за обратный вызов или зачем та или иная функция - экономия времени, залог успеха!

5. Перечисления.

В редких случаях, но они все-таки бывают, используют перечисления, с ними иногда удобно и они имеют место быть:
SourcePawn:
// ПаскальРегистр
enum ArmorType
{
    // Наименование полей строго капсом
    ARMOR_NONE,
    ARMOR_KEVLAR,
    ARMOR_VESTHELM
};
Тут только добавлю, что бывают ситуации, когда перечислители стоит называть в ПаскальРегистре, вполне, допустимо, а яркий пример - MenuAction.

Ссылка по данной теме.
- Википедия

6. Структуры.

Структуры
строятся по аналогии с перечислениями, только поля структуры (переменные внутри нее), работают по принципу локальных переменных, а методы, как функции.
SourcePawn:
// структура
struct Statistics
{
    // поля
    char name[MAX_NAME_LENGTH];
    int frags;
    int deaths;
    float headshotAccuracy;
 
    // метод
    int GetFrags()
    {
        return frags;
    }

    ...
};

Ссылка по данной теме.
- Википедия

Закончив с базой, можно переходить к мелочам и деталям.

7. Пробелы.

Из маленьких штришков и мазков складывается картина, точно самое и с кодом. Небольшая деталь, но показывает на сколько разработчик аккуратен и следит за своей разработкой.
SourcePawn:
// отделяйте условия пробелами, тем самым это выглядит куда более гармонично, чем если
// вы лепили все с друг другом
if (param1)
{
    for (int i = 1; i <= MaxClients; ++i)
    {
        ...
    }
}
else if (param2)
{
    while (flag)
    {
        ...
    }
}
else
{
    // главное не отделяйте пробелом передачу аргументов во функцию!
    Foo();
}

Отделяйте литералы и операнды - используйте пробелы и не забывайте про них, вы обязательно заметите, как ваш код преобразуется не внеся никаких изменений в его логику.
SourcePawn:
bool Foo(int param1, int param2)
{
    result = param1 + param2;
    result += 2;
    result -= 2;
 
    // старайтесь брать в круглые скобочки условия или операции, превышающие одного слова,
    // тем самым вы подчеркиваете важность данного условия и оно в первую очередь бросится в глаза.
    return (result > 0) ? true : false;
}

8. Комментарии.

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

Я выделяю 3 вида комментарий в SourcePawn:
- Строчный комментарий.
- Блочный комментарий.
- JSDoc комментарий.

Пробежимся по ним.

1. Строчный комментарий - обычно используется, если нужно внести небольшую пометку, которая уместится в одну строчку.
SourcePawn:
// пункты меню
#define ITEAM_1             1
#define ITEAM_2             2
#define ITEAM_3             3
#define ITEAM_BACKBUTTON    9 // кнопка назад

void Foo()
{
    // пробегаемся по клиентам с четными индексами
    for (int i = 1; i <= MaxClients; ++i)
    {
        if(IsClientInGame(i) && i % 2)
        {
            ...
        }
    }
}

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

2. Блочный комментарий - используется, когда вы хотите вылить все свои мысли на определенный участок кода, обычно использую перед функциями или когда нужно оставить заметку непосредственно в процессе написания кода.
SourcePawn:
/*
    Совершенно бесполезная функция, возвращает переданное число.
    TODO: Хорошо бы переписать её, чтобы она несла пользу.
*/
int Foo(int param)
{
    ...
 
    return param;
}

3. JSDoc комментарий - один из самых интересных стилей введения комментариев, так как он подсвечивает ваш комментарий при написание той или иной функции (в зависимости от среды разработки). Тут советую почитать дополнительную информацию в интернете, хотя в пределах SourcePawn такой вид комментария используется только при объявление нативных функций или форвардов.

SourcePawn:
/**
* Проверяет игрока на нахождение в игре.
*
* @param     client - индекс игрока.
* @return             true, если игрок в игре,
*                    иначе false
*/
native bool IsClientInGame(int client);

Советую прочитать про теги и в целом про вид данного комментария.
- Википедия

Думаю, базовую концепцию стиля написания на языке SourcePawn я смог разъяснить, вы будете исключительно правы - выдвигая свои способы и методы написания кода, так как в большинстве - это индивидуально и сравнимо с почерком, каждый пишет код так, как считает нужным, НО люди, которые только начинают основывать язык и в большинстве случаев даже не являются программистами или скриптерами (два разных понятия, подмечу, пожалуй), пишут совершенно абсурдные вещи, мешают старый синтаксис с новым, теряются сами в своем коде и просят помощи, подытожу. Данная статья была написана, исключительно для ребят, которые мечутся и не могут выбрать точный стиль написания, это был урок по стилю написания кода на SourcePawn - пишите свой код чище, уделяйте внимание мелочам и не забывайте про комментарии, всем спасибо и всем хорошего кодирования!

Пару ссылок:
Венгерская нотация
Гайд по оформлению кода на C++
Введение в SourcePawn 1.7
Переходный синтаксис SourcePawn
Комментирование кода: хороший, плохой, злой
 
Последнее редактирование:

Nekro

Терра инкогнита
Сообщения
4,042
Реакции
2,295
Глобальная переменная должна иметь:
- Яркое, самоговорящее название.
- Иметь префикс g_ (что расшифровывается, как global_).
- Содержать тип самой переменной (вы же помните, что хоть мы и пользуемся новым синтаксисом, указанный тип переменной в её название, облегчит вашу совместную жизнь с ней в разы).
Это определённо здорово, но опять же если плагин в 100 строк объявлять именно таким образом возможно излишне и достаточно типа переменной
bEnable
Но в целом это конечно хорошая практика и g_ всегда полезно, просто если код мал.. Это скорее к большому коду в тысячи строк.

3. Локальные переменные

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

Область видимости локальной переменной - это функция в которой она определена, обычно в скриптовых языках, да и в общем на практике писать большие функции - не комильфо.
Поэтому, вполне разумным будет для локальной переменной присвоить название, которое соответствует ее назначению, не стоит дописывать название типа переменной, так как оно и так на виду и старайтесь использовать такой стиль написания, как верблюжийРегистр.
Опять же, если функция большая, то возможно имеет смысл дописать тип переменной iClient, так как каждый раз листать код в поисках.. ведь проще определить сразу по названию, да и смотрится вроде лучше.

Так же хотел сказать в целом спасибо за статью, побольше бы такой информации. Однозначно с меня лайк 👍
 

DENFER

Пишу плагины за два биг тести и картошку фри..
Сообщения
260
Реакции
289
Это определённо здорово, но опять же если плагин в 100 строк объявлять именно таким образом возможно излишне и достаточно типа переменной
bEnable
Но в целом это конечно хорошая практика и g_ всегда полезно, просто если код мал.. Это скорее к большому коду в тысячи строк.


Опять же, если функция большая, то возможно имеет смысл дописать тип переменной iClient, так как каждый раз листать код в поисках.. ведь проще определить сразу по названию, да и смотрится вроде лучше.

Так же хотел сказать в целом спасибо за статью, побольше бы такой информации. Однозначно с меня лайк 👍
Попробую аргументировать свое сие чудо, использовать префиксы - это хорошая практика натренировать руку на простом. В дальнейшем вы перестанете даже замечать, как на автомате используете префикс в название переменной.

Что касается, больших функций, то такие функции лучше разбивать на подфункции, не делать громоздкий код, а стараться укомплектовать, но опять-таки, думаю, все зависит от ситуации, я лишь постарался конкретизировать общие случаи и любому такому случаю, есть исключения.

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

Chris D

Участник
Сообщения
14
Реакции
7
Заполняемая табличка из редактирования пользователя.
Чаще всего встречаются такие директивы, как:
- #include
- #define
- #pragma
- #if / #else
забыл упомянуть tryinclude, тоже частая директива в модульных плагинах, если наличие какого-то инклуда опционально.

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

Если функция является колбеком, то лучше добавить соответствующий префикс
намного проще все колбеки помечать префиксом On, который уже сигнализирует, что её вызывает кто-то/что-то, когда что-то происходит. А чтобы понять тип - обычно достаточно посмотреть на сигнатуру. никто же в здравом уме не станет определять колбек подключения к базе, указав у него параметрами выполнение команды клиентом в консоли, правда?)
 

DENFER

Пишу плагины за два биг тести и картошку фри..
Сообщения
260
Реакции
289
забыл упомянуть tryinclude, тоже частая директива в модульных плагинах, если наличие какого-то инклуда опционально.


сами разработчики, к слову, используют и рекомендуют называть переменные в змеином_стиле.


намного проще все колбеки помечать префиксом On, который уже сигнализирует, что её вызывает кто-то/что-то, когда что-то происходит. А чтобы понять тип - обычно достаточно посмотреть на сигнатуру. никто же в здравом уме не станет определять колбек подключения к базе, указав у него параметрами выполнение команды клиентом в консоли, правда?)
О да, я ждал этого, да воцарится дискуссия 😈 Ладно, ближе к теме. Сейчас пробегусь по вашим аргументам и постараюсь аргументировать свою точку зрения.

Во-первых, я постарался прикрепить те директивы, которые чаще всего замечал в плагинах, да #tryinclude был, но я пренебрег им, как и впрочем #error и #undef - и указал на них в отдельной статье.

Во-вторых, тяжело смотреть на скрипт, в котором переменные используют Снейк_Кейс - обычно он подходит для констант с использованием капса, и да кстати, если полазить в исходниках SM, что я в принципе и сделал перед публикацией статьи, то вы обнаружите тот самый camelCase. Обычно данный стиль используют в таких языках, как: Python, Ruby, Rust и даже если я не ошибаюсь в них это принято за правило.

В-третьих, вы слишком серьезно относитесь к скриптовому языку, будьте проще ;) Лично сугубое мнение, лучше в данном языке пометить колбек префиксом непосредственно функции, которая вызывает колбек, тем более программисты - люди ленивые и сыщики, если что-то не попалось под глаз или не ясно происхождение, то можно и по сигнатурам полазить, просто будьте проще ;) Не всегда общепринятое правило, действует везде.
 

Chris D

Участник
Сообщения
14
Реакции
7
Заполняемая табличка из редактирования пользователя.
это с какой колокольни крикнули?
банально в их дс можно найти, ещё на форуме сам Байло писал неоднократно.

если полазить в исходниках SM, что я в принципе и сделал перед публикацией статьи, то вы обнаружите тот самый camelCase
и какое отношение исходники SM имеют к скриптовой среде? правильно, никакое, оно лишь настраивает и запускает SourcePawn, реализуя часть функционалов для этих самых плагинов.
в плагинах camelCase иногда проскакивает, но в целом если посмотреть по тому же Гитхабу, часть пуллов чаще всего не мерджилась из-за камела.

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

В-третьих, вы слишком серьезно относитесь к скриптовому языку, будьте проще ;)
тогда я не вижу смысла в публикации этого материала, если на него всё равно будут забивать, аргументируя так же ("ну это же скриптовый язык, надо быть проще").
с другой стороны - хоть кто-то где-то описал то, что здесь принято давно, и это хорошо.

я лишь высказал своё имхо по тем моментам, по которым мне это показалось уместным.
 

DENFER

Пишу плагины за два биг тести и картошку фри..
Сообщения
260
Реакции
289
банально в их дс можно найти, ещё на форуме сам Байло писал неоднократно.


и какое отношение исходники SM имеют к скриптовой среде? правильно, никакое, оно лишь настраивает и запускает SourcePawn, реализуя часть функционалов для этих самых плагинов.
в плагинах camelCase иногда проскакивает, но в целом если посмотреть по тому же Гитхабу, часть пуллов чаще всего не мерджилась из-за камела.

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


тогда я не вижу смысла в публикации этого материала, если на него всё равно будут забивать, аргументируя так же ("ну это же скриптовый язык, надо быть проще").
с другой стороны - хоть кто-то где-то описал то, что здесь принято давно, и это хорошо.

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

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

Paranoiiik

хачю клиентмод
Сообщения
2,047
Реакции
1,491
Тоже хочу докопаться
Глобальная переменная должна иметь:
- Иметь префикс g_
Никогда этого не понимал. Лично для меня это совершенно бесполезный префикс.
Если и так расставляешь префиксы правильно, даже в большом плагине путаница не возникнет.
Типа g_iCount, g_bTrue, g_sString, g_fTime?
Считаю, що и iCount, bTrue, sString, fTime отлично понимается.
А если путаница потенциально возникает, когда в одном и том же месте встречаются и, допустим, квары, и просто переменные, можно квары называть логически в целом или логически, опираясь на суть программы - iCVarCount
Статья, вроде как, призвана писать "лаконичный" чёткий код, а с этими g_ он превращается в лютое дерьмо и кашу
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,569
Реакции
5,071
В первую очередь хочется вырвать автору руки из задницы и пришить на положенное им место за использование им #pragma tabsize 0.

Во вторую хотелось бы ему сообщить, что однотипные переменные можно группировать в один блок при создании.
В смысле делать не так:
C-подобный:
bool foo;
bool bar;
bool foobar;
, а вот так (имеет смысл в случае объявления локальных переменных):
C-подобный:
bool foo, bar, foobar;
или вот так (лучше при объявлении глобальных переменных):
C-подобный:
bool
    foo,
    bar,
    foobar;
Это позволяет визуально выделять однотипные переменные в блоки (и экономить размер исходника ^_^).

Ещё хотелось бы напомнить самое главное: форматирование кода должно быть однообразным во всём плагине (отступы либо только табуляцией, либо только пробелами, лично я предпочитаю табуляцию размером в 4 пробела; при заключении блоков кода в фигурные скобки, открывающая должна быть только либо в конце строки, либо в начале пустой строки, я предпочитаю второй вариант, т.к. для меня так проще находить начало блока).

И да, автор совет на счёт пробела между if, for, while, etc. и открывающей круглой скобкой в своём коде сам не соблюдает. =)
Я, кстати не вижу в этом совершенно никакого смысла, т.к. использую подсветку синтаксиса и у меня эти скобки отличаются цветом от окружающих их символов.

На счёт camelCase и snake_case: я предпочитаю использовать в именах глобальных переменных первый тип, а второй - для локальных.
Да и указывать тип для локальной переменной меньше смысла, т.к. обычно блоки, в которых они используются, малы и забыть тип переменной не слишком уж легко (а чтобы вспомнить не требуется прокрутить весь исходник).
По этой же причине не вижу смысла делать префиксы g_* для глобальных переменных.
Капс же обычно использую для имён констант (const в типе переменной) и дефайнов.

На счёт использования #define: учитывайте то, что это несколько упрощает написание однотипного кода, но иногда предпочтительнее написать функцию.
Т.к. использование #define визуально сокращает код, но при компиляции код получится точно таким, как если бы #define не использовался (т.е. займёт столько же места в памяти).
Т.е. это просто дублирование кода.

На счёт комментариев: я грешен и практически не комментирую свой код (да и 90% кода этого вроде как и не требует, хотя я люблю использовать всякие хаки и новичок в моём коде точно не разберётся, а иногда по истечению какого-то времени я и сам понять не могу ^_^).

Кстати, на счёт структуры кода: ТС вспомнил о ней в начале, но в статье ничего про это нет.
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #11
таким образом возможно излишне
наоборот, во-первых получится что в один плагинах глобальные переменные по одному называются, а других по другому. Во-вторых - зачем опускать префикс? Как размер кода влияет на его стиль? А если через год он расширится, переименовывать переменные?

Для автора - стоит упомянуть что подобное именование - это Венгерская нотация — Википедия

почитал комментарии по диагонали:
по размерам функций - желательно чтобы каждая функция делала небольшой логически связанный кусочек работы и желательно могла переиспользоваться


может еще что добавлю как дочитаю
 

DENFER

Пишу плагины за два биг тести и картошку фри..
Сообщения
260
Реакции
289
Такс, пробегусь пожалуй снизу вверх, вот то, чего я и ожидал.

Для автора - стоит упомянуть что подобное именование - это Венгерская нотация — Википедия
Да, благодарю, что напомнил, держал в голове, но в какой-то момент выскользнуло, поправил ссылки.

В первую очередь хочется вырвать автору руки из задницы и пришить на положенное им место за использование им #pragma tabsize 0.

Во вторую хотелось бы ему сообщить, что однотипные переменные можно группировать в один блок при создании.
В смысле делать не так:
C-подобный:
bool foo;
bool bar;
bool foobar;
, а вот так (имеет смысл в случае объявления локальных переменных):
C-подобный:
bool foo, bar, foobar;
или вот так (лучше при объявлении глобальных переменных):
C-подобный:
bool
    foo,
    bar,
    foobar;
Это позволяет визуально выделять однотипные переменные в блоки (и экономить размер исходника ^_^).

Ещё хотелось бы напомнить самое главное: форматирование кода должно быть однообразным во всём плагине (отступы либо только табуляцией, либо только пробелами, лично я предпочитаю табуляцию размером в 4 пробела; при заключении блоков кода в фигурные скобки, открывающая должна быть только либо в конце строки, либо в начале пустой строки, я предпочитаю второй вариант, т.к. для меня так проще находить начало блока).

И да, автор совет на счёт пробела между if, for, while, etc. и открывающей круглой скобкой в своём коде сам не соблюдает. =)
Я, кстати не вижу в этом совершенно никакого смысла, т.к. использую подсветку синтаксиса и у меня эти скобки отличаются цветом от окружающих их символов.

На счёт camelCase и snake_case: я предпочитаю использовать в именах глобальных переменных первый тип, а второй - для локальных.
Да и указывать тип для локальной переменной меньше смысла, т.к. обычно блоки, в которых они используются, малы и забыть тип переменной не слишком уж легко (а чтобы вспомнить не требуется прокрутить весь исходник).
По этой же причине не вижу смысла делать префиксы g_* для глобальных переменных.
Капс же обычно использую для имён констант (const в типе переменной) и дефайнов.

На счёт использования #define: учитывайте то, что это несколько упрощает написание однотипного кода, но иногда предпочтительнее написать функцию.
Т.к. использование #define визуально сокращает код, но при компиляции код получится точно таким, как если бы #define не использовался (т.е. займёт столько же места в памяти).
Т.е. это просто дублирование кода.

На счёт комментариев: я грешен и практически не комментирую свой код (да и 90% кода этого вроде как и не требует, хотя я люблю использовать всякие хаки и новичок в моём коде точно не разберётся, а иногда по истечению какого-то времени я и сам понять не могу ^_^).

Кстати, на счёт структуры кода: ТС вспомнил о ней в начале, но в статье ничего про это нет.
Очень много информации, руки только не вырывайте, хотя бы правую 🙃 Я ценю, что вы залезли и посмотрели мои плагины из продакшена, но я не позиционировал себя, как пример для подражания. Кстати, существуют и другие мои работы, не опубликованные на общее обозрение, вашу критику в свою сторону я услышал.

Тоже хочу докопаться

Никогда этого не понимал. Лично для меня это совершенно бесполезный префикс.
Если и так расставляешь префиксы правильно, даже в большом плагине путаница не возникнет.
Типа g_iCount, g_bTrue, g_sString, g_fTime?
Считаю, що и iCount, bTrue, sString, fTime отлично понимается.
А если путаница потенциально возникает, когда в одном и том же месте встречаются и, допустим, квары, и просто переменные, можно квары называть логически в целом или логически, опираясь на суть программы - iCVarCount
Статья, вроде как, призвана писать "лаконичный" чёткий код, а с этими g_ он превращается в лютое дерьмо и кашу
Под словом должна, я конкретизирую и выделяю под общее обозрение свое видение, очевидно, что у каждого оно свое, я лишь призываю.

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

Тоже хочу докопаться
Не сказал бы, что докопался, вполне весомое замечание и думаю будущему поколению будет интересно узнать и вашу точку зрения и @Grey83.

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