Где лучше размещать серверные методы во внешней обработке: в модуле формы или в модуле объекта?

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

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

Различие контекстов исполнения: модуль формы и модуль объекта

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

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

Когда стоит использовать модуль объекта

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

  1. Программный вызов извне. Если ваш функционал должен вызываться не только интерактивно пользователем, но и другими частями системы (например, регламентными заданиями или другими обработками), модуль формы вам не поможет. Фоновое задание не «открывает» форму. Оно создает объект обработки методом ВнешниеОбработки.Создать(). В этом случае доступны только экспортные методы модуля объекта.
  2. Поддержка длительных операций. Согласно стандартам БСП (Библиотеки стандартных подсистем), тяжелые расчеты должны выполняться в фоновом задании, чтобы не блокировать интерфейс пользователя. Механизм длительных заданий требует передачи имени серверного метода. Как правило, это метод общего модуля или модуля объекта. Вызвать метод формы в фоновом задании невозможно.
  3. Чистота архитектуры. Разделение ответственности — важный принцип. Модуль формы должен отвечать за «интерактив»: проверку заполнения на клиенте, управление видимостью кнопок и реакцию на действия пользователя. Вся бизнес-логика (расчеты, запись в базу, запросы) должна быть инкапсулирована в модуле объекта.

Проблема производительности: РеквизитФормыВЗначение

Многие разработчики, пытаясь совместить удобство модуля формы и мощь модуля объекта, используют метод РеквизитФормыВЗначение("Объект"). Проанализируем ситуацию, описанную в дискуссии: использование этого метода может быть крайне «дорогим» удовольствием.

Выясним причину: при вызове РеквизитФормыВЗначение платформа создает полную копию данных в памяти сервера в виде прикладного объекта. Если вы вызываете этот метод внутри цикла (например, при обработке строк таблицы), производительность упадет в геометрической прогрессии.

Посмотрим на пример неправильного кода:


&НаСервере
Процедура ОбработатьДанныеНаСервере()
    // ТАК ДЕЛАТЬ НЕЛЬЗЯ В ЦИКЛЕ
    Для Каждого Строка Из Объект.Товары Цикл
        ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
        ОбработкаОбъект.РассчитатьЦену(Строка);
        ЗначениеВРеквизитФормы(ОбработкаОбъект, "Объект");
    КонецЦикла;
КонецПроцедуры

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

Инструкции препроцессора и совместимость

Автор темы затронул важный вопрос: нужно ли страховаться в модуле объекта инструкциями #Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда?

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

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

Хитрый прием: вызов экспортных методов формы

Иногда возникают ситуации, когда логика все же «застряла» в модуле формы, и ее нужно вызвать из другого серверного контекста. Рассмотрим пример из типовых решений, где форма передается как параметр. Это позволяет использовать экспортные методы формы даже в &НаСервереБезКонтекста.

Проанализируем пример кода, предложенный участниками обсуждения:


&НаКлиенте
Процедура ВыполнитьДействие(Команда)
    // Передаем форму как параметр в серверную процедуру
    ВыполнитьНаСервереБезКонтекста(ЭтаФорма);
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ВыполнитьНаСервереБезКонтекста(ФормаПараметр)
    // Мы можем вызвать экспортный серверный метод этой формы
    ФормаПараметр.МойЭкспортныйМетодНаСервере();
КонецПроцедуры

&НаСервере
Процедура МойЭкспортныйМетодНаСервере() Экспорт
    Сообщить("Метод формы успешно выполнен на сервере!");
КонецПроцедуры

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

Рекомендации по размещению кода (Best Practices)

Подведем итог и сформулируем правила «хорошего тона» при разработке внешних обработок:

  1. Модуль объекта: используйте для всей бизнес-логики. Помещайте сюда запросы, алгоритмы заполнения, механизмы интеграции. Обязательно делайте методы Экспортными. Если логика использует серверные модули — используйте #Если Сервер Тогда.
  2. Модуль формы: оставляйте здесь только код, обслуживающий интерфейс. Директивы &НаСервере в форме используйте для предварительного заполнения данных при открытии (ПриСозданииНаСервере) или для быстрых внеконтекстных вызовов &НаСервереБезКонтекста, когда нужно получить справочную информацию из базы.
  3. Обмен данными: если вам нужно обработать данные объекта в модуле объекта, не злоупотребляйте РеквизитФормыВЗначение. Попробуйте передать нужную таблицу или структуру данных в экспортный метод модуля объекта как параметр.
  4. Фоновые задания: если ваша обработка предполагает работу с большими объемами данных, сразу проектируйте запуск серверного метода из модуля объекта через механизм фоновых заданий БСП. Это избавит пользователей от зависания программы с надписью «Приложение не отвечает».

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

← На главную