вторник, 21 октября 2008 г.

И снова баги...

Вчера убил больше двух часов на поиск ошибки. Причем шибка возникла на ровном месте там, где ее в принципе и не могло бы быть...

А дело было так.

Правлю я там там что-то в переводчике связанное с интерфейсом взаимодействия между GUI и плагинами и в процессе тестирования вижу странное.

Берем предложение и переводим, получаем два варианта перевода. Все как ожидалось:


А теперь берем и делаем второй вариант перевода предложения основным (т.е. первым в списке переводов):


Упс! А текст-то не тот!

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

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

И совершенно случайно я все-таки нашел в чем была проблема... Вы не поверите.

Итак, где-то в классе TextTranslator (отвечающем за перевод текста) есть такой код:

            for (k = 0; k < ersent.rus.Count;k++ )
                RunProccessRVariantQueue(ersent.rus, par, sent, k);

... который в итоге вызывает такую функцию:

        static void RunProccessRVariantQueue(List<trstr> snt, int par, int sent, int variant)
        {
            for (int i = 0; i < ModulesFactory.Instance.rvar_proccess_queue.Count; i++)
            {
                ((IRStrVariantProcessor) ModulesFactory.Instance.rvar_proccess_queue[i].obj).ProcessRStringVariant(snt, variant, par, sent);
            }
        }

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

Ну и вот, чтобы не допустить ошибок при сортировке и лишних потерь в производительности, функция ProcessRStringVariant модуля сортировки начинается со строчки:


            if(variant != 0) return;

... что по идее должно было заставлять выполнять сортировку один раз. И оно даже работало. Но с одним интересным побочным эффектом.

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

Итерация №1
Вызов модуля склонения для варианта №0
Вызов сортировкщика. В сортировщике стоит указние, что надо вариант с нормером 1 поставить в начало списка (т.е. сделать его номером 0).

Итерация №2
Вызов модуля склонения для варианта №1
Сортировщик ничего не делает, т.к. вариант !=0

Так вот, на итерации №1 мы имеем что? Правильно! Тот же самый вариант, что и на итерации №0, т.к. сортировщик свое дело сделал :) В результате, второй вариант перевода не склонялся.

Решением проблемы оказалась замена приведенного выше условия на следующее:

            if(variant!=Count-1) return;

Вот так вот... Два часа на поиск одной единственной строчки...

Комментариев нет:

Отправить комментарий