
Аудит legacy-кодовой базы на VB.NET: чек-лист перед доработкой
Прежде чем добавлять функцию в проект десятилетней давности, стоит потратить день на аудит. Он покажет, где код сломается от первой же правки, и сэкономит недели на исправлении последствий.
Зачем аудит, если задача маленькая
Типичная ситуация: заказчик просит добавить поле в форму и выгрузку в отчёт. Оценка: два дня. Через две недели выясняется, что проект собирается только на одной машине, отчёт формируется SQL-строкой из семи конкатенаций, а исключения проглатываются пустыми Catch, поэтому никто не знал, что выгрузка давно теряет часть строк.
Аудит перед доработкой нужен не для красивого отчёта, а для честной оценки. Он отвечает на три вопроса: можно ли собрать и запустить проект, где самые опасные места, и какой минимум нужно сделать до первой правки, чтобы не сломать то, что работает.
1. Сборка и окружение
Первый час уходит на то, чтобы проект собрался на чистой машине. Если это не получается, остальные пункты вторичны.
- целевой фреймворк каждого проекта: .NET Framework 2.0-4.8 или современный .NET, есть ли смесь;
- формат проектов: старый vbproj с перечнем файлов или SDK-стиль;
- зависимости: packages.config, PackageReference или DLL в папке lib без версий и источника;
- ссылки на COM-компоненты и сборки из GAC, которых нет на новой машине;
- собирается ли решение командой msbuild или dotnet build без открытия Visual Studio;
- есть ли CI и когда он последний раз был зелёным.
rem целевые фреймворки всех проектов
findstr /s /i "TargetFramework" *.vbproj
rem ссылки на сборки с жёстким путём (кандидаты на «работает только у меня»)
findstr /s /i "HintPath" *.vbproj
rem COM-ссылки
findstr /s /i "COMReference" *.vbproj
rem сборка с нуля, журнал в файл
msbuild Billing.sln /t:Rebuild /p:Configuration=Release /fl /flp:logfile=build.log2. Настройки компилятора
У VB.NET есть особенность, которой нет у C#: можно отключить строгую типизацию. Option Strict Off разрешает неявные сужающие преобразования и позднее связывание, Option Explicit Off позволяет пользоваться необъявленными переменными. В старых проектах, перенесённых из VB6 мастером миграции, это встречается постоянно.
Посчитайте, в скольких файлах стоит Option Strict Off и какие настройки заданы на уровне проекта. Включать строгий режим разом по всему решению не нужно: это сотни ошибок компиляции. Правильнее включить его в проекте, а в старых файлах явно прописать Option Strict Off в первой строке, затем снимать эту строку с файлов, которые вы трогаете.
3. Данные и безопасность
Это раздел, где находят самые дорогие проблемы. Проверьте каждый пункт поиском по коду:
- SQL-запросы, собранные конкатенацией с пользовательским вводом: ищите «SELECT» рядом с оператором & и обращениями к .Text или Request;
- строки подключения и пароли в коде или в открытом web.config, особенно в истории репозитория;
- собственная криптография, хранение паролей в MD5 или открытом виде;
- устаревшие протоколы: явный SecurityProtocolType.Tls или Ssl3 в коде;
- десериализация через BinaryFormatter, который в современных .NET запрещён;
- доступ к файлам по пути из запроса без проверки.
' Было: SQL-инъекция и незакрытое соединение
Dim cmd As New SqlCommand("SELECT * FROM Clients WHERE Name = '" & txtName.Text & "'", con)
' Стало: параметр и Using
Using con As New SqlConnection(connString),
cmd As New SqlCommand("SELECT Id, Name FROM Clients WHERE Name = @name", con)
cmd.Parameters.Add("@name", SqlDbType.NVarChar, 200).Value = txtName.Text
con.Open()
Using rd = cmd.ExecuteReader()
' ...
End Using
End Using4. Обработка ошибок и наблюдаемость
Найдите все пустые блоки Catch и Catch, где исключение только пишется в Debug. Отдельно ищите On Error Resume Next: в VB.NET он поддерживается ради совместимости и превращает любую ошибку в тихое продолжение работы. Каждый такой случай это место, где программа может давно работать неправильно, и никто об этом не знает.
Посмотрите, куда пишутся логи и читает ли их кто-нибудь. Если логирования нет, добавьте его до доработки, а не после: иначе после релиза вы не сможете отличить новую ошибку от старой.
5. Тесты и карта рисков
Тестов в legacy-проекте, скорее всего, нет или они не запускаются. Не пытайтесь покрыть всё. Напишите характеризационные тесты на тот код, который будете менять: зафиксируйте текущее поведение на реальных входных данных, даже если оно кажется странным. Тест проверяет не правильность, а неизменность.
Итог аудита это короткая таблица: модуль, риск, что сделать до доработки, что можно отложить. Обычно в обязательный минимум попадают воспроизводимая сборка, параметризация SQL в затронутых местах, логирование и характеризационные тесты на изменяемый код. Всё остальное идёт в бэклог технического долга с оценками.
Как это делают сегодня
Вопросы и ответы
Сколько времени должен занимать аудит?
Для проекта на 50-200 тысяч строк обычно от одного до трёх дней. Цель не полный отчёт обо всём, а список рисков для конкретной доработки.
Нужно ли сразу включать Option Strict во всём проекте?
Нет. Включите его на уровне проекта, оставьте явное Option Strict Off в старых файлах и снимайте его по мере того, как трогаете код.
Что делать, если найдены секреты в истории git?
Сменить их немедленно: удаление из истории не отменяет утечку. Затем перенести в переменные окружения или хранилище секретов и добавить проверку в CI.