Раздутые общие модули в УТ 11.5: посчитала метрики 2711 модулей и проверила рейтинг
Разработка - Рефакторинг и качество кода
Файлы
ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.
Подписка PRO — скачивайте любые файлы со скидкой до 85% из Базы знаний
Оформите подписку на компанию для решения рабочих задач
Оформить подписку и скачать решение со скидкойВы можете заказать платную доработку или адаптацию этой разработки под вашу конфигурацию на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
Метрики из исходников быстро показывают, где сосредоточен код конфигурации, но рейтинг нельзя применять без проверки: он считает тексты запросов кодом и не видит часть вызовов.
- 81 модуль длиннее 5000 строк кода хранит 43,1 % кода всех общих модулей.
- Два из десяти самых длинных модулей (расчёт себестоимости) на 80,6 и 87,0 % состоят из строк текста запросов.
- 301 модуль из 2711 не имеет вызывающих по счёту скрипта; 16 из них названы обработчиками подписок и заданий.
Рейтинг годится, чтобы составить список кандидатов на осмотр. Решение о разбиении принимается после чтения самого модуля.
Для кого: разработчики и ведущие разработчики 1С, которые сопровождают большую типовую или собственную конфигурацию и хотят подкрепить планирование рефакторинга цифрами.
Общие модули по 20 тысяч строк в типовой конфигурации встречаются часто. Чтобы решить, какой из них разбирать первым, нужны цифры: впечатления от прокрутки недостаточно. Я написала скрипт, который считает метрики общих модулей по выгрузке конфигурации, и проверила его рейтинг на УТ 11.5 и на небольшой учебной конфигурации.
Стенд
Скрипту нужна выгрузка конфигурации в файлы: каталог с CommonModules и файлы BSL остальных объектов. Платформа 1С при подсчёте не запускалась. Копия файлов лежала вне облачной синхронизации.
| Условие | Значение |
|---|---|
| Компьютер | Windows 11 Pro, Intel Core i5-2400, 7,9 ГБ ОЗУ, SATA SSD; рабочая машина с открытыми приложениями |
| Инструмент | Python 3.12.10, стандартная библиотека |
| Платформа | 1С:Предприятие 8.3 не запускалось: выгрузки читаются как текст |
| Основная выгрузка | УТ 11.5, версия 11.5.22.77, типовая, без расширений: 2711 общих модулей, 12 290 файлов BSL |
| Для сравнения | «Нано-УТ» из релизного комплекта 24.10.2026: 119 общих модулей, 211 файлов BSL |
| Полный разбор УТ | итоговый прогон 247,9 с, из них процессорного времени 50,8 с; в других запусках на этом же компьютере от 9 до 16 минут, пока диск был занят другими задачами (evidence/03, 09) |
Что считает скрипт
Для каждого файла CommonModules/Имя/Ext/Module.bsl скрипт убирает комментарии и содержимое строковых литералов, затем считает показатели из таблицы. Продолжения многострочных строк (символ | в начале) учитываются: слова внутри текста запроса не засчитываются ни как условия, ни как вызовы.
| Показатель | Как считается |
|---|---|
| code | непустые строки, которые не являются целиком комментарием |
| text | из code: строки-продолжения многострочных строк, то есть в основном тексты запросов |
| proc, exp | число процедур и функций; из них с ключевым словом Экспорт |
| max_proc | самая длинная процедура в физических строках, от заголовка до Конец... |
| max_cc | наибольшая цикломатическая сложность процедуры |
| fan_out | число других общих модулей, к которым обращается модуль (вид Имя.Метод) |
| fan_in | число объектов конфигурации, которые обращаются к модулю |
| cc/строка | сумма сложностей всех процедур, делённая на code |
Сложность процедуры равна 1 плюс число слов Если, ИначеЕсли, Для, Пока, Исключение, И, ИЛИ и выражений ?( вне строк и комментариев. Это приближение по ключевым словам, без дерева разбора.
Для fan_in объект определяется двумя первыми компонентами пути (Catalogs/Товары): модуль объекта и модуль формы одного справочника дают одного вызывающего.
Формула рейтинга
Пределы взяты из распределения самой УТ 11.5: это округлённые 99-е процентили (code 9669, max_proc 1222, max_cc 139, exports 153, fan_out 30). Модуль, который достиг предела по всем пяти показателям, получает 100. Веса и пределы выбраны мной, нормативом они служить не могут. Для небольшой конфигурации свои значения задаются параметром --caps. fan_in в формулу не входит: он показывает последствия правки и читается рядом с рейтингом.
Проверка счёта: пять модулей с ручным подсчётом
Прежде чем смотреть на УТ, я проверила сам счёт. В каталоге fixtures лежат пять синтетических модулей и три вызывающих объекта (модуль и форма справочника, модуль документа). Метрики посчитаны вручную до запуска и записаны в тестах.
| Модуль | Что проверяет | code | proc | exp | max_proc | max_cc | fan_out | fan_in |
|---|---|---|---|---|---|---|---|---|
| МалыйМодуль | слова Если, Для, Пока в строке и комментарии | 10 | 2 | 1 | 5 | 2 | 0 | 3 |
| ЦиклыИУсловия | Для, Если, И, ИначеЕсли, ИЛИ, Пока, Исключение, ?( | 19 | 1 | 1 | 19 | 9 | 0 | 1 |
| СпискиДанных | длинный список и текст запроса со словами-ключами | 39 | 2 | 2 | 34 | 1 | 0 | 0 |
| Связанный | вызовы двух модулей, упоминание в комментарии | 10 | 3 | 2 | 4 | 1 | 2 | 1 |
| ДлинныйЗаголовок | заголовок на трёх строках, Экспорт в третьей | 5 | 1 | 1 | 5 | 1 | 0 | 0 |
fan_in модуля МалыйМодуль равен трём: его вызывают Catalogs/Товары (из модуля объекта и из формы, один раз), Documents/Заказ и общий модуль Связанный.
Все 14 тестов проходят (evidence/01-tests.txt). Они проверяют также CRLF и BOM, экранированные кавычки, английские ключевые слова и каталог без CommonModules.
Ошибка, которую нашёл тест
В первой версии строки внутри многострочного текста запроса не считались кодом. Ручной подсчёт для СпискиДанных дал 39 строк, скрипт вывел 38: две строки-продолжения после вырезания содержимого строки становились пустыми. Теперь code считается по исходным строкам, а продолжения запроса вынесены в показатель text. Без этого теста длина всех модулей с большими запросами на УТ оказалась бы заниженной.
Второй способ на УТ
Код УТ устроен разнообразнее синтетических модулей, поэтому на восьми модулях УТ я пересчитала часть показателей намеренно грубым способом (crosscheck.py): процедуры по строкам, начинающимся с Процедура или Функция, и вызывающие объекты по вхождению Имя с точкой в текст файла без вырезания комментариев.
| Модуль | Процедур: скрипт | Процедур: грубо | Строк Конец... | Вызывающих: скрипт | Вызывающих: грубо |
|---|---|---|---|---|---|
| СервисДоставки | 345 | 345 | 345 | 13 | 27 |
| ПродажиСервер | 196 | 196 | 196 | 111 | 111 |
| СкладыСервер | 202 | 202 | 202 | 136 | 136 |
| ЭлектронноеАктированиеЕИС | 467 | 467 | 467 | 12 | 34 |
| ИнтеграцияЕГАИС | 176 | 176 | 176 | 33 | 42 |
| НастройкиСистемы | 12 | 12 | 12 | 3 | 5 |
| РасчетСебестоимостиНДС | 143 | 143 | 143 | 9 | 9 |
| ОбменСКонтрагентамиУТ | 387 | 387 | 387 | 45 | 45 |
(evidence/10-crosscheck.txt)
Число процедур совпадает в обоих счётах. Грубый счёт вызывающих не может быть меньше основного, и это выполняется для всех восьми модулей. У четырёх модулей он больше: грубый счёт засчитывает комментарии, строки и совпадения в конце длинного имени, причины по каждому модулю я не разбирала.
Что нашлось в УТ 11.5
Распределение по 2711 общим модулям (evidence/05-ut115-stats.txt):
| Показатель | Медиана | 90 % | 99 % | Максимум |
|---|---|---|---|---|
| code | 135 | 1698 | 9669 | 68 310 |
| max_proc | 48 | 284 | 1222 | 6001 |
| max_cc | 7 | 39 | 139 | 794 |
| fan_in | 3 | 27 | 234 | 2425 |
Всего в общих модулях 2 057 693 строки кода. Модулей от 3000 строк кода 149, они содержат 55,9 % кода; от 5000 - 81 модуль, 43,1 %; от 10 000 - 26 модулей, 24,1 %; от 20 000 - 10 модулей, 14,0 %. Первые 25 строк рейтинга содержат 20,7 % кода. На строки-продолжения многострочных строк (text) приходится 461 468 строк, 22,4 % всего кода общих модулей.
Строки рейтинга с первой по четвёртую, седьмая и десятая (evidence/03-ut115-run.txt):
| Модуль | score | code | max_proc | max_cc | fan_out | fan_in |
|---|---|---|---|---|---|---|
| ОбменСКонтрагентамиУТ | 100,0 | 26 743 | 1304 | 235 | 78 | 45 |
| РасчетСебестоимостиПрикладныеАлгоритмы | 95,0 | 20 392 | 899 | 158 | 30 | 162 |
| ПродажиСервер | 94,3 | 17 472 | 1270 | 263 | 46 | 111 |
| ИнтеграцияСМаркетплейсомOzonСервер | 92,8 | 22 458 | 853 | 157 | 30 | 10 |
| ВзаиморасчетыСервер | 90,3 | 23 146 | 860 | 112 | 30 | 149 |
| МенеджерОбменаЧерезУниверсальныйФормат | 86,1 | 68 310 | 2855 | 794 | 60 | 0 |
ВзаиморасчетыСервер и РасчетСебестоимостиПрикладныеАлгоритмы вызывают 149 и 162 объекта: правка затронет много мест. ИнтеграцияСМаркетплейсомOzonСервер вызывают 10 объектов, перенос его частей рискует меньше. Рейтинг этой разницы не показывает, поэтому рядом стоит fan_in.
Где рейтингу верить нельзя
Самый длинный модуль уступает девяти более коротким
МенеджерОбменаЧерезУниверсальныйФормат длиннее остальных: 68 310 строк кода, 1800 процедур, процедура на 2855 строк, сложность до 794. В рейтинге у него 86,1, десятая строка списка. Показатели code, max_proc и max_cc у него превысили пределы и дают максимум, а экспортных процедур всего 11, вклад exports равен 1,1 из 15. Рейтинг с пределами насыщается: после порога разница между 20 000 и 68 000 строк в нём не видна.
У этого модуля fan_in равен нулю. Поиск по тексту нашёл его имя в одном месте: в модуле ОбменДаннымиУТ он добавляется в структуру версий формата как значение.
Обращения вида Имя.Метод здесь нет: модуль передаётся как объект. Скрипт ищет только Имя с точкой и записал нулевую связанность. Решив по этому показателю, что модуль никому не нужен, я бы ошиблась.
Длинные модули, состоящие из запросов
Среди модулей длиннее 5000 строк кода самая низкая плотность ветвлений у модулей расчёта себестоимости (evidence/05-ut115-stats.txt).
| Модуль | code | доля text | cc/строка | Место в рейтинге |
|---|---|---|---|---|
| РасчетСебестоимостиНДС | 24 218 | 87,0 % | 0,021 | 28 |
| РасчетСебестоимостиКорректировкаСтоимости | 21 394 | 80,6 % | 0,020 | 27 |
| РасчетСебестоимостиРешениеСЛУ | 5636 | 84,4 % | 0,018 | 122 |
От 80 до 87 % строк этих модулей относятся к многострочным строкам, в первую очередь к текстам запросов (evidence/08-query-share.txt). Для сравнения, у ОбменСКонтрагентамиУТ доля text 11,3 %, у СервисДоставки 4,9 %. Модуль с набором запросов читается иначе, чем модуль с логикой на 20 тысяч строк. Большая доля запросов есть и у модулей из верхней части списка: у СкладыСервер 67,6 %, у ПродажиСервер 53,1 %.
Короткие, но сложные
Среди модулей до 600 строк кода самая высокая сложность процедуры у НастройкиСистемы: 486 строк, процедура на 467 строк, сложность 149. В рейтинге модуль стоит 179-м. Рейтинг его почти не выделяет: размер и число экспортных процедур малы. Такие процедуры видны только в колонках max_cc и max_proc.
Нулевая связанность и подписки
В УТ 301 модуль имеет fan_in, равный нулю, из них 4 длиннее 1000 строк кода. Я проверила, не названы ли они обработчиками подписок на события или регламентных заданий (evidence/07-zero-fanin.txt, 509 файлов метаданных). Обработчиками названы 16 модулей из 301, среди них ОбменДаннымиПодключаемоеОборудованиеOfflineСобытия (474 строки кода) и ОбщегоНазначенияУТСобытия (238 строк). Ни один из четырёх длинных модулей обработчиком не назван, но один из них, МенеджерОбменаЧерезУниверсальныйФормат, используется. Удалять модуль по нулевому fan_in можно только после поиска его имени по всей конфигурации и проверки метаданных.
Планирование разбиения: режим --plan
Режим --plan строит граф внутренних вызовов процедур модуля и показывает связные группы: число процедур, строк, экспортных процедур и внешних объектов, которые вызывают хотя бы одну процедуру группы. Группа с малым числом внешних вызывающих легко переносится в новый модуль. Я запустила режим на трёх модулях (evidence/03-ut115-run.txt).
СкладыСервер
202 процедуры, 159 внутренних вызовов, 75 групп. Три крупные группы:
| Группа | Процедур | Строк | Экспортных | Внешних вызывающих объектов |
|---|---|---|---|---|
| 1 (размещение и отбор товара в ячейках) | 30 | 6740 | 9 | 5 |
| 2 (ордерная схема при отгрузке) | 31 | 4513 | 17 | 46 |
| 3 (планирование поступления товаров) | 31 | 4430 | 18 | 33 |
Названия в скобках - моя расшифровка по именам первых процедур группы. Группу 1 извне вызывают 5 объектов, она занимает 6740 строк процедур и остаётся ближайшим кандидатом на перенос в отдельный модуль. Группы 2 и 3 вызываются из многих мест. Тексты запросов входят в строки процедур.
ПродажиСервер
196 процедур, 226 внутренних вызовов, 61 группа. Первая группа объединяет 84 процедуры и 9964 строки, её вызывают 30 внешних объектов. Вторая по размеру: 27 процедур, 2833 строки, 4 внешних вызывающих. Одна большая группа по вызовам не делится, шов придётся искать по смыслу процедур.
СервисДоставки
345 процедур, 513 внутренних вызовов, 83 группы. 258 процедур с 11 288 строками и 103 экспортными объединены в одну группу. В журнале показаны первые 12 групп; со второй по двенадцатую в каждой одна-две процедуры. Дешёвого шва скрипт не нашёл. Возможно, одна-две процедуры вызываются почти отовсюду и связывают всё в одну группу, но это предположение: я не читала код модуля и не убирала такие процедуры из графа.
Режим --plan показывает, где модуль уже распадается по вызовам. Он не знает, что процедуры работают с одним документом или регистром, и не видит общих переменных модуля.
Та же проверка на «Нано-УТ»
Для сравнения я запустила скрипт на «Нано-УТ» (evidence/04-nano-run.txt, 06-nano-stats.txt): 119 общих модулей, 2338 строк кода. Самый длинный модуль ТоварыУчет содержит 247 строк кода, 99-й процентиль code равен 187. С пределами для УТ лучший результат у ОтчетыСервер, 12,0 из 100. Монстров в этой конфигурации нет. Режим --plan у ТоварыУчет показывает три группы на 10, 5 и 2 процедуры с 3, 13 и 18 внешними вызывающими; для модуля в 247 строк такое разбиение не нужно.
Что проверить у себя
- Выгрузите конфигурацию в файлы и запустите скрипт с параметром --csv.
- Для небольшой конфигурации задайте свои пределы через --caps.
- Для кандидатов из верхней части списка сравните code, text, max_cc и fan_in.
- Перед выделением частей модуля запустите --plan для него и прочитайте группы с малым числом внешних вызывающих.
- Модуль с fan_in = 0 ищите по имени во всей конфигурации и в подписках, регламентных заданиях.
В архиве monster-modules-19-3-companion.zip: скрипт, 14 тестов с синтетическими модулями, вспомогательные скрипты, README.md и журналы запусков из статьи.
Пределы
- Платформа 1С при подсчёте не использовалась: метрики берутся из текста, сложность считается по ключевым словам.
- Скрипт не видит вызовы через Вычислить и Выполнить, имя модуля в переменной и модуль, переданный как значение. Последний случай встретился в УТ.
- Обращения из расширений и внешних обработок видны, только если их исходники лежат в том же каталоге. Расширения УТ я не разбирала.
- Веса и пределы рейтинга выбраны по одной конфигурации; на других релизах УТ и других конфигурациях результаты не проверялись.
- Названия групп СкладыСервер даны по именам первых процедур; код я не читала.
Итог
Метрики из исходников отвечают на вопрос, где в конфигурации сосредоточен код: 81 модуль длиннее 5000 строк хранит 43,1 % кода всех общих модулей УТ 11.5, а 26 модулей длиннее 10 000 строк хранят 24,1 %. Рейтинг собирает список кандидатов, но места в нём нельзя читать как приговор: самый длинный модуль оказался ниже девяти более коротких, модули себестоимости на 80-87 % состоят из запросов, а модуль без вызовов по счёту скрипта используется.
Режим разбиения работает как подсказка: у СкладыСервер он нашёл группу в 6740 строк с 5 внешними вызывающими объектами, у СервисДоставки шва не нашёл. Переносить код стоит после чтения самих групп. Проверка на синтетических модулях выявила ошибку в подсчёте строк, пересчёт процедур вторым способом расхождений не дал.
Вступайте в нашу телеграмм-группу Инфостарт