Стандарты разработки 1С по этой теме сводятся к четырём правилам: бизнес-логика живёт в модулях объектов и общих модулях, а не в формах; формы открываются только через ОткрытьФорму с параметрами и описанием оповещения; тексты запросов оформляются единообразно — заглавные ключевые слова, явные псевдонимы через КАК, без вложенных запросов; повторяющийся код выносится в общие модули и библиотеки, прежде всего в БСП.
Ниже — шпаргалка с примерами «как не надо» и «как надо». Это не пересказ всех требований, а те пункты, которые я чаще всего встречаю нарушенными при приёмке чужих доработок и которые потом дороже всего обходятся при сопровождении.
Бизнес-логика вне формы
Самая частая проблема в доработках — весь код в модуле формы. Пока с документом работают только руками, всё выглядит нормально. Затем появляется обмен, загрузка из Excel, обработка группового заполнения — и выясняется, что при программной записи служебные реквизиты не заполняются, итоги не пересчитываются, проверки не срабатывают.
Правило простое: форма отвечает за взаимодействие с пользователем, всё остальное — в модуле объекта, модуле менеджера или общем модуле.
| Что делает код | Где ему место |
|---|---|
| Видимость, доступность, оформление элементов | Модуль формы |
| Вопросы пользователю, открытие других форм | Модуль формы (клиент) |
| Заполнение реквизитов по правилам предметной области | Модуль объекта |
| Проверки при записи и проведении | Модуль объекта |
| Получение данных, используемых в нескольких местах | Модуль менеджера или общий модуль |

Единое поведение формы и программного интерфейса
Если при выборе договора в форме заполняются валюта и срок оплаты, то же самое должно происходить и при программной записи документа. Для этого метод заполнения размещаем в модуле объекта и вызываем его и из формы, и из ПередЗаписью:
// Модуль объекта документа
#Область ПрограммныйИнтерфейс
// Заполняет валюту и срок оплаты по выбранному договору.
Процедура ЗаполнитьПоДоговору() Экспорт
Если Не ЗначениеЗаполнено(Договор) Тогда
Возврат;
КонецЕсли;
РеквизитыДоговора = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Договор,
"ВалютаВзаиморасчетов, СрокОплаты");
Валюта = РеквизитыДоговора.ВалютаВзаиморасчетов;
СрокОплаты = РеквизитыДоговора.СрокОплаты;
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиСобытий
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// При программной записи заполняем то же, что и в форме.
Если Не ЗначениеЗаполнено(Валюта) Тогда
ЗаполнитьПоДоговору();
КонецЕсли;
КонецПроцедуры
#КонецОбластиВ форме остаётся только вызов:
&НаКлиенте
Процедура ДоговорПриИзменении(Элемент)
ДоговорПриИзмененииНаСервере();
КонецПроцедуры
&НаСервере
Процедура ДоговорПриИзмененииНаСервере()
ДокументОбъект = РеквизитФормыВЗначение("Объект");
ДокументОбъект.ЗаполнитьПоДоговору();
ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");
КонецПроцедурыИмена реквизитов здесь условные — важен принцип. Хороший образец такого подхода — справочник «Пользователи» в БСП: поля формы, которых нет среди реквизитов справочника, передаются через ДополнительныеСвойства объекта, и вся логика их обработки сосредоточена в модуле объекта. Неважно, записывается пользователь из формы или кодом — поведение одинаковое.
Открытие форм по стандарту
Только ОткрытьФорму
Форму открывают методом глобального контекста ОткрытьФорму. Связка «ПолучитьФорму, затем обращение к реквизитам, затем открытие» не рекомендуется: она привязывает вызывающий код к внутреннему устройству формы и добавляет лишние серверные вызовы. ОткрытьФорму гарантирует, что вся инициализация пройдёт в ПриСозданииНаСервере.
Параметры вместо обращения к элементам
Всё, что нужно форме при открытии, описывается в её параметрах. Набор параметров — это декларация того, как форму можно настроить снаружи.
Не так:
ФормаМастера = ПолучитьФорму("ОбщаяФорма.МастерНастройки");
ФормаМастера.Открыть();
ФормаМастера.Элементы.Страницы.ТекущаяСтраница = ФормаМастера.Элементы.СтраницаПриветствие;А так:
ПараметрыФормы = Новый Структура("НачальнаяСтраница", "Приветствие");
ОткрытьФорму("ОбщаяФорма.МастерНастройки", ПараметрыФормы);Внутри формы параметр читается в ПриСозданииНаСервере через Параметры.НачальнаяСтраница, и там же выбирается страница.
Результат через описание оповещения
Чтобы получить результат работы формы, передаём описание оповещения о закрытии. Модальные окна в современных конфигурациях не используются, поэтому это единственный правильный путь:
&НаКлиенте
Процедура ПоказатьНапоминание(Команда)
Оповещение = Новый ОписаниеОповещения("ПоказатьНапоминаниеЗавершение", ЭтотОбъект);
ОткрытьФорму("ОбщаяФорма.Напоминание", , , , , , Оповещение,
РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);
КонецПроцедуры
&НаКлиенте
Процедура ПоказатьНапоминаниеЗавершение(БольшеНеПоказывать, ДополнительныеПараметры) Экспорт
// Неопределено — пользователь закрыл форму крестиком.
Если БольшеНеПоказывать = Неопределено Тогда
Возврат;
КонецЕсли;
Если БольшеНеПоказывать Тогда
ОтключитьНапоминаниеНаСервере();
КонецЕсли;
КонецПроцедурыВ самой форме результат возвращается вызовом Закрыть(Результат).
Прочие ограничения
- В
ПриОткрытиине открывайте другие формы — порядок окон может нарушиться. Используйте короткий обработчик ожидания или откройте форму по команде пользователя. - Не открывайте и не закрывайте форму в одном обработчике: разнесите действия по времени.
- Формы, предназначенные только для внешних пользователей, явно блокируйте для обычных сеансов:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Не Пользователи.ЭтоСеансВнешнегоПользователя() Тогда
Отказ = Истина;
Возврат;
КонецЕсли;
КонецПроцедуры- Основные формы списков, обработок и отчётов должны открываться из меню «Все функции», даже если объект не выведен в командный интерфейс.
Оформление текстов запросов
Текст запроса длиннее нескольких строк выносится в отдельную функцию: так метод выполнения остаётся коротким, а текст удобно анализировать отдельно. Сами тексты оформляются по правилам:
- Ключевые слова — заглавными буквами.
- Каждому полю выборки — явный псевдоним, всегда через
КАК. - Даже короткий запрос — не в одну строку.
- В сложных запросах с соединениями и объединениями — комментарии. Учтите, что конструктор запросов удаляет комментарии без предупреждения.
- При программной сборке текста — комментарий к каждому этапу, и каждая часть должна открываться конструктором.
Явный псевдоним защищает от неожиданностей. Поле Касса.Валюта.Наименование без псевдонима получит имя ВалютаНаименование, а не Наименование, и код, читающий выборку, сломается при первом же переименовании.
Осмысленные псевдонимы источников
Псевдоним таблицы образуется от термина предметной области и объясняет роль таблицы в этом запросе. Нельзя: однобуквенные имена, имена с подчёркивания, Таблица1, Справочник.
ВЫБРАТЬ
ВсяНоменклатура.Ссылка КАК Товар,
ЕСТЬNULL(ОстаткиНаСкладах.КоличествоОстаток, 0) КАК Остаток
ИЗ
Справочник.Номенклатура КАК ВсяНоменклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ОстаткиНаСкладах
ПО ВсяНоменклатура.Ссылка = ОстаткиНаСкладах.НоменклатураИсключение — универсальные механизмы, где имя таблицы подставляется во время выполнения: там допустим нейтральный псевдоним вроде Таблица.
Без вложенных запросов
Вложенные запросы стандарт не рекомендует: временные таблицы читаются легче, их результат проще проверить в отладке, а соединение с вложенным запросом нередко выполняется медленно из-за неудачного плана СУБД. Пакет с ПОМЕСТИТЬ почти всегда лучше.
Программная модификация текста запроса
Когда часть запроса зависит от условий, текст меняют так, чтобы исходный вариант оставался валидным и открывался конструктором.
Подстановка поля или таблицы. Вместо склейки строк — параметр-заглушка и СтрЗаменить:
ТекстЗапроса =
"ВЫБРАТЬ
| Номенклатура.Наименование КАК Наименование,
| &ПолеАртикула КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";
// Поле артикула зависит от настройки учёта.
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолеАртикула", "Номенклатура." + ИмяПоляАртикула);В исходном виде &ПолеАртикула — обычный параметр, и конструктор открывает такой запрос без ошибок.
Временная таблица по условию. Не раскомментируйте ПОМЕСТИТЬ заменой. Пишите полный текст и удаляйте лишнее:
ТекстЗапроса =
"ВЫБРАТЬ
| Контрагенты.Ссылка КАК Ссылка
|ПОМЕСТИТЬ ВТКонтрагенты
|ИЗ
| Справочник.Контрагенты КАК Контрагенты";
Если Не ПомещатьВоВременнуюТаблицу Тогда
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПОМЕСТИТЬ ВТКонтрагенты", "");
КонецЕсли;Сборка пакета. Удобнее всего собирать тексты в массив и соединять через разделитель — так не нужно следить, где поставить точку с запятой:
РазделительПакета =
"
|;
|////////////////////////////////////////////////////////////////////////////////
|";
ТекстыПакета = Новый Массив;
Если ИспользоватьУпаковки Тогда
ТекстыПакета.Добавить(ТекстЗапросаУпаковки());
КонецЕсли;
ТекстыПакета.Добавить(ТекстЗапросаНоменклатура());
ТекстЗапроса = СтрСоединить(ТекстыПакета, РазделительПакета);Не дублируйте код: общие модули и БСП
Принцип DRY в 1С нарушают постоянно: копируют функцию в соседнюю форму, слегка правят — и через год никто не знает, какая из пяти копий правильная. Исправление ошибки превращается в поиск всех мест, а пропущенная копия становится новой ошибкой.
Повторяющийся код выносится в общий модуль с правильными флагами компиляции. А прежде чем писать собственный механизм, стоит проверить, нет ли его в библиотеках:
- БСП — пользователи, права, печать, дополнительные реквизиты, файлы, обмены, длительные операции и многое другое;
- библиотека подключаемого оборудования;
- библиотеки конкретных типовых конфигураций и собственные библиотеки команды.
Версию БСП, встроенную в конфигурацию, можно посмотреть в регистре сведений «Версии подсистем» по подсистеме СтандартныеПодсистемы, а документацию к нужной версии — на ИТС. При подключении подсистем внимательно читайте раздел документации о настройке и использовании подсистем при разработке.
Код, написанный по стандарту, дешевле в сопровождении: его быстрее читает следующий разработчик, он проходит автоматическую проверку и меньше ломается при обновлениях.
Проверить соответствие стандартам можно автоматически, а если нужна независимая оценка качества доработок — в рамках аудита 1С. Новые доработки 1С и разработку конфигураций я веду по этим правилам с самого начала.
Коротко
- Бизнес-логика — в модуле объекта, менеджера или общем модуле; форма только вызывает её.
- Формы открываются через
ОткрытьФормус параметрами, результат возвращается через описание оповещения иЗакрыть(Результат). - В запросах: заглавные ключевые слова, явные псевдонимы через
КАК, осмысленные имена источников, временные таблицы вместо вложенных запросов. - Текст запроса меняют заменой параметров-заглушек и сборкой пакета из массива, а не склейкой строк и раскомментированием.
- Дублирующийся код выносите в общие модули и сначала ищите готовое в БСП.




