Как правильно вызвать процедуру серверного общего модуля из клиент-серверного общего модуля в 1С?

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

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

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


Выясняем причину: как платформа 1С компилирует контексты

Для того чтобы понять природу ошибки, рассмотрим детально, что происходит под капотом платформы 1С:Предприятия в момент компиляции общего модуля ОМ1, для которого установлены флаги «Клиент (управляемое приложение)» и «Сервер».

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

  1. Клиентский экземпляр модуля — загружается в оперативную память клиентского приложения. Он предназначен для выполнения «легких» расчетов на стороне пользователя.
  2. Серверный экземпляр модуля — компилируется и выполняется непосредственно в рабочем процессе сервера приложений 1С.

При прохождении синтаксического контроля или при компиляции на стороне клиента препроцессор 1С анализирует весь текст модуля ОМ1 сверху вниз. Когда он натыкается на строчку вызова серверного модуля ОМ2 (у которого установлен только флаг «Сервер»), возникает конфликт:

С точки зрения клиентского приложения, общего модуля ОМ2 не существует в природе. На клиенте нет метаданных и исполняемого кода этого модуля. Так как у ОМ2 отсутствует свойство «Вызов сервера», клиентское приложение не может выполнить удаленный вызов процедуры. В результате компилятор выдает логичную ошибку: Переменная не определена (ИмяСерверногоМодуля).


Анализ нерекомендуемого решения: создание модуля-прослойки с «Вызовом сервера»

Часто разработчики решают эту проблему «в лоб»: создают новый общий модуль, устанавливают для него флаг «Вызов сервера» и переносят вызов туда. Рассмотрим, почему этот подход противоречит стандартам БСП (Библиотеки стандартных подсистем) и рекомендациям 1С:ИТС:


Правильное архитектурное решение: использование инструкций препроцессора

Поскольку исходный модуль ОМ1 является клиент-серверным, предполагается, что его функции могут выполняться в обоих контекстах. Но если логика внутри функции требует обращения к базе данных или специфическим серверным механизмам (как в случае с получением кадровых данных сотрудников), этот участок кода должен отрабатывать только тогда, когда сам модуль ОМ1 выполняется на сервере.

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

Рассмотрим пример реализации:


// Функция располагается в модуле УчетСреднегоЗарабокаКлиентСервер
Функция ПолучитьСведенияОСотруднике(Сотрудник, ДатаСведений) Экспорт
    
    Результат = Новый Структура("Подразделение, Должность");
    
    #Если Сервер Или ВнешнееСоединение Тогда
        // Этот блок кода будет скомпилирован исключительно в серверном контексте.
        // На клиенте этот фрагмент кода физически не будет существовать при выполнении.
        
        КадровыеДанные = КадровыйУчет.КадровыеДанныеСотрудников(Истина, Сотрудник, "Подразделение, Должность", ДатаСведений);
        Если КадровыеДанные.Количество() > 0 Тогда
            ЗаполнитьЗначенияСвойств(Результат, КадровыеДанные[0]);
        КонецЕсли;
    #Иначе
        // При необходимости здесь описывается альтернативное поведение на клиенте,
        // либо блок оставляется пустым, если на клиенте логика не требуется.
    #КонецЕсли
    
    Возврат Результат;
    
КонецФункции

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

  1. При проверке на клиенте препроцессор вырезает весь блок между #Если Сервер и #КонецЕсли. Ошибки «Переменная не определена» не возникает.
  2. При вызове функции на сервере код внутри условия отрабатывает штатно. Обращение к модулю КадровыйУчет происходит напрямую внутри оперативной памяти сервера приложений 1С.
  3. Отсутствуют сетевые задержки на сериализацию и передачу данных, нет ограничений на работу с мутабельными типами данных.

Архитектурные стандарты именования и разделения модулей в 1С

Чтобы в дальнейшем избегать подобных коллизий, давайте закрепим общие правила разделения ответственности между общими модулями, принятые в Библиотеке стандартных подсистем (БСП) и стандартах разработки фирмы «1С»:

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

← На главную