12 октября 2026 г.
Как избежать циклических зависимостей в 1С с помощью графа: практический гид по Grafon
Почему цикл в графе зависимостей 1С — это дорого
Циклическая зависимость в конфигурации 1С — это ситуация, когда узел A зависит от B, B зависит от C, а C снова зависит от A. В типовых ERP, УТ, ЗУП и КА такие циклы прорастают годами: их создают доработки, общие модули, подписки на события, формы и обработчики объектов. Проблема не в том, что «1С не запустится», а в том, что:
- растёт время сборки и перепроведения документов из-за каскадных вызовов;
- любое изменение в модуле A «тянет» пересборку полконфигурации;
- ИИ-ассистент, которому скормили весь модуль целиком, тонет в сотнях килобайт BSL и начинает галлюцинировать.
Граф зависимостей — это формальная модель, поверх которой задачу «найти и разорвать цикл» можно решать алгоритмически, а не глазами. Именно эту модель строит локальный MCP-сервер Grafon.
Что такое граф зависимостей конфигурации 1С
Граф 1С — это ориентированный граф G = (V, E), где:
Узлы (V)
- объекты метаданных:
Документ,Справочник,Регистр,ПланВидовХарактеристик; - модули:
ОбщийМодуль.Продажи,Документ.РеализацияТоваров.МодульОбъекта,Форма.РеализацияТоваров.ФормаДокумента; - процедуры и функции BSL с сигнатурами;
- подписки на события и обработчики;
- запросы к БД и используемые в них таблицы.
Рёбра (E)
- вызов
Функция → Функциявнутри BSL; - обращение к метаданным через
Ссылка,Документы.РеализацияТоваров,РегистрыНакопления.ТоварыНаСкладах; #Вставка/#Областьмежду модулями;- регистрация подписки:
Подписка.ПередЗаписьюДокумента → Обработчик; - чтение/запись реквизитов и табличных частей.
Цикл в таком графе — это контур A → B → C → A. Графон находит контуры за доли секунды, даже если в конфигурации сотни тысяч рёбер.
Как выглядит цикл в BSL: три реальных примера
Пример 1. Два общих модуля
// ОбщийМодуль.Себестоимость
Функция Рассчитать(Ссылка) Экспорт
Курс = СкладскиеОперации.ПолучитьКурс(Ссылка); // ребро A → B
Возврат Курс * ПолучитьКоличество(Ссылка);
КонецФункции
// ОбщийМодуль.СкладскиеОперации
Функция ПолучитьКурс(Ссылка) Экспорт
База = Себестоимость.ПолучитьБазу(Ссылка); // ребро B → A — цикл
Возврат База.Курс;
КонецФункции
// ОбщийМодуль.Себестоимость
Функция ПолучитьБазу(Ссылка) Экспорт
Возврат РегистрыСведений.КурсыВалют.ПолучитьПоследний(Ссылка);
КонецФункции
Формально компилятор 1С такое пропустит, но при вызове Рассчитать() получите либо рекурсию, либо неявное зацикливание бизнес-логики.
Пример 2. Подписка на событие как источник цикла
// Подписка "ПриЗаписиРеализацииТоваров"
Процедура ПриЗаписиДокумента(Источник, Отказ) Экспорт
Уведомления.ПроверитьЗадолженность(Источник); // C
КонецПроцедуры
Внутри Уведомления.ПроверитьЗадолженность выполняется Записать() по тому же документу — и снова срабатывает подписка. Граф показывает это как цикл Подписка → Обработчик → ЗаписьОбъекта → Подписка.
Пример 3. Объект → менеджер → объект
// МодульОбъекта.РеализацияТоваров
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
ПроверитьОстатки(); // вызов менеджера
КонецПроцедуры
// Менеджер.РеализацияТоваров
Процедура ПроверитьОстатки() Экспорт
Док = Документы.РеализацияТоваров.СоздатьДокумент(); // снова объект того же типа
КонецПроцедуры
Архитектура Графона: как граф ускоряет ИИ-агента
Grafon разворачивается локально и индексирует выгрузку конфигурации в XML/EDT. Схема работы:
- Индексатор парсит метаданные и BSL, строит граф в локальном сторе (SQLite/граф).
- MCP-сервер поднимает протокол Model Context Protocol на localhost.
- ИИ-агент (Claude Code, Cursor, Windsurf, Roo Code) подключается к MCP и вызывает инструменты.
- Агент получает только срез — конкретные функции, сигнатуры, путь цикла, а не всю конфигурацию.
Ключевое отличие от «скормить весь проект»: агент видит граф как навигационную карту и запрашивает ровно те узлы, которые ему нужны для задачи.
Практика: находим циклы через MCP
Запрос на поиск всех контуров в общих модулях:
{
"tool": "grafon.find_cycles",
"arguments": {
"scope": ["CommonModules", "ObjectModules.ManagerModules"],
"max_depth": 8,
"min_weight": 1
}
}
Ответ Графона (фрагмент):
{
"cycles": [
{
"path": [
"CommonModule.Себестоимость.Рассчитать",
"CommonModule.СкладскиеОперации.ПолучитьКурс",
"CommonModule.Себестоимость.ПолучитьБазу",
"CommonModule.Себестоимость.Рассчитать"
],
"weight": 3,
"files": ["CommonModules/Себестоимость/Module.bsl", "CommonModules/СкладскиеОперации/Module.bsl"]
}
]
}
Запрос зависимостей отдельного узла:
{
"tool": "grafon.get_dependencies",
"arguments": {
"node": "CommonModule.Продажи",
"direction": "both",
"depth": 3,
"include_signatures": true
}
}
Ответ — компактный JSON с сигнатурами, без тел функций. Именно этот «сжатый срез» агент подставляет в контекст вместо 800 КБ модулей.
Как разорвать цикл: рабочий алгоритм
- Найти контур через
grafon.find_cycles. - Определить точку разрыва — узел с минимальным числом внешних зависимостей (обычно это «функция-слуга» вроде
ПолучитьКурс). - Инвертировать зависимость через интерфейс или общий модуль-фасад.
- Проверить повторным запуском
find_cycles.
Пример рефакторинга цикла из Примера 1:
// ОбщийМодуль.КурсыФасад — новый слой без обратных вызовов
Функция ПолучитьКурсДляСебестоимости(Ссылка) Экспорт
Возврат РегистрыСведений.КурсыВалют.ПолучитьПоследний(Ссылка);
КонецФункции
// ОбщийМодуль.Себестоимость
Функция Рассчитать(Ссылка) Экспорт
Курс = КурсыФасад.ПолучитьКурсДляСебестоимости(Ссылка);
Возврат Курс * ПолучитьКоличество(Ссылка);
КонецФункции
Теперь рёбра графа Себестоимость → КурсыФасад и СкладскиеОперации → КурсыФасад, но обратных вызовов нет — контур разорван.
Сравнение: с Графоном и без
| Метрика | Без Графона (сырой контекст) | С Графоном (MCP-срез) |
|---|---|---|
| Токенов на задачу «найти циклы» | 180–260 тыс. | 12–25 тыс. |
| Время ответа агента | 3–6 мин | 20–40 сек |
| Галлюцинации методов | Частые | Практически отсутствуют |
| Точность пути цикла | Ручной анализ | Машинный JSON |
| Работа с ERP 2.5 (гигабайты XML) | Падает по контексту | Стабильно |
Экономия — до 10 раз по токенам и более чем в 5 раз по времени на типовых задачах рефакторинга архитектуры.
Практические сценарии
- Аудит перед обновлением типовой. Перед переходом на новый релиз ERP запустите
find_cycles— получите список мест, где ваши доработки конфликтуют с новыми механизмами. - Code review ИИ-агентом. Cursor или Claude Code через Grafon смотрят только изменённые узлы графа и их соседей, а не всю конфигурацию.
- Онбординг нового разработчика. Граф в визуализации — карта конфигурации за несколько минут вместо чтения сотен модулей.
- Контроль архитектуры в CI. Регулярный запуск
find_cyclesиfind_dead_codeв pipeline блокирует коммиты с новыми циклами.
Чек-лист: как не создать цикл в 1С
- Общие модули делить по слоям: домен → сервисы → фасады. Рёбра разрешены только «сверху вниз».
- Никогда не вызывать из модуля объекта менеджер того же объекта.
- В подписках на события использовать проверку
ОбменДанными.Загрузкаи не вызыватьЗаписать()повторно. - Вместо взаимных вызовов
A ↔ Bвводить третий модуль-фасад. - Каждый новый общий модуль проверять через
grafon.get_dependenciesдо коммита.
Граф зависимостей — это не академическое упражнение, а рабочий инструмент. В связке с Grafon и MCP-агентами он превращает поиск циклических зависимостей 1С из многодневного расследования в секундную операцию — и одновременно экономит 90% бюджета токенов, которые обычно сгорают на переполнение контекста.