Как правильно называть переменные и функции в 1С:Предприятии для создания чистого и читаемого кода?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

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

Венгерская нотация – пережиток прошлого или полезный инструмент?

Венгерская нотация, подразумевающая использование префиксов для указания типа переменной (например, `ст` для структуры, `тд` для табличного документа, `о` для объекта), некогда была весьма популярна. Однако сегодня многие разработчики считают её устаревшей.

Преимущества: Некоторые разработчики видят удобство в быстром определении типа данных переменной, особенно в условиях динамической типизации 1С, где явное объявление типа отсутствует. Например, увидев `оКонтрагент`, мы сразу понимаем, что это переменная типа "объект", а `Контрагент` может быть ссылкой. Аналогично, `пНоменклатура` может использоваться для обозначения параметра метода, чтобы избежать конфликта имен с реквизитами или свойствами.

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

Наш вывод: В целом, в современных подходах к чистому коду венгерская нотация не рекомендуется. Однако, если она закреплена во внутренних стандартах проекта, её следует придерживаться для обеспечения единообразия. Важно, чтобы используемые префиксы были максимально однозначными и не создавали "смысловой мусор", как некоторые считают. Например, вместо `ПеременнаяМодуляИмяПеременной` можно использовать `мИмяПеременной`, если это согласовано.

Длина имен: баланс между ясностью и читабельностью

Современные принципы "Чистого кода" настоятельно рекомендуют использовать длинные, описательные имена для переменных и функций. Такой подход делает код самодокументируемым, что снижает когнитивную нагрузку на разработчика, который читает или поддерживает этот код.

Аргументы за длинные имена: Мы стремимся к тому, чтобы код был понятен любому программисту, который будет работать с ним в будущем. Подробные имена, такие как `НоменклатураНаименование` вместо `Ним`, однозначно указывают на смысл переменной. Это особенно актуально для переменных модуля, для которых также можно использовать префиксы, например, `мНоменклатураКод`, чтобы показать область действия и избежать неоднозначности.

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

Пример именования по "префиксному" принципу:


// Переменная-ссылка
Контрагент = Справочники.Контрагенты.НайтиПоКоду("000000001"); 

// Объект
оКонтрагент = Контрагент.ПолучитьОбъект();

// Параметр метода
Процедура ОбработатьДанные(пНоменклатура, пКонтрагент, пОрганизация);
    Номенклатура = пНоменклатура;
    Контрагент = пКонтрагент;
    Организация = пОрганизация;
КонецПроцедуры;

В данном примере мы видим, как префиксы `о` и `п` помогают быстро определить назначение переменной, уменьшая "смысловой мусор" и увеличивая читаемость, особенно когда в процедуре могут присутствовать одноименные реквизиты.

Использование структур для группировки связанных данных: Вместо множества однотипных переменных с префиксами, например, `НоменклатураКод`, `НоменклатураНаименование`, мы можем использовать структуры. Этот подход позволяет логически сгруппировать связанные данные и обращаться к ним через точку, например, `Номенклатура.Код` и `Номенклатура.Наименование`.


// Вместо отдельных переменных
// НоменклатураКод = "001";
// НоменклатураНаименование = "Молоко";

// Используем структуру
Номенклатура = Новый Структура;
Номенклатура.Вставить("Код", "001");
Номенклатура.Вставить("Наименование", "Молоко");

// Обращение к данным
Сообщить(Номенклатура.Код);
Сообщить(Номенклатура.Наименование);

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

Именование функций и процедур: глаголы, существительные и префиксы

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

"Получить", "Найти", "Создать" и другие глаголы в именах функций

В стандартах разработки 1С, особенно в типовых конфигурациях и БСП, часто встречаются функции с глагольными префиксами, такими как `Получить`, `Найти`, `Создать`. Тем не менее, 1С официально не одобряет использование слова `Получить` в функциях, хотя на практике оно встречается повсеместно.

Аргументы за использование глаголов: Мы можем сказать, что использование глаголов в начале имени функции делает её назначение предельно ясным. Функция `ПолучитьНаименованиеНоменклатуры` сразу говорит нам, что она возвращает наименование. Это помогает нам различать функции, выполняющие различные действия с одним и тем же объектом. Например, `Номенклатура()` ничего не говорит нам о ее назначении, в то время как `ПолучитьНоменклатура()` или `НоменклатураПолучить()` четко указывают на действие. Более того, наличие таких префиксов облегчает поиск нужных методов, например, по слову `Установить`.

Аргументы против использования глаголов: Некоторые эксперты по "Чистому коду", например, Роберт Мартин, настаивают на том, что имена методов должны быть глаголами или глагольными словосочетаниями, но при этом они должны описывать действие, а не быть просто "получением". Например, `postPayment()`, `deletePage()`. В этом контексте `ПолучитьНаименованиеНоменклатуры` может быть расценено как избыточное, если `НаименованиеНоменклатуры()` уже подразумевает получение. Также, в таких конструкциях как `НоменклатураНаименованиеПолучить` некоторые видят нарушение принципов чистого кода, предпочитая более естественный порядок слов.

Наш анализ: Мы видим, что нет единого мнения. Если рядом существуют функции `НаименованиеНоменклатуры()`, `ЗаполнитьНаименованиеНоменклатуры()` и `СформироватьНаименованиеНоменклатуры()`, то без глагольного префикса они могут выглядеть запутанно. Здесь глагол помогает различать их назначение. Важно продумать на будущее: "лишние" буковки сегодня могут сделать код более стройным и понятным завтра.

Глаголы в процедурах, существительные в функциях: функциональный подход

В контексте чистого кода и функционального программирования, мы часто различаем функции и процедуры по их побочным эффектам. Функции, как правило, должны возвращать значение и не иметь побочных эффектов (то есть не изменять состояние программы за пределами себя). Процедуры, наоборот, могут изменять состояние и обычно не возвращают значения.

Рекомендации: * Для процедур, изменяющих состояние или выполняющих действия, мы рекомендуем использовать глаголы или глагольные словосочетания в повелительном наклонении: `УстановитьСтатус`, `УдалитьФайл`, `ОткройФорму`. * Для функций, возвращающих значение, без изменения состояния, можем рассматривать два варианта: * Глагол, описывающий получение значения: `ПолучитьСписокКонтрагентов()`. * Существительное, соответствующее возвращаемому значению: `УпаковочныйЛист()` (если функция формирует и возвращает печатную форму) или `СписокКонтрагентов()`.

Примеры: Посмотрим на пример из дискуссии:


Процедура УстановитьСтатус(Знач Документ, Знач Статус) Экспорт
    // логика стейт-машины
КонецПроцедуры

Процедура УстановитьСтатусОжидание(Знач Документ) Экспорт
    УстановитьСтатус(Документ, Перечисления.СтатусыОпераций.Ожидание);
КонецПроцедуры

//... и другие процедуры для установки конкретных статусов

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

Однако, мы также должны быть осторожны с излишним созданием множества однотипных функций. Если есть возможность, лучше использовать одну функцию с параметрами, которая может принимать различные значения, вместо сотни функций с похожей логикой. Пример: `СформироватьУпаковочныйЛист("Формат2025")` вместо `СформироватьУпаковочныйЛистПечатнаяФормаФормат2025()`.

Передача параметров и возврат значений через структуры

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

Преимущества:

  1. Уменьшение количества аргументов: Вместо длинной "гирлянды" из множества параметров в сигнатуре метода, мы можем передать одну структуру. Это делает объявление метода гораздо короче и читабельнее.
  2. Упрощение рефакторинга и расширения: При необходимости добавить новый параметр, нам не нужно изменять сигнатуру функции или процедуры. Мы просто добавляем новое свойство в передаваемую или возвращаемую структуру. Это особенно ценно в больших проектах с частыми доработками.
  3. Централизованное управление ошибками: Структура позволяет вернуть не только основной результат операции, но и флаг успешности (`Результат`), а также подробное описание ошибки (`ОписаниеОшибки`), если что-то пошло не так. Это очень удобно для работы с веб-сервисами или при взаимодействии с внешними системами.

Пример возврата структуры с результатом и ошибкой: Давайте посмотрим на пример функции, которая возвращает структуру:


Функция ПолучитьКонтрольноеЧислоGS1(Знач ID) Экспорт
    СтруктураВозврата = Новый Структура;
    СтруктураВозврата.Вставить("Результат", Истина);
    СтруктураВозврата.Вставить("ОписаниеОшибки", "");
    СтруктураВозврата.Вставить("КонтрольноеЧисло", Неопределено);
    
    Если АСФОбщегоНазначенияКлиентСервер.ЕстьНеЦифрыВСтроке(ID) Тогда
        СтруктураВозврата.ОписаниеОшибки = "Переданный идентификатор семейства GS1 должен содержать только цифры.";
        СтруктураВозврата.Результат = Ложь;
        Возврат СтруктураВозврата;
    КонецЕсли;

    // ... далее идет логика расчета контрольного числа ...
    // Если все успешно:
    // СтруктураВозврата.КонтрольноеЧисло = РассчитанноеЗначение;
    // Возврат СтруктураВозврата;
    
    Возврат СтруктураВозврата;
КонецФункции

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

Пример передачи параметров структурой:


// Вместо: Процедура КакойТоМетодОбработки(Номенклатура, Контрагент, Организация);
Процедура КакойТоМетодОбработки(ПараметрСтруктура); 
    Номенклатура = ПараметрСтруктура.Номенклатура;
    Контрагент = ПараметрСтруктура.Контрагент;
    Организация = ПараметрСтруктура.Организация;
КонецПроцедуры

Этот подход делает объявление метода более лаконичным, и нам не придется изменять его сигнатуру при добавлении новых параметров.

Недостатки и их смягчение: Основной недостаток — отсутствие строгой типизации в 1С. Мы не можем на этапе компиляции гарантировать, что в структуре `ПараметрСтруктура` будут присутствовать ожидаемые свойства (`Номенклатура`, `Контрагент` и т.д.). Это требует от нас дополнительных проверок в коде или хорошего документирования "контракта" функции (что ожидается в структуре).

Некоторые коллеги предлагают использовать для этого "псевдомейби" (аналог Maybe-типов в функциональных языках):


// Пример использования вспомогательного модуля для возврата результата
ответ = ЧтоТоНадоСделать();
Если НЕ _Результат.ЭтоОшибка(ответ) Тогда
    данные = _Результат.ДанныеИз(ответ);
Иначе
    ВызватьИсключение _Результат.ОшибкаИз(ответ);
КонецЕсли;

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

Обработка ошибок: структуры или исключения?

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

Структуры для штатных ошибок: Мы рекомендуем использовать возврат ошибок в структурах (как мы рассмотрели выше) для "штатных" ошибок. Это те ситуации, которые являются ожидаемой частью логики программы, например: "пользователь ввел некорректные данные", "запись не найдена", "внешний сервис вернул ошибку". В таких случаях функция возвращает структуру, которая содержит не только результат, но и флаг успешности и подробное описание причины неудачи.


// Пример возврата ошибки в структуре
Функция ПроверитьПользователя(Логин, Пароль) Экспорт
    РезультатПроверки = Новый Структура;
    РезультатПроверки.Вставить("Успешно", Истина);
    РезультатПроверки.Вставить("Сообщение", "");

    Если Логин = "" Тогда
        РезультатПроверки.Успешно = Ложь;
        РезультатПроверки.Сообщение = "Логин не может быть пустым.";
        Возврат РезультатПроверки;
    КонецЕсли;
    // ... дальнейшая логика проверки ...
    Возврат РезультатПроверки;
КонецФункции

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

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

Стандарты кодирования 1С и личные предпочтения

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

Официальные стандарты 1С: Мы знаем, что 1С рекомендует начинать каждое слово в имени переменной с прописной буквы (`ИмяПеременной`), а также запрещает начинать имена переменных с подчеркивания (`_`). Однако на практике мы часто видим отступления от этих правил, например, в именах общих модулей, таких как `_СокращенноеИмяФранчаОбщийМодуль`, или для разделения составных имен, как `КонтрольОстатков_ТоварыВЯчейках`.

Личные стили и их мотивация: Некоторые разработчики предпочитают отклоняться от официальных рекомендаций, чтобы улучшить читаемость или обозначить область действия переменных. Например: * Локальные переменные: начинать с маленькой буквы (`локальнаяПеременная`) для отличия от реквизитов формы. * Параметры методов: использовать префикс `п` (`пНоменклатура`), чтобы избежать конфликтов с именами свойств или реквизитов. * Переменные модуля: использовать префикс `м` (`мИмяПеременной`) для обозначения области действия. * Вспомогательные модули: начинать имена общих модулей с подчеркивания (`_Массивы`) для "библиотечных" методов, не относящихся к бизнес-логике. Эти подходы мотивированы желанием уменьшить когнитивную нагрузку и "смысловой мусор", компенсируя отсутствие строгой типизации и неймспейсов в 1С. Например, модуль `_Массивы` может содержать общие методы для работы с массивами, такие как `_Массивы.НовыйМассив()`, что короче, чем `ОбщегоНазначенияМассивы.НовыйМассив()`.

Важность согласованности: Независимо от того, какой подход мы выберем, самое важное — это единообразие и согласованность в рамках проекта. Даже если какой-то стандарт кажется нам неидеальным, его последовательное применение всей командой намного лучше, чем хаотичное смешение различных стилей. В коллективной разработке важны стандарты, а не личные предпочтения. Стандарты уменьшают "когнитивный хаос" и помогают новичкам быстрее влиться в проект. Поэтому, мы должны договориться о единой культуре кода и придерживаться её.

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

Главное — читаемость и единообразие

Подводя итог нашему обсуждению, мы приходим к следующему выводу: код должен быть читабельным и самодокументируемым. Все остальное — вторично. Мы должны стремиться к тому, чтобы любой разработчик, столкнувшись с нашим кодом, мог быстро понять его смысл без глубокого анализа.

Основные принципы, к которым мы стремимся:

  1. Описательные имена: Переменные и функции должны иметь имена, которые ясно описывают их назначение и содержимое.
  2. Баланс длины: Имена должны быть достаточно длинными для ясности, но не настолько, чтобы ухудшать читаемость.
  3. Предсказуемое поведение: Функции должны либо возвращать результат без побочных эффектов, либо быть процедурами, явно изменяющими состояние.
  4. Использование структур: Для передачи множества параметров и возврата сложных результатов (включая информацию об ошибках) структуры являются предпочтительным решением.
  5. Правильная обработка ошибок: Штатные ошибки возвращаем через структуру, исключительные — через исключения.
  6. Единообразие: Это самый критичный фактор. В команде необходимо договориться о единых стандартах именования и неукоснительно им следовать. Даже если принятый стандарт не идеален, его последовательное применение будет намного эффективнее, чем хаотичное смешение стилей.

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

← На главную