Разработка модулей в 1С 8.3: от типов до отладки

· 9 мин

Содержание

Модуль в 1С нельзя «создать» отдельным файлом — он уже встроен в каждый объект конфигурации. Чтобы написать код, нужно открыть нужный модуль в Конфигураторе: двойной щелчок по объекту в дереве, затем вкладка или пункт Открыть модуль объекта. Отдельно добавляют только общие модули — в ветке Общие → Общие модули через правый клик Добавить.

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

Ниже — как устроены модули 1С 8.3, где писать какой код, как управлять исполнением через директивы компиляции и как потом всё это отладить. Платформа — 8.3 с интерфейсом «Такси».

Какие бывают модули и за что каждый отвечает

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

Модули объектов:

  • 🧩 Модуль формы — обработчики событий элементов формы (ПриНажатии, ПриИзменении) и команд. Открывается на самой форме, вкладка Модуль.
  • 📦 Модуль объекта (документа, справочника) — бизнес-логика записи: ПередЗаписью, ОбработкаПроведения, ПриКопировании.
  • 🗂️ Модуль менеджера — методы, относящиеся не к одной записи, а к объекту в целом: формирование печатных форм, выборки, заполнение по основанию.
  • 📊 Модуль набора записей — для регистров, при записи движений.
  • ⚙️ Модуль команды — код команды объекта.

Модули приложения и сеанса — глобальные, срабатывают при старте:

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

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

Выбор прост: событие конкретного документа — в модуль объекта; поведение формы — в модуль формы; код, который нужен в двух и более местах, — в общий модуль.

Как открыть модуль и из чего он состоит

Структура любого модуля одинаковая и строго упорядоченная — разделы идут сверху вниз:

  1. Объявление переменных — директива Перем на уровне модуля, до первой процедуры.
  2. Процедуры и функции — основное тело.
  3. Основная программа — операторы вне процедур, выполняются при загрузке модуля в память.

Простейшая функция в общем модуле выглядит так:

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

    Возврат Номенклатура.СтавкаНДС;

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

Процедура отличается от функции тем, что не возвращает значение. Обе могут принимать параметры, в том числе со значением по умолчанию: Функция Расчёт(Сумма, Коэффициент = 1).

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

Параметры в 1С передаются по значению или по ссылке. По умолчанию простые типы (число, строка, дата) идут по значению — изменение внутри процедуры не влияет на исходную переменную. Объекты и коллекции (таблица значений, массив, структура) передаются по ссылке: процедура меняет тот же экземпляр. Чтобы защитить примитив от изменения, перед параметром ставят ключевое слово Знач: Процедура Обработать(Знач Сумма).

Чтобы код из модуля формы вызвал эту функцию, общий модуль должен иметь галочку нужного контекста (Сервер, Клиент) в палитре свойств, а сама функция — ключевое слово Экспорт. Без него функция видна только внутри своего модуля.

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

Директивы компиляции: где физически работает код

Директива компиляции — строка со знаком & над процедурой. Она говорит платформе, на какой стороне (клиент или сервер) выполнять код. Это ядро архитектуры управляемого приложения 1С 8.3.

ДирективаГде выполняетсяДля чего
&НаКлиентена клиентеинтерфейс, диалоги, реакция на действия пользователя
&НаСерверена сервере, с контекстом формычтение и запись данных, когда нужны реквизиты формы
&НаСервереБезКонтекстана сервере, без данных формырасчёты и запросы, которым форма не нужна
&НаКлиентеНаСервереБезКонтекстаобе стороныобщая логика, доступная везде

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

&НаКлиенте
Процедура ПересчитатьСумму(Команда)
    ОбновитьИтогНаСервере();
КонецПроцедуры

&НаСервере
Процедура ОбновитьИтогНаСервере()
    Объект.ИтогоСумма = Объект.Товары.Итог("Сумма");
КонецПроцедуры

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

Директиву &НаСервереБезКонтекста выбирайте везде, где процедуре не нужны реквизиты формы: она не гоняет контекст формы на сервер и обратно, а значит экономит трафик.

Проверьте себя
Где выполнится код с директивой `&НаСервереБезКонтекста`?
Какое ключевое слово делает функцию общего модуля видимой извне?
Можно ли из `&НаКлиенте` напрямую выполнить запрос к базе?

Экспорт процедур и область видимости

Область видимости определяет, кто может вызвать вашу процедуру.

  • Без Экспорт — процедура локальная, доступна только внутри своего модуля.
  • С Экспорт в модуле объекта — доступна снаружи через ссылку на объект: Документ.РассчитатьСкидку().
  • С Экспорт в общем модуле — доступна из любого места конфигурации по имени модуля: ОбщегоНазначения.ТекущаяДатаСеанса().

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

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

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

Переменные модуля, объявленные через Перем без Экспорт, живут только внутри модуля. С Экспорт в модуле объекта — становятся дополнительными свойствами объекта, доступными снаружи на время жизни объекта в памяти.

Оптимизация: запрос вместо цикла и кэширование

Главная причина медленных модулей — обращение к данным через точку внутри цикла. Каждое .Реквизит по ссылке — это отдельный поход в базу.

Медленный код (на каждой строке — скрытый запрос к номенклатуре):

Для Каждого Строка Из Товары Цикл
    Если Строка.Номенклатура.Услуга Тогда
        Сумма = Сумма + Строка.Сумма;
    КонецЕсли;
КонецЦикла;

Быстрый вариант — получить все нужные данные одним запросом и сложить в соответствие:

Запрос = Новый Запрос;
Запрос.Текст =
    "ВЫБРАТЬ Ссылка, Услуга
    |ИЗ Справочник.Номенклатура
    |ГДЕ Ссылка В (&Список)";
Запрос.УстановитьПараметр("Список", Товары.ВыгрузитьКолонку("Номенклатура"));
Выборка = Запрос.Выполнить().Выбрать();

Несколько правил, которые заметно ускоряют код:

  • 🚀 Данные из базы берите запросом, а не обходом ссылок в цикле.
  • 🚀 Не ставьте запрос внутрь цикла — выносите наружу, используйте параметр со списком.
  • 🚀 В запросе выбирайте только нужные поля, не ВЫБРАТЬ * по смыслу (в языке запросов перечисляйте колонки).
  • 🚀 Для часто вызываемой функции с одинаковыми параметрами включите флаг Повторное использование возвращаемых значений — результат закэшируется на время вызова или сеанса.

При сборке строки с числом не склеивайте типы напрямую — используйте Формат(Число, "ЧГ=0") или СтрШаблон("Проведено %1 строк", Количество), иначе получите ошибку преобразования или лишние пробелы.

Когда в одном расчёте участвуют несколько таблиц, не делайте серию отдельных запросов — объедините их в пакетный запрос с временными таблицами (ПОМЕСТИТЬ ВременнаяТаблица). Платформа выполнит пакет за один обход, а менеджер временных таблиц сам уберёт их из памяти. Так считают сложные отчёты и сверки: сначала во временные таблицы собирают исходные данные, затем соединяют их финальным запросом.

Отдельная ловушка — обход результата запроса. Если вам нужно обработать строки по группам, выбирайте данные с итогами (ИТОГИ ... ПО) и обходите выборку по уровням группировки, а не фильтруйте одну и ту же выборку в несколько проходов. Один проход по упорядоченной выборке почти всегда быстрее, чем повторные выборки из той же таблицы.

Перед вводом кода в работу
Выполнено: 0 / 5

Отладка и тестирование модуля

Отладка идёт в Конфигураторе. Чтобы она работала, в режиме запуска приложения должна быть включена отладка (Сервис → Параметры → Запуск 1С:Предприятия → Дополнительные → Отладка в текущем сеансе), а на сервере — разрешена отладка в свойствах информационной базы.

Базовый цикл отладки:

  1. Поставьте точку останова на нужной строке — клавиша F9 или клик на левом поле модуля.
  2. Запустите приложение из Конфигуратора (F5). На точке останова выполнение замрёт.
  3. Двигайтесь по коду: F11 — шагнуть внутрь процедуры, F10 — выполнить строку целиком, F5 — продолжить до следующей точки.
  4. Смотрите значения переменных в окне Табло или наведением курсора. Сложное выражение проверяйте через Shift+F9 (Вычислить выражение).

Для серверного кода точка останова сработает только при включённой отладке на сервере — иначе выполнение «проскочит» мимо.

Чтобы найти, где именно тормозит код, используйте замер производительности (Отладка → Замер производительности): платформа покажет, сколько раз вызвана каждая строка и сколько времени заняла. Это точнее, чем гадать.

Отлаживая чужой код или боевую базу, не меняйте данные «на пробу» прямым проведением документов — движения задвоятся. Для проверок разворачивайте копию базы.

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

Не забывайте про журнал регистрации (Администрирование → Журнал регистрации в режиме предприятия): туда можно писать свои сообщения через ЗаписьЖурналаРегистрации, чтобы видеть ход выполнения уже после того, как код ушёл в работу и отладчик недоступен.

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

Чем модуль объекта отличается от модуля менеджера?
Модуль объекта работает с конкретной записью — одним документом или элементом справочника, которые уже загружены в память. Модуль менеджера относится к объекту в целом: там удобно держать методы формирования печатных форм, заполнения по основанию, выборки без привязки к конкретной записи.
Почему функция из общего модуля не вызывается — пишет «Процедура не определена»?
Три частые причины: у функции нет ключевого слова Экспорт; у общего модуля не стоит флаг нужного контекста (вызываете с клиента, а стоит только Сервер); или имя модуля в вызове написано с опечаткой. Проверьте все три.
Нужно ли объявлять переменные перед использованием?
В 1С строгого требования нет — переменная создаётся при первом присваивании. Но объявление через Перем в начале модуля и осмысленные имена делают код читаемым и помогают отладчику. Для переменных уровня модуля объявление обязательно.
Когда включать флаг «Повторное использование возвращаемых значений»?
Для функций, которые при одинаковых параметрах всегда возвращают одно и то же и вызываются часто: получение настройки, курса, признака по ссылке. Для функций, результат которых зависит от меняющихся данных, кэширование включать нельзя — получите устаревшее значение.
Можно ли дописать модуль типовой конфигурации, не ломая обновления?
Да. Самый безопасный путь — расширение конфигурации (доступно с платформы 8.3.6): ваш код хранится отдельно, оригинал не трогается, обновление типовой проходит штатно. Прямая правка снятой с поддержки конфигурации тоже возможна, но тогда каждое обновление придётся сверять вручную.