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

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

Наем ведущего программиста 1С (Lead Developer) или эксперта по технологическим вопросам — задача нетривиальная. Обычные тестовые задания на создание простейших документов или отчетов не позволяют оценить глубину понимания платформы. Нам важно проверить не просто знание синтаксиса, а понимание механизмов СУБД (MS SQL Server, PostgreSQL), работы индексов, управляемых блокировок и путей оптимизации запросов под высокой нагрузкой (Highload).

В этой статье мы подробно разберем практические кейсы, нестандартные задачи и архитектурные вопросы, которые помогут объективно оценить квалификацию кандидата уровня Senior / Lead. Мы рассмотрим готовые задачи с решениями, которые можно использовать на собеседованиях.

В чем разница между ведущим разработчиком и технологическим экспертом?

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

  1. Ведущий программист (Архитектор): Это специалист, проектирующий метаданные, структуру регистров, определяющий логику взаимодействия подсистем и организующий процесс разработки. Для него критически важен широкий кругозор, знание прикладных областей (например, основ РСБУ, управленческого учета, ERP-систем) и опыт проектирования масштабируемых систем.
  2. Эксперт по технологическим вопросам (Performance Expert): Это узкоспециализированный инженер, который может не знать тонкостей бухгалтерского учета, но досконально разбирается в планах запросов СУБД, блокировках, индексах, настройках серверов и решении проблем производительности.

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

Задача 1. Тривиальная задача с нетривиальным решением: Срез последних в табличной части

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

Формулировка задачи:
Написать запрос, который получает актуальную цену товара из периодического регистра сведений для каждой строки табличной части документа. Учет в системе ведется в разрезе номенклатуры и характеристик. Цену необходимо получить строго на дату документа (или на актуальный момент).

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

Вариант 1. Использование виртуальной таблицы «СрезПоследних» с параметром «Период»

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


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

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

Вариант 2. Использование физической таблицы регистра и подзапроса (коррелированный запрос)

Второй вариант решает проблему получения цен для множества документов с разными датами. Мы обращаемся к физической таблице регистра сведений и накладываем условие на период через вложенный запрос.


ВЫБРАТЬ
	ДокТовары.Ссылка КАК Ссылка,
	ДокТовары.Номенклатура КАК Номенклатура,
	ДокТовары.Характеристика КАК Характеристика,
	ЕСТЬNULL(ЦеныФизическая.Цена, 0) КАК Цена
ИЗ
	Документ.РеализацияТоваровУслуг.Товары КАК ДокТовары
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК ЦеныФизическая
		ПО ДокТовары.Номенклатура = ЦеныФизическая.Номенклатура
		И ДокТовары.Характеристика = ЦеныФизическая.Характеристика
		И ЦеныФизическая.Период = (
			ВЫБРАТЬ МАКСИМУМ(ЦеныМакс.Период)
			ИЗ РегистрСведений.ЦеныНоменклатуры КАК ЦеныМакс
			ГДЕ ЦеныМакс.Номенклатура = ДокТовары.Номенклатура
				И ЦеныМакс.Характеристика = ДокТовары.Характеристика
				И ЦеныМакс.Период <= ДокТовары.Ссылка.Дата
		)

Анализ решения: Это гибкий способ, корректно отрабатывающий для любого количества документов. Однако на уровне СУБД коррелированный подзапрос для каждой строки может выполняться медленно, если в регистре миллионы записей, а индексы построены неоптимально.

Вариант 3. Левое соединение физической таблицы «на себя» (метод Anti-Join / поиск максимума)

Это наиболее элегантный с точки зрения реляционной алгебры способ. Мы соединяем таблицу товаров с физической таблицей цен (назовем ее Цены1), которая меньше или равна дате документа, и затем повторно соединяем с этой же таблицей цен (назовем ее Цены2) по условию, что существует запись с более поздним периодом, но все еще не превышающим дату документа. В секции ГДЕ мы отсекаем такие записи, оставляя только самую последнюю.


ВЫБРАТЬ
	ДокТовары.Ссылка КАК Ссылка,
	ДокТовары.Номенклатура КАК Номенклатура,
	ДокТовары.Характеристика КАК Характеристика,
	ЕСТЬNULL(Цены1.Цена, 0) КАК Цена
ИЗ
	Документ.РеализацияТоваровУслуг.Товары КАК ДокТовары
	
	// Первое соединение: все цены, которые были ранее или в дату документа
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК Цены1
		ПО ДокТовары.Номенклатура = Цены1.Номенклатура
		И ДокТовары.Характеристика = Цены1.Характеристика
		И Цены1.Период <= ДокТовары.Ссылка.Дата
		
	// Второе соединение: ищем, есть ли цена позже, чем Цены1, но до даты документа
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК Цены2
		ПО ДокТовары.Номенклатура = Цены2.Номенклатура
		И ДокТовары.Характеристика = Цены2.Характеристика
		И Цены2.Период <= ДокТовары.Ссылка.Дата
		И Цены1.Период < Цены2.Период
ГДЕ
	// Если более поздней записи не нашлось, значит Цены1 - это и есть срез последних
	Цены2.Период ИС НУЛЛ

Анализ решения: Понимание этого паттерна показывает, что кандидат умеет мыслить множествами и понимает, как работают соединения без использования тяжелых подзапросов СУБД.

Задача 2. Алгоритмическая головоломка: генерация последовательности без таблиц БД

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

Формулировка задачи:
Написать запрос, который возвращает таблицу чисел от 1 до заданного параметра N (где N — целое число, например, 1000). Ограничения: запрещено использовать реальные таблицы базы данных, запрещено использовать конструкции ОБЪЕДИНИТЬ / ОБЪЕДИНИТЬ ВСЕ, в запросе должен быть ровно один параметр — число &N.

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

Рассмотрим по шагам пример построения такой последовательности:


// Шаг 1. Создаем базовый набор из нескольких строк с помощью виртуальных таблиц констант или параметров.
// В 1С запросах можно использовать автогенерацию строк через соединение предопределенных значений.
ВЫБРАТЬ 1 КАК Цифра ПОМЕСТИТЬ Десятка;
// Далее делаем кросс-соединение таблицы саму на себя несколько раз, чтобы получить степени десятки.
// Полноценное решение этой задачи требует от кандидата понимания, как СУБД обрабатывает декартовы произведения.

Если соискатель сможет логически обосновать структуру построения такой таблицы (например, через возведение базовой строки в степень с последующим расчетом нарастающего итога связями), это гарантирует глубокое понимание математической логики SQL.

Задача 3. Технологический кейс на SARGability (индексируемость условий)

Один из важнейших навыков ведущего разработчика — написание запросов, которые эффективно используют индексы СУБД. Предложите кандидату проанализировать следующий код запроса:


ВЫБРАТЬ
	Продажи.Номенклатура,
	Продажи.СуммаОборот
ИЗ
	РегистрНакопления.Продажи.Обороты КАК Продажи
ГДЕ
	НАЧАЛОПЕРИОДА(Продажи.Период, ДЕНЬ) = &ВыбранныйДень

Вопрос кандидату: Будет ли данный запрос работать быстро на базе данных объемом в несколько терабайт? В чем его проблема и как его переписать?

Правильный ответ и объяснение:
Этот запрос будет выполняться крайне медленно (произойдет полное сканирование таблицы — Table Scan или Index Scan). Причина заключается в нарушении принципа SARGability (Search Argument Able). Мы применили функцию НАЧАЛОПЕРИОДА к индексируемому полю Период в секции ГДЕ.

Когда СУБД видит функцию над колонкой индекса, она не может использовать индекс для прямого поиска значения (Index Seek), так как ей необходимо вычислить результат функции для каждой строки таблицы. Чтобы исправить это, мы должны переписать условие так, чтобы колонка оставалась «чистой», а функции применялись только к параметрам:


ВЫБРАТЬ
	Продажи.Номенклатура,
	Продажи.СуммаОборот
ИЗ
	РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода) КАК Продажи

Или, если мы работаем с физической таблицей:


ГДЕ
	Продажи.Период МЕЖДУ &НачалоДня И &КонецДня

Задача 4. Мифы об индексации временных таблиц

Спросите кандидата: «Всегда ли нужно индексировать временные таблицы? В каком случае создание индекса замедлит работу системы?»

Ожидаемый ответ:
Многие разработчики слепо следуют правилу «всегда индексировать временные таблицы по полям связи». Это ошибка. Проанализируем физику процесса:

Задача 5. Проектирование высоконагруженных систем: борьба с Deadlocks

Перейдем к архитектурным вопросам уровня Lead. Задайте соискателю практический кейс по управлению транзакционными блокировками.

Формулировка кейса:
В вашей системе работают два фоновых задания. Они параллельно обрабатывают списки документов и записывают движения в независимый регистр сведений СтатусыДокументов. Периодически в журнале регистрации фиксируются ошибки взаимных блокировок (Deadlocks). Как решить эту проблему?

Проанализируем шаги, которые должен предложить кандидат для устранения взаимоблокировок:

  1. Внедрение управляемых блокировок: Первым делом необходимо явно установить исключительную управляемую блокировку на пространство регистра сведений перед началом транзакции записи. Это предотвратит попытки СУБД эскалировать блокировки с уровня строк до уровня страниц или таблиц.
  2. Сортировка данных (Жесткое упорядочивание): Самая частая причина взаимных блокировок — захват ресурсов в разном порядке. Например, Транзакция №1 блокирует Документ А, затем Документ Б. Транзакция №2 в этот же момент блокирует Документ Б, а затем пытается заблокировать Документ А. Происходит клин (Deadlock).
    Решение: Перед началом записи в транзакции массив данных необходимо строго отсортировать по уникальному идентификатору (UUID) или коду. Если обе транзакции будут блокировать записи строго в одном и том же порядке (например, по возрастанию UUID), то транзакция №2 просто будет ожидать окончания работы транзакции №1 на первом же общем элементе, не вызывая взаимного тупика.
  3. Сокращение времени транзакции: Вынос всех тяжелых расчетов, не требующих изоляции, за пределы транзакции. Внутри транзакции должна происходить только быстрая запись готовых данных.

Задача 6. Влияние расширений конфигурации на производительность

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

Формулировка вопроса:
Мы добавили новый реквизит Спецификация в документ ЗаказПокупателя через расширение конфигурации. Затем вывели этот реквизит в динамический список на форме. Почему при росте базы этот список стал критически тормозить и как СУБД выполняет этот запрос?

Ответ эксперта:
При добавлении новых реквизитов объектов через механизм расширений платформа 1С не перестраивает основную таблицу документа на уровне SQL. Вместо этого она создает отдельную физическую таблицу для хранения данных расширения.

При любом запросе к документу, где участвует новый реквизит, платформа на уровне СУБД неявно выполняет операцию LEFT JOIN между основной таблицей документа и таблицей расширения по первичному ключу (ссылке). В динамических списках с пагинацией и сложными отборами такое неявное соединение разрушает оптимальные планы запросов, увеличивает логические чтения и может приводить к полному сканированию индексов. Ведущий программист должен знать об этой особенности и минимизировать добавление реквизитов через расширения в высоконагруженных таблицах, предпочитая классическое изменение конфигурации или использование дополнительных сведений/свойств.

← На главную