Инструкции по разработке на 1С: что должен знать каждый программист, чтобы не переделывать по три раза
Вы когда-нибудь получали задачу «сделай как-нибудь, а потом разберёмся»? А потом это «как-нибудь» жило в боевой базе три года — и сломалось именно в конце квартала, при сдаче отчётности.
Знакомо. Я лично через это прошёл — и не один раз. И это не проблема конкретного разработчика. Это проблема отсутствия стандартов.
Здесь — практическое руководство по разработке на 1С: от соглашений по именованию до работы с транзакциями и обменами. То, что реально используется в серьёзных командах. То, что спасает нервы и деньги.
Почему стандарты разработки в 1С — это не бюрократия, а выживание
Типичная картина: программист пишет код, всё работает, уходит в другую компанию. Через полгода приходит новый разработчик, открывает модуль и видит переменные вида «х1», «ТемпПеременная2», «РезультатФинальный_НОВЫЙ». И три часа уходит только на то, чтобы понять — что вообще здесь происходит.
По данным опросов в 1С-сообществе, до 60% времени разработчика уходит на чтение и понимание чужого кода. Не на написание нового — на разбор старого. Это деньги заказчика, которые буквально сгорают из-за отсутствия договорённостей внутри команды.
Хорошие стандарты решают три задачи:
- Новый разработчик входит в проект за дни, а не недели
- Баги находятся быстрее, потому что код предсказуем
- Обновление типовой конфигурации не превращается в ад
Ладно, погнали к конкретике.
Соглашения по именованию в 1С: как называть переменные, процедуры и функции
Платформа 1С использует русскоязычный синтаксис. Это и преимущество, и ловушка. Преимущество — код читается как текст. Ловушка — разработчики начинают называть переменные как попало, потому что «и так понятно».
Переменные и параметры
Правило первое: венгерская нотация для типов. Да, в 1С она не обязательна, но помогает.
- стр — строка (стрНаименование, стрКомментарий)
- н — число (нКоличество, нСумма)
- б — булево (бПроведён, бАктивен)
- д — дата (дНачала, дОкончания)
- Сп — список значений
- Таб — таблица значений
- Рез — результат запроса
Плохой пример — то, что реально встречается в проектах. На одном из моих проектов весь модуль проведения был написан именно так:
// ПЛОХО — так писать не надо
Процедура Обработать(Парам1, Парам2, ФлагНовый)
Перем ТемпДата;
Перем РезФин;
ТемпДата = Парам2;
РезФин = Парам1 * 1.2;
КонецПроцедуры
Хороший пример — тот же код, но понятный:
// ХОРОШО — читается как документация
Процедура РассчитатьСуммуСНДС(нСуммаБезНДС, дДатаРасчёта, бПримененьСпецСтавка)
Перем дАктуальнаяДата;
Перем нСуммаСНДС;
дАктуальнаяДата = ?(ЗначениеЗаполнено(дДатаРасчёта), дДатаРасчёта, ТекущаяДата());
нСуммаСНДС = нСуммаБезНДС * ПолучитьСтавкуНДС(дАктуальнаяДата, бПримененьСпецСтавка);
КонецПроцедуры
Разница очевидна. Второй вариант — самодокументирующийся код. Через год откроете его и сразу поймёте, что происходит.
Процедуры и функции: глагол + существительное
Процедура — это действие. Функция — это вычисление с результатом. Называйте соответственно.
- Процедура: ЗагрузитьДанные, ОчиститьТаблицу, ОтправитьУведомление
- Функция: ПолучитьСуммуДокумента, ВычислитьОстаток, НайтиКонтрагента
Если функция возвращает булево — добавляйте префикс «Это» или «Есть»: ЭтоПроведённыйДокумент, ЕстьОстатокНаСкладе.
Структура модулей в 1С: как организовать код, чтобы не потеряться
Открываете модуль объекта в чужом проекте — и видите 3000 строк кода без единого комментария и логической структуры. Всё вперемешку: обработчики событий, вспомогательные функции, бизнес-логика.
Это типичная история. Я видел такое в 4 из 5 проектов, куда приходил как новый разработчик.
Стандарт структуры модуля — это договорённость команды о том, в каком порядке располагается код. Рекомендуемый порядок:
- Область «Переменные модуля» — объявления переменных модуля
- Область «Программный интерфейс» — экспортные процедуры и функции
- Область «Обработчики событий» — ПриЗаписи, ПриПроведении и т.д.
- Область «Служебные процедуры и функции» — внутренняя логика
- Область «Инициализация» — код, выполняемый при создании объекта
Используйте директивы #Область / #КонецОбласти — они сворачивают блоки кода и делают навигацию по модулю человеческой:
#Область ПрограммныйИнтерфейс
// Рассчитывает итоговую сумму документа с учётом скидок и НДС
// Параметры:
// Ссылка - ДокументСсылка - ссылка на документ
// Возвращаемое значение: Число - итоговая сумма
Функция ПолучитьИтоговуюСумму(Ссылка) Экспорт
Возврат РассчитатьСумму(Ссылка);
КонецФункции
#КонецОбласти
Обратите внимание на комментарий перед функцией. Это не опционально — это обязательно для экспортных процедур. Такой формат поддерживается Синтакс-помощником и отображается в подсказках при написании кода.
Работа с запросами в 1С: 5 правил, которые спасут производительность
Запросы — это то место, где большинство проектов теряют производительность. Один неправильный запрос в документе с 500 пользователями — и сервер падает каждый вечер в 18:00.
Правило 1: Никаких запросов в циклах
Это правило №1. Его нарушают чаще всего. Запрос в цикле по 1000 строк — это 1000 обращений к базе данных вместо одного.
// ПЛОХО — запрос в цикле, база рыдает
Для Каждого СтрокаТЧ Из ТабличнаяЧасть Цикл
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Цена ИЗ РегистрСведений.ЦеныНоменклатуры
|ГДЕ Номенклатура = &Ном";
Запрос.УстановитьПараметр("Ном", СтрокаТЧ.Номенклатура);
Рез = Запрос.Выполнить().Выбрать();
КонецЦикла// ХОРОШО — один запрос для всей таблицы
СписокНоменклатуры = ТабличнаяЧасть.ВыгрузитьКолонку("Номенклатура");
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Номенклатура, Цена
|ИЗ РегистрСведений.ЦеныНоменклатуры
|ГДЕ Номенклатура В (&СписокНом)";
Запрос.УстановитьПараметр("СписокНом", СписокНоменклатуры);
ТаблицаЦен = Запрос.Выполнить().Выгрузить();
// Дальше работаем с ТаблицаЦен.НайтиСтроки() — без запросов
Правило 2: Используйте виртуальные таблицы с параметрами
Виртуальные таблицы — это готовые срезы регистров. Но многие используют их неправильно: сначала получают все данные, потом фильтруют через ГДЕ.
Это катастрофа для производительности — и я не преувеличиваю.// ПЛОХО — фильтр после виртуальной таблицы
ВЫБРАТЬ КоличествоОстаток
ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ГДЕ Остатки.Склад = &НужныйСклад
// ХОРОШО — параметр передаётся В виртуальную таблицу
ВЫБРАТЬ КоличествоОстаток
ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(
,
Склад = &НужныйСклад
) КАК Остатки
Разница: в первом случае база читает ВСЕ остатки и потом фильтрует. Во втором — только нужный склад. На большой базе это может быть разница в 10-100 раз по скорости.
Правило 3: Временные таблицы для сложных запросов
Если запрос сложный и использует одни и те же данные несколько раз — выносите их во временную таблицу. Это читаемо и быстро.
МенеджерВТ = Новый МенеджерВременныхТаблиц;
// Шаг 1: Получаем нужные документы во временную таблицу
Запрос1 = Новый Запрос;
Запрос1.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос1.Текст = "ВЫБРАТЬ Ссылка
|ПОМЕСТИТЬ ВТ_Документы
|ИЗ Документ.РеализацияТоваровУслуг
|ГДЕ Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И Проведён = ИСТИНА";
Запрос1.УстановитьПараметр("НачалоПериода", НачалоПериода);
Запрос1.УстановитьПараметр("КонецПериода", КонецПериода);
Запрос1.Выполнить();
// Шаг 2: Используем ВТ в основном запросе
Запрос2 = Новый Запрос;
Запрос2.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос2.Текст = "ВЫБРАТЬ ...
|ИЗ ВТ_Документы КАК Документы
|ЛЕВОЕ СОЕДИНЕНИЕ ...";
РезультатЗапроса = Запрос2.Выполнить();
Транзакции и обработка ошибок в 1С: как не потерять данные
Транзакции — это то, о чём многие разработчики думают в последнюю очередь. А потом получают частично записанные данные в базе и звонок от бухгалтера в 9 утра. Помню случай — клиент позвонил в пятницу вечером: «у нас документы провелись, но остатки не изменились». Три часа разбирались. Причина — отсутствие транзакции при записи связанных объектов.
Правило простое: если вы записываете несколько связанных объектов — используйте транзакцию. Либо всё записалось, либо ничего.
Процедура ПровестиДокументСПривязкой(ДокументОбъект, СвязанныйОбъект)
НачатьТранзакцию();
Попытка
// Записываем основной документ
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
// Записываем связанный объект
СвязанныйОбъект.ДокументОснование = ДокументОбъект.Ссылка;
СвязанныйОбъект.Записать();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
// Логируем ошибку — не глотаем её!
ЗаписьЖурналаРегистрации(
"Ошибка проведения документа",
УровеньЖурналаРегистрации.Ошибка,
,
,
ОписаниеОшибки()
);
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
Обратите внимание на ВызватьИсключение в блоке Исключение. Это критически важно. Многие разработчики пишут Исключение — и не перевызывают его. В результате ошибка «проглатывается», транзакция откатывается, но пользователь видит успешное завершение. Данные не записаны, пользователь не знает. Это катастрофа.
Вложенные транзакции: подводный камень
В 1С вложенные транзакции работают не так, как вы думаете. НачатьТранзакцию() внутри уже открытой транзакции не создаёт новую — это просто счётчик. ЗафиксироватьТранзакцию() уменьшает счётчик. Реальная фиксация происходит только когда счётчик доходит до нуля.
Это значит: если внутренняя «транзакция» откатилась, а внешняя пытается зафиксироваться — получите исключение. Проектируйте архитектуру так, чтобы минимизировать вложенность.
Работа с RLS и правами доступа в 1С: типичные ошибки разработчиков
RLS (Record Level Security — ограничение на уровне записей) — мощный механизм. И источник самых загадочных тормозов, которые вы когда-либо видели.
Типичная история: запрос работает за 0.1 секунды под администратором. Под обычным пользователем — 15 секунд. Разработчик в панике. А проблема в том, что RLS добавляет условие к каждому запросу — и если это условие неоптимально, всё рушится.
Правило: всегда тестируйте под пользователем с ограниченными правами
Звучит очевидно. Но я считаю, что именно это нарушение — самое массовое в 1С-разработке. По моим наблюдениям, минимум 8 из 10 разработчиков тестируют только под администратором — и это системная проблема, не личная.
Обязательные проверки перед сдачей задачи:
- Запустить под пользователем с минимальными правами для данной задачи
- Проверить время выполнения ключевых операций
- Убедиться, что нет ошибок «Недостаточно прав» в неожиданных местах
- Проверить журнал регистрации на ошибки доступа
Привилегированный режим: когда использовать и когда нет
Привилегированный режим отключает проверку прав. Это нужно в конкретных случаях — например, в фоновых заданиях или при записи служебных данных. Использовать его «чтобы не разбираться с правами» — это не решение, это бомба замедленного действия.
// Правильное использование привилегированного режима
// Только для конкретной операции, не для всего модуля
&НаСервере
Процедура ЗаписатьСлужебныеДанные(ДанныеДляЗаписи)
УстановитьПривилегированныйРежим(Истина);
Попытка
// Записываем только служебные данные
РегистрСведений.СлужебныеДанные.УстановитьЗначения(ДанныеДляЗаписи);
Исключение
УстановитьПривилегированныйРежим(Ложь);
ВызватьИсключение;
КонецПопытки;
УстановитьПривилегированныйРежим(Ложь); // Всегда снимаем!
КонецПроцедуры
Ключевое правило: привилегированный режим всегда снимается после использования — в том числе при исключении.
Обмены данными в 1С: стандарты, которые сэкономят вам недели отладки
Обмены — это отдельный мир боли. Данные не приходят, приходят дважды, приходят в неправильном формате. Если нет стандартов — каждый обмен становится уникальным квестом.
Логирование обменов: минимальный стандарт
Каждый обмен должен писать в журнал регистрации. Не «если что-то пошло не так» — а всегда. Успешная загрузка, количество обработанных записей, время выполнения. Сейчас будет важное — не пропустите: именно итоговая запись в журнал спасает вас, когда заказчик говорит «данные не пришли».
Процедура ВыполнитьОбменСВнешнейСистемой()
ВремяНачала = ТекущаяДата();
КоличествоОбработано = 0;
КоличествоОшибок = 0;
Попытка
ДанныеОбмена = ПолучитьДанныеИзВнешнейСистемы();
Для Каждого ЗаписьОбмена Из ДанныеОбмена Цикл
Попытка
ОбработатьЗапись(ЗаписьОбмена);
КоличествоОбработано = КоличествоОбработано + 1;
Исключение
КоличествоОшибок = КоличествоОшибок + 1;
ЗаписьЖурналаРегистрации(
"Обмен: ошибка обработки записи",
УровеньЖурналаРегистрации.Ошибка,
,
ЗаписьОбмена.Идентификатор,
ОписаниеОшибки()
);
КонецПопытки;
КонецЦикла;
Исключение
ЗаписьЖурналаРегистрации(
"Обмен: критическая ошибка",
УровеньЖурналаРегистрации.Ошибка,
, ,
ОписаниеОшибки()
);
ВызватьИсключение;
КонецПопытки;
// Итоговая запись в журнал
Сообщение = СтрШаблон(
"Обмен завершён. Обработано: %1, Ошибок: %2, Время: %3 сек.",
КоличествоОбработано,
КоличествоОшибок,
(ТекущаяДата() - ВремяНачала)
);
ЗаписьЖурналаРегистрации("Обмен", УровеньЖурналаРегистрации.Информация, , , Сообщение);
КонецПроцедуры
Этот шаблон спасёт вас, когда заказчик скажет «данные не пришли» — откроете журнал и за 30 секунд найдёте проблему.
Работа с интерфейсом в 1С: управляемые формы и производительность
Управляемые формы — это клиент-серверная архитектура. И главный источник непонимания у разработчиков, которые пришли из 1С 7.7 или из обычных форм.
Главное правило: всё тяжёлое — на сервере. На клиенте — только UI-логика.
Директивы компиляции: используйте правильно
- &НаКлиенте — только UI: открыть форму, показать сообщение, обработать нажатие кнопки
- &НаСервере — запросы, запись объектов, тяжёлые вычисления
- &НаКлиентеНаСервереБезКонтекста — простые вычисления без обращения к базе
- &НаСервереБезКонтекста — серверные операции без передачи всей формы (быстрее!)
// Правильная структура обработчика команды
&НаКлиенте
Процедура ЗагрузитьДанные(Команда)
ОчиститьСообщения();
// Показываем индикатор загрузки
Состояние("Загружаю данные...");
// Вся тяжёлая работа — на сервере
ЗагрузитьДанныеНаСервере();
КонецПроцедуры
// Серверная процедура без контекста — не тащим всю форму
&НаСервереБезКонтекста
Процедура ЗагрузитьДанныеНаСервере()
// Здесь запросы, запись, вся логика
РезультатЗапроса = ВыполнитьЗапросЗагрузки();
ОбработатьРезультат(РезультатЗапроса);
КонецПроцедуры
Минимизируйте серверные вызовы
Каждый вызов сервера — это сетевой round-trip. На тонком клиенте через интернет это может быть 200-500 мс. Если у вас 10 серверных вызовов при открытии формы — пользователь ждёт 2-5 секунд. Это неприемлемо.
Группируйте серверные операции: лучше один вызов, который делает 5 вещей, чем 5 вызовов по одной вещи.
Документирование кода в 1С: минимум, который обязателен
«Хороший код не требует комментариев» — это миф, который придумали люди, не поддерживавшие чужой код через три года после написания. Честно? Я раньше тоже так думал, пока не открыл собственный модуль двухлетней давности и не провёл полчаса, пытаясь вспомнить логику.
В 1С есть стандарт документирования — он поддерживается BSP (Библиотекой стандартных подсистем) и отображается в Синтакс-помощнике.
Что обязательно документировать:
- Все экспортные процедуры и функции — всегда
- Нетривиальную бизнес-логику — «почему именно так»
- Обходные решения и костыли — с указанием причины и ссылкой на задачу
- Параметры сложных процедур — типы и допустимые значения
// Рассчитывает сумму скидки для строки документа.
// Учитывает накопительные скидки контрагента и акционные предложения.
// ВНИМАНИЕ: не учитывает ручные скидки — они применяются отдельно.
//
// Параметры:
// СтрокаТЧ - СтрокаТаблицыЗначений - строка табличной части
// Контрагент - СправочникСсылка.Контрагенты - контрагент документа
// ДатаДокумента - Дата - дата документа для определения акций
//
// Возвращаемое значение:
// Число - процент скидки от 0 до 100
Функция РассчитатьПроцентСкидки(СтрокаТЧ, Контрагент, ДатаДокумента) Экспорт
// Логика расчёта...
КонецФункции
Чек-лист перед сдачей задачи: 10 пунктов, которые спасут вас от возврата
Это практический чек-лист — тот самый, который я использую сам и который внедрял в командах. Распечатайте и повесьте над монитором.
- Нет запросов в циклах — проверить все циклы в коде
- Виртуальные таблицы с параметрами — не фильтровать через ГДЕ после виртуальной таблицы
- Транзакции закрыты — каждый НачатьТранзакцию имеет Зафиксировать или Отменить
- Исключения не проглочены — в блоке Исключение есть ВызватьИсключение или обработка
- Тест под ограниченным пользователем — не только под администратором
- Логирование ключевых операций — журнал регистрации пишется
- Экспортные функции задокументированы — есть описание параметров и возвращаемого значения
- Нет жёстко зашитых значений — никаких магических чисел и строк прямо в коде
- Обновление типовой — изменения в расширении или с минимальным вмешательством в типовой код
- Проверка на пустые значения — ЗначениеЗаполнено() перед использованием ссылок
Этот чек-лист сокращает количество возвратов задач на доработку в среднем в 2-3 раза. Проверено на практике в командах от 5 до 30 разработчиков.
Итог: стандарты — это инвестиция, а не трата времени
Написать код без стандартов быстрее. На 20-30% быстрее — в моменте. Но потом вы платите за это годами: медленный онбординг новых разработчиков, долгий поиск багов, мучительные обновления конфигурации.
Реальные цифры из практики: внедрение стандартов разработки в команде из 8 человек сократило время code review с 3 часов до 45 минут на задачу. За год это 500+ часов сэкономленного времени. При ставке разработчика 3000 рублей в час — это 1,5 миллиона рублей.
Ну вы поняли, к чему я веду. Стандарты — это не про перфекционизм. Это про деньги и нервы.
Начните с малого: договоритесь об именовании, структуре модулей и обязательном логировании. Остальное придёт со временем.
Если вам нужен опытный разработчик 1С, который уже знает все эти стандарты и не будет учиться на вашем проекте — заходите на koderion.ru. Это биржа проверенных специалистов 1С: программисты, консультанты, DevOps. Найдёте нужного человека под конкретную задачу — будь то разовая доработка или долгосрочный проект.