понедельник, сентября 24, 2007

Любите править чужие баги?

Никто не любит копаться в старом чужом коде, и вылавливать там баги (ну, почти никто :). Но порой приходится. Что делать, когда перед тобой система в сотню тысяч строк кода, задача buglog-а, причем и то и другое ты видишь в первый раз?
Большинство приложений, с которыми приходится иметь дело имеют похожую высокоуровневую структуру. Впереди располагается "морда" в виде GUI, web или windows, а на противоположенном конце БД (для .Net это чаще всего SQL сервер). Между этими полюсами располагаются десятки и сотни тысяч строк кода. Структура этого кода тебе не известна, а во взгляде начальника в место сочувствия читается "ну - ну, сейчас мы посмотрим, что ты за программер...". На этот случай у меня есть очень простая и эффективная техника локализации ошибки, о которой я хочу рассказать.

Сначала воспроизводим баг в тестовом environment-е, и локализуем в UI точку входа для воспроизведения бага. Что-то вроде "вот, если теперь нажать на кнопку "Details", система рушится в синий экран".

Вторым шагом, идем в backend, на SQL сервер и запускаем SQL profiler. Наша цель - перехватить все SQL команды отправляемые нашей системой в БД. Функциональная структура рассматриваемого нами класса систем, несмотря на все их разнообразие, довольно однородна: по команде с UI система выполняет ту или иную бизнес логику, которая неизбежно приводит к записи данных в БД. Итак, запустив SQL профилировщик, еще раз инициируем в UI сценарий воспроизводящий баг. После этого останавливаем профилировщик и анализируем полученный лог. Нас будут интересовать имена вызываемых хранимых процедур и SQL запросы. Эти имена мы ищем в коде системы. Они обязательно там будут, в виде строковых констант, в ресурсах или, быть может, в файлах конфигурации :). Наша цель, найти в коде точки, из которых вызываются хранимые процедуры и SQL запросы и установить в них точки прерывания.

После этого, мы в третий раз выполняем сценарий воспроизводящий баг, но уже в режиме отладки. Остановившись в точке прерывания, мы спешим увидеть стек вызовов (Ctrl+Alt+C в студии), потому что call stack, это и есть та нить Ариадны, которая проведет нас через сотни тысяч строк кода незнакомой системы. Конечно, если система имеет несколько физических уровней, то таким способом мы препарируем только один уровень. Впрочем, при должном умении, можно получить цепочку стека вызовов всех уровней системы, но тут уже многое зависит от конкретной архитектуры. Далее, расставляем точки прерывания по стеку вызовов и занимаемся исправлением бага.

3 комментария:

Mike Chaliy комментирует...

Помойму все проще. Надо просто запустить дебаггер, и поставить так чтобы он прерывался на всех ексепшенах (включая прохендленные)Debug/Exceptions/User handled. Когда остановиться то у вас будет и стек и все остальное... Обычно этого более чем достаточно. Бывают правда ситуации когда в коде десятки прохендленых ексепшенов.. Вот тогда начинаеться драйв.

Sergey Rozovik комментирует...

to Mike Chaliy
Хех :)
Большинство багов имеют функциональную природу, т.е. нет никаких эксепшенов, просто система делает что то не так как надо.
Когда есть эксепшен да еще и stack trace, тут уже ничего интересного - механическая работа.

kmmbvnr комментирует...

почти так и делаем )

только в случае оракла используем Toad Sql Monitor