При разработке в системе 1С:Предприятие 8.3 программисты часто сталкиваются со стандартной конструкцией, в которую оборачивается практически всё содержимое модулей объектов (документов, справочников и т.д.). Эта конструкция выглядит так: #Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда ... #КонецЕсли. На первый взгляд она кажется избыточной, особенно если учитывать, что модули объектов в управляемом приложении и так исполняются на сервере. Однако за этой строкой стоит глубокая логика разделения контекстов и обеспечения стабильности системы. Рассмотрим подробно, почему это необходимо.
Для начала проанализируем, за что отвечает каждая часть этого логического условия с точки зрения компилятора 1С:
Важный момент: обратите внимание, что в списке отсутствует ТолстыйКлиентУправляемоеПриложение. Именно в исключении этого режима и кроется основной смысл всей конструкции.
Проанализируем ситуацию: пользователь запускает систему в режиме Толстого клиента (управляемое приложение). В этом режиме клиентское приложение технически способно исполнять серверный код прямо у себя «на борту». Однако архитектурно серверный код (модуль объекта) часто к этому не готов. Например, внутри модуля может вызываться УстановитьПривилегированныйРежим(Истина). На реальном сервере это сработает, а в толстом клиенте (в управляемом режиме) — нет, или приведет к непредсказуемому поведению прав доступа.
Используя конструкцию #Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда, мы гарантируем, что код будет выполнен только в тех средах, которые платформа 1С считает «доверенными» для серверных операций. Это исключает выполнение тяжелых процедур на стороне клиента, даже если это Толстый клиент.
Выясним, как инструкции препроцессора влияют на производительность. Важно понимать, что инструкции препроцессора — это не обычное Если, которое проверяется во время работы программы. Это команды для компилятора.
Когда Тонкий клиент или Веб-клиент обращается к серверу за объектом (например, открывает форму документа), сервер должен скомпилировать модуль этого объекта. Если код внутри модуля не обернут в директивы препроцессора, то весь текст модуля (который может занимать сотни килобайт) будет передан на сторону клиента для проверки синтаксиса и компиляции клиентской части образа объекта.
Рассмотрим пример. Допустим, у нас есть огромный модуль со сложными расчетами:
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
Процедура РассчитатьСложныеНалоги(ДокументОбъект) Экспорт
// Здесь 5000 строк сложного кода с запросами
Запрос = Новый Запрос;
// ...
КонецПроцедуры
#КонецЕсли
Если мы уберем #Если ... Тогда, то при каждом открытии документа в Тонком клиенте через медленный интернет все эти 5000 строк текста будут передаваться по сети. С использованием препроцессора компилятор просто «выкинет» этот блок для Тонкого клиента, и объем передаваемых данных сократится до нуля.
Разберем еще одну важную причину — доступность типов данных. На сервере нам доступны такие объекты, как Запрос, ВыгрузкаНоменклатуры, специфические COM-объекты или методы работы с файловой системой сервера. В Тонком клиенте этих типов данных просто не существует в пространстве имен.
Если серверный код не обернут в директивы, Тонкий клиент попытается его скомпилировать, наткнется на слово Новый Запрос и выдаст ошибку: «Переменная не определена (Запрос)». Таким образом, препроцессор защищает клиентское приложение от попыток осознать код, который оно физически не может исполнить.
Проанализируем современные реалии платформы (версии 8.3.18 и выше). С появлением мобильного клиента и автономных серверов ситуация стала еще интереснее. Если ваш код исполняется на мобильном устройстве в автономном режиме (когда нет связи с основным сервером), флаг #Если Сервер внезапно станет Истина прямо на смартфоне.
В этом случае рассматриваемая нами конструкция может потребовать уточнения. Если код слишком тяжел для мобильного процессора, разработчики иногда добавляют дополнительные проверки:
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Если НЕ МобильныйКлиент Тогда
// Код, который точно не должен работать на мобилках
#КонецЕсли
#КонецЕсли
Посмотрим на ситуацию со стороны универсальности кода. Часто возникает вопрос: «Почему бы не написать просто #Если Сервер?». Ответ кроется в поддержке Внешнего соединения и Обычного приложения. Если вы оставите только Сервер, то при попытке подключиться к вашей базе через COM из другой программы (например, для обмена данными), код внутри модуля объекта просто «исчезнет», так как в режиме COM-соединения флаг Сервер может не установиться (в зависимости от версии и настроек), зато флаг ВнешнееСоединение будет активен.
Таким образом, данная связка из трех условий — это «золотой стандарт» 1С, обеспечивающий работу кода во всех полноценных серверных (или приравненных к ним) контекстах, одновременно отсекая «слабые» клиенты и специфический управляемый толстый клиент.
Подводя итог, использование инструкции #Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда в модулях объектов позволяет:
Мы рекомендуем всегда придерживаться этого правила при написании кода в модулях объектов, модулях менеджеров и модулях наборов записей, если только вы специально не создаете процедуру, предназначенную для вызова непосредственно из контекста Толстого клиента.