История одной баги

Nov 24, 2006 20:15

В последнее время некоторые мои знакомые активно интересуются - каково это - работать в крупной оффшорной софтверной компании? При этом когда я пытаюсь говорить о каких-то деталях своей работы, у меня у самого появляется ощущение неполноты картины. Наверное, мне нужно было бы отвечать в стиле "Вот сами устраивайтесь и увидите", но я вспоминаю себя в студенческие времена и понимаю, что мне тогда была бы очень важна подобная информация. Так что я решил создать метку "реальное программирование" и подготовить в ней несколько заметок о моей работе, что бы рассказать, как это реально происходит. Сначала представляю описание того, как я недавно правил багу. Вобщем-то, могу сказать, что этот эпизод во многом типичен, потом будет описание некоторых других.

Когда-то мне казалось, что работа с компьютерами отличается точностью, чёткостью, понятностью даже в мелочах. На практике же, чем глубже влезаешь в какой-нибудь сложный большой проект, тем всё более работа приобретает неопределённые черты, и ещё хорошо, если просто вероятностные, хуже когда даже вероятность каких-то вещей оценить не можешь...

Вот недавно досталась мне на редактирование одна весьма интересненькая бага. Иногда CRM-система, которую мы разрабатываем и поддерживаем, при переходе между экранными формами меняет название дочерней компании на свою родительскую, почему - непонятно. Довольно быстро нашёл файл, который за это отвечает, но это файл, во-первых, узлового типа, т.е. через него идут вообще все переходы по ссылкам в проекте, а во-вторых, один из самых древних и, как следствие, в его написании в разные времена принимало участие множество народу, большую часть которого я в проекте не застал. Как это обычно бывает, каждый новый человек не сильно разбирался в предыдущем коде, а просто дописывал какой-то функционал поверх, нередко дублируя какие-то функции. Короче, файл, не из самых понятных и при этом из очень важных.

Сначала долго штурмую файл, пытаясь его отлаживать, что бы понять - как он работает? Вникаю в беспорядочные редкие комментарии, пытаюсь что-то сообразить по именам параметров форм, переменных и методов. Пытаюсь целый день (с обеда до вечера и на следующий день с утра и до обеда), в итоге удаётся разобраться только в паре небольших кусков, всё остальное так и представляется полнейшей абракадаброй. Через некоторое время становится понятно, что разбираться можно долго, а дело надо делать... Отлаживая, стал смотреть, где происходит переход не туда, куда нужно. Выяснил, что не хватает параметра запроса в командной строке. Почему-то он устанавливается в сессию и сразу же удаляется - решил не трогать этот механизм, просто передавать каждый раз его дальше, прописал во все ссылки, которые нашёл, вроде заработало - за`commit`ил багу и сижу довольный.

Тестеры нашли такие хитро-запрятанные ссылки, которые не заметил я. Матерясь про себя, полез, нашёл их в коде, исправил, за`commit`ил багу. Потом тестеры ещё нашли ссылок, которые я снова исправил и в который раз за`commit`ил, с мыслями, что это - уж точно "самый последний конец".

В описании баги была ещё вторая часть, которую я не без труда упросил руководство отделить мне от первой, заведя отдельную багу, т.к. они никак не связаны на уровне кода. Вторая часть заключается в том, что банкир, который ни разу не просматривал информацию о какой-либо компании, получает ошибку при попытке это первый раз сделать, а во второй раз у него уже всё нормально. Переведя дух, пытаюсь отловить эту самую вторую часть баги - не ловится! Всё нормально. Вывод один - исправив первую часть баги, я как-то непонятным для себя образом, исправил и вторую, следовательно, они связаны. Чувствую себя несколько неуютно, ибо 10 минут назад упорно доказывал руководству, что они никак не связаны... :((((

Стыд теплится недолго - скоро тестеры revert`ят мне эту багу, приписав комментарий, что бага наблюдается только у дочерних компаний. Фууух! :))) Значит, всё-таки, никак не связаны, авторитет спасён, просто тестер, который багу нашёл, недостаточно её конкретизировал в описании. Итак, надо debugg`ить...

Ошибка возвращается из Oracle`а, так что, может быть, даже не Java в ней и виновата, но, прежде чем обвинять базистов, нужно всё хорошо проверить и идти к ним со всеми доказательствами. Залезаю в файл, генерирующий результаты, которые выводятся на экран, бегло просматриваю - вроде ничего особенного. Что бы debugg`ить, надо создать такого банкира, который ни разу на страницу описания компаний не заходил. Тот банкир, под которым я в данный момент работаю с системой, естественно, многократно заходил на эту страницу и для отлова баги не годится. В силу специфики проекта, банкиры у нас не создаются - только берутся и используются готовые, которых около 14 тысяч в тестовой и developer`ской базе, по-этому особо переживать по этому поводу не стоит - на наш век банкиров хватит.

Долго выясняю у тестеров - как же это можно узнать - заходил банкир на эту страницу или нет? Есть - говорят мне через некоторое время - такая табличка, в которой содержится информация о последней странице этого раздела, на которую заходил банкир. Замечательно, лезу в эту табличку, нахожу в ней по ID`шнику своего банкира и заменяю в ней информацию о том, куда я последний раз ходил. Запускаю сервак - бац! - ошибка "Null pointer exception", не проходит авторизация. Возвращаю изменённые данные назад - всё равно не авторизуется, перегружаю сервак - по-прежнему не заходит. Ну ё-моё!..

Слава богу, есть ещё и другие схемы, в которых пока ещё всё нормально, коннекчусь к другой схеме Oracle`а, отмечая в бумажке, что как высвободится немного свободного времени, нужно будет разобраться с банкиром в похеренной схеме. Зашёл. Больше своим исконным банкиром решил не рисковать, лучше сменить его на другого, про которого из этой таблички можно узнать - был он на этой глючной странице или нет. Залезаю в SQL Navigator, формирую запрос и вывожу список с немеренным количеством банкиров, не просматривавших никогда информацию о компаниях. Swop`люсь на первого попавшегося - почему-то система его не видит. Блин. Второго, третьего... Четвёртого видит - ну слава богу! Параллельно приходит объяснение - у первых трёх были установлены флажки "is_Terminated" в "Y" - понимаю, что надо было это предусмотреть и в запросе на выборку выводить только тех, у кого он установлен в "N", не ленюсь и делаю это сейчас, потому что потом забуду, прогоняю запрос - действительно, первых трёх теперь нету.

Осторожно пододвигаю курсор мышки и кликаю на ссылку... Как по минному полю, блин. IDEA отлавливает поток выполнения - ну чтож, поехали...

Debugg`ить большие сложные приложения - это что-то типа работы полевого снайпера. Снайпер сидит в засаде и ждёт, когда жертва появится, может ждать часами и в любой момент жертва может появиться всего лишь на пару секунд и по-этому он должен быть готов стрелять на протяжении всего времени ожидания. Программист сидит и по одному оператору выполняет программу, каждый раз сопоставляя то поведение, которое видит и то, что должно быть, что бы выяснить, где же они расходятся. Если потеряешь бдительность, поток выполнения может перейти к неправильному сценарию действий, а ты этого даже не заметишь; на секунду даже появится ощущение, что программа-то работает правильно, просто требования к ней предъявляются не такие, как надо :)))

Слава богу, обычно ошибку более или менее ясно, где искать и участок кода, в котором она может возникнуть, довольно легко локализовать. Так и в этот раз - это явно метод величиной в 2 страницы разряжённого пустыми строками и комментариями кода. IDEA подсвечивает синеньким последовательно одну за другой строчки, пока не сваливается в блок "catch" - ага, ошибка при вызове одной из процедур Oracle`а!

Повторяю процедуру - swop`люсь на другого банкира, захожу под ним на страницу с описанием этой дочерней компании, прогоняю ещё раз, только теперь сразу отлавливаю поток на этой ошибочной строке. Какие же данные тебе передаются, что ты валишься, а? Ну точно - передаётся null в качестве id`шника компании. Проверка через SQL Navigator показывает, что null эта процедура принимать категорически отказывается, валится с ошибкой. А что, спрашивается, я ещё могу передать, если у меня здесь для таких компаний этого id`шника нету?..

Интересно другое - почему остальные процедуры не валятся, а валится только эта, ведь им тоже во входных параметрах передаётся этот null? Тут я вспоминаю, что две-три недели назад работал с этим модулем и что в его процедуры передаётся два параметра с ID шниками и мне базисты вроде бы даже зачем-то тогда объясняли, что процедуры построены так, что один из этих ID`шников равен null. А именно этой процедуре передаётся только один ID`шник...

Что бы проверить догадку, опять swop`люсь на девственного банкира, прогоняю программу в debugging mode ещё раз. Ну точно, второй ID-шник значимый и все предыдущие процедуры работают по нему, и лишь с этой заминка. Подхожу к базистам, прошу посмотреть, нельзя ли и эту процедуру переделать так, как те, что работают. Через некоторое время говорят, что нельзя и вообще интересуются, не ошибся ли я - точно мы должны что-то из этой информации показывать для таких компаний?

Подхожу к аналитику, выясняю, что всё-таки, к удивлению базистов, должны. Ну ок, тогда как мне быть? Варианта 2 - либо не вызывать эту процедуру из Java, либо передавать ей вместо null`а какую-то заглушку, пустышку, по которой она по крайней мере, не свалится, а выдаст пустую выборку. Советуюсь с менеджером проекта (потому что аналитик уже уходит) и делаю по второму варианту - нуль вполне подходит, возвращая пустую выборку.

Вобщем, изменяю строку "Collection info7 = proc7(Type1ID);" на "Collection info7 = proc7(Type1ID == null ? "0" : Type1ID);", пару минут любуюсь этим изменением как единственным реальным результатом моей напряжённой работы в течении нескольких часов, затем компилирую проект, deploy`ю его, перезапускаю сервак с порталом, тестирую на новом девственном банкире - вроде ошибок не выдаёт - затем заливаю файл в систему контроля версий и отмечаю в Bug tracking системе, что вторая часть баги по`fix`ена.

Откидываюсь на спинку стула. Одолевают философские мысли о том, какой же ID-шник передаётся в эту процедуру при втором и третьем заходе банкира на страницу о таких компаниях, ведь их там всё равно нету, а ошибка не валится, и это значит, что он всё-таки берётся из сессии, но реально принадлежит другим компаниям, а система уже на prodaction`е и вроде жалоб не было... Собираюсь где-то себе пометить, что надо будет придумать, что делать в случаях повторного захода, что бы не брать чужой ID`шник для запроса, а тоже пихать "0". При поиске, куда бы записать, взгляд падает на оставленную пометку - "Разобраться с первой схемой!!!", вспоминаю, что теперь не могу зайти на одну из важных для разработки схем - так что помечаю то, что хотел, а затем запускаю SQL Navigator и начинаю разбираться, уже понимая, что сегодня задержусь допоздна.

Ибо такая уж у меня работа, сам её выбрал... :)

реальное программирование

Previous post Next post
Up