Мифический человеко-месяц
Шрифт:
Автономная отладка
За последние двадцать лет процедуры отладки программ развивались по большому циклу, и в некотором смысле они сегодня вернулись туда, откуда начинали. Этот цикл прошел четыре этапа. Любопытно проследить за ними и обнаружить предпосылки каждого шага.
Машинная отладка. Первые ЭВМ имели сравнительно плохое внешнее оборудование и очень медленный ввод/вывод. Обычно машина считывала с бумажных или магнитных лент и на них же помещала результаты, а для подготовки лент и печати на них использовались автономные устройства. Они делали ввод и вывод с лент очень неудобными для отладки, поэтому вместо них стали использоваться пульты. Таким образом, отладка была организована так, что в течение одного выхода на машину имелась возможность пропустить отлаживаемую программу столько раз, сколько это удастся.
Программист тщательно разрабатывал процедуру отладки, планировал, где остановиться, какие ячейки памяти проверить, что следует ожидать там и что делать, если ожидания не оправдались. Эта неприятная необходимость программировать самого себя в качестве отладочной машины занимала почти половину времени, затрачиваемого па написание отлаживаемой машиной программы.
Самым страшным грехом считалось тогда нажатие па кнопку ПУСК без предварительного разбиения программы на части с планируемыми остановами.
Выдача памяти. Машинная отладка была очень эффективна: при выходе на машину, длившемся два часа, можно было получить до дюжины выдач. Но вычислен-тельных машин было мало, они были очень дорогие, и одна мысль о том, что почти все машинное время тратится впустую, приводила в ужас.
Поэтому с появлением быстродействующих печатающих устройств методика отладки изменилась. Программа пропускалась до тех пор, пока не появлялась Выборочная выдача. Машины, в которых при-менялась выдача памяти, имели сначала 2000-4000 слов, или от 8 до 16 тыс. байтов памяти. Но размеры памяти стремительно росли, и вскоре производить выдачу всей памяти стало непрактично. Поэтому появились методы для выборочной выдачи, для избирательной трассировки и для вставки в программу команд выдачи. Test ran в OS/360 может считаться последним словом в этом направлении; он позволяет вводить в программу команды выдачи без повторного ассемблирования пли рекомпиляции.
Диалоговая отладка. В 1959 г. Кодд со своими коллегами3) и Стрейчи6) независимо опубликовали работы, посвященные отладке в режиме разделения времени, методу, позволяющему сочетать преимущества быстрой оборачиваемости в случае машинной отладки и эффективного использования машины при отладке " в пакетном режиме.
В обеих системах в памяти вычислительной машины хранилось несколько программ, готовых к выполнению. Каждая отлаживаемая программа имела в своем распоряжении программно-управляемый терминал. Управляла отладкой программа-супервизор. Когда программист за терминалом останавливал свою программу, чтобы посмотреть результаты или внести исправления, супервизор пропускал другую программу, так что машина постоянно оставалась занятой.
Мультипрограммная система Кодда была создана, но основное внимание ее разработчики направили на увеличение производительности путем улучшения эффективности ввода/вывода, и диалоговая отладка в ней не была реализована. Идеи Стрейчи были усовершенствованы Корбато п его коллегами и реализованы в 1963 г. на экспериментальной системе для IBM 7090 в MIT7). Эта разработка непосредственно привела к проектам Multics, TSS и другим сегодняшним системам разделения времени.
С точки зрения пользователя основные различия между традиционной машинной отладкой и современной диалоговой отладкой сводятся к средствам, ставшим возможными благодаря появлению программы-супервизора и связанных с нею языковых интерпретаторов. Теперь можно писать программы и отлаживать их на языке высокого уровня. Эффективные средства редактирования упростили проблему внесения изменений и получения выборочных выдач памяти.
Возврат к возможностям быстрой оборачиваемости, присущим машинной отладке, не означал, однако, возврата к предварительному планированию отладки. В определенном смысле такое предварительное планирование уже не столь необходимо, как раньше, потому что машинное время не тратится впустую, пока программист сидит и размышляет.
Тем не менее, известны интересные экспериментальные данные Гоулда8), показывающие, что при диалоговой отладке наиболее успешным бывает первый диалог 'каждого сеанса. Это позволяет с уверенностью утверждать, что мы не реализуем всех потенциальных возможностей диалога именно из-за отсутствия плана отладки. Настало время вернуть к жизни старые методы машинной отладки.
Я считаю, что плодотворное использование хорошей терминальной системы требует, чтобы работе за столом посвящалось, как минимум, два часа после каждого двухчасового сеанса за терминалом. Половина этого времени обычно уходит на обработку последнего сеанса: на ведение личного журнала отладки, на занесение новых распечаток программы в личную тетрадь, на объяснение странных явлений. Вторая половина посвящается подготовке: планированию изменений и усовершенствований, разработке подробных тестов на следующий раз. Без такого предварительного планирования трудно производительно работать все два часа сеанса. А без "домашнего анализа" трудно обеспечить систематическое движение вперед от одного сеанса к другому.
Тесты. Что касается разработки реальных процедур отладки и тестов, то все это очень хорошо изложено в работе Груенбергера9), хотя есть и менее подробные изложения в некоторых других учебниках 10'11).
Системная отладка
Системная отладка неожиданно оказалась очень трудной частью процесса создания системы программирования. Я уже рассматривал некоторые причины как сложности этой проблемы, так и ее непредвиденности. Из всего сказанного необходимо усвоить две вещи: отладка системы будет длиться дольше, чем это ожидается, и ее трудность можно преодолеть посредством крайне систематичного и планируемого подхода. Давайте посмотрим, в чем заключается этот подход12).
Использование отлаженных компонент. Если не общепринятая практика, то здравый смысл требуют, чтобы отладка системы начиналась только после того, как начали работать ее части.
Обычная практика отступает от этого принципа по двум направлениям. Первый подход гласит: "свяжите все это вместе и опробуйте". Он основывается на идее о том, что в дополнение к ошибкам в компонентах появятся ошибки в системе (т. е. в сопряжениях). И чем раньше все части будут связаны воедино, тем раньше выявятся системные ошибки. Более примитивная идея сводится к тому, что, используя отдельные части системы для проверки друг друга, можно сэкономить на подготовке тестов. Все это так, однако опыт показывает, что не совсем так,-использование готовых, отлаженных компонент экономит вполне достаточно времени на системной отладке, чтобы использовать его на подготовку тестов и на тщательную отладку компонент.
Несколько более смутная идея "известных ошибок" сводится к тому, что можно начинать комплексную отладку системы уже после того, как в компонентах найдены все ошибки, но прежде, чем они будут исправивлены. Тогда, согласно этой теории, при отладке системы все ожидаемые эффекты таких ошибок уже известны, так что их можно проигнорировать, сосредоточить внимание на новых явлениях.
Но ато лишь иллюзия, попытка обосновать отставание от графика. Никто не может предвидеть всех эффектов, вызываемых уже известными ошибками. Если бы эта связь была столь непосредственной, отладка системы не была бы таким трудным делом. Более того, исправление известных ошибок обязательно приведет к появлению новых, и тогда отладка системы совершенно запутается.
Оснастка. Под "оснасткой" я понимаю все программы и данные, подготавливаемые для проведения отладки, но никогда не появляющиеся в конечном продукте. Нет ничего страшного, если объем таких программ примерно равен половине объема всей системы.
Один из таких приемов - фиктивная компонента, которая включает в себя только сопряжения, и, может быть, какие-то придуманные данные пли несколько тестов. Например, в системе может быть программа сортировки, которая еще нс закончена. Тогда соседние программы можно отлаживать с использованием фиктивной программы, которая только читает и проверяет формат входных данных и выдает набор бессмысленных, но упорядоченных данных правильного формата.