К статье
Практический материал

Разработка и Конфигурация · 13 мин

Для чего нужны функции и процедуры в 1С

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

Функции и процедуры — базовые строительные блоки любого кода на встроенном языке 1С. Каждый обработчик кнопки, каждая проверка заполнения документа, каждый расчёт итогов в отчёте в конечном счёте оформляется именно как процедура или функция. Без них невозможно написать ни одного работающего расширения или доработки конфигурации.

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

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

Что такое процедура и функция: ключевое различие

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

Функция отличается одним принципиальным свойством: она обязана вернуть значение через оператор Возврат. Функции применяют там, где нужен результат вычисления: рассчитать сумму НДС, проверить корректность ИНН, получить текущего пользователя, определить ставку по договору. Объявляется функция словом Функция и завершается КонецФункции.

Выбор между процедурой и функцией определяется простым вопросом: нужен ли вызывающему коду результат? Если да — объявляйте функцию. Если код только что-то делает (записывает, выводит, изменяет данные) и результат не требуется — достаточно процедуры. Возвращать результат «через параметр по ссылке» вместо нормальной функции считается плохим стилем и затрудняет чтение кода.

Как объявить и вызвать: синтаксис на практике

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

// Объявление процедуры

Процедура ЗаписатьСообщениеВЛог(ТекстСообщения, Уровень = "Информация") Экспорт

ЗаписьЖурналаРегистрации("Обмен", УровеньЖурналаРегистрации.Информация, , , ТекстСообщения);

КонецПроцедуры

// Вызов

ЗаписатьСообщениеВЛог("Обмен завершён");

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

Функция РассчитатьСуммуНДС(Сумма, СтавкаНДС) Экспорт

Если СтавкаНДС = 0 Тогда

Возврат 0;

КонецЕсли;

Возврат Окр(Сумма * СтавкаНДС / (100 + СтавкаНДС), 2);

КонецФункции

Параметры могут иметь значения по умолчанию — они указываются после знака равенства и должны стоять в конце списка параметров. При вызове такие параметры можно опускать. Ключевое слово Знач перед параметром означает передачу по значению: изменения параметра внутри метода не затронут переменную вызывающего кода.

bsl
Функция ПолучитьЦену(Номенклатура, Дата = Неопределено) Экспорт
    Если Дата = Неопределено Тогда
        Дата = ТекущаяДатаСеанса();
    КонецЕсли;
    // ... запрос цены на дату
    Возврат Цена;
КонецФункции

Где размещать процедуры и функции: виды модулей

Код в 1С не существует «сам по себе» — каждая процедура и функция живёт в каком-то модуле. От выбора модуля зависит, где код будет исполняться (на клиенте или на сервере) и кто сможет его вызвать.

  • Модуль формы — обработчики событий элементов формы и вспомогательные методы, нужные только этой форме.
  • Модуль объекта — логика самого объекта: обработка проведения, заполнение, проверка заполнения.
  • Модуль менеджера — операции над коллекцией объектов: создание, поиск, печатные формы.
  • Общие модули — переиспользуемая логика, доступная из любого места конфигурации. Именно сюда выносят функции вроде расчёта НДС или проверки ИНН.
  • Модуль команды — код, выполняемый при вызове команды интерфейса.

Общие модули имеют важные флаги: «Сервер», «Клиент», «Вызов сервера», «Привилегированный режим». Функцию, которая обращается к базе данных, нельзя помещать в клиентский модуль — она просто не скомпилируется или упадёт в рантайме. Общее правило: вся работа с данными — в серверных модулях, на клиенте остаётся только интерфейсная логика.

Директивы компиляции и контекст выполнения

В модулях форм и команд перед объявлением процедуры или функции указывается директива компиляции: &НаКлиенте, &НаСервере, &НаСервереБезКонтекста или &НаКлиентеНаСервереБезКонтекста. Директива определяет, где будет исполняться метод, и какие объекты ему доступны.

Метод &НаСервере в модуле формы имеет доступ к данным формы и реквизитам, но при каждом вызове данные формы сериализуются и передаются на сервер — это дорогая операция. Метод &НаСервереБезКонтекста не видит реквизиты формы, зато выполняется быстрее: в него нужно явно передать все необходимые параметры. Для тяжёлых серверных операций, которым не нужны данные формы целиком, вариант «без контекста» предпочтительнее.

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

Как вынести повторяющийся код в общую функцию
  1. 1
    Найдите фрагмент кода, который дублируется в двух и более местах
  2. 2
    Создайте или выберите подходящий общий модуль с нужными флагами (Сервер, Вызов сервера)
  3. 3
    Объявите функцию с ключевым словом Экспорт и осмысленными параметрами
  4. 4
    Перенесите код в тело функции, заменив конкретные переменные на параметры
  5. 5
    Замените все дублирующиеся фрагменты вызовом новой функции
  6. 6
    Проверьте работу каждого места вызова и выполните проверку конфигурации

Параметры, возвращаемые значения и структурирование кода

Хорошая функция делает одну вещь и называется глаголом с дополнением: РассчитатьСуммуДокумента, ПолучитьОстатокПоСкладу, СформироватьПечатнуюФорму. Если в имени хочется написать «И» — это признак того, что функцию стоит разделить на две.

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

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

Процедура или функция: как выбрать

Процедура

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

Функция

Нужен результат вычисления или проверки: сумма, признак успеха, найденная ссылка, структура данных. Вызывающий код использует возвращённое значение.

Функция с возвратом структуры

Результат составной: несколько значений, признак ошибки и описание проблемы. Позволяет расширять результат без изменения сигнатуры.

Типичные ошибки и как их избежать

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

Вторая группа ошибок связана с контекстом: попытка вызвать серверную функцию из клиентского модуля без флага «Вызов сервера», обращение к реквизитам формы из метода &НаСервереБезКонтекста, использование модального кода там, где он запрещён. Большинство таких проблем выявляет проверка конфигурации с включёнными режимами проверки тонкого и веб-клиента — запускайте её после каждой доработки.

Третья типичная проблема — «божественные» функции на несколько сотен строк, которые делают всё сразу. Такой код невозможно тестировать и страшно менять. Признак, что пора разделять: внутри функции появляются комментарии-разделители вроде «// теперь считаем скидку». Каждый такой блок — кандидат на отдельный метод.

Типичные ошибки
01
Пропущен оператор Возврат в одной из веток функции — в этом сценарии возвращается Неопределено и ломается вызывающий код
02
Изменение параметра-объекта внутри функции без необходимости — неожиданные побочные эффекты в месте вызова
03
Размещение серверной логики в клиентском модуле — ошибки компиляции или падение в рантайме
04
Десять и более параметров у метода — нечитаемые вызовы и постоянные правки всех мест использования
05
Дублирование одного расчёта в нескольких модулях вместо общей экспортной функции — при изменении правил часть мест забывают поправить

Как проверить, что код написан правильно

После создания или изменения процедур и функций выполните проверку конфигурации (Конфигурация → Проверка конфигурации) с отмеченными режимами «Тонкий клиент» и «Веб-клиент». Она выявит несуществующие методы, неправильный контекст вызова и обращения к несуществующим свойствам.

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

Контрольные точки

Как проверить результат

Проверка конфигурации
Норма

Нет ошибок по изменённым модулям во всех режимах проверки

Тревожный признак

Ошибки вида «Процедура или функция не обнаружена» или «недоступно на клиенте»

Возвращаемое значение функции
Норма

При всех входных данных возвращается значение ожидаемого типа

Тревожный признак

В отдельных сценариях возвращается Неопределено

Вызовы из других модулей
Норма

Все места вызова работают, результат корректен

Тревожный признак

Часть сценариев использует старую логику или падает с ошибкой

Производительность формы
Норма

Один пользовательский жест — один серверный вызов

Тревожный признак

Форма «подвисает» из-за цепочки серверных вызовов в цикле

Частые вопросы

Может ли процедура вернуть значение через оператор Возврат?

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

Что делает ключевое слово Знач перед параметром?

Знач означает передачу параметра по значению: внутри метода создаётся копия, и изменения параметра не влияют на переменную вызывающего кода. Без Знач параметры примитивных типов всё равно ведут себя похоже, а вот объекты (структуры, таблицы, ссылки) передаются по ссылке, и их изменение внутри метода видно снаружи. Явное Знач документирует намерение и защищает от случайных побочных эффектов.

Сколько параметров допустимо у функции?

Жёсткого ограничения платформа не накладывает, но на практике больше четырёх-пяти параметров делают вызовы нечитаемыми. Когда данных много, группируйте их в структуру: вызов вида РассчитатьСкидку(ПараметрыРасчёта) понятнее, чем перечисление десяти аргументов, и легче расширяется.

Чем отличается метод общего модуля от метода модуля объекта?

Метод модуля объекта работает в контексте конкретного объекта: ему доступны реквизиты и табличные части этого экземпляра без передачи параметров. Метод общего модуля самодостаточен — все данные он получает через параметры. Логику, привязанную к одному объекту (проведение, заполнение), держат в модуле объекта; переиспользуемые расчёты выносят в общие модули.

Нужно ли слово Экспорт для обработчиков событий?

Нет. Обработчики событий формы или объекта (ПриНажатии, ПередЗаписью и т.п.) вызываются платформой, а не вашим кодом, поэтому Экспорт им не требуется. Экспорт нужен только тем методам, которые вы планируете вызывать из других модулей.

Почему функция возвращает Неопределено, хотя Возврат написан?

Почти всегда причина в том, что Возврат стоит не на всех путях выполнения: например, внутри условия Если, а ветка Иначе отсутствует. При определённых входных данных выполнение доходит до КонецФункции, не встретив Возврат, и результатом становится Неопределено. Проверьте, что каждая ветка логики завершается возвратом значения.

Итог

Что важно запомнить

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