Лебедь, рак и щука, или Гадкий утенок

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

Третий участник проекта был (и есть) настолько талантлив как программист, чтомог с одинаковым успехом участвовать, кажется, решительно в любом программномпроекте. Базы данных и сети, протоколы обменов и многозадачность, графика ииздательские системы, вычислительные алгоритмы, распределенная обработка иискусственный интеллект?—?во всем он чувствовал себя уверенно и имел на тополное основание.

Так что шеф, глядя на нашу троицу с неподдельной гордостью, вполне мог считать,что вместе мы горы свернем. Однако далеко не все было гладко…

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

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

Так, компилятор сначала выполняет полный семантический анализ всего исходноготекста, и только потом генерирует для всей программы результирующий код. Почемутакая организация компилятора была выбрана третьим участником, до сих порнепонятно. Какое-то объяснение было тогда дано, но оно тут же выпало из нашейпамяти, и вспомнить сейчас невозможно, а попытаться самим объяснить?—?неполучается. Такое решение (удивительно, но принятое без всякого обсуждения)приводит к тому, что компилятор сохраняет полное дерево программы (и,следовательно, вынужден сохранять и семантические таблицы, так как они друг сдругом сильно связаны) вплоть до завершения обработки всего исходного текста.Более логичным и экономичным был бы подход, согласно которому для каждойфункции выполняется вся обработка, вплоть до генерации кода, после чего вструктурах компилятора сохраняется только информация из ее заголовка,необходимая для компиляции вызовов. Исключение достаточно сделать длявстраиваемых (inline) функций, да и то не всегда.

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

Получилось так, что семантические таблицы были спроектированы, имея в видувторой, более естественный подход, а структура дерева?—?согласно первомуподходу. Разработчику семантических таблиц (мне, попросту говоря), будучипоставленному перед фактом уже в процессе реализации, ничего не оставалось, каксрочно перекроить их структуру. Крайне неприятно, но эта ситуация сохранилась ипо сей день. Надо ли уточнять, что эти структуры были в свое время придуманыдвумя участниками, которые в свое время не смогли (не захотели) вместе обсудитьсвои решения и возможные проблемы…

Справедливости ради следует сказать, что такое проектноерешение неожиданно оказалось весьма уместным и даже естественно необходимым в«следующей жизни» нашего компилятора. Однако, в том, первоначальном, проектеоно сильно осложнило разработку компилятора, и, конечно, было недопустимым.

(Комментарий 2001 года)

Подобных, более мелких, но крайне неприятных рассогласований и неувязок быломного, и, самое ужасное, с течением времени их число нарастало. Возникалотяжелое ощущение того, что компилятор?—?это большая темная комната, а у тебятолько маломощный фонарик, который в состоянии осветить небольшой аппарат?—?твои модули. От аппарата тянутся в темноту провода и вереницы зубчатых колес.Что делается в дальних углах, неизвестно. Иногда вокруг раздаются какие-тозвуки, из темноты выступают части каких-то движущихся механизмов, назначениекоторых остается неведомым, даже если осветить их. Время от времени из темнотыраздается голос, настоятельно требующий: "нажми на кнопку с надписью ABC","переведи рычаг XYZ в правое положение". Что делается в комнате и как всеработает вместе, понять совершенно невозможно.

Пришло время говорить о неприятном?—?через некоторое время от нас ушел третийучастник. Он весь был ориентирован на получение результата, а не на процессего достижения. Само по себе это исключительно ценное качество, его наличие(подкрепленное высокой квалификацией) гарантирует успешное завершение работы взаданные сроки. Однако в данном случае оно обернулось своей худшей стороной?—?откровенно небрежным кодированием ("компилятор соптимизирует"?—?классическийответ на все замечания), принятием важных решений "на ходу", без всякогообсуждения и плохо скрываемым недовольством коллегами, которые непонятно почемукопаются там, где надо скорее программировать. Главное?—?скорее! За один деньсделать работоспособный синтаксис, за месяц?—?добиться трансляции программы"Hello world!". Сложность системы не играет никакой роли, все программыустроены одинаково. Модули должны взаимодействовать согласно своим интерфейсам,обсуждать и комментировать которые нет смысла, они и так сами за себя говорят?—?на то они и интерфейсы.

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

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

Ошибки были исправлены примерно за неделю (половина из них оказалась "ненашими", а как раз того третьего), однако он так и не вернулся в проектникогда… Мы остались вдвоем.

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

Я хочу, чтобы нас правильно поняли. У нас нет к ушедшему абсолютно никакихпретензий. Нас не обманули, не предали, не нарушили никаких обязательств. Болеетого, я вполне допускаю, что сами мы не без греха, и работа в то время шла неслишком ритмично (надеюсь, что и ему уход не принес много горечи). И если ярассказываю об этом эпизоде, то только потому, что мы сами многое при этомпоняли и многому научились.

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

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

Эта точка зрения, точнее, конкретный опыт, быть может, входит в противоречие ссовременными моделями процесса создания ПО, описанными классиками,-- Г.Бучем,Э.Йоданом и другими, однако повторю еще раз, компилятор Си++?—?невполне типичная программная система, по крайней мере, с точки зрениясемантической и логической сложности.

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

А вы?









 


Главная | В избранное | Наш E-MAIL | Прислать материал | Нашёл ошибку | Верх