Программирование "наизнанку"
Решающим фактором в том, что сегодня мы имеем нечто, что можно с уверенностьюназвать компилятором Си++, стало тестирование. Нам трудно судить о том,как следует тестировать, скажем, текстовый редактор или (упаси, Господи!)операционную систему, но наш опыт тестирования и отладки компилятора говорит отом, что это едва ли не самое главное во всем проекте.
Нам очень повезло. Кроме компилятора, бельгийцы заказали еще и пакет тестов напроверку компилятора (любого, не только нашего) на соответствие стандарту. Этотпакет мы и натравили на наш компилятор, точнее, на то, что мы тогда считалитаковым.
Нам повезло и в том отношении, что пакет делала другая команда. Два опытныхспециалиста, давно занимавшиеся проблематикой тестирования именно компиляторов,на этом еще в прежние времена защитившиеся, придумали методику разработкитестов и написали формальные спецификации, а группа студентов по этимспецификациям выдавала сами тесты.
Надо понять специфику этой работы, чтобы оценить ее невероятную сложность. Естьстандарт языка (который и не стандарт вовсе, а "рабочие материалы попредварительному стандарту рабочих групп ANSI и ISO", и почти каждый кварталвыходит новая версия этих "рабочих материалов"). Это кирпич в три килограмма.Каждый абзац стандарта содержит одно утверждение (а чаще несколько)относительно того или иного свойства языка. Тестовый пакет должен проверятькаждое такое свойство, т. е. содержать соответствующий тест на каждоеутверждение стандарта. Каждое утверждение тестируется в предположении, чтодругие языковые свойства компилятор реализует корректно,-- протестировать всесочетания свойств физически невозможно. Предварительный стандарт, как ужеговорилось, постоянно изменяется, значит каждый новый талмуд нужно просмотретьи увидеть, что изменилось по сравнению с прежним (перечень изменений рабочиегруппы не ведут), и внести в тесты соответствующие изменения и добавления.
Далее, текст стандарта написан, как и полагается, невероятно сложным, занудным,бюрократическим языком. По-другому нельзя, так как в стандарте требуетсяпредельная точность, но попробуйте это перевести и понять! Примеров программочень мало, и некоторые нужно разбирать так же, как разбирается сложная фразана чужом языке — слово за словом. Это ни в малейшей степени не похоже научебник по языку — никаких пояснений, никакой специальной методики изложения,никакого принципа "от простого к сложному", в любом месте текста можетвстретиться ссылка на термин, вводимый далеко впереди.
Наконец, предварительный стандарт — это текущий результат живых дискуссий,обсуждений, голосований рабочих групп; там сидят очень грамотные специалисты,но и они ошибаются и не все сразу видят. Поэтому в каждой версии есть (и вокончательном варианте будут) ошибки, неясности, двусмысленности,недоговоренности. Все это присутствует, наверное, в любом стандарте, ноСи++ в этом отношении чемпион — слишком это сложный язык и слишкомхаотически и спонтанно он проектируется. Так что, читая стандарт, следует четкоосознать, почему та или иная фраза кажется тебе абракадаброй: то ли ты плохознаешь английский, то ли недостаточно глубоко понимаешь Си++, то лиребята из ANSI/ISO что-то напутали (а часто и то, и другое, и третье). И не скем посоветоваться — все учебники по Си++ излагают в лучшем случаеверсию "Зеленой книги" 1990 г.,-- и нельзя проверить свое понимание накомпьютере: нет компилятора, который реализовывал бы свойство, за котороекомитет проголосовал на прошлой неделе. Еще не отлита та пуля…
В таких условиях и был написан тестовый набор, который в итоге содержал более6500 тестов. (Можно понять, почему подобные пакеты стоят на Западе до 20 тыс.долл.!) Важно то, что до определенного момента две наши команды работалиполностью независимо, никак не влияя друг на друга. В результате тесты неподгонялись под компилятор, а алгоритмы компилятора проектировались строго посемантике языка, без ориентации на то, чтобы протолкнуть его сквозь конкретныетесты. Взаимные консультации касались только обсуждения собственно текстастандарта — отправной точки для обеих групп. Только когда компилятор в основномбыл сделан, мы начали использовать тесты из него.
Вообще, создание тестового пакета — отдельная история, не менее интересная идраматичная, чем наша. На самом деле далеко не все было так гладко ипоследовательно, как описано выше. Наш шеф В.А.Сухомлин потратил очень многоусилий на формирование коллектива тестовиков. Можно понять сложность задачи — непросто найти программистов, которые хотели и могли бы заниматься"программированием наизнанку" — использовать язык не для решения какой-либозадачи, а для проверки того или иного свойства самого языка! Авторы методикитестирования довольно быстро выполнили свою задачу и, не будучи знатокамиСи++, отошли от проекта. Руководить той адовой работой по написаниютестов, о которой мы писали выше, пытались разные люди, но только с приходомДениса Давыдова, аспиранта мехмата, процесс приобрел систематический ипродуктивный характер. У этого одаренного и трудолюбивого парня была массаочень интересных и действительно перспективных находок и идей, связанных стестированием ПО, и если бы не его совершенно необъяснимая и неожиданнаякончина, вся эта работа сейчас наверняка выглядела бы еще сильнее и солиднее.Талантливые люди всегда уходят слишком рано…
С тех пор отладка тестов почти полностью легла на наши плечи, и мы вложили впакет очень много своего труда. Тестовой команды как таковой уже нет — труднорассчитывать, что студенты будут, практически ничего не получая, в течениедолгого времени тянуть эту тяжелую лямку (тем более, что студенты ВМК сейчасмогут с легкостью получить, пусть не слишком интересную, но гораздо менеетяжелую и неплохо оплачиваемую работу). Таким образом, мы с достаточнымоснованием можем говорить о том, что этот тестовый набор в значительной степенинаш (мы имеем в виду только авторство — с формальной точки зрения онпринадлежит заказавшей его фирме). Сейчас это прекрасный, всесторонневыверенный и протестированный набор из почти семи тысяч небольших, но строгоспецифицированных и единообразно составленных программ, охватывающий весь языкСи++ в соответствии с последней (декабрьской 1996 г.) версиейпредварительного стандарта. Не знаю, что делают с ним бельгийцы, продают ли ониего и за сколько, но для нас ценность его исключительно велика, мы любим его неменьше, чем компилятор.
В какой-то статье было сказано, что нормальное соотношение разработчиков итестировщиков на Западе — один к двум. У нас пропорция была даже выше.
Настоящая работа
Сейчас мы с ужасом думаем, что было бы, не будь у нас тестового пакета. Мы самисмогли бы написать сто, от силы двести слабо систематизированных тестов (набольшее не хватило бы времени и терпения), может быть, насобирали быдесяток-другой исходников на Си++, пропихнули бы все это черезкомпилятор и ходили довольные и гордые тем, что наваяли. Потом программа началабы исправно рушиться на каждой мало-мальски серьезной программе, мы в паникелатали бы дыры, вскоре нам и заказчикам это надоело, и проект тихо умер бы,оставив у нас на руках никому не нужные останки того, что когда-то называлоськомпилятором. Судьба многих и многих проектов…
Все было по-другому. Вечером мы запускали тестовый прогон, утром (если нашжалкий SparcClassic или монструозный диск Maxtor на 300 Мбайт за ночь не далсбой) получали протоколы тестирования, разбирали "по принадлежности"непрошедшие тесты, и начиналась настоящая программистская работа — поиск иисправление ошибок.
Как интересно проектировать структуры данных и алгоритмы! Какое увлекательноезанятие — писать программы! Какое наслаждение смотреть, как они работают и какприятно видеть результаты прогонов! Это все и работой назвать язык неповорачивается — сплошные удовольствия. Программисты меня поймут. Настоящая жеработа, которая требует предельных умственных усилий, от которой действительноустаешь, и которая по-настоящему вызывает удовлетворение, заключается именно вотладке. Нужно держать в голове (никакой отладчик в этом не поможет)замысловатую логику изрядного фрагмента очень сложной программы, буквально ввиде движущихся образов представлять себе, как срабатывает та или иная функциядля данного фактического параметра, и постоянно помнить состояние и глубинустека вызовов для кода, который кто-то тебя (или коллегу) дернул сделатьрекурсивным. Кстати говоря, весь компилятор мы отладили без всяких фокусов,используя древние как мир отладочные печати (плюс десяток специально написанныхфункций, которые опять же печатали таблицы и деревья в наглядном виде) ипримитивный по интерфейсу, но чрезвычайно удобный и мощный отладчик gdb.