Разработка модулей в 1С 8.3: от типов до отладки
Содержание
Модуль в 1С нельзя «создать» отдельным файлом — он уже встроен в каждый объект конфигурации. Чтобы написать код, нужно открыть нужный модуль в Конфигураторе: двойной щелчок по объекту в дереве, затем вкладка или пункт Открыть модуль объекта. Отдельно добавляют только общие модули — в ветке Общие → Общие модули через правый клик Добавить.
Дальше всё решает выбор места: от типа модуля зависит, когда код загрузится в память и будет ли он виден другим частям конфигурации. Ошибка на этом шаге — самая частая причина сообщений вида Процедура не определена или Метод объекта не обнаружен, хотя код формально написан верно.
Ниже — как устроены модули 1С 8.3, где писать какой код, как управлять исполнением через директивы компиляции и как потом всё это отладить. Платформа — 8.3 с интерфейсом «Такси».
Какие бывают модули и за что каждый отвечает
Модули делятся на две группы: привязанные к конкретному объекту и общие, доступные всей конфигурации.
Модули объектов:
- 🧩 Модуль формы — обработчики событий элементов формы (
ПриНажатии,ПриИзменении) и команд. Открывается на самой форме, вкладкаМодуль. - 📦 Модуль объекта (документа, справочника) — бизнес-логика записи:
ПередЗаписью,ОбработкаПроведения,ПриКопировании. - 🗂️ Модуль менеджера — методы, относящиеся не к одной записи, а к объекту в целом: формирование печатных форм, выборки, заполнение по основанию.
- 📊 Модуль набора записей — для регистров, при записи движений.
- ⚙️ Модуль команды — код команды объекта.
Модули приложения и сеанса — глобальные, срабатывают при старте:
- Модуль управляемого приложения — запуск в режиме тонкого и веб-клиента.
- Модуль обычного приложения — для совместимого интерфейса.
- Модуль внешнего соединения — при подключении к базе через COM.
- Модуль сеанса — только для установки параметров сеанса, выполняется на сервере раньше всех остальных.
Общий модуль — главный инструмент разработчика. В него выносят переиспользуемый код: функции расчётов, обращения к данным, работу с внешними сервисами. Один раз написали — вызываете из любой формы и любого объекта.
Выбор прост: событие конкретного документа — в модуль объекта; поведение формы — в модуль формы; код, который нужен в двух и более местах, — в общий модуль.
Как открыть модуль и из чего он состоит
Структура любого модуля одинаковая и строго упорядоченная — разделы идут сверху вниз:
- Объявление переменных — директива
Перемна уровне модуля, до первой процедуры. - Процедуры и функции — основное тело.
- Основная программа — операторы вне процедур, выполняются при загрузке модуля в память.
Простейшая функция в общем модуле выглядит так:
Функция ПолучитьСтавкуНДС(Номенклатура) Экспорт
Возврат Номенклатура.СтавкаНДС;
КонецФункции
Процедура отличается от функции тем, что не возвращает значение. Обе могут принимать параметры, в том числе со значением по умолчанию: Функция Расчёт(Сумма, Коэффициент = 1).
Операторы, записанные вне процедур и функций, образуют основную программу модуля. Она выполняется один раз — в момент, когда модуль впервые загружается в память. Для модуля объекта это происходит при создании объекта, для общего модуля — при первом обращении к любой его функции. Держать в основной программе тяжёлые вычисления не стоит: они замедлят первое обращение и будут повторяться для каждого объекта. Инициализацию лучше вынести в отдельную процедуру и вызывать явно.
Параметры в 1С передаются по значению или по ссылке. По умолчанию простые типы (число, строка, дата) идут по значению — изменение внутри процедуры не влияет на исходную переменную. Объекты и коллекции (таблица значений, массив, структура) передаются по ссылке: процедура меняет тот же экземпляр. Чтобы защитить примитив от изменения, перед параметром ставят ключевое слово Знач: Процедура Обработать(Знач Сумма).
Чтобы код из модуля формы вызвал эту функцию, общий модуль должен иметь галочку нужного контекста (Сервер, Клиент) в палитре свойств, а сама функция — ключевое слово Экспорт. Без него функция видна только внутри своего модуля.
Перед правкой типовой конфигурации снимите её с поддержки аккуратно или используйте расширение конфигурации — иначе обновление затрёт ваш код. Расширения появились в платформе 8.3.6 и позволяют дописывать логику, не трогая оригинал.
Директивы компиляции: где физически работает код
Директива компиляции — строка со знаком & над процедурой. Она говорит платформе, на какой стороне (клиент или сервер) выполнять код. Это ядро архитектуры управляемого приложения 1С 8.3.
| Директива | Где выполняется | Для чего |
|---|---|---|
&НаКлиенте | на клиенте | интерфейс, диалоги, реакция на действия пользователя |
&НаСервере | на сервере, с контекстом формы | чтение и запись данных, когда нужны реквизиты формы |
&НаСервереБезКонтекста | на сервере, без данных формы | расчёты и запросы, которым форма не нужна |
&НаКлиентеНаСервереБезКонтекста | обе стороны | общая логика, доступная везде |
Правило: данные читаются и пишутся только на сервере. Клиент не имеет прямого доступа к базе. Поэтому обработчик кнопки обычно начинается на клиенте, а за данными уходит на сервер:
&НаКлиенте
Процедура ПересчитатьСумму(Команда)
ОбновитьИтогНаСервере();
КонецПроцедуры
&НаСервере
Процедура ОбновитьИтогНаСервере()
Объект.ИтогоСумма = Объект.Товары.Итог("Сумма");
КонецПроцедуры
Каждый вызов серверной процедуры из клиента — это обращение по сети. Чем их меньше за одно действие пользователя, тем быстрее работает форма. Собирайте несколько операций в один серверный вызов, а не делайте по вызову на каждую строку таблицы.
Директиву &НаСервереБезКонтекста выбирайте везде, где процедуре не нужны реквизиты формы: она не гоняет контекст формы на сервер и обратно, а значит экономит трафик.
Экспорт процедур и область видимости
Область видимости определяет, кто может вызвать вашу процедуру.
- Без
Экспорт— процедура локальная, доступна только внутри своего модуля. - С
Экспортв модуле объекта — доступна снаружи через ссылку на объект:Документ.РассчитатьСкидку(). - С
Экспортв общем модуле — доступна из любого места конфигурации по имени модуля:ОбщегоНазначения.ТекущаяДатаСеанса().
У общего модуля есть флаги, и они решают, откуда функция будет доступна. Ключевые из них:
- Клиент (управляемое приложение) и Сервер — на каких сторонах доступны методы.
- Вызов сервера — разрешает дёргать серверные функции прямо из клиента. Включайте с осторожностью: это точка входа, её видно снаружи.
- Привилегированный — код выполняется без проверки прав доступа. Нужен для служебных операций, но опасен: через него можно обойти ролевые ограничения, поэтому в привилегированном модуле держат только то, что действительно должно работать от имени системы.
- Повторное использование возвращаемых значений — кэширование, о нём ниже.
Не делайте общий модуль «и клиентским, и серверным» без нужды. Если функция только считает и ходит в базу — оставьте один флаг Сервер и директиву &НаСервереБезКонтекста. Это и быстрее, и безопаснее.
Переменные модуля, объявленные через Перем без Экспорт, живут только внутри модуля. С Экспорт в модуле объекта — становятся дополнительными свойствами объекта, доступными снаружи на время жизни объекта в памяти.
Оптимизация: запрос вместо цикла и кэширование
Главная причина медленных модулей — обращение к данным через точку внутри цикла. Каждое .Реквизит по ссылке — это отдельный поход в базу.
Медленный код (на каждой строке — скрытый запрос к номенклатуре):
Для Каждого Строка Из Товары Цикл
Если Строка.Номенклатура.Услуга Тогда
Сумма = Сумма + Строка.Сумма;
КонецЕсли;
КонецЦикла;
Быстрый вариант — получить все нужные данные одним запросом и сложить в соответствие:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ Ссылка, Услуга
|ИЗ Справочник.Номенклатура
|ГДЕ Ссылка В (&Список)";
Запрос.УстановитьПараметр("Список", Товары.ВыгрузитьКолонку("Номенклатура"));
Выборка = Запрос.Выполнить().Выбрать();
Несколько правил, которые заметно ускоряют код:
- 🚀 Данные из базы берите запросом, а не обходом ссылок в цикле.
- 🚀 Не ставьте запрос внутрь цикла — выносите наружу, используйте параметр со списком.
- 🚀 В запросе выбирайте только нужные поля, не
ВЫБРАТЬ *по смыслу (в языке запросов перечисляйте колонки). - 🚀 Для часто вызываемой функции с одинаковыми параметрами включите флаг Повторное использование возвращаемых значений — результат закэшируется на время вызова или сеанса.
При сборке строки с числом не склеивайте типы напрямую — используйте Формат(Число, "ЧГ=0") или СтрШаблон("Проведено %1 строк", Количество), иначе получите ошибку преобразования или лишние пробелы.
Когда в одном расчёте участвуют несколько таблиц, не делайте серию отдельных запросов — объедините их в пакетный запрос с временными таблицами (ПОМЕСТИТЬ ВременнаяТаблица). Платформа выполнит пакет за один обход, а менеджер временных таблиц сам уберёт их из памяти. Так считают сложные отчёты и сверки: сначала во временные таблицы собирают исходные данные, затем соединяют их финальным запросом.
Отдельная ловушка — обход результата запроса. Если вам нужно обработать строки по группам, выбирайте данные с итогами (ИТОГИ ... ПО) и обходите выборку по уровням группировки, а не фильтруйте одну и ту же выборку в несколько проходов. Один проход по упорядоченной выборке почти всегда быстрее, чем повторные выборки из той же таблицы.
Отладка и тестирование модуля
Отладка идёт в Конфигураторе. Чтобы она работала, в режиме запуска приложения должна быть включена отладка (Сервис → Параметры → Запуск 1С:Предприятия → Дополнительные → Отладка в текущем сеансе), а на сервере — разрешена отладка в свойствах информационной базы.
Базовый цикл отладки:
- Поставьте точку останова на нужной строке — клавиша
F9или клик на левом поле модуля. - Запустите приложение из Конфигуратора (
F5). На точке останова выполнение замрёт. - Двигайтесь по коду:
F11— шагнуть внутрь процедуры,F10— выполнить строку целиком,F5— продолжить до следующей точки. - Смотрите значения переменных в окне Табло или наведением курсора. Сложное выражение проверяйте через
Shift+F9(Вычислить выражение).
Для серверного кода точка останова сработает только при включённой отладке на сервере — иначе выполнение «проскочит» мимо.
Чтобы найти, где именно тормозит код, используйте замер производительности (Отладка → Замер производительности): платформа покажет, сколько раз вызвана каждая строка и сколько времени заняла. Это точнее, чем гадать.
Отлаживая чужой код или боевую базу, не меняйте данные «на пробу» прямым проведением документов — движения задвоятся. Для проверок разворачивайте копию базы.
Для повторяемых проверок есть автоматизированное тестирование: сценарные тесты через расширение тестирования или внешние обработки, которые прогоняют типовые операции. Простые проверки удобно оформлять отдельной командой, которая вызывает вашу функцию с заранее известными параметрами и сравнивает результат с ожидаемым.
Не забывайте про журнал регистрации (Администрирование → Журнал регистрации в режиме предприятия): туда можно писать свои сообщения через ЗаписьЖурналаРегистрации, чтобы видеть ход выполнения уже после того, как код ушёл в работу и отладчик недоступен.
Частые вопросы
Чем модуль объекта отличается от модуля менеджера?
Почему функция из общего модуля не вызывается — пишет «Процедура не определена»?
Экспорт; у общего модуля не стоит флаг нужного контекста (вызываете с клиента, а стоит только Сервер); или имя модуля в вызове написано с опечаткой. Проверьте все три.Нужно ли объявлять переменные перед использованием?
Перем в начале модуля и осмысленные имена делают код читаемым и помогают отладчику. Для переменных уровня модуля объявление обязательно.