При разработке под обычные формы в системе «1С:Предприятие 8» программисты нередко сталкиваются с ситуацией, когда код ведет себя совершенно не так, как ожидается. Особенно много сюрпризов преподносит файловый режим работы базы данных. Классический пример — использование инструкций препроцессора для разделения клиентской и серверной логики в одном модуле.
В этой статье мы подробно разберем, почему конструкция #ИначеЕсли Клиент Тогда может игнорироваться платформой, выясним разницу между директивами компиляции и инструкциями препроцессора, а также рассмотрим стандарты разработки, которые помогут избежать подобных архитектурных ошибок.
Представим типовой сценарий. Разработчик создает внешнюю обработку под обычные формы (например, для конфигурации «Управление торговым предприятием», редакция 2) и пишет в модуле формы следующий обработчик нажатия кнопки:
Процедура Кнопка1Нажатие(Элемент)
#Если Сервер Тогда
А = 0;
#ИначеЕсли Клиент Тогда
Б = 0;
#КонецЕсли
КонецПроцедуры
Казалось бы, логика очевидна: при нажатии кнопки на форме мы находимся в клиентском контексте, поэтому должна сработать ветка Б = 0. Однако при тестировании в файловой базе платформа упорно выполняет ветку А = 0. При этом в клиент-серверном варианте (на SQL-сервере) тот же самый код отрабатывает абсолютно корректно и уходит в ветку клиента. Выясним, почему так происходит.
Прежде чем перейти к файловому режиму, важно устранить частую терминологическую путаницу. Разработчики часто называют конструкции с символом решетки # директивами компиляции, хотя на самом деле это инструкции препроцессора.
Давайте разберем их ключевые отличия:
& (например, &НаКлиенте, &НаСервере). Они указывают компилятору, в каком контексте должна быть скомпилирована и выполнена процедура или функция целиком. Применяются они в основном в управляемых формах и командах.# (например, #Если Сервер Тогда). Препроцессор обрабатывает модуль до момента его фактической компиляции. Он буквально «вырезает» из текста программы участки кода, условия для которых ложны, и передает компилятору только оставшийся «чистый» текст.В обычных формах (Толстый клиент) концепция директив компиляции & не применяется в модулях форм напрямую так же, как в управляемых формах. Вместо этого разработчики часто вынуждены использовать инструкции препроцессора # для разграничения кода.
Основная причина аномального поведения кода кроется в архитектуре файловой базы данных. В файловом варианте при запуске системы в режиме «Толстый клиент (обычное приложение)» клиентская и серверная части платформы физически выполняются в одном и том же процессе на компьютере пользователя.
Согласно официальной документации «1С:Предприятия», для обеспечения совместимости кода в файловом варианте предопределенные символы препроцессора Сервер, Клиент, ТолстыйКлиентОбычноеПриложение определены всегда. Это означает, что для препроцессора в файловой базе оба флага — и Сервер, и Клиент — одновременно принимают значение Истина.
Теперь проанализируем, как препроцессор обрабатывает наше условие:
#Если Сервер Тогда. Поскольку в файловой базе значение Сервер равно Истина, препроцессор принимает решение оставить строку А = 0; для компиляции.#Если ... #ИначеЕсли ... #КонецЕсли, и первое условие уже выполнилось (вернуло истину), препроцессор, следуя правилам логики ветвления, полностью отбрасывает и игнорирует все последующие ветки (включая #ИначеЕсли Клиент).А = 0;.Давайте посмотрим на пример кода, где условия препроцессора написаны независимо друг от друга:
#Если Сервер Тогда
А = 0;
#КонецЕсли
#Если Клиент Тогда
Б = 0;
#КонецЕсли
Если мы запустим этот код в файловой базе (в режиме толстого клиента), препроцессор обработает оба условия независимо. Так как оба флага равны Истина, в итоговый скомпилированный код попадут обе строчки. Программа выполнит и А = 0, и Б = 0.
В клиент-серверном же варианте компиляция происходит раздельно для клиентского приложения и сервера приложений. На клиенте скомпилируется только Б = 0, а на сервере — только А = 0.
Использование сложных инструкций препроцессора типа #Если Сервер внутри модулей форм или общих модулей с целью разделения контекста считается плохой практикой разработки. Это приводит к трудноуловимым ошибкам при миграции баз данных из файлового режима в клиент-серверный и обратно, а также крайне усложняет отладку.
Рассмотрим, как правильно решить эту задачу по рекомендациям стандартов ИТС:
РаботаСКлиентомКлиент — модуль с установленным флагом «Клиент» в свойствах.РаботаСКлиентомСервер — модуль с установленным флагом «Сервер» (и, при необходимости, «Вызов сервера»).
Процедура ВыполнитьДействиеНаСервере()
// Серверная логика
А = 0;
КонецПроцедуры
Процедура Кнопка1Нажатие(Элемент)
// Клиентская логика
Б = 0;
// При необходимости вызываем серверный метод
ВыполнитьДействиеНаСервере();
КонецПроцедуры
Придерживаясь этих простых архитектурных правил, вы защитите свои разработки от неожиданного поведения в файловых базах и сделаете код понятным, легко читаемым и соответствующим стандартам качества фирмы «1С».