Стандарты разработки 1С по этой теме сводятся к четырём правилам: бизнес-логика живёт в модулях объектов и общих модулях, а не в формах; формы открываются только через ОткрытьФорму с параметрами и описанием оповещения; тексты запросов оформляются единообразно — заглавные ключевые слова, явные псевдонимы через КАК, без вложенных запросов; повторяющийся код выносится в общие модули и библиотеки, прежде всего в БСП.

Ниже — шпаргалка с примерами «как не надо» и «как надо». Это не пересказ всех требований, а те пункты, которые я чаще всего встречаю нарушенными при приёмке чужих доработок и которые потом дороже всего обходятся при сопровождении.

Бизнес-логика вне формы

Самая частая проблема в доработках — весь код в модуле формы. Пока с документом работают только руками, всё выглядит нормально. Затем появляется обмен, загрузка из Excel, обработка группового заполнения — и выясняется, что при программной записи служебные реквизиты не заполняются, итоги не пересчитываются, проверки не срабатывают.

Правило простое: форма отвечает за взаимодействие с пользователем, всё остальное — в модуле объекта, модуле менеджера или общем модуле.

Что делает кодГде ему место
Видимость, доступность, оформление элементовМодуль формы
Вопросы пользователю, открытие других формМодуль формы (клиент)
Заполнение реквизитов по правилам предметной областиМодуль объекта
Проверки при записи и проведенииМодуль объекта
Получение данных, используемых в нескольких местахМодуль менеджера или общий модуль
Бизнес-логика в ядре объекта: форма, обмен и обработка вызывают одну и ту же логику
Бизнес-логика в ядре объекта: форма, обмен и обработка вызывают одну и ту же логику

Единое поведение формы и программного интерфейса

Если при выборе договора в форме заполняются валюта и срок оплаты, то же самое должно происходить и при программной записи документа. Для этого метод заполнения размещаем в модуле объекта и вызываем его и из формы, и из ПередЗаписью:

1С
// Модуль объекта документа

#Область ПрограммныйИнтерфейс

// Заполняет валюту и срок оплаты по выбранному договору.
Процедура ЗаполнитьПоДоговору() Экспорт

	Если Не ЗначениеЗаполнено(Договор) Тогда
		Возврат;
	КонецЕсли;

	РеквизитыДоговора = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Договор,
		"ВалютаВзаиморасчетов, СрокОплаты");
	Валюта = РеквизитыДоговора.ВалютаВзаиморасчетов;
	СрокОплаты = РеквизитыДоговора.СрокОплаты;

КонецПроцедуры

#КонецОбласти

#Область ОбработчикиСобытий

Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)

	Если ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;

	// При программной записи заполняем то же, что и в форме.
	Если Не ЗначениеЗаполнено(Валюта) Тогда
		ЗаполнитьПоДоговору();
	КонецЕсли;

КонецПроцедуры

#КонецОбласти

В форме остаётся только вызов:

1С
&НаКлиенте
Процедура ДоговорПриИзменении(Элемент)
	ДоговорПриИзмененииНаСервере();
КонецПроцедуры

&НаСервере
Процедура ДоговорПриИзмененииНаСервере()

	ДокументОбъект = РеквизитФормыВЗначение("Объект");
	ДокументОбъект.ЗаполнитьПоДоговору();
	ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");

КонецПроцедуры

Имена реквизитов здесь условные — важен принцип. Хороший образец такого подхода — справочник «Пользователи» в БСП: поля формы, которых нет среди реквизитов справочника, передаются через ДополнительныеСвойства объекта, и вся логика их обработки сосредоточена в модуле объекта. Неважно, записывается пользователь из формы или кодом — поведение одинаковое.

Открытие форм по стандарту

Только ОткрытьФорму

Форму открывают методом глобального контекста ОткрытьФорму. Связка «ПолучитьФорму, затем обращение к реквизитам, затем открытие» не рекомендуется: она привязывает вызывающий код к внутреннему устройству формы и добавляет лишние серверные вызовы. ОткрытьФорму гарантирует, что вся инициализация пройдёт в ПриСозданииНаСервере.

Параметры вместо обращения к элементам

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

Не так:

1С
ФормаМастера = ПолучитьФорму("ОбщаяФорма.МастерНастройки");
ФормаМастера.Открыть();
ФормаМастера.Элементы.Страницы.ТекущаяСтраница = ФормаМастера.Элементы.СтраницаПриветствие;

А так:

1С
ПараметрыФормы = Новый Структура("НачальнаяСтраница", "Приветствие");
ОткрытьФорму("ОбщаяФорма.МастерНастройки", ПараметрыФормы);

Внутри формы параметр читается в ПриСозданииНаСервере через Параметры.НачальнаяСтраница, и там же выбирается страница.

Результат через описание оповещения

Чтобы получить результат работы формы, передаём описание оповещения о закрытии. Модальные окна в современных конфигурациях не используются, поэтому это единственный правильный путь:

1С
&НаКлиенте
Процедура ПоказатьНапоминание(Команда)

	Оповещение = Новый ОписаниеОповещения("ПоказатьНапоминаниеЗавершение", ЭтотОбъект);
	ОткрытьФорму("ОбщаяФорма.Напоминание", , , , , , Оповещение,
		РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);

КонецПроцедуры

&НаКлиенте
Процедура ПоказатьНапоминаниеЗавершение(БольшеНеПоказывать, ДополнительныеПараметры) Экспорт

	// Неопределено — пользователь закрыл форму крестиком.
	Если БольшеНеПоказывать = Неопределено Тогда
		Возврат;
	КонецЕсли;

	Если БольшеНеПоказывать Тогда
		ОтключитьНапоминаниеНаСервере();
	КонецЕсли;

КонецПроцедуры

В самой форме результат возвращается вызовом Закрыть(Результат).

Прочие ограничения

  • В ПриОткрытии не открывайте другие формы — порядок окон может нарушиться. Используйте короткий обработчик ожидания или откройте форму по команде пользователя.
  • Не открывайте и не закрывайте форму в одном обработчике: разнесите действия по времени.
  • Формы, предназначенные только для внешних пользователей, явно блокируйте для обычных сеансов:
1С
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

	Если Не Пользователи.ЭтоСеансВнешнегоПользователя() Тогда
		Отказ = Истина;
		Возврат;
	КонецЕсли;

КонецПроцедуры
  • Основные формы списков, обработок и отчётов должны открываться из меню «Все функции», даже если объект не выведен в командный интерфейс.

Оформление текстов запросов

Текст запроса длиннее нескольких строк выносится в отдельную функцию: так метод выполнения остаётся коротким, а текст удобно анализировать отдельно. Сами тексты оформляются по правилам:

  1. Ключевые слова — заглавными буквами.
  2. Каждому полю выборки — явный псевдоним, всегда через КАК.
  3. Даже короткий запрос — не в одну строку.
  4. В сложных запросах с соединениями и объединениями — комментарии. Учтите, что конструктор запросов удаляет комментарии без предупреждения.
  5. При программной сборке текста — комментарий к каждому этапу, и каждая часть должна открываться конструктором.

Явный псевдоним защищает от неожиданностей. Поле Касса.Валюта.Наименование без псевдонима получит имя ВалютаНаименование, а не Наименование, и код, читающий выборку, сломается при первом же переименовании.

Осмысленные псевдонимы источников

Псевдоним таблицы образуется от термина предметной области и объясняет роль таблицы в этом запросе. Нельзя: однобуквенные имена, имена с подчёркивания, Таблица1, Справочник.

Запрос 1С
ВЫБРАТЬ
	ВсяНоменклатура.Ссылка КАК Товар,
	ЕСТЬNULL(ОстаткиНаСкладах.КоличествоОстаток, 0) КАК Остаток
ИЗ
	Справочник.Номенклатура КАК ВсяНоменклатура
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ОстаткиНаСкладах
		ПО ВсяНоменклатура.Ссылка = ОстаткиНаСкладах.Номенклатура

Исключение — универсальные механизмы, где имя таблицы подставляется во время выполнения: там допустим нейтральный псевдоним вроде Таблица.

Без вложенных запросов

Вложенные запросы стандарт не рекомендует: временные таблицы читаются легче, их результат проще проверить в отладке, а соединение с вложенным запросом нередко выполняется медленно из-за неудачного плана СУБД. Пакет с ПОМЕСТИТЬ почти всегда лучше.

Программная модификация текста запроса

Когда часть запроса зависит от условий, текст меняют так, чтобы исходный вариант оставался валидным и открывался конструктором.

Подстановка поля или таблицы. Вместо склейки строк — параметр-заглушка и СтрЗаменить:

1С
ТекстЗапроса =
	"ВЫБРАТЬ
	|	Номенклатура.Наименование КАК Наименование,
	|	&ПолеАртикула КАК Артикул
	|ИЗ
	|	Справочник.Номенклатура КАК Номенклатура";

// Поле артикула зависит от настройки учёта.
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолеАртикула", "Номенклатура." + ИмяПоляАртикула);

В исходном виде &ПолеАртикула — обычный параметр, и конструктор открывает такой запрос без ошибок.

Временная таблица по условию. Не раскомментируйте ПОМЕСТИТЬ заменой. Пишите полный текст и удаляйте лишнее:

1С
ТекстЗапроса =
	"ВЫБРАТЬ
	|	Контрагенты.Ссылка КАК Ссылка
	|ПОМЕСТИТЬ ВТКонтрагенты
	|ИЗ
	|	Справочник.Контрагенты КАК Контрагенты";

Если Не ПомещатьВоВременнуюТаблицу Тогда
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПОМЕСТИТЬ ВТКонтрагенты", "");
КонецЕсли;

Сборка пакета. Удобнее всего собирать тексты в массив и соединять через разделитель — так не нужно следить, где поставить точку с запятой:

1С
РазделительПакета =
	"
	|;
	|////////////////////////////////////////////////////////////////////////////////
	|";

ТекстыПакета = Новый Массив;

Если ИспользоватьУпаковки Тогда
	ТекстыПакета.Добавить(ТекстЗапросаУпаковки());
КонецЕсли;
ТекстыПакета.Добавить(ТекстЗапросаНоменклатура());

ТекстЗапроса = СтрСоединить(ТекстыПакета, РазделительПакета);

Не дублируйте код: общие модули и БСП

Принцип DRY в 1С нарушают постоянно: копируют функцию в соседнюю форму, слегка правят — и через год никто не знает, какая из пяти копий правильная. Исправление ошибки превращается в поиск всех мест, а пропущенная копия становится новой ошибкой.

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

  • БСП — пользователи, права, печать, дополнительные реквизиты, файлы, обмены, длительные операции и многое другое;
  • библиотека подключаемого оборудования;
  • библиотеки конкретных типовых конфигураций и собственные библиотеки команды.

Версию БСП, встроенную в конфигурацию, можно посмотреть в регистре сведений «Версии подсистем» по подсистеме СтандартныеПодсистемы, а документацию к нужной версии — на ИТС. При подключении подсистем внимательно читайте раздел документации о настройке и использовании подсистем при разработке.

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

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

Коротко

  • Бизнес-логика — в модуле объекта, менеджера или общем модуле; форма только вызывает её.
  • Формы открываются через ОткрытьФорму с параметрами, результат возвращается через описание оповещения и Закрыть(Результат).
  • В запросах: заглавные ключевые слова, явные псевдонимы через КАК, осмысленные имена источников, временные таблицы вместо вложенных запросов.
  • Текст запроса меняют заменой параметров-заглушек и сборкой пакета из массива, а не склейкой строк и раскомментированием.
  • Дублирующийся код выносите в общие модули и сначала ищите готовое в БСП.