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

Многие программисты инстинктивно говорят: “Выдавайте сообщение об ошибке!” Нет, не нужно. Никого это не волнует. С такими проблемами гораздо легче справиться в языках, поддерживающих исключения, таких как Java. В таких языках просто перехватываешь все исключения на самом верхнем уровне и готово. И не нужно беспокоить пользователя сообщением о том, что какое-то значение равно нулю.

Сейбел: Вы когда-нибудь просто проходили программу пошагово - для отладки или, как некоторые советуют, для проверки написанного кода?

Завински: Нет, не совсем. Обычно я использую пошаговое выполнение для отладки. Пожалуй, иногда для проверки правильности написанного кода. Но не часто.

Сейбел: Так что же вы делаете при отладке?

Завински: Сначала пробегаю глазами код, читаю его, пока не подумаю: “Так, этого не может быть, все должно работать правильно”. Тогда я добавляю некоторый код для проверки и разрешения этого противоречия. Либо если, читая код, я не вижу никаких проблем, то запускаю его на выполнение, останавливаю где-нибудь в середине и смотрю, что происходит. Сложно говорить об этом вообще. Ситуации бывают разные.

Сейбел: Что касается операторов утверждений - насколько формально вы к ним подходите? Кто-то использует стандартное утверждение: “Я считаю, что в этом месте кода некоторое условие должно быть истинным”. А кто-то мыслит более формально: у функций есть предусловия, постусловия и есть глобальные инварианты. Какова ваша позиция?

Завински: Я точно не думаю об этом в контексте математического доказательства корректности. Скорее я за стандартные утверждения. Конечно же, всегда полезно, получив входные данные в функции, хотя бы приблизительно понимать, какие у них ограничения. Может ли это быть пустая строка? Что-то в таком духе.

Сейбел: Тестирование - тема, весьма близкая к отладке. В Netscape была специальная группа обеспечения качества или вы все тестировали сами?

Завински: И то и другое. Мы все время запускали свои программы - это лучший способ проверки качества на месте. Но была и группа обеспечения качества, у которой были формальные тесты. И каждый раз перед выпуском новой версии они все проверяли по списку. Перейти на такую-то страничку, щелкнуть там-то. Вы должны увидеть это. Или не должны увидеть.

Сейбел: А как насчет тестов на уровне разработчика, таких как модульные тесты?

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

Сейбел: Переросло ли это в какую-то форму автоматического тестирования?

Завински: Нет, когда я писал такие модульные тесты для своего кода, они запускались в основном лишь тогда, когда я сам запускал их. Потом мы немного занимались этим, когда работали над проектом Grendel, переписывая почтовый клиент на Java, поскольку там гораздо легче писать модульные тесты при разработке новых классов.

Сейбел: Оглядываясь назад, как вы считаете, ваша команда пострадала от этого или нет? Упростилась бы или ускорилась разработка, если бы вы были дисциплинированнее в вопросах тестирования?

Завински: Не думаю. Мне кажется, это бы только замедляло нас. Можно долго говорить о том, как все делать правильно с первого раза. Первоначально мы были зациклены на скорости. Нам нужно было выпустить продукт, пусть даже несовершенный. Мы могли бы выпустить его позже, и его качество было бы выше, но к тому времени нас мог бы кто-нибудь опередить.

Довольно часто говорят, что дело пойдет быстрее при наличии модульных тестов, меньших модулей и тому подобное. Все это хорошо звучит в теории. При неспешном темпе разработки это действительно отличный вариант. Но когда тебе говорят: “Нам нужно сделать это с нуля за шесть недель”, - приходится чем-то жертвовать, иначе не справиться. И я выбрасываю то, что не является абсолютно критичным. Модульные тесты не критичны. Пользователь не будет жаловаться на то, что у вас нет модульных тестов. Это ваше личное дело.

Не хочу, чтобы все решили, будто я считаю тесты ерундой. Нет. Это всего лишь вопрос приоритетов. Вы пытаетесь написать хорошую программу или пытаетесь закончить к следующей неделе? Сделать то и другое одновременно не получится. У нас в Netscape была такая шутка: “Мы стопроцентно преданы качеству. Мы собираемся выпустить продукт самого высокого, насколько у нас получится, качества к 31 марта”.

Сейбел: Отсюда другая тема - сопровождение программного обеспечения. Как вы разбираетесь в коде, который не сами писали?

Завински: Я просто беру его и читаю.

Сейбел: С чего вы начинаете? Читаете его последовательно, с первой страницы?

Завински: Когда как. Чаще всего приходится изучать, как использовать новую библиотеку или набор инструментов. Если повезет, будет даже какая-нибудь документация. Есть некий API. Разбираешься с отдельным фрагментом, чтобы понять, как он работает, или выясняешь, как что-то реализовано. Так и прокладываешь себе путь через все это. С такими инструментами, как Emacs, можно начать снизу. Из чего состоят списочные ячейки (cons cells)? Как это выглядит? От этого можно танцевать. Иногда знакомство с системой построения позволяет понять, как все это сочетается. Мне всегда казалось, что, для того чтобы погрузиться в кусок кода, нужно взять некоторую задачу и попытаться ее решить.

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

Сейбел: В Emacs вы в конце концов переписали компилятор байт-кода и части байт-кода виртуальной машины. Мы уже говорили о том, что значительно приятнее что-то переписать заново, чем исправлять, но это не всегда подходит. Не понимаю, как вы перешли эту черту? Вы решили переписать компилятор целиком, потому что это проще, чем исправить только некоторые его части? Или просто подумали: “Ух ты! А здорово будет написать компилятор!”

Завински: Так уж вышло, что в результате компилятор был переписан полностью. Я начал с внесения исправлений и попыток оптимизации. Но в конце концов в нем не осталось ничего от первоначального варианта. Я использовал тот же API, пока в нем не отпала необходимость. По-моему, компилятор байт-кода вышел отлично, отчасти потому, что это был изолированный модуль с единственной “точкой входа”: скомпилировать и сохранить.

Конечно, многое из того, что я добавил в Lucid Emacs, было не столь полезным. На самом деле, многие мои действия объяснялись желанием приблизить все это к Лисп-машинам и к более привычным для меня версиям Emacs и средам разработки под Лисп. И я приложил много усилий, чтобы Лисп в Emacs был более совершенным: например, чтобы использовались объекты-события, а не списки чисел. Использовать списки чисел вместо объектов-событий - примитив и безвкусица. Теперь понятно, что эти изменения были одной из главных проблем, поскольку приводили к несовместимости с библиотеками сторонних

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату