framework_eng/skills/bsl-practices/coding-standards/SKILL.md
BSL coding standards (1C). This skill teaches the agent to write code in the built-in 1C language (BSL) in accordance with the standards of the 1C:Enterprise platform and ITS recommendations.
npx skillsauth add steelmorgan/1c-agent-based-dev-framework coding-standardsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
ITS standard: "Module texts" - names in Russian, CamelCase.
| Element | Format | Example |
|---------|--------|--------|
| Variable | NounOrPhrase | КоличествоСтрок, ДатаНачалаПериода |
| Procedure | VerbPhrase | ЗаполнитьТабличнуюЧасть, УстановитьОтбор |
| Function | NounOrQuestion | ПолучитьСписокДокументов, ЭтоНовый |
| Boolean variable | Affirmative form | ЭтоНовый, РазрешеноРедактирование, ЕстьОшибки |
| Parameter | LikeVariable | ДокументСсылка, РежимОткрытия |
Процедура ЗаполнитьТабличнуюЧастьТовары(ДокументОбъект, ДанныеЗаполнения)
КоличествоСтрок = ДанныеЗаполнения.Количество();
ЕстьОшибки = Ложь;
Для Каждого СтрокаДанных Из ДанныеЗаполнения Цикл
НоваяСтрока = ДокументОбъект.Товары.Добавить();
НоваяСтрока.Номенклатура = СтрокаДанных.Номенклатура;
НоваяСтрока.Количество = СтрокаДанных.Количество;
КонецЦикла;
КонецПроцедуры
ITS standard: "Module structure" - regions (#Область) in a specific order.
#Область ПрограммныйИнтерфейс
// Экспортные процедуры и функции — публичный API модуля.
Функция ПолучитьКурсВалюты(Валюта, ДатаКурса) Экспорт
// ...
КонецФункции
#КонецОбласти
#Область СлужебныйПрограммныйИнтерфейс
// Экспортные процедуры для вызова только из других модулей данной подсистемы.
Функция ПересчитатьКурсВнутренний(ПараметрыПересчета) Экспорт
// ...
КонецФункции
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Внутренняя реализация. Не экспортные.
Функция СформироватьЗапросКурса(Валюта, Дата)
// ...
КонецФункции
#КонецОбласти
#Область ОписаниеПеременных
Перем МассивИзменённыхРеквизитов;
#КонецОбласти
#Область ОбработчикиСобытий
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
// ...
КонецПроцедуры
Процедура ПередЗаписью(Отказ)
// ...
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
#КонецОбласти
#Область Инициализация
МассивИзменённыхРеквизитов = Новый Массив;
#КонецОбласти
When &НаСервере is called, the platform serializes the entire form context back and forth. &НаСервереБезКонтекста passes only parameters - drastically less traffic.
| Directive | Where it runs | Access to form data | When to use |
|-----------|----------------|----------------------|-------------------|
| &НаКлиенте | Client (thin/web) | Yes (client copy) | Interactive logic: dialogs, navigation |
| &НаСервере | Server | Yes (full form context) | Need access to form attributes + database |
| &НаСервереБезКонтекста | Server | No | Database queries, calculations without form data |
| &НаКлиентеНаСервереБезКонтекста | Both client and server | No | Pure calculations, validation without database |
&НаКлиенте
Процедура НоменклатураПриИзменении(Элемент)
ДанныеНоменклатуры = ПолучитьДанныеНоменклатуры(Элементы.Товары.ТекущиеДанные.Номенклатура);
ЗаполнитьСтрокуТоваровНаКлиенте(ДанныеНоменклатуры);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьДанныеНоменклатуры(НоменклатураСсылка)
Возврат Новый Структура("ЕдиницаИзмерения, Цена, СтавкаНДС",
НоменклатураСсылка.ЕдиницаИзмерения,
НоменклатураСсылка.Цена,
НоменклатураСсылка.СтавкаНДС);
КонецФункции
A local variable with the name of a global collection hides the manager - later references to it in the code will fail.
// Правильно — конкретное имя
МассивДокументовКОбработке = Новый Массив;
СправочникНоменклатура = Справочники.Номенклатура;
Документы, Справочники, Регистры, Перечисления, ПланыОбмена, ПланыВидовХарактеристик, ПланыВидовРасчета, ПланыСчетов, БизнесПроцессы, Задачи, Обработки, Отчеты, Константы, ПараметрыСеанса, РегистрыСведений, РегистрыНакопления, РегистрыБухгалтерии, РегистрыРасчета
+ in loopsIn BSL, strings are immutable. Строка1 + Строка2 in a loop with N iterations gives O(N^2) in memory and time - each iteration copies everything before it.
ITS standard: "Efficient string handling".
// O(N) — массив + СтрСоединить()
ЧастиСтроки = Новый Массив;
Для Каждого Элемент Из КоллекцияДанных Цикл
ЧастиСтроки.Добавить(Элемент.Наименование);
КонецЦикла;
РезультатСтрока = СтрСоединить(ЧастиСтроки, ", ");
// Для фиксированного числа подстановок — СтрШаблон() (до 10 параметров)
ТекстСообщения = СтрШаблон(
НСтр("ru = 'Документ %1 от %2 на сумму %3 руб.'"),
НомерДокумента,
Формат(ДатаДокумента, "ДЛФ=D"),
Формат(Сумма, "ЧДЦ=2"));
ITS standard: "Module structure" - mandatory standard regions.
#Область ОписаниеПеременных
#КонецОбласти
#Область ОбработчикиСобытийФормы
#КонецОбласти
#Область ОбработчикиСобытийЭлементовШапкиФормы
#КонецОбласти
#Область ОбработчикиСобытийЭлементовТаблицыФормыТовары
#КонецОбласти
#Область ОбработчикиКомандФормы
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
#КонецОбласти
Rules: do not nest deeper than 2 levels; do not create empty regions; use the standard names from ITS (the IDE and analysis tools rely on them).
ITS standard: "Description of procedures and functions" - exported procedures MUST have a descriptive comment.
// Возвращает курс валюты на указанную дату.
// Если на указанную дату курс не установлен, возвращает курс на ближайшую предыдущую дату.
//
// Параметры:
// Валюта - СправочникСсылка.Валюты - валюта, курс которой нужно получить.
// ДатаКурса - Дата - дата, на которую нужен курс.
// Если не указана, используется текущая дата сеанса.
//
// Возвращаемое значение:
// Число - курс валюты. 0 если курс не найден.
//
Функция ПолучитьКурсВалюты(Валюта, ДатаКурса = Неопределено) Экспорт
// Сумму округляем до копеек, потому что бухгалтерский учёт не допускает дробных копеек,
// а при пересчёте НДС могут возникнуть дроби.
СуммаНДС = Окр(СуммаБезНДС * СтавкаНДС / 100, 2);
All strings shown to the user are wrapped in НСтр() for localization.
ITS standard: "Using the НСтр() function".
ТекстПредупреждения = НСтр("ru = 'Документ не может быть проведён. Не заполнена дата.'");
// С параметрами — НСтр() + СтрШаблон()
ТекстСообщения = СтрШаблон(
НСтр("ru = 'Остаток товара ""%1"" на складе: %2 %3'"),
Номенклатура,
Остаток,
ЕдиницаИзмерения);
A procedure longer than 100 lines is a signal to decompose it. Splitting into small functions with descriptive names makes the code self-documenting.
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
ИнициализироватьДанныеДокумента();
ПроверитьЗаполнениеРеквизитов(Отказ);
Если Не Отказ Тогда
СформироватьДвижения(Отказ);
КонецЕсли;
КонецПроцедуры
BSL is dynamically typed. Describing types in the comment for an exported function is the only way to document the contract.
// Создаёт новый элемент справочника «Номенклатура» с заполнением по умолчанию.
//
// Параметры:
// ДанныеЗаполнения - Структура - содержит поля:
// * Наименование - Строка - наименование номенклатуры (обязательно).
// * ВидНоменклатуры - ПеречислениеСсылка.ВидыНоменклатуры - вид (обязательно).
// * ЕдиницаИзмерения - СправочникСсылка.ЕдиницыИзмерения - ед. изм. Необязательно,
// по умолчанию «шт.».
// * Артикул - Строка - артикул. Необязательно.
//
// Возвращаемое значение:
// СправочникСсылка.Номенклатура - ссылка на созданный элемент.
//
Функция СоздатьНоменклатуру(ДанныеЗаполнения) Экспорт
Выполнить() and Вычислить() unless absolutely necessarySecurity risk (an eval-like equivalent), invisible to static analysis, difficult to debug.
// Правильно — прямой вызов через метаданные
МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоСсылке(СсылкаНаОбъект);
Hard-coded values are unclear, duplicated, and not configurable.
// Правильно — перечисление, значение самодокументировано
Если Документ.Статус = Перечисления.СтатусыДокументов.Согласован Тогда
// ...
КонецЕсли;
// Или константа для настраиваемых значений
МаксимальноеКоличествоПопыток = Константы.МаксимальноеКоличествоПопытокОтправки.Получить();
Reference chains create implicit JOINs. For compound types, the platform makes a JOIN to all possible tables.
// Правильно — один запрос с явными JOIN
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Номенклатура КАК Номенклатура,
| Товары.Номенклатура.ВидНоменклатуры КАК ВидНоменклатуры,
| Товары.Номенклатура.ЕдиницаИзмерения КАК ЕдиницаИзмерения
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК Товары
|ГДЕ
| Товары.Ссылка = &ДокументСсылка";
Для Каждого СтрокаТоваров Из Документ.Товары Цикл
ВидНоменклатуры = СтрокаТоваров.Номенклатура.ВидНоменклатуры;
ЕдиницаИзмерения = СтрокаТоваров.Номенклатура.ЕдиницаИзмерения;
КонецЦикла;
ПолучитьФорму() is for the classic application and does not work in the managed interface.
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Ключ", ДокументСсылка);
ОткрытьФорму("Документ.РеализацияТоваровУслуг.ФормаОбъекта",
ПараметрыФормы,
ЭтотОбъект,
,
,
,
Новый ОписаниеОповещения("ПослеЗакрытияФормыДокумента", ЭтотОбъект));
Put write and validation logic in the object module - for testability and reuse.
// Модуль объекта документа
Процедура ПередЗаписью(Отказ)
Для Каждого Строка Из Товары Цикл
Строка.Сумма = Строка.Количество * Строка.Цена;
КонецЦикла;
КонецПроцедуры
See error-handling, rule 1.
See form-patterns.
ask_ai_assistant (VALIDATE_BSL template from buddy-prompting). Provide a code fragment - get standards violations and recommendations for replacing them with БСП/platform methods.ask_ai_assistant (SEARCH_ITS template from buddy-prompting). If the skill differs from ITS, ITS takes priority.testing
MUST use BEFORE making a judgment about the cause of a conflict, a test failure, or an artifact dispute. Defines the end-to-end verification method L1→L6 and the classification of the first broken link.
development
MUST use AFTER a work cycle with ≥2 iterations (wrote → error → fixed → success). Provides the retrospective procedure and the format for recording practice/anti-patterns in references/learned-patterns.md or {project}/.context/learned-patterns.md.
tools
MUST use WHEN you are writing reusable knowledge into RLM (pattern / architectural decision / stable domain fact) OR reading it before a non-trivial task/solution in the domain. Provides the breakdown of native-push vs RLM-pull, tools for writing and reading RLM, H-MEM levels, and hygiene.
testing
MUST use WHEN the task is classified as simple (< 20 lines, 1 file, no new metadata objects, no architectural decisions). Provides a short cycle of 3 steps with a guard on the self path and mandatory verify.