framework/skills/bsl-practices/ssl-patterns/SKILL.md
MUST use WHEN используешь или расширяешь функциональность БСП (Библиотека стандартных подсистем). Provides каталог готовых функций ОбщегоНазначения и правила вызова подсистем без дублирования.
npx skillsauth add steelmorgan/1c-agent-based-dev-framework ssl-patternsInstall 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.
Код БСП проверен на миллионах установок, обновляется централизованно, знаком другим разработчикам. Дублирование БСП — антипаттерн.
Сигнатуры функций БСП — через
get_signature_help. У функцийОбщегоНазначенияи прочих модулей БСП много параметров и перегрузок; не угадывайте порядок и состав аргументов. В точке вызоваget_signature_help(uri, line, character)показывает параметры и перегрузки вызываемого метода прямо по месту — без открытия определения модуля БСП. Применяйте при вызове любой функции из каталога ниже, если не уверены в сигнатуре.
Прежде чем писать свою реализацию, проверьте — возможно, в БСП уже есть готовая функция.
| Функция | Когда использовать |
|---------|-------------------|
| ЗначениеРеквизитаОбъекта() | Вместо Ссылка.Реквизит (избегаем точечную нотацию) |
| ЗначенияРеквизитовОбъекта() | Несколько реквизитов одним вызовом |
| СообщитьПользователю() | Сообщение с привязкой к полю (вместо Сообщить()) |
| МенеджерОбъектаПоСсылке() | Вместо Выполнить("Справочники." + Имя) |
| ПодсистемаСуществует() | Условный вызов модулей |
| ОбщийМодуль() | Динамический вызов модуля БСП |
| ЭтоСсылка() | Валидация параметров |
| СсылкаСуществует() | Проверка перед обращением |
// ПЛОХО: три обращения к БД через точку
Наименование = КонтрагентСсылка.Наименование;
ИНН = КонтрагентСсылка.ИНН;
Ответственный = КонтрагентСсылка.ОсновнойМенеджер;
// ПРАВИЛЬНО: одно обращение через БСП
РеквизитыКонтрагента = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(
КонтрагентСсылка,
"Наименование, ИНН, ОсновнойМенеджер");
Модуль содержит оптимизированные функции, корректно обрабатывающие edge cases.
| Функция | Когда использовать |
|---------|-------------------|
| ПодставитьПараметрыВСтроку() | Аналог СтрШаблон(), с дополнительными проверками |
| СтрокаСЧисломПредметов() | Склонение: «5 документов», «1 документ» |
| ЕстьНедопустимыеСимволы() | Валидация ввода |
| ТолькоЦифрыВСтроке() | Валидация ИНН, КПП |
| РазложитьСтрокуВМассивПодстрок() | Парсинг по разделителю |
// Склонение: «1 документ», «2 документа», «5 документов»
ТекстОповещения = СтроковыеФункцииКлиентСервер.СтрокаСЧисломПредметов(
КоличествоДокументов,
НСтр("ru = 'документ, документа, документов'"));
Директива &НаКлиентеНаСервереБезКонтекста — доступен и на клиенте, и на сервере.
| Функция | Описание |
|---------|----------|
| ДополнитьМассив() | Объединение двух массивов |
| ДополнитьСтруктуру() | Объединение двух структур |
| СвойствоСтруктуры() | Безопасное чтение свойства (значение по умолчанию если нет) |
| ПроверитьПараметр() | Валидация типа с информативной ошибкой |
// Безопасный доступ с значением по умолчанию
ДатаНачала = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(
ПараметрыОтчёта, "ДатаНачала", НачалоГода(ТекущаяДатаСеанса()));
navigate_symbol("ЗначенияРеквизитовОбъекта")grep -r "Функция.*КурсВалюты" src/CommonModules/| Ситуация | Решение | |----------|---------| | В БСП есть подходящая функция | Используй БСП | | В БСП есть похожая, но с лишним функционалом | Используй БСП — лишнее не мешает | | Нужной функции нет в БСП | Пиши своё в стиле БСП | | Конфигурация без БСП | Пиши своё |
См. error-handling, правило 7.
Прямая работа с файлами не учитывает: права доступа, временные файлы, кросс-платформенность.
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
Попытка
ТабличныйДокумент.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.XLSX);
// ... работа с файлом ...
Исключение
// Обработка ошибки
КонецПопытки;
// Явное удаление
УдалитьФайлы(ИмяВременногоФайла);
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
Если НЕ ЗначениеЗаполнено(Контрагент) Тогда
ОбщегоНазначения.СообщитьПользователю(
НСтр("ru = 'Не заполнен контрагент.'"),
ЭтотОбъект, "Контрагент",, Отказ);
КонецЕсли;
// Условное исключение реквизитов из проверки
Если ВидОперации = Перечисления.ВидыОпераций.Услуга Тогда
ОбщегоНазначенияКлиентСервер.УдалитьЗначениеИзМассива(
ПроверяемыеРеквизиты, "Склад");
КонецЕсли;
КонецПроцедуры
Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм,
ОбъектыПечати, ПараметрыВывода) Экспорт
Если УправлениеПечатью.НужноПечататьМакет(КоллекцияПечатныхФорм, "Счёт") Тогда
ТабличныйДокумент = Новый ТабличныйДокумент;
ТабличныйДокумент.КлючПараметровПечати = "Документ.РеализацияТоваровУслуг.Счёт";
УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
КоллекцияПечатныхФорм, "Счёт", НСтр("ru = 'Счёт на оплату'"),
ТабличныйДокумент);
КонецЕсли;
КонецПроцедуры
| Что часто пишут сами | Что есть в БСП |
|----------------------|----------------|
| Получение реквизита по ссылке | ОбщегоНазначения.ЗначениеРеквизитаОбъекта() |
| Подстановка в строку | СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку() |
| Склонение слов | СтроковыеФункцииКлиентСервер.СтрокаСЧисломПредметов() |
| Отправка почты | РаботаСПочтовымиСообщениями |
| Курс валюты | РаботаСКурсамиВалют.ПолучитьКурсВалюты() |
| Длительная операция в фоне | ДлительныеОперации.ВыполнитьФункцию() |
| Хранение секретов / паролей | БезопасноеХранилище.ПрочитатьДанные() |
| Профили прав доступа | ГруппыДоступаПользователей / ПрофилиГруппДоступа |
| Регистрация внешней обработки | СведенияОВнешнейОбработке() |
| Суффикс модуля | Среда | Пример |
|----------------|-------|--------|
| (без суффикса) | Сервер | ОбщегоНазначения |
| Клиент | Клиент | ОбщегоНазначенияКлиент |
| КлиентСервер | Обе среды | ОбщегоНазначенияКлиентСервер |
| ПовтИсп | Сервер, с кэшированием | ОбщегоНазначенияПовтИсп |
Для клиентского кода формы — ищите сначала в *КлиентСервер, потом в *Клиент. Для серверного — в основном модуле (без суффикса). *ПовтИсп — для часто запрашиваемых справочных данных.
Используй подсистему ДлительныеОперации для любой серверной работы дольше ~3 сек. Не блокируй UI самодельным циклом ожидания.
// Запуск фоновой задачи
&НаСервере
Функция ЗапуститьОперацию(Параметры)
ПараметрыФона = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
ПараметрыФона.НаименованиеФоновогоЗадания = НСтр("ru = 'Обработка данных'");
Возврат ДлительныеОперации.ВыполнитьФункцию("ОбщийМодуль.ФункцияДляФона",
ПараметрыФона, Параметры);
КонецФункции
// Подключение ожидания на клиенте
&НаКлиенте
Процедура ЗапуститьОперациюНаКлиенте()
Операция = ЗапуститьОперацию(ПараметрыРасчёта);
ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
ПараметрыОжидания.ВыводитьПрогресс = Истина;
ДлительныеОперацииКлиент.ОжидатьЗавершение(Операция,
Новый ОписаниеОповещения("ОперацияЗавершена", ЭтотОбъект), ПараметрыОжидания);
КонецПроцедуры
// Обработка результата
&НаКлиенте
Процедура ОперацияЗавершена(Операция, ДополнительныеПараметры) Экспорт
Если Операция = Неопределено Тогда
Возврат; // Отменена пользователем
КонецЕсли;
Если Операция.Статус = "Ошибка" Тогда
СтандартныеПодсистемыКлиент.ОбработатьОшибкуФоновогоЗадания(Операция);
Возврат;
КонецЕсли;
// Получить результат
РезультатОперации = ПолучитьРезультатСервер(Операция.АдресРезультата);
КонецПроцедуры
Ключевые правила:
ДлительныеОперации.СообщитьПрогресс() внутри фоновой процедуры.Никогда не храни пароли, токены и секреты в:
// Запись секрета
БезопасноеХранилище.Записать(ЭтотОбъект, Новый Структура("Пароль", ПарольПользователя));
// Чтение секрета
ДанныеХранилища = БезопасноеХранилище.ПрочитатьДанные(ЭтотОбъект);
Если ДанныеХранилища <> Неопределено Тогда
Пароль = ДанныеХранилища.Пароль;
КонецЕсли;
// Удаление при удалении объекта
БезопасноеХранилище.Удалить(ЭтотОбъект);
В обработчике ПередУдалением объекта всегда вызывай БезопасноеХранилище.Удалить() — иначе «осиротевшие» записи накапливаются в хранилище.
При разработке подсистем с ролевым доступом — используй механизм профилей БСП вместо прямого назначения ролей.
// Пример описания профиля в ОписаниеПрофилейГруппДоступа()
Профиль = УправлениеДоступом.ОписаниеПрофиля();
Профиль.Идентификатор = "ИдентификаторПрофиля_UUID";
Профиль.Наименование = НСтр("ru = 'Менеджер по продажам'");
Профиль.Роли.Добавить("РольМенеджерПродаж");
Профили.Добавить(Профиль);
Ключевые правила:
ПривилегированныйРежим() строго локально, сразу снимай после операции.УправлениеДоступом.ПроверитьДопустимостьДействия(), не через РольДоступна() напрямую — последнее не учитывает RLS.Регистрация внешней обработки в БСП-базе требует функции СведенияОВнешнейОбработке() в основном модуле обработки.
// В модуле обработки
Функция СведенияОВнешнейОбработке() Экспорт
СведенияОВнешнейОбработке = ДополнительныеОтчётыИОбработки.СведенияОВнешнейОбработке();
СведенияОВнешнейОбработке.Вид = ДополнительныеОтчётыИОбработкиКлиентСервер
.ВидОбработки().ДополнительнаяОбработка;
СведенияОВнешнейОбработке.Наименование = НСтр("ru = 'Моя обработка'");
СведенияОВнешнейОбработке.Версия = "1.0";
СведенияОВнешнейОбработке.БезопасныйРежим = Истина;
// Описание команды
Команда = СведенияОВнешнейОбработке.Команды.Добавить();
Команда.Представление = НСтр("ru = 'Выполнить'");
Команда.Идентификатор = "Выполнить";
Команда.ИспользованиеКонтекста = ДополнительныеОтчётыИОбработкиКлиентСервер
.ИспользованиеКонтекстаКоманды().ВПроцедуреВыполнитьКоманду;
Возврат СведенияОВнешнейОбработке;
КонецФункции
// Точка входа для команды
Процедура ВыполнитьКоманду(Идентификатор, ПараметрыКоманды, ОбъектыНазначения) Экспорт
// ... реализация ...
КонецПроцедуры
Если search_ssl_functions не дал результата — ask_ai_assistant (шаблон VALIDATE_BSL из buddy-prompting): передать фрагмент кода, получить рекомендации по замене на методы БСП. Также SEARCH_DOCS для документации по конкретному методу БСП.
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.