Анализ кода внешних обработок 1С: как проверить чужой .epf и не читать его целиком
Иван Недомолков · Опубликовано: · Обновлено:
Возьмите базу, которой больше трёх лет, и откройте в ней справочник “Дополнительные отчёты и обработки”. Позиций там наберётся два-три десятка: какие-то писали вы, какие-то остались от прошлого разработчика или пришли от подрядчика, а откуда взялись ещё несколько, не помнит уже никто. Каждая запускается с правами пользователя, лезет в базу, проводит документы, дёргает HTTP. А в редакторе их код так ни разу никто и не открыл.
Мы посчитали это по десяти продуктивным базам, которые ведём: 575 внешних обработок, из них живых без пометки удаления 548, реально опубликованных и работающих 501. Подробности замера в разборе про один MCP-сервер на десять баз. Пятьсот одна работающая обработка - это пятьсот одна причина, по которой две одинаковые с виду базы ведут себя по-разному. И столько же мест, которые может сломать обновление типовой: метод общего модуля, который обработка зовёт, в новом релизе пропал, а узнаёте вы об этом на строке вызова. Такие вызовы до обновления находит проверка внешних обработок перед обновлением 1С.
Ниже разбор того, как этот слой проверять: что искать глазами, где обычный поиск по тексту врёт, как из находок получается решение и во что всё это выливается в часах. Короткая версия с историей самоаудита опубликована на Инфостарте, здесь полный чек-лист ручного ревью, разбивка каталога правил по категориям и раздел про границы метода, которым там не нашлось места. Отдельный класс риска появляется в день обновления типовой: обработка вызывает экспортный метод общего модуля, а в новом релизе его переименовали или убрали. Эту проверку мы вынесли в отдельную статью про внешние обработки после обновления 1С.
Начнём с неприятного, потому что иначе текст читается рекламой.
Мы прогнали анализатор по своим обработкам первыми
Семнадцать файлов, которые лежат на площадке и которые у нас покупают. 24 142 строки кода.
| Что получили | Значение |
|---|---|
| Замечаний всего | 239 |
| Из них критичных | 186 |
| Технический долг | 7 070 минут, почти пятнадцать рабочих дней по восемь часов |
| Красных светофоров | 2 |
Последнее место, 20 из 100 по индексу качества, у “Выгрузки структуры метаданных для нейросетей”: тридцать замечаний на 857 строк. Следом “Карта объёмов” с индексом 25: одиннадцать критичных находок на 444 строки, взвешенная плотность 991 на тысячу строк и вердикт “требует срочной переработки”. Исправление одного этого файла тянет на пять с половиной часов.
Отчёт снят 20.08.2026 версией анализатора 0.6.0, до починки. Ни одна из семнадцати обработок на момент публикации не переписана. Очередь на ремонт задаст тот же рейтинг, и первыми в ней стоят две красные.
Показываем это по одной причине. Легко написать статью об инструменте проверки кода, в которой автор безупречен, а весь плохой код лежит где-то у других. Собственный красный светофор доказывает работоспособность лучше любого описания правил.
Почему готовые анализаторы сюда не дотягиваются
Хорошие инструменты статического анализа для 1С существуют давно: SonarQube, BSL Language Server, АПК, EDT. Мы работаем с ними сами и вытеснять их не планируем. Просто сделаны они под другую задачу.
Их территория - код, который уже под контролем: репозиторий, конфигурация, ветка, сборка. Попасть туда код может, только став проектом, а для этого нужны git, выгрузка в исходники, Java, сервер анализа и человек, который всё это развернёт и будет чинить после каждой поломки. Команде разработчиков такие вложения окупаются. Когда же просят “вот обработка, глянь за десять минут”, порог входа неподъёмный.
В репозитории внешних обработок нет. Их место - справочник в базе и папка на сетевом диске, причём каждая упакована в двоичный .epf, и без конфигуратора исходников из него не достать. Для сборки таких файлов просто не существует.
Часть кода вам не принадлежит. Это купленный на площадке инструмент, работа подрядчика или наследство прошлой команды. Выгружать такое во внешний сервис анализа вы не вправе, а согласовать это со службой безопасности выйдет дороже, чем прочитать код самому.
Отсюда требование, которое определяет всё остальное: анализ чужого кода должен идти внутри вашего контура, без интернета и без внешних компонент.
Чек-лист ручного ревью: что искать в чужой обработке за десять минут
Если инструмента под рукой нет, порядок такой. Распакуйте .epf конфигуратором в исходники и идите по списку сверху вниз: он отсортирован по цене ошибки, а не по частоте.
- Запрос внутри цикла. Ищите
Выполнить(и смотрите, лежит ли вызов внутриЦикл. Ошибка дорожает линейно вместе с объёмом данных: десять записей проскочат незаметно, десять тысяч остановят обработку. - Запись объекта в цикле.
ПолучитьОбъект()иЗаписать()внутри перебора выборки. То же самое, только дороже по блокировкам. Код обработки из справочника в поиск по конфигурации не попадает, поэтому её стоит проверить, когда значение реквизита меняется неизвестно кем. - Выборка без отбора.
.Выбрать()без условий читает всю таблицу и фильтрует уже в коде. - Транзакция без отката.
НачатьТранзакциюесть,ОтменитьТранзакциюв блокеИсключениенет. Записи остаются заблокированными, а сеанс виснет, пока его не снимут руками. - Пустой блок
Исключение. Ошибка проглатывается молча. Опаснее всего такой блок вокруг отправки уведомлений: канал тихо отваливается, и о том, что алерты перестали доходить, узнают, только когда случится событие, ради которого их настраивали. - Хардкод пароля, токена, GUID. Пароль в тексте обработки читает любой, кто её открыл. GUID при переносе базы превращается в мину: ссылка есть, объекта нет. С паролем СУБД похожая история уровнем выше: его восстанавливает любой, кто читает файл кластера, и аудит паролей СУБД показывает, у каких баз он извлекается.
Выполнить()с кодом из переменной. Если в эту переменную приходит текст из файла или значение реквизита, обработка получает дыру размером с платформу.- Схема компоновки, а не только модуль. Во внешнем отчёте основной запрос сидит в схеме компоновки, в модуле его просто нет. Соединение с виртуальной таблицей,
ИЛИв условии соединения, трёхуровневое обращение через точку,ПОДОБНОс ведущим процентом - половина проблем с запросами живёт там, куда ревью модулей не заглядывает. - Длина процедуры и вложенность. Процедура длиннее 125 строк или глубже пяти уровней вложенности - повод посмотреть внимательнее, даже если правил она не нарушает.
Эти девять пунктов покрывают большинство причин, по которым обработка на тестовой базе летает, а на рабочей висит. Но проверять их поиском по тексту нельзя, и вот почему.
Четыре класса, в которых поиск по тексту врёт
Первую версию анализатора мы написали за один вечер на регулярных выражениях. Искала она .Выполнить( внутри Цикл, ПолучитьОбъект() в том же месте, пустое Исключение и склейку строк в цикле. Работала быстро, находок давала много и смотрелась солидно.
Потом взяли 32 срабатывания, снятых с реального кода, и сделали из них контрольный набор. Каждое проверяли три раза независимо, читая исходник всей процедуры, в которой стояла находка, а в отчёт прототипа не заглядывали: задача была найти, где он ошибся, подтверждать его никто не собирался.
| Вердикт | Позиций |
|---|---|
| Ложное срабатывание | 20 |
| Настоящий дефект | 7 |
| Спорно, надо смотреть глазами | 5 |
Семь настоящих из тридцати двух замечаний. Точность 22 процента.
Именно с таким ощущением от анализаторов многие и уходят: запустил, получил простыню, пролистал и закрыл. С правилами при этом всё в порядке. Поиск по тексту просто не видит, с чем имеет дело.
Находка внутри строки или комментария
Встречается чаще всего.
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Ссылка
|ИЗ
| Документ.РасходТовара.Товары КАК Товары";
Регулярка находит в этом тексте нужные слова и сообщает о находке, хотя перед ней строковый литерал. В контрольном наборе была позиция, похожая на запись объекта в цикле, а процедура на деле оказалась аккуратно батчированной: сработка пришлась на текст запроса. С комментариями так же: закомментированный код уже не код, но поиск по тексту разницы не видит.
Снимается лексером: посимвольный обход в трёх состояниях (код, литерал, комментарий). Литерал начинается с кавычки, сдвоенная кавычка внутри него значит экранирование, а // вне литерала начинает комментарий до конца строки.
Опасен этот класс направлением вранья. Промолчи регулярка, было бы полбеды, но она выдаёт ошибки за уверенные находки: отчёт выходит подробный, красивый и неверный, и разоблачит его только чтение исходников.
Цикл из соседней процедуры
У прототипа глубина вложенности циклов не сбрасывалась на выходе из процедуры. Цикл мог начаться и закончиться в одной процедуре, а находку из следующей он всё равно помечал как “внутри цикла”. Звучит “запрос внутри цикла” солидно, и на ревью такое пропускают: выяснять, тот ли это цикл, никто не станет.
Снимается парсером: дерево блоков и стек циклов, а токены Процедура, Функция, КонецПроцедуры, КонецФункции этот стек обнуляют.
Одно имя метода у разных объектов
КомпоновщикМакета.Выполнить(СКД, Настройки, ДанныеРасшифровки);
Здесь макет компонуется в памяти, до СУБД дело вообще не доходит. Регулярка же видит .Выполнить( в цикле, значит, запрос в цикле, значит, Blocker.
С Записать похожая картина. ДвоичныеДанные.Записать(Путь) сохраняет файл на диск, а ДокументОбъект.Записать() пишет в базу: слово одно, цена разная. А правило о конкатенации в цикле не отличит Счётчик = Счётчик + 1 от Лог = Лог + Строка.
Снимается трассировкой конструктора. Внутри процедуры ведётся таблица, где у каждой переменной записано, чем её создали. Новый Запрос отправляет переменную в список запросов, Новый КомпоновщикМакетаКомпоновкиДанных в список “не СУБД”, и правило о запросе в цикле смотрит только в первый. Полный вывод типов для встроенного языка тут не нужен, трассировки внутри процедуры достаточно.
Цикл, тело которого выполняется один раз
Для Каждого Строка Из Выборка Цикл
Объект = Строка.Ссылка.ПолучитьОбъект();
Возврат Объект;
КонецЦикла;
Если в той же ветке стоит безусловный Возврат или Прервать, цикл отработает не больше одного раза, и к производительности такая находка отношения уже не имеет. Снимается тем же деревом блоков. Нашёлся выход того же уровня вложенности между находкой и ближайшим КонецЦикла - находка опускается до информационной.
Практический вывод для ручного ревью. Каждую находку поиском по тексту надо проверять по четырём вопросам: не литерал ли это, тот ли цикл, тот ли объект, выполняется ли тело больше одного раза. Четыре вопроса на находку - это и есть та причина, по которой ревью чужой обработки занимает полдня, а не десять минут.
Как устроен движок, который эти четыре класса снимает
Под анализатором обычно понимают перечень плохих паттернов и программу, которая этот перечень обходит. У нас правила занимают только четвёртый слой из шести, а первые три слоя нужны ровно для того, чтобы находки не врали, как это делал прототип.
1. АДАПТЕРЫ ИСТОЧНИКА разные форматы входа -> единая модель
v
2. ЛЕКСЕР текст -> поток токенов
v
3. ПАРСЕР токены -> структура кода + разбор запросов
v
4. ПРАВИЛА каталог проверок по токенам и структуре
v
5. СКОРИНГ метрики, индекс качества, техдолг
v
6. ОТЧЁТ один самодостаточный HTML
Адаптеры источника. На вход приходит либо распакованный дамп .epf, либо конфигурация, выгруженная в файлы, и это два разных зверя. Каталоги у них устроены по-своему, модуль объекта лежит в другом месте, файлы форм названы иначе. Адаптер сводит оба варианта к общей модели, и следующим слоям уже всё равно, откуда код.
Лексер. Режет текст на токены. Ему известны комментарии, многострочные литералы через вертикальную черту, инструкции препроцессора и аннотации. Литералы, в которых угадывается текст запроса, он метит особо, чтобы следующий слой разобрал их как запрос.
Парсер. Собирает из токенов структуру: где проходят границы процедур, как вложены блоки, на какой глубине стоит каждый цикл и к какому циклу привязан вызов. В нём же сидит небольшой разборщик языка запросов, так что запросные правила получают запрос уже разобранным и с текстом не работают.
Правила. Ключевое свойство каталога записано в виде запрета: правило видит только токены и структуру, к сырому тексту его не пускают. Как только правило начинает искать подстроку, в него возвращаются все ошибки, от которых должны были спасать предыдущие слои.
Скоринг и отчёт. Метрики, индекс качества, долг в минутах и отчёт единым HTML-файлом без внешних зависимостей. Он откроется на любой машине с браузером, и его можно переслать подрядчику без всякой переделки.
Вокруг движка есть ещё две вещи, без которых он развалится на второй неделе. Первая - реестр правил в таблице значений: идентификатор, категория и профиль, уровень и вес, признак включения и имя процедуры. Диспетчер вызывает Выполнить("Правило_" + Имя + "(...)") по разу на правило и модуль, в цикле по токенам - никогда. Вторая - парные тесты на каждое правило: где оно обязано сработать и где обязано промолчать. Второй тест важнее. Научить правило ловить свой паттерн - дело получаса, а чтобы оно молчало на всём похожем, нужны ещё три захода, и без негативного теста до них никто не доходит.
Каталог правил: 28 включённых, разбивка по категориям
| Категория | Что смотрит | Включено правил |
|---|---|---|
| PERF | производительность модулей | 7 |
| SEC | безопасность | 6 |
| REL | надёжность | 3 |
| STD | метрики кода | 3 |
| QRY | запросы в модулях | 2 |
| По модулям всего | 21 | |
| SKD | запросы в схемах компоновки | 7 |
Кандидатов около семидесяти, включены двадцать восемь. В таблицах ниже из каждой категории взяты самые дорогие правила, с уровнем и весом. Вес задаёт, сколько минут стоит исправить одну находку, и на нём держатся технический долг и взвешенная плотность. Долг в семь тысяч минут из начала статьи - сумма весов по всем 239 находкам, в среднем по полчаса на каждую.
PERF, производительность.
| Что ищем | Уровень | Вес |
|---|---|---|
Запрос.Выполнить() внутри цикла | Blocker | 60 |
ПолучитьОбъект() или Записать() в цикле | Critical | 45 |
.Выбрать() без отбора | Critical | 40 |
| Конкатенация строк в цикле | Major | 20 |
QRY, запросы в модулях.
| Что ищем | Уровень | Вес |
|---|---|---|
| Соединение с подзапросом | Critical | 45 |
ВЫБРАТЬ * | Minor | 10 |
Дорого обходится соединение с подзапросом: статистики по нему у оптимизатора СУБД нет, и план он строит вслепую. Разбор того, чем это лечится, у нас в отдельном материале про приёмы оптимизации запросов 1С.
SKD, запросы в схемах компоновки. У схем свой проход и своя кнопка, а находок по запросам здесь набирается половина.
| Что ищем | Уровень | Вес |
|---|---|---|
| Соединение с виртуальной таблицей | Major | 30 |
ИЛИ в условии соединения | Major | 30 |
| Обращение через точку на три уровня и глубже | Major | 25 |
ПОДОБНО "%…" с ведущим процентом | Major | 25 |
Точка на три уровня вглубь порождает неявные левые соединения, которых нет в тексте запроса и которых вы не писали. С ИЛИ в условии соединения индекс обычно не используется, а ведущий процент в ПОДОБНО гарантированно даёт полное сканирование.
REL, надёжность.
| Что ищем | Уровень | Вес |
|---|---|---|
НачатьТранзакцию без отката | Blocker | 45 |
Пустой блок Исключение | Critical | 30 |
SEC, безопасность.
| Что ищем | Уровень | Вес |
|---|---|---|
| Хардкод пароля или токена | Blocker | 30 |
Выполнить() с кодом из переменной | Critical | 40 |
| Инъекция во внешний запрос | Critical | 40 |
| Хардкод GUID | Major | 25 |
STD, метрики. Порогов три: процедура длиннее 125 строк, цикломатическая сложность выше 20, вложенность глубже 5 уровней.
Учебник мы здесь не копировали. Для длины и сложности взят девяносто пятый перцентиль по большому массиву живого кода, так что флаг получают пять процентов процедур, которые заметно выбиваются из общей массы. По сложности учебная рекомендация и перцентиль совпали: 20 против 21. По вложенности осталась книжная пятёрка, хотя перцентиль показал четыре: при четырёх под флаг попадает слишком много нормального рабочего кода.
Как правило попадает в релиз
Условий три:
| Фильтр | Порог |
|---|---|
| Частота | от десяти вхождений на живом коде, либо уровень Blocker, либо класс безопасности |
| Ущерб | внятный ответ на вопрос “что сломается или насколько замедлит” |
| Точность | ложных срабатываний меньше десяти процентов на выборке в тридцать срабатываний |
Частотный порог нужен вот зачем: правило, которое ни разу не срабатывает, только раздувает каталог и создаёт видимость мощи, пользы от него ноль.
Есть две оговорки, благодаря которым фильтр не стал украшением. Транзакция без отката нашлась шесть раз, хардкод пароля пять, то есть по частоте не проходят оба. Мы их всё равно оставили: ради таких дефектов аудит и заказывают, а редкий дефект не значит неважный. Инъекция во внешний запрос попала в релиз, имея единственный подтверждённый случай, хотя формально фильтр закрывал ей дорогу полностью. Это решение внесено в журнал явно, потому что фильтр, который тихо обходят по удобству, через месяц уже ничего не значит.
Индекс качества и техдолг: как из находок получается решение
Отчёт на двести строк - это не решение. Решение выглядит как “эти три чинить, остальные двадцать две не трогать”, и получается оно из трёх чисел.
Сводный рейтинг обработок. Если прогнать весь каталог или весь справочник допобработок, получится таблица разобранных обработок, где худшие по индексу качества стоят вверху. Она сразу отвечает, с чего начинать, а анализаторы, работающие с одним файлом, такого не дают.
Индекс качества, 0-100. Считается от плотности находок с учётом весов на тысячу строк, по логарифмической шкале. Благодаря плотности пять замечаний в модуле на двадцать тысяч строк не смотрятся хуже трёх замечаний в модуле на двести. Кроме того, есть два жёстких потолка, которые перевешивают любую арифметику:
- хватит одного Blocker, и индекс не выше 49, светофор всегда красный;
- хватит одного Critical, и потолок 79, до зелёного не дотянуть.
Не будь их, зашитый в код пароль растворился бы в плотности большого модуля, и светофор горел бы зелёным.
Технический долг. Складывается из нормативных трудозатрат на исправление всех находок. С таким порядком величины уже можно идти к руководителю и говорить: “обработку надо приводить в порядок полтора дня, решайте”. В этой валюте наши семнадцать файлов тянут почти на пятнадцать рабочих дней.
Честные статусы правил: принято, чинить, отложено, сломано
Статус в каталоге есть у каждого правила.
Принято. Срабатывание проверено на живом коде. Пример - ПолучитьОбъект() или Записать() внутри цикла: формулировка однозначная, ловится структурой уверенно, спорить здесь не о чем.
Чинить. Правило срабатывает, но с ложняком. Хардкод GUID застрял здесь до сих пор: предопределённому элементу GUID обычно прописывают осознанно, у документа это почти всегда мина, а по тексту мы их пока не различаем.
Отложено. Для правила нужен слой, которого ещё нет. Нормального вывода типов пока ждут вложенные циклы сложностью O(n²) и чтение реквизитов ссылки через точку в цикле. За час их написать можно, только врать они будут.
Сломано. Ловит не то, что должно, и потому выключено. Правило о временной таблице без индекса сейчас просто считает слово ПОМЕСТИТЬ, хотя поместить данные во временную таблицу само по себе не дефект. По-настоящему оно формулируется так: “таблица без индекса участвует в соединении”, а для этого запрос нужно разбирать целиком. Такого разбора пока нет, и правило стоит выключенным: сотни пустых находок хуже, чем ни одной.
Путь правила из “сломано” к рабочему виду хорошо видно на Выполнить() со строкой. Первая редакция завалила отчёт срабатываниями, почти все они пришлись на Выполнить(); вообще без аргументов. Так вызывается собственная экспортная процедура обработки с этим именем - обычная схема, когда обработку запускает регламентное задание. Правило пришлось разделить: код в константной строке теперь идёт как Info с весом 10, код из переменной по-прежнему Critical с весом 40. Обе части пока числятся в “чинить”: ложняк никуда не делся, просто сменил сорт.
Если у инструмента не видно ни одного изъяна, скорее всего, автор просто не искал.
Что получилось после движка
Результат по механизмам (со слоями схемы тесты не совпадают: разбор схем компоновки и типы живут внутри парсера):
ЛЕКСЕР 45/0 | ПАРСЕР 38/0 | ТИПЫ 40/0 | ПРАВИЛА 67/0 | ОТЧЁТ 53/0 | СКД 29/0
= 272 проверки, 0 ошибок
Прогон на контрольном наборе из 32 позиций: замолчали все двадцать ложных срабатываний, а семь настоящих дефектов найдены до одного. Пять спорных ушли в уровень “требует ручной проверки”. Это решение спорное и на наш собственный взгляд, о нём ниже.
Границы, названные прямо
Эти границы напечатаны внизу каждого отчёта. Инструмент, изображающий, будто умеет больше, чем умеет, вреден.
Паттерны видит, смысла не видит. Сообщит, что запрос стоит в цикле по неограниченной выборке и к СУБД уйдут тысячи обращений. Что расчёт себестоимости реализован неверно, не скажет: такие ошибки ловят инварианты и проверка чужими руками.
Не знает кардинальности. По тексту не понять, сколько строк вернёт запрос, и цикл на десять записей ничем не отличается от цикла на десять миллионов.
Между процедурами идёт только на один уровень. Если процедуру с запросом зовут из цикла через три уровня вложенности, этот запрос останется невидимым.
Блокировки не анализирует, индексы СУБД под условия запросов не проверяет. Для блокировок нужен рантайм и технологический журнал, это соседняя работа - её мы разбираем в чек-листе “1С тормозит: что делать”.
Обычные формы внутри .epf не читает. Модули таких форм сидят в бинарном Form.bin, и отдельным файлом конфигуратор их при выгрузке не выдаёт. Разбору доступны управляемые формы и модуль объекта. Если обработки достались по наследству и половина из них на обычных формах, ограничение серьёзное.
Большой модуль разбирается одним куском. Двадцать тысяч строк лексер проходит секунд за десять, а прогресса и кнопки “Остановить” у полного разбора пока нет: форма на очень большом модуле просто ждёт.
С требованиями тоже без прикрас. Платформа нужна 8.3.27.1606 или новее, Windows и толстый либо тонкий клиент. Веб-клиент не подходит: запустить из него конфигуратор для распаковки нельзя. На каждую распаковку уходит клиентская лицензия, так что десяток обработок означает десять запусков подряд. Когда исходники уже выгружены, конфигуратор не нужен вовсе, достаточно подать на вход готовые .bsl.
Грабли, которые стоили дороже всего
Самая полезная часть, если собираетесь делать похожее руками или своим скриптом.
Молчаливый ноль на кодировке. Без явной кодировки ЧтениеТекста берёт системную ANSI, а конфигуратор выгружает в UTF-8 без BOM. На реальных файлах первый прогон не дал ни одной находки по трём правилам разом, и смотрелось это как “замечаний нет”. Хуже отказа не бывает: инструмент не падает, не ругается, а спокойно и успокаивающе врёт. С тех пор мы явно задаём кодировку.
Удвоение строк при распаковке. При записи модулей мы не задали перенос строки явно, текстовый режим Windows сделал из \r\n последовательность \r\r\n, и на чтении каждая строка раздвоилась. В отчётах номера строк разъехались вдвое, статистика по длине процедур вместе с ними: порог длины мы сначала выставили в 250 строк вместо настоящих 125 и половину слишком длинных процедур пропустили бы. А номер строки - главное, на чём держится доверие к отчёту. Если он неверен, отчёт не годится целиком, даже при правильном вердикте.
Пустой Исключение бывает законным. Это правило мы считали эталоном без ложняка, пока не нашёлся контрпример:
Попытка
Объект.ДатаИзготовления = Дата(СтрокаИзФайла);
Исключение
КонецПопытки;
Во встроенном языке строку на дату без исключения не проверишь. Пустой блок здесь сознательный: не разобралось - оставляем пустым. По умолчанию правило по-прежнему считает это дефектом, но понижает до информационного, если между Попытка и Исключение стоит одна-единственная инструкция, присваивание с конструктором преобразования. Рекомендация тогда звучит как “заведите счётчик ошибок разбора”.
Спорное место: показывать неуверенное или молчать
Уровень “требует ручной проверки”. Туда попали пять спорных позиций из контрольного набора, и туда же идут находки, у которых не удалось оценить число итераций цикла.
По-нашему, этот уровень значит “я не знаю”, мелочью его не назовёшь. Запрос в цикле по неограниченной выборке нормален на десяти записях и губителен на десятках тысяч, а по тексту программы разницы не видно. Честнее показать находку с пометкой, чем промолчать.
Возражение при этом весомое. За каждой неуверенной находкой стоит работа, которую инструмент сваливает на человека. Анализатор, скрывающий всё сомнительное, отдаёт короткий и чистый отчёт, а ему верят охотнее. Корзина “на проверку” у нас действительно разрасталась, и движок пришлось научить прикидывать порядок числа итераций по тому, откуда берётся цикл.
Красивого выхода нет: отчёт выходит либо честным и местами шумным, либо чистым и кое-где лживым.
Что со всем этим делать дальше
Порядок работ, который мы применяем у себя и на сопровождении:
- Снять список внешних обработок по справочнику дополнительных отчётов и обработок, отдельно посчитать живые (без пометки удаления) и реально опубликованные.
- Прогнать весь каталог разом и получить рейтинг: красные сверху.
- Взять красные и посчитать их долг в часах. Это число идёт руководителю как заявка на время.
- Чинить сверху вниз. Зелёные и жёлтые не трогать, пока не кончились красные.
- Поставить проверку на входе: обработка от подрядчика не выкатывается, пока по ней нет отчёта.
Пятый пункт превращает разовую уборку в регламент, и он же единственный, который не даёт справочнику обрасти заново.
Готовая обработка
Всё описанное собрано во внешнюю обработку на встроенном языке: без Java, без git, без внешнего сервера анализа, и проверяемый код остаётся на вашей машине. Можно прогнать весь каталог или весь справочник допобработок и получить сводный рейтинг, индекс качества, техдолг в минутах, находки с подсветкой исходника и готовыми примерами “было / стало”.
Файл лежит на Инфостарте: Анализ кода внешних обработок 1С: рейтинг по качеству, техдолг и находки с подсветкой.
Соседние инструменты той же линейки:
- Помощник перехода на 1С:Предприятие 8.5 - разбирает код с другой целью: найти, что сломается при смене платформы. Подготовка к переходу разобрана у нас отдельно.
- Трансформатор SQL в 1С - возвращает запросу из профайлера человеческие имена справочников и регистров. Пригодится, когда тормоза видны, а чей это запрос, неясно.
- Оптимизатор временных таблиц - нужен сразу после находки: в пакетном запросе он находит место последнего использования каждой временной таблицы и ставит УНИЧТОЖИТЬ сразу после него, чтобы таблица не лежала в tempdb до конца пакета.
- Чек-ап СУБД под 1С - закрывает вторую половину диагностики: если код чистый, а система всё равно тормозит, смотреть надо в настройки сервера.
Разделите найденный дефект и объяснение модели
В прикладном анализе кода полезно выдавать модели уже найденное правило, участок исходника и основание срабатывания. Статический анализатор отвечает за воспроизводимую находку, модель помогает объяснить последствия. При этом объяснение тоже может содержать ошибку, поэтому в отчёте сохраняют исходное правило и ссылку на код.
Проверьте анализ на размеченном наборе: известный дефект, корректный похожий код и случай, для которого данных недостаточно. Считайте ложные срабатывания отдельно от пропусков: как собрать такой набор из своих процедур и по каким признакам видно, что замер врёт, разобрано в статье про проверку нейросети на своём коде. Если модель меняет вердикт при повторении одинакового запроса, это нужно учитывать в процессе приёмки; уверенная формулировка не повышает достоверность.
В ИИ-анализаторе кода 1С поиск и пояснение разделены на разные части. Ни одна из них не подтверждает работу интерфейса без выполнения: для готового файла нужен прогон управляемой формы, включая команды до заполнения данных и отменённые действия.