Фредерик БРУКС Мифический человеко-месяц или как создаются программные системы
Посвящение издания 1975 года
Посвящается двоим людям, благодаря которым мои годы в IBM были особенно насыщенными:
Томасу Дж. Уотсону Младшему, чье глубокое внимание к людям по-прежнему ощущается в его фирме, и Бобу О. Эвансу, чье смелое руководство превратило работу в приключение.
Посвящение издания 1995 года
Посвящается Нэнси, Божьему дару для меня.
Предисловие к изданию 1995 года
К моему удивлению и удовольствию, «Мифический человеко-месяц» остается популярным через 20 лет после выхода. Тираж превысил 250 000 экземпляров. Меня часто спрашивают, какие из оценок и рекомендаций, изложенных в 1975 году, я по-прежнему считаю верными, а какие претерпели изменения, и в чем именно. Несмотря на то, что в моих лекциях этот вопрос время от времени затрагивается, я давно жду возможности изложить его в печатном виде.
Питер Гордон (Peter Gordon), являющийся сейчас совладельцем издательства Addison-Wesley, терпеливо и с пользой сотрудничает со мной с 1980 года. Он предложил подготовить юбилейное издание. Мы решили не исправлять оригинал, а перепечатать его в неприкосновенности, за исключением обычных опечаток, и дополнить мыслями, возникшими в более позднее время.
В главе 16 перепечатывается статья «Серебряной пули нет: сущность и акциденция в программной инженерии», опубликованная IFIPS (Международная федерация обществ по обработке информации) в 1986 году и явившаяся результатом опыта, полученного мною во время руководства исследованием использования программного обеспечения в военных областях, проводившегося Военным комитетом по науке. Мои соавторы по этому исследованию, а также наш исполнительный секретарь Роберт Л. Патрик, оказали мне неоценимое содействие в моем возвращении к крупным практическим программным проектам. Статья была перепечатана в издании IEEE “Computer” в 1987 году, благодаря которому получила широкую известность.
Статья «Серебряной пули нет» была дерзкой. В ней предрекалось, что в течение ближайшего десятилетия не возникнет методов программирования, использование которых позволит на порядок величин повысить производительность разработки программного обеспечения при прочих равных условиях. До конца этого десятилетия остался год, и, похоже, мое предсказание сбылось. Статья вызвала более оживленную дискуссию в печати, чем «Мифический человеко-месяц», поэтому в главе 17 содержатся ответы на некоторые из опубликованных критических замечаний, а также уточняются взгляды, изложенные в 1986 году.
При подготовке ретроспективного анализа и уточнения книги «Мифический человеко-месяц» я был удивлен тем, как мало содержавшихся в ней заявлений подверглось критике — как из числа доказанных, так и опровергнутых последующим опытом и исследованиями в области разработки программного обеспечения. Мне показалось полезным систематизировать эти заявления в чистом виде, без сопутствующих доказательств и данных. Я включил в книгу этот очерк в качестве главы 18, надеясь, что эти чистые утверждения вызовут поиск аргументов и фактов для доказательства, опровержения, пересмотра или уточнения.
Глава 19 собственно и представляет собой попытку пересмотреть изначальные утверждения. Следует предупредить читателя, что излагаемые новые взгляды далеко не в той мере подкреплены «боевым опытом», как это было в первой части книги. Дело в том, что в последнее время я работал в университетской среде, а не в промышленности, и над небольшими, а не крупномасштабными проектами. С 1986 года я занимаюсь только преподавательской деятельностью в области разработки программного обеспечения, но не исследованиями в ней. Моя исследовательская работа больше касается виртуальных сред и их применений.
При подготовке данной ретроспективы я поинтересовался современными взглядами своих друзей, которые практически занимаются разработкой программного обеспечения. В число тех, перед кем я в долгу за готовность поделиться своими взглядами, сделать полезные замечания к первоначальному тексту и усовершенствовать мое образование, входят Барри Бём (Barry Boehm), Кен Брукс (Ken Brooks), Дик Кейс (Dick Case), Джеймс Коггинс (James Coggins), Том Демарко (Tom DeMarco), Джим Маккарти (Jim McCarthy), Дэвид Парнас (David Parnas), Эрл
Уилер (Earl Wheeler) и Эдвард Йордон (Edward Yordon). Фэй Уард (Fay Ward) прекрасно выполнила техническую работу, связанную с изданием новых глав.
Я благодарен моим коллегам из Группы по программному обеспечению для военных целей Военного комитета по науке Гордону Беллу (Gordon Bell), Брюсу Бьюкенену (Bruce Buchanan), Рику Хейз-Роту (Rick Hayes-Roth) и особенно Дэвиду Парнасу — за их плодотворные идеи, а Ребеке Бирли (Rebekah Bierly) — за подготовку к печати статьи, опубликованной в данной книге в качестве главы 16. Анализ проблем программирования в категориях «сущность» (essence) и «акциденция» (accident) возникло благодаря Нэнси Гринвуд Брукс, использовавшей такой анализ в статье об обучении игре на скрипке методом Сузуки.
Обычаи издательства Addison-Wesley не позволили мне в предисловии к изданию 1975 года выразить благодарность его сотрудникам за сыгранную ими важную роль. Следует особенно отметить вклад двух человек: Нормана Стентона (Norman Stenton), являвшегося ответственным редактором, и Герберта Боуза (Herbert Boes), бывшего художественным редактором. Боуз создал изящный стиль, особо отмеченный одним из рецензентов: «широкие поля и творческое использование шрифтов и компоновки материала». Что еще важнее, он дал важный совет поместить в начале каждой главы свою картинку. (В то время у меня были только картинки Смоляных ям и Реймского собора.) Чтобы найти все картинки, мне потребовался целый год, но я бесконечно благодарен за совет.
Soli Deo gloria — Богу единому слава!
F. P. B., Jr. Чапел Хилл, Северная Каролина Март 1995
Предисловие к первому изданию
Во многих отношениях управление большим проектом разработки программного обеспечения аналогично любому другому крупному начинанию — в большей мере, чем обычно считают программисты. Однако во многих отношениях имеет отличия — в большей мере, чем обычно предполагают профессиональные менеджеры.
Идет процесс накопления профессиональных знаний в этой области. Состоялось несколько конференций, заседаний на конференциях AFIPS, опубликовано несколько книг и статей. Но знания еще не оформились в том виде, когда их можно систематически изложить в учебнике. Тем не менее, представляется уместным предложить эту небольшую по объему книгу, отражающую, в основном, мои личные взгляды.
Мое профессиональное становление в вычислительной технике первоначально было связано с программированием, однако в период 1956-1963 годов, когда разрабатывались автономные управляющие программы и языки высокого уровня, я занимался, в основном, архитектурой компьютеров. Когда в 1964 году я стал менеджером проекта разработки Operating System/360, то обнаружил, что мир программирования совершенно изменился благодаря успехам, достигнутым за несколько последних лет.
Руководство разработкой OS/360 было очень поучительным, хотя и полным расстройств. Команде разработчиков, в том числе сменившему меня Ф. М. Трапнеллу (F. M. Trapnell), можно многим гордиться. Система содержит много отличных решений в конструкции и функционировании, и ей удалось получить широкое распространение. Некоторые идеи, в первую очередь, организация ввода/вывода, независимая от устройств, и управление внешними библиотеками стали техническими новинками, ныне широко используемыми. Сейчас эта система вполне надежна, достаточно производительна и весьма гибка.
Однако проект нельзя назвать вполне успешным. Всякому пользователю OS/360 быстро становится ясно, насколько лучше могла бы быть система. Ошибки проектирования и реализации особенно заметны в управляющей программе, а не в компиляторах языков. Большая часть этих просчетов относится к периоду 1964-65 годов и потому должна быть отнесена на мой счет. Более того, система вышла с задержкой, потребовала больше памяти, чем предполагалось, стоимость разработки в несколько раз превысила запланированную, и первые несколько версий функционировали не слишком удачно.
Покинув в 1965 году IBM и придя в Чэпел Хилл, как это и предполагалось, я возглавил разработку OS/360 и стал анализировать опыт этой разработки, чтобы извлечь уроки технологических решений и администрирования. В частности, я хотел понять, почему столь различным оказался опыт администрирования при разработке аппаратной части System/360, с одной стороны, и создании операционной системы OS/360 — с другой. Эта книга является запоздалым ответом на вопросы Тома Уотсона относительно трудности управления разработкой программ.
В решении этой задачи я получил большую пользу от длительного общения с Р. П. Кейсом (R. P. Case), помощником менеджера проекта в 1964-65 годах, и Ф. М. Трапнеллом, менеджером проекта в 1965-68 годах. Я обсудил свои выводы с менеджерами других крупных программных проектов, в том числе Ф. Дж. Корбато (F. J. Corbato) из МТИ, Джоном Харром (John Harr) и В. Высоцким (V. Vyssotsky) из Bell Telephone Laboratories, Чарльзом Портманом (Charles Portman) из International Computers Limited, А. П. Ершовым из Вычислительного центра Сибирского отделения Академии наук СССР, а также А. М. Пьетрасанта (A. M. Pietrasanta) из IBM.
Собственные мои выводы содержатся в следующих ниже очерках, предназначенных профессиональным программистам, профессиональным менеджерам и особенно профессиональным менеджерам в программировании.
Хотя книга написана как отдельные очерки, у нее есть центральная тема, излагаемая в главах 2-7. Вкратце мое мнение заключается в том, что трудности, испытываемые при управлении крупными программными проектами, иного рода, нежели при управлении небольшими проектами, что связано с проблемами разделения труда. Я считаю важнейшей задачей сохранение концептуальной целостности самого продукта. В этих главах обсуждаются трудности, возникающие на пути к этому единству, и способы их преодоления. В главах, следующих за ними, обсуждаются другие аспекты управления разработкой программного обеспечения.
Имеющаяся по этой теме литература не слишком богата, но весьма распылена. Поэтому я постарался включить ссылки на литературу, которые помогут осветить отдельные вопросы и отошлют заинтересованного читателя к другим полезным работам. Рукопись книги прочли многие мои друзья, и некоторые из них сделали пространные и полезные замечания. В тех случаях, когда, несмотря на ценность, они не вполне вписывались в текст, я включал их в примечания.
Поскольку эта книга представляет собой сборник очерков, а не единый текст, все ссылки и примечания вынесены в конец, и читателю при первом чтении можно их пропустить.
Я глубоко признателен мисс Саре Элизабет Мур (Sara Elizabeth Moore), мистеру Дэвиду Вагнеру (David Wagner) и миссис Ребекке Беррис (Rebecca Burris) за помощь в подготовке данной рукописи, а также профессору Джозефу Слоуну (Joseph C. Sloane) за советы в отношении иллюстраций.
F. P. B., Jr. Чэпел Хилл, Северная Каролина Октябрь 1974
Глава 1 Смоляная яма
Een Schip op bet strand is een baken in zee. (Корабль на мели — моряку маяк.)
ГОЛЛАНДСКАЯ ПОСЛОВИЦА
Самая яркая сцена доисторических времен — борьба огромных животных со смертью в смоляных ямах. Воображение представляет динозавров, мамонтов и саблезубых тигров, пытающихся высвободиться из смолы. Чем отчаянней борьба, тем сильнее затягивает смола, и как бы ни был силен или ловок зверь, в конечном итоге ему уготована гибель.
Такой смоляной ямой в последнее десятилетие было программирование больших систем: в ней сгинул не один большой и сильный зверь. По большей части это происходило в области систем, где мало кому удалось реализовать спецификации, уложиться в график и бюджет. Большие и малые, массивные и жилистые — одна за другой эти команды увязли в смоле. Казалось, ничто в отдельности не вызывает трудностей — одну лапу всегда можно вытащить. Но накопление действующих одновременно и взаимовлияющих факторов все более и более замедляет движение. Вызывает удивление неприятность возникшей проблемы, и распознать ее сущность нелегко. Но нужно это сделать, если мы собираемся решить ее.
Поэтому начнем с определения того, что такое системное программирование, и какие радости и печали оно таит.
Системный программный продукт
Время от времени можно прочесть в газете о том, как в переоборудованном гараже пара программистов сделала замечательную программу, оставившую позади разработки больших команд. И каждый программист охотно верит в эти сказки, поскольку знает, что может создать любую программу со скоростью, значительно превышающей те 1000 операторов в год, которые, по сообщениям, пишут программисты в промышленных бригадах.
Почему же до сих пор все профессиональные бригады программистов не заменены одержимыми дуэтами из гаражей? Нужно посмотреть на то, что, собственно, производится.
В левом верхнем углу рисунка 1.1 находится программа. Она является завершенным продуктом, пригодным для запуска своим автором на системе, на которой была разработана. В гаражах обычно производится такой продукт, и это — тот объект, посредством которого отдельный программист оценивает свою производительность.
Есть два способа, которыми программу можно превратить в более полезный, но и более дорогой объект. Эти два способа представлены по краям рисунка.
При перемещении вниз через горизонтальную границу программа превращается в программный продукт. Это программа, которую любой человек может запускать, тестировать, исправлять и развивать. Она может использоваться в различных операционных средах и со многими наборами данных. Чтобы стать общеупотребительным программным продуктом, программа должна быть написана в обобщенном стиле. В частности, диапазон и вид входных данных должны быть настолько обобщенными, насколько это допускается базовым алгоритмом. Затем программу нужно тщательно протестировать, чтобы быть уверенным в ее надежности. Для этого нужно подготовить достаточное количество контрольных примеров для проверки диапазона допустимых значений входных данных и определения его границ, обработать эти примеры и зафиксировать результаты. Наконец, развитие программы в программный продукт требует создания подробной документации, с помощью которой каждый мог бы использовать ее, делать исправления и расширять. Я пользуюсь практическим правилом, согласно которому программный продукт стоит, по меньшей мере, втрое дороже, чем просто отлаженная программа с такой же функциональностью.
Рис. 1.1 Эволюция системного программного продукта
При пересечении вертикальной границы программа становится компонентом программного комплекса. Последний представляет собой набор взаимодействующих программ, согласованных по функциям и форматам, и вкупе составляющих полное средство для решения больших задач. Чтобы стать частью программного комплекса, синтаксис и семантика ввода и вывода программы должны удовлетворять точно определенным интерфейсам. Программа должна быть также спроектирована таким образом, чтобы использовать заранее оговоренный бюджет ресурсов — объем памяти, устройства ввода/вывода, процессорное время. Наконец, программу нужно протестировать вместе с прочими системными компонентами во всех сочетаниях, которые могут встретиться. Это тестирование может оказаться большим по объему, поскольку количество тестируемых случаев растет экспоненциально. Оно также занимает много времени, так как скрытые ошибки выявляются при неожиданных взаимодействиях отлаживаемых компонентов. Компонент программного комплекса стоит, по крайней мере, втрое дороже, чем автономная программа с теми же функциями. Стоимость может увеличиться, если в системе много компонентов.
В правом нижнем углу рисунка 1.1 находится системный программный продукт. От обычной программы он отличается во всех перечисленных выше отношениях. И стоит, соответственно, в десять раз дороже. Но это действительно полезный объект, который является целью большинства системных программных проектов.
Радости профессии
Почему заниматься программированием интересно? Какими радостями вознаграждаются те, кто им занимается?
Во-первых, это просто радость, получаемая при создании чего-либо своими руками. Как ребенок радуется, делая куличики из песка, так и взрослый получает удовольствие, создавая какие-либо вещи, особенно если сам их и придумал. Я думаю, что этот восторг — отражение восторга Господа, творящего мир, восторга, проявляющегося в индивидуальности и новизне каждого листочка и каждой снежинки.
Во-вторых, это удовольствие создавать вещи, которые могут быть полезны другим людям. Глубоко в душе мы испытываем потребность в том, чтобы другие использовали результаты нашего труда и считали их полезными. В этом отношении программная система по своей сути — то же, что и изготовленная ребенком подставка для карандашей «папе в подарок».
В-третьих, это очарование создания сложных головоломных объектов, состоящих из взаимодействующих движущихся частей и наблюдения за их работой, круг за кругом демонстрирующей результаты изначально заложенных принципов. Компьютер с работающей на нем программой обладает доведенным до высшего предела очарованием игорного или музыкального автомата.
В-четвертых, это радость, получаемая от неизменного узнавания нового, проистекающего из неповторимой природы задачи. В том или ином отношении задача всегда ставится по-новому, и тот, кто ее решает, получает новые знания — либо практические, либо теоретические, либо те и другие вместе.
Наконец, наслаждение доставляет работа со столь податливым материалом. Программист, подобно поэту, работает почти непосредственно с чистой мыслью. Он строит свои замки в воздухе и из воздуха, творя силой воображения. Трудно найти другой материал, используемый в творчестве, который столь же гибок, прост для шлифовки или переработки и доступен для воплощения грандиозных замыслов. (Как мы позднее увидим, такая податливость таит свои проблемы.)
Однако программная конструкция, в отличие от поэтических творений, реальна, в том смысле, что она движется и работает, производя видимые результаты, которые отделимы от самой конструкции. Она печатает результаты, рисует картинки, производит звуки, приводит в движение рычаги. В наше время осуществилось волшебство мифа и легенды. С клавиатуры вводится верное заклинание, и экран монитора оживает, показывая то, чего никогда не было и не могло быть.
Таким образом, программирование доставляет удовольствие, поскольку отвечает глубокой внутренней потребности в творчестве и удовлетворяет чувственные потребности, которые есть у всех нас.
Печали профессии
Не все, однако, в радость, и если предвидеть присущие этому ремеслу огорчения, то они легче переносятся.
Во-первых, необходима безошибочная точность действий. В этом отношении компьютер также напоминает волшебство. Один неверный знак, одна пауза в заклинании, и чудо не состоялось. Человеку несвойственно совершенство, и оно является необходимым лишь в немногих сферах его деятельности. Мне кажется, что при освоении программирования труднее всего привыкнуть к требованию совершенства.[1]
Кроме того, постановка задач, обеспечение ресурсами и предоставление информации осуществляется другими людьми. Редко удается контролировать условия работы и даже ее цели. На языке администрирования это означает, что полномочия ниже ответственности. Впрочем, похоже, что в любой работе, где должен быть получен результат, формальная власть никогда не соизмерима с ответственностью. На практике фактическая (в противоположность формальной) власть приобретается в результате успешного выполнения задач.
Зависимость от других имеет особенно неприятную системному программисту сторону. Он находится в зависимости от программ, написанных другими людьми, и эти программы зачастую плохо спроектированы, слабо написаны, получены в неполном виде (без исходного текста и контрольных примеров) и плохо документированы. Поэтому программисту приходится тратить многие часы на изучение и исправление вещей, которые, в идеале, должны быть полными, доступными и годными к использованию.
Следующий «минус» связан с тем, разработка грандиозных идей — это удовольствие, а поиск паршивых маленьких «жучков» — это всего лишь работа. В каждом творческом деле бывают ужасные периоды однообразного и кропотливого труда, и программирование не является исключением.
Далее оказывается, что при отладке программы сходимость является линейной, если не хуже, хотя можно было предполагать некое квадратичное приближение к окончанию. В итоге отладка продолжается долго, причем на поиск последних более сложных ошибок уходит больше времени, чем на отыскание первых.
Последняя горесть, а часто и последняя капля, — то, что продукт, на который было положено столько труда, оказывается устаревшим в момент его завершения (или даже раньше). Коллеги и конкуренты уже с пылом работают над новыми и лучшими идеями. И уничтожение плода вашей мысли уже не только задумано, но и запланировано.
На самом деле положение обычно лучше, чем кажется. В то время как ваш продукт уже завершен, этот новый и лучший продукт, как правило, отсутствует на рынке, о нем лишь много разговоров, и для его разработки потребуются месяцы. Настоящий тигр не пара бумажному, если требуется реальное использование. Реальное существование имеет преимущества.
Конечно, технологическая основа разработки всегда развивается. Как только разработка проекта закончена, он становится устаревшим в смысле заложенных в нем концепций. Но для осуществления реального проекта необходимо разбиение на стадии и уровни. Судить о том, является ли некая реализация устаревшей, можно лишь сравнивая ее с другими существующими реализациями, а не с нереализованными идеями. Трудность и цель состоят в том, чтобы найти реальные решения для реальных задач в установленные сроки, используя имеющиеся ресурсы.
Таково программирование — и смоляная яма, в которой увязли многие проекты, и творчество со своими радостями и печалями. Для многих радости значат гораздо больше, чем печали. Для них и написана эта книга в попытке проложить какие-то мостки через это болото.
Глава 2 Этот мифический «человеко-месяц»
Чтобы приготовить вкусную пищу, требуется время. Если вам пришлось ждать, то лишь потому, что мы хотим лучше обслужить вас и доставить вам удовольствие.
МЕНЮ РЕСТОРАНА «АНТУАН» В НЬЮ-ОРЛЕАНЕ
Программные проекты чаще проваливаются из-за нехватки календарного времени, чем по всем остальным причинам вместе взятым. Почему эта причина неудач столь распространена?
Во-первых, слабо развиты наши методы оценок. В сущности, они отражают молчаливое и совершенно неверное предположение, что все будет идти хорошо.
Во-вторых, наши методы оценки ошибочно путают достигнутый прогресс с затраченными усилиями, неявно допуская, что скорость выполнения проекта пропорциональна количеству занятых в нем сотрудников.
В-третьих, поскольку менеджеры программных проектов не уверены в своих оценках, им часто недостает вежливого упрямства, как у шеф-повара ресторана «Антуан».
В-четвертых, выполнение графика работ слабо контролируется. Типовые опробованные в других инженерных дисциплинах методы считаются радикальными нововведениями при разработке программного обеспечения.
В-пятых, при обнаружении отставания от графика естественной и общепринятой реакцией является увеличение числа разработчиков. Это все равно, что тушить пламя бензином. В результате дела идут значительно хуже. Чем сильнее пламя, тем больше нужно бензина, и в итоге этот путь приводит к катастрофе.
Контроль выполнения графика будет предметом отдельного разговора. Рассмотрим более подробно остальные аспекты проблемы.
Оптимизм
Все программисты — оптимисты. Возможно, эта современная разновидность колдовства особенно привлекательна для тех, кто верит в хэппи-энды и добрых фей. Возможно, сотни неудач отталкивают всех, кроме тех, кто привык сосредоточиваться на конечной цели. А может быть, дело всего лишь в том, что компьютеры и программисты молоды, а молодости свойствен оптимизм. Как бы то ни было, в результате одно: «На этот раз она точно пойдет!» Или : «Я только что выявил последнюю ошибку!»
Итак, в основе планирования разработки программ лежит ложное допущение, что все будет хорошо, т.е. каждая задача займет столько времени, сколько «должна» занять.
Глубокий оптимизм программистов заслуживает более серьезного изучения. Дороти Сэйерс (Dorothy Cayers) в своей превосходной книге «Разум творца» (“The Mind of the Maker”) выделяет в творческой деятельности три стадии: замысел, реализацию, взаимодействие. Соответственно, книга, компьютер или программа сначала возникают как идеальное построение, существующее не во времени и пространстве, а лишь в мозгу своего создателя. Реализация же во времени и пространстве происходит с помощью пера, чернил, бумаги, либо — проводов, кремния и феррита. Творение будет завершено, когда кто-либо прочтет книгу, воспользуется компьютером или запустит программу, тем самым вступив во взаимодействие с разумом их создателя.
Это описание используемое Сэйерс для освещения не только творческой деятельности человека, но и христианского догмата Троицы, поможет нам в нашей текущей задаче. Для человека, который что-то создает, неполнота и противоречивость идей выявляются только при их реализации. Поэтому для теоретика изложение на бумаге, экспериментирование, изготовление является неотъемлемыми частями творческого процесса.
Во многих видах творческой деятельность материал с трудом поддается обработке. Дерево колется, краски пачкаются, электрические цепи «звенят». Эти физические ограничения сужают круг идей, которые могут быть выражены, а также создают неожиданные трудности при реализации.
Реализация, таким образом, требует сил и времени как из-за физического материала, так и ввиду неадекватности основополагающих идей. Большую часть затруднений при реализации мы склонны объяснять недостатками физического материала, поскольку он «чужд» нам — в отличие от идей, которыми мы гордимся.
При создании же программ мы имеем дело с чрезмерно податливым материалом. Программист осуществляет свои построения на основе чистого мышления — понятий и очень гибких их представлений. Поскольку материал столь податлив, мы не ожидаем трудностей при реализации, отсюда и наш глубокий оптимизм. Из-за ошибочности наших идей возникают ошибки в программах. Следовательно, наш оптимизм не имеет оправдания.
Для отдельной задачи допущение, что все буде хорошо, оказывает на график работ вероятностный эффект. Все может действительно идти по плану, поскольку есть некоторое распределение вероятности для возможной задержки и существует конечная вероятность того, что задержки не будет. Однако большой программный проект состоит из множества задач, часть из которых может быть начата только после окончания других. Вероятность того, что все задачи будут завершены в срок, бесконечно мала.
Человеко-месяц
Вторая ошибка рассуждений заключена в самой единице измерения, используемой при оценивании и планировании: человеко-месяц. Стоимость действительно измеряется как произведения числа занятых на количество затраченных месяцев. Но не достигнутый результат. Поэтому использование человеко-месяца как единицы измерения объема работы является опасным заблуждением.
Рис. 2.1 Зависимость времени от числа занятых — полностью разделимая задача
Число занятых и число месяцев являются взаимозаменяемыми величинами лишь тогда, когда задачу можно распределить среди ряда работников, которые не имеют между собой взаимосвязи (рис. 2.1). Это верно, когда жнут пшеницу или собирают хлопок, но в системном программировании это далеко не так.
Рис. 2.2 Зависимость времени от числа занятых — неразделимая задача
Если задачу нельзя разбить на части, поскольку существуют ограничения на последовательность выполнения этапов, то увеличение затрат не оказывает влияния на график (рис. 2.2). Чтобы родить ребенка требуется девять месяцев независимо от того, сколько женщин привлечено к решению данной задачи. Многие задачи программирования относятся к этому типу, поскольку отладка по своей сути носит последовательный характер.
Рис. 2.3 Зависимость времени от числа занятых — разделимая задача, требующая обмена данными
Для задач, которые могут быть разбиты на части, но требуют обмена данными между подзадачами, затраты на обмен данными должны быть добавлены к общему объему необходимых работ. Поэтому достижимый наилучший результат оказывается несколько хуже, чем простое соответствие числа занятых и количества месяцев (рис. 2.3).
Дополнительная нагрузка состоит из двух частей — обучения и обмена данными. Каждого работника нужно обучить технологии, целям проекта, общей стратегии и плану работы. Это обучение нельзя разбить на части, поэтому данная часть затрат изменяется линейно в зависимости от числа занятых.
Рис. 2.4 Зависимость времени от числа занятых — задача со сложными взаимосвязями
С обменом данными дело обстоит хуже. Если все части задания должны быть отдельно скоординированы между собой, то затраты возрастают как n(n-2)/2. Для трех работников требуется втрое больше попарного общения, чем для двух, для четырех — вшестеро. Если помимо этого возникает необходимость в совещаниях трех, четырех и т.д. работников для совместного решения вопросов, положение становится еще хуже. Дополнительные затраты на обмен данными могут полностью обесценить результат дробления исходной задачи и привести к положению, описываемому рисунком 2.4.
Поскольку создание программного продукта является по сути системным проектом — практикой сложных взаимосвязей, затраты на обмен данными велики и быстро начинают преобладать над сокращением сроков, достигаемым в результате разбиения задачи на более мелкие подзадачи. В этом случае привлечение дополнительных работников не сокращает, а удлиняет график работ.
Системное тестирование
Из всех элементов графика работ наибольшему воздействию со стороны ограничений на последовательность выполнения действий подвержены отладка компонентов и системное тестирование. Кроме того, затраты времени зависят от количества выявленных ошибок и от того, насколько они «скрытые». Теоретически, ошибок быть не должно. Из-за своего оптимизма мы обычно склонны недооценивать действительное количество ошибок. Поэтому в программировании придерживаться графиков работ обычно труднее всего при отладке.
В течение ряда лет при планировании разработки программного обеспечения я пользуюсь следующим эмпирическим правилом:
1/3 — планирование,
1/6 — написание программ,
1/4 — тестирование компонентов и предварительное системное тестирование,
1/4 — системное тестирование при наличии всех компонентов.
Это правило имеет несколько важных различий с общепринятым планированием:
1. На планирование отводится больше времени, чем обычно. И все равно этого времени едва достаточно для разработки подробных и надежных технических условий и недостаточно для проведения исследовательских работ или поиска новейших технологий.
2. Половина графика работ, отведенная на отладку законченного кода, значительно выше нормы.
3. Та часть, которую легко оценить, т.е. написание кода, занимает всего одну шестую общего времени.
Изучая проекты, график которых был составлен традиционным образом, я обнаружил, что немногие из них отводили по графику половину времени на отладку, но на практике в большинстве случаев тратили на нее половину фактического времени. Многие проекты укладывались в график на всех этапах, исключая системное тестирование.[2]
Особенно катастрофические последствия может иметь недостаток времени для системного тестирования. Поскольку задержка происходит в конечной части графика, никто не подозревает о том, что график находится под угрозой срыва вплоть до дня сдачи продукта. Плохие вести, полученные поздно и без предупреждения, обескураживают клиентов и менеджеров.
Более того, задержка на этом этапе имеет особенно тяжелые материальные и психологические последствия. Проект осуществляется при полной
укомплектованности работниками и максимальных финансовых издержках. Что важнее, программное обеспечение должно обеспечить поддержку другой деловой активности (поставки компьютеров, запуска новых производственных мощностей и т.п.), и связанные с задержкой вторичные издержки очень высоки. На практике эти вторичные издержки могут быть выше, чем все прочие. Поэтому очень важно в изначальном графике работ отвести достаточно времени для системного тестирования.
Робость в оценках
Для программиста, как и для повара, давление со стороны хозяина может определять запланированный срок завершения задачи, но не может определять время ее фактического завершения. Омлет, обещанный через две минуты, может успешно жариться, но если через две минуты он не готов, то у клиента есть две возможности: ждать еще или съесть его сырым. Тот же выбор встает и перед заказчиком программного обеспечения.
У повара есть еще одна возможность: добавить жару. В результате омлет часто оказывается безнадежно испорченным: горелым с одного края и сырым — с другого.
Я не думаю, что у менеджеров программных продуктов меньше храбрости или твердости, чем у поваров или других менеджеров в инженерных областях. Но липовые графики, нацеленные на желательную хозяину дату, встречаются здесь значительно чаще, чем в любых других инженерных областях. Очень тяжело, рискуя потерять рабочее место, с энергией и любезностью отстаивать срок, который определен без применения каких-либо количественных методов при недостатке данных и подкреплен, в основном, интуицией менеджера.
Очевидно, необходимо сделать две вещи. Мы должны получить и сделать общедоступными численные данные, характеризующие производительность, частоту программных ошибок, методы оценки и т.д. Вся отрасль может только выиграть от опубликования таких данных.
Пока методы оценивания не получат более прочной основы, менеджерам остается только мужаться и защищать свои прогнозы, утверждая, что полагаться на их слабую интуицию все же лучше, чем основываться на одних желаниях.
Действия при срыве графика
Что делают, когда важный программный проект начинает отставать от графика? Естественно, добавляют людей. Как показывают рисунки 2.1-2.4, это не всегда помогает.
Рассмотрим пример.[3] Предположим, что трудоемкость задачи оценивается в 12 человеко-месяцев, и три человека должны выполнить ее за 4 месяца, причем в конце каждого месяца имеются четыре контрольные точки A, B, C и D, в которых можно произвести измерения (рис. 2.5).
Рис. 2.5
Предположим теперь, что первая контрольная точка была достигнута лишь по истечении двух месяцев. Какие альтернативы имеются у менеджера?
1. Допустим, что необходимо соблюсти срок выполнения задачи, и ошибочно оценена была только первая часть задачи, т.е. рисунок 2.6 верно отражает положение. Значит, остается 9 человеко-месяцев трудозатрат и два месяца, поэтому понадобится 4Ѕ человека, и к троим имеющимся нужно добавить еще двоих.
Рис. 2.6
2. Допустим, что необходимо соблюсти срок выполнения задачи, и одинаково занижена была вся оценка , т.е. положение соответствует рисунку 2.7. Значит, остается 18 человеко-месяцев трудозатрат и два месяца, поэтому понадобится 9 человек. К троим имеющимся нужно добавить еще шестерых.
Рис. 2.7
3. Изменить график. Мне нравится замечание, сделанное П. Фаггом (P. Fagg), опытным инженером по вычислительной технике: «Маленьких задержек не бывает». Это означает, что в новом графике должно быть достаточно времени, чтобы работа была исполнена тщательно и полностью, и не пришлось бы вновь переделывать график.
4. Сократить задачу. На практике этим всегда и кончается, когда команда обнаруживает, что не укладывается в график. Когда очень высоки вторичные издержки, это единственное, что можно сделать. Менеджеру предоставляется возможность официально и аккуратно сократить задачу, изменить график, либо наблюдать, как задача молча урезается при поспешном изменении проекта и неполном тестировании.
В первых двух случаях настаивать на том, чтобы задача в неизменном виде была выполнена за четыре месяца, чревато катастрофой. Рассмотрим, к примеру, восстановительный эффект первой альтернативы (рис. 2.8). Двое новых работников, какими бы знающими они ни были, и как бы быстро не удалось их найти, должны изучить задачу с помощью одного из опытных разработчиков. Если для этого потребуется месяц, то 3 человеко-месяца будут потрачены на работу, которая не учитывается в исходной оценке. Кроме того, задача, разбитая первоначально на три потока, должна быть теперь перекроена на пять частей. Поэтому часть уже сделанной работы будет потеряна, а системное тестирование нужно будет продлить. В результате в конце третьего месяца останется работы существенно больше, чем на 7 человеко-месяцев, а в распоряжении будет 5 подготовленных человек и один месяц. Согласно рисунку 2.8 продукт будет запаздывать так же, как если бы ни одного человека не было добавлено (см. рис. 2.6).
Если рассчитывать управиться за четыре месяца с учетом только времени обучения, но не перераспределения задач и дополнительного системного тестирования, то в конце второго месяца потребуется добавить 4, а не 2 человека. Чтобы компенсировать воздействие перераспределения задач и системного тестирования, потребуются еще новые люди. Теперь, однако, команда состоит не из 3, а, по крайней мере, 7 человек, и такие вопросы, как организация команды и распределение задач приобретают новый качественный уровень.
Обратите внимание, что к концу третьего месяца дело выглядит весьма мрачно. Несмотря на все административные усилия контрольная точка, намеченная на 1 марта, не достигнута. Возникает сильный соблазн повторить цикл, добавив еще людей. Это безумное решение.
Рис. 2.8
В предшествующих рассуждениях предполагалось, что только первая контрольная точка была неверно рассчитана. Если 1 марта сделать консервативное предположение, что весь график был излишне оптимистичен, как отражено на рисунке 2.7, требуется добавить 6 человек к исходной задаче. Расчет воздействия обучения, перераспределения задач и системного тестирования предоставляется сделать читателю в качестве упражнения. Нет сомнений, что при попытке уложиться в срок в итоге получится худший продукт, чем при изменении графика и сохранении первоначальных троих человек без усиления.
Крайне упрощая, сформулируем Закон Брукса:
Если проект не укладывается в сроки, то добавление рабочей силы задержит его еще больше.
Это развенчивает миф о человеко-месяце. Продолжительность осуществления проекта зависит от ограничений, накладываемых последовательностью работ. Максимальное количество разработчиков зависит от числа независимых подзадач. Эти две величины позволяют получить график работ, в котором будет меньше занятых разработчиков и больше месяцев. (Единственная опасность заключается в возможном устаревании продукта.) Нельзя, однако, составить работающие графики, в которых занято больше людей и требуется меньше времени. Программные проекты чаще проваливаются из-за нехватки календарного времени, чем по всем остальным причинам вместе взятым.
Глава 3 Операционная бригада
Эти исследования выявили большие индивидуальные различия в производительности между лучшими и худшими работниками, часто на порядок величин.
САКМАН, ЭРИКСОН И ГРАНТ[1]
На встречах компьютерных специалистов можно постоянно слышать утверждения молодых менеджеров программных проектов, что им предпочтительней небольшие деятельные команды первоклассных специалистов, чем проекты, в которых участвуют сотни программистов, что подразумевает их средний уровень. И всем нам тоже.
Такое наивное представление альтернатив уходит от решения сложной задачи — как создавать большие системы в разумные сроки? Рассмотрим этот вопрос более подробно со всех сторон.
Проблема
Менеджеры программных проектов давно поняли, что хорошие и плохие программисты очень сильно различаются между собой по производительности. Однако реально измеренные величины поразительны. В одном из исследований Сакман (Sackman), Эриксон (Erikson) и Грант (Grant) измеряли производительность труда в группе опытных программистов. Внутри одной лишь этой группы соотношение между лучшими и худшими результатами составило примерно 10:1 по производительности труда и 5:1 по скорости работы программ и требуемой для них памяти! Короче, программист, зарабатывающий 20 тысяч долларов в год, может быть в десять раз продуктивнее программиста, зарабатывающего 10 тысяч долларов. Правда, возможно и обратное. Полученные данные не выявили какой-либо корреляции между стажем работы и производительностью. (Я не уверен, что это всегда справедливо.)
Выше я доказал, что само число разработчиков, действия которых нужно согласовывать, оказывает влияние на стоимость проекта, поскольку значительная часть издержек вызвана необходимостью общения и устранения отрицательных последствий разобщенности (системная отладка). Это также наводит на мысль, что желательно разрабатывать системы возможно меньшим числом людей. Действительно, опыт разработки больших программных систем, как правило, показывает, что подход с позиций грубой силы влечет удорожание, замедленность, неэффективность, а создаваемые в результате системы не являются концептуально целостными. Список, иллюстрирующий это, бесконечен: OS/360, Exec 8, Scop 6600, Multics, TSS, SAGE и другие.
Вывод прост: если над проектом работают 200 человек, включая менеджеров, являющихся наиболее знающими и опытными программистами, увольте 175 бойцов, и пусть менеджеры снова займутся программированием.
Давайте рассмотрим это решение. С одной стороны, ему не удается приблизиться к идеалу небольшой активной команды, в которой, по общему признанию, должно быть не более 10 человек. Поэтому размер бригады предполагает наличие как минимум двух уровней управления, или около пяти менеджеров. Потребуются дополнительны финансовые расходы, сотрудники, место для работы, секретари и операторы машин.
С другой стороны, исходная команда из 200 человек имела численность, недостаточную для создания действительно крупных систем методом грубой силы. Рассмотрим, к примеру, OS/360. Одно время в ее создании было занято больше 1000 человек — программистов, составителей документации, операторов, клерков, секретарей, менеджеров, вспомогательных групп и т.д. С 1963 по 1966 год на ее проектирование, реализацию и написание документации было затрачено, вероятно, около 5000 человеко-лет. Если бы строго соблюдалась пропорция между количеством занятых и продолжительностью работ, нашей предполагаемой команде из двухсот человек потребовалось бы 25 лет, чтобы довести продукт до сегодняшнего уровня!
В этом и состоит изъян идеи маленькой активной команды: для создания по-настоящему крупных систем ей потребуется слишком много времени. Посмотрим, как разработка OS/360 осуществлялась бы маленькой активной командой, допустим, из 10 человек. Положим, что они в семь раз более продуктивны средних программистов (что далеко от истины). Допустим, что уменьшение объема общения благодаря малочисленности команды позволило еще в семь раз повысить производительность. Допустим, что на протяжении всего проекта работает одна и та же команда. Таким образом, 5000/(10*7*7)=10, т.е. работу в 5000 человеко-лет они выполнят за 10 лет. Будет ли продукт представлять интерес через 10 лет после начала разработки или устареет благодаря стремительному развитию программных технологий?
Дилемма представляется жестокой. Для эффективности и концептуальной целостности предпочтительнее, чтобы проектирование и создание системы осуществили несколько светлых голов. Однако для больших систем желательно поставить под ружье значительный контингент, чтобы продукт мог увидеть свет вовремя. Как можно примирить эти два желания?
Предложение Миллза
Предложение Харлана Миллза дает свежее и творческое решение[2,3]. Миллз предложил, чтобы на каждом участке работы была команда разработчиков, организованная наподобие бригады хирургов, а не мясников. Имеется в виду, что не каждый участник группы будет врезаться в задачу, но резать будет один, а остальные оказывать ему всевозможную поддержку, повышая его производительность и плодотворность.
При некотором размышлении ясно, что эта идея приведет к желаемому, если ее удастся осуществить. Лишь несколько голов занято проектированием и разработкой, и в то же время много работников находится на подхвате. Будет ли такая организация работать? Кто играет роль анестезиологов и операционных сестер в группе программистов, а как осуществляется разделение труда? Чтобы нарисовать картину работы такой команды с включением всех мыслимых видов поддержки, я позволю себе вольное обращение к метафорам.
Хирург. Миллз называет его главным программистом. Он лично определяет технические условия на функциональность и эксплуатационные характеристики программы, проектирует ее, пишет код, отлаживает его и составляет документацию. Он пишет на языке структурного программирования, таком как PL/I, и имеет прямой доступ к компьютерной системе, на которой не только производится отладка, но и сохраняются различные версии его программ с возможностью легкой модификации файлов, а также осуществляет редактирование документации. Он должен обладать большим талантом, стажем работы свыше десяти лет и существенными знаниями в системных и прикладных областях, будто прикладная математика, обработка деловых данных или что-либо иное.
Второй пилот. Это второе «я» хирурга, может выполнять любую его работу, но менее опытен. Его главная задача — участвовать в проектировании, где он должен думать, обсуждать и оценивать. Хирург испытывает на нем свои идеи, но не связан его предложениями. Часто второй пилот представляет свою бригаду при обсуждении с другими группами функций и интерфейса. Он хорошо знает весь код программы. Он исследует возможности альтернативных стратегий программирования. Он, очевидно, подстраховывает на случай какой-либо беды с хирургом. Он может даже заниматься написанием кода, но не несет ответственности за какую-либо его часть.
Администратор. Хирург — начальник, и ему принадлежит последнее слово в отношении персонала, прибавок к жалованью, помещений и т.п., но на эти дела он должен тратить как можно меньше времени. Поэтому ему необходим профессиональный администратор, заботой которого будут деньги, люди, помещения, машины, и который будет контактировать с административным механизмом организации в целом. Бейкер считает, что на полный рабочий день администратор должен привлекаться лишь в случае, когда отношения с заказчиком определяют существенные юридические, контрактные, отчетные или финансовые требования к проекту. В остальных случаях один администратор может обслуживать две команды.
Редактор. Обязанность разработки документации лежит на хирурге. Чтобы она была максимально понятна, он должен писать ее сам. Это относится к описаниям, предназначенных как для внешнего, так и для внутреннего использования. Задача редактора — взять созданный хирургом черновик или запись под диктовку, критически переработать, снабдить ссылками и библиографией, проработать несколько версий и обеспечить публикацию.
Два секретаря. Администратору и редактору нужны секретари. Секретарь администратора обрабатывает переписку, связанную с проектом, а также документы, не относящиеся к продукту.
Делопроизводитель. Он отвечает за регистрацию всех технических данных бригады в библиотеке программного продукта. Он имеет секретарскую подготовку и несет ответственность за все файлы, предназначенные как для машины, так и для чтения.
Все данные для ввода в компьютер поступают делопроизводителю, который регистрирует их или вводит при необходимости с клавиатуры. Листинги вывода также поступают к нему для регистрации и хранения. Результаты самых свежих прогонов всех моделей заносятся в журнал результатов, а предыдущие хранятся в хронологическом порядке в архиве.
Жизненно важным для концепции Миллза является превращение программирования «из личного искусства в общественную деятельность» путем предоставления результатов всех прогонов всем членам команды и определения всех программ и данных, как общей собственности команды, а не чьей-то личной.
Особые обязанности, возлагаемые на делопроизводителя, освобождают активных программистов от рутинных работ, систематизируют и обеспечивают надлежащее выполнение тех рутинных операций, которыми часто пренебрегают, и приближают главное, для чего работает команда — ее программный продукт. Ясно, что предложенная концепция предполагает прогон пакетных заданий. Если используются интерактивные терминалы, в особенности без возможности печати, функции делопроизводителя не сокращаются, но претерпевают изменения. В этом случае он ведет учет всех изменений, вносимых в общий экземпляр программы из личных копий, осуществляет прогон всех пакетных заданий и со своего терминала осуществляет контроль целостности и работоспособности увеличивающегося в размерах продукта.
Инструментальщик. Благодаря возможности в любое время редактировать файлы и тексты и пользоваться службой интерактивной отладки команде редко требуется своя вычислительная машина и группа обслуживающего персонала. Но доступ к этим службам должен осуществляться с безусловной быстротой и надежностью. Только хирург может решать, удовлетворяет ли его работа имеющихся служб. Ему необходим инструментальщик, ответственный за обеспечение доступа к основным службам, а также за создание, поддержку и обновление специальных инструментов — в основном, интерактивных служб, которые требуются его команде. У каждой команды должен быть свой инструментальщик, независимо от качества и надежности имеющихся централизованных служб, и его дело обеспечить всем необходимым или желательным инструментом своего хирурга, а не другие команды. Инструментальщик обычно пишет специализированные утилиты,
каталогизированные процедуры, макробиблиотеки.
Отладчик. Хирургу потребуется набор подходящих контрольных примеров для отладки написанных им фрагментов кода, а затем и всей программы. Отладчик является, таким образом, как противником, разрабатывающим контрольные примеры для системного тестирования, исходя из функциональных спецификаций, так и помощником, готовящим данные для ежедневной отладки. Он также обычно планирует последовательность тестирования и создание среды для тестирования компонентов.
Языковед. Вскоре после появления Algol обнаружилось, что в большинстве вычислительных центров есть один-два человека, поражающих своим владением тонкостями языка программирования. Эти эксперты оказываются очень полезными, и с ними часто советуются. Здесь требуется иной талант, чем у хирурга, который является преимущественно системным проектировщиком и мыслит представлениями. Языковед может найти эффективные способы использования языка для решения сложных, неясных и хитроумных задач. Иногда ему требуется провести небольшое исследование (два-три дня) для нахождения удачной технологии. Один языковед может работать с двумя или тремя хирургами.
Вот таким образом 10 человек могут выполнять хорошо дифференцированные и специализированные роли в команде программистов, организованной по образцу операционной бригады.
Как это работает
Созданная нами бригада может достичь желаемой цели несколькими способами. Над задачей трудятся десять человек, семь из которых профессионалы, но система является продуктом одного ума, по крайней мере двух, действующих uno animo (как одно целое).
Обратите особое внимание на различие между группой из двух программистов с обычной организацией и группой типа «хирург — второй пилот». Во-первых, в обычной бригаде работники делят задачу между собой, и каждый из них отвечает за замысел и воплощение некоторой части. В операционной бригаде и хирург, и второй пилот находятся в ведении всего проекта и всего программного кода. Это сберигает затраты на распределение памяти, доступ к дискам и т.п., а также обеспечивает концептуальную целостность продукта.
Во-вторых, в обычной бригаде партнеры равны, и неизбежные разногласия должны разрешаться путем переговоров или компромиссов. Поскольку задача и ресурсы разделены, разногласия относятся к общей стратегии и интерфейсам, но к ним примешивается и противоположность интересов, например, чью память использовать для буфера. В хирургической бригаде различий интересов нет, а разногласия единолично решаются хирургом. Эти два различия — отсутствие разбиения задачи и отношение подчиненности — позволяют хирургической бригаде действовать uno animo.
Кроме того, решающее влияние на эффективность оказывает специализация функций остальных членов бригады, так как в результате осуществима значительно более простая схема контактов между сотрудниками, которая показана на рисунке 3.1.
В статье Бейкера [3] сообщается об одной проверке такой концепции бригады, проведенной в ограниченном масштабе. Как и предсказывалось, результаты оказались великолепными.
Масштабирование
До сих пор все было хорошо. Проблема, однако, состоит в том, как создавать продукты, на которые сейчас уходит не 20 или 30, а 5000 человеко-лет. Бригада из 10 человек может быть эффективна вне зависимости от своей организации, если задача целиком находится в ее компетенции. Но как использовать идею операционной бригады в задачах, для выполнения которых привлекаются сотни людей?
Успех при масштабировании обусловливается коренным улучшением концептуального единства каждого участка, ведь количество проектировщиков уменьшилось в семь раз. Поэтому можно привлечь к работе над задачей 200 человек, и необходимость координации умственных усилий потребуется всего для 20 из них — хирургов.
Рис. 3.1 Схема контактов между сотрудниками в бригаде из 10 человек
Однако задача координации требует использования особых методов, обсуждаемых в последующих главах. Пока достаточно сказать, что вся система в целом должна обладать концептуальным единством, и необходим системный архитектор, чтобы проектировать ее целиком, в нисходящем направлении. Для того чтобы этой работой можно было управлять, необходимо провести строгое разграничение архитектуры и воплощения, и системный архитектор должен добросовестно посвятить себя разработке архитектуры. Опыт показывает, что такое распределение ролей и такие методы осуществимы и оказываются весьма результативными.
Глава 4 Аристократия, демократия и системное проектирование
Этот величественный храм является выдающимся произведением искусства. В принципах, которые он излагает, нет ни сухости, ни беспорядка…
Это вершина стиля, труд художников, которые поняли и восприняли все достижения своих предшественников, в совершенстве владея техникой своего века, но пользовались ей, избегая нескромного показа или необоснованной демонстрации мастерства.
Несомненно, замысел общего плана здания принадлежит д’Орбе, и те, кто его сменил, придерживались этого плана, по крайней мере, в существенных чертах. Это одна из причин удивительной гармоничности и единства здания.
ПУТЕВОДИТЕЛЬ ПО РЕЙМСКОМУ СОБОРУ[1]
Концептуальное единство
У большинства европейских соборов части, построенные разными поколениями строителей, имеют различия в планировке и архитектурном стиле. Более поздние строители испытывали соблазн «улучшить» проект своих предшественников, чтобы отразить новые веяния моды и свои личные вкусы. В итоге мирный норманнский трансепт создает конфликт с примыкающим к нему возносящимся в высь готическим нефом, и результат столь же служит восхвалению славы Господней, сколь и гордыни строителей.
Архитектурное единство Реймского собора находится в прямой противоположности с таким смешением стилей. Источником наполняющей зрителя радости служат как цельность конструкции, так и отдельные образцы совершенства. Как сказано в путеводителе, цельность была достигнута благодаря самоотречению восьми поколений строителей собора, пожертвовавших своими идеями ради чистоты общего замысла. То что получилось в результате, служит восхвалению не только славы Господней, но и Его могущества, способного спасти грешных людей от их гордыни.
Хотя на создание программных систем не уходят века, в большинстве своем они демонстрируют меньшую согласованность концепций, чем в любом соборе. Обычно это происходит не оттого, что главные проектировщики сменяют друг друга, а потому, что проект расщепляется на ряд задач, выполняемых разными разработчиками.
Я убежден, что концептуальная целостность является важнейшей характеристикой системного проекта. Лучше убрать из системы отдельные необычные возможности и усовершенствования и реализовать единый набор конструктивных идей, чем оснастить ее многими хорошими, но невзаимосвязанными и несогласованными идеями. В этой и двух последующих главах мы изучим следствия этой концепции для проектирования программных систем:
• Как достичь концептуальной целостности?
• Не будет ли это требование причиной раскола на элиту, аристократический класс архитекторов — с одной стороны, и толпы плебеев-исполнителей, чьи творческие таланты и идеи подавляются, — с другой?
• Как удержать архитекторов от витания в облаках и разработки несущественных или чрезмерно дорогих спецификаций?
• Как добиться того, чтобы любая мелочь из созданной архитектором спецификации дошла до исполнителя, была им правильно понята и точно внедрена в продукт?
Достижение концептуальной целостности
Назначение системы программирования — облегчить использование компьютера. Для этого поставляются языки и различные средства, являющиеся, по сути, программами, вызываемыми и управляемыми возможностями языка. Но эти средства стоят денег: объем внешнего описания системы программирования в десять-двадцать раз больше описания собственно вычислительной системы. Пользователю оказывается значительно проще задать любую выбранную функцию, но выбор очень велик, и нужно помнить значительно больше вариантов и форматов.
Использование облегчается, только если выигрыш времени при задании функции превышает время, потраченное на обучение, запоминание и поиск руководств. Современные системы программирования дают такой выигрыш, но похоже, что в последние годы отношение выигрыша к затратам уменьшилось в результате добавления все более и более сложных функций. Я часто вспоминаю, как легко было использовать IBM 650, даже без ассемблера или вообще каких-либо программ.
Поскольку целью проектирования является простота использования, окончательную оценку проекта системы дает достигнутое отношение функциональности к сложности концепций. Ни функциональность, ни простота в отдельности не являются признаками хорошего проекта.
Это обстоятельство часто неправильно понимается. Operating System/360 превозносится своими создателями, как лучшая из когда-либо созданных, поскольку неоспоримо, что в ней больше функций. Функции, а не простота всегда служили критерием превосходства ее создателей. С другой стороны, создатели системы с разделением времени для PDP-10 превозносят ее превосходство ввиду простоты и немногочисленности положенных в основу идей. Однако по всем меркам ее функциональность ниже по классу, чем OS/360. Если в качестве критерия определена простота использования, становится очевидной несбалансированность этих систем, достигающих цели лишь наполовину.
Однако для некоторого заданного уровня функциональности лучшей оказывается та система, в которой можно работать с наибольшей простотой и непосредственностью. Простота — это еще не все. Язык TRAC, созданный Муером, и Algol 68 достигают простоты, если количественно измерять ее числом отдельных элементарных понятий. Непосредственность, однако, не характерна для них. Чтобы выразить свои намерения, часто требуется сочетать базовые средства сложным и неожиданным образом. Недостаточно изучить базовые элементы и правила их комбинирования, нужно изучить еще идиоматическое использование, целую область знаний о том, как на практике комбинировать элементы. Простота и непосредственность проистекают из концептуальной целостности. Во всех частях должны найти отражение единая философия и единообразные пропорции между желаемыми целями. В каждой части должны также использоваться одинаковый синтаксис и сходные семантические обозначения. Таким образом, простота использования требует единства проекта, концептуальной целостности.
Аристократия и демократия
Концептуальная целостность, в свою очередь, требует, чтобы проект исходил от одного разработчика, или небольшого числа их, действующих согласованно и в унисон.
С другой стороны, напряженность графика требует привлечения большого числа работников. Есть два метода разрешения этой дилеммы. Первый состоит в тщательном разделении труда между архитектурой и исполнением. Второй — новый способ организации бригад программистов-исполнителей, обсуждавшийся в предыдущей главе.
Отделение разработки архитектуры от реализации является эффективным способом достижения концептуальной целостности при работе над очень большими проектами. Я лично был свидетелем успешного его применения при создании IBM компьютера Stretch и серии продуктов System/360. Но он не сработал при разработке Operating System/360, поскольку недостаточно применялся.
Под архитектурой системы я понимаю полную и подробную спецификацию интерфейса пользователя. Для компьютера это руководство по программированию. Для компилятора это руководство по языку. Для управляющей программы это руководство по одному или нескольким языкам, используемым для вызова ее функций. Для системы в целом — это набор всех руководств, к которым должен обращаться пользователь при работе.
Архитектор системы, как и архитектор здания, является представителем пользователя. Его задача — использовать все свои профессиональные и технические знания исключительно в интересах пользователя, а не продавца, изготовителя и т.п.[2]
Архитектура и разработка должны быть тщательно разделены. Как сказал Блау (Blaauw), «архитектура говорит, что должно произойти, а разработка — как сделать, чтобы это произошло».[3]В качестве простого примера он приводит часы, архитектура которых состоит из циферблата, стрелок и заводной головки. Ребенок, освоивший это архитектуру, с одинаковой легкостью может узнать время и по ручным часам, и по часам на колокольне. Исполнение же и его реализация описывают, что происходит внутри: передача усилий и управление точностью каждым из многих механизмов.
К примеру, в System/360 одна и та же архитектура компьютера совершенно по-разному реализована примерно в девяти моделях. Обратным образом, одна и та же реализация потока данных, памяти и микропрограмм из Model 30 использовалась в разное время в четырех различных архитектурах: System/360, мультиплексном канале с подключением до 224 логически независимых подканалов, селекторном канале и компьютере 1401.[4]
Такие же различия можно проводить в отношении систем программирования. Существует стандарт для Fortran IV. Это архитектура, используемая во многих компиляторах. В рамках этой архитектуры возможны разные реализации: текст в оперативной памяти или компилятор, быстрая или оптимизирующая, синтаксическая или ad hoc. Аналогично, любой язык ассемблера или язык управления заданиями допускает многие реализации ассемблера или планировщика.
Теперь мы можем заняться весьма чувствительным вопросом борьбы аристократии и демократии. Не стали ли архитекторы новой аристократией, интеллектуальной элитой, призванной разъяснить бедным безгласным исполнителям, что они должны делать? Не захватила ли эта элита всю творческую деятельность, сделав исполнителей лишь зубчиками в механизме? Не окажется ли, что более совершенный продукт можно получить, используя идеи всей бригады и исповедуя философию демократии, а не ограничивая круг разработчиков несколькими лицами?
Проще всего ответить на последний вопрос. Я, разумеется, не стану утверждать, что хорошие архитектурные идеи могут возникать только у архитекторов. Часто свежая идея исходит от исполнителя или пользователя. Однако весь личный опыт убеждает меня, и я пытался это показать, что простоту пользования системой определяет ее концептуальная целостность. Достойные внимания функции и идеи, которые не объединяются с основными концепциями системы, лучше оставить в стороне. Если таких важных, но несовместимых идей появляется слишком много, выкидывают всю система и начинают разработку целостной системы сначала, основывая ее на иных основополагающих концепциях.
Что касается обвинений в аристократизме, то ответ и положительный, и отрицательный. Положительный, потому что действительно должно быть несколько архитекторов, чьи результаты живут дольше, чем отдельные реализации, и архитектор находится в фокусе сил, которые он в конечном итоге должен использовать в интересах пользователя. Если вы хотите, чтобы система обладала концептуальной целостностью, то руководство концепциями должен взять кто-то один. Это аристократизм, который не нуждается в извинениях.
Ответ отрицательный, поскольку разработка проекта требует не меньше творчества, чем задание внешних спецификаций. Это тоже творческая работа, но другого характера. Разработка проекта для заданной архитектуры требует и допускает столько же творческой деятельности, новых идей, изобретательности, как и проект внешних спецификаций. Практически, коэффициент стоимость/эффективность созданного продукта больше зависит от исполнителя, а простота его использования — от архитектора.
Есть масса примеров, подсказанных другими искусствами и ремеслами, которые подводят к мнению, что дисциплина идет на пользу. Действительно, афоризм художника гласит, что «форма освобождает». Самые ужасны строения — это те, бюджет которых был слишком велик для поставленных целей. Творческую активность Баха едва ли могла подавлять необходимость еженедельная необходимость изготавливать кантату определенного вида. Я уверен, что архитектура компьютера Stretch стала бы лучше, если бы на нее наложили более жесткие ограничения; так, ограничения, наложенные бюджетом на System/360 Model 30, по моему мнению, принесли лишь пользу архитектуре Model 75.
Аналогично, я считаю, что получение архитектуры извне усиливает, а не подавляет творческую активность группы исполнителей. Они сразу сосредоточиваются на той части задачи, которой никто не занимался, и в результате изобретательность бьет ключом. В не ограничиваемой группе большая часть обдумывания и обсуждения посвящена архитектурным решениям в ущерб реализации.[5]
Этот многократно наблюдавшийся мной эффект подтвердил Р. У. Конвей (R. W. Conway), чья группа разработала в Корнельском университете компилятор PL/C для языка PL/I. Он говорит: «В конечном итоге мы решили реализовать язык без изменений и усовершенствований, поскольку обсуждение языка отняло бы у нас все силы.»[6]
Чем заняться разработчику, пока он вынужден ждать?
Очень неприятно совершить ошибку стоимостью в миллион долларов, но зато она надолго запоминается. Я отчетливо помню тот день, когда мы приняли решение о том, как практически организовать составление внешних спецификаций для OS/360. Менеджер по архитектуре, менеджер по реализации управляющей программы и я прорабатывали план, график и разделение обязанностей.
У менеджера по архитектуре было 10 хороших специалистов. Он утверждал, что они в состоянии написать спецификации и сделать это должным образом. Это должно было занять 10 месяцев — на три больше, чем отводилось по графику.
У менеджера по реализации управляющей программы было 150 человек. Он заявлял, что они могут подготовить спецификации, при этом группа архитекторов выполняла бы координирующие функции. Обещалось, что это будет сделано хорошо и практично, с соблюдением сроков. Более того, если оставить спецификации группе архитекторов, его 150 человек в течение десяти месяцев будут бить баклуши.
На это менеджер по архитектуре возразил, что если я сделаю ответственной за написание спецификаций группу управляющей программы, то результата в срок не будет: он все равно задержится на три месяца, но по качеству будет много хуже. Так оно и оказалось в действительности. Он оказался прав в обоих пунктах. Кроме того, из-за отсутствия концептуальной целостности создание и внесение изменений в систему оказались значительно более дорогостоящими, и, по моим оценкам, отладка удлинилась на год.
Конечно, многие факторы повлияли на принятие этого ошибочного решения, но определяющими были желание уложиться в график и стремление занять работой этих 150 человек. Пение этих сирен таит смертельные опасности, которые я и хочу сейчас показать.
Когда предлагается, чтобы все внешние спецификации для компьютерной или программной системы были составлены небольшой командой архитекторов, исполнители выдвигают три возражения:
• Спецификации будут перегружены функциями и не будут учитывать практических затрат на реализацию.
• Архитекторы получат все радости творчества и заблокируют изобретательность исполнителей.
• Многочисленным исполнителям придется ожидать в праздности, пока спецификации пройдут через узкое горлышко команды архитекторов.
Первое возражение отражает реальную опасность и будет рассмотрено в следующей главе. Остальные два являются чистым заблуждением. Как мы видели выше, разработка также является в высшей степени творческой деятельностью. Возможность проявить творчество и изобретательность при разработке незначительно ограничивается необходимостью работать в рамках заданных внешних спецификаций, и такая дисциплина может даже усилить степень творчества. Это, несомненно, верно для проекта в целом.
Последнее возражение касается планирования временных рамок и этапов. Проще всего воздержаться от найма исполнителей до завершения работы над спецификациями. Когда воздвигается здание, так и поступают.
Однако при создании компьютерных систем темпы выше, и желательно уплотнить график работ. В какой мере разработка спецификаций и разработка могут перекрываться?
Как отмечает Блау, всю программу создания составляют три отдельные стадии: архитектура, разработка и реализация. Оказывается, что на практике их можно начинать параллельно и продолжать одновременно.
Например, при проектировании компьютеров проектировщик может приступать к работе, имея относительно общие допущения в отношении руководства пользователя, несколько более ясные идеи относительно технологии и вполне определенные задачи по стоимости и рабочим характеристикам. Он может начать проектирование потоков данных, управляющих последовательностей, общих идей компоновки и т.д. Он разрабатывает или адаптирует необходимый инструментарий, особенно систему ведения учета, в том числе систему автоматизации проектирования.
В то же время на уровне реализации нужно спроектировать, усовершенствовать и описать микросхемы, платы, кабели, каркасы, блоки питания и устройства памяти. Эта работа протекает параллельно с архитектурой и разработкой.
То же самое справедливо при создании программных систем. Задолго до завершения внешних спецификаций проектировщик может найти себе достаточно работы. Он может приступить к делу, основываясь на грубом приближении функциональности системы, которая в конечном итоге будет воплощена во внешних спецификациях. У него должны быть ясно определенные цели в отношении памяти и временных параметров. Он должен изучить конфигурацию системы, на которой будет выполняться его продукт. Затем он может начать определение границ модулей, структур таблиц, расчленения на проходы или стадии алгоритмов и всевозможных инструментальных средств. Некоторое время он должен также посвятить общению с архитектором.
В то же время достаточно работы и на уровне реализации. У программирования своя технология. Если машина новая, много труда требуют соглашения по подпрограммам, технология работы с супервизором, алгоритмы поиска и сортировки.[7]
Концептуальная целостность требует, чтобы система отражала единую философию, и технические условия, в том виде, в котором они будут видны пользователю, проистекали от малого числа авторов. Это не означает, что спроектированная таким образом система создается дольше, поскольку используется действительное
разделение труда на архитектуру, разработку и реализацию. Опыт показывает обратное: цельная система продвигается быстрее и требует меньше времени для отладки. В результате широко распространенное горизонтальное разделение труда значительно сокращается за счет вертикального разделения, что влечет резкое уменьшение обмена информацией и улучшение концептуальной целостности.
Глава 5 Эффект второй системы
Adde parvum parvo magnus acervus erit. (Складывай малое с малым, и получишь большую кучу.)
ОВИДИЙ
Если ответственность за спецификацию функций отделить от ответственности за быстрое создание недорогого продукта, то чем сдержать изобретательский энтузиазм архитектора?
Принципиальное решение — обеспечение всестороннего, тщательного и доброжелательно обмена информацией между архитектором и разработчиком. Однако имеются и более тонкие решения, которые заслуживают внимания.
Дисциплина взаимодействия для архитектора
Архитектор, строящий здание, действует в рамках сметы, используя методы оценки, которые в последующем подтверждаются или корректируются заявками подрядчиков. Часто случается, что все предложения выходят за рамки сметы. Тогда архитектор пересматривает свои оценки в сторону увеличения сметы, а проект — в сторону сокращения, и цикл повторяется. Иногда он предлагает подрядчикам способы удешевления реализации его проекта в сравнении с избранными ими способами.
Сходные процессы происходят с архитектором компьютерных или программных систем. Однако у него есть то преимущество, что предложения подрядчика можно получить на ранних стадиях проектирования, часто — в любой момент. Недостатком обычно является то, что работа идет с единственным подрядчиком, который может менять цену в зависимости от степени своей удовлетворенности проектом. На практике, процесс общения, начатый на ранних этапах и продолжающийся непрерывно, может дать архитектору верную оценку стоимости, а разработчику — уверенность в проекте, не снимая при этом четкого разграничения сфер ответственности.
У архитектора, когда он сталкивается с неприемлемо высокой стоимостью, есть два выхода: сократить проект или воздействовать на стоимость, предлагая более дешевые способы реализации. Второй способ неизбежно вызывает эмоции, ведь архитектор оспаривает то, как строитель справляется со своим делом. Чтобы успешно справиться с этим, архитектору необходимо:
• помнить, что ответственность за изобретательность и творчество, проявляемые при реализации, несет строитель, поэтому архитектор предлагает, а не требует;
• всегда быть готовым предложить некоторый способ реализации своих замыслов и быть готовым согласиться с любым другим способом, позволяющим решить задачу не хуже;
• выдвигая такие предложения, действовать без шума и огласки;
• не рассчитывать на признательность за сделанные предложения.
Обычно разработчик парирует предложением изменений в архитектуре. Часто он прав — реализация какой-нибудь малосущественной детали может оказаться неожиданно дорогостоящей.
Самодисциплина — эффект второй системы
Первый проект архитектора стремится к скромности и ясности. Архитектор понимает, что не знает, чем занимается, поэтому он занимается этим со старанием и самоограничением.
При работе над первым проектом ему постоянно приходят в голову то одни, то другие «украшения». Они откладываются в сторону для использования «в следующий раз». В конце концов, первая система закончена, и архитектор, с твердой уверенностью в себе и продемонстрированным освоением этого класса систем, готов к созданию нового проекта.
Эта вторая система таит наибольшие опасности для проектировщика. При работе над третьей и последующими системами закрепляется полученный ранее опыт в отношении общих характеристик таких систем, а различия между ними выявляют те части опыта, которые носят частный характер и не могут быть обобщены.
Общая тенденция заключается в перегруженности проекта второй системы идеями и украшательствами, благоразумно отложенными в сторону при работе над первым проектом. В результате получается, говоря словами Овидия, «большая куча». Рассмотрим, например, архитектуру IBM 709, воплощенную позднее в машине 7090. Это — модернизация, вторя система для очень успешной и хорошо скроенной системы 704. Набор команд был настолько богат и изобилен, что регулярно использовалась примерно лишь половина его.
Рассмотрим в качестве более сильного примера архитектуру, разработку и даже реализацию компьютера Stretch, которые дали выход сдерживающимся изобретательским стремлениям многих людей, для большинства которых это было вторая система. Вот что пишет в своем обзоре Стрейчи (Strachey):
У меня создалось впечатление, что некоторым образом Stretch являет собой окончание определенного направления разработок. Как и некоторые ранние компьютерные программы, эта система чрезвычайно изобретательна, чрезвычайно сложна и очень эффективна, но в то же время является сырой, расточительной и неизящной, оставляя ощущение, что эти вещи можно делать лучшим образом.[1]
Operating System/360 была второй системой для большинства своих проектировщиков. Группы проектировщиков пришли после работы над дисковой операционной системой 1410-7010, операционной системой Stretch, системой реального времени Project Mercury и IBSYS для 7090. Едва ли кто-то из них имел опыт работы над двумя предшествующими операционными системами. Поэтому OS/360 является ярким примером эффекта второй системы, аналогом Stretch в искусстве программирования, к которому в полной мере применимы и похвалы, и упреки приведенной критики Стрейчи.
Например, в OS/360 отводится 26 байт для резидентной процедуры преобразования даты, чтобы правильно обрабатывать 31 декабря в високосном году (когда это 366-й день). Это можно было оставить оператору.
Эффект второй системы имеет и другое проявление, кроме простого украшательства функциями. Это — склонность к усовершенствованию методов, само существование которых стало анахронизмом благодаря изменениям в базовых принципах системы. OS/360 содержит многочисленные примеры, подтверждающие это.
Рассмотрим редактор связей, предназначенный для загрузки независимо скомпилированных программ и разрешения их перекрестных ссылок. Помимо этой основной функции он также управляет программными оверлеями. Это одно из лучших когда-либо созданных средств работы с оверлеями. Оно позволяет создавать оверлейную структуру внешним образом при редактировании связей, не трогая исходного кода. Оно позволяет изменять структуру оверлеев без перекомпиляции при каждом прогоне. Оно предоставляет богатый выбор полезных опций и возможностей. В известном смысле, это завершающий итог многолетней разработки технологии статических оверлеев.
И в то же время это последний и совершеннейший динозавр, поскольку входит в систему, в которой многопрограммность является обычным режимом, а динамическое распределение памяти — базовым принципом. Это вступает в прямой конфликт с понятием использования статических оверлеев. Несколько лучше работала бы система, если бы усилия, потраченные на управление оверлеями, были перенаправлены на то, чтобы ускорить работу средств поддержки динамического распределения памяти и перекрестных ссылок!
Более того, редактор связей требует так много памяти, и сам содержит столько оверлеев, что даже при использовании только для редактирования без управления оверлеями уступает в скорости большинству системных компиляторов. Ирония состоит в том, что назначение редактора связей — избежать повторной компиляции. Как у конькобежца корпус оказывается впереди ног, так и усовершенствования продолжались, пока не вышли далеко за рамки системных принципов.
Другим примером этой тенденции является отладчик TESTRAN. Это совершенный пакетный отладчик, предоставляющий действительно элегантные средства получения мгновенных снимков и дампов памяти. В нем используется понятие управляющих разделов и искусная технология генерации, позволяющие осуществлять избирательную трассировку и получение мгновенных снимков без дополнительных расходов на интерпретацию или рекомпиляцию. Здесь пышным цветом расцвели впечатляющие концепции операционной системы Share Operating System[3]для модели 709.
Между тем устарела сама идея пакетной отладки без рекомпиляции. Главный вызов был брошен интерактивным вычислительным системам с интерпретаторами языков программирования и пошаговыми компиляторами. Но даже в системах с пакетной обработкой появление компиляторов с быстрой компиляцией и медленным выполнением сделало более предпочтительной технологию отладки на уровне исходного кода и получения мгновенных снимков. Насколько лучше оказалась бы система, если бы силы, потраченные на проект TESTRAN, были перенаправлены на ускоренное создание лучших средств для интерактивной работы и быстрой компиляции!
Еще один пример — планировщик, предоставляющий действительно отличные возможности для управления потоком фиксированных пакетов заданий. На практике этот планировщик является усовершенствованной, улучшенной и наделенной разными украшениями второй системой, которой предшествовала дисковая операционная система 1410-7010 — система пакетной обработки, не являющаяся многопрограммной, за исключением ввода-вывода, и предназначенной, главным образом, для деловых приложений. В этом качестве планировщик OS/360 хорош. Но на него почти никакого влияния не оказали потребности OS/360 в удаленном вводе заданий, многопрограммности и резидентном размещении интерактивных подсистем. И действительно, проект планировщика затрудняет решение этих задач.
Как архитектору избежать эффекта второй системы? Очевидно, пропустить свою вторую систему он не может. Но он может отдавать себе отчет в особых опасностях, которым она его подвергает, и проявить дополнительную самодисциплину, чтобы избежать функционального украшательства и сохранения функций, нужда в которых отпала ввиду изменений в принципах и целях.
Порядок, способный открыть архитектору глаза, заключается в том, чтобы присвоить численное значение каждой, пусть малой, функции: характеристика x должна обойтись не более чем в m байтов памяти и n микросекунд на один вызов. Эти величины должны служить руководством при принятии начальных решений, а также напоминанием и руководством при реализации.
Как менеджеру проекта избежать эффекта второй системы? Настаивать на том, чтобы его старший архитектор имел опыт разработки хотя бы двух систем. Кроме того, будучи осведомленным о возможных опасностях, он может предъявлять необходимые требования для того, чтобы в детальном проекте нашли полное отражение идеологических концепций и цели.
Глава 6 Донести слово
Он сядет здесь и будет распоряжаться: «Сделайте это! Сделайте то!» А дело и с места не сдвинется.
ГАРРИ С. ТРУМЕН. «О ПРЕЗИДЕНТСКОЙ ВЛАСТИ»[1]
Как менеджеру, имея опытных дисциплинированных архитекторов и достаточное число исполнителей, добиться того, чтобы все услышали, поняли и выполнили решения архитектора? Как группе из 10 архитекторов поддерживать концептуальную целостность системы, над которой трудится 1000 человек? Для достижения этого при осуществлении программы проектирования аппаратной части System/360 была разработана целая технология, которая в равной степени применима для проектов создания программного обеспечения.
Письменные спецификации — руководство
Руководство, или письменная документация, является необходимым, хотя и не достаточным, инструментом. Руководство является внешней спецификацией продукта. В нем расписаны все подробности того, что видит пользователь, и потому оно является главным продуктом, который создает архитектор.
Его подготовка идет кругами, собирая замечания пользователей и разработчиков о недостатках проекта, затрудняющих использование или реализацию. Для удобства разработчиков необходимо квантовать изменения: согласно определенным в графике датам выпускать очередные версии.
Инструкция должна не только описывать все, что видит пользователь, в том числе все интерфейсы, но и воздерживаться от описания того, чего пользователь не видит. Последнее — забота разработчика, и здесь свобода его решений не должна быть ограничена. Архитектор всегда должен быть готов показать пример реализации любой описанной им функции, но он не должен пытаться навязывать определенную реализацию.
Стиль должен быть точным, полным и очень подробным. Пользователь часто обращается к отдельному определению, поэтому во всех из них должны быть повторены все существенные элементы, и все они должны быть согласованы друг с другом. По этой причине инструкции часто скучно читать, но точность имеет приоритет перед увлекательностью.
Единство «Принципов работы System/360» проистекает из того, что у них было лишь два автора: Джерри Блау и Андрис Падега. Авторами идей являются порядка десяти человек, но если требуется соблюсти согласованность описания и продукта, отливку решений в прозаические спецификации должны осуществлять не более двух человек. Для написания определения требуется принять массу мини-решений, которые не столь важны, чтобы выносить их на всеобщее обсуждение. Для System/360 примером служат подробности того, как после каждой операции устанавливается код условия. Однако задача всеобщей согласованности таких мини-решений не является тривиальной.
Думаю, что лучший виденный мной образец руководства — это написанное Блау приложение к «Принципам работы System/360». В нем тщательно и точно описаны границы совместимости System/360. Дано определение совместимости, предписывается, к чему нужно стремиться, и перечислены те области внешних проявлений, где архитектура намеренно молчит, и где результаты, полученные на разных моделях, могут отличаться между собой, где разные экземпляры одной модели могут дать различные результаты и даже один и тот же экземпляр может давать различия после конструктивных изменений. Это уровень точности, к которому стремятся составители руководств. Они должны одинаково описывать как то, что можно делать, так и то, что делать нельзя.
Формальные определения
Английский язык, как и любой другой естественный язык, по своей природе не является точным инструментом, пригодным для таких описаний. Поэтому составитель руководства должен держать в узде себя и свой язык, чтобы достичь необходимой строгости. Привлекательна возможность использования для таких определений формальных обозначений. В конце концов, целью является точность, что обусловливает право формальных обозначений на жизнь.
Рассмотрим достоинства и слабости формальных определений. Как отмечалось, формальные определения являются точными. Они тяготеют к полноте: пробелы заметнее, а потому скорее восстанавливаются. Их недостаток — трудность понимания. На английском языке можно описать структурные принципы, очертить структуры по этапам или по уровням и привести примеры. Легко отметить исключения и подчеркнуть противоположности. Еще важнее, что можно объяснить причины. Предлагавшиеся до сих пор формальные определения вызывали восхищение своей элегантностью и уверенность в их точности. Но они требовали текстуальных пояснений для облегчения изучения своего содержания. По этой причине я полагаю, что в будущем спецификации будут состоять как из формальных, так и из текстовых описаний.
Древнее изречение предупреждает о том, что в море нельзя выходить с двумя хронометрами: нужно взять один или три. То же, очевидно, применимо и к текстовым и формальным определениям. Если имеются оба вида, то один должен быть стандартом, а другой — производным описанием, о чем должно быть прямо указано. Основным стандартом может быть любой из них. В Algol 68 в качестве стандарта выбрано формальное определение, а текстовые определения являются описательными. В PL/I стандартом является текст, а формальное определение — производным. В System/360 также в качестве стандарта принят текст, а производными являются формальные описания.
Есть много средств создания формальных определений. Для определения языков часто используется форма Бэкуса-Наура, по которой есть богатая литература.[3]В формальном описании PL/I используются новые обозначения абстрактного синтаксиса, надлежащим образом описанные.[3]APL Иверсона был использован для описания машин, в частности, IBM 7090[4]и System/360.[7]
Белл и Ньюэлл предложили новые нотации для описания как конфигураций, так и машин, и проиллюстрировали их на нескольких машинах, включая DEC PDP-8, [6] 7090 [6] и System/360. [7]
Почти все формальные определения оказались пригодными для воплощения или описания аппаратных средств или программных систем, внешние спецификации которых они регламентируют. Синтаксис можно описать без этого, но семантика обычно определяется с помощью программы, выполняющей определяемую операцию. Конечно, это является реализацией и в этом качестве переопределяет архитектуру. Поэтому нужно указать, что формальное определение относится только к внешним спецификациям, и объяснить, что ими является.
Не только формальное определение является реализацией, но и реализация может служить формальным определением. Когда были созданы первые совместимые компьютеры, использовалась именно эта технология. Новая машина должна была соответствовать имеющейся. Руководство туманно в некоторых местах? Задайте вопрос машине! Создавалась тестовая программа для выяснения поведения, и новая машина строилась так, чтобы достигалось соответствие.
Программная модель аппаратной или программной системы может использоваться точно таким же образом. Это — реализация. Она работает. Поэтому все вопросы, связанные с определением, могут быть решены путем проверки.
Использование реализации в качестве определения имеет некоторые преимущества. Все проблемы можно однозначно решить путем эксперимента. Дискуссий не требуется, поэтому ответ получается быстро. Ответ может быть сколь угодно точным и, по определению, всегда является правильным. С другой стороны, есть
значительное количество недостатков. Реализация может переопределять даже внешние спецификации. Даже при ошибочном синтаксисе всегда получается некоторый результат; в контролируемой системе этот результат является указанием на ошибку и ничем больше. В неконтролируемой системе могут возникнуть любые побочные эффекты и быть использованы программистами. Когда мы, например, эмулировали IBM 1401 на System/360, выявилось 30 различных «курьезов» — побочных эффектов предположительно незаконных операций, которые широко использовались и должны были быть признаны частью определения. Реализация в качестве определения возобладала. Она не только говорила о том, что должна делать машина, но и многое сказала о том, как машина не должна была это делать.
Кроме того, на проницательные вопросы реализация иногда дает неожиданные ответы, и определение де-факто часто оказывается неизящным в этих особых случаях потому, что над ними никогда не задумывались. Копирование этой неэлегантности в другой реализации часто оказывается замедляющим или дорогостоящим. Например, в некоторых машинах в регистре множимого после умножения остается мусор. Точная природа этого мусора становится частью определения де-факто, однако его копирование может помешать использованию более быстрого алгоритма умножения.
Наконец, использование реализации в качестве формального определения может создать неясность, какое из описаний — текстовое или формальное — в действительности является стандартом. Это относится особенно к программным моделям. Следует также воздерживаться от внесения изменений в реализацию, пока она служит в качестве стандарта.
Прямое включение
У архитекторов программных систем есть чудесный метод распространения и внедрения определений. Он особенно полезен при установлении если не семантики, то синтаксиса межмодульных интерфейсов. Этот прием состоит в создании объявлений передаваемых параметров или совместно используемой памяти и требовании включения этих объявлений при операциях времени компиляции (макрос или %INCLUDE в PL/I). Если, кроме того, все ссылки на интерфейс происходят только по символическим именам, объявления можно менять, добавляя или вставляя новые имена и лишь заново компилируя, но не изменяя использующую его программу.
Конференции и суды
Нет нужды говорить о том, что совещания необходимы. Сотни частных консультаций должны дополняться крупными и более формальными собраниями. Мы признали полезными два уровня таких собраний. Первый – это еженедельная конференция всех архитекторов вместе с официальными представителями разработчиков аппаратной и программной части и сотрудниками маркетинга продолжительностью в половину рабочего дня под председательством главного архитектора системы.
Предлагать задачи и изменения можно всем, но обычно предложения распространяются в письменном виде до совещания. Обычно новая задача некоторое время обсуждается. Упор делается на творческой стороне, а не просто на принятии решения. Группа пытается предложить несколько решений проблемы, затем ряд предложенных решений передается одному или нескольким архитекторам для разработки подробных и точно сформулированных предложений по внесению изменений в руководство.
Подробные предложения об изменениях затем выносятся для принятия решения. Предложения тщательно изучаются исполнителями и пользователями, и выясняются все "за" и "против". Если возникает всеобщее согласие, все в порядке. В противном случае решение принимает главный архитектор. Ведется протокол, и решения формально, оперативно и широко распространяются.
Решения еженедельных конференций дают быстрые результаты и позволяют продолжить работу. Если кто-то очень недоволен, допускается немедленная апелляция к менеджеру проекта, но это происходит очень редко.
Плодотворность этих совещаний обусловлена несколькими причинами:
1. Одна и та же группа – архитекторы, разработчики и исполнители – на протяжении месяцев встречаются между собой каждую неделю. Не требуется времени, чтобы ввести людей в курс дела.
2. Группа состоит из предприимчивых, способных, хорошо осведомленных в вопросах и глубоко заинтересованных в конечном результате людей. Никто не участвует с "совещательным" голосом. Все уполномочены принимать на себя обязательства.
3. При возникновении проблем решения ищутся как внутри, так и вне очевидных границ.
4. Благодаря формализму письменных предложений сосредоточивается внимание, требуется принятие решения и устраняется несогласованность, свойственная черновым решениям комиссий.
5. Открытое предоставление права принятия решения главному архитектору помогает избежать поиска компромиссов и задержек.
Со временем выясняется, что некоторые решения не в полной мере выполняются. Тот или иной из участников так и не принял всей душой какую-либо мелочь. Другие решения породили непредвиденные проблемы, и еженедельное совещание отказывается повторно их рассматривать. Так возникает хвост из мелких возражений, открытых тем или раздражения. Для их урегулирования мы проводим ежегодные "сессии верховного суда", обычно продолжающиеся две недели. (Если бы я проводил их сейчас, то делал бы это раз в полгода.)
Эти сессии проводились накануне важных дат окончательного принятия разделов руководства. Присутствовали не только представители программистов и проектировщиков по архитектуре, но и менеджеры программных, маркетинговых и реализационных проектов. Председательствовал менеджер проекта System/360. Повестка работы включала обычно около 200 пунктов, в основном мелких, перечисленных в развешанных по комнате списках. Заслушивались все стороны и принимались решения. Благодаря чуду компьютерной верстки (и превосходной работе сотрудников) каждое утро каждый участник обнаруживал на своем рабочем месте исправленное руководство, в которое были внесены решения, принятые накануне.
Эти "осенние фестивали" были полезны не только для пересмотра решений, но и для того, чтобы они были приняты. Каждый был услышан, каждый принимал участие, каждый лучше понимал сложные ограничения и взаимосвязи между решениями.
Множественные реализации
У архитекторов System/360 было два почти беспрецедентных преимущества: достаточно времени для тщательной работы и такое же политическое влияние, как у проектировщиков. Наличие времени было обеспечено графиком по новой технологии; политическое равенство происходило благодаря одновременному созданию нескольких реализаций. Необходимость их строгой совместимости лучше всего способствовала исполнению спецификаций.
В большинстве компьютерных проектов наступает день, когда оказывается, что машина и руководство по ее использованию не согласуются. В последующем конфликте обычно проигрывает руководство, поскольку его можно изменить значительно быстрее и меньшей ценой, чем машину. Однако это не так, если существует несколько реализаций. Тогда временные и финансовые издержки, связанные с исправлением машины с ошибками, могут быть ниже, чем связанные с переделкой машин, верно следовавших руководству.
Это замечание можно с пользой применить при определении языка программирования. Можно с уверенностью утверждать, что рано или поздно потребуется создать несколько интерпретаторов или компиляторов для разных целей. Определение будет яснее, а дисциплина более крепкой, если изначально строятся как минимум две реализации.
Журнал регистрации телефонных разговоров
Какими бы точными не были спецификации, по ходу проектирования возникает несчетное множество вопросов касательно интерпретации архитектуры. Очевидно, многие из этих вопросов требуют более ясного изложения в тексте. Прочие просто отражают неправильное понимание.
Важно, чтобы озадаченные исполнители звонили ответственным архитекторам и задавали вопросы, а не продолжали работу на основании догадок. Важно также понимать, что ответы на такие вопросы являются авторитетными заявлениями архитекторов и должны доводиться до всех.
Полезным механизмом является ведение архитектором журнала регистрации телефонных разговоров, в который им заносятся все вопросы и ответы. Каждую неделю журналы нескольких архитекторов объединяются воедино, размножаются и распределяются среди пользователей и исполнителей. Несмотря на свою неформальность, такой механизм является и быстрым, и понятным.
Тестирование продукта
Лучший друг менеджера проекта — его постоянный противник, независимая организация, тестирующая продукт. Группа проверяет соответствие машин и продуктов спецификациям и выступает пособником дьявола, указывая на все замеченные дефекты и несоответствия. Каждой организации, ведущей разработки, нужна такая независимая группа технического аудита, которая должна быть неподкупна.
Последний анализ в качестве независимого аудитора осуществляет покупатель. В безжалостном свете практического применения станет виден каждый огрех. Группа тестирования продукта как раз заменяет покупателя, настроенного на поиск ошибок. Время от времени тщательная проверка продукта обнаруживает места, где не услышали указание, где проектные решения поняли неправильно или выполнили неточно. Поэтому такая группа проверяющих является необходимым звеном в цепочке, по которой доходит слово проектировщика, звеном, которое должно начать действовать рано и одновременно с проектированием.
Глава 7 Почему не удалось построить Вавилонскую башню?
На всей земле был один язык и одно наречие. Двинувшись с востока, они нашли в земле Сеннаар равнину и поселились там. И сказали друг другу: наделаем кирпичей и обожжем огнем. И стали у них кирпичи вместо камней, а земляная смола вместо извести. И сказали они: построим себе город и башню, высотою до небес, и сделаем себе имя прежде, нежели рассеемся по лицу всей земли. И сошел Господь посмотреть город и башню, которые строили сыны человеческие. И сказал Господь: вот, один народ, и один у всех язык; и вот что они начали делать, и не отстанут они от того, что задумали делать; сойдем же и смешаем там язык их, так чтобы один не понимал речи другого. И рассеял их Господь оттуда по всей земле; и они перестали строить город
КНИГА БЫТИЯ 11:1-8
Аудит менеджмента Вавилонского проекта
Согласно Книге бытия, Вавилонская башня была вторым крупным инженерным предприятием человека после Ноева ковчега. Вавилонская башня стала первым инженерным фиаско.
Эта история глубока и поучительна в нескольких отношениях. Давайте, однако, рассмотрим ее как чисто технический проект и посмотрим, какие уроки администрирования можно из нее извлечь. Насколько хорошо проект был обеспечен необходимыми составляющими успеха? Имелись ли:
1. Ясность цели? Да, хотя и наивно недостижимой. Проект провалился задолго до того, как столкнулся с эти принципиальным ограничением.
2. Человеческие ресурсы? В большом числе.
3. Материалы? Глина и битум в изобилии имеются в Месопотамии.
4. Достаточно времени? Да, нет никаких указаний на ограничения по времени.
5. Адекватные технологии? Да, пирамидальной или конической структуре присуща устойчивость и хорошее распределение нагрузки сжатия. Очевидно, свойства каменной кладки были хорошо известны. Проект провалился до того, как вышел за пределы технологических ограничений.
Так почему же провалился проект, если все это у них было? Чего у них не хватало? Двух вещей — обмена информацией и вытекающей из него организации. Они не могли разговаривать друг с другом и, как следствие, согласовывать усилия. Когда отказала координация, работа встала. Читая между строк, мы обнаруживаем, что отсутствие обмена информацией привело к спорам, дурному настроению и взаимной ревности. Вскоре кланы начали расходиться, предпочтя обособленность спорам.
Обмен информацией в большом программном проекте
В наше время происходит тоже самое. Отставание от графика, несоответствие функциональности, системные ошибки — все это из-за того, что левая рука не знает, что творит правая. По ходу работы участвующие в ней несколько бригад понемногу изменяют функции, размер, быстродействие своих программ, явно или косвенно меняют допущения относительно входных данных и использования выходных.
Например, исполнитель функции, осуществляющей оверлейную загрузку программ, может столкнуться с проблемами и снизить быстродействие, основываясь на статистических данных, указывающих на редкость использования этой функции в прикладных программах. В то же время его сосед может разрабатывать важную часть супервизора таким образом, что она крайне зависит от скорости выполнения этой функции. Это изменение скорости выполнения, в сущности, становится значительным изменением спецификаций, о нем нужно широко объявить и оценить с точки зрения системы.
Как же должны бригады обмениваться между собой информацией? Всеми возможными способами:
• Неформально. Хорошая телефонная связь и ясное определение взаимозависимостей между бригадами должны способствовать многочисленным телефонным переговорам, от которых зависит единая интерпретация печатных документов.
• Совещания. Нельзя переоценить значение регулярных совещаний участников проекта с поочередным заслушиванием технических отчетов бригад. Таким путем устраняются сотни мелких непониманий.
• Рабочая тетрадь. В самом начале нужно завести рабочую тетрадь учета проделанной работы. Эта тема заслуживает отдельного раздела.
Рабочая тетрадь проекта
Что. Рабочая тетрадь проекта является не столько отдельным документом, сколько структурой, налагаемой на все документы, которые будут созданы во время выполнения проекта.
Все документы проекта должны входить в эту структуру, включая цели, внешние спецификации, спецификации интерфейсов, технические стандарты, внутренние спецификации и административные записки.
Почему. Технологический документ практически вечен. Если исследовать генеалогию руководства пользователя по какому-нибудь аппаратному или программному продукту, можно проследить не только идеи, но и множество отдельных предложений и параграфов, вплоть до первой памятной записки, предлагающей продукт или поясняющей первый проект. Для составителя документации ножницы и клей — такая же важная вещь, как перо.
Раз это так, и завтрашние руководства для готового продукта развиваются из сегодняшних памятных записок, очень важно правильно определить структуру документации. Разработка рабочей тетради проекта на ранних этапах обеспечивает продуманную, а не случайную структуру документации. Более того, задание структуры позволяет составленные позднее документы оформить в виде отрывков, которые вписываются в эту структуру.
Второй причиной для ведения рабочей тетради является необходимость управления процессом распространения информации. Задача состоит не в ограничении доступа к информации, а в том, чтобы соответствующая информация достигла всех, кому она может понадобиться.
Первым делом следует пронумеровать все памятные записки, так чтобы имелись упорядоченные списки названий, и каждый работник мог убедиться в наличии необходимых ему материалов. Организация рабочей тетради идет значительно дальше, устанавливая древовидную структуру памятных записок. Древовидная структура позволяет, если нужно, организовать доставку информации соответственно поддеревьям.
Механика. Как и во многих задачах управления программными проектами, проблема технических меморандумов усложняется нелинейным образом по мере увеличения объема данных. Если в работе участвуют 10 человек, документы можно просто пронумеровать. Если участвуют 100 человек, часто достаточно нескольких линейных последовательностей. Для 1000 сотрудников, неизбежно разбросанных по нескольким площадкам, возрастает потребность в структурированной рабочей тетради, и, следовательно, возрастает ее объем. Как поступать в этом случае?
Я думаю, мы правильно поступили при работе над проектом OS/360. На необходимости хорошо структурированной рабочей тетради особенно настаивал О. С. Локен, который убедился в ее эффективности при работе над своим предыдущим проектом, — операционной системой 1410-7010.
Мы быстро приняли решение, что каждый программист должен иметь возможность видеть весь материал, т.е. должен иметь экземпляр рабочей тетради в своем офисе.
Решающее значение имеет своевременное обновление. Рабочая тетрадь должна отражать текущее состояние проекта. Это очень трудно осуществить, когда для внесения обновлений нужно перепечатывать целые документы. Однако в тетради с вынимающимися листами достаточно заменить отдельные страницы. У нас имелась компьютерная система редактирования текста, оказавшаяся бесценной для своевременного обновления. Офсетные формы изготавливались непосредственно на принтере, и цикл обработки составлял меньше одного дня. Перед получателем всех этих обновленных страниц встает, однако, проблема усвоения. Когда он впервые получает обновленную страницу, то ему нужно знать, что было изменено. Когда он позже обращается к ней, то ему нужно знать, какое определение действительно на текущий день.
Последнюю потребность удовлетворяет непрерывность обновления документации. Чтобы выделить изменения, требуются другие меры. Во-первых, нужно отметить на странице измененный текст, например, с помощью вертикальной линии на полях рядом с каждой измененной строчкой. Во-вторых, необходимо вместе с измененными страницами распространять краткую отдельную сводку с перечислением изменений и характеристикой их значения.
Наш проект не перешел и шестимесячного рубежа, когда мы столкнулись с другой проблемой. Толщина рабочей тетради составила около полутора метров! Если бы мы сложили в одну стопку требующиеся программистам 100 экземпляров в своих помещениях здания Time-Life в Манхеттене, она бы превысила по высоте само здание. Кроме того, ежедневные исправления имели толщину больше пяти сантиметров и насчитывали около 150 страниц, которые надо было заменить. Поддержка рабочей тетради стала занимать значительную часть ежедневного рабочего времени.
С этого времени мы перешли на микрофиши, что сберегло миллион долларов даже с учетом стоимости устройств для чтения микрофишей в каждом офисе. Мы смогли достичь отличной продолжительности цикла производства микрофишей. Рабочая тетрадь уменьшилась в объеме с 90 дм [3] до 5 дм [3] и, что более важно, обновления выпускались порциями по сотне страниц, стократно уменьшая сложность замены листов.
Микрофиши имеют свои недостатки. С точки зрения менеджера, неудобство замены бумажных страниц гарантировало, что их прочтут, для чего и велась рабочая тетрадь. Микрофиши слишком облегчили задачу ведения рабочей тетради, если только они не сопровождались печатным документом с перечислением изменений.
Кроме того, микрофиши не позволяют читателю легко делать выделения, пометки и комментарии. Документы, с которыми читатель работал, приносят больше пользы автору и читателю. Взвешивая все, я полагаю, что микрофиши являются очень удачной технологией, и для очень крупных проектов я бы отдал им предпочтение перед бумажной рабочей тетрадью.
Как можно осуществить это сегодня? Сегодняшние системные технологии, я думаю, делают предпочтительнее ведение рабочей тетради в файле прямого доступа с полосками, помечающими измененные части, и датами внесения изменений. Любой пользователь может обратиться к журналу с дисплейного терминала. Сводка изменений, готовящаяся ежедневно, должна храниться в виде стека (LIFO) с установленной точкой доступа. Программист может ежедневно ее читать, но если он пропустил один день, ему придется дольше читать на следующий день. Прочтя об изменениях, он может прерваться и прочесть сам измененный текст.
Обратите внимание, что сама рабочая тетрадь остается неизменной. Она по-прежнему остается собранием всей проектной документации, тщательно организованной. Единственное изменение — механизм распределения доступа. Д. С. Энглебарт с коллегами создали такую систему в Стэнфордском исследовательском институте и используют ее для ведения документации по сети ARPA.
Д. Л. Пранас и Университета Карнеги-Мелона предложил еще более радикальное решение. [1] Он полагает, что производительность программиста выше всего, когда он огражден от подробностей конструкции тех частей системы, над которыми он не работает. Это предполагает, что все интерфейсы полностью и точно заданы. Такой проект определенно хорош, но если полагаться на его идеальное осуществление, это приведет к катастрофе. Хорошая информационная система не только должна выявлять ошибки в интерфейсах, но и способствовать их исправлению.
Организация крупного программного проекта
Если над проектом работает n человек, то существует (n [2] –n)/2 интерфейсов, через которые может происходить обмен данными, и потенциально существует почти 2 n групп, внутри которых должно происходить согласование. Цель организации работы состоит в сокращении необходимого объема обмена информацией и согласования. Поэтому создание правильной организационной структуры является решающим направлением решения проблем информационного обмена, рассматривавшихся выше.
Способы, которыми сокращается обмен информацией, — разделение труда и специализация функций. Древовидная организационная структура отражает уменьшение потребности в подробном обмене информацией при использовании разделения труда и специализации.
В действительности, организация в виде дерева возникает как структуризация полномочий и ответственности. Принцип, что никто не может быть слугой двух господ, требует, чтобы структура полномочий была древовидной. Однако структура обмена информацией не столь ограничена, и дерево является мало пригодным приближением структуры общения, которая является сетью. Неадекватность приближения деревом служит причиной возникновения бригад, целевых групп, комиссий и даже организаций матричного типа, существующих во многих инженерных лабораториях.
Рассмотрим древовидную организацию программистов и исследуем существенные характеристики, которыми должны обладать поддеревья, чтобы быть эффективными. Таковыми являются:
1 — задание,
2 — продюсер,
3 — технический директор или архитектор,
4 — график работ,
5 — разделение труда,
6 — определение интерфейсов между разными частями.
Все перечисленное очевидно и обычно, исключая различие между продюсером и техническим директором. Сначала рассмотрим сами эти две функции, а затем их взаимоотношения.
В чем назначение продюсера? Он собирает бригаду, распределяет работу и устанавливает график ее выполнения. Он занимается приобретением необходимых ресурсов. Это означает, что большая часть его функций состоит в общении, которое направлено вне бригады, — вверх и в стороны. Он устанавливает схему связи и предоставления отчетности внутри бригады. Наконец, он обеспечивает выполнение графика, осуществляя маневр ресурсами и меняя организацию в соответствии с новыми обстоятельствами.
А что же технический директор? Он постигает проект, который должен быть реализован, выявляет его составляющие, определяет, как он будет выглядеть внешне, и делает эскиз внутренней структуры. Он обеспечивает единство и концептуальную целостность проекта в целом и таким образом способствует ограничению сложности системы. При возникновении технических проблем он изыскивает их решения или при необходимости изменяет системный проект. Он, согласно прелестному выражению Ала Каппа, является «своим человеком в паршивых делах». Общение его происходит преимущественно внутри команды. Его работа почти исключительно техническая.
Теперь видно, что для этих двух функций требуются совершенно разные способности. Способности встречаются в разных сочетаниях, и отношения между продюсером и директором должны определяться теми конкретными сочетаниями, которыми они обладают. Не люди должны быть втиснуты в чисто теоретические организационные формы, а организация должна строиться вокруг тех людей, которые есть.
Возможны три типа отношений, и все они с успехом встречаются на практике.
Одно и то же лицо может быть продюсером и техническим директором. Это вполне оправдано в маленьких командах, насчитывающих от трех до шести программистов. В более крупных проектах это очень редко осуществимо по двум причинам. Во-первых, редко встречаются люди, сочетающие в себе большие административные и технические способности. Мыслители встречаются редко, практики еще реже, но реже всего — мыслители-практики.
Во-вторых, в больших проектах выполнение каждой из функций требует полного рабочего дня или даже больше. Продюсеру трудно передать кому-либо достаточную часть своих обязанностей, чтобы высвободить время для технической работы. Директору невозможно передать свои обязанности, не нанося ущерба концептуальной целостности проекта.
Продюсер может быть начальником, а директор — его правой рукой. Сложность здесь состоит в том, чтобы определить полномочия директора при принятии технических решений, с тем чтобы он не тратил свое время, участвуя в административной цепочке.
Очевидно, продюсер должен объявить о полномочиях директора в технической области и в высшей степени укреплять их в возникающих спорных ситуациях. Чтобы это было возможно, продюсер и директор должны иметь схожие взгляды по основным техническим вопросам. Они должны частным образом согласовывать основные технические проблемы, прежде чем они встанут на повестку дня. Продюсер должен также с большим уважением относиться к техническому мастерству директора.
Что менее очевидно, продюсер может с помощью символов статуса (таких как размер кабинета, ковровое покрытие, мебель, рассылка вторых экземпляров документов и т.п.) подчеркивать, что директор, находясь вне административной цепочки, обладает, тем не менее, властью в принятии решений.
Это может действовать очень успешно. К несчастью, к этому редко прибегают. Что хуже всего получается у менеджеров проектов, — так это использование технического гения людей, не очень сильных в администрировании.
Директор может быть начальником, а продюсер — его правой рукой. Роберт Хайнлайн ярко описывает такую организацию в «Человеке, продавшем Луну».
Костер закрыл лицо руками, затем взглянул вверх:
— Я разбираюсь в этом. Я знаю, что нужно делать, но всякий раз, когда я пытаюсь заняться технической проблемой, какой-нибудь болван хочет, чтобы я принял решение по поводу грузовиков, или телефонов, или еще какой-нибудь ерунды. Простите, мистер Гарриман. Мне казалось, я справлюсь со всем этим.
Гарриман очень мягко сказал:
— Не отчаивайся, Боб. Ты ведь недосыпал последнее время, правда? Вот что я скажу: мы перехитрим Фергюсона. Я возьму твой стол на несколько дней и построю организацию, которая оградит тебя от таких вещей. Я хочу, чтобы твои мозги были заняты векторами реакции, эффективностью топлива и сложностями проекта, а не контрактами по грузовикам. — Гарриман подошел к двери, выглянул наружу и заметил человека, который был, возможно, старшим клерком. — Эй, вы! Подойдите сюда!
Человек показался озадаченным, встал и, подойдя к двери, спросил:
— Да?
— Я хочу, чтобы этот стол в углу и все, что на нем, были перенесены в пустую комнату на этом этаже, и немедленно.
Он проследил, как Костер и второй его стол переехали в другую комнату, убедился, что телефон в новом помещении отключен, и, подумав, заставил перенести туда диван.
— Мы поставим проектор, чертежную доску, книжные шкафы и все такое прочее сегодня вечером, — сказал он Костеру. — Просто составь список всего необходимого, чтобы заниматься делом. — Он вернулся в официальный кабинет главного инженера и с радостью взялся за работу, пытаясь выяснить, каково положение дел, и что не ладится.
Часа через три он позвал Баркли, чтобы познакомить его с Костером. Главный инженер спал, сидя за столом, положив голову на руки. Гарриман хотел выйти, но Костер проснулся.
— Прошу прощения, — сказал он, краснея, — я, наверное, задремал.
— Для этого я притащил тебе диван, — сказал Гарриман, — на нем удобнее. Боб, познакомься с Джоком Беркли. Это твой новый раб. Ты остаешься главным инженером и неоспоримым начальником. Джок будет Главным лордом Все Остальное. С этого момента тебе абсолютно не о чем беспокоиться — исключая такую мелочь, как лунный корабль.
Они пожали руки.
— Хочу просить об одной вещи, мистер Костер, — сказал Беркли с серьезностью, — передавайте мне все, что сочтете необходимым — ваша сторона техническая, — но Бога ради, записывайте все, чтобы я был в курсе. Я хочу, чтобы вам на стол поставили выключатель, который будет управлять опечатанным магнитофоном на моем столе.
— Отлично! — Гарриману показалось, что Костер помолодел.
— И если вам понадобится что-либо, не относящееся к технике, не занимайтесь этим сами. Нажмите выключатель и свистните. Все будет сделано. — Беркли взглянул на Гарримана. — Хозяин говорит, что собирается поговорить с вами о настоящей работе. Я вас покину и займусь делами. — Он вышел.
Гарриман сел. Костер последовал его примеру и сказал:
— Уф!
— Так лучше?
— Мне понравился этот Беркли.
— Это хорошо. Теперь это твой двойник. Не беспокойся: он работал у меня раньше. Ты почувствуешь себя, как в хорошей больнице. [2]
Этот текст едва ли нуждается в аналитических комментариях. Такая организация тоже может эффективно действовать.
Мне кажется, что последний тип организации лучше подходит для небольших команд, описанных в главе 3 «Операционная бригада». Полагаю, что продюсер в качестве начальника более подходит для больших поддеревьев действительно крупных проектов.
Вавилонская башня была, возможно, первым инженерным фиаско, но не последним. Решающее значение для успеха имеют схема связи и вытекающая из нее организация. Технологии обмена информацией и создания организационных структур требуют от менеджера большой работы мысли и такой же подкрепленной опытом компетентности, как и сама технология программного обеспечения.
Глава 8 Объявляя удар
Практика — лучший учитель.
ПУБЛИЙ
Опыт — дорогой учитель, но для глупцов иного нет.
АЛЬМАНАХ БЕДНОГО РИЧАРДСА
(Бедный Ричард — образ необразованного, но здравомыслящего доморощенного философа, созданный Бенджамином Франклином, издававшим в 1732 — 1757 годах ежегодный альманах и использовавшим этот псевдоним (примеч. перев.)).
Сколько времени потребует задача системного программирования? Сколько сил понадобится? Как можно это оценить?
Ранее я предложил соотношения, которые можно применять для времени планирования, написания программ, тестирования компонентов и тестирования системы. Во-первых, нужно сказать, что нельзя делать оценку всей задачи, оценивая только часть, относящуюся к написанию программ, а затем применяя соотношения. Написание программ составляет лишь одну шестую часть задачи или около того, и ошибки при его оценивании или в соотношениях могут привести к смехотворным результатам.
Во-вторых, нужно учитывать, что оценки, полученные при создании отдельных небольших программ, нельзя применять для больших системных продуктов. К примеру, для программы, насчитывающей 3200 слов, Сакман, Эриксон и Грант оценивают суммарное время написания программ и отладки для одного программиста в 178 часов, что экстраполируется до 35800 операторов в год. Вдвое меньшая программа потребовала меньше четверти указанного времени, что при экстраполяции дает производительность, близкую уже к 80000 операторам в год.[1]Необходимо добавить затраты времени на планирование, составление документации, тестирование, системную интеграцию и обучение. Линейная экстраполяция данных, относящихся к коротким задачам, бессмысленна. Если экстраполировать время, за которое можно пробежать стометровку, то окажется, что можно пробежать милю менее чем за три минуты.
Прежде чем отказаться от этих данных, отметим, что и для не совсем сравнимых задач они показывают, что объем работы растет как степенная функция размера, даже без учета процесса отмена информацией (кроме программиста с собственной памятью).
Показанные на рис. 8.1 данные вызывают грустные чувства. График демонстрирует результаты, полученные в исследовании, проведенном Нанусом (Nanus) и Фарром (Farr)[2]в System Development Corporation. В нем выявляется зависимость с показателем степени 1,5:
Объем работы = (константа) Ч (количество команд) ^ 1.5.
В другом исследовании, проведенном в этой компании, о котором сообщает Вайнвурм (Weinwurm)[3], также получен показатель, близкий к 1,5.
Есть несколько исследований относительно производительности труда программиста, в которых предложен ряд технологий оценивания. Есть обзор опубликованных данных, подготовленный Моурином (Morin).[4]Я приведу здесь лишь несколько наиболее показательных результатов.
Рис. 8.1 Затраты на программирование как функция размера программы
Данные Портмана
Чарльз Портман (Charles Portman), менеджер отдела программирования ICL — Computer Equipment Organization (Northwest) в Манчестере, предлагает свое понимание проблемы, которое может оказаться полезным.
Он обнаружил, что его команды программистов отстают от графиков примерно наполовину, т.е. каждое задание выполняется примерно вдвое дольше, чем предполагалось. При этом оценки очень тщательно проводились группами опытных экспертов, оценивавших в человеко-часах трудоемкость нескольких сотен подзадач с помощью диаграмм ПЕРТ. Когда выявлялось отставание от графика, он просил вести подробные ежедневные журналы использования времени. Из них выяснилось, что ошибка оценок полностью объясняется тем, что его команды использовали на программирование и отладку лишь 50 процентов рабочего времени. Остальное время терялось из-за отказов машины, на небольшие срочные посторонние задания, совещания, писание бумаг, дела фирмы, болезни, личное время и т.д. Короче оценки исходили из нереалистичного предположения о том, какая часть рабочего времени отводится непосредственно работе.[6]
Данные Арона
Джоэл Арон (Joel Aron), менеджер IBM по системным технологиям в Гейтерсберге, штат Мэриленд, изучал эффективность труда программистов во время работы над девятью крупными системами (крупная соответствует более чем 25 программистам и 30000 операторов).[7]Он классифицирует такие системы в соответствии с интенсивностью взаимодействия между программистами (и частями системы) и обнаруживает следующие величины производительности:
Человеко-год здесь не учитывает поддержку и системное тестирование, только разработку и программирование. При введении поправки с коэффициентом два с целью учета системного тестирования эти цифры близко соответствуют данным Харра.
Данные Харра
Джон Харр (John Harr), менеджер по программированию Electronic Switching System, входящей в состав Bell Telephone Laboratories, сообщил о своем собственном опыте и других известных ему данных в докладе на Объединенной конференции по компьютерам весной 1969 года.[8]Эти данные приведены на рисунках 8.2, 8.3 и 8.4.
Наиболее поучителен и содержит больше данных рисунок 8.2. Первые два задания являются, по преимуществу, управляющими программами, а два вторых — языковыми трансляторами. Производительность измеряется в количестве отлаженных слов за человеко-год. При этом учитывается время программирования, отладки и системного тестирования. Неизвестно, учтены ли затраты на планирование, поддержку машины, составление документации и т.п.
Рис. 8.2 Сводка по четырем важнейшим программным проектам,
осуществленным в ESS
Производительность разбивается на два класса: для управляющих программ составляет около 600 слов на человека за год, для трансляторов — около 2200. Обратите внимание, что все четыре программы приблизительно одного размера, различие состоит в размере рабочих групп, продолжительности работы и количестве модулей. Что является причиной, а что — следствием? Была ли сложность причиной того, что для управляющих программ требовалось больше людей? Или же большее число модулей и человеко-месяцев обусловлено большим числом людей, привлеченных к работе? Была ли большая продолжительность выполнения вызвана сложностью проблем или многочисленностью занятых людей? Трудно сказать с уверенностью. Конечно, управляющие программы были более сложными. Если оставить в стороне эти неопределенности, то цифры описывают реальную производительность при создании больших систем, и потому представляют ценность.
На рисунках 8.3 и 8.4 показаны некоторые интересные данные о фактической скорости программирования и отладки в сравнении с прогнозом.
Данные OS/360
Опыт OS/360 подтверждает данные Харра, хотя данные по OS/360 не столь подробны. В группах разработки управляющей программы производительность составила 600-800 отлаженных команд в год на человека. В группах разработки трансляторов производительность достигла 2000-3000 отлаженных команд в год на человека. При этом учитывается планирование, тестирование компонентов, системное тестирование и некоторые затраты на поддержку. Насколько я могу судить, эти данные согласуются с результатами Харра.
Рис. 8.3 Предсказанная и фактическая скорость программирования
Ежемесячная оценка размера программы
Рис. 8.4 Предсказанная и фактическая скорость отладки
Данные Арона, Харра и OS/360 дружно подтверждают резкие различия в производительности в зависимости от сложности и трудности самой задачи. В работе оценивания сложности я придерживаюсь той линии, что компиляторы втрое хуже обычных пакетных прикладных программ, а операционные системы втрое хуже компиляторов. [9]
Данные Корбато
Данные Харра и OS/360 относятся к программированию на языке ассемблера. Есть немного публикаций относительно производительности системного
программирования с использованием языков высокого уровня. Корбато (Corbato) из проекта MAC Массачусетского технологического института сообщает о средней производительности 1200 строк отлаженных операторов PL/I на человека в год при разработке операционной системы MULTICS (от 1 до 2 миллионов слов). [10]
Это число очень вдохновляет. Как у других проектов, MULTICS включает в себя управляющие программы и языковые трансляторы. Результатом также является системный продукт, отлаженный и документированный. Данные кажутся сравнимыми в отношении видов исполненной работы. А производительность повышается до средней величины между управляющими программами и трансляторами в других проектах.
Но Корбато указывает количество строк за год на человека, а не слов! Каждому оператору в его системе соответствует от трех до пяти слов кода, написанного вручную! Из этого можно сделать два важных вывода:
• Производительность, измеренная в элементарных операциях, оказывается постоянной, что кажется разумным, если учитывать, сколько времени нужно думать над оператором, и сколько ошибок может в нем быть. [11]
• При использовании подходящего языка высокого уровня производительность можно повысить в пять раз. [12]
Глава 9 Два в одном
Автору стоит присмотреться к Ною и… поучиться на примере Ковчега, как в очень маленькое пространство втиснуть очень много.
СИДНЕЙ СМИТ, «ЭДИНБУРГСКОЕ РЕВЮ»
Размер программы как стоимость
Какова стоимость программы? Если не считать времени выполнения, то помять, занимаемая программой, составляет главные издержки. Это верно даже для собственных разработок, когда пользователь платит автору существенно меньше, чем стоит разработка. Возьмем интерактивную систему IBM APL. Плата за ее использование составляет $400 в месяц. При работе она требует не меньше 160 Кбайт памяти. У машины Model 165 ежемесячная аренда 1 Кбайта памяти стоит около $12. Если пользоваться программой круглосуточно, то месячная плата составит $400 за пользование программой и $1920 за память. Если пользоваться системой APL лишь четыре часа в день, то месячная плата составит $400 за пользование программой и $320 за использование памяти.
Нередко можно встретить человека, выражающего ужас по поводу того, что в машине, имеющей 2 Мбайт памяти, под операционную систему может быть отведено 400 Кбайт. Это столь же глупо, как ругать Боинг-747 за то, что он стоит 27 миллионов долларов. Надо же спросить: «А что она делает?» Какую, собственно, простоту в использовании и производительность (посредством эффективного использования системы) получаешь за потраченные деньги? Нельзя ли вложенные в аренду памяти $4800 в месяц израсходовать с большей пользой — на другие аппаратные средства, программистов, прикладные программы?
Проектировщик системы отводит часть всех аппаратных ресурсов программам, резидентно находящимся в памяти, если считает, что пользователю это нужнее, чем сумматоры, диски и т.д. Нельзя критиковать программную систему за размер как таковой, и в то же время последовательно пропагандировать тесную интеграцию проектирования аппаратного и программного обеспечения.
Поскольку размер определяет значительную долю того, во что обходится пользователю системный программный продукт, изготовитель должен планировать размер, контролировать его и разрабатывать технологии, уменьшающие размер, подобно тому, как изготовитель аппаратной части планирует количество деталей, контролирует его и разрабатывает методы сокращения количества деталей. Как и для всякой цены, плох не большой размер как таковой, а размер, не вызываемый необходимостью.
Управление размером
Для менеджера проекта управление размером является отчасти технической, отчасти административной задачей. Чтобы устанавливать размеры предлагаемых систем, необходимо изучать пользователей и используемые ими приложения. Затем системы должны разлагаться на компоненты, для которых определяются проектные размеры. Поскольку варьировать соотношением скорости и размера можно лишь достаточно большими скачками, планирование размера является непростым делом, требующим знания возможных компромиссов для каждой части. Опытный менеджер сделает себе также «заначку», которую можно будет использовать в процессе работы.
Все же при работе над OS/360 пришлось извлечь несколько горьких уроков, несмотря на то, что все описанные меры были приняты.
Прежде всего, недостаточно установить размер памяти, нужно взвесить размер со всех сторон. Большинство прежних операционных систем размещалось на магнитных лентах, и большое время поиска на ленте не располагало к частой загрузке программных сегментов. OS/360 располагалась на диске, как и ее непосредственные предшественники — операционная система Stretch и дисковая операционная системы 1410-7010. Ее создатели получили свободу легкого обращения к диску. Первоначально это обернулось катастрофой для производительности.
При определении размеров памяти компонентов мы не установили одновременно бюджетов доступа. Как и следовало ожидать, программист, выходивший за рамки определенной ему памяти, разбивал программу на оверлеи. В результате и суммарный размер увеличивался, и выполнение замедлялось. Хуже то, что наша система административного контроля не смогла это обнаружить. Каждый программист сообщал, сколько памяти он использовал, и так как он укладывался в задание, никто не беспокоился.
К счастью, вскоре настал день, когда заработала система моделирования технических характеристик OS/360. Первые результаты показали наличие серьезных проблем. Моделирование компиляции с Fortran H на машине Model 65 с барабанами дало результат пять операторов в минуту! Анализ показал, что все модели управляющей программы делали множество обращений к диску. Даже интенсивно используемые модули супервизора часто обращались к диску, и результат по звуку весьма напоминал шелест перелистываемой книги.
Первая мораль ясна: планировать нужно как размер резидентной части, так и общий размер. Помимо планирования этих размеров нужно планировать и количество обращений к диску для обратной записи.
Второй урок был аналогичен. Ресурсы памяти устанавливались прежде, чем для каждого модуля было определено точное распределение памяти для функций. В результате каждый программист, не укладывавшийся в размеры, искал, что из его кода можно выкинуть через забор в память соседу. Поэтому буфера управляющей программы стали частью памяти пользователя. Что хуже, так же поступали все управляющие блоки, и в результате были полностью скомпрометированы безопасность и защита системы.
Поэтому второй вывод тоже совершенно ясен: при задании размера модуля нужно точно определить, что он должен делать.
И третий, более серьезный урок, который нужно извлечь из этого опыта. Проект был слишком велик, а общение между менеджерами недостаточным, чтобы многочисленные участники могли почувствовать себя добывающими зачетные очки для команды, а не создателями программных продуктов. Каждый оптимизировал свой личный участок, чтобы решить поставленные задачи, и мало кто задумывался над тем, как это отразится на заказчике. Потеря ориентации и связи представляют собой главную опасность для больших проектов. В течение всей разработки системные архитекторы должны поддерживать постоянную бдительность для обеспечения постоянной целостности системы. Однако такая стратегия зависит от позиции самих разработчиков. Едва ли не главнейшей функцией менеджера программного проекта должно быть воспитание позиции заботы об общей системе, ориентировки на пользователя.
Технологии сбережения памяти
Никакое распределение ресурсов памяти и контроль не сделают программу маленькой. Для этого требуется изобретательность и мастерство.
Очевидно, что чем больше функций, тем больше требуется памяти при том же самом быстродействии. Поэтому первой областью, где нужно приложить мастерство, является нахождение компромисса между функциональностью и размером. Здесь мы сразу сталкиваемся с важной стратегической проблемой. В какой мере этот выбор можно предоставить пользователю? Можно разработать программу со многими факультативными функциями, каждая из которых требует памяти. Можно сконструировать генератор, просматривающий список опций и соответствующим образом адаптирующий программу. Но цельная программа, соответствующая каждому отдельному списку опций, заняла бы меньше памяти. Это как в автомобиле: если подсветка карты, прикуриватель и часы входят в прейскурант как единая статья, их стоимость окажется ниже, чем если порознь выбирать каждый из предметов. Поэтому проектировщику следует определить степень детализации опций пользователя.
Если система проектируется для работы с памятью разного объема, возникает другой важный вопрос. Диапазон приспособляемости нельзя сделать произвольно широким — даже при разбиении программы на очень мелкие модули. В маленькой системе большинство модулей перегружается. Значительная часть резидентной памяти маленькой системы должна быть отведена для временной или страничной памяти, в которую загружаются другие части. Ее размер ограничивает размер каждого модуля. А разбиение функций на мелкие модули влечет потери и производительность, и памяти. Поэтому в большой системе, где временная память в двадцать раз больше, она лишь позволяет уменьшить количество обращений. Из-за маленьких размеров модулей система все-таки теряет в скорости и расходовании памяти. По этой причине эффективность системы, которую можно построить их модулей маленькой системы, ограничена.
Второй областью приложения мастерства является нахождение компромисса между памятью и быстродействием. Для отдельной функции увеличение памяти влечет за собой рост быстродействия, что справедливо в удивительно широком диапазоне величин. Этот факт делает возможным установление ресурсов памяти.
Чтобы облегчить своей команде поиск правильного соотношения между памятью и производительностью, менеджер может сделать две вещи. Во-первых, организовать обучение технике программирования, а не просто полагаться на природный ум и предшествующий опыт. Это особенно важно, если машина или язык новые. Особенности их эффективного использования нужно быстро изучить и сделать общим достоянием, возможно, присуждая особые призы за освоение новой техники.
Во-вторых, нужно понять, что у программирования есть технология и компоненты нужно собирать из готовых частей. В каждом проекте должен иметься набор хороших процедур или макросов для обработки очередей, поиска, хеширования и сортировки, причем не менее чем в двух вариантах: одном быстром, другом экономящем память. Разработка такой технологии является важной задачей реализации, которую можно решать параллельно с разработкой системной архитектуры.
Представление — суть программирования
За мастерством стоит изобретательность, благодаря которой появляются экономичные и быстрые программы. Почти всегда это является результатом стратегического прорыва, а не тактического умения. Иногда таким стратегическим прорывом является алгоритм, как, например, быстрое преобразование Фурье, предложенное Кули и Тьюки, или замена n [2] сравнений на n log n при сортировке.
Гораздо чаще стратегический прорыв происходит в результате представления данных или таблиц. Здесь заключена сердцевина программы. Покажите мне блок-схемы, не показывая таблиц, и я останусь в заблуждении. Покажите мне ваши таблицы, и блок-схемы, скорей всего, не понадобятся: они будут очевидны.
Примеры мощи, которой обладает представление, легко умножить. Я вспоминаю одного молодого человека, занимавшегося созданием усовершенствованного консольного интерпретатора для IBM 650. Ему удалось вместить его в поразительно малое пространство благодаря разработке интерпретатора для интерпретатора и пониманию того, что взаимодействие человека с машиной происходит медленно и редко, а память дорога. Элегантный маленький компилятор с Fortran фирмы Digitek использует особое очень плотное представление кода самого компилятора, благодаря чему не требуется внешней памяти. Время, которое тратится на распаковку кода, десятикратно окупается за счет отсутствия ввода-вывода. (Упражнения в конце главы 6 книги Брукса и Иверсона «Автоматическая обработка данных» [1] включает подборку таких примеров, как и многие упражнения у Кнута. [2] )
Программист, ломающий голову по поводу нехватки памяти, часто поступит лучше всего, оставив в покое свой код, вернувшись назад и хорошенько посмотрев свои данные. Представление — суть программирования.
Глава 10 Документарная гипотеза
Гипотеза:
Среди моря бумаг несколько документов становятся критически важными осями, вокруг которых вращается все управление проектом. Они являются главными личными инструментами менеджера.
Технология, правила фирмы и традиции ремесла требуют выполнить некоторое количество канцелярской работы по проекту. Менеджеру-новичку, только что самому бывшему мастеровым, эта работа кажется совершенной помехой и ненужным отвлечением, бумажным валом, грозящим захлестнуть его. По большей части так и есть в действительности.
Однако понемногу он начинает понимать, что некоторая небольшая часть этих документов заключает в себе значительную часть его административной работы. Подготовка каждого из них служит главным поводом для сосредоточения мысли и кристаллизации обсуждений, которые без этого длились бы вечно. Ведение этих документов становится механизмом наблюдения и предупреждения. Сам документ становится памяткой, индикатором состояния и базой данных для составления отчетов.
Чтобы увидеть, как это должно работать в программном проекте, рассмотрим некоторые документы, полезные и в другом контексте, и посмотрим, можно ли сделать обобщения.
Документы для проекта разработки компьютера
Предположим, что разрабатывается компьютер. Какие важнейшие документы должны быть разработаны?
Цели. Здесь описывается, какие потребности нужно удовлетворить, а также задачи, пожелания, ограничения и приоритеты.
Спецификации. Это руководство по компьютеру плюс спецификации технических характеристик. Это один из первых документов, составляемых для нового продукта, и завершается он последним.
График.
Бюджет. Это не просто ограничение, но один из наиболее полезных менеджеру документов. Наличие бюджета заставляет осуществлять технические решения, которых старались бы избежать, и, что еще важнее, служит выполнению и разъяснению стратегических решений.
Организационная структура.
Пространственное расположение.
Оценка, прогноз, цены. Они находятся в циклической взаимосвязи, что определяет успех или провал проекта:
Чтобы сделать прогноз рынка, нужны технические характеристики и установленные цены. Цифры прогноза вместе с заданным проектом числом компонентов определяют оценку стоимости производства и долю расходов на разработку и фиксированных затрат, приходящихся на одно устройство. Эти расходы, в свою очередь, определяют цены.
Если цены ниже установленных, начинается радостная раскрутка спирали успеха. Прогноз растет, стоимость одного устройства падает, а цены опускаются еще ниже.
Если цены выше установленных, начинается раскрутка спирали катастрофы, и все силы должны быть брошены на то, чтобы сломить ее. Нужно улучшить технические характеристики и разработать новые приложения, чтобы поднять рыночный прогноз. Издержки нужно снизить, чтобы получить более низкие оценки. Напряженность такого цикла часто требует больших усилий маркетолога и инженера.
При этом возможны забавные колебания. Я вспоминаю машину, у которой в течение трех лет разработки каждые полгода счетчик команд устраивался то в оперативной памяти, то вне ее. На одном этапе требовались чуть лучшие характеристики, и счетчик делали на транзисторах. На следующем этапе начиналась борьба за снижение стоимости, поэтому счетчик организовывался как адрес в оперативной памяти. В другом проекте лучший известный мне менеджер по инженерным проектам служил гигантским маховиком, гася своей инерцией колебания, исходившие от маркетинга и менеджмента.
Документы для факультета в университете
Несмотря на огромные различия в целях и деятельности, критическое множество для председателя факультета в университете составляет сходное число сходных документов. Почти каждое решение декана, совета кафедры или председателя является спецификацией или изменением следующих документов:
Цели.
Описание курса.
Требования к соискателю степени.
Предложения по исследовательской работе (и планы, при наличии финансирования).
Расписание занятий и назначение преподавателей.
Бюджет.
Помещения.
Назначение руководителей для аспирантов.
Обратите внимание, что документы очень похожи на те, которые нужны для компьютерного проекта: цели, спецификации продукта, распределение времени, денег, места и людей. Только документы с ценами отсутствуют: этим занимается законодательное собрание. Сходство не случайно — заботами всякой задачи управления являются: что, когда, по какой цене, где и кто.
Документы для программного проекта
Во многих программных проектах работа начинается с совещаний, на которых обсуждается структура; затем приступают к написанию программ. Однако как бы ни был мал проект, менеджер поступит мудро, если сразу начнет формализовать хотя бы минидокументы, которые послужат его базой данных. И он обнаружит, что ему нужны, по большей части, те же документы, что и другим менеджерам.
Что: цели. Здесь определяется, какие потребности должны быть удовлетворены, а также задачи, пожелания, ограничения и приоритеты.
Что: спецификации продукта. Начинается как предложение, а кончается как руководство и внутренняя документация. Важнейшей частью являются спецификации скорости и памяти.
Когда: график.
По какой цене: бюджет.
Где: расположение помещений.
Кто: организационная структура. Она переплетается со спецификацией интерфейса, как предсказывает закон Конвея: «Организации, проектирующие системы, неизбежно производят системы, являющиеся копиями их организационных структур». [1] Конвей идет дальше и указывает, что организационная структура первоначально отражает проект первой системы, который наверняка был ошибочным. Если проект системы должен допускать внесение изменений, то и организация должна быть готова к переменам.
Зачем нужны формальные документы?
Во-первых, необходимо записывать принятые решения. Только когда пишешь, становятся видны пропуски и проступают несогласованности. В процессе записывания возникает необходимость принятия сотен мини-решений, и их наличие отличает четкую и ясную политику от расплывчатой.
Во-вторых, посредством документов решения сообщаются исполнителям. Менеджеру приходится постоянно удивляться, что политика, которую он считал известной всем, оказывается совершенно неизвестной одному из членов его команды. Поскольку основная его работа состоит в том, чтобы все двигались в одном направлении, его главная ежедневная задача заключается в обмене информацией, а не принятии решений, и документы очень облегчат ему эту нагрузку.
Наконец, документы образуют базу данных менеджера и его контрольный список. Периодически изучая их, он видит, в какой точке пути находится, и определяет необходимость смещения акцентов или изменения направления.
Я не разделяю выдвигаемых продавцами видений «всеохватывающей информационной системы для управления», в которой администратор вводит в компьютер запрос с клавиатуры, и на экране вспыхивает нужный ему ответ. Есть много фундаментальных причин, по которым этого не произойдет. Одна причина заключается в том, что только маленькая часть, возможно 20 процентов, рабочего времени администратора занята задачами, которые требуют сведений, отсутствующих в его памяти. А все остальное время — это общение: слушать, отчитываться, обучать, убеждать, советовать, ободрять. Но для той доли, для которой действительно нужны данные, необходимы несколько важных документов, которые удовлетворяют большинство нужд.
Задача менеджера состоит в том, чтобы разработать план и выполнить его. Но только записанный план является точным и может быть сообщен другим. Такой план состоит из документов, описывающих: что, когда, по какой цене, где и кто. Этот маленький набор важных документов охватывает значительную часть работы менеджера. Если в самом начале понять их всеохватывающую и важную сущность, то они станут для менеджера добрым инструментом, а не раздражающей обузой. Сделав это, он определит свой курс более четко и быстро.
Глава 11 Планируйте на выброс
В этом мире нет ничего постояннее непостоянства.
СВИФТ
Разумно взять метод и испытать его. При неудаче честно признайтесь в этом и попробуйте другой метод. Но главное, делайте что-нибудь.
ФРАНКЛИН Д. РУЗВЕЛЬТ
Опытные заводы и масштабирование
Инженеры-химики давно поняли, что процесс, успешно осуществляемый в лаборатории, нельзя одним махом перенести в заводские условия. Необходим промежуточный шаг, создание опытного завода, чтобы получить опыт наращивания количеств веществ и функционирования в незащищенных средах. К примеру, лабораторный процесс опреснения воды следует проверить на опытном заводе мощностью 50 тысяч литров в день, прежде чем использовать в городской системе водоснабжения мощностью 10 млн. литров в день.
Разработчики программных систем тоже получили этот урок, но, похоже, до сих пор его не усвоили. В одном проекте за другим разрабатывают ряд алгоритмов и затем начинают создавать поставляемое клиенту программное обеспечение по графику, требующему поставки первой же сборки.
В большинстве проектов первой построенной системой с трудом можно пользоваться. Она может быть слишком медленной, слишком большой, неудобной в использовании, а то и все вместе. Не остается другой альтернативы, кроме как, поумнев, начать сначала и построить перепроектированную программу, в которой эти проблемы решены. Браковка и перепроектирование могут делаться для всей системы сразу или по частям. Но весь опыт разработки больших систем показывает, что будет сделано. [2] В тех случаях, когда используются новые системные концепции и новые технологии, приходится создавать систему на выброс, поскольку даже самое лучшее планирование не столь всеведуще, чтобы попасть в цель с первого раза.
Поэтому проблема не в том, создавать или нет опытную систему, которую придется выбросить. Вы все равно это сделаете. Вопрос единственно в том, планировать ли заранее разработку системы на выброс или обещать клиентам поставку системы, которую придется выбросить. Если смотреть под этим углом, ответ становится намного проще. Поставка хлама клиенту позволяет выиграть время, но происходит это ценой мучений пользователя, отвлечений разработчиков во время перепроектирования и дурной репутации продукта, которую даже самой удачно перепроектированной программе будет трудно победить.
Поэтому планируйте выбросить первую версию — вам все равно придется это сделать.
Постоянны только изменения
После уяснения того, что опытную систему нужно создавать, а потом выбросить, и что перепроектирование с новыми идеями неизбежно, полезно обратиться лицом к изменению как явлению природы. Первый шаг — признание того, что изменение — это образ жизни, а не постороннее и досадное исключение. Косгроув мудро указал, что программист поставляет удовлетворение потребности пользователя, а не какой-то осязаемый продукт. И в то время как программы создаются, тестируются и используются, меняются как фактические потребности пользователя, так и понимание им своих потребностей. [3]
Конечно, это справедливо и в отношении потребностей, удовлетворяемых физическими продуктами, будь то автомобили или компьютеры. Но само существование осязаемого продукта определяет запросы пользователя и их квантование. Податливость и неосязаемость программного продукта побуждают его создателей к бесконечному изменению требований.
Я далек от того, чтобы считать, будто все изменения целей и требований клиента можно или необходимо учитывать в проекте. Очевидно, должен быть установленный порог, который должен подниматься все выше и выше по ходу разработки, иначе ни один продукт никогда не будет создан.
Тем не менее некоторые изменения в задачах неизбежны, и лучше подготовиться к ним заранее, чем предполагать, что их не возникнет. Неизбежны не только изменения в целях, но также изменения в стратегии разработки и технологии. Концепция «работы на мусорный ящик» есть лишь признание того факта, что по мере приобретения опыта меняется проект. [4]
Планируйте внесение изменений в систему
Способы проектирования системы с учетом будущих изменений хорошо известны и широко обсуждаются в литературе — возможно, шире обсуждаются, чем применяются. Они включают в себя тщательное разбиение на модули, интенсивное использование подпрограмм, точное и полное определение межмодульных интерфейсов и полную их документацию. Менее очевидно, что при любой возможности необходимо использовать стандартные последовательности вызова и технологии табличного управления.
Очень важно использовать языки высокого уровня и технологии самодокументирования, чтобы уменьшить число ошибок, вызываемых изменений. Мощную поддержку при внесении изменений оказывают операции времени компиляции по включению стандартных объявлений.
Важным приемом является квантование изменений. Каждый продукт должен иметь нумерованные версии, и каждая версия должна иметь свой график работ и дату фиксации, после которой изменения включаются уже в следующую версию.
Планируйте организационную структуру для внесения изменений
Косгроув рекомендует ко всем планам, вехам и графикам относиться как к пробам, чтобы облегчить изменения. Здесь он заходит слишком далеко — сегодня группы программистов терпят неудачи обычно из-за слишком слабого, а не слишком сильного административного контроля.
Тем не менее он выказывает большую проницательность. Он замечает, что нежелание документировать проект происходит не только от лени или недостатка времени. Оно происходит от нежелания проектировщика связывать себя отстаиванием решений, которые, как он знает, предварительные. «Документируя проект, проектировщик становится объектом критики со всех сторон, и должен защищать все, что написал. Если организационная структура может представлять угрозу, не будет документироваться ничего, кроме того, что нельзя оспорить.»
Создавать организационную структуру с учетом внесения в будущем изменений значительно труднее, чем проектировать систему с учетом будущих изменений. Каждый получает задание, расширяющее круг его обязанностей, чтобы сделать технически более гибким все подразделение. В больших проектах менеджеру нужно иметь двух или трех высококлассных программистов в качестве резерва, который можно бросить на самый опасный участок боя.
Структуру управления также нужно изменять по мере изменения системы. Это означает, что руководитель должен уделить большое внимание тому, чтобы его менеджеры и технический персонал были настолько взаимозаменяемы, насколько позволяют их способности.
Барьеры являются социологическими, и с ними нужно бдительно и настойчиво бороться. Во-первых, менеджеры сами рассматривают руководителя как «слишком большую ценность», чтобы использовать их для реального программирования. Во-вторых, работа менеджера обладает более высоким престижем. Чтобы преодолеть эти сложности, в некоторых лабораториях, например, в Bell Labs, упраздняют все наименования должностей. Каждый профессиональный служащий является «техническим сотрудником». В других, например в IBM, вводят двойную лестницу продвижения (рис. 11.1). Соответствующие ступеньки теоретически равнозначны.
Рис. 11.1 Двойная служебная лестница IBM
Легко установить соответствующие ступенькам размеры жалования. Значительно труднее дать им соответствующий престиж. Офисы должны иметь одинаковый размер и обстановку. Секретарские и прочие службы должны быть соответствующими. Перевод с технической лестницы в управленческую не должен сопровождаться повышением, и о нем всегда нужно сообщать как о «переводе», а не как о «повышении». Обратный перевод всегда должен сопровождаться прибавкой к жалованью.
Менеджеров нужно посылать на курсы технической переподготовки, а старший технический персонал — на курсы обучения управлению. Цели проекта, ход работы и административные проблемы должны доводиться до всех руководящих работников.
Если позволяет подготовка, руководящие работники должны быть технически и морально готовы возглавить группы или насладиться разработкой программ собственными руками. Конечно, осуществление всего этого требует много труда, но результат того стоит!
Идея организации групп программистов наподобие операционных бригад представляет собой коренное решение этой проблемы. Она заставляет руководящего работника почувствовать, что он не унижает себя, когда пишет программы, и пытается убрать социальные препятствия, мешающие ему испытать радость творчества.
Более того, эта структура предназначена для сокращения числа интерфейсов. Благодаря ей систему можно изменять с максимальной легкостью, и становится относительно просто перенаправить всю бригаду на другое задание в случае необходимости организационных изменений. Это действительно долгосрочное решение проблемы гибкой организации.
Два шага вперед, шаг назад
Программа не перестает изменяться после своей поставки клиенту. Изменения после поставки называются сопровождением программы, но этот процесс в корне отличается от сопровождения аппаратной части.
Сопровождение аппаратной части компьютерной системы состоит из трех видов деятельности: замены испорченных деталей, чистки и смазки и осуществления технических изменений для исправления конструктивных дефектов. (Большая часть
технических изменений, но не все, устраняет дефекты разработки или реализации, а не архитектуры, и потому незаметна пользователю.)
Сопровождение программ не предполагает чистки, смазки или замены испортившихся компонентов. Оно состоит главным образом из изменений, исправляющих конструктивные дефекты. Гораздо чаще, чем для аппаратной части, эти изменения включают в себя дополнительные функции. Обычно они видны пользователю.
Общая стоимость сопровождения широко используемой программы обычно составляет 40 и более процентов стоимости ее разработки. Удивительно, что на стоимость сопровождения сильно влияет число пользователей. Чем больше пользователей, тем больше ошибок они находят.
Бетти Кэмпбелл из Лаборатории ядерной физики МТИ отмечает интересный цикл в жизни отдельной версии программы. Он показан на рисунке 11.2. В начале существует тенденция повторного появления ошибок, найденных и устраненных в предыдущих версиях. Обнаруживаются ошибки в функциях, впервые появившихся в новой версии. Все они исправляются, и в течение нескольких месяцев все идет хорошо. Затем количество обнаруженных ошибок снова начинает расти. По мнению Кэмпбелл, это происходит потому, что пользователи выходят на новый уровень сложности, начиная полностью применять новые возможности версии. Эта интенсивная работа выявляет более скрытые ошибки в новых функциях. [5]
Рис. 11.2 Частота обнаружения ошибок как функция возраста версии программы
Фундаментальная проблема при сопровождении программ состоит в том, что исправление одной ошибки с большой вероятностью (20-50 процентов) влечет появление новой. Поэтому весь процесс идет по принципу «два шага вперед, один назад».
Почему не удается устранить ошибки более аккуратно? Во-первых, даже скрытый дефект проявляет себя как отказ в каком-то одном месте. В действительности же он часто имеет разветвления по всей системе, обычно неочевидные. Всякая попытка исправить его минимальными усилиями приведет к исправлению локального и очевидного, но если только структура не является очень ясной или документация очень хорошей, отдаленные последствия этого исправления останутся незамеченными. Во-вторых, исправляет ошибки обычно не автор программы, и часто это младший программист или стажер.
Вследствие внесения новых ошибок сопровождение программы требует значительно больше системной отладки на каждый оператор, чем при любом другом виде программирования. Теоретически, после каждого исправления нужно прогнать весь набор контрольных примеров, по которым система проверялась раньше, чтобы убедиться, что она каким-нибудь непонятным образом не повредилась. На практике такое возвратное тестирование действительно должно приближаться к этому теоретическому идеалу, и оно очень дорого стоит.
Очевидно, методы разработки программ, позволяющие исключить или, по крайней мере, выявить побочные эффекты, могут резко снизить стоимость сопровождения, как и методы разработки проектов меньшим числом людей и с меньшим числом интерфейсов — а значит, и с меньшим числом ошибок.
Шаг вперед, шаг назад
Леман и Белади изучили историю последовательных выпусков большой операционной системы. [6] Они считают, что общее количество модулей растет линейно с номером версии, но число модулей, затронутых изменениями, растет экспоненциально в зависимости от номера версии. Все исправления имеют тенденцию к разрушению структуры, увеличению энтропии и дезорганизации системы. Все меньше сил тратится на исправление ошибок исходного проекта и все больше — на ликвидацию последствий предыдущих исправлений. По прошествии времени система становится все менее и менее организованной. Рано или поздно исправление ошибок теряет смысл. На каждый шаг вперед приходится шаг назад. В принципе годная для вечного использования система перестает быть основой развития. Кроме того, меняются машины, конфигурации, требования пользователя, так что фактически система является вечной. Необходим совершенно новый проект, выполняемый с самого начала.
От механической статистической модели Белади и Леман приходят к общему заключению относительно программных систем, которое подкреплено всем опытом человечества. «Лучшая пора вещей — когда они только что появились», — сказал Паскаль. Ч. С. Льюис выразил это более весомо:
Вот ключ к пониманию истории. Высвобождается огромная энергия, возникают цивилизации, создаются прекрасные учреждения, но всякий раз что-то происходит не так. Какая-то роковая ошибка возносит на вершину себялюбивых и жестоких людей, и все скатывается назад, в нищету и руины. Действительно, машина глохнет. Она нормально стартует и проезжает несколько метров, а затем ломается. [7]
Системное программирование является процессом, уменьшающим энтропию, а потому ему внутренне присуща метастабильность. Сопровождение программ есть процесс, увеличивающий энтропию, и даже самое умелое его ведение лишь отдаляет впадение системы в безнадежное устаревание.
Глава 12 Острый инструмент
Хорошего работника узнают по инструменту.
ПОСЛОВИЦА
Даже в наше время многие программные проекты, с точки зрения использования инструментария, работают как механические мастерские. У каждого механика есть свой набор инструментов, собиравшийся в течение всей жизни, который он тщательно запирает и охраняет — наглядное свидетельство личного мастерства. Точно также программист собирает маленькие редакторы, сортировки, двоичные дампы, утилиты для работы с дисками и припрятывает их в своих файлах.
Однако такой подход не оправдан при работе над программным проектом. Во-первых, важной задачей является обмен информацией, а личный инструмент ему мешает, а не содействует. Во-вторых, при переходе на новую машину или новый рабочий язык технология меняется, поэтому срок жизни инструмента недолог. И наконец, очевидно, значительно эффективнее совместно разрабатывать и сопровождать программные инструменты общего назначения.
Однако недостаточно иметь инструменты общего назначения. Как специальные задачи, так и личные предпочтения обусловливают необходимость иметь также и специализированный инструмент. Поэтому при обсуждении состава команды программистов я предлагал иметь в бригаде одного инструментальщика. Этот человек владеет всеми общедоступными инструментами и может обучать их использованию. Он может также создавать специализированные инструменты, которые потребуются его начальнику.
Таким образом, менеджер проекта должен установить принципы и выделить ресурсы для разработки общих инструментов. В то же время он должен понимать необходимость в специализированных инструментах и не препятствовать разработке собственных инструментов в подчиненных рабочих группах. Есть опасный соблазн попытаться достичь большей эффективности, собрав вместе отдельных разработчиков инструмента и доработав общегрупповой инструментарий. Но это не удается.
Что это за инструменты, разработку которых менеджер должен обдумывать, планировать и организовывать? Прежде всего, вычислительные средства. Для этого требуются машины, и должна быть принята политика планирования времени. Для этого требуется операционная система, и должна быть установлена политика обслуживания. Для этого требуется язык, и должна быть заложена политика в отношении языка. Затем идут утилиты, средства отладки, генераторы контрольных примеров и текстовый процессор для работы с документацией. Рассмотрим их поочередно.[1]
Целевые машины
Машинную поддержку полезно разделить на целевые машины и рабочие машины. Целевая машина — это та, для которой пишется программное обеспечение и на которой, в конце концов, его нужно будет тестировать. Рабочие машины — это те, которые предоставляют сервисы, используемые для создания системы. Если создается новая операционная система для старой машины, последняя может служить одновременно и целевой, и рабочей.
Каковы типы целевых средств? Если бригада создает новый супервизор или другое программное средство, составляющее сердцевину системы, то ей, конечно, нужна своя машина. Для таких систем потребуются операторы и один или два системных программиста, чтобы машина была в рабочем состоянии.
Если требуется отдельная машина, то она должна быть довольно специфической: не требуется, чтобы она была быстрой, но требуется, по меньшей мере, 1 Мбайт
оперативной памяти, 100 Мбайт в активных дисках и терминалы. Достаточно символьных терминалов, но со значительно большей скоростью, чем 15 символов в секунду, характерных для пишущих машинок. Наличие большой памяти значительно способствует продуктивности, позволяя заняться разбиением на оверлеи и минимизацией размера после тестирования функций.
Машина или программные средства для отладки должны также иметь средства для автоматического подсчета и измерений любых параметров программы во время отладки. К примеру, карты использования памяти служат мощным диагностическим средством при выяснении странной логики поведения или неожиданно низкой производительности.
Планирование времени. Если целевая машина новая, — например, для нее создается первая операционная система, — то машинного времени мало, и планирование становится большой проблемой. Потребности в рабочем времени целевой машины имеет специфическую кривую роста. При разработке OS/360 у нас были хорошие эмуляторы System/360 и другие машины. По прежнему опыту мы оценили, сколько часов рабочего времени S/360 нам понадобится, и стали получать первые машины с производства. Но месяц за месяцем они оставались без нагрузки. Затем сразу все 16 систем оказались загруженными, и распределение времени стало проблемой. Использование машин выглядело примерно как на рисунке 12.1. Все одновременно начали отлаживать первые компоненты, и затем все команды постоянно что-то отлаживали.
Рис. 12.1 Рост использования целевых машин
Мы централизовали все свои машины и библиотеки магнитных лент и организовали для их работы профессиональную и опытную группу машинного зала. Для максимизации бывшего в недостатке машинного времени S/360 все отладочные прогоны мы осуществляли в пакетном режиме на подходящих свободных машинах. Мы добились четырех запусков в день (оборачиваемость составила два с половиной часа), а требовалась четырехчасовая оборачиваемость. Вспомогательная машина 1401 с терминалами использовалась для планирования прогонов, отслеживания тысяч заданий и контроля времени оборачиваемости.
Но со всей этой организованностью мы перестарались. После нескольких месяцев низкой оборачиваемости, взаимных обвинений и прочих мук мы перешли к выделению машинного времени крупными блоками. К примеру, вся группа из пятнадцати человек, занимавшаяся сортировкой, получала систему на срок от четырех до шести часов. Планирование этого времени было их внутренним делом. Даже если система была на занята, посторонние не могли ею пользоваться.
Это оказалось более удачным способом планирования. Хотя коэффициент использования машины, возможно, несколько упал (а часто и этого не было), производительность поднялась. Для каждого члена команды десять запусков в течение шести часов значительно продуктивнее, чем десять запусков, осуществленных с перерывами в три часа, поскольку постоянная концентрация сокращает время обдумывания. После такой гонки команде обычно требовалось один-два дня, чтобы подогнать работу с документами, прежде чем просить о выделении нового блока. Зачастую всего три программиста могут с пользой поделить и распределить между собой выделенный им блок времени. Похоже, что это лучший способ использования целевой машины при отладке новой операционной системы.
Так было на практике, хотя это не соответствовало теории. Системная отладка всегда была занятием для ночной смены, подобно астрономии. Двадцать лет назад, работая над 701-й машиной, я впервые познал продуктивную свободу от формальностей, присущую предрассветным часам, когда все начальники из машинного зала крепко спят по домам, а операторы не расположены бороться за соблюдение правил. Сменилось три поколения машин, полностью изменились технологии, появились операционные системы, но этот лучший способ работы остался прежним. Он продолжает жить, поскольку наиболее эффективен. Пришла пора признать его продуктивность и шире применять.
Рабочие машины и службы данных
Эмуляторы. Если целевой компьютер новый, то для него необходим логический эмулятор. Это дает аппарат для отладки задолго до того, как целевая машина будет в наличии. Что столь же важно, даже тогда, когда становится доступной целевая машина, имеется доступ к надежному средству для отладки.
Надежное — не то же самое, что точное. Эмулятор неизбежно в каком-либо отношении будет отступать от верной и точной реализации архитектуры новой машины. Но это будет одна и та же реализация и сегодня, и завтра, чего не скажешь о новой аппаратной части.
В наше время мы привыкли к тому, что аппаратная часть компьютера большую часть времени работает без сбоев. Если только разработчик прикладной программы не замечает, что система неодинаково ведет себя при разных идентичных прогонах программы, ему правильнее всего поискать ошибки в своем коде, а не в технике.
Этот опыт, однако, сослужил плохую службу при программировании новой машины. Лабораторные разработки, предварительные или ранние выпуски компьютеров не работают должным образом, не работают надежно и не остаются неизменными день ото дня. По мере обнаружения ошибок технические изменения производятся во всех экземплярах машины, включая используемый группой программистов. Такая неустойчивость основания достаточно неприятна. Отказы аппаратуры, обычно скачкообразные, еще хуже. И хуже всего неопределенность, лишающая стимула старательно копаться в своем коде в поисках ошибки — ее может там вовсе не быть. Поэтому надежный эмулятор на зрелой машине остается полезным значительно дольше, чем можно было предположить.
Машины для компилятора и ассемблера. По тем же причинам требуются компиляторы и ассемблеры, работающие на надежных машинах, но компилирующие объектный код для целевой системы. Затем можно начать его отладку на эмуляторе.
При программировании на языках высокого уровня значительную часть отладки можно произвести при компиляции для вспомогательной машины и тестировании результирующей программы, прежде чем отлаживать программу для целевой машины. Этим достигается производительность непосредственного исполнения, а не эмуляции, в сочетании с надежностью стабильной машины.
Библиотеки программ и учет. Очень успешным и важным применением вспомогательной машины в программе разработки OS/360 была поддержка библиотек программ. Система, разработанная под руководством У. Р. Кроули (W. R. Crowley), состояла из двух соединенных вместе машин 7010 и общей дисковой базой данных. На 7010 поддерживался также ассемблер для S/360. В этой библиотеке хранился весь протестированный или находящийся в процессе тестирования код, как исходный, так и ассемблированные загрузочные модули. На практике библиотека была разбита на подбиблиотеки с различными правами доступа.
Прежде всего, у каждой группы или программиста была область для хранения экземпляров программ, контрольных примеров и окружения, которое требовалось для тестирования компонентов. На этой площадке для игр не было никаких ограничений на действия с собственными программами.
Когда компонент программиста был готов к включению в более крупную часть, его экземпляр передавался менеджеру этой более крупной системы, который помещал его в подбиблиотеку системной интеграции. Теперь автор не мог его изменить без разрешения менеджера интеграции. Когда система собиралась воедино, этот менеджер проводил все виды системного тестирования, выявляя ошибки и получая исправления.
Через некоторое время системная версия была готова для более широкого использования. Тогда она перемещалась в подбиблиотеку текущей версии. Этот экземпляр был священным, и доступ к нему разрешался только для исправления разрушительных ошибок. Его можно было использовать для интегрирования и тестирования всех новых версий модулей. Программный каталог на машине 7010 отслеживал все версии каждого модуля, его состояние, местонахождение и изменения.
Здесь важны два обстоятельства. Первое — это контроль, означающий, что экземпляры программ принадлежат менеджерам, и только они могут санкционировать их изменение. Второе — формальное разделение и перемещение с площадки для игр к интеграции и выпуску новой версии.
По моему мнению, это было одним из лучших решений в программе OS/360. Эта часть технологии управления была независимо разработана для нескольких крупных программных проектов, в том числе в Bell Labs, ICL и Кембриджском университете. [2] Она применима как к программам, так и к документации. Это — неоценимая технология.
Программные инструменты. По мере появления новых технологий отладки старые теряют значение, но не исчезают. По-прежнему необходимы дампы памяти, редакторы исходного текста, дампы мгновенного состояния, даже трассировки.
Аналогичным образом, требуется полный набор утилит для загрузки колод перфокарт на диски, копирования магнитных лент, печати файлов, изменения каталогов. Если инструментальщика проекта назначить на достаточно ранней стадии, то все это может быть сделано сразу и находиться в готовности к моменту надобности.
Система документации. Из всех инструментов больше всего труда может сберечь компьютеризированная система редактирования текста, действующая на надежной машине. Наша система, разработанная Дж. У. Франклином (J. W. Franklin), была очень удобна. Я думаю, без нее руководства по OS/360 появились бы значительно позднее и оказались бы более запутанными. Есть люди, которые станут утверждать, что двухметровая полка руководств по OS/360 является следствием недержания речи, и сама ее объемистость являет собой новый тип непостижимости. И доля правды в этом есть.
Но у меня есть два возражения. Во-первых, хотя документация по OS/360 и ошеломляет размерами, план ее изучения тщательно изложен. Если использовать его избирательно, то чаще всего можно не обращать внимания на большую часть всей массы. Документацию по OS/360 нужно рассматривать как библиотеку или энциклопедию, а не материал для обязательного чтения.
Во-вторых, это гораздо лучше, чем крайняя недостаточность документации, характерная для большинства систем программирования. Я охотно соглашусь, тем не менее, что в некоторых местах текст можно было значительно улучшить, и результатом лучшего описания стал бы меньший объем. Некоторые части (например, «Концепции и средства») сейчас очень хорошо написаны.
Эмулятор производительности. Лучше его иметь. Разработайте его «снаружи внутрь», как описано в следующей главе. Используйте одинаковое проектирование сверху вниз для эмулятора производительности, эмулятора логики и самого продукта. Начните работу с ним как можно раньше. Прислушайтесь к тому, что он вам скажет.
Языки высокого уровня и интерактивное программирование
Сегодня два важнейших инструмента системного программирования — это те, которые не использовались при разработке OS/360 почти десятилетие назад. Они до сих пор не очень широко используются, но все указывает на их мощь и применимость. Это: а) языки высокого уровня и б) интерактивное программирование. Я убежден, что только инертность и лень препятствует повсеместному принятию этих инструментов, технические трудности более не являются извинениями.
Языки высокого уровня. Главные основания для использования языков высокого уровня — это производительность и скорость отладки. Производительность мы обсуждали раньше (глава 8). Имеющиеся данные, хотя и немногочисленные, указывают на многократный рост, а не на увеличение на несколько процентов.
Улучшение отладки происходит благодаря тому, что ошибок становится меньше, а находить их легче. Их меньше, поскольку устраняется целый уровень образования ошибок, уровень, на котором делаются не только синтаксические, но и семантические ошибки, такие как неправильное использование регистров. Их легче находить, поскольку в этом помогает диагностика компилятора и, что еще важнее, очень легко вставлять получение отладочных моментальных снимков.
Меня эти возможности производительности и отладки ошеломляют. Мне трудно представить себе систему программирования, которую я стал бы создавать на языке ассемблера.
Ну, а как с классическими возражениями против этого инструмента? Их три: я не могу сделать то, что хочу; результирующая программа слишком велика; результирующая программа слишком медленна.
Что касается возможностей, возражение, я думаю, больше не состоятельно. Все свидетельствует в пользу того, что можно делать то, что хочется, потрудившись найти способ, но иногда для этого приходится изловчиться. 3, [4]
Что касается памяти, то новые оптимизирующие компиляторы начинают показывать весьма удовлетворительные результаты, и их усовершенствование продолжается.
Что касается скорости, то оптимизирующие компиляторы иногда порождают код, который зачастую выполняется быстрее, чем написанный вручную. Более того, проблемы скорости можно обычно решить, заменив от 1 до 5 процентов скомпилированной программы кодом, написанным вручную, после ее полной отладки. [5]
Какой язык высокого уровня следует использовать для системного программирования? Сегодня единственный достойный кандидат — PL/I. [6] У него очень полный набор операторов; он соответствует окружению операционной среды; имеется целый ряд компиляторов с разными особенностями — интерактивных, быстрых, с улучшенной диагностикой, с высокой степенью оптимизации. Лично я быстрее разрабатываю алгоритмы с помощью APL; затем я перевожу их в PL/I для соответствия системному окружению.
Интерактивное программирование. Одним из оправданий проекта МТИ MULTICS была его польза для создания систем программирования. MULTICS (и вслед за тем TSS IBM) концептуально отличается от других интерактивных компьютерных систем именно в тех отношениях, которые необходимы для системного программирования: многоуровневая система разделения доступа и защиты данных и программ, интенсивное управление библиотеками и средства для совместной работы пользователей терминалов. Я убежден, что во многих приложениях интерактивные системы никогда не заменят системы с обработкой пакетных заданий. Но я думаю, что создатели MULTICS привели самые убедительные доводы в ее пользу именно в применении к системному программированию.
Пока есть не много свидетельств действительной плодотворности этих очевидно мощных инструментов. Существует широко распространенное признание того, что отладка является трудной и медленной частью системного программирования, и медленная оборачиваемость — проклятие отладки. Поэтому логика интерактивного программирования кажется неумолимой. [7]
Рис. 12.2 Сравнительная производительность при пакетном и диалоговом программировании
Помимо того, есть хорошие отзывы тех, кто разработал таким способом небольшие системы или части систем. Единственные доступные мне данные относительно влияния на программирование больших систем исходят от Джона Харра из Bell Labs. Они представлены на рисунке 12.2. Эти цифры охватывают написание, ассемблирование и отладку программ. Первая программа является, в основном, управляющей. Остальные три — языковые трансляторы, редакторы и т.п. Данные Харра позволяют предположить, что средства интерактивной работы, по крайней мере, удваивают производительности системного программирования. [8]
Эффективное использование большинства интерактивных средств требует, чтобы работа производилась на языке высокого уровня, поскольку телетайп и пишущую машинку нельзя использовать для получения дампа памяти. С использованием языка высокого уровня легко редактировать исходный текст и делать отдельные распечатки. Вместе они действительно составляют пару отточенных инструментов.
Глава 13 Целое и части
Я духов вызывать могу из бездны. И я могу, и каждый может, Вопрос лишь, явятся ль на зов они?
ШЕКСПИР, КОРОЛЬ ГЕНРИХ IV
Среди современных кудесников, как и встарь, встречаются хвастуны: «Я могу писать программы, которые управляют воздушным движением, перехватывают баллистические ракеты, делают переводы по банковским счетам, управляют производственными линиями». На что есть ответ: «И я могу, и каждый может, но будет ли работать то, что ты напишешь?»
Как написать программу, которая будет работать? Как протестировать программу? И как объединить набор протестированных программ-компонентов в протестированную и надежную систему? Несколько раз мы уже касались соответствующих приемов, давайте теперь рассмотрим их более систематически.
Проектирование без ошибок
Защита определений от ошибок. Самые пагубные и неуловимые системные ошибки возникают из-за несоответствия допущений, сделанных авторами различных компонентов. Подход к концептуальной целостности, изложенных выше в главах 4, 5 и 6, непосредственно обращается к этим проблемам. Кратко говоря, концептуальная целостность продукта не только упрощает его использование, но также облегчает разработку и делает менее подверженным ошибкам.
Такую же роль выполняет детализированная трудоемкая работа по разработке архитектуры, подразумеваемая этим подходом. В. А. Высоцкий из проекта Safeguard, выполнявшегося в Bell Telephone Laboratories, говорит так: «Решающая задача — дать определение для продукта. Очень многие неудачи связаны именно с теми аспектами, которые не были вполне специфицированы». [1] Тщательное определение функций, тщательная спецификация и старательное избегание всех украшательств функций и полетов технической мысли — все это снижает количество системных ошибок, которые будут обнаружены.
Проверка спецификации. Задолго до написания всякого кода спецификация должна быть передана сторонней группе тестирования для тщательного рассмотрения полноты и ясности. Как считает Высоцкий, сами разработчики сделать это не могут: «Они не могут признаться, что не понимают ее, они будут счастливо прокладывать свой путь через пропущенные и темные места».
Нисходящее проектирование. В очень четкой статье 1971 года Никлаус Вирт формализовал процедуру разработки, годами использовавшуюся лучшими программистами. [2] Более того, его замечания, сделанные в отношении разработки программ, полностью применимы к разработке сложных программных систем. Воплощением этих замечаний является разделение создания систем на проектирование архитектуры, разработку и реализацию. Более того, каждая из задач проектирования архитектуры, разработки и реализации лучше всего может быть решена нисходящими методами.
Вкратце, метод Вирта определяет разработку как последовательность уточняющих шагов. Набрасывается примерное описание задачи и грубый метод решения, позволяющий получить основной результат. Затем определение изучается более пристально, чтобы увидеть, в чем отличие полученного результата от требуемого, и крупные этапы решения разбиваются на более мелкие. Каждое уточнение в определении задачи становится уточнением алгоритма решения и может сопровождаться уточнением представления данных.
В этом процессе выявляются модули решения или данных, дальнейшее уточнение которых может быть продолжено независимо от основной работы. Степень такой модульности определяет гибкость и изменяемость программы.
Вирт считает необходимым использование на каждом шаге нотации как можно более высокого уровня, чтобы выделить понятия и скрыть детали, пока не станет необходимым дальнейшее уточнение.
Правильно осуществляемое нисходящее проектирование позволяет избегать ошибок по нескольким причинам. Во-первых, прозрачность структуры и представления облегчает точную формулировку требований к модулям и их функций. Во-вторых, расчленение и независимость модулей помогают избежать системных ошибок. В-третьих, проект можно тестировать на каждом уточняющем шаге, поэтому тестирование моно начать раньше и на каждом шаге сосредоточиться на подходящем уровне детализации.
Процесс пошагового уточнения не означает, что в случае столкновения с какой-нибудь неожиданно затруднительной деталью не приходится возвращаться назад, отбрасывать самый верхний уровень и начинать все сначала. На практике это часто случается. Но становится значительно легче точно увидеть, когда и почему нужно отбросить весь проект и начать сначала. Многие слабые системы появляются в результате попыток сохранить скверный первоначальный проект путем разного рода косметических заплаток. Нисходящее проектирование уменьшает такой соблазн.
Я убежден, что нисходящее проектирование является важнейшей новой формализацией программирования за десятилетие.
Структурное программирование. Другой важный круг идей для разработки, сокращающих число ошибок в программе, исходит то Дейкстры (Dijkstra) [3] и построен на теоретической структуре Бёма (Boehm) и Джакопини (Jacopini). [4]
В своей основе подход заключается в разработке программ, управляющие структуры которых состоят только из циклов, определяемых такими операторами, как DO WHILE и группами условно выполняемых операторов, ограниченных скобками с использованием операторов условия IF…THEN…ELSE. Бём и Джакопини показывают теоретическую достаточность таких структур. Дейкстра доказывает, что альтернативное неограниченное применение ветвление с помощью GO TO образует структуры, располагающие к появлению логических ошибок.
В основе, несомненно, лежат здравые мысли. При обсуждении сделано много критических замечаний — в частности, большое удобство представляют дополнительные управляющие структуры, такие как n-вариантный переход (так называемый оператор CASE) для различения среди нескольких случаев и аварийный выход (GO TO ABNORMAL END). Кроме того, некоторые догматически избегают всех GO TO , что представляется чрезмерным.
Важной и существенной для создания программ, не содержащих ошибок, является необходимость рассматривать управляющие структуры системы как управляющие структуры, а не как отдельные операторы перехода. Такой образ мысли является большим шагом вперед.
Отладка компонентов
За последние двадцать лет процедуры отладки программ прошли большой круг и в некоторых отношениях вернулись к начальной точке. Цикл прошел четыре этапа и любопытно проследить их, отметив мотивацию перехода.
Отладка в активном режиме. У первых машин было сравнительно слабое оборудование ввода-вывода, обусловливавшее большие задержки. Обычно машина использовала для чтения и записи бумажные и магнитные ленты, а для подготовки лент и печати использовались автономные средства. Из-за этого ввод-вывод на ленту был невыносимо неудобен для отладки, и для нее использовалась консоль. Поэтому отладка организовывалась таким образом, чтобы обеспечить за сеанс работы с машиной возможно большее число проверок.
Программист тщательно разрабатывал свои процедуры отладки, планируя места остановки, адреса памяти для просмотра, их возможное содержимое и дальнейшие действия в зависимости от содержимого. Это дотошное программирование самого себя в качестве отладчика вполне могло занять половину времени написания отлаживаемой программы.
Главным грехом было смело нажать кнопку START, не разбив предварительно программу на отлаживаемые секции с запланированными остановками.
Дампы памяти. Отладка в активном режиме была очень эффективной. За двухчасовую отладку можно было запустить программу раз десять. Но компьютеры были малочисленны и очень дороги, и мысль о такой напрасной трате машинного времени ужасала.
Поэтому, когда появились скоростные принтеры, подключаемые в активном режиме, технология изменилась. Программа запускалась и работала до возникновения ошибки, после чего распечатывался дамп памяти. Тогда начинался кропотливый труд за столом по изучению содержимого каждого адреса. Времени уходило примерно столько же, сколько и при отладке на машине, но это было уже после контрольного прогона, и работа состояла в расшифровке данных, а не в планировании, как прежде. Для каждого отдельного пользователя отладка занимала значительно больший срок, поскольку тестовые запуски зависели от оборачиваемости пакетной обработки. Однако процедура в целом была предназначена для сокращения времени использования компьютера и обслуживания возможно большего числа программистов.
Снимки моментального состояния. Машины, для которых были разработаны дампы памяти, имели память размером 2000-4000 слов, или 8-16 Кбайт. Однако размер памяти рос огромными темпами, и делать дамп памяти стало нереальным. Поэтому разработали методы выборочного дампа, выборочной трассировки и вставки в программы команд для моментальных снимков. Вершиной развития этого направления стал TESTRAN в OS/360, позволявший вставлять в программу моментальные снимки без повторной сборки и компиляции.
Интерактивная отладка. В 1959 году Кодд (Codd) с коллегами [5] и Стрейчи (Strachey) [6] сообщили о работе, целью которой была отладка в режиме разделения времени, позволяющая одновременно достичь мгновенной оборачиваемости отладки в активном режиме и эффективно использовать машинное время, как при пакетной обработке заданий. Компьютер должен был иметь в памяти несколько программ, готовых к запуску. Терминал, управляемый только программой, должен был быть связан с каждой из отлаживаемых программ. Отладка должна была проходить под управлением программы-супервизора. Когда программист за терминалом останавливал свою программу, чтобы изучить ее выполнение или внести изменения, супервизор запускал другую программу, занимая таким образом машину.
Мультипрограммная система Кодда была разработана, но акцент был сделан на увеличение производительности благодаря эффективному использованию ввода-вывода, и интерактивная отладка не была осуществлена. Идеи Стрейчи были улучшены и в 1963 году воплощены Корбато с коллегами в МТИ в экспериментальной системе 7090. Это разработке привела к MULTICS, TSS и другим сегодняшним системам разделения времени.
Главными ощущаемыми пользователем различиями между отладкой в активном режиме, как она осуществлялась ранее, и сегодняшней интерактивной отладкой являются возможности, полученные в результате присутствия программы-супервизора и связанных с ней интерпретаторов языков программирования. Можно программировать и производить отладку на языках высокого уровня. Эффективные средства редактирования позволяют легко делать изменения и моментальные снимки.
Возврат к мгновенной оборачиваемости отладки в активном режиме пока не привел к возвращению предварительного планирования отладочных сеансов. В сущности, такое предварительное планирование не столь необходимо, как раньше, поскольку машинное время теперь не тратится впустую, пока человек сидит и думает.
Тем не менее интересные экспериментальные данные Голда (Gold) показывают, что во время первого диалога каждого сеанса достигается втрое больший прогресс в интерактивной отладке, чем при последующих диалогах. [8] Это убедительно говорит о том, что из-за отсутствия планирования мы не полностью реализуем потенциал диалоговой работы. Пора стряхнуть пыль со старых методов работы в интерактивном режиме.
Я считаю, что для правильного использования хорошей терминальной системы на каждые два часа работы за терминалом должно приходиться два часа работы за столом. Половина этого времени уходит на подчистки после первого сеанса: внесение изменений в журнал отладки, подшивку новых листингов в системный журнал, объяснение непонятных явлений. Вторая часть уходит на подготовку: планирование изменений и усовершенствований и разработку детальных тестов для очередного сеанса. Без такого планирования трудно поддерживать продуктивность на протяжении всех двух часов. Без подчистки после сеанса трудно сделать последовательность сеансов систематичной и продвигающей работу вперед.
Контрольные примеры. Что касается разработки фактических процедур отладки и контрольных примеров, особенно удачное изложение предлагает Грюнбергер (Gruenberger), [9] есть и более короткие описания в других известных учебниках. 10, [11]
Системная отладка
Неожиданно трудным этапом создания системы программирования оказывается тестирование системы. Я уже обсуждал некоторые причины как его трудности, так и непредсказуемости. Можно не сомневаться в двух вещах: системная отладка займет больше времени, чем предполагается, а ее сложность оправдывает досконально систематичный и плановый подход. Рассмотрим, что включает в себя такой подход. [12]
Используйте отлаженные компоненты. Обычный здравый смысл, если не обычная практика, подсказывают, что системную отладку нужно начинать, когда работает каждая составляющая часть.
Далее общепринятая практика следует двумя путями. Первый подход — «свинти и попробуй». Видимо, он основывается на том, что кроме ошибок в компонентах найдутся и ошибки в системе (т.е. в интерфейсах). Чем скорее части будут соединены вместе, тем скорее всплывут системные ошибки. Легко также представить, что, используя компоненты для тестирования друг друга, можно в значительной мере избежать создания окружения для тестирования. И то, и другое, очевидно, является правдой, но, как показывает опыт, не всей правдой: значительно больше времени сберегается при тестировании системы с использованием чистых отлаженных компонентов, чем его тратится на создание окружения и доскональной проверки компонентов.
Несколько более тонким является подход «документированной ошибки». Он означает, что компонент готов к использованию в системной проверке, когда все его ошибки найдены, но необязательно уже исправлены. Тогда, теоретически, при системном тестировании возможные эффекты этих ошибок известны и могут быть проигнорированы, а сосредоточиться можно на новых явлениях.
Все это означает принимать желаемое за действительное и происходит от стремления объяснить провал графика работ. Никто не знает всех возможных последствий известных ошибок. Если бы все было просто, системное тестирование не вызывало бы затруднений. Кроме того, исправление документированных ошибок, несомненно, приведет к внесению новых ошибок, и системный тест окажется испорченным.
Создайте больше окружений. Под «окружением» я понимаю все программы и данные, созданные для целей отладки, но не предназначенные для использования в конечном продукте. В окружении нет смысла иметь и половины того кода, который входит в продукт.
Один из видов окружения — фиктивный компонент, который может состоять только из интерфейсов и, возможно, каких-нибудь искусственных данных или небольших контрольных примеров. Например, в систему может входить программа сортировки, которая еще не закончена. Связанные с ней компоненты можно тестировать с помощью фиктивной программы, которая просто читает и проверяет формат входных данных и возвращает набор правильно отформатированных бессмысленных, но упорядоченных данных.
Другой вид — мини-файл. Распространенным видом системной ошибки является неправильное восприятие форматов ленточных и дисковых файлов. Поэтому стоит создать несколько маленьких файлов, содержащих лишь несколько типовых записей и все описания, указатели и т.п.
Предельный случай мини-файла — фиктивный файл, который фактически не существует. Язык управляющих заданий OS/360 имеет такое средство, и оно очень полезно для отладки компонентов.
Другой вид окружения — вспомогательные программы. Генераторы данных для тестирования, печать специального анализа, анализаторы таблиц перекрестных ссылок — все это примеры специальных приспособлений, которые может потребоваться создать. [13]
Контролируйте изменения. Жесткий контроль во время тестирования является впечатляющим методом отладки аппаратуры, с успехом применимым к системам программирования.
Прежде всего, кто-то должен быть ответственным. Он, и только он должен разрешать изменения в компонентах и замену одной версии другой.
Далее, как обсуждалось выше, система должна иметь контролируемые экземпляры: один экземпляр с последними версиями, находящийся под замком и используемый для тестирования компонентов; один тестируемый экземпляр с установленными исправлениями; рабочие экземпляры каждого сотрудника для внесения исправлений и дополнений в свои компоненты.
В технических моделях System/360 среди обычных желтых проводов можно было иногда видеть фиолетовые провода. При обнаружении дефекта делались две вещи. Быстро придумывалось исправление и устанавливалось в системе, чтобы продолжить отладку. Это изменение делалось фиолетовыми проводами, так что оно торчало как бельмо на глазу. Изменение регистрировалось в журнале. Тем временем готовился официальный документ о внесении исправлений, который запускался в жернова автоматизированного проектирования. В итоге это выливалось в измененные чертежи и списки проводов и новую заднюю панель, в которой изменения были сделаны на печатной плате или желтыми проводами. Теперь физическая модель и документация соответствовали друг другу, и фиолетовый провод исчезал.
Программированию тоже требуется технология фиолетовых проводов, и очень требуется жесткий контроль и глубокое уважение к документу, который в конечном счете, окажется продуктом. Неотъемлемыми составляющими такой технологии являются регистрация всех изменений в журнале и заметное отличие в исходном коде между заплатками на скорую руку и продуманными и документированными исправлениями.
Добавляйте компоненты по одному. Этот рецепт также очевиден, но им часто пренебрегают из-за оптимизма и лени. Чтобы следовать ему, требуются фиктивные программы и разное окружение, а это отнимает время. И в конце концов, вся эта работа может оказаться лишней! Может быть, ошибок и нет!
Нет! Противьтесь соблазну! Это то, в чем заключается систематичное тестирование системы. Нужно предполагать, что ошибок будет много, и планировать упорядоченную процедуру избавления от них.
Учтите, что нужно иметь полный набор контрольных примеров для проверки частично собранных систем после добавления каждого компонента. Прежние примеры, успешно выполненные на последней частичной сборке, нужно перезапустить на новой, чтобы проверить, не ухудшилась ли система.
Квантуйте изменения. По мере созревания системы время от времени начинают появляться разработчики компонентов, принося свежие версии своих изделий — более быстрые, меньшие по размеру, более полные или предположительно содержащие меньше ошибок. Замена работающего компонента новой версией требует такой же систематической процедуры тестирования, как и добавление нового компонента, хотя и требует меньше времени, поскольку обычно уже имеются более полные и эффективные контрольные примеры.
Каждая команда, создающая новый компонент, использует новейшую версию интегрированной системы в качестве среды для отладки своего компонента. Проделанная работа будет отброшена назад, если эта среда изменится. Конечно, она должна измениться. Но внесение изменений нужно производить квантами. Тогда у каждого пользователя будут промежутки продуктивной стабильности, прерываемые пакетным обновлением среды тестирования. Это оказывается значительно менее разрушительным, чем постоянные волнения и дрожь.
Леман и Белади дают свидетельства в пользу того, что квант изменений должен быть либо очень большим и редким, либо очень маленьким и частым. [14] Последняя стратегия, согласно их модели, больше подвержена неустойчивости. Мой опыт это подтверждает: я никогда не рискну использовать ее на практике.
Квантовые изменения хорошо вписываются в технологию фиолетовых проводов. Быстрая заплатка держится до следующей регулярной версии компонента, которая должна содержать исправление в отлаженном и документированном виде.
Глава 14 Назревание катастрофы
Никто не любит приносящего дурные вести.
СОФОКЛ
Как оказывается, что проект запаздывает на год? … Сначала запаздывает на один день.
Когда слышишь о катастрофическом отставании проекта от графика, то представляется ряд обрушившихся на него больших бедствий. Однако обычно причиной катастрофы служат не смерчи, а термиты: отставание от графика происходит незаметно, но неумолимо. На самом деле, с крупными бедствиями справиться легче: используются крупные силы, коренная реорганизация, изобретаются новые подходы. Вся команда поднимается на борьбу.
Отставание, растущее понемногу изо дня в день, труднее распознать, труднее предотвратить, труднее исправить. Вчера не удалось провести совещание из-за болезни ключевого работника. Сегодня выключены все машины, потому что молния ударила в силовой трансформатор. Завтра не удастся начать тестирование процедур работы с дисками, поскольку поставка с завода первого диска задерживается на неделю. Снегопад, работа в суде присяжных, семейные проблемы, экстренные встречи с клиентами, проверки руководством — список бесконечен. Каждое событие задерживает какую-нибудь работу на полдня или день. И растет отставание от графика, каждый раз еще на один день.
Вехи или помехи?
Как управлять большим проектом по жесткому графику? Прежде всего, надо иметь график. У каждого из событий, называемых вехами, должна быть дата. Выбор дат — уже обсуждавшаяся задача оценки, и он решающим образом зависит от опыта.
Для выбора всех вех есть только одно пригодное правило. Вехами должны служить конкретные особые события, которые можно идентифицировать с полной определенностью. В качестве отрицательных примеров отметим, что написание программы «закончено на 90 процентов» в течение половины всего времени кодирования. Отладка «закончена на 99 процентов» почти всегда. «Планирование завершено» — событие, которое можно объявить почти произвольно. [1]
Напротив, вехи должны быть 100-процентными событиями. «Спецификации подписаны архитекторами и разработчиками», «исходный код готов на 100 процентов, отперфорирован и загружен в библиотеку на диске», «отлаженная версия прошла все контрольные примеры». Такие конкретные вехи разграничивают расплывчатые этапы планирования, кодирования и отладки.
Наличие четко очерченных границ и недвусмысленность важнее, чем возможность легкой проверки начальником. Едва ли человек станет лгать о прохождении вехи, если она очерчена столь ясно, что от не может себя обманывать. А вот если веха расплывчата, начальник часто воспринимает доклад иначе, чем тот, кто ему докладывает. Дополняя Софокла, скажем, что никто не любит и сам приносить дурные вести, поэтому они смягчаются без злого намерения ввести в заблуждение.
Два интересных исследования поведения правительственных подрядчиков по проведению оценок в крупномасштабных исследовательских проектах показали:
1. Оценки продолжительности работы, тщательно проведенные и пересматриваемые каждые две недели перед началом работы, не сильно меняются по мере приближения начала работы, какими бы неверными они ни оказались в конечном итоге.
2. После начала работы завышенные изначально оценки постоянно уменьшаются по мере продвижения.
3. Заниженные оценки существенно не меняются, пока до запланированного срока окончания работ не остается около трех недель.
Четко различимые вехи в действительности создают удобство команде, которая должна рассчитывать, что менеджер их хорошо определит. С неясно видимой вехой жизнь становится труднее. Это уже не веха, а мельничный камень, перетирающий боевой дух, поскольку она вводит в заблуждение относительно потерь времени, пока они не станут непоправимыми. А хроническое отставание от графика угнетающе действует на моральное состояние.
”Другая часть тоже опаздывает”
Отставание от графика на один день — ну и что? Кого волнует отставание на один день? Позже нагоним. Другая часть, в которую входит наша, тоже отстает на один день.
Менеджер бейсбола считает энергию важным талантом, как для выдающихся игроков, так и для выдающихся команд. Это способность бегать быстрее, чем необходимо, передвигаться скорее, чем необходимо, стараться сильнее, чем необходимо. Энергия важна и для выдающихся команд программистов. Она обеспечивает упругость, резервную мощность, позволяющие команде справиться с повседневными неприятностями, предвосхищать мелкие беды и уберегаться от них. Рассчитанная реакция, размеренные усилия охлаждают энергию. Как мы видели, нужно приходить в возбуждение из-за отставания на один день, ибо они являются составляющими катастрофы.
Но не все отставания на один день одинаково катастрофичны. Поэтому необходимо рассчитывать реакцию, хотя это и ослабляет энергию. Как отличить отставания, которые существенны? Ничем нельзя заменить диаграммы ПЕРТ или метод критического пути. Такая сеть показывает, кто находится в ожидании каких событий. Она показывает, кто находится на критическом пути, на котором любое отставание влечет перенос даты окончания. Она также показывает, какое предельное отставание возможно для некоторой работы, прежде чем оно приведет на критический путь.
Технология ПЕРТ, строго говоря, есть разработка графика работ с критическим путями, когда для каждого события производятся три оценки, соответствующие разным вероятностям уложиться в установленные сроки. Я не думаю, что такое уточнение стоит затрачиваемых усилий, но для краткости всякую сеть с критическим путями буду называть диаграммой ПЕРТ.
Подготовка диаграмм ПЕРТ есть самая ценная часть ее применения. Определение топологии сети, указание зависимостей в ней и оценивание путей заставляют выполнить большой объем очень конкретного планирования на самых ранних стадиях проекта. Первая диаграмма всегда ужасна, и для создания второй приходится проявить много изобретательности.
Во время выполнения проекта диаграмма ПЕРТ дает ответ на деморализующие извинения типа «другая часть тоже запаздывает». Она показывает, когда необходимо развить энергию, чтобы увести свою часть работы с критического пути, и подсказывает способы наверстать потерянное время в других частях.
Под ковром
Когда менеджер низового звена видит, что его маленькая команда отстает, он не склонен бежать к начальнику со своим горем. Возможно, команда сумеет наверстать время, либо он сможет что-нибудь придумать или реорганизовать для решения проблемы. Зачем же беспокоить этим начальника? До поры до времени это допустимо. Для того и существуют менеджеры низового звена, чтобы решать такие проблемы. А у начальника достаточно других забот, требующих его вмешательства, чтобы искать новые. Так вся эта грязь заметается под ковер.
Но каждому начальнику нужны два вида данных: информация о срывах плана, которая требует вмешательства, и картина состояния дел, чтобы быть в курсе. [3] С этой целью он должен знать положение дел во всех своих командах. Получить правдивую картину нелегко.
В этом месте интересы менеджера низового звена и начальника вступают в противоречие. Менеджер низового звена боится, что если он доложит начальнику о возникшей у него проблеме, тот возьмется за нее сам. Его вмешательство отнимет у менеджера его функции, уменьшит его власть и нарушит другие его планы. Поэтому, пока менеджер считает, что может сам решить проблему, он не докладывает о ней начальнику.
У начальника есть два способа заглянуть под коврик. Использовать нужно оба. Первый — уменьшить конфликт ролей и стимулировать открытие информации. Второй — сдернуть коврик.
Уменьшение конфликта ролей. В первую очередь начальник должен провести различие между данными и действиях и данными о состоянии дел. Он должен приучить себя не вмешиваться в проблемы, которые могут решить его менеджеры, и никогда не вмешиваться в проблемы непосредственно во время изучения состояния дел. Я знал одного начальника, который неизменно снимал трубку и начинал давать указания, не дочитав до конца первый абзац отчета о состоянии дел. При таких действиях вам обеспечено утаивание полных данных.
Напротив, если менеджер знает, что его начальник воспримет отчет без паники или вмешательства, он будет давать честные оценки.
Весь этот процесс идет успешно, если начальник подчеркивает, что совещания, заслушивания и конференции носят характер изучения состояния дел, а не принятия мер по проблемам, и ведет себя соответствующим образом. Очевидно, можно созвать совещание по принятию мер по результатам заслушивания о состоянии дел, если возникает ощущение, что проблема вышла из-под контроля. Но тогда по крайней мере все знают, что происходит, и начальник дважды подумает, прежде чем взять управление на себя.
Сдергивание коврика. Тем не менее необходимо иметь способ узнать истинное положение дел независимо от наличия стремления к сотрудничеству. Основой такого изучения служит диаграмма ПЕРТ с часто расположенными вехами. В большом проекте можно потребовать еженедельного изучения какой-либо части ее, рассматривая всю диаграмму раз в месяц или около того.
Главным документом является отчет с указанием вех и степени их фактического выполнения. (На рисунке 14.1 показан фрагмент такого отчета.) Он может показывать отставание по некоторым позициям и служить в качестве повестки дня совещания. Всем известны выносимые на него вопросы, и соответствующие менеджеры готовы доложить о причинах отставания, предполагаемых сроках завершения, принимаемых мерах, а также требуется ли помощь от начальника или других групп, и если да, то какая.
В. Высоцкий из Bell Telephone Laboratories добавляет следующее наблюдение:
Для меня оказалось удобным иметь в отчете о состоянии дел две даты — «плановую» и «оцениваемую». Плановые даты принадлежат менеджеру проекта и представляют собой последовательный план работы для проекта в целом, a priori являющийся приемлемым. Оцениваемые даты принадлежат менеджерам низшего звена, в переделах компетенции которых находятся рассматриваемые участки, и представляют их мнения о сроке фактического наступления события при имеющихся у них ресурсах и получении входных данных (или обязательствах об их поставке). Менеджер проекта должен осторожно относиться к оцениваемым датам и стремиться к получению точных, неискаженных оценок, а не утешительно-оптимистичных или перестраховочно-консервативных данных. Если эта позиция утвердится в умах, то менеджер проекта действительно сможет предвидеть, что он попадет в беду, если не предпримет каких-нибудь мер. [4]
Создание диаграммы ПЕРТ является обязанностью начальника и подотчетных ему менеджеров. Внесение в нее изменений, пересмотр и подготовка отчетности должны осуществляться небольшой (от одного до трех человек) группой, как бы продолжающей начальника. Такая группа планирования и контроля неоценима при работе над большим проектом. Она не обладает иными полномочиями, кроме как требовать от менеджеров низового звена предоставления сведений об установке или изменении вех и их достижении. Поскольку группа планирования и контроля осуществляет всю бумажную часть работы, нагрузка на менеджеров низового звена ограничивается самым важным — принятием решений.
У нас была умелая, энергичная и дипломатичная группа планирования и контроля, возглавлявшаяся А. М. Пьетрасанта (A. M. Pietrasanta), проявившим значительные изобретательные способности для разработки эффективных, но ненавязчивых методов контроля. В результате его группа пользовалась широким уважением и хорошим отношением. Это немалое достижение для группы, которая по природе своей должна вызывать раздражение.
Выделение небольшого числа подготовленных работников в группу планирования и контроля приносит большую отдачу. Для успешного завершения проекта это значительно лучше, чем если бы они непосредственно занимались разработкой программных продуктов, так как группа планирования и контроля стоит на страже того, чтобы неощутимые задержки стали видимыми, и сигнализирует о критических положениях. Это система раннего обнаружения потери года, происходящей день за днем.
Глава 15 Обратная сторона
Чего мы не понимаем, тем не владеем.
ГЕТЕ
О, дайте мне выступить комментатором, Скользящим по поверхности и будоражащим умы.
КРАББ
Компьютерная программа — это послание человека машине. Строго выстроенный синтаксис и тщательные определения нацелены на то, чтобы бездумной машине стали понятны намерения человека.
Но у написанной программы есть обратная сторона: она должна быть в состоянии рассказать о себе пользователю-человеку. Это требуется даже для программы, написанной исключительно для собственных нужд, поскольку память может изменить автору-пользователю, и ему потребуется освежить детали своего труда.
Насколько же более необходима документация для программы общего пользования, пользователь которой отдален от автора во времени, и в пространстве! Для программного продукта сторона, обращенная к пользователю, столь же важна, как и сторона, обращенная к машине.
Многие из нас бранили далекого безымянного автора за скудно документированную программу. И многие поэтому пытались на всю жизнь привить молодым программистам уважение к документации, преодолевающее лень и пресс графика работ. В целом нам это не удалось. Я думаю, мы использовали неверные методы.
Томас Дж. Уотсон Старший (Thomas J. Watson, Sr.) рассказал мне историю своего первого опыта в качестве продавца кассовых аппаратов в северной части штата Нью-Йорк. Исполненный энтузиазма, он отправился в путь в своем фургоне, нагруженном кассовыми аппаратами. Он прилежно объехал свой участок, но ничего не продал. Обескураженный, он сообщил об этом своему хозяину. Послушав некоторое время, управляющий сказал: «Помоги мне загрузить несколько касс в фургон, запрягай лошадь, и поедем снова.» Так они и сделали, и обходя покупателей одного за другим, старик показывал, как продавать кассовые аппараты. Судя по всему, урок пошел впрок.
Несколько лет я старательно читал группам инженеров-программистов лекции о необходимости и желательности хорошей документации, увещевая их все с большим пылом и красноречием. Это не подействовало. Я предположил, что они поняли, как правильно составлять документацию, но не делали этого по недостатку рвения. Тогда я попробовал погрузить в повозку несколько кассовых аппаратов, т.е. показать им, как делается эта работа. Это имело значительно больший успех. Поэтому оставшаяся часть этого повествования посвящена не столько поучениям, сколько объяснению того, как делать хорошую документацию.
Какая документация требуется?
Необходимы различные уровни документации: для пользователя, обращающегося к программе от случая к случаю, для пользователя, который существенно зависит от программы в своей работе, и для пользователя, который должен адаптировать программу к изменившемуся окружению или задачам.
Чтобы использовать программу. Каждому пользователю требуется словесное описание программы. По большей части документация страдает отсутствие общего обзора. Описаны деревья, прокомментированы кора и листья, но план леса
* Томас Дж. Уотсон Старший — основатель компании IBM (примеч. перев.)
отсутствует. Чтобы написать полезное текстовое описание, взгляните издалека, а затем медленно приближайтесь:
1. Назначение. Что является главной функцией программы и причиной ее написания?
2. Среда. На каких машинах, аппаратных конфигурациях и конфигурациях операционной системы будет она работать?
3. Область определения и область значений. Каковы допустимые значения входных данных? Какие правильные значения выходных результатов могут появиться?
4. Реализованные функции и использованные алгоритмы. Что конкретно может делать программа?
5. Форматы ввода-вывода, точные и полные.
6. Инструкция по работе, в том числе описание вывода на консоль и устройство вывода при нормальном и аварийном завершении.
7. Опции. Какой выбор предоставляется пользователю в отношении функций? Каким образом нужно его задавать?
8. Время работы. Сколько времени занимает решение задачи заданного размера на заданной конфигурации?
9. Точность и проверка. Какова ожидаемая точность результатов? Какие имеются средства проверки точности?
Часто все эти данные можно изложить на трех или четырех страницах. При этом нужно уделить особое внимание полноте и точности. Большую часть этого документа нужно вчерне написать до разработки программы, поскольку в нем воплощены основные плановые решения.
Чтобы доверять программе. Описание того, как использовать программу, нужно дополнить описанием того, как убедиться в ее работоспособности. Это означает наличие контрольных примеров.
Каждый экземпляр поставляемой программы должен содержать несколько небольших контрольных примеров, которые можно постоянно использовать, чтобы уверить пользователя в том, что он может доверять программе, и она правильно загружена в машину.
Кроме того, нужны более тщательные тесты, которые обычно выполняются только после модификации программы. Они относятся к трем участкам области входных данных:
1. Основные параметры, проверяющие главные функции программы на обычно встречаемых данных.
2. Примеры на грани допустимого, проверяющие границы области входных данных и убеждающие, что работают наибольшие значения, наименьшие значения и все допустимые исключения.
3. Примеры за границей допустимого, проверяющие границы с обратной стороны и убеждающие, что недопустимые значения вызывают правильные диагностические сообщения.
Чтобы модифицировать программу. Для адаптации или исправления программы требуется значительно больше данных. Разумеется, требуются все детали, а они содержатся в хорошо прокомментированном листинге. У пользователя, модифицирующего программу или редко ее использующего, возникает острая необходимость в ясном отчетливом обзоре, на этот раз внутренней структуры. В такой обзор входят:
1. Блок-схема или граф подпрограммной организации. Подробнее об этом см. ниже.
2. Полные описания используемых алгоритмов или ссылки на такие описания в литературе.
3. Разъяснение структуры всех используемых файлов.
4. Обзор организации прохождения данных — последовательности, в которой данные или программы загружаются с ленты или диска и описание того, что делается на каждом ходе.
5. Обсуждение модификаций, предполагаемых исходным проектом, сущность и расположение добавочных блоков и выходов и дискурсивное обсуждение мыслей автора программы относительно изменений, которые могут оказаться желательными, и как их можно провести. Полезно также изложить его замечания о скрытых ловушках.
Бич блок-схем
Блок-схема чаще всего является лишней частью программной документации. Для многих программ блок-схемы вообще не нужны. Редкие программы требуют блок-схемы более чем на одну страничку.
Блок-схемы показывают структуру принятия программой решений, что является лишь одной стороной структуры программы. Когда блок-схема размещается на одной странице, структура решений выглядит довольно элегантно, но наглядность сразу утрачивается, когда есть несколько страниц, связанных пронумерованными входами и выходами.
Одностраничная блок-схема для значительной по размеру программы становится, в сущности, диаграммой структуры программы и этапов или шагов. В этом качестве она очень удобна. Рисунок 15.1 показывает такой граф подпрограммной структуры.
Рис. 15.1 Граф структуры программы (пример W. V. Wright)
Конечно, такой структурный граф не требует особых усилий по соблюдению стандартов ANSI для блок-схем. Все эти правила относительно вида прямоугольников, соединительных линий, нумерации и т.п. нужны только для понимания подробных блок-схем.
Подробная пошаговая блок-схема является досадным анахронизмом, пригодным только для новичков в алгоритмическом мышлении. Введенные Голдштайном и фон Нейманом [1] прямоугольники вместе со своим содержимым служили языком высокого уровня, объединяя непостижимые операторы машинного языка в осмысленные
группы. Как давно понял Иверсон, [2] в систематическом языке высокого уровня группировка уже проведена, и каждый прямоугольник содержит оператор (рис. 15.2). Поэтому сами прямоугольники являются утомительным и отнимающим место упражнением в черчении и вполне могут быть удалены. Тогда остаются только стрелки. Стрелки, связывающие один оператор с другим, расположенным в следующей строке, излишни, и их можно удалить. Тогда остаются только GO TO, и если придерживаться хорошей практики программирования и использовать блочные структуры для минимизации числа GO TO, таких стрелок окажется немного, но они очень способствуют пониманию. Вполне можно нарисовать их на листинге и вовсе избавиться от блок-схемы.
В действительности о блок-схемах больше говорят, чем пользуются ими. Я никогда не видел опытного программиста, который в повседневной деятельности рисовал бы подробные блок-схемы, прежде чем начать писать программу. Там, где блок-схемы требуются правилами организации, они почти всегда создаются задним числом. Многие гордятся использованием специальных программ для генерации этого «незаменимого инструмента разработки» на основе уже законченной программы. Думаю, что этот всеобщий опыт не является постыдным и предосудительным отходом от хорошей практики программирования, признаваться в котором можно лишь с нервным смешком. Напротив, это результат здравого рассуждения, дающий нам урок относительно полезности блок-схем.
Апостол Петр сказал о новообращенных язычниках и законе Моисея: «Что же вы желаете возложить на выи учеников иго, которого не могли понести ни отцы наши, ни мы?» (Деяния апостолов 15:10). То же сказал бы я о программистах-новичках и устаревшей практике блок-схем.
Самодокументирующиеся программы
Один из основных принципов обработки данных учит, что безрассудно стараться поддерживать синхронность независимых файлов. Значительно лучше собрать их в один файл, в котором каждая запись содержит все данные их обоих файлов, относящиеся к данному ключу.
Тем не менее наша практика документирования программ противоречит собственным теориям. Обычно мы пытаемся поддерживать программу в виде, пригодном для ввода в машину, а независимый комплект документации, состоящей из текста и блок-схем, — в виде, пригодном для чтения человеком.
Результаты этого подтверждают мысль о неразумности поддержки независимых файлов. Программная документация получается удивительно плохой, а ее сопровождение — и того хуже. Вносимые в программу изменения не получают быстрого, точного и обязательного отражения в документе.
Я полагаю, что правильным решением должно быть слияние файлов: включение документации в исходный текст программы. Это одновременно и сильный побудительный мотив к должному сопровождению, и гарантия того, что документация всегда будет под рукой у пользователя. Такие программы называют самодокументирующимися.
Очевидно, при этом неудобно, хотя и возможно, включать блок-схемы, если в этом есть необходимость. Но, приняв во внимание анахронизм блок-схем и использование преимущественно языков высокого уровня, становится возможным объединить программу с документацией.
Использование исходного кода программы в качестве носителя документации влечет некоторые ограничения. С другой стороны, непосредственный доступ читателя документации к каждой строке программы открывает возможность для новых технологий. Пришло время разработать радикально новые подходы и методы составления программной документации.
В качестве важнейшей цели мы должны попытаться предельно уменьшить груз документации — груз, с которым ни мы, ни наши предшественники толком не справились.
Подход. Первое предложение состоит в том, чтобы разделы программы, обязанные присутствовать в ней согласно требованиям языка программирования, содержали как можно больше документации. Соответственно, метки, операторы объявления и символические имена включают в задачу передать читателю как можно больше смысла.
Рис. 15.2 Сравнение блок-схемы и соответствующей программы на PL/I (фрагмент)
Второе предложение — в максимальной мере использовать пространство и формат, чтобы улучшить читаемость и показать отношения подчиненности и вложенности.
Третье предложение — включить в программу необходимую текстовую документацию в виде параграфов комментариев. В большинстве программ достаточно иметь построчные комментарии. В программах, отвечающих жестким стандартам организаций на «хорошее документирование», их часто слишком много. Однако даже в этих программах обычно недостаточно параграфов комментариев, которые действительно способствуют понятности и обозримости целого.
Поскольку документация встраивается в используемые программой структуру, имена и форматы, значительную часть этой работы необходимо проделать, когда программу только начинают писать. Но именно тогда и нужно писать документацию. Поскольку подход на основе самодокументирования сокращает дополнительную работу, меньше препятствий к его осуществлению.
Некоторые приемы. На рисунке 15.3 показана самодокументирующаяся программа на языке PL/I. [3] Числа в кружочках не являются ее частью, а служат метадокументацией для ссылок при обсуждении.
1. Используйте для каждого запуска свое имя задания и ведите журнал, в котором учитывайте предмет проверки, время и полученные результаты. Если имя состоит из мнемоники (здесь QLT) и числового суффикса (здесь 4), то суффикс можно использовать в качестве номера запуска, связывающего запись в журнале и листинг. При этом для разных прогонов требуются свои карты задания, но их можно делать колодами с дублированием постоянных данных.
2. Используйте мнемонические названия программы, включающие идентификатор версии — в предположении, что будет несколько версий. Здесь индекс — две младшие цифры года.
3. Включите текстовое описание в качестве комментариев к PROCEDURE.
4. Для документирования алгоритмов ссылайтесь, где можно, на литературу. Это экономит место, адресует к более полному освещению, чем можно дать в программе, и дает возможность знающему читателю пропустить ссылку, оставляя уверенность, что он вас поймет.
5. Покажите связь с алгоритмом, описанным в книге: а) изменения; б) особенности использования; в) представление данных.
6. Объявите все переменные. Используйте мнемонику. Используйте комментарии для превращения оператора DECLARE в полноценную легенду. Обратите внимание, что он уже содержит имена и описания структур, нужно лишь дополнить его описаниями назначения. Сделав это здесь, вы избежите отдельного повторения имен и структурных описаний.
7. Поставьте метку в начале инициализации.
8. Поставьте метки перед группами операторов, соответствующие операторам алгоритма, описанного в книге.
9. Используйте отступы для показа структуры и группирования.
10. Вручную поставьте стрелки, показывающие логический порядок операторов. Они очень полезны при отладке и внесении изменений. Их можно поместить на правом поле места для комментариев и сделать частью вводимого в машину текста.
11. Вставьте строчные комментарии для пояснения всего, что неочевидно. При использовании изложенных выше приемов они окажутся короче и малочисленней, чем обычно.
12. Помещайте несколько операторов на одной строке или один оператор на нескольких строках в соответствии с логической группировкой, а также чтобы показать связь с описанием алгоритма.
Возражения. Каковы недостатки такого подхода к документированию? Они существуют, и в прежние времена были существенными, но сейчас становятся мнимыми.
Рис. 15.3 Самодокументирующаяся программа
Самым серьезным возражением является увеличение размера исходного текста, который нужно хранить. Поскольку практика все более тяготеет к хранению исходного кода в активных устройствах, это вызывает растущее беспокойство. Лично я пишу более краткие комментарии в программах на APL, которые хранятся на диске, чем в программах на PL/I, которые хранятся на перфокартах.
Однако одновременно мы движемся к хранению в активных устройствах текстовых документов, доступ к которым и изменение осуществляется с помощью компьютеризированных текстовых редакторов. Как указывалось выше, слияние текста и программы сокращает общее количество хранимых символов.
Аналогичное возражение вызывает аргумент, что самодокументирующиеся программы требуют больше ввода с клавиатуры. В печатном документе требуется, по меньшей мере, одно нажатие на клавишу для каждого символа на каждый черновой экземпляр. В самодокументирующейся программе суммарное количество символов меньше, и на один символ приходится меньше нажатий на клавиши, так как черновики не перепечатываются.
А что же блок-схемы и структурные графы? Если используется только структурный граф самого высокого уровня, он вполне может содержаться в отдельном документе, поскольку редко подвергается изменениям. Но конечно, его можно включить в исходный текст программы в качестве комментария, что будет благоразумно.
В какой мере описанные выше приемы применимы для программ на языке ассемблера? Я думаю, что базовый подход документирования применим всюду. Свободным пространством и форматами можно пользоваться с меньшей степенью свободы, и поэтому они используются не так гибко. Имена и объявления структур, несомненно, можно использовать. Очень могут помочь макросы. Интенсивное использование параграфов комментарием является хорошей практикой в любом языке.
Но подход на основе самодокументирования стимулирован применением языков высокого уровня и обретает наибольшую мощь и наивысшее оправдание в языках высокого уровня, используемых в режиме он-лайн, будь то в пакетном режиме или интерактивно. Как я доказывал, такие языки и системы очень сильно облегчают жизнь программистов. Поскольку машины сделаны для людей, а не люди для машин, их использование оправдано как с экономической точки зрения, так и чисто по-человечески.
Глава 16 Серебряной пули нет — сущность и акциденция в программной инженерии
Нет ни одного открытия ни в технологии, ни в методах управления, одно только использование которого обещало бы в течение ближайшего десятилетия на порядок повысить производительность, надежность, простоту разработки программного обеспечения.
Резюме[1]
Создание программного обеспечения всегда включает в себя существенные задачи — моделирование сложных концептуальных структур, составляющих абстрактный программный объект, и второстепенные задачи — создание представлений этих абстрактных объектов с помощью языков программирования и отображение их в машинные языки с учетом ограничений по памяти и скорости. В прошлом рост продуктивности программирования по большей части достигался благодаря устранению искусственных преград, делавших второстепенные задачи чрезмерно трудными, например, жестких аппаратных ограничений, неудобных языков программирования, нехватки машинного времени. Какая часть работы разработчиков программного обеспечения все еще связана со второстепенными, а не с существенными обстоятельствами? Если она занимает менее 9/10 всех затрат, то, даже сведя все второстепенные затраты к нулю, мы не получим роста производительности на порядок величин.
Поэтому, похоже, настало время обратиться к существенным задачам программирования, связанным с моделированием концептуальных структур большой сложности. Я предлагаю:
• Использовать массовый рынок, чтобы избежать создания того, что можно купить.
• Использовать быстрое макетирование как часть запланированных итераций для установления технических требований к программному обеспечению.
• Органично наращивать программы, добавляя к системам все большую функциональность по мере их запуска, использования и тестирования.
• Выявлять и растить выдающихся разработчиков концепций нового поколения.
Введение
Из всех монстров, которыми наполнены кошмары нашего фольклора, самыми страшными являются оборотни, поскольку нас пугает неожиданное превращение того, что нам хорошо знакомо, в нечто ужасное. Мы ищем серебряные пули, которые могли бы волшебным образом уложить оборотней наповал.
Хорошо знакомый программный проект напоминает таких оборотней (по крайней мере, в представлении менеджеров, не являющихся техническими специалистами) тем, что, будучи простым и невинным на вид, он может стать чудищем проваленных графиков работы, раздувшихся бюджетов и неработающих продуктов.
И мы слышим отчаянные крики с просьбами дать серебряную пулю — нечто, способное снизить стоимость программных продуктов так же резко, как снизилась стоимость компьютеров.
Но, вглядываясь в предстоящее десятилетие, мы не видим никакой серебряной пули. Нет ни одного открытия ни в технологии, ни в методах управления, одно только использования которых обещало бы хоть на порядок величин повысить производительность, надежность, простоту. В этой главе мы попытаемся увидеть, почему это так, исследуя природу задач программирования и свойства предлагаемых пуль.
Однако скептицизм — это не пессимизм. Хотя мы не видим ошеломляющих прорывов и действительно считаем их несвойственными природе программирования, происходит много вселяющих надежды нововведений. Дисциплинированные и последовательные усилия, направленные на их развитие, распространение и использование, действительно могут дать рост на порядок величин. Нет царского пути, но все же путь есть.
Первым шагом к лечению болезней стала замена представлений о демонах и «соках» в организме теорией бактерий. Сам этот шаг, обещавший надежду, опроверг все мечты о чудесном исцелении. Он подсказал исследователям, что прогресс будет осуществляться шажками, с большим трудом, и что постоянное и неослабное внимание нужно уделять санитарии. То же происходит сегодня с программной инженерией.
Неизбежны ли трудности? Трудности, вытекающие из сущности
Серебряных пуль не только не видно в настоящее время, но в силу самой природы программного обеспечения маловероятно, что они вообще будут найдены — не будет изобретений, способных повлиять на продуктивность создания, надежность и простоту программного обеспечения так, как электроника, транзисторы и интегральные схемы — на аппаратное обеспечение компьютеров. Не следует ожидать, что когда-либо в будущем каждые два года будет происходить двукратный рост.
Во-первых, следует считать необычным не то, что так медленно происходит прогресс в программировании, а то, что он так быстро идет в аппаратном обеспечении компьютеров. Ни одна другая технология за всю историю цивилизации не имела за 30 лет своего развития роста соотношения производительность/цена на шесть порядков. Ни одна другая технология не позволяет выбрать, какой выигрыш предпочесть: улучшить технические характеристики или снизить затраты. Оба эти выигрыша стали возможны благодаря переходу производства компьютеров из сборочного производства в обрабатывающее.
Во-вторых, чтобы посмотреть, какой скорости развития можно ожидать от программных технологий, полезно изучить имеющиеся в них трудности. Следуя Аристотелю, я делю их на сущности — трудности, внутренне присущие природе программного обеспечения, и акциденции — трудности, которые сегодня сопутствуют производству программного обеспечения, но не являются внутренне ему присущими.
Акциденции я рассматриваю в следующем параграфе. Сначала рассмотрим сущность.
Сущностью программного объекта является конструкция, состоящая из сцепленных вместе концепций: наборов данных, взаимосвязей между элементами данных, алгоритмов и вызовов функций. Эта сущность является абстрактной в том отношении, что концептуальная конструкция остается одной и той же при различных представлениях. Тем не менее она обладает высокой точностью и большим числом деталей.
Я считаю, что сложность создания программного обеспечения заключается в задании технических требований, проектировании и проверке этой концептуальной конструкции, а не в затратах, связанных с ее представлением и проверкой точности представления. Конечно, мы делаем синтаксические ошибки, но в большинстве систем они несущественны в сравнении с концептуальными ошибками.
Верно то, что создание программных систем всегда будет трудным. Серебряной пули нет по самой природе вещей.
Рассмотрим неотъемлемые свойства этой несократимой сущности современных программных систем: сложность, согласованность, изменяемость и незримость.
Сложность. Сложность программных объектов более зависит от их размеров, чем, возможно, для любых других создаваемых человеком конструкций, поскольку никакие две их части не схожи между собой (по крайней мере, выше уровня операторов). Если они схожи, то мы объединяем их в одну подпрограмму, открытую или закрытую. В этом отношении программные системы имеют глубокое отличие от компьютеров, домов и автомобилей, где повторяющиеся элементы имеются в изобилии.
Сами цифровые компьютеры сложнее, чем большинство изготавливаемых людьми вещей. Число их состояний очень велико, поэтому их трудно понимать, описывать и тестировать. У программных систем число возможных состояний на порядки величин превышает число состояний компьютеров.
Аналогично, масштабирование программного объекта — это не просто увеличение в размере тех же самых элементов, это обязательно увеличение числа различных элементов. В большинстве случаев эти элементы взаимодействуют между собой неким нелинейным образом, и сложность целого растет значительно быстрее, чем линейно.
Сложность программ является существенным, а не второстепенным свойством. Поэтому описания программных объектов, абстрагирующиеся от их сложности, часто абстрагируются от их сущности. Математика и физические науки за три столетия достигли больших успехов, создавая упрощенные модели сложных физических явлений, получая из этих моделей свойства и проверяя их опытным путем. Это удавалось благодаря тому, что сложности, игнорировавшиеся в моделях, не были существенными свойствами явлений. И это не действует, когда сложности являются сущностью.
Многие классические трудности разработки программного обеспечения проистекают их этой сложности сущности и ее нелинейного роста при увеличении размера. Сложность служит причиной трудности процесса общения между участниками бригады разработчиков, что ведет к ошибкам в продукте, превышению стоимости разработки, затягиванию выполнения графиков работ. Сложность служит причиной трудности перечисления, а тем более понимания, всех возможных состояний программы, а отсюда возникает ее ненадежность. Сложность функций служит причиной трудностей при их вызове, из-за чего программами трудно пользоваться. Сложность структуры служит причиной трудностей при развитии программ и добавлении новых функций так, чтобы не возникали побочные эффекты. Сложность структуры служит источником невизуализуемых состояний, в которых нарушается система защиты.
Сложность служит причиной не только технических, но и административных проблем. Из-за сложности трудно осуществлять надзор, а в результате страдает концептуальная целостность. Трудно найти и держать под контролем все свободные концы. Обучение и понимание становится колоссальной нагрузкой, из-за чего текучесть рабочей силы превращается в катастрофу.
Согласованность. Люди, связанные с программированием, не одиноки в проблемах сложности. Физика имеет дело с объектами чрезвычайной сложности даже на уровне элементарных частиц. Однако физик работает в твердой уверенности, что можно найти общие принципы, будь то кварки или общая теория поля. Эйнштейн неоднократно утверждал, что природа должна иметь простые объяснения, поскольку Богу не свойственны капризность и произвол.
У разработчика программного обеспечения нет такой утешительной веры. Сложность, с которой он должен совладать, по большей части является произвольной, необоснованно вызванной многочисленными человеческими установлениями и системами, которым должны удовлетворить его интерфейсы. Системы различаются интерфейсами и меняются во времени не в силу необходимости, а лишь потому, что были созданы не Богом, а разными людьми.
Во многих случаях программное обеспечение должно согласовываться, поскольку только что появилось на сцене. В других случаях оно должно согласовываться, поскольку есть ощущение, что его легче всего согласовать. Но во всех случаях значительная часть сложности происходит от согласования с другими интерфейсами, и это невозможно упростить только в результате перепроектирования программного обеспечения.
Изменяемость. Программные объекты постоянно подвержены изменениям. Конечно, это относится и к зданиям, автомобилям, компьютерам. Но произведенные вещи редко подвергаются изменениям после изготовления. Их заменяют новые модели, или существенные изменения включают в более поздние серийные экземпляры того же базового проекта. Отзывы у потребителей автомобилей на практике встречаются весьма редко, а изменения работающих компьютеров еще реже. То и другое случается значительно реже, чем модификация работающего программного обеспечения.
Отчасти это происходит потому, что программное обеспечение в системе воплощает ее назначение, а назначение более всего ощущает влияние изменений. Отчасти это происходит потому, что программное обеспечение легче изменить: это чистая мысль, бесконечно податливая. Здания тоже перестраиваются, но признаваемая всеми высокая стоимость изменений умеряет капризы новаторов.
Все удачные программные продукты подвергаются изменениям. При этом действуют два процесса. Во-первых, как только обнаруживается польза программного продукта, начинаются попытки применения его на грани или за пределами первоначальной области. Требование расширения функций исходит, в основном, от пользователей, которые удовлетворены основным назначением и изобретают для него новые применения.
Во-вторых, удачный программный продукт живет дольше обычного срока существования машины, для которой он первоначально был создан. Приходят если не новые компьютеры, то новые диски, новые мониторы, новые принтеры, и программа должна быть согласована с возможностями новых машин.
Короче, программный продукт встроен в культурную матрицу приложений, пользователей, законов и машин. Все они непрерывно меняются, и их изменения неизбежно требуют изменения программного продукта.
Незримость. Программный продукт невидим и невизуализуем. Геометрические абстракции являются мощным инструментом. План здания помогает архитектору и заказчику оценить пространство, возможности перемещения, виды. Становятся очевидными противоречия, можно заметить упущения. Масштабные чертежи механических деталей и объемные модели молекул, будучи абстракциями, служат той же цели. Геометрическая реальность схватывается в геометрической абстракции.
Реальность программного обеспечения не встраивается естественным образом в пространство. Поэтому у него нет готового геометрического представления подобно тому, как местность представляется картой, кремниевые микросхемы — диаграммами, компьютеры — схемами соединений. Как только мы пытаемся графически представить структуру программы, мы обнаруживаем, что требуется не один, а несколько неориентированных графов, наложенных один на другой. Несколько графов могут представлять управляющие потоки, потоки данных, схемы зависимостей, временных последовательностей, соотношений пространства имен. Обычно они даже не являются плоскими, не то что иерархическими. На практике одним из способов установления концептуального контроля над такой структурой является обрезание связей до тех пор, пока один или несколько графов не станут иерархическими. [2]
Несмотря на прогресс, достигнутый в ограничении и упрощении структур программного обеспечения, они остаются невизуализуемыми по своей природе, тем самым лишая нас одного из наиболее мощных инструментов оперирования концепциями. Этот недостаток не только затрудняет индивидуальный процесс проектирования, но и серьезно затрудняет общение между разработчиками.
Прежние прорывы разрешили второстепенные трудности
Если рассмотреть три наиболее плодотворных шага в произошедшем развитии программных технологий, то обнаружится, что все они были сделаны в направлении решения различных крупных проблем разработки программ, но эти проблемы затрагивали второстепенные, а не относящиеся к сущности трудности. Можно также видеть естественные пределы экстраполирования каждого их этих направлений.
Языки высокого уровня. Конечно, наибольшее значение для роста производительности, надежности и простоты имело все более широкое использование языков высокого уровня. Большинство исследователей считает, что этим был достигнут, по крайней мере, пятикратный рост производительности при одновременном выигрыше в надежности, простоте и легкости понимания.
Что делает язык высокого уровня? Он освобождает программу от значительной доли необязательной сложности. Абстрактная программа состоит из концептуальных конструкций: операций, типов данных, последовательностей и связи. Конкретная машинная программа связана с битами, регистрами, условиями, переходами, каналами, дисками и прочим. В той мере, в какой в языке высокого уровня воплощены необходимые абстрактной программе конструкции и избегаются конструкции низшего порядка, он ликвидирует целый уровень сложности, совершенно не являющийся необходимым свойством программы.
Самое большее, что может сделать язык высокого уровня, — это предоставить все конструкции, которые по замыслу программиста содержит абстрактная программа. Конечно, уровень утонченности наших представлений о структурах данных, типах данных и операциях неуклонно растет, но с постоянно убывающей скоростью. И языки в своем развитии все больше приближаются к изощренности нашего мышления.
Более того, с некоторого момента дальнейшая разработка языков высокого уровня становится обузой, осложняющей, а не упрощающей интеллектуальные задачи пользователя, редко использующего эзотерические конструкции.
Разделение времени. Большинство исследователей считает, что благодаря работе в режиме разделения времени произошел большой рост производительности труда программистов и качества создаваемых программных продуктов, хотя и не такой значительный, как вызванный использованием языков высокого уровня.
Разделение времени помогает решить совсем другую задачу. Благодаря разделению времени обеспечивается безотлагательность, и потому возможность иметь общее впечатление о сложности. Из-за медленной оборачиваемости при пакетной обработке мы неизбежно забываем мелочи, если не самое направление нашей мысли, в тот момент, когда мы прервались и начали компиляцию и выполнение программы. Этот обрыв мысли дорого обходится по времени, поскольку приходится восстанавливать ее в памяти. В худшем случае, можно вообще потерять представление о том, что происходит со сложной системой.
Медленная оборачиваемость, как и сложности машинных языков, является второстепенной, а не существенной трудностью процесса программирования. Предельный вклад, вносимый разделением времени, определяется непосредственно. Главное — это сократить время отклика системы. По мере приближения его к нулю, оно переходит порог скорости человеческого восприятия, составляющей около 100 миллисекунд. Дальше никакой выгоды получить уже нельзя.
Объединенные среды программирования. Считается, что Unix и Interlisp, первые широко распространенные интегрированные среды программирования, повысили производительность в несколько раз. Почему?
Они направлены на преодоление второстепенных трудностей совместного использования программ путем использования общих библиотек, унифицированных форматов файлов, каналов и фильтров. В результате концептуальные структуры, которые, в принципе, всегда могут вызывать, обмениваться данными и использовать друг друга, получают возможность осуществлять это практически.
Это достижение, в свою очередь, стимулировало развитие целых инструментальных наборов, поскольку всякий новый инструмент мог применяться к любым программам, используя стандартные форматы.
Благодаря этим успехам среды программирования стали предметом многих сегодняшних исследований в программной инженерии. В следующем параграфе мы рассмотрим, что от них можно ожидать, и какие им присуще ограничения.
Надежды на серебро
Рассмотрим теперь те технические достижения, которые чаще всего выдвигаются кандидатами на роль серебряной пули. К каким задачам они обращаются? Задачам, относящимся к сущности, или остаткам наших акцидентных сложностей? Предлагают ли они революционное развитие или пошаговое продвижение?
Ada и другие достижения языков высокого уровня. Одним из наиболее рекламируемых достижений последнего времени является язык программирования Ada — язык высокого уровня общего назначения 80-х годов. Ada действительно не только отражает эволюционное развитие концепций языков, но и воплощает черты, поддерживающие современные идеи проектирования и модульности. Возможно, большим достижением является не язык Ada, а философия Ada как философия модульности, абстрактных типов данных, иерархического структурирования. Ada, пожалуй перегружен возможностями, будучи естественным продуктом процесса, породившего требования, положенные в основу его разработки. Это не смертельно, поскольку подмножества рабочих словарей могут решить проблему изучения, а прогресс электроники даст нам дешевые миллионы операций в секунду, решающие проблему компиляции. Развитие структурированности программных систем — это очень хорошее применение для денег, которые мы тратим на приобретение все больших вычислительных мощностей. Операционные системы, громко осуждавшиеся в 60-х годах за дороговизну памяти и вычислений, оказались хорошим способом применения быстродействия и дешевой памяти, полученных в результате быстрого развития аппаратных средств.
Тем не менее Ada не станет той серебряной пулей, которая уложит монстра низкой производительности производства программного обеспечения. В конце концов это всего лишь еще один язык высокого уровня, а самую большую отдачу от применения таких языков мы уже получили при первом переходе от второстепенной сложности машин к более абстрактной формулировке пошаговых решений. После устранения тех акциденций остались менее существенные, и выгоды от их устранения будет, конечно, меньше.
Я предвижу, что через десятилетие, когда оценят эффективность Ada, будет признан значительный вклад этого языка, но не благодаря какой-либо отдельной его возможности и даже не благодаря им всем вместе взятым. Не станут причиной успехов и новые среды программирования на Ada. Наибольшим вкладом Ada явится то, что переход на этот язык послужит причиной изучения программистами современных методов проектирования программного обеспечения.
Объектно-ориентированное программирование. Многие, изучающие искусство программирования, связывают с объектно-ориентированным программированием больше надежд, чем с любыми другими современными техническими увлечениями. [3] Я принадлежу к их числу. Марк Шерман (Mark Sherman) из Дартмута замечает, что следует проводить отличие между двумя разными идеями, фигурирующими под этим названием: абстрактных типов данных и иерархических типов, называемых также классами. Понятие абстрактного типа данных состоит в том, что тип объекта определяется именем, множеством допустимых значений и множеством допустимых операций, а не организацией хранения, которая должна быть скрыта. Примерами являются пакеты Ada (с защищенными типами) и модули в языке Modula.
Иерархические типы, такие классы в Simula-67, позволяют определять общие интерфейсы, которые в дальнейшем можно уточнять с помощью подчиненных типов. Эти две концепции ортогональны: могут быть открытые иерархии и скрытие без иерархий. Обе концепции действительно являются достижением в искусстве программирования.
Каждая из них устраняет еще одну второстепенную сложность, позволяя разработчику выразить сущность своего проекта без использования большого количества синтаксического материала, не добавляющего нового информационного содержания. Использование как абстрактных, так и иерархических типов устраняет второстепенные трудности более высокого порядка и позволяет выразить проект на более высоком уровне.
И все же такие достижения могут не более чем устранить второстепенные трудности при выражении проекта. Существенна сложность самого проекта, на что решение таких задач никак не может повлиять. Добиться выигрыша на порядок величин с помощью объектно-ориентированного программирования можно лишь в том случае, если остающаяся сегодня в нашем языке программирования необязательная работа по спецификации типов сама по себе ответственна за 9/10 усилий, затрачиваемых на проектирование программного продукта. В этом я не сомневаюсь.
Искусственный интеллект. Многие ожидают, что успехи в области искусственного интеллекта позволят осуществить революционный переворот, который принесет рост производительности разработки программного обеспечения и его качества на порядки величин. [4] Я этого не жду. Чтобы увидеть, почему, разберем, что понимается под «искусственным интеллектом», а затем посмотрим, какие возможны применения.
Парнас внес ясность в терминологический хаос:
Сегодня в ходу два совершенно разных определения ИИ. ИИ-1: использование компьютеров для решения задач, которые раньше могли быть решены только с помощью человеческого интеллекта. ИИ-2: использование специальных приемов программирования, известных как эвристическое, или основанное на правилах, программирование. При таком подходе изучают действия экспертов, чтобы определить, какими эвристиками и практическим правилами они пользуются при решении задач… Программа корректируется для решения задач так, как, по-видимому, ее решает человек.
У первого определения скользкий смысл… Кое-что укладывается сегодня в определение ИИ-1, но как только мы видим работу программы и понимаем задачу, мы уже не думаем о ней, как о ИИ… К несчастью, я не вижу ядра методов, которые уникальны в этой области… По большей части методы проблемно-ориентированны, и для их переноса требуются известные абстракция и творчество. [5]
Я полностью согласен с этой критикой. Приемы, используемые для распознавания речи, выказывают мало сходства с методами распознавания изображений, при этом в экспертных системах используются методы, отличные от тех и других. Я затрудняюсь сказать, к примеру, какое влияние распознавание изображений может оказать на методы программирования. То же самое справедливо в отношении распознавания речи. При разработке программ трудно решить, что именно сказать, а не собственно сказать. Никакое облегчение выражения не может дать больше, чем незначительные выгоды.
Методы экспертных систем ИИ-2 заслуживают отдельного параграфа.
Экспертные системы. Наиболее развитой и широко применяемой частью искусственного интеллекта являются экспертные системы. Многие ученые в области программирования напряженно трудятся над применением этой технологии в средах разработки программного обеспечения. [5] В чем состоит идея, и каковы перспективы?
Экспертная система — это программа, содержащая обобщенный генератор выводов и базу правил, предназначенную для приема входных данных и допущений и исследования логических следствий через заключения, выводимые из базы правил, предоставляющая заключения и рекомендации и предлагающая пользователю объяснение полученных результатов путем обратного прослеживания своих рассуждений. Помимо чисто детерминированной логики, генератор выводов обычно может работать с нечеткими или вероятностными данными.
Такие системы предоставляют некоторые явные преимущества перед запрограммированными алгоритмами решения тех же задач:
• Технология генератора выводов разрабатывается независимо от применения и используется затем во многих приложениях.
• Изменяемые части специфических для приложения данных единообразно кодируются в базе правил. Обеспечивается инструментарий для разработки, изменения, проверки и документирования базы правил. Этим упорядочивается значительная часть сложности самого приложения.
Эдвард Фейгенбаум (Edward Feigenbaum) считает, что мощь таких систем растет не благодаря совершенствованию механизмов вывода, а скорее, благодаря пополнению базы знаний, все более точно отражающей реальный мир. Я считаю, что самое важное достижение этой технологии состоит в разделении сложности приложения и самой программы.
Как можно использовать экспертные системы при создании программного обеспечения? Различными способами: предложение правил интерфейсов, рекомендации по стратегии отладки, запоминание частоты ошибок каждого типа, подсказки по оптимизации и т.п.
Представим себе, к примеру, некоего советчика по отладке. В самой зачаточной форме диагностическая экспертная система весьма напоминает памятку пилота, по сути, делая предположения относительно возможных причин затруднений. По мере развития базы правил предположения становятся более специфичными, более изощренно учитывая симптомы проблемы. Можно представить такого помощника предлагающим сначала самые общие решения, но, по мере воплощения в базе правил все большей части структуры системы, становящегося все более разборчивым в генерируемых гипотезах и предлагаемых тестах. Такая экспертная система может решительно отличаться от обычных тем, что ее база правил, вероятно, должна быть иерархически разбита на модули таким же образом, как соответствующий программный продукт. Поэтому при изменении модульной структуры продукта изменяется также модульная структура базы диагностических правил.
Работа, которую необходимо проделать для создания диагностических правил, в любом случае должна быть проведена при создании набора контрольных примеров для модулей и для системы. Если это делать достаточно общим образом, с единообразной структурой правил и при наличии хорошего генератора выводов, то можно действительно сократить объем работ при генерации контрольных примеров, а также пожизненном сопровождении и тестировании модификаций. Такие же условия мы можем поставить и для других советчиков, используемых для других участников задачи создания программы. Возможно, они будут многочисленны и иногда просты.
На пути ранней реализации полезных экспертных советников для разработчика программы стоит много препятствий. Решающей частью нашего воображаемого сценария является разработка простых способов перехода от задания структуры программы к автоматическому или полуавтоматическому созданию диагностических правил. Еще более сложной и важной является двойная задача приобретения знаний: найти членораздельно выражающихся и способных к самоанализу экспертов, понимающих, почему они делают то или другое действие, и разработать эффективные методы извлечения их знаний и превращения в базы правил. Чтобы построить экспертную систему, необходимо иметь эксперта.
Наибольшим вкладом экспертных систем, несомненно, будет предоставление неопытному программисту опыта и всех знаний, накопленных лучшими программистами. И это не мало. Разрыв между лучшими и средними приемами программирования очень велик, возможно, он больше, чем в любой другой инженерной дисциплине. Поэтому средство распространения хороших приемов было бы очень важным.
«Автоматическое» программирование. Почти 40 лет люди ждут и пишут об «автоматическом программировании» — генерации решающей задачу программы, исходя из формулировки спецификации этой задачи. Некоторые высказываются сегодня так, будто ожидают от этой технологии грядущего переворота. [7]
Парнас предполагает, что термин используется из-за эффектности, а не семантического содержания, утверждая:
Короче, автоматическое программирование всегда было эвфемизмом для программирования на языке более высокого уровня, чем доступный программисту в данный момент. [8]
Он утверждает, в сущности, что в большинстве случаев нужно задать спецификацию не задачи, а метода решения.
Можно отыскать исключения. Метод создания генераторов является очень мощным и повседневно с пользой применяется в программах сортировки. Некоторые системы интегрирования дифференциальных уравнений также позволяли прямую формулировку задачи. Система производила оценку параметров, выбирала из библиотеки методы решения и генерировала программы.
У этих применений есть свойства, благоприятствующие автоматизации:
• Проблемы легко описываются сравнительно небольшим числом параметров.
• Известно много методов решения, что обеспечивает наличие библиотеки альтернатив.
• Тщательный анализ привел к выработке явных правил выбора методов решения в зависимости от параметров.
Едва ли возможно обобщение таких методов на весь мир обычных программных систем, в котором ситуация с такими приятными свойствами являются исключениями. Трудно даже представить себе, как такой прорыв в обобщении мог бы произойти разумным образом.
Графическое программирование. Излюбленной темой докторских диссертаций в программной инженерии является графическое, или визуальное, программирование — применение компьютерной графики в разработке программного обеспечения. [9] Иногда перспективы такого подхода основываются на аналогии с проектированием СБИС, в котором компьютеры играют такую большую роль. Иногда такой подход обосновывается, исходя из того, что блок-схемы являются идеальным материалом при проектировании программ. Имеются мощные средства для создания таких блок-схем.
Ничего убедительного и удивительного из этих попыток пока не вышло, — и я уверен, не выйдет.
Во-первых, как я всюду доказываю, блок-схема является весьма слабой абстракцией структуры программы. [10] Лучше всего это видно из попыток Беркса, фон Неймана и Гольдстайна снабдить свой предполагаемый компьютер крайне необходимым управляющим языком высокого уровня. В том жалком виде — многие страницы соединенных линиями прямоугольников, — в котором сегодня разрабатываются блок-схемы, они доказали, в сущности, свою бесполезность: программисты рисуют их после, а не до создания описываемых ими программ.
Во-вторых, сегодняшние экраны имеют слишком мало пикселов, чтобы показать целиком и с достаточным разрешением сколько-нибудь подробную схему программы. Так называемая «метафора рабочего стола» становится метафорой «сиденья самолета». Всякий, кому приходилось листать пачку бумаг, будучи стиснутым двумя корпулентными соседями, почувствует разницу: одновременно можно увидеть очень немного. Настоящий рабочий стол позволяет обозревать и произвольно выбирать множество бумаг. Более того, в порыве творчества не один программист или писатель предпочитал рабочему столу более вместительный пол. Аппаратным технологиям нужно сделать очень большой наг, чтобы предоставляемый экранами обзор был достаточным для задач проектирования программ.
Если обратиться к основам, программное обеспечение очень трудно визуализировать, как я доказывал это выше. Составляем ли мы схемы управляющей логики, вложенных областей, видимости переменных, перекрестных ссылок переменных, потоков данных, иерархических структур данных или чего-то еще, они отражают лишь одно изменение взаимодействующих запутанным образом частей программной системы. Если наложить одна на другую эти схемы, отражающие взгляд с различных точек зрения, трудно извлечь из этого какую-либо общую точку зрения. Аналогия с интегральными схемами вводит, в сущности, в заблуждение: конструкция микросхемы представляет собой многослойный двумерный объект, геометрия которого отражает сущность. Программная система не является таким объектом.
Верификация программ. Много труда в современном программировании тратится на отладку и исправление ошибок. Может быть, мы найдем серебряную пулю, устранив все ошибки в самом начале, на этапе системного проектирования? Можно ли радикально повысить производительность и надежность продукта, если следовать совершенно иной стратегии — обеспечить корректность проекта, прежде чем тратить огромные усилия на его реализацию и тестирование?
Не думаю, что мы обнаружим здесь чудеса. Верификация программ является очень мощной концепцией, и она очень важна для таких вещей, как создание надежного ядра операционной системы. Эта технология не обещает, однако, экономии труда. Верификация требует столько работы, что весьма немногие значительные программы вообще были верифицированы.
Верификация программ не означает создания программ, лишенных ошибок. И здесь нет чудес. Математические доказательства тоже могут быть ошибочными. Поэтому хотя верификация может облегчить тестирование, она не может отменить его.
Более существенно, что даже самая совершенная верификация программы может лишь определить, что программа отвечает своим спецификациям. Самая сложная задача программирования — получить полную и непротиворечивую спецификацию, и сущность создания программы на практике во многом состоит в отладке спецификации.
Среды программирования и инструменты. Какого еще выигрыша можно ожидать от стремительно расширяющихся исследований по усовершенствованию сред программирования? Инстинктивно кажется, что задачи, которые сулили наибольшую отдачу, были в числе первых, за которые взялись, и их уже решили: иерархические файловые системы, единообразные форматы файлов для получения единообразных программных интерфейсов и обобщенных инструментов. Ориентированные на конкретные языки интеллектуальные редакторы пока не очень распространены, но большее, на что они способны, это устранение синтаксических ошибок и мелких семантических.
Возможно, наибольший выигрыш среда программирования сможет дать при использовании строенных систем баз данных для отслеживания мириадов деталей, которые каждый программист должен точно вспоминать, и которые должны храниться в текущем состоянии в группе работающих над одной системой.
Несомненно, что это работа заслуживает внимания и принесет некоторые плоды как для производительности, так и для надежности. Но ввиду самой ее сути отдача должна быть незначительной.
Рабочие станции. Какой выигрыш может получить искусство программирования от несомненного и быстрого роста мощности и объема памяти отдельной рабочей станции? Сколько миллионов операций в секунду можно плодотворно использовать? Составление и редактирование программ вполне обеспечиваются сегодняшними скоростями. Компиляция может быть ускорена, но десятикратное увеличение скорости машины, вне сомнения, сделает обдумывание основным занятием программиста в течение рабочего дня. Пожалуй, это так уже сейчас.
Конечно, мы приветствуем увеличение мощности рабочих станций. Но рассчитывать на связанные с этим чудеса мы не можем.
Перспективные подходы к концептуальной сущности
Хотя никакой прорыв в технологии не обещает таких волшебных результатов, какие мы видим в аппаратной части компьютеров, в настоящее время делается много полезного, и есть надежды на неуклонный, хотя и неброский прогресс.
Все технологические подходы к акциденциям процесса программирования принципиально ограничены уравнением продуктивности:
Время решения задачи = ^ (Частот)/ х (Длительность)/
Если, как я полагаю, концептуальные составляющие задачи сейчас отнимают большую часть времени, то никакая работа над составными частями задачи, являющимися просто выражением концепций, не даст большого выигрыша.
Поэтому мы должны рассмотреть те направления, которые затрагивают саму сущность проблемы программирования — формулировку этих сложных концептуальных структур. К счастью, некоторые из этих направлений весьма многообещающи.
Покупать, а не создавать. Наиболее радикальное возможное решение при создании программ — вообще не создавать их.
С каждым днем это становится все легче, поскольку все большее число поставщиков предлагает все более многочисленные и лучшие программные продукты для немыслимого разнообразия приложений. Пока мы, инженеры-программисты, трудились над совершенствованием методологии производства, революция, произведенная персональными компьютерами, создала не один, а много массовых рынков программного обеспечения. В каждом газетном киоске выставлены ежемесячные журналы, в которых, отсортированные по типам машин, рекламируются и рецензируются десятки продуктов по ценам от нескольких долларов до нескольких сотен долларов. Более специализированные издания предлагают очень мощные продукты для рабочих станций и других рынков Unix. Даже инструменты и среды программирования могут быть куплены в коробочном виде. Я где-то предложил базар для отдельных модулей.
Любой такой продукт дешевле купить, чем создавать заново. Даже при цене 100 000 долларов купленный продукт стоит примерно столько, сколько годовое содержание программиста. И поставка немедленная! Немедленная, по крайней мере, для реально существующих продуктов, проспект которых разработчик может послать счастливому пользователю. Более того, такие продукты обычно гораздо лучше документированы и несколько лучше сопровождаются, чем доморощенные программы.
Развитие массового рынка является, по моему мнению, наиболее глубокой долгосрочной тенденцией программной инженерии. Стоимость программного продукта всегда определялась стоимостью разработки, а не тиражирования. Разделив эту стоимость даже на нескольких пользователей, мы коренным образом снижаем цену на одного пользователя. Взглянув на это с другой стороны, мы видим, что использование п копий программной системы фактически умножает на п производительность его разработчиков. Это рост производительности отрасли и всей страны.
Главным вопросом, конечно, является производительность. Смогу ли я использовать имеющийся коробочный продукт для решения своих задач? Здесь случилась удивительная вещь. В 50-х и 60-х годах одно исследование за другим показывало, что пользователи не хотят использовать коробочные пакеты для расчета зарплаты, управления складом, учета дебиторов по расчетам и т.д. Требования были слишком специальными, отклонения от случая к случаю слишком большими. В 80-х годах мы обнаруживаем большой спрос на такие пакеты и широкое их использование. Что изменилось?
Только не пакеты. Они стали несколько более общими и лучше настраиваются, чем раньше, но не намного. И не область их применения. В конце концов, сегодня потребности бизнеса и науки более разнообразны и сложны, чем 20 лет назад.
Резко изменилось соотношение стоимости компьютеров и программ. Тот, кто в 1960 году покупал машину за 2 миллиона долларов, считал, что может позволить себе потратить еще 250 000 долларов на заказную программу расчета зарплаты, которая легко и без ущерба вписалась бы во враждебную компьютерам социальную среду. Те, кто сегодня покупают машину для офиса за 50 000 долларов, не могут, понятно, позволить себе заказные программы расчета зарплаты, поэтому они приспосабливают свои процедуры расчета зарплаты к имеющимся пакетам. Компьютеры сейчас столь обычны, если не столь любимы, что адаптация воспринимается как обычное дело.
Есть яркие исключения из моего утверждения о том, что обобщенность программных пакетов за последние годы мало изменилась: электронные таблицы и простые системы баз данных. Эти мощные инструменты, столь очевидные задним умом и так поздно появившиеся, имеют бесчисленное множество применений, в том числе, весьма необычные. Есть масса статей и даже книг о том, как с помощью электронной таблицы решать неожиданные задачи. Большое число задач, для которых раньше были бы написаны заказные программы на Cobol или Report Program Generator, теперь шаблонно решается с помощью этих инструментов.
Многие пользователи изо дня в день применяют свои компьютеры для разных приложений, никогда не написав ни одной программы. На практике многие из этих пользователей и не могут писать для своих машин новые программы, но тем не менее приверженцы решению возникающих задач с их помощью.
Я считаю, что сегодня для многих организаций самая правильная политика для повышения производительности разработки программного обеспечения — это установить своим не имеющим компьютерных знаний работникам умственного труда компьютеры и хорошие общие программы для обработки текстов, рисования, работы с файлами и электронными таблицами и отпустить их в вольное плавание. Такая же политика в отношении распространенных математических и статистических пакетов, а также некоторых навыков программирования подойдет сотням ученых, работающих в лабораториях.
Уточнение требований и быстрое макетирование. Самая трудная отдельная задача в разработке программной системы — это точно решить, что разрабатывать. Ни одна другая задача работы над концепциями не является столь трудной, как разработка подробных технических требований, включая все интерфейсы пользователей, машинные интерфейсы и интерфейсы к другим программным системам. Ни одна другая часть работы не наносит такого ущерба готовой системе, если сделана неправильно. Ни одна другая часть не исправляется позднее с бульшим трудом.
Поэтому наиболее важной функцией, осуществляемой разработчиками для своих клиентов, является повторяющееся получение и уточнение требований к продукту. Правда заключается в том, что клиенты не знают, чего хотят. Обычно они не знают, на какие вопросы нужно дать ответ, и почти никогда не задумывались над задачей настолько детально, как это нужно указать в спецификации. Даже простой ответ — «сделайте так, чтобы новая программная система работала так, как наша старая ручная система обработки информации» — оказывается в действительности слишком упрощенным. Клиенты никогда не хотят этого в точности. Более того, сложные программные системы действуют, движутся, работают. Динамику этого действия трудно себе представить. Поэтому при планировании любых действий необходимо оставить резерв для многократного взаимодействия между клиентом и проектировщиком при описании системы.
Я пойду дальше и стану утверждать, что на практике клиенты, даже вместе с инженерами-программистами, не в состоянии указать полно, строго и корректно точные требования к современному программному продукту, прежде чем будут созданы и опробованы какие-либо версии продукта, спецификации к которому они составляют.
Поэтому одним из наиболее многообещающих современных направлений в технологии, причем обращенных к сущности, а не к акциденциям проблем программирования, является разработка подходов и инструментов для быстрого создания макетов систем как части итеративного процесса разработки спецификаций.
Макет программной системы моделирует главные интерфейсы и выполняет основные функции предполагаемой системы, при этом не обязательно будучи связан теми же ограничениями быстродействия компьютера, размера или стоимости. Обычно макеты выполняют основные задачи системы, но не пытаются обрабатывать исключительные ситуации, правильно реагировать на ввод недопустимых данных, корректно прерывать работу и т.д. Назначение макета — показать, как воплощается выбранная концептуальная структура, чтобы клиент мог проверить ее пригодность к использованию и непротиворечивость.
Сегодня многие процедуры приобретения программного обеспечения основываются на предположении, что можно заранее задать технические требования для желаемой системы, рассмотреть предложения разработчиков, получить разработанную систему и установить ее. Я думаю, что такое предположение в корне неверно, и из-за этой ошибки проистекают многие проблемы при приобретении программ, поскольку эти проблемы нельзя устранить без пересмотра основ, для которого требуется интерактивная разработка и спецификации макетов и продуктов.
Пошаговая обработка: наращивать программу, а не строить сразу. Я до сих пор помню испытанный в 1958 году удар, когда впервые услышал, как мой друг говорил о строительстве (building) программ в противоположность написанию (writing). В мгновение он расширил все мое представление о процессе программирования. Применение метафоры было сильным и точным. Сегодня мы понимаем, что сходство существует между созданием программы и другими строительными процессами, и свободно используем другие элементы метафоры, такие как спецификации (specifications), сборка компонентов (assembly of components), леса (scaffolding).
Метафора строительства пережила свое время. Пора снова вносить изменения. Если, как я считаю, создаваемые сегодня концептуальные структуры слишком сложны, чтобы их можно было точно специфицировать заранее, и слишком сложны, чтобы строить без ошибок, тогда нужен радикально иной подход.
Обратимся к природе и рассмотрим сложность живых созданий, а не безжизненных творений человека. Там мы обнаруживаем конструкции, сложность которых вселяет в нас ужас. Один только мозг настолько сложен, что невозможно составить его схему. Его мощь невозможно повторить, он богат своеобразием, способен к самосохранению и самообновлению. Секрет в том, что мозг растет, а не строится.
Так же должны создаваться наши программные системы. Несколько лет назад Харлан Миллз предложил наращивать программные системы путем пошаговой разработки. [11] Это значит, что сначала систему надо заставить выполняться, даже если при этом она не делает ничего полезного, кроме вызова некоторого числа фиктивных подпрограмм. Затем она понемногу обрастает мясом, причем подпрограммы, в свою очередь, разрабатываются сначала как вызовы пустых фиктивных подпрограмм, находящихся на уровень ниже.
Настаивая на применении этой технологии разработчиками проектов на моих лабораторных занятиях по программной инженерии, я стал свидетелем поразительных результатов. За последнее десятилетие ничто другое не оказало столь сильного влияния на мою собственную работу и ее эффективность. Этот подход предполагает нисходящее проектирование, поскольку это — нисходящее наращивание программы. Он позволяет легко отслеживать работу в обратном направлении. Он предоставляет возможность раннего создания макетов. Каждая новая функция или возможность работы с более сложными данными или условиями органически вырастают на того, что уже имеется.
Воздействие на моральный дух ошеломительное. Когда есть хотя бы простая работающая система, возрастает энтузиазм. Энергия удваивается, когда на экране появляется картинка из новой графической программной системы, даже если это всего лишь прямоугольник. И на каждой стадии процесса разработки существует работающая система. Я считаю, что за одинаковые сроки команда может нарастить значительно более сложный объект, чем построить.
В больших проектах можно ощутить такие же выгоды, как и в моих маленьких. [12]
Выдающиеся проектировщики. Главная проблема совершенствования искусства программирования заключена, как всегда, в людях.
Мы можем добиваться хороших проектов, следуя хорошим, а не плохим практическим приемам. Хорошим приемам можно обучать. Программисты принадлежат к наиболее интеллектуальной части общества, следовательно, они в состоянии изучать хорошие приемы. Поэтому важнейшим направлением в Соединенных Штатах является распространение хороших современных приемов. Новые курсы, новые издания, новые организации, такие как Институт инженеров-программистов (Software Engineering Institute) — все это вызвано к жизни стремлением повысить уровень наших практических приемов. Это совершенно правильно.
Тем не менее, я считаю, что мы не сможем подняться еще на одну ступеньку выше, действуя в этом направлении. Выбор правильного метода проектирования определяет различия между плохим и хорошим концептуальным проектом, но не между хорошим и выдающимся. Выдающиеся проекты создаются выдающимися проектировщиками. Создание программ является творческим процессом. Крепкая методология может придать силу и освободить творческий ум, но она не может воспламенить или вдохновить того, кто занят нудной работой.
И разница немалая — это как Сальери и Моцарт. Одно исследование за другим показывают, что лучшие проектировщики создают структуры, которые быстрее, меньше по размеру, проще, понятнее и разработаны меньшими усилиями. Различия между выдающимся и средним достигают порядка величины.
Нетрудно проследить, что ряд хороших и полезных программных систем проектировался комиссиями и создавался с помощью проектов, состоявших из многих частей. Но программные системы, вызвавшие восхищение страстных поклонников, являются продуктом одного или небольшого числа выдающихся проектировщиков. Посмотрите на Unix, APL, Pascal, интерфейс Smalltalk и даже Fortran — с одной стороны, и Cobol, PL/I, Algol, MVS/370 и MS-DOS — с другой (рис. 16.1).
Рис. 16.1 Имеются ли у этих продуктов страстные поклонники?
Поэтому, высоко ценя нынешние программы передачи технологий и развития обучения, я считаю, что наиболее важной программой, которую мы можем предпринять, является развитие способов воспитания выдающихся проектировщиков.
Ни одна занятая в программировании организация не может игнорировать эту проблему. Хороших менеджеров, как бы мало их ни было, не меньше, чем хороших проектировщиков. Как выдающиеся проектировщики, так и выдающиеся менеджеры встречаются редко. В большинстве организаций значительные усилия тратятся на поиска и выращивание подающих надежды менеджеров. Я не слышал, чтобы кто-либо тратил такие же усилия на поиски и развитие выдающихся проектировщиков, от которых, в конечном счете, зависит техническое превосходство продуктов.
Первое мое предложение состоит в том, чтобы каждая занятая в программировании организация определила для себя и провозгласила, что выдающиеся проектировщики имеют для ее успеха такое же большое значение, как и выдающиеся менеджеры, и что они могут рассчитывать на такие же заботу и вознаграждение. Не только зарплата, но и атрибуты положения — размеры офиса, мебель, техническое оборудование, командировочные фонды, обеспеченность сотрудниками — должны быть полностью равнозначны.
Как растить выдающихся проектировщиков? Место не позволяет обсуждать это пространно, но вот некоторые очевидные шаги:
• Систематически и как можно раньше выявлять первоклассных проектировщиков. Лучшие — не всегда самые опытные.
• Назначить наставника, ответственного за рост перспективного проектировщика и тщательно следить за его карьерой.
• Разработать и осуществлять план служебного роста для каждого перспективного проектировщика, включающий тщательно продуманное обучение у передовых проектировщиков, периоды дополнительного формального обучения, краткосрочные курсы, перемежающиеся с самостоятельным проектированием и назначением на руководящие технические должности.
• Обеспечить возможности для взаимодействия и взаимного стимулирования растущих проектировщиков.
Глава 17 Новый выстрел «Серебряной пули нет»
У всякой пули — свое предназначение.
ВИЛЬГЕЛЬМ III ОРАНСКИЙ Кто хочет увидеть образец совершенства, Тот мечтает о том, чего никогда не было, нет и не будет.
АЛЕКСАНДР ПОП, «О КРИТИКЕ»
Об оборотнях и прочих мифических ужасах
«Серебряной пули нет: сущность и акциденция в программной инженерии» (глава 16 данной книги) первоначально была заказным докладом для конференции IFIP (Международной федерации по обработки информации) 1986 года в Дублине и была опубликована в ее трудах. [1] Журнал «Computer» перепечатал ее под обложкой в готическом стиле, иллюстрируя кадрами из фильмов, таких как «Вервольф из Лондона», [2] и снабдив боковым полем «Убить вервольфа» с изложением современной легенды о том, что справиться с ним можно только с помощью серебряной пули. До публикации я не знал об иллюстрациях, и для меня было неожиданностью, что серьезная техническая статья была так красочно издана.
Однако редакторы «Computer» знали свое дело и достигли желаемого результата: похоже, что статью прочли многие. Поэтому я подобрал для той главы еще одну картинку с оборотнем — старинное изображение почти забавного создания. Надеюсь, что эта менее яркая картинка окажет такое же полезное действие.
Серебряная пуля все-таки есть — ВОТ ОНА!
«Серебряной пули нет» утверждает и доказывает, что в течение десятилетия (с момента публикации статьи в 1986 году) ни одна разработка в области техники программного обеспечения не позволит повысить производительность труда в программировании на порядок. Из этого десятилетия прошло уже девять лет, и можно посмотреть, насколько сбывается предсказание.
В то время как «Мифический человеко-месяц» породил частое цитирование и мало споров, статья «Серебряной пули нет» вызвала статьи с опровержениями и письма в редакции журналов, поток которых не прекратился и по сей день. [3] Чаще всего критикуется главное утверждение о том, что волшебного решения нет, и мое ясно выраженное мнение о том, что его и быть не может. Большинство соглашается с основной частью моих аргументов в «СПН», но затем заявляет, что в действительности серебряная пуля для программного зверя существует, и изобрел ее автор. Перечитывая сегодня ранние отклики, не могу не отметить, что патентованные средства, столь энергично предлагавшиеся в 1986 и 1987 годах, не возымели эффекта, на который претендовали.
Я обычно покупаю компьютеры и программы, проверяя их на «счастливом обладателе», т.е. беседуя с вызывающими доверие людьми, заплатившими деньги за продукт и пользующимися им с удовольствием. Аналогично, я с готовностью поверю в материализацию серебряной пули, когда вызывающий доверие независимый пользователь выступит вперед и скажет: «Я использовал эту методологию, этот инструмент или продукт, и это позволило мне в десять раз повысить производительность разработки программ».
Многие корреспонденты сделали верные поправки и разъяснения. Некоторые проанализировали статью пункт за пунктом и привели возражения, за что я им благодарен. В этой главе я хочу сообщить о сделанных поправках и ответить на опровержения.
Неясное изложение влечет непонимание
Судя по некоторым откликам, мне не удалось четко изложить свои аргументы.
Второстепенное свойство (accident). В резюме главы 16 я постарался со всей возможной ясностью изложить основные аргументы «СПН». Некоторые, однако, были смущены терминами второстепенное свойство (accident) и несущественный, второстепенный (accidental), которые я использовал в старом употреблении, восходящем к Аристотелю. [4] Под accidental я не имел в виду «случайный» или «относящийся к несчастному случаю», а скорее, «несущественный», «побочный» (incidental) или «принадлежащий» (appurtinent).
Я не хочу порочить роль случайности при разработке программ. Вслед за английским драматургом, автором детективов и теологом Дороти Сэйерс (Dorothy Sayers) я рассматриваю всякую творческую деятельность, как состоящую из: а) формулирования концептуальных конструкций, б) воплощения в реальном материале и в) диалога с пользователем в реальной жизни. [5] Та часть построения программы, которую я назвал сущностью (essence), состоит из умственной работы создания концепутальной конструкции, а та, которую я назвал второстепенной (accident), есть процесс ее воплощения.
Выяснение истины. Мне кажется (хотя не все со мной согласны), что верность центрального аргумента сводится к выяснению ответа на вопрос: какая доля затрат связана с точным и упорядоченным представлением концептуальной конструкции, а какая — с умственными усилиями по изготовлению этих конструкций. Поиск и устранение ошибок попадают в тот или иной раздел в зависимости от того, являются ли ошибки концептуальными (например, пропуск какого-либо особого случая) или ошибками представления (например, ошибка в указателе или распределения памяти).
Мое личное мнение состоит в том, что второстепенная или направленная на представление часть работы сейчас снизилась до половины или менее того от общего объема. Поскольку эта доля является экспериментальной величиной, ее значение, в принципе, можно получить путем измерений. [5] Если это не удается, мою оценку можно поправить на основе более полных и более современных данных, но ни в публичных, ни в частных заявлениях никто не утверждал, что неосновная часть достигает величины 9/10.
«СПН» с несомненностью доказывает, что если доля неосновной части работы меньше 9/10, то даже сведя ее к нулю (что было бы чудом), нельзя получить рост продуктивности на порядок. Атаку необходимо нацелить на существенную часть.
После появления «СПН» Брюс Блум (Bruce Blum) обратил мое внимание на работу 1959 года Герцберга, Мознера и Зейдермана (Herzberg, Mausner, Sayderman). [7] Они находят, что факторы мотивации могут увеличить производительность. С другой стороны, факторы окружения и второстепенные факторы, сколь бы они ни были положительны, не могут этого сделать, но, будучи отрицательными, могут уменьшить производительность. В «СПН» доказывается, что значительная часть прогресса в программной инженерии достигнута за счет устранения влияния следующих отрицательных факторов: крайне неудобных машинных языков, пакетной обработки с долгой оборачиваемостью, слабого инструментария и строгих ограничений на размер памяти.
Являются ли в таком случае безнадежными трудности, связанные с сущностью? Отличная работа «Серебряная пуля есть», написанная Бредом Коксом (Bred Cox) в 1990 году, красноречиво доказывает, что многократно используемые и взаимозаменяемые компоненты должны послужить основой для атаки на концептуальную сущность проблемы. [8] Я охотно соглашаюсь.
Однако Кокс неправильно понимает «СПН» в двух отношениях. Во-первых, он находит в ней утверждение того, что трудности разработки программного обеспечения проистекают из «некоторых порогов технологий, использовавшихся программистами в то время». Я же доказывал, что трудности, связанные с сущностью, являются неотъемлемой частью концептуальной сложности разрабатываемых программных функций во все времена и при любых методах. Во-вторых, он и многие другие прочли в «СПН» утверждение того, что нет никаких надежд успешно справиться со сложностями разработки программ, связанными с вопросами сущности. Это не то, что я имел в виду. Создание концептуальной конструкции действительно имеет внутренне присущие трудности, такие как сложность, согласованность, изменяемость и незримость. Однако неприятности, вызываемые всеми этими трудностями, можно уменьшить.
Сложность разделения на уровни. Например, наиболее серьезной внутренней трудностью является сложность, но она не всегда неизбежна. Значительная часть (но не вся) концептуальной сложности в наших программных конструкциях проистекает от произвольной сложности самих применений. Действительно, Ларс Седаль из MYSYGMA Sohdal and Partners, международной консалтинговой фирмы в области менеджмента, пишет:
Мой опыт показывает, что все сложности, с которыми сталкиваются при разработке систем, являются признаками организационных неполадок. Попытка моделирования практической деятельности программами соответствующей сложности влечет сохранение неразберихи вместо решения проблем.
Стив Лукашик (Steve Lukasik) из Northrop доказывает, что даже организационная сложность, возможно, не является произвольной, а может испытывать воздействие принципов упорядочения:
Я получил образование в облати физики и поэтому вижу, что «сложные» вещи могут быть описаны на языке более простых понятий. Вы можете быть правы, и я не стану утверждать, что все сложные вещи поддаются принципам упорядочения… по тем же правилам доказательства нельзя утверждать, что не поддаются.
…То, что вчера было сложностью, завтра будет в порядке вещей. Сложность беспорядочного движения молекул привела к возникновению кинетической теории газов и открытию трех законов термодинамики. Сейчас программное обеспечение не позволяет увидеть присущие ему принципы упорядочения, но вы как раз и должны объяснить, почему это происходит. Это не проявление моей бестолковости или желания поспорить. Я убежден, что в один прекрасный день «сложность» программного обеспечения будет объяснена на языке каких-нибудь понятий более высокого порядка (инвариантов, как говорят физики).
Я не занимался более глубоким анализом, к которому справедливо призывает Лукашик. Как отрасль науки мы нуждаемся в развитии теории информации для количественной оценки информационного содержания статистических структур, подобно тому, как теория Шэннона делает это для информационных потоков. Это совсем не моя задача. Лукашику я просто отвечу, что сложность системы является функцией мириадов деталей, каждая из которых должна быть точно задана либо с помощью какого-нибудь общего правила, либо подробным описанием, но не просто статистически. Представляется весьма сомнительным, чтобы несогласованные результаты работы многих голов оказались достаточно связными, чтобы быть точно описанными общими правилами.
Значительно большая часть сложности программных конструкций обусловлена, однако, не соответствием внешнему миру, а самой реализацией — структурами данных, алгоритмами, способами коммуникаций. Наращивание программ с помощью больших блоков высокого уровня, созданных когда-то раньше или кем-то другим, помогает избежать целых уровней сложности. «СПН» провозглашает поход на проблему сложности в полной надежде, что можно достичь прогресса. Она выступает за добавление к программной системе необходимой сложности:
• иерархически, располагая модули или объекты по уровням;
• пошагово, что обеспечивает постоянную работоспособность системы.
Анализ Харела
Дэвид Харел (David Harel) в статье 1992 года «Кусая серебрянную пулю» предпринимает самый тщательный анализ «СПН» из всех опубликованных. [9]
Пессимизм против оптимизма и реализма. Харел рассматривает как «СПН», так и статью Парнаса 1984 года «Программные аспекты стратегических оборонительных систем» [10] как «слишком унылые». Он намеревается высветить более яркую сторону проблемы, предпосылая статье подзаголовок «К светлому будущему порграммных разработок». Так же, как и Кокс, Харел считает «СПН» пессимистической, говоря: «Если взглянуть на те же факты с другой точки зрения, возникают более оптимистические выводы». Оба они неправильно воприняли тональность статьи.
Прежде всего, моя жена, коллеги и редакторы считают, что я гораздо чаще впадаю в неоправданный оптимизм, чем в пессимизм. В конце концов я по происхождению программист, а оптимизм — это профессиональная болезнь данного ремесла.
В «СПН» прямо сказано: «Вглядываясь в предстоящее десятилетие, мы не видим серебряной пули… Однако скептицизм не есть пессимизм… Нет царского пути, но путь есть». Она предсказывает, что нововведения, происходящие в 1986 году, будучи разработаны и использованы, в совокупности действительно позволят достичь роста производительности на порядок. Десятилетие 1986-1996 подходит к концу, и это предсказание оказывается, скорее, слишком оптимистичным, а не мрачным.
Даже если бы все без исключения считали «СПН» пессимистической, что в этом худого? Является ли утверждение Эйнштейна о том, что ничего не может перемещаться со скоростью, большей скорости света, «унылым» и «мрачным»? А как насчет результатов Геделя о том, что некоторые вещи невычислимы? «СПН» пытается утверждать, что «сама сущность программного обеспечения делает маловероятным открытие «серебряных пуль» когда-либо в будущем». Турский в своем отличном ответном докладе на конференции IFIP красноречиво заявил:
Из всех попыток науки продвинуться в ложном направлении наиболее возвышенны те, которые были направлены на поиск философского камня — вещества, с помощью которого предполагалось обращать простые металлы в золото. Высшая цель алхимии, к которой с рвением стремились поколения исследователей, щедро финансировавшиеся светскими и духовными правителями, — это в чистом виде стремление принимать желаемое за действительное и общепринятое мнение, что вещи таковы, какими мы хотели бы их видеть. Это очень по-человечески. Нужно сделать над собой большое усилие, чтобы смириться с существованием неразрешимых проблем. Стремление вопреки всему найти выход, даже когда доказано, что его не существует, очень и очень сильно. И в большинстве своем мы с большим сочувствием относимся к этим храбрецам, которые пытаются достичь невозможного. Это продолжается и по сей день. Пишутся сочинения о квадратуре круга. Стряпаются лосьоны для восстановления утраченных волос — и неплохо продаются. Рождаются методы повышения производительности программирования — и хорошо расходятся.
Мы слишком часто склонны доверять своему оптимизму (или эксплуатировать оптимистические надежды своих спонсоров). Мы слишком часто не хотим прислушиваться к голосу рассудка и обращаем много внимания на продавцов панацей, поющих голосами сирен. [11]
Турский, как и я, предупреждает, что мечтательность тормозит движение вперед и ведет к пустой трате сил.
«Мрачные» темы. Харел считает, что мрачность «СПН» придают три темы:
• Резкое разделение между сущностью и второстепенным.
• Изолированное рассмотрение каждого кандидата в «серебряные пули».
• Прогноз лишь на ближайшие 10 лет, а не на срок, в течение которого можно ожидать «существенных улучшений».
Что касается первого, то в это вся соль статьи. Я по-прежнему считаю, что такое разделение необходимо для понимания того, почему трудно создавать программное обеспечение. И это верное указание, куда должен быть направлен удар.
Что касается изолированного рассмотрения кандидатов в «серебряные пули», то это
правда. Разные кандидаты предлагались поочередно и непомерными претензиями на
собственное всесилие. Правомерно и рассматривать их поочередно. Я возражаю не
против самих технологий, но против ожидания от них чуда. Гласс, Весси и Конджер
(Glass, Vessey, Conger) в своей статье 1992 года представили многочисленные
свидетельства того, что бесполезные поиски серебряной пули все еще продолжаются. [12]
Что касается выбора в качестве периода предсказаний 10, а не 40 лет, то частично это признание того, что наши предсказания на больший срок никогда не были удачными. Кто из нас в 1975 году предсказал микрокомпьютерную революцию 80-х?
Есть и другие причины ограничиться десятилетием: все кандидаты претендовали на получение результатов немедленно. Я не помню ни одного, который бы сказал: «Если сегодня вы сделаете инвестиции в предлагаемое мной средство, то по прошествии 10 лет начнете пожинать плоды». Более того, за десятилетие соотношение производительность/цена для компьютеров выросло, наверное, в сотни раз, и неизбежно подсознательно производится сравнение, которое совершенно недопустимо. Мы наверняка достигнем большего прогресса за предстоящие 40 лет. Рост за 40 лет на порядок едва ли покажется чудом.
Мысленный эксперимент Харела. Харел предлагает мысленный эксперимент, в котором «СПН» была написана в 1952 году, а не в 1986, но содержала бы те же утверждения. Он хочет использовать это в качестве доказательства от противного в борьбе против попыток отделить сущность от акциденции.
Это доказательство неверно. Во-первых, «СПН» начинается с утверждения, что для программирования в 1950-х характерно значительное преобладание трудностей в акциденциях над трудностями в сущности. Этого преобладания больше не существует, что привело к росту производительности на порядки величин. Переносить это доказательство на 40 лет назад бессмысленно: никто не стал бы в 1952 году утверждать, что не трудности акциденций ответственны за большую часть затрачиваемых усилий.
Во-вторых, Харел неточно представляет положение дел в 1950-х:
Это было время, когда вместо того, чтобы разрабатывать большие сложные системы, программисты писали обычные однопользовтельские программы, которые на современных языках программирования заняли бы 100-200 строк, и которые должны были выполнять скромные алгоритмические задачи. При существовавших тогда технологиях и методологиях такие задачи тоже были очень трудными. Сплошь и рядом были неудачи, ошибки, нарушение сроков.
Затем он описывает, как за последние 25 лет упомянутые неудачи, ошибки, нарушенные сроки в обычных маленьких одновользовательских программах были улучшены на порядок.
Но в действительности в 1950-х годах вершиной технологии были не маленькие однопользовательские программы. В 1952 году Univac был занят обработкой данных переписи 1950 года с помощью сложной программы, которую разрабатывали примерно восемь программистов. [13] Другие машины применялись в химической динамике, расчетах рассеяния нейтронов, расчетах полета ракет и т.д. [14] Повседневно использовались ассемблеры, перемещающие компоновщики и загрузчики, системы интерпретации с плавающей точкой и т.п. [15]
К 1955 году уже создавались программы для бизнеса объемом от 50 до 100 человеко-лет. [16] В 1956 году на заводе Дженерал Электрик в Льюисвилле работала программа размером более 80 000 слов. В 1957 году в течение уже двух лет в системе противовоздушной обороны работал компьютер SAGE ANFSQ/7, и на 30 площадках действовала система реального времени, использовавшая телекоммуникации и дублирование в целях отказоустойчивости, объемом 75 000 команд. [17] Едва ли можно придерживаться мнения, что развитие технологий для однопользовательских программ — главная характеристика усилий в технике программного обеспечения после 1952 года.
ВОТ ОНА. Харел продолжает, предлагая собственную серебряную пулю, технологию моделирования под названием «Vanilla Framework» («ванильная структура»). Сам подход описан недостаточно подробно, чтобы его можно было оченить, но есть ссылка на статью и технический отчет, который в свое время должен быть опубликован в виде книги. [18] Моделирование касается сущности, правильной разработки и отладки понятий, поэтому технология может оказаться революционной. Надеюсь, что это так. Кен Брукс сообщает, что эта методология оказалась полезной, когда он попытался применить ее к реальной задаче.
Незримость. Харел энергично доказывает, что значительная часть концептуальной конструкции программного обеспечения является по своей природе топологической задачей, и эти взаимосвязи находят соответствие в пространственно-графических представлениях:
Использование подходящего визуального формализма может оказать заметное воздействие на инженеров и программистов. Более того, это воздействие не ограничивается областью акциденций, было обнаружено положительное влияние на качество и быстроту самого их мышления. В будущем успехи в разработке систем будут связаны с визуальными представлениями. Сначала мы будем создавать концепции с помощью «правильных» объектов и взаимосвязей, затем формулировать наши концепции как последовательный ряд все более обстоятельных моделей с использованием подходящей комбинации визуальных языков. Именно комбинации, поскольку модели систем имеют несколько граней, каждая из которых вызывает в воображении различные виды образов.
…Некоторые грани процесса моделирования не столь легко поддаются хорошей визуализации. Например, алгоритмические операции над переменными и структурами данных, возможно, останутся текстуальными.
Здесь наши позиции близки. Я доказывал, что структура программного обеспечения не является трехмерной, поэтому не существует естественного отображения концептуального проекта в диаграмму в пространстве как двух, так и большего числа измерений. Харел допускает, и я согласен, что требуется много диаграмм, каждая из которых охватывает какую-то одну сторону, а некоторые аспекты вообще плохо отображаются на диаграммах.
Я вполне разделяю его энтузиазм по поводу использования диаграмм как вспомогательного средства при обдумывании и проектировании. Долгое время я любил задавать кандидатам на работу программистом вопрос: «Где находится следующий ноябрь?». Если вопрос кажется загадочным, то в другом виде: «Какова ваша мысленная мысленная модель календаря?» У действительно хороших программистов хорошее чувство пространства, у них обычно есть геометрическая модель времени, и они часто без труда понимают первый вопрос. Их модели очень индивидуальны.
Точка зрения Джонса: производительность приходит вслед за качеством
Каперс Джонс (Capers Jones) сначала в серии служебных записок, а затем в отдельной книге демонстрирует глубокую интуицию, отмеченную несколькими моими корреспондентами. «Статья «СПН», как и многие в то время, сосредоточилась на производительности — выходе программной продукции на единицу входных затрат», — говорит Джонс. — «Нет, сосредоточьтесь на качестве, а производительность придет следом.» [19] Он утверждает, что дорогостоящие и нарушившие сроки проекты требуют больше всего дополнительных усилий и времени для поиска и устранения ошибок в спецификациях, в проекте, в разработке. Он приводит данные, свидетельствующие о сильной корреляции между отсутствием систематического контроля качества и срывом графика работ. Я им вполне верю. Бём (Boehm) указывает, что производительность снова падает, когда преследуется исключительно высокое качество, как было в программах IBM для космического челнока.
Аналогичным образом, Коки (Coqui) утверждает, что принципы систематической разработки программного обеспечения явились ответом на озабоченность не столько производительностью, сколько качеством (в особенности, стремлением избежать крупных катастроф).
Но обратите внимание: целью применения инженерных принципов к разработке программного обеспечения в 1970-х годах было поднять качество, тестируемость, устойчивость и предсказуемость программных продуктов, а не обязательно производительность труда программистов.
Движущей силой использования при разработке программ принципов программной инженерии было опасение крупных аварий, к которым могла привести разработка все более сложных систем неуправляемыми художниками. [20]
Так что же случилось с производительностью?
Производительность в цифах. Цифры, характеризующие производительность, очень тяжело определить, калибровать и найти. Каперс Джонс считает, что для двух одинаковых программ на Cobol, написанных с интервалом в 10 лет — с применением структурного программирования и без него — разница в производительности троекратная.
Эд Йордон (Ed Yourdin) утверждает: «По моим наблюдениям, благодаря рабочим станциям и программным инструментам производительность увеличилась в пять раз.» Том Демарко (Tom DeMarco) считает, что «ваше ожидание десятикратного роста производительности за 10 лет благодаря целому набору технологий было оптимистичным: мне неизвестны организации, добившиеся роста
производительности на порядок.»
Программа в упаковке: покупайте, не надо разрабатывать. Одна из оценок «СПН» оказалась, я думаю, правильной: «Возникновение массового рынка является… наиболее глубокой долгосрочной тенденцией в разработке программного обеспечения». С точки зрения науки, программное обеспечение для массового рынка образует практически новую отрасль в сравнении с разработкой заказных программ как внутри фирмы, так и сторонними организациями. Когда счет проданных пакетов идет на миллионы или хотя бы на тысячи, главными проблемами становятся качество, своевременность, технические характеристики и стоимость поддержки, а не стоимость разработки, которая имеет такое большое значение при разработке заказных систем.
Электроинструмент для ума. Лучший способ повысить производительность труда программистов информационно-управляющих систем — это пойти в ближайший компьютерный магазин и купить уже готовым то, что они собираются разработать. Это не шутка: доступность дешевых и мощных коробочных программ удовлетворила многие из потребностей, ранее удовлетворявшихся заказными программами. Эти электроинструменты для ума больше похожи на электрическте дрели, пилы и шлифовальные машины, чем на большие и сложные производственные станки. Интеграция их в совместимые и перекрестно-связанные наборы, такие как Microsoft Works или лучше интегрированный ClarisWorks, обеспечивает огромную гибкость. И подобно домашней коллекции инструмента, в результате частого использования набольшого набора для разных задач вырабатываются привычные навыки. Такой инструмент подчеркивает простоту использования обычным пользователем, даже не профессионалом.
Иван Селин (Ivan Selin), глава American Management Systems писал мне в 1987 году:
Я хочу придраться к вашему утверждению, что в действительности пакеты не настолько изменились… Я думаю, что вы слишком легко отбросили главные следствия вашего замечания, что (программные пакеты) «могут быть немного более общими и немного лучше настраиваемыми, чем раньше, но не намного». Даже принимая это заявление за чистую монету, я полагаю, что пользователи расценивают пакеты, как обладающие более широкими возможностями и легче настраиваемые, и что такое восприятие делает пользователей более податливыми перед пакетами. В большинстве случаев, известных моей компании, не программисты, а (конечные) пользователи неохотно пользуются пакетами, покскольку думают, что лишатся важных возможностей и функций, а потому возможность легкой настройки весьма повышает для них привлекательность продукта.
Я думаю, что Селин совершенно прав: я недооценил как степень настраиваемости пакета, так и важность этого фактора.
Объектно-ориентированное программирование: а медна пуля не подойдет?
Разработка из больших частей. Если осуществлять сборку из частей, которые достаточно сложны и имеют однородные интерфейсы, можно быстро образовывать довольно богатые структуры.
Согласно одному из взглядов на объектно-ориентированное программирование эта дисциплина осуществляет модульность и чистые интерфейсы. Другая точка зрения подчеркивает инкапсуляцию — невозможность увидеть и еще менее изменить внутреннюю структуру детали. Еще одна точка зрения отмечает наследование и сопутствующую ему иерархическую структуру классов с виртуальными функциями. И еще один взгляд: важнейшей является сильная абстрактная типизация данных вместе с гарантиями, что конкретный тип данных будет обрабатываться только применимыми к нему операциями.
В настоящее время не нужен весь пакет Smalltalk или C++, чтобы использовать любой из этих дисциплин — многие из них поглотили объектно-ориентированные технологии. Объектно-ориентированный подход привлекателен, как поливитамины: одним махом (т.е. переподготовкой программиста) получаешь все. Очень многообещающая концепция.
Почему объектно-ориентированная технология медленно развивалась? В течение девяти лет после выхода «СПН» надежды неуклонно росли. Почему развитие было таким медленным? Теорий много. Джеймс Коггинс, в течение четырех лет ведущий колонку в The C++ Report, дает такое объяснение:
Проблема в том, что программисты, работающие в ООП, экспериментировали с кровосмесительными приложениями и были нацелены на низкий уровень абстракции. Например, они строили такие классы, как «связанный список» вместо «интерфейс пользователя», или «луч радиации», или «модель из конечных элементов». К несчастью, строгая проверка типов, которая помогает программистам C++ избегать ошибок, одновременно затрудняет построение больших объектов из маленьких. [21]
Он возвращается к фундаментальной проблеме программирования и доказывает, что один из способов удовлетворить потребность в программном обеспечении — увеличить численность образованной рабочей силы путем подготовки и привлечения наших клиентов. В пользу нисходящего проектирования приводятся такие аргументы:
Если мы проектируем крупные классы, представляющие концепции, с которыми наши клиенты уже работают, то они в состоянии понимать и критиковать проект по мере его развития, а также вместе с нами разрабатывать контрольные примеры. Офтальмологов, с которыми я работаю, не волнует организация стека; их волнует описание формы роговицы с помощью полиномов Лежандра. Маленькая инкапсуляция дает и маленькую выгоду.
Дэвид Парнас, чья статья была одним из источников идей объектно-ориентированного программирования, смотрят на вещи по иному. Он писал мне:
Ответ прост. Это из-за привязанности ООП к сложным языкам. Вместо объяснения людям, что ООП является видом проектирования, и вооружения их принципами проектирования, их учили, что ООП — это использование определенного инструмента. Любыми срадствами можно писать и плохие, и хорошие программы. Если не учить людей проектированию, то языки не имеют большого значения. Результатом будут плохие разработки с помощью этих языков и малая выгода. А если выгода невелика, то ООП не войдет в моду.
Расходы сейчас, прибыль потом. По моему мнению, у объектно-ориентированных методологий особенно тяжелый случай болезни, характерной для многих усовершенствований в методологии. Весьма существенны предварительные издержки — в основном, чтобы научить программистов мыслить совершенно по новому, а также на преобразование функций в обобщенные классы. Выгоды, которые я считаю реальными, а не чисто предположительными, достигаются во время всего цикла разработки, но настоящая окупаемость происходит при разработке последующих программ, расширении и сопровождении. Коггинс коворит: «Объектно-ориентированное программирование не ускорит разработку первого проекта, так же как и второго. А вот пятый проект из того же семейства будет сделан очень быстро.» [22]
Рисковать реальными начальными деньгами ради предполагаемых, но неопределенных прибылей в будущем — это то, чем инвесторы занимаются изо дня в день. Однако во многих программирующих организациях менеджерам требуется для этого смелость — качество более редкое, чем компетенция в технических вопросах или административное мастерство. Я полагаю, что крайняя степень авансироания расходов и откладывания прибыли является самым существенным фактором, замедляющим принятие О-О технологий. Но даже в таких условиях C++, похоже, уверенно вытесняет C во многих организациях.
Что с повторным использованием?
Лучший способ справиться с разработкой части программной системы, относящейся к ее сущности — это вообще ее не разрабатывать. Пакеты программ — один из способов сделать это. Другой способ — повторное использование. Действительно, одной из наиболее привлекательных черт объектно-ориентированного программирования является обещание простоты повторного использования классов в сочетании с легкостью настройки благодаря наследованию.
Как часто бывает, после получения некоторого опыта работы по новой технологии обнаруживается, что она не так проста, как казалось на первый взгляд.
Конечно, программисты всегда повторно использовали собственные разработки. Джонс пишет:
У наиболее опытных программистов есть свои личные библиотеки, позволяющие им при разработке новых программ повторно использовать до 30% кода по объему. На корпоративном уровне повторное использование приближается к 75% по объему и требует специальных библиотек и администрирования. Повторное использование кода в корпоративных масштабах требует изменений в бухгалтерии проекта и методах измерения работы. [23]
У. Хуан (W. Huang) предложил организацию программного производства с матричной структурой управления функциональными специалистами, чтобы держать под контролем их естественную склонность к повторному использованию собственного кода. [24]
Ван Шнайдер (Van Snyder) из JPL напоминает мне, что в кругах разработчиков математического программного обеспечения существует давняя традиция повторного использования программ:
Мы полагаем, что препятствия к повторному использованию возникают не со стороны производителя, а со стороны потребителя. Если разработчик программного обеспечения — потенциальный потребитель стандартных программных компонентов — считает, что найти и проверить нужный компонент дороже, чем написать его заново, значит, будет написан новый компонент, дублирующий прежний. Обратите внимание, мы сказали «считает» — реальная стоимость повторной разработки не имеет значения.
Повторное использование кода имеет успех при разработке математических программ. Причин этому две: 1) это магия, требующая огромного интеллектуального вклада в каждую строчку кода, и 2) существует богатая и стандартная терминология, а именно — математика, для описания функциональности любых компонентов. Поэтому повторно разработать математический компонент стоит дорого, а разобраться в функциональности стоит дешево. Давняя традиция публикации и сбора алгоритмов профессиональными журналами и предложения их по умеренной цене, а также коммерческое предложение высококачественных алгоритмов по несколько более высокой, но все же скромной цене, делают поиск требуемых компонентов проще, чем в других областях, где часто невозможно точно и сжато описать требуемое. Благодаря совместному действию этих факторов повторное использование математических программ более привлекательно, чем повторное их изобретение.
Такое же явление повторного использования обнаруживается и в других сообществах, например, в разработке программ для атомных реакторов, моделирования климата, моделирования океанов — по тем же самым причинам. Каждое из этих сообществ выросло на одних и тех же учебниках, с одной и той же системой обозначений.
**Как сегодня обстоят дела с повторным использованием на корпоративном уровне? Проведено множество исследований, а вот практикуется в США относительно мало. Что же касается повторного использования за рубежом, то тут имеют место неправдоподобные отчеты. [25]
Джонс сообщает, что все клиенты его фирмы, у которых более 5000 программистов, проводят формальные исследования повторной используемости, в то время как из числа клиентов с 500 и менее программстами это делает менее 10 процентов. [26] По его сообщению, в отраслях с высоким потенциалом повторного использования исследования (не реализация) «ведутся активно и энергично, даже если не вполне успешно». Эд Йордон сообщает о программной фирме в Маниле, в которой 50 программистов из общего числа 200 заняты только разработкой повторно используемых модулей для использования всеми остальными, и что в тех случаях, которые он видел, принятие этой технологии было вызвано организационными, а не техническими факторами — например, системой поощрений.
Демарко сообщает мне, что наличие массовых рыночных пакетов и возможность предоставления ими общих функций, таких как системы баз данных, существенно снизили как настоятельность, так и предельную полезность повторного использования модулей собственных приложений. «Повторно используемые модули имели тенденцию в конце концов становиться общими функциями.»
Парнас пишет следующее:
Повторное использование — это то, о чем легче говорить, чем осуществить. Для него требуются как хорошее проектирование, так и очень хорошая документация. Даже когда мы видим хорошее проектирование, что по-прежнему не часто, без хорошей документации компоненты не будут использоваться повторно.
Кен Брукс сообщает, что трудно рассчитать, какая степень обобщенности окажется необходимой: «Мне приходится менять вещи, даже в пятый раз используя собственную библиотеку пользовательских интерфейсов.»
Реально повторное использование только начинается. Джонс сообщает, что на открытом рынке есть несколько модулей с повторно используемым кодом по цене от 1 до 20 процентов от обычной стоимости разработки. [27] Демарко говорит:
Меня все более обескураживает вся эта история с повторным использованием. Практически отсутствует теорема существования для повторного использования. Время подтвердило, что сделать вещи повторно используемыми стоит дорого.
Йордон дает оценку того, сколько это стоит: «Хорошее эмпирическое правило говорит, что повторно используемые компоненты потребуют вдвое больших затрат, чем «одноразовые» компоненты.» [28] Я рассматриваю эту цену как величину затрат на запуск компонентов в производство, обсуждавшуюся в главе 1, поэтому я оцениваю рост затрат как троекратный.
Конечно, мы видим различные формы и варианты повторного использования, но оно далеко не так широко применяется, как мы предполагали. Предстоит еще многое понять.
Понимание больших словарей: неожиданная проблема повторного использования, которую можно было предвидеть
Чем выше уровень, на котором осуществляется мышление, тем более многочисленны примитивные составляющие мысли, с которыми приходится иметь дело. Так, языки высокого уровня гораздо сложнее машинных языков, а естественные языки еще более сложны. У языков высокого уровня больше словари, более сложный синтаксис и более строгая семантика.
Как научная дисциплина, мы не взвесили последствия этого факта для повторного использования программ. Чтобы повысить качество и производительность, мы хотим строить программы из частей с отлаженными функциями, которые существенно выше по уровню, чем операторы языков программирования. Поэтому, делаем ли мы это с помощью библиотек классов или библиотек процедур, нам придется столкнуться с резким увеличением размеров наших словарей программирования. Изучение словаря составляет значительную часть препятствий к повторному использованию.
На сегодняшний день есть библиотеки классов, насчитывающие свыше 3000 членов. Многие объекты требуют задания от 10 до 20 параметров и переменных-переключателей. Всякий, использующий такую библиотеку, должен изучить синтаксис (внешние интерфейсы) и семантику (подробное поведение функции) ее членов, если собирается полностью реализовать потенциал повторного использования.
Эта задача вовсе не безнадежна. Обычно человек использует около 10000 слов родного языка, образованные люди — значительно больше. Каким-то образом мы обучаемся синтаксису и тонким семантическим различиям. Мы правильно опеределяем различия между словами гигантский, огромный, пространный, колоссальный, громадный — никто не говорит о колоссальных пустынях и пространных слонах.
Нужны дополнительные исследования, чтобы можно было применить к проблеме повторного использования программ существующие знания о том, как люди овладевают языком. Некоторые выводы непосредственно очевидны:
• Обучение происходит в контексте предложения, поэтому нужно публиковать многочисленные примеры составных продуктов, а не просто библиотеки составляющих частей.
• Человек запоминает только правописание. Синтаксис и семантика изучаются постепенно, в контексте, путем применения.
• Человек группирует правила соединения слов в синтаксические классы, а не в совместимые подмножества объектов.
Чистый итог по пулям: положение прежнее
Итак, мы возвращаемся к основам. Сложность — это то, чем мы занимаемся, и сложность — это то, что нас ограничивает. Р. Л. Гласс (R. L. Glass) писал в 1988 году, точно суммируя мои взгляды 1995 года:
Так что же в итоге сообщили нам Парнас и Брукс? Что разработка программ является концептуально сложным занятием. Что волшебные решения не лежат за каждым углом. Что занимающимся этим делом пора изучить достижения, имеющие эволюционный характер, а не ждать революцию и не надеяться на нее.
Некоторые считают это безрадостной картиной. Это те, кто полагал, что вот-вот наступит прорыв.
Но некоторые из нас — достаточно сварливые, чтобы считать себя реалистами, — относятся к этому как к глотку свежего воздуха. Наконец-то можно сосредоточиться на чем-то более близком к жизни, чем журавль в небе. Теперь, вероятно, мы сможем заняться постепенными усовершенствованиями производства программного обеспечения, которые действительно достижимы, а не ждать прорывов, которые вряд ли когда-либо произойдут. [29]
Глава 18 Заявления «Мифического человеко-месяца»: правда или ложь?
Краткость очень полезна,
Когда нас понимают или не понимают.
СЭМЮЭЛ БАТЛЕР, «ГУДИБРАС»
Сегодня о технике разработки программного обеспечения известно значительно больше, чем в 1975 году. Какие из утверждений, содержащихся в первом издании 1975 года, подтвердились опытом и данными? Какие были опровергнуты? Какие устарели в нашем изменчивом мире? Чтобы вам легче было судить, здесь, в виде сводки, приведены важнейшие утверждения книги 1975 года, которые я считал верными: факты и извлеченные из опыта практические правила, приведенные с сохранением изначального смысла. (Можно задаться вопросом: если это все, что было сказано в первоначальном издании, почему тогда это заняло так много места?) В скобках приведены свежие комментарии.
Большинство этих предложений можно проверить на практике. Излагая их в сжатой форме, я надеюсь сконцентрировать мысли читателя, измерения и комментарии.
Глава 1. Смоляная яма
1.1 Для создания системного программного продукта требуется примерно в девять раз больше усилий по сравнению с составляющими его программами, написанными отдельно для частного использования. По моей оценке, превращение программы в продукт вводит коэффициент, равный трем; проектирование, интеграция и тестирование компонентов, которые должны образовать согласованную систему, также вводит коэффициент, равный трем; все эти составляющие стоимости существенно независимы друг от друга.
1.2 Занятие программированием «отвечает глубокой внутренней потребности в творчестве и удовлетворяет чувственные потребности, которые есть у всех у нас», доставляя пять видов радости:
• Радость, получаемая при создании чего-либо своими руками.
• Удовольствие создавать вещи, которые могут быть полезны другим людям.
• Очарование создания сложных головоломных объектов, состоящих из взаимодействующих движущихся частей.
• Радость, получаемая от неизменного узнавания нового, неповторяемости задачи.
• Удовольствие от работы со столь податливым материалом — чистой мыслью, который, тем не менее, существует, движется и работает так, как не могут словесные объекты.
1.3 В то же время этому занятию присущи и огорчения:
• При изучении программирования труднее всего привыкнуть к требованию совершенства.
• Постановка задач осуществляется другими людьми и приходится зависеть от вещей (особенно, программ), которые нельзя контролировать; полномочия не соответствуют ответственности.
• Страшно только на словах: фактическая власть приобретается как следствие успешного выполнения задач.
• Программный проект приближается к окончательному виду тем медленнее, чем ближе окончание, хотя кажется, что к концу сходимость должна быть более быстрой.
• Программному продукту грозит устаревание еще до его завершения. Настоящий тигр — не пара бумажному, если требуется реальное использование.
Глава 2. Мифический человеко-месяц
2.1 Программные проекты чаще проваливаются из-за нехватки календарного времени, чем по всем остальным причинам, вместе взятым.
2.2 Чтобы приготовить вкусную пищу, нужно время; некоторые задачи нельзя ускорить, не испортив результат.
2.3 Все программисты являются оптимистами: «Все будет хорошо».
2.4 Поскольку программист работает с чистыми идеями, мы не ожидаем особых трудностей при реализации.
2.5 Но сами наши идеи бывают ошибочными — отсюда и ошибки в программах.
2.6 Наши методы оценивания, основанные на учете затрат, смешивают затраты с полученным результатом. Человеко-месяц является ошибочным и опасным заблуждением, поскольку предполагает, что месяцы и количество людей можно менять местами.
2.7 Разделение задачи между несколькими людьми вызывает дополнительные затраты на обучение и обмен информацией.
2.8 Мое практическое правило: 1/3 времени — на проектирование, 1/6 — на написание программы, 1/4 — на тестирование компонентов и 1/4 — на системное тестирование.
2.9 Как научной дисциплине нам не хватает методов оценки.
2.10 Поскольку мы не уверены в своих оценках сроков работы, нам часто не достает смелости упрямо отстаивать их под нажимом руководства и клиентов.
2.11 Закон Брукса: если проект не укладывается в сроки, то добавление рабочей силы задержит его еще больше.
2.12 Добавление рабочей силы увеличивает общий объем затрат тремя путями: труд по перекраиванию задач и происходящее при этом нарушение работы, обучение новых людей, дополнительное общение.
Глава 3. Операционная бригада
3.1 Самые лучшие программисты-профессионалы в 10 раз продуктивнее слабых при равной подготовке и двухлетнем стаже (Сакман, Грант и Эриксон).
3.2 Данные Сакмана, Гранта и Эриксона не выявили корреляции между опытом и продуктивностью. Я думаю, что это всегда так.
3.3 Лучше всего иметь маленькую активную команду — как можно меньше мыслителей.
3.4 Часто лучше всего, если команда состоит из двух человек, один из которых является лидером. (Обратите внимание, как Богом задуман брак.)
3.5 Для создания действительно крупных систем маленькая активная команда работает слишком медленно.
3.6 Опыт разработки большинства действительно больших систем показывает, что подход к ускорению с позиций грубой силы оказывается дорогостоящим, медленным, неэффективным и приводит к появлению систем, не являющихся концептуально целостными.
3.7 Организация по типу хирургических бригад с главным программистом предлагает способ достижения целостности продукта благодаря его проектированию в нескольких головах и общей продуктивности благодаря наличию многочисленных помощников при радикально сокращенном обмене информацией.
Глава 4. Аристократия, демократия и системное проектирование
4.1 «Концептуальная целостность является наиболее важным соображением при проектировании систем.»
4.2 «Окончательную оценку проекту системы дает отношение функциональности к сложности концепций», а не только богатство функций. (Это соотношение является мерой простоты использования, пригодной как для простого, так и для сложного использования.)
4.3 Для достижения концептуальной целостности проект должен создаваться одним человеком или группой единомышленников.
4.4 «Отделение разработки архитектуры от реализации является эффективным способом достижения концептуальной целостности при работе над очень большими проектами.» (И маленькими тоже.)
4.5 «Если вы хотите, чтобы система обладала концептуальной целостностью, кто-то один должен взять руководство концепциями. Это аристократизм, который не нуждается в извинениях.»
4.6 Дисциплина полезна искусству. Получение архитектуры извне усиливает, а не подавляет творческую активность группы исполнителей.
4.7 Концептуально целостные системы быстрее разрабатываются и тестируются.
4.8 Проектирование архитектуры, разработку и реализацию можно в значительной мере осуществлять параллельно. (Проектирование аппаратного и программного обеспечения тоже могут проходить параллельно.)
Глава 5. Эффект второй системы
5.1 Связь, установленная на ранних этапах и продолжающаяся непрерывно, может дать архитектору верную оценку стоимости, а разработчику — уверенность в проекте, не снимая при этом четкого разграничения сфер ответственности.
5.2 Как архитектору успешно влиять на реализацию:
• Помнить, что ответственность за творчество, проявляемое при реализации, несет строитель, поэтому архитектор только предлагает.
• Всегда быть готовым предложить некоторый способ реализации своих замыслов и быть готовым согласиться с любым другим способом, который не хуже.
• Выдвигая такие предложения, действовать тихо и частным образом.
• Не рассчитывать на признательность за предложенные усовершенствования.
• Выслушивать предложения разработчиков по усовершенствованию архитектуры.
5.3 Из всех проектируемых систем наибольшую опасность представляет вторая по счету; обычно ее приходится перепроектировать заново.
5.4 OS/360 является ярким примером эффекта второй системы. (Похоже, что Windows NT — это пример для 1990 года.)
5.5 Достойной внимания практикой является предварительное назначение функциям величин в байтах и микросекундах.
Глава 6. Донести слово
6.1 Даже в большой команде проектировщиков оформление результатов нужно поручить одному или двум людям, чтобы обеспечить согласованность мини-решений.
6.2 Важно явно определить те части архитектуры, которые не прописаны столь же тщательно, как остальные.
6.3 Необходимо иметь как формальное описание проекта — для точности, так и текстуальное — для понимания.
6.4 Либо формальное, либо текстуальное определения выбираются в качестве стандарта, при этом второе определение является производным. Каждое определение может выступать в любой из ролей.
6.5 Реализация, в том числе модель, может служить определением архитектуры; такое использование имеет существенные недостатки.
6.6 Прямое включение является очень искусным приемом для осуществления стандартов архитектуры в программном обеспечении (в аппаратном обеспечении — тоже: возьмите интерфейс Mac WIMP, встроенный в ROM).
6.7 Архитектурное «определение будет яснее, а (архитектурная) дисциплина крепче, если изначально строятся как минимум две реализации».
6.8 Важно, чтобы архитектор в телефонных разговорах отвечал исполнителям на их вопросы; обязательно нужно регистрировать эти разговоры в журнале и доводить их до общего сведения. (Сейчас для этого предпочтительнее электронная почта.)
6.9 «Лучший друг менеджера проекта — его постоянный противник, независимая организация, тестирующая продукт.»
Глава 7. Почему не удалось построить Вавилонскую башню?
7.1 Проект Вавилонской башни провалился из-за недостатка обмена информацией и, как следствие, организации.
Обмен информацией
7.2 «Отставание графика, несоответствие функциональности, системные ошибки — все это из-за того, что левая рука не знает, что творит правая.» Предположения команд расходятся.
7.3 Бригады должны поддерживать между собой связь всеми возможными способами: неформально, путем регулярных совещаний по проекту с техническими отчетами и через общую рабочую тетрадь проекта. (А также электронную почту.)
Рабочая тетрадь проекта
7.4 Рабочая тетрадь проекта есть «не столько отдельный документ, сколько структура, налагаемая на все документы, которые, так или иначе, будут созданы во время выполнения проекта.»
7.5 «Все документы проекта должны входить в эту структуру (рабочей тетради).»
7.6 Структуру рабочей тетради нужно проектировать тщательно и рано.
7.7 Правильное структурирование текущей документации с самого начала позволяет «составленные позднее документы оформить в виде отрывков, которые вписываются в эту структуру» и улучшает руководства по продукту.
7.8 «Каждый член команды должен видеть все материалы (рабочей тетради).» (Сейчас я бы сказал «должен иметь возможность видеть». Например, достаточно WWW-страниц.)
7.9 Своевременное обновление может иметь критическое значение.
7.10 Необходимо, чтобы внимание пользователя было особо привлечено к изменениям, произошедшим после его последнего прочтения, причем с пометками об их значении.
7.11 Рабочая тетрадь проекта OS/360 начиналась с бумажного варианта с последующим переходом на микрофиши.
7.12 Сегодня (и даже в 1975 году) общий электронный блокнот является значительно лучшим, более дешевым и простым механизмом достижения этих целей.
7.13 Необходимо помечать текст с помощью полосок изменения дат пересмотра (или их функционального эквивалента). Так же необходима сводка изменений по типу стека.
7.14 Парнас старается доказать, что стремление к тому, чтобы каждый видел все, совершенно ошибочно: части должны инкапсулироваться таким образом, чтобы никому не требовалось или не разрешалось видеть содержание каких-либо частей, кроме своих собственных, а видны могут быть только интерфейсы.
7.15 Предложение Парнаса — путь к катастрофе. (Парнас вполне убедил меня в обратном, и я совершенно изменил свое мнение.)
Организация
7.16 Задачей организации является сокращение объема необходимого общения и согласования.
7.17 Организация заключает в себе разделение труда и специализацию функций с целью сократить обмен информацией.
7.18 Обычная древовидная организация отражает структурный принцип власти, который показывает, что нельзя одновременно служить двум хозяевам.
7.19 Структура обмена информацией в организации является не деревом, а сетью, и нужно придумать различные виды специальных организационных механизмов («пунктирные линии»), чтобы преодолеть дефицит обмена информацией в древовидной организации.
7.20 В каждом субпроекте есть две руководящие должности: продюсер и технический директор, или архитектор. Их функции совершенно различны и требуют разных способностей.
7.21 Вполне эффективным может быть любой тип взаимоотношений между этими двумя должностями:
• Это может быть одно лицо.
• Продюсер может быть начальником, а директор — его правой рукой.
• Директор может быть начальником, а продюсер — его правой рукой.
Глава 8. Объявляя удар
8.1 Нельзя точно оценить общий объем или график работ программного проекта, просто оценив время написания программы и умножив на некоторые коэффициенты для остальных частей задания.
8.2 Данные, относящиеся к созданию небольших отдельных систем, не применимы к проектам создания программных комплексов.
8.3 Объем работ растет как степенная функция размера программы.
8.4 Некоторые опубликованные исследования показывают, что показатель степени примерно равен 1,5. (Результаты Бёма с этим не согласуются и меняются от 1,05 до 1,2.) [1]
8.5 Данные Портмана по ICL показывают, что занятые на полный рабочий день программисты только около 50 процентов времени занимаются программированием и отладкой, а остальное время занимают разные дополнительные задачи.
8.6 По данным Арона из IBM, производительность труда лежит в пределах от 1,5 до 10 тысяч строк программы на человека в год в зависимости от количества взаимодействий между частями системы.
8.7 По данным Харра из Bell Labs, производительность труда при задаче типа разработки операционной системы составила около 0,6 тысяч строк кода на человека в год, а при разработке компиляторов — 2,2 тысячи для законченных продуктов.
8.8 Данные Брукса по OS/360 согласуются с данными Харра: 0,6-0,8 тысяч строк кода на человеко-год для операционных систем и 2-3 тысячи для компиляторов.
8.9 Данные Корбато по проекту МТИ MULTICS показывают, что производительность труда при разработке смеси операционной системы и компиляторов составила 1,2 тысяч строк кода на человека в год, но это строки кода PL/I, а остальные данные относятся к строкам кода ассемблера!
8.10 Производительность примерно постоянна в переводе на элементарные операторы.
8.11 При использовании подходящих языков высокого уровня производительность можно увеличить в пять раз.
Глава 9. Два в одном
9.1 Если не считать времени выполнения, то главные издержки приходятся на занимаемое программой пространство памяти. Это в особенности верно для операционных систем, значительная часть которых остается резидентной.
9.2 Несмотря на это, деньги, потраченные на память для размещения программы, дают очень хорошее улучшение характеристик на единицу вложений — лучшее, чем все другие способы инвестирования в конфигурацию. Плох не размер программы, а лишний размер.
9.3 Разработчик программы должен устанавливать задание по размеру, контролировать размер и придумывать методы сокращения размера, так же, как разработчик аппаратной части делает это для деталей.
9.4 Ресурсы по памяти должны явно задавать не только размер резидентной части, но и интенсивность обращений программы к диску.
9.5 Ресурсы памяти должны привязываться к назначению функций: точно определяйте, что должен делать модуль, когда задаете его размеры.
9.6 Группы в составе больших бригад склонны производить оптимизацию в своих узких интересах, не думая о конечном эффекте, который она окажет на пользователя. Эта потеря ориентации является большой опасностью для крупных проектов.
9.7 На всем протяжении реализации системные архитекторы должны постоянно проявлять бдительность с целью непрерывного обеспечения целостности системы.
9.8 Воспитание общесистемного и ориентированного на пользователя подхода является, возможно, главной задачей менеджера по программированию.
9.9 Нужно уже на ранних этапах определить, насколько детализированным будет предоставляемый пользователю выбор опций, поскольку объединение опций в группы сберегает память (а часто и расходы на маркетинг).
9.10 Важно определить размер транзитной памяти, связанный с размером перегружаемого кода, поскольку зависимость производительности от этого размера сильнее, чем линейная. (Этот пункт полностью устарел благодаря наличию виртуальной памяти и дешевизне физической памяти. Теперь пользователи обычно покупают память в количестве, достаточном для размещения всего кода основных приложений.)
9.11 Для достижения хорошего компромисса между пространством и временем необходимо проводить обучение технике программирования, присущей данному языку или машине, особенно если они новые.
9.12 У программирования есть технология, и каждый проект нуждается в библиотеке стандартных компонентов.
9.13 Библиотеки программ должны иметь по две версии каждого компонента — быструю и компактную. (Похоже, что сегодня это устарело.)
9.14 Компактные и быстрые программы почти всегда являются результатом стратегического прорыва, а не тактической грамотности.
9.15 Таким прорывом часто является новый алгоритм.
9.16 Еще чаще прорыв происходит благодаря изменению представления данных или таблиц. Представление — сущность программирования.
Глава 10. Документарная гипотеза
10.1 Гипотеза: Среди моря бумаг несколько документов становятся критически важными осями, вокруг которых вращается все управление проектом. Они являются главными личными инструментами менеджера.
10.2 Для проекта разработки компьютера решающими документами являются цели, руководство, график, бюджет, организационная структура, план помещений, а также оценка, прогноз и цены для самой машины.
10.3 Для факультета университета важнейшие документы аналогичны: цели, требования к соискателям степеней, описания курсов, предложения по научной работе, расписание занятий и план обучения, бюджет, план помещений, а также назначения преподавателей и аспирантов.
10.4 Для программного проекта требования те же: цели, руководство пользователя, внутренняя документация, график, бюджет, организационная структура и план помещений.
10.5 Поэтому даже для самого маленького проекта менеджер с самого начала должен формализовать такой набор документов.
10.6 Подготовка каждого документа их этого маленького набора концентрирует мысль и кристаллизует обсуждение. При изложении на бумаге требуется принятие сотен мини-решений, и их наличие отличает четкую и точную политику от расплывчатой.
10.7 Сопровождение каждого важного документа требует наличия механизма слежения за состоянием и предупреждения.
10.8 Каждый документ в отдельности служит контрольным списком и базой данных.
10.9 Важнейшая задача менеджера — обеспечить общее движение в одном направлении.
10.10 Главная постоянная задача менеджера — общение, а не принятие решений; документы информируют всю команду о планах и решениях.
10.11 Только маленькая часть, возможно, 20 процентов, рабочего времени администратора занята задачами, которые требуют сведений, отсутствующих в его памяти.
10.12 По этой причине модная идея «всеохватывающей информационной системы для управления», обеспечивающей поддержку руководителя, основывается на неверной модели поведения руководителя.
Глава 11. Планируйте на выброс
11.1 Инженеры-химики выяснили, что осуществленный в лаборатории процесс нельзя одним махом перенести в заводские условия, но необходимо построить опытный завод, чтобы получить опыт наращивания количеств веществ и функционирования в незащищенных средах.
11.2 Этот промежуточный шаг в равной мере необходим для программных продуктов, но для инженеров-программистов пока не стало обычной практикой проводить полевые испытания опытной системы, прежде чем начинать поставки готового продукта. (Сейчас это уже стало общей практикой благодаря выпуску бета-версий. Это не то же самое, что макет с ограниченной функциональностью, альфа-версия, которую я также пропагандирую.)
11.3 Для большинства проектов первую построенную версию едва можно использовать: слишком медленная, слишком большая, слишком сложная в применении, или все это вместе.
11.4 Отбросить и перепроектировать можно все сразу, а можно по частям, но все равно это придется сделать.
11.5 Поставка первой системы (хлама) клиенту позволяет выиграть время, но происходит это ценой мучений пользователей, отвлечения разработчиков, поддерживающих систему во время перепроектирования и дурной репутации продукта, которую будет трудно победить.
11.6 Поэтому планируйте выбросить первую версию — вам все равно придется это сделать.
11.7 «Программист поставляет удовлетворение потребности пользователя, а не какой-то осязаемый продукт» (Косгроув).
11.8 Как фактические потребности пользователя, так и понимание им своих потребностей меняются во время создания, тестирования и использования программы.
11.9 Податливость и неосязаемость программного продукта побуждают его создателей (исключительно) к вечному изменению требований.
11.10 Некоторые законные изменения в задачах (и стратегиях разработки) неизбежны, и лучше подготовиться к ним заранее, чем предполагать, что их не будет.
11.11 Способы проектирования системы с учетом будущих изменений, особенно структурное программирование с тщательным документированием интерфейсов модулей, хорошо известны, но не всегда применяются. Полезно также, где только можно, использовать технологии табличного управления. (Такая техника благодаря стоимости и размеру памяти в настоящее время применяется все более успешно.)
11.12 Для сокращения вносимых при изменениях ошибок следует использовать языки высокого уровня, операции времени компиляции, встраивание ссылок на объявления и технику самодокументирования.
11.13 Вносите изменения квантами в хорошо определенные нумерованные версии. (Сейчас это обычная практика.)
Планируйте организацию для изменений
11.14 «Нежелание программистов документировать проект происходит не столько от лени, сколько от неуверенности, стоит ли связывать себя отстаиванием решений, которые, как знает проектировщик, являются предварительными» (Косгроув).
11.15 Создавать организационную структуру с учетом внесения в будущем изменений значительно труднее, чем проектировать систему с учетом будущих изменений.
11.16 Руководитель проекта должен стремиться к тому, чтобы его менеджеры и технический персонал были настолько взаимозаменяемы, насколько позволяют их способности. В частности, нужно иметь возможность легко переводить людей с технической на управленческую работу и обратно.
11.17 Препятствия к поддержанию эффективной организации с двойной служебной лестницей являются социологическими. Необходимо постоянно бдительно и энергично бороться с ними.
11.18 Легко установить соответствующие размеры жалованья для соответствующих ступенек двойной лестницы, но требуется принять меры, чтобы дать им соответствующий престиж: одинаковые офисы, одинаковые службы поддержки, в значительной мере компенсирующие управленческую деятельность.
11.19 Организация по типу операционной бригады позволяет активно решать все стороны этой проблемы. Это действительно долгосрочное решение проблемы гибкой организации.
Два шага вперед, шаг назад: сопровождение программ
11.20 Сопровождение программы в корне отличается от сопровождения аппаратной части; оно состоит, главным образом, из изменений, исправляющих конструктивные дефекты, включение дополнительных функций или адаптацию к изменениям среды использования или конфигурации.
11.21 Стоимость пожизненного сопровождения широко используемой программы обычно составляет 40 и более процентов стоимости ее разработки.
11.22 Стоимость сопровождения сильно зависит от числа пользователей: чем больше пользователей, тем больше ошибок они находят.
11.23 Кэмпбел отмечает интересную кривую взлета и падений обнаруживаемых ошибок в течение жизни продукта.
11.24 Исправление одной ошибки с большой вероятностью (от 20 до 50 процентов) вносит другую.
11.25 После каждого исправления нужно прогнать весь набор контрольных примеров, по которым система проверялась раньше, чтобы убедиться, что она каким-нибудь непонятным образом не повредилась.
11.26 Методы разработки программ, позволяющие исключить или по крайней мере выявить побочные эффекты, могут резко снизить стоимость сопровождения.
11.27 То же можно сказать о методах реализации проектов меньшим числом интерфейсов и меньшим количеством ошибок.
Шаг вперед, шаг назад: энтропия системы с течением времени растет
11.28 Леман и Белади считают, что общее количество модулей растет линейно с номером версии операционной системы (OS/360), но числи модулей, затронутых изменениями, растет экспоненциально в зависимости от номера версии.
11.29 Все исправления имеют тенденцию к разрушению структуры, увеличению энтропии и дезорганизации системы. Даже самое искусное сопровождение программы только отдаляет момент повержения ее в состояние неисправимого хаоса, выходом из которого является повторное проектирование с самого начала. (Иногда реальная необходимость обновления программы, например, с целью повышения производительности, вызывает необходимость изменения
внутренних границ структур. Часто исходные границы служат причиной выявляющихся впоследствии недостатков.)
Глава 12. Острый инструмент
12.1 Менеджер проекта должен установить принципы и выделить ресурсы для разработки общеупотребляемых инструментов, в то же время он должен признать необходимость в персонализированных инструментах.
12.2 Бригадам, разрабатывающим операционные системы, необходима для отладки собственная целевая машина. Для нее требуется скорее максимум памяти, чем максимум скорости, и системный программист для поддержки стандартного программного обеспечения.
12.3 Машина для отладки или ее программное обеспечение должны иметь инструмент для автоматического подсчета и изменения всех видов параметров программы.
12.4 Потребность в целевой машине описывается специфической кривой: после низкой активности следует взрывной рост, который потом выравнивается.
12.5 Системной отладкой, как астрономией, всегда занимались преимущественно по ночам.
12.6 Вопреки теории, выделение времени целевой машины одной бригаде значительными блоками оказалось лучшим вариантом планирования времени, чем чередование использования машины бригадами.
12.7 Этот предпочтительный при нехватке компьютеров метод планирования времени пережил 20 лет (с 1975 года) технологических изменений, поскольку является наиболее продуктивным. (И остается им в 1995 году.)
12.8 Если целевой компьютер является новым, необходим его логический эмулятор. Его можно получить раньше, и он обеспечивает надежную машину для отладки даже после того, как поставляется настоящая машина.
12.9 Главную библиотеку программ нужно разделить на: 1) набор индивидуальных «игровых площадок», 2) подбиблиотеку системной интеграции, проходящую системное тестирование и 3) версию-релиз. Формальное разделение и перемещение обеспечивают контроль.
12.10 Инструмент, обеспечивающий наибольшую экономию труда в программном проекте, — это, наверное, система редактирования текстов.
12.11 Объемистость системной документации создает новый тип непостижимости (см., например Unix), но это значительно предпочтительнее, чем более распространенный крайний недостаток документации.
12.12 Создайте эмулятор производительности снаружи внутрь, сверху вниз. Начните работу с ним как можно раньше. Прислушайтесь к тому, что он вам скажет.
Языки высокого уровня
12.13 Только лень и инертность препятствуют повсеместному применению языков высокого уровня и интерактивного программирования. (Но сегодня они приняты повсеместно.)
12.14 Язык высокого уровня способствует не только увеличению производительности, но и отладке. Меньше ошибок и легче поиск.
12.15 Прежние возражения, связанные с функциональностью, размером и скоростью результирующей программы устарели благодаря развитию языков и технологии компиляции.
12.16 Сегодня единственный подходящий кандидат для системного программирования — PL/I. (Больше не соответствует действительности.)
Интерактивное программирование
12.17 В некоторых приложениях пакетные системы никогда не будут вытеснены интерактивными системами. (По-прежнему верно.)
12.18 Отладка — это тяжелая и долгая часть системного программирования, и медленная оборачиваемость является проклятием отладки.
12.19 Есть свидетельства тому, что интерактивное программирование по крайней мере удваивает скорость системного программирования.
Глава 13. Целое и части
13.1 Детальная и старательная проработка архитектуры согласно главам 4, 5 и 6 не только упрощает использование продукта, но также облегчает его разработку и делает менее подверженным ошибкам.
13.2 Высоцкий говорит, что «очень многие неудачи связаны именно с теми аспектами, которые были не вполне специфицированы».
13.3 Задолго до всякого написания программы спецификация должна быть передана сторонней группе тестирования для тщательного рассмотрения полноты и ясности. Сами разработчики сделать это не могут.
13.4 «Нисходящее проектирование Вирта (с пошаговым уточнением) является самой важной новой формализацией программирования за десятилетие (1965-1975).»
13.5 Вирт проповедует использование на каждом шаге нотации возможно более высокого порядка.
13.6 Хорошее нисходящее проектирование помогает избегать ошибок благодаря четырем обстоятельствам.
13.7 Иногда приходится возвращаться назад, отбрасывать самый верхний уровень и начинать все сначала.
13.8 Структурное программирование, т.е. разработка программ, управляющие структуры которых состоят только из заданного набора операторов, воздействующих на блоки кода (в противоположность беспорядочным переходам), дает верный способ избежать ошибок и представляет собой правильный способ мышления.
13.9 Экспериментальные данные Голда показывают, что во время первого диалога каждого сеанса достигается втрое больший прогресс в интерактивной отладке, чем при последующих диалогах. Все же полезно тщательно спланировать отладку, прежде чем регистрироваться на машине. (Я полагаю, что это полезно до сих пор, в 1995 году.)
13.10 Я считаю, что для правильного использования хорошей системы (интерактивной отладки с быстрой реакцией) на каждые два часа работы за столом должно приходиться два часа работы на машине: один час — на подчистки и документирование после первого сеанса, и один час — на планирование изменений и тестов очередного сеанса.
13.11 Системная отладка (в отличие от отладки компонентов) занимает больше времени, чем ожидается.
13.12 Трудность системной отладки оправдывает тщательную систематичность и плановость.
13.13 Системную отладку нужно начинать, только убедившись в работоспособности компонентов, (в противоположность подходу «свинти и попробуй» и началу системной отладки при известных, но не устраненных ошибках в компонентах). (Это особенно справедливо для бригад.)
13.14 Рекомендуется создать большое окружение и много проверочного кода и «лесов» для отладки, возможно, на 50 процентов больше, чем сам отлаживаемый продукт.
13.15 Необходимо контролировать изменения и версии, при этом члены команды пусть играют со своими копиями на «площадках для игр».
13.16 Во время системного тестирования добавляйте компоненты по одному.
13.17 Леман и Белади свидетельствуют, что квант изменений должен быть либо большим и вноситься редко, либо очень маленьким — и часто. Последний случай более чреват неустойчивостью. (В Microsoft работают маленькими частыми квантами. Разрабатываемая система собирается заново каждые сутки.)
Глава 14. Назревание катастрофы
14.1 «Как оказывается, что проект запаздывает на один год? …Сначала он запаздывает на один день.»
14.2 Отставание, растущее понемногу изо дня в день, труднее распознать, труднее предотвратить, труднее выправить.
14.3 Чтобы управлять большим проектом по жесткому графику, надо прежде всего иметь график, состоящий из вех и соответствующих им дат.
14.4 Вехи должны быть конкретными, специфическими, измеримыми событиями, определенными с предельной точностью.
14.5 Программист редко лжет относительно движения вехи, если веха очерчена резко, он не может обманывать себя.
14.6 Исследования поведения правительственных подрядчиков по проведению оценок в крупных проектах показали, что оценки сроков работы, тщательно пересматриваемые каждые две недели, незначительно меняются по мере приближения начала работ, что во время работ переоценки уверенно снижаются и что недооценки не меняются, пока до запланированного срока окончания работ не остается около трех недель.
14.7 Хроническое отставание от графика убивает моральный дух. (Джим Маккарти из Microsoft говорит: «Если вы пропустили один крайний срок, будьте уверены, что пропустите и второй.» [2] )
14.8 Для выдающихся команд программистов характерна энергия, как и для выдающихся бейсбольных команд.
14.9 Ничто не заменит график с критическими путями, чтобы определить, какое отставание во что обойдется.
14.10 Подготовка диаграммы критических путей есть самая ценная часть ее применения, поскольку определение топологии сети, указание зависимостей в ней и оценивание путей вынуждают осуществить большой объем очень конкретного планирования на самых ранних стадиях проекта.
14.11 Первая диаграмма всегда ужасна, и для создания второй приходится проявить много изобретательности.
14.12 Диаграмма критических путей дает отпор деморализующей оговорке «другая часть тоже запаздывает».
14.13 Каждому начальнику нужны два вида данных: информация о срывах плана, которая требует вмешательства, и картина состояния дел, чтобы быть осведомленным и иметь раннее предупреждение.
14.14 Получить правдивую картину состояния дел нелегко, поскольку у подчиненных менеджеров есть основания не делиться своими данными.
14.15 Неправильными действиями начальник может обеспечить утаивание всей картины состояния дел; напротив, тщательное рассмотрение отчетов без паники и вмешательства поощряет честный доклад.
14.16 Необходимо иметь методологию обзора, с помощью которой подлинное положение вещей становится известным всем игрокам. Главным для этой цели является график с вехами и документ о завершении.
14.17 Высоцкий: «Я нашел, что удобно иметь в отчете о состоянии работ две даты — «плановую» (дату начальника) и «оцениваемую» (дату менеджера низшего звена). Менеджер проекта должен осторожно относиться к оцениваемым датам.»
14.18 Небольшая группа планирования и контроля, дающая отчеты о прохождении вех, неоценима при работе над большим проектом.
Глава 15. Обратная сторона
15.1 Для программного продукта сторона, обращенная к пользователю, — документация — столь же важна, как и сторона, обращенная к машине.
15.2 Даже для программ, написанных исключительно для себя, текстуальная документация необходима: память может изменить автору-пользователю.
15.3 В целом, преподавателям и менеджерам не удалось воспитать на всю жизнь у программистов уважение к документации, преодолевающее лень и пресс графика работ.
15.4 Эта неудача вызвана не столько недостатком старания или красноречия, сколько неспособностью показать, как проводить документирование эффективно и экономично.
15.5 Документация часто страдает отсутствием общего обзора. Посмотрите сначала издалека, а потом медленно приближайтесь.
15.6 Важная документация пользователя должна быть вчерне написана до разработки программы, поскольку в ней содержатся основные плановые решения. В ней должны быть описаны девять предметов (см. текст главы).
15.7 Программу нужно поставлять с несколькими контрольными примерами: с допустимыми входными данными, допустимыми на грани возможностей, и с явно недопустимыми входными данными.
15.8 Внутренняя документация программы, предназначенная тому, кто должен ее модифицировать, также должна содержать текстуальный обзор, в котором должны быть описаны пять предметов (см. главу).
15.9 Блок-схема чаще всего напрасно включается в документацию. Подробная пошаговая блок-схема устарела благодаря письменным языкам высокого уровня. (Блок-схема — графический язык высокого уровня.)
15.10 Редко требуется блок-схема более чем на одну страницу — если она вообще нужна. (Стандарт MILSPEC здесь совершенно не прав.)
15.11 Что действительно необходимо — это структурный граф программы без соблюдения стандартов составления блок-схем ANSI.
15.12 Чтобы обеспечить обновление документации, важно включить ее в исходный текст программы, а не держать отдельным документом.
15.13 Для облегчения труда ведения документации есть три важных правила:
• Как можно больше используйте для документирования обязательные части программы, такие как имена и объявления.
• Используйте свободное пространство и формат, чтобы показать отношения подчиненности, вложенности и улучшить читаемость.
• Вставляйте в программу необходимую текстовую документацию в виде параграфов комментариев, особенно в заголовках модулей.
15.14 В документации, которой будут пользоваться при модификации программы, объясняйте не только «как», но и «почему». Назначение является решающим для понимания. Даже языки высокого уровня совсем не передают значения.
15.15 Методы самодокументирующегося программирования наиболее полезны и мощны при использовании языков высокого уровня.
Эпилог к первому изданию
E.1 Программные системы являются, возможно, самыми сложными и запутанными (в смысле числа различных типов составляющих) созданиями человека.
E.2 Смоляная яма программной инженерии еще долгое время будет оставаться вязкой.
Глава 19 «Мифический человеко-месяц» двадцать лет
Я не знаю другого способа судить о будущем, как с помощью прошлого.
ПАТРИК ГЕНРИ
Опираясь на прошлое, невозможно планировать будущее.
ЭДМУНД БЕРК
Для чего понадобилось юбилейное двадцатое издание?
Самолет гудел в ночи, направляясь к Лагардии. Облака и сумрак скрыли все интересное для глаза. Документ, который я читал, был неинтересным. Однако мне не было скучно. Сидящий рядом попутчик читал «Мифический человеко-месяц», и я ожидал, когда словом или жестом он выдаст свое впечатление. В конце концов, когда мы уже выруливали к выходу, я не выдержал:
— Как вам эта книга? Советуете прочесть?
— Хм, в ней нет ничего, чего я не знал бы раньше.
Я решил не представляться.
Почему «Мифический человеко-месяц» выжил? Почему с ним до сих пор считаются в современной практике программирования? Почему его читательская аудитория выходит за пределы сообщества программистов-разработчиков, а книга порождает статьи, цитаты и письма не только разработчиков программ, но и юристов, врачей, психологов, социологов? Каким образом книга, написанная 20 лет назад об опыте разработки программ, имевшем место 30 лет назад, может до сих пор быть актуальной и даже полезной?
Согласно одному из объяснений, которые можно услышать, разработка программного обеспечения как дисциплина не получила нормального и правильного развития. В поддержку этой точки зрения часто указывают на несоответствие роста производительности труда программистов и эффективности производства компьютеров, выросшей в тысячи раз за последние два десятилетия. Как объясняется в главе 16, аномалия состоит не в замедленном развитии программирования, а в беспрецедентном в истории человечества взрыве компьютерных технологий. В целом, причина этого в постепенном переходе производства компьютеров из сборочного производства в обрабатывающее, из трудоемкого производства в капиталоемкое. Разработка же аппаратного и программного обеспечения, в отличие от производства, остается по своей сути трудоемкой.
Второе часто выдвигаемое объяснение гласит, что «Мифический человеко-месяц» лишь случайно касается разработки программного обеспечения, а в основном он написан о групповой разработке чего бы то ни было. Доля правды в этом есть. В предисловии к изданию 1975 года сказано, что управление программным проектом имеет больше сходства с любым другим управлением, чем изначально считается большинством программистов. Я до сих пор так считаю. История человечества — это пьеса, в которой сюжеты постоянны, сценарии медленно меняются с развитием культуры, а декорации меняются непрерывно. Поэтому в ХХ веке мы узнаем себя в Шекспире, Гомере и Библии. Поэтому в той мере, в какой «МЧ-М» написан о людях, он устаревает медленно.
Каковы бы ни были причины, книгу продолжают покупать и присылают мне замечания, которые я ценю. Меня часто спрашивают: «Как вы считаете, в чем вы тогда ошиблись? Что устарело в наши дни? Что действительно новое появилось в мире разработки программ?» Эти четкие вопросы вполне законны, и я постараюсь
ответить на них. Не в таком, правда, порядке, но по группам тем. Прежде всего, посмотрим, что было верным в момент написания и осталось таковым до сих пор.
Центральный аргумент: концептуальная целостность и архитектор
Концептуальная целостность. Чистый и элегантный программный продукт должен представить своим пользователям согласованную идеальную модель приложения, стратегий осуществления приложения и тактики пользовательских интерфейсов, используемой при задании действий и параметров. Концептуальная целостность продукта в восприятии пользователя является важнейшим фактором, влияющим на простоту использования. (Есть, конечно, и другие факторы. Важным примером является единообразие пользовательского интерфейса в приложениях для Macintosh. Более того, можно создать согласованные интерфейсы, являющиеся тем не менее, совершенно неуклюжими. Например MS-DOS.)
Есть многочисленные примеры элегантных программных продуктов, созданных одним или двумя людьми. Так делается большая часть чисто интеллектуальных продуктов, таких как книги или музыкальные произведения. Однако во многих промышленных областях процессы разработки продукта не могут осуществляться на основе столь простого подхода к концептуальной целостности. Конкуренция вынуждает к спешке. Во многих современных технологиях конечный продукт обладает большой сложностью, и проектирование неизбежно требует многих человеко-месяцев труда. Для программных продуктов характерны как сложность, так и напряженность графика, обусловленная конкуренцией.
Таким образом, всякий достаточно большой или срочный продукт, требующий усилий многих людей, сталкивается со специфической трудностью: результат должен концептуально согласовываться с разумом одиночного пользователя и в то же время проектироваться усилиями нескольких разумов. Как организовать проектирование, чтобы достичь такой концептуальной целостности? Это центральный вопрос «МЧ-М». Один из его тезисов гласит, что существуют качественные различия между управлением большими и маленькими программными проектами — лишь в силу числа работающих над ними голов. Для достижения согласованности необходимы обдуманные и даже героические действия.
Архитектор. С четвертой по шестую главу я доказываю, что самое важное — назначить одного человека архитектором продукта, ответственным за все его стороны, воспринимаемые пользователем. Архитектор формирует и имеет в своем владении общедоступную идеальную модель продукта, с помощью которой пользователю будет объяснено его применение. В ее состав входит подробное указание всех его функций и средств вызова и управления. Архитектор также действует в интересах пользователя при поиске компромисса между функциями, техническим характеристиками, размером, стоимостью и выполнением графика работ. Выполнение этой задачи требует полной занятости, и только в очень маленьких группах может быть совмещено с должностью руководителя. Архитектора можно сравнивать с режиссером, а менеджера — с продюсером кинокартины.
Отделение архитектуры от разработки и реализации. Чтобы сделать возможным осуществление архитектором своей главной задачи, необходимо отделить архитектуру, т.е. определение продукта в восприятии пользователя, от его разработки. Архитектура и разработка определяют четкую грань между разными частями задачи проектирования, и по каждую сторону этой грани лежит большая работа.
Рекурсивность архитектуры. В очень больших проектах одному человеку не справиться со всей архитектурой, даже если он избавлен от всех забот, связанных с разработкой. Поэтому главный архитектор системы должен разбить целое на подсистемы. Границы подсистем должны быть проведены так, чтобы интерфейсы между ними были минимальны и легче всего строго определяемы. Тогда у каждой части может быть свой архитектор, подчиняющийся главному архитектору системы в отношении архитектуры. Очевидно, при необходимости этот процесс может быть продолжен рекурсивно.
Сегодня я убежден более чем когда-либо. Концептуальная целостность является важнейшим условием качества продукта. Наличие системного архитектора есть важнейший шаг в направлении концептуальной целостности. Эти принципы ни в коей мере не ограничиваются разработкой программного обеспечения, а справедливы при проектировании любой сложной конструкции, будь то компьютер, самолет, стратегическая оборонная инициатива или система глобальной навигации. После преподавания в более чем 20 лабораториях разработки программного обеспечения я стал настаивать, чтобы группы учащихся, даже из четырех человек, выбирали менеджера и отдельно — архитектора. Разделение функций в таких маленьких группах может показаться несколько чрезмерным требованием, но, по моим наблюдениям, это оправдано и способствует достижению успеха.
Эффект второй системы: функциональность и угадывание частоты
Проектирование для больших групп пользователей. Одним из последствий революции, произведенной персональными компьютерами, является все возрастающее, по крайней мере в области обработки деловых данных, вытеснение заказных программ коробочными программными пакетами. Более того, стандартные программные пакеты продаются сотнями тысяч и даже миллионами экземпляров. Системные архитекторы программ, поставляемых вместе с машиной, всегда должны были создавать проект, ориентированный на большую аморфную массу пользователей, а не на отдельное определенное приложение в одной компании. Теперь такая задача встает перед очень многими архитекторами.
Парадокс состоит в том, что спроектировать инструмент общего назначения, нежели специализированный, гораздо труднее именно потому, что нужно придать вес различающимся потребностям разных пользователей.
В погоне за функциональностью. Архитектор инструмента общего назначения, такого, например, как электронная таблица или текстовый редактор, подвержен сильному соблазну перегрузить продукт функциями предельной полезности ценой снижения производительности и даже простоты использования. Вначале привлекательность предлагаемых возможностей кажется очевидной. Расплата производительностью становится очевидной лишь при системном тестировании. Утрата простоты использования коварно подкрадывается по мере того, как небольшими порциями добавляются новые функции, а руководства пользователя все более разбухают. [1]
Соблазн особенно велик в отношении долгоживущих массовых продуктов, развивавшихся на протяжении ряда поколений. Миллионы покупателей требуют сотен новых возможностей. Всякая просьба свидетельствует о наличии спроса на рынке. Часто архитектор первоначальной системы уже ушел в поход за новой славой, и архитектура оказалась в руках людей с меньшим опытом взвешенного представления общих интересов пользователей. В недавней рецензии на Microsoft Word 6.0 сказано: «Переполнен возможностями; обновление замедлено перегруженностью… Кроме того, Word 6.0 занимает много места и медленно работает.» С неудовольствием отмечается, что Word 6.0 занимает 4 Мбайт памяти и сообщается, что из-за богатых дополнительных функциональных возможностей «даже Macintosh IIfx едва пригоден для выполнения Word 6». [2]
Определение группы пользователей. Чем крупнее и аморфнее группа предполагаемых пользователей, тем более необходимо явно ее определить, если вы намерены достичь концептуальной целостности. У каждого члена группы проектировщиков наверняка есть неявный мысленный образ пользователя, и все образы будут отличаться друг от друга. Поскольку представление архитектора о пользователе явно или подсознательно оказывает влияние на все архитектурные решения, важно, чтобы команда проектировщиков пришла к единому общему образу. Для этого необходимо составить список признаков предполагаемых пользователей, указав в нем:
• кто они такие,
• что им нужно,
• что, по их мнению, им нужно,
• чего они хотят.
Частоты. Для любого программного продукта каждая характеристика пользователя представляет собой распределение со множеством возможных значений и соответствующими частотами. Как архитектору получить эти частоты? Изучение этой слабо очерченной популяции представляется сомнительным и дорогостоящим занятием. [3] С годами я пришел к убеждению, что архитектор должен угадать или, если вам больше нравится, постулировать полный набор признаков и значений вместе с частотами для создания полного, явного и общего для всех описания группы пользователей.
Такая непривлекательная процедура имеет ряд полезных последствий. Во-первых, при стремлении точно угадать частоты архитектор вынужден очень тщательно обдумать, какова возможная группа пользователей. Во-вторых, при фиксации частот возникает обсуждение, полезное для всех участников и выявляющее различия в образах пользователя, имеющихся у разных проектировщиков. В-третьих, явное присвоение частот содействуют пониманию того, какие решения какими свойствами группы пользователей обусловлены. Даже такой неформальный анализ чувствительности приносит пользу. Когда обнаруживается, что очень важные решения зависят от некоторых специфических предположений, оказывается уместным получить более точные численные оценки. (Разработанная Джеффом Конклином (Jeff Conklin) система позволяет формально и точно прослеживать принятие проектных решений и документировать их основания. [4] Мне не приходилось ею пользоваться, но думаю, что она должна быть очень полезна.)
Подводя итоги: установите предположительные признаки группы пользователей. Гораздо лучше ошибаться, но выражаться ясно, чем выражаться туманно.
Как насчет эффекта второй системы? Один наблюдательный ученый заметил, что «Мифический человеко-месяц» рекомендовал на случай неудачи для всякой новой системы планировать поставку второй версии (см. глава 11), которая в главе 5 характеризуется как таящая наибольшие опасности. Я вынужден был признать, что он меня «поймал».
Противоречие скорее лингвистическое, чем реальное. «Вторая» система, описываемая в главе 5, — это вторая система, выпускаемая в развитие предыдущей с привлечением дополнительных функций и украшений. «Вторая» система в главе 11 — это вторая попытка разработки первой выпускаемой системы. Она разрабатывается в условиях всех ограничений, накладываемых графиком, способностями и неведением, характерными для новых проектов — ограничений, навязывающих дисциплину умеренности.
Триумф интерфейса WIMP
Одним из наиболее впечатляющих явлений в программировании за последние двадцать лет был триумф интерфейса, состоящего из окон, значков, меню и указателей (Windows, Icons, Menus, Pointers — WIMP). Сегодня он настолько широко известен, что не требует описания. Впервые эту идею представили публике Дуг Энглебарт (Doug Englebart) с группой коллег из Стэндфордского научно-исследовательского института на Объединенной компьютерной конференции Запада в 1968 году. [5] Оттуда идеи перекочевали в исследовательский центр Xerox в Пало-Альто, где они реализовались на персональной рабочей станции Alto, разработанной Бобом Тейлором (Bob Taylor) с сотрудниками. Их подхватил Стив Джобс для компьютера Apple Lisa — слишком медленного для осуществления своих восхитительных концепций простоты использования. Эти концепции Джобс затем воплотил в коммерчески успешном Apple Macintosh в 1985 году. Позднее они были приняты в Microsoft Windows для IBM PC и его клонов. Мой пример будет базироваться на версии для Мака. [6]
Концептуальная целостность через метафору. WIMP является отличным примером пользовательского интерфейса, обладающего концептуальной целостностью, достигаемой принятием знакомой идеальной модели — метафоры рабочего стола, и ее тщательного последовательного развития для использования воплощения в компьютерной графике. Например, из принятой метафоры непосредственно следует сложно осуществимое, но правильное решение о перекрытии окон вместо расположения их одно рядом с другим. Возможность менять размер и форму окон является последовательным расширением, дающим пользователю новые возможности, обеспечиваемые носителем — компьютерной графикой. У реальных бумаг на столе нельзя так же легко менять размер и форму. Буксировка непосредственно вытекает из метафоры; выбор значков с помощью курсора является прямой аналогией захвата предметов рукой. Значки и вложенные папки являются точными аналогами документов на столе, как и мусорная корзина. Идеи вырезания, копирования и вставки точно имитируют операции, которые мы обычно осуществляем с документами на столе. Следование метафоре столь буквально, а развитие настолько последовательно, что пользователей-новичков решительно коробит, когда перетаскивание значка дискеты в мусорную корзину приводит к извлечению дискеты из дисковода. Если бы интерфейс не был столь единообразно последовательным, эта (довольно неприятная) непоследовательность так бы не раздражала.
В каких местах интерфейс WIMP вынужден далеко отойти от метафоры рабочего стола? Наиболее заметны два отличия: меню и работа одной рукой. На реальном рабочем столе с документами осуществляют действия, а не приказывают кому-то или чему-то осуществить их. А когда кому-то дается указание совершить действие, команда обычно не выбирается из списка, а письменно или устно подается в виде глагола в повелительном наклонении: «пожалуйста, подшейте это в папку», «пожалуйста, найдите предыдущие письма» или «пожалуйста, передайте это Мэри для принятия мер».
К сожалению, надежная интерпретация команд в свободном формате на английском языке, будь они в устном или письменном виде, находится за пределами наших сегодняшних возможностей. Поэтому проектировщики интерфейса на два шага отошли от непосредственных действий пользователя с документами. Они мудро взяли имевшийся на обычном рабочем столе образец выбора команд — отпечатанную «сопроводиловку», в которой пользователь производит выбор из ограниченного меню команд со стандартной семантикой. Эту идею они превратили в горизонтальное меню с вертикально опускающимися подменю.
Подача команд и проблема двух курсоров. Команды являются повелительными предложениями, в них всегда есть и обычно имеется прямое дополнение. Для любого действия нужно задать глагол и существительное. Метафора указания говорит, что для одновременного задания двух предметов нужно иметь на экране два разных курсора, управляемых своими мышами, одной — в правой руке, другой — в левой. В конце концов, на физическом столе мы обычно работаем двумя руками. (Однако одна рука часто придерживает вещи на месте, что на компьютерном рабочем столе происходит по умолчанию.) Мозг, конечно, приспособлен к действиям двумя руками: мы систематически используем две руки при вводе с клавиатуры, езде на автомобиле, приготовлении пищи. Увы, и одна мышь была большим достижением для изготовителей компьютеров. Коммерческих систем, поддерживающих
одновременные действия с двумя курсорами мышей, по одному для каждой руки, нет. [7]
Разработчики интерфейса смирились с реалиями и сделали проект для одной мыши, приняв синтаксическое соглашение, что первым отмечается (выбирается) существительное. Затем указывают на глагол, пункт меню. При этом в значительной мере утрачивается простота использования. Когда я наблюдаю за пользователями, просматриваю видеозапись их действий или зарегистрированные компьютером перемещения курсора, то всегда обращаю внимание на то, что одному курсору приходится выполнять работу двух: выбрать объект в окне на рабочем столе; выбрать глагол в меню; найти другой объект или вновь отыскать прежний; снова опустить меню (часто, то же самое) и выбрать глагол. Курсор мечется взад-вперед, от пространства данных к пространству меню, всякий раз теряя полезную информацию о том, где он находился в этом пространстве в прошлый раз — в целом, неэффективный процесс.
Великолепное решение. Даже если бы электроника и программы могли без труда работать одновременно с двумя активными курсорами, остаются сложности с топологией пространства. На рабочем столе в метафоре WIMP в действительности есть пишущая машинка, и в физическом пространстве реального стола необходимо поместить реальную клавиатуру. Клавиатура плюс два коврика для мышей займут немалую часть пространства в пределах досягаемости рук. Так почему бы проблему клавиатуры не обратить себе на пользу, почему не использовать обе руки — одной рукой задавая на клавиатуре глаголы, а другой рукой выбирая существительные с помощью мыши? Теперь курсор будет оставаться в пространстве данных и пользоваться тем, что последовательные существительные выбираются близко одно от другого. Реальная эффективность, реально большие возможности пользователя.
Мощность функций или простота использования. Однако при таком решении теряется то, что делает использование меню таким простым для новичков: меню представляет список альтернативных глаголов, допустимых в каждом конкретном состоянии. Можно купить коробку, принести ее домой и начать работать, не читаю инструкцию, зная лишь, для чего она куплена и экспериментируя с различными глаголами в меню.
Одна из сложнейших задач, стоящих перед архитекторами — это найти соотношение между мощностью функций и простотой использования. Нужно ли проектировать программу в расчете на новичка и случайного пользователя или строить ее с мощными функциями для профессионала? Идеальное решение – обеспечить и то, и другое концептуально согласованным образом, что достигается при помощи интерфейса WIMP. У часто используемых глаголов меню есть клавишные эквиваленты из одной клавиши + командной клавиши, которые обычно легко ввести левой рукой одним аккордом. Например, в Маке командная клавиша () находится как раз под клавишами Z и X, поэтому самые частые действия кодируются как
Постепенный переход от новичка к опытному пользователю. Такая двойная система задания командных глаголов не только отвечает потребности новичка в легком обучении и потребности опытного пользователя в эффективном использовании, но и позволяет каждому пользователю плавно перейти из одного режима в другой. Буквенные обозначения, называемые клавишами сокращенного набора, показываются в меню рядом с глаголами, поэтому в случае неуверенности пользователь может раскрыть меню, чтобы проверить буквенный эквивалент, вместо выбора пункта меню. Каждый новичок запоминает сначала сокращенный набор для своих частых операций. Он может попробовать любое сокращение, в котором не уверен, поскольку отменяет любое ошибочное одиночное действие. С другой стороны, он может справиться в меню относительно допустимых команд. Новички очень часто опускают меню, опытные пользователи — редко, а тем, которые находятся посередине, лишь от случая к случаю понадобится выбирать из меню, поскольку они уже знают клавиши, которые вызывают большинство осуществляемых ими операций. Мы, проектировщики программного обеспечения, слишком привыкли к этому интерфейсу, чтобы оценить его элегантность и мощь.
Успех прямого включения как средства навязывания архитектуры. Интерфейс Мака примечателен еще в одном отношении. Без всякого принуждения разработчики сделали его стандартом для разных приложений, включая большинство из тех, которые описаны сторонними организациями. Поэтому пользователь приобретает концептуальную согласованность на уровне интерфейса не только для программ, поставляемых вместе с машиной, но и для всех других приложений.
Этот подвиг создатели Мака осуществили, встроив интерфейс в ПЗУ, в результате чего разработчикам проще и быстрее пользоваться существующим, чем создавать свои идиосинкразические интерфейсы. Это естественное стремление к единообразию возобладало настолько широко, что стало стандартом де-факто. Естественные стремления были поддержаны полной приверженностью со стороны
менеджеров и существенным принуждением со стороны Apple. Независимые рецензенты в журналах, поняв огромное значение межпрограммной концептуальной целостности, также подкрепили естественные стремления, безжалостно критикуя продукты, не удовлетворяющие этому интерфейсу.
Это отличительный пример технологии, рекомендованной в главе 6 для достижения единообразия путем поощрения других сторон непосредственно включать в свои продукты имеющийся код вместо разработки новых программ согласно имеющимся спецификациям.
Судьба WIMP: устаревание. Несмотря на все достоинства, по моему мнению, интерфейс WIMP через поколение станет достоянием истории. Указание курсором останется способом задания существительных при управлении нашими компьютерами. Для выражения глаголов станет использоваться речь. Такие инструменты, как Voice Navigator для Маков и Dragon для PC, уже предоставляют такую возможность.
Не разрабатывайте программ на выброс, каскадная модель неверна!
В главе 11 дается радикальный совет: «планируйте выбросить первую программу, вам все равно придется это сделать». Сейчас я считаю это ошибочным — не в силу чрезмерного радикализма, но в силу чрезмерной упрощенности.
Самой большой ошибкой этой концепции является косвенное принятие классической последовательности — в виде каскада — модели создания программы. Эта модель происходит от структуры диаграммы Гранта для поэтапного процесса, которую часто изображают, как на рисунке 19.1. В классической статье 1970 года Винтон Ройс (Winton Royce) усовершенствовал последовательную модель путем:
• добавления некоторой обратной связи с предшествующими этапами;
• ограничения обратной связи только непосредственными предшественниками, чтобы исключить вызываемые ими издержки и задержки в выполнении графика.
Он предвосхитил «МЧ-М», рекомендовав разработчикам «делать работу дважды» [8] . Глава 11 — не единственная, на которую повлияла каскадная модель. Она проходит через всю книгу, начиная с правила планирования в главе 2. Это практическое правило отводит 1/3 времени на планирование, 1/6 — на написание программ, 1/4 — на тестирование компонентов и 1/4 — на системное тестирование.
Рис. 19.1 Каскадная модель создания программы
Основное заблуждение каскадной модели состоит в предположениях, что проект проходит через весь процесс один раз, архитектура хороша и проста в использовании, проект осуществления разумен, а ошибки в реализации устраняются по мере тестирования. Иными словами, каскадная модель исходит из того, что все ошибки будут сосредоточены в реализации, а потому их устранение происходит равномерно во время тестирования компонентов и системы.
«Планируйте на выброс» действительно резко нападает на это заблуждение. Ошибка не в диагнозе, а в лекарстве. Сейчас я предположил, что первую систему можно отбросить или перепроектировать не всю целиком, а по частям. Хорошо, если это так, но при этом не затрагивается корень проблемы. В каскадной модели системное тестирование, а следовательно и тестирование пользователем, отодвигается в конец процесса создания программы. Поэтому есть шанс обнаружить крайние неудобства для пользователя, или неприемлемые технические характеристики, или опасную уязвимость к ошибкам или злонамеренным действиям пользователя лишь в самом конце разработки. Изучение спецификаций при альфа-тестировании нацелено на раннее обнаружение таких ошибок, но ничто не может заменить непосредственных пользователей.
Вторым недостатком каскадной модели является предположение, что система строится сразу вся целиком для тестирования с начала до конца после того, как завершены все проектные разработки, большая часть написания программ и значительная часть тестирования компонентов.
К несчастью, каскадная модель, это преобладавшее в 1975 году представление о программных проектах, была включена в DOD-STD-2167 — спецификацию Министерства обороны для любого военного программного обеспечения. По этой причине она просуществовала долгое время после того, как большая часть думающих практиков осознала ее неадекватность и отказалась от нее. К счастью, в МО позднее поняли истину. [9]
Необходимо двигаться против течения. Опыт и идеи из каждой расположенной ниже по течению части процесса создания программы, как энергичный лосось, должны прыгать вверх по течению, иногда сразу через несколько этапов, и воздействовать на деятельность наверху.
Проектные разработки покажут, что некоторые предусмотренные архитектурой возможности ухудшают технические характеристики, и потому архитектура должна быть переработана. Программирование при реализации выявит, что некоторые функции непомерно увеличивают требования к памяти, поэтому нужно внести изменения в архитектуру и разработку.
Поэтому вполне может потребоваться осуществить несколько итераций цикла архитектура-разработка, прежде чем начать какую-либо программную реализацию.
Модель пошагового создания лучше: последовательное уточнение
Построение каркаса с начала до конца. Гарлан Миллз (Harlan Mills), работающий в системе с разделением времени, давно уже рекомендует строить основной цикл опроса системы реального времени с вызовами подпрограмм (заглушками) для всех функций (рис. 19.2), но пустыми подпрограммами. Откомпилируйте его, протестируйте, и он будет идти цикл за циклом, буквально ничего не делая, но делая это без ошибок. [10]
Рис. 19.2
На следующем шаге мы навешиваем модуль ввода (возможно, примитивный) и модуль вывода. Voila! Работающая система, делающая нечто, возможно, неинтересное. Теперь, функция за функцией, мы строим и добавляем модули. На каждом шаге мы имеем работающую систему. При достаточном трудолюбии на каждом шаге мы имеем отлаженную, протестированную систему. (По мере роста системы растет и тяжесть повторного тестирования всех новых модулей по всем прежним контрольным примерам.)
После того как на примитивном уровне каждая функция работает, мы улучшаем или переписываем один модуль за другим, пошагово наращивая систему. Иногда для надежности мы переписываем исходный движущий цикл, а возможно, и его интерфейсы с модулями.
Поскольку в любой момент времени у нас есть работающая система:
• можно очень рано начать тестирование пользователями;
• можно принять стратегию разработки в соответствии с бюджетом, полностью защищающую от перерасхода времени или средств (возможно, за счет сокращения функциональности).
В течение 22 лет я преподавал в лаборатории программной инженерии Университета штата Северная Каролина, иногда вместе с Дэвидом Парнасом. На этих занятиях бригады, обычно состоявшие из четырех человек, в течение одного семестра должны были построить некоторую реальную прикладную программную систему. Примерно посередине этого срока я стал преподавать инкрементную разработку. Я был поражен, какой возбуждающий эффект на моральный дух группы оказывает первая картинка на экране, первая работающая система.
Семейства Парнаса. Дэвид Парнас был главным властителем дум в программотехнике в течение всего этого 20-летнего периода. Всем известна его идея скрытия информации. Менее известна очень важная идея Парнаса о проектировании программного продукта как семейства взаимосвязанных продуктов. [11] Он требует, чтобы проектировщик имел в виду как дальнейшее развитие, так и новые версии продукта и определял их функциональные или межплатформенные различия так, чтобы строить дерево родственных продуктов (рис. 19.3).
Рис. 19.3
Фокус при проектировании такого дерева состоит в том, чтобы ближе к корню поместить те решения, изменение которых наименее вероятно.
Такая стратегия проектирования повышает повторную используемость модулей. Еще важнее, что ее можно расширить, включая не только поставляемые продукты, но и последовательные промежуточные версии, созданные по стратегии инкрементируемых сборок. В этом случае продукт развивается через промежуточные стадии с минимумом возврата назад.
Подход Microsoft: «ежевечерняя сборка». Джеймс Маккарти (James McCarthy) описал мне процесс, использовавшийся им и другими в Microsoft. Это пошаговое наращивание, доведенное до логического конца. Он пишет:
Сделав первую поставку, новые версии мы поставляем с дополнительными функциями, по сравнению с существующим работающим продуктом. Почему должен быть иным процесс первоначальной сборки? С момента достижения нами первой вехи (у первой поставки три промежуточных вехи) мы каждый вечер заново собираем разрабатываемую систему (и прогоняем контрольные примеры). Цикл сборки становится ритмом жизни проекта. Каждый вечер одна или более бригад программистов, проводящих тестирование, регистрируют модули с новыми функциями. После каждой сборки у нас есть работающая система. Если сборка оказывается неудачной, мы останавливаем весь процесс, пока ошибка не будет найдена и исправлена. В любой момент все в группе знают положение дел.
Это действительно тяжело. Требуется выделение больших ресурсов, но это управляемый процесс, прослеживаемый и понятный. Он вызывает у команды доверие к себе. А доверие определяет мораль, эмоциональное состояние.
Такой процесс удивляет и даже шокирует разработчиков в других организациях. Один из них говорит: «Я взял себе за правило делать сборку каждую неделю, но ежедневная сборка, я думаю, потребует слишком много труда.» И это, возможно, верно. Например, в Bell Northern Research собирают систему, состоящую из 12 миллионов строк, раз в неделю.
Инкрементная сборка и быстрое макетирование. Поскольку инкрементная разработка позволяет рано начать тестирование реальными пользователями, в чем ее отличие от быстрого макетирования? Мне кажется, что они связаны, но различаются. Одним можно пользоваться без другого.
Харел дает полезное определение макета:
(версия программы, которая) отражает только проектные решения, принятые в процессе подготовки концептуальной модели, а не решения, вызванные соображениями реализации. [12]
Можно построить макет, который вовсе не является частью продукта, развивающегося в направлении поставки. Например, можно создать макет интерфейса, за которым стоит не реально работающая программа, а лишь конечный автомат, заставляющий его имитировать прохождение состояний. Можно даже макетировать и тестировать интерфейсы методом волшебника изумрудного города, когда спрятанный человек имитирует отклик системы. Такое макетирование может быть весьма полезным для быстрого получения обратной связи от пользователя, но оно находится совершенно в стороне от тестирования продукта, который готовится к поставке.
Аналогично, разработчики могут попробовать построить вертикальный срез продукта, в котором полностью реализован весьма ограниченный набор функций, чтобы заранее пролить свет на те места, где могут таиться опасности для производительности продукта. В чем состоит различие между сборкой на первой вехе в процедуре Microsoft и быстрым макетом? В функциях. Продукт с первой вехи может иметь такую ограниченную функциональность, что ни для кого не будет представлять интереса. Готовность продукта к поставке определяется завершенностью в предоставлении полезного набора функций и своим качеством, уверенностью в надежной работе.
Парнас был прав, а я — нет в отношении сокрытия информации
В главе 7 я противопоставляю две точки зрения на то, в какой мере каждый участник команды может иметь право или поощряться к знанию проектов и текстов программ, созданных коллегами. Во время проекта Operating System/360 мы решили, что все программисты должны видеть весь материал, т.е. у каждого программиста была рабочая тетрадь проекта, которая к концу насчитывала свыше 10000 страниц. Харлан Миллз убедительно доказывал, что «программирование должно быть открытым процессом», что предоставление всей работы на общее обозрение способствует контролю качества как благодаря давлению со стороны коллег, заставляющему работать хорошо, так и благодаря тому, что коллеги действительно находят промахи и ошибки.
Этот взгляд резко противоречит мнению Дэвида Парнаса о том, что программные модули должны быть инкапсулированы, с хорошо определенными интерфейсами, а внутренность таких модулей должна быть частной собственностью программиста, невидимой снаружи. Программисты эффективнее всего работают, будучи ограждены от внутренностей чужих модулей. [13]
В главе 7 я заклеймил идею Парнаса как «рецепт катастрофы». Парнас был прав, а я ошибался. Сегодня я убежден, что ограничение информации, часто осуществляемое теперь методами объектного программирования, является единственным способом поднять уровень программных разработок.
Используя другие методы, можно действительно попасть в беду. Согласно методике Миллза программисты могут получить подробности семантики интерфейсов, с которыми они работают, узнав, что находится «по ту сторону». Укрывание этой семантики может быть причиной системных ошибок. С другой стороны, методика Парнаса способствует устойчивости при внесении изменений и больше подходит к стратегии проектирования, предполагающей изменения в будущем.
В главе 16 утверждается следующее:
• большая часть роста производительности разработки программного обеспечения обеспечена устранением второстепенных трудностей, таких как неудобные языки программирования и медленная оборачиваемость пакетной обработки;
• легких решений в этом направлении практически не осталось;
• радикального прогресса можно добиться, разрешив существенные сложности моделирования сложных концептуальных конструкций.
Самое очевидное на этом пути — признать, что программы составляются из концептуальных блоков, значительно более крупных, чем отдельные операторы языков высокого уровня: подпрограмм, или модулей, или классов. Если мы сумеем ограничить проектирование и построение программ задачей соединения вместе и параметризации таких блоков из ранее созданных наборов, то радикально повысим концептуальный уровень и избавимся от огромного объема работ и широких возможностей для ошибок, существующих на уровне отдельных операторов.
Данное Парнасом определение модулей с сокрытием информации было первым открытым шагом в этой критически важной программе исследований и идейным провозвестником объектно-ориентированного программирования. Он определил модуль как программный объект с собственной моделью данных и собственным набором операций. Доступ к его данным может быть осуществлен только через имеющиеся в нем операции. Следующий шаг явился вкладом нескольких исследователей: развитие модулей Парнаса в абстрактный тип данных, из которого можно производить много объектов. Абстрактный тип данных обеспечивает единообразный способ представления и задания интерфейсов модулей, а также дисциплину доступа, которую легко осуществлять.
Третий шаг, объектно-ориентированное программирование, вводит важное понятие наследования, при котором классы (типы данных) по умолчанию имеют атрибуты своих предков в иерархии классов. [14] То, что мы рассчитываем получить от объектно-ориентированного программирования, происходит, в сущности, от первого шага, инкапсуляции модулей, плюс идея заранее подготовленных библиотек модулей или классов, спроектированных и протестированных с целью повторного использования. Многие предпочли проигнорировать тот факт, что такие модули не просто программы, а программные продукты в том смысле, который разъяснен в главе 1. Напрасно рассчитывать на успешное повторное использование модулей, не оплачивая начальные издержки на разработку качественных программных модулей: обобщенных, надежных, протестированных и документированных. Объектно-ориентированное программирование и повторное использование обсуждались в главах 16 и 17.
Насколько мифичен человеко-месяц? Модель и данные Бёма
В течение ряда лет были выполнены многочисленные количественные исследования производительности труда программистов и влияющих на нее факторов, особенно соотношений между обеспеченностью персоналом и графиком работ.
Наиболее обстоятельное исследование сделано Барри Бёмом (Barry Boehm) на основании примерно 63 проектов, в основном в аэрокосмической области, из них около 25 – в TRW. Его работа «Экономика разработки программного обеспечения» содержит не только результаты, но и ряд полезных моделей затрат с нарастающей сложностью. Хотя несомненно, что применяемые в моделях коэффициенты различны для обычных космических программ и для программ, создаваемых в аэрокосмической области по правительственным стандартам, все же его модели подкрепляются огромным количеством данных. Я думаю, что книга будет полезным классическим трудом и через поколение.
Полученные им результаты уверенно подкрепляют содержащееся в МЧ-М утверждение о том, что соотношение между численностью занятых и временем выполнения проекта далеко не линейное, что человеко-месяц действительно является мифической мерой производительности. В частности, он считает: [15]
• Существует оптимальное, с точки зрения затрат, время выполнения графика для первой поставки: T = 2,5 (ЧМ) 1/3 . То есть оптимальное время в месяцах изменяется как кубический корень предполагаемого объема работ в человеко-месяцах — формула, полученная из оценки размера и других факторов в его модели. Следствием является кривая, дающая оптимальную численность занятых.
• Кривая стоимости медленно растет, если запланированный график длиннее оптимального. Работа занимает все отведенное для нее время.
• Кривая стоимости резко растет, если запланированный график короче оптимального.
• Практически ни один проект невозможно завершить быстрее, чем за [3] Л расчетного оптимального графика вне зависимости от количества занятых в нем! Этот примечательный результат дает менеджеру программного проекта солидное подкрепление, когда высшее руководство требует принятия невозможного графика.
Насколько верен закон Брукса? Были даже проведены тщательные исследования закона Брукса (намеренно упрощенного), согласно которому выделение дополнительных людей для отстающего графика проекта лишь задерживает его выполнение. Лучше всего это сделано Абдель-Хамидом (Abdel-Hamid) и Мадником (Madnick) в честолюбивой и ценной книге «Динамика программного проекта: интегрированный подход». [16] В книге разработана количественная модель динамики проекта. Глава о законе Брукса более подробно вникает в то, что происходит при различных допущениях относительно того, кого добавляют, и когда. Чтобы исследовать это, авторы развивают собственную тщательную модель программного проекта среднего размера, предполагая, что у вновь добавляемых людей есть кривая обучения, и учитывая дополнительные издержки на общение и обучение. Они приходят к выводу, что «добавление новых людей к запаздывающему проекту всегда приводит к его удорожанию, но не всегда к более позднему завершению» (курсив авторов). В частности, увеличение численности работников в начале проекта гораздо безопаснее, чем в конце, поскольку добавление новых людей всегда вызывает отрицательный эффект, для компенсации которого требуются недели.
Штуцке (Stutzke) предлагает более простую модель для проведения аналогичных исследований, и с тем же результатом. [17] Он проводит подробный анализ процесса и издержек, связанных с привлечением новых работников, явным образом учитывая отвлечение наставников от непосредственной работы над проектом. Он проверял свою модель на реальном проекте, в котором численность работником была удвоена, благодаря чему удалось уложиться в первоначальный график, несмотря на отставание в середине. Он рассматривает альтернативы добавлению новых работников, особенно сверхурочную работу. Наибольшую ценность представляют его многочисленные практические советы о том, как привлекать новых работников, обучать их, обеспечивать инструментарием и т.д., чтобы минимизировать отрицательный эффект увеличения персонала. Особенно достойно внимания его замечание, что дополнительно привлекаемые на поздних стадиях проекта работники должны быть игроками команды, стремящимися войти в игру и вписаться в процесс, а не пытаться изменить или усовершенствовать сам процесс!
Штуцке считает, что дополнительная тяжесть обмена информацией в крупном проекте имеет второй порядок малости, и не включает ее в свою модель. Не вполне ясно, учитывают ли ее Абдель-Хамид и Мадник, и если да, то как. Ни в одной из моделей не учитывается то обстоятельство, что работа должна быть перераспределена — процесс, который для меня часто оказывался нетривиальным.
«Крайне упрощенная» формулировка закона Брукса становится более полезной, будучи дополнена этими тщательно сделанными надлежащими оговорками. Подытоживая, я продолжаю придерживаться исходного утверждения как приближения к истине нулевого порядка, практического правила, предупреждающего менеджеров о неразумности инстинктивной попытки вытянуть запаздывающий проект.
Кадры решают все (или почти все)
Некоторые читатели удивляются, что большая часть рассуждений МЧ-М посвящена административным сторонам программной инженерии, а не многочисленным техническим проблемам. Такой перекос частично вызван той ролью, которую я играл в IBM Operating System/360 (теперь MVS/370). Если смотреть глубже, это происходит от убеждения, что качество людей, занятых в проекте, их организация и администрирование имеют гораздо большее значение для успеха, чем инструменты, которыми они пользуются, или применяемые ими технические решения.
Последующие исследования подкрепили мою уверенность. Модель COCOMO Бёма признает, что качество команды является важнейшим фактором ее успеха, практически вчетверо более важным, чем следующий за ним по значимости. Большинство научных исследований по программной инженерии сосредоточилось на инструментах. Я люблю хороший инструмент и жажду его. Тем не менее отрадно видеть продолжение исследовательских программ в отношении заботы о людях, их роста и поддержки, а также развития управления разработкой программного обеспечения.
Человеческий фактор. Крупным достижением последних лет стала книга Демарко (DeMarco) и Листера (Lister) «Человеческий фактор: продуктивные проекты и программы», изданная в 1987 году. В основе ее лежит положение о том, что «главные проблемы в нашей работе по природе своей не столько технологические, сколько социологические». Она изобилует такими жемчужинами, как «задача менеджера не заставить людей работать, а сделать так, чтобы они могли работать». В ней говорится о таких прозаических вещах, как помещение, мебель, совместное питание команды. Демарко и Листер приводят реальные данные из своего «Программирования военных игр», которые показывают поразительную корреляцию между производительностью программистов из одной и той же организации, а также между характеристиками рабочих мест и уровнем продуктивности и наличия ошибок.
В помещениях наиболее продуктивных программистов тише, они более личные, лучше защищены против непрошеного вторжения, и они просто больше… Понимаете ли вы, что покой, пространство и уединенность способствуют лучшей работе ваших теперешних работников или (с другой стороны) способствует привлечению и сохранению лучших работников?[18]
Я искренне рекомендую эту книгу всем моим читателям.
Передача проектов. Демарко и Листер уделяют большое внимание спаянности команды, неуловимому, но важному качеству. Я думаю, что непонимание администрацией спаянности служит причиной той готовности, с которой, как я наблюдал, в компаниях, расположенных на нескольких площадках, проекты передаются из одной лаборатории в другую.
В своей практике я наблюдал, возможно, с полдюжины передач проекта, и ни одна из них не была успешной. Можно с успехом передавать задания. Но во всех случаях попытки передать проект новая команда фактически начинала сначала, несмотря на наличие хорошей документации, некоторого продвижения в проекте и некоторых людей из передающей команды. Я думаю, что разрушение спаянности прежней команды приводит к выкидышу проекта, находящегося в эмбриональном состоянии, и осуществлению его с начальной точки.
Сила отказаться от власти
Если согласиться, что, как я неоднократно доказывал на протяжении этой книги, творчество исходит от личностей, а не организационных структур и процессов, тогда главная задача менеджера программного проекта — создать организационную структуру и рабочий процесс, способствующий творчеству и инициативе, а не подавляющие их. К счастью, эта проблема присуща не только программным организациям, и над ней работали многие большие умы. Е. Ф. Шумахер (E. F. Schumacher) в классической работе «Малое прекрасно: экономика ради людей» предлагает теорию организации предприятий, максимизирующую творческую активность и радость работников. В качестве первого принципа он выдвигает «принцип вспомогательной функции» из энциклики Quadragesimo Anno папы Пия XI:
Передача большему и вышестоящему сообществу того, что могут делать меньшие и нижестоящие организации является несправедливостью и в то же время серьезным злом и нарушением правильного порядка. Ибо всякая общественная деятельность по сути своей должна предоставлять помощь членам социальной группы, а не разрушать и поглощать их… Тем, кто управляет, следует быть уверенными, что чем лучше среди различных сообществ сохраняется дифференцированный порядок в соблюдении принципа второстепенной функции, тем крепче будет власть и эффективность в обществе, тем более счастливым и процветающим государство.[19]
Шумахер приводит разъяснение:
Принцип второстепенной функции учит нас, что власть и эффективность центра увеличатся, если будут тщательно охраняться свобода и ответственность более низких формирований, а в итоге организация в целом будет «более счастливой и процветающей».
Как можно добиться такой организации? … Большая организация должна состоять из множества полуавтономных единиц, которые можно назвать квази-фирмами. Каждая из них должна обладать значительной свободой, чтобы предоставить наилучшие возможности для творчества и предприимчивости… Каждая из квазифирм должна иметь свой учет прибылей и потерь, а также балансовый отчет.[20]
К числу наиболее замечательных достижений программной инженерии принадлежат первые этапы практического осуществления таких организационных идей. Прежде всего, микрокомпьютерная революция создала новую программную индустрию с сотнями вновь возникших фирм, которые изначально малы и отмечены энтузиазмом, свободой и творчеством. Сейчас индустрия меняется по мере поглощения мелких фирм крупными. Посмотрим, поймут ли крупные фирмы важность сохранения творческой активности мелких, поглощаемых ими.
Еще более примечательно, что высшее руководство ряда крупных фирм предприняло меры по передаче власти вниз отдельным командам, работающим над программными проектами, что сближает их с квази-фирмами Шумахера по структуре и ответственности. Результаты вызвали удивление и удовлетворение.
Джим Маккарти из Microsoft описывал мне свой опыт эмансипации команд:
У каждой бригады (30-40 человек) есть свой набор разрабатываемых объектов, свой график и даже свои правила разработки, реализации и поставки. В бригаде есть специалисты в четырех или пяти областях, в том числе реализации, тестировании и документировании. Бригада сама улаживает разногласия по пустякам, начальник не вмешивается. Не боюсь переоценить важность перемещения власти, когда бригада самостоятельно несет ответственность за свои достижения.
Эрл Уилер (Earl Wheeler), бывший руководитель программных разработок IBM, поделился со мной своим опытом делегирования вниз полномочий, бывших в течение долгого времени сосредоточенными у администрации управления IBM.
Ключевым порывом последних лет стало делегирование полномочий вниз. Это было чудом! Улучшились качество, продуктивность, моральный дух. У нас небольшие бригады без централизованного управления. Бригады сами определяют правила производственного процесса, но они испытывают давление со стороны рынка. И это давление заставляет их самих искать способы решения проблем.
Общение с отдельными членами бригад показывает, конечно, и удовлетворение от передачи полномочий и свободы, а также более сдержанную оценку того, в какой мере контроль действительно ослаблен. Тем не менее, достигнутая степень передачи полномочий являет шаг в правильном направлении. Получаемые выгода точно те, которые предсказывались Пием XI: в результате делегирования полномочий центр усиливает свою реальную власть, а организация в целом становится более счастливой и процветающей.
Какой самый большой сюрприз? Миллионы компьютеров
Все компьютерные гуру, с которыми я разговаривал, признают, что для них были неожиданностью микрокомпьютерная революция и ее порождение — производство коробочных программных продуктов. Вне сомнения, это самое значительное событие за два десятилетия после выхода МЧ-М. Оно имеет многочисленные последствия для программной инженерии.
Микрокомпьютерная революция изменила характер использования компьютеров. Шумахер сформулировал проблему более 20 лет назад:
Чего мы действительно хотим от ученых и технологов? Я отвечу так: нам нужны методы и оборудование, которые:
• достаточно дешевы, чтобы быть доступными практически каждому;
• пригодны для небольших приложений;
• соответствуют потребности человека в творческой деятельности.[21]
Это как раз те замечательные свойства, которые микрокомпьютерная революция дала компьютерной промышленности и ее потребителям, которыми теперь стала широкая публика. Средний американец может сегодня позволить себе не только собственный компьютер, но и набор программных средств, для покупки которого 20 лет назад потребовалось бы королевское жалованье. Каждую из целей, поставленных Шумахером, стоит рассмотреть отдельно. Представляет также интерес, в какой мере они достигнуты — особенно последняя. В одной области за другой обычным людям и профессионалам становятся доступны все новые средства самовыражения.
Отчасти, развитие в других областях происходит так же, как в создании программ — благодаря устранению побочных трудностей. Побочные ограничения на рукописи накладывались длительностью и стоимостью перепечатывания для внесения исправлений. Работу объемом в 300 страниц иногда приходилось перепечатывать каждые три или шесть месяцев, а в перерыве чиркать в рукописи. Трудно было оценить влияние внесенных изменений на общий ход мысли и ритм слов. Сейчас чудесным образом рукописи стали постоянно меняющимися.[22]
Аналогичную изменчивость компьютер придал многим другим материалам: картинам художников, планам построек, чертежам механизмов, музыкальным сочинениям, фотографиям, кинофильмам, слайдовым презентациям, мультимедийным работам и даже электронным таблицам. В каждом случае при ручном способе изготовления для того, чтобы увидеть изменения в контексте, требовалось копирование больших неизменных частей. Теперь, независимо от материала, мы можем пользоваться такими же выгодами, какие работа в режиме разделения времени принесла в программирование: возможность редактирования и мгновенной оценки результата без потери хода мысли.
Творческие возможности усилились также благодаря новым гибким вспомогательным инструментам. Один пример — сочинение прозы, при котором мы пользуемся проверкой орфографии, грамматики, стилистическими подсказками, системами библиографии и замечательной возможностью одновременно видеть страницы в окончательно отформатированном виде. Мы еще не оценили значения мгновенного доступа к энциклопедиям и безграничным ресурсам всемирной паутины для использования писателем импровизированного поиска.
Самое главное, обретенная изменчивость материала упрощает изучение многих в корне различных возможностей, когда творческая работа только обретает форму. Вот другой пример, когда порядок величины в количественном параметре — в данном случае, времени, необходимом для внесения изменений, — производит качественный скачок в подходе к задаче.
Инструменты для черчения позволяют проектировщикам зданий за час творческой работы исследовать гораздо больше вариантов. Подключение компьютеров к синтезаторам и программы, позволяющие автоматически записывать или проигрывать ноты, значительно облегчают фиксацию бренчания по клавишам. Цифровая обработка фотографий, как в Adobe Photoshop, позволяет в течение считанных минут провести эксперименты, для которых потребовались часы работы в фотолаборатории. Электронные таблицы позволяют легко исследовать десятки альтернативных сценариев типа «что, если».
Наконец, благодаря вездесущести персональных компьютеров создается совершенно новый материал. Гипертексты, предложенные Ванневаром Бушем в 1945 году, осуществимы только с помощью компьютеров.[23]Мультимедийные презентации и опыты были сложнейшими задачами — слишком много хлопот — до того, как стало возможным проводить их с помощью компьютеров и соответствующего богатого программного обеспечения. Системы виртуальной реальности, пока еще дорогие и не широко распространенные, в будущем станут такими и создадут новый материал для творчества.
Микрокомпьютерная революция изменила характер разработки программного обеспечения. Технологии разработки программного обеспечения 1970-х сами изменились в результате микрокомпьютерной революции и вызвавших ее технических достижений. Устранена значительная часть второстепенных сложностей технологий разработки программного обеспечения. Быстрые персональные компьютеры стали обычным инструментом разработчика, и время оборачиваемости стало почти устаревшим понятием. Сегодняшний персональный компьютер быстрее не только суперкомпьютера 60-го года, но и Unix-станции 1985-го. Это значит, что компиляция быстро осуществляется даже на скромных по мощности машинах, а благодаря большому объему памяти отпали задержки при компоновке с использованием дисков. Большая память позволяет также хранить в памяти таблицы символических имен вместе с объектным кодом, в результате чего становится обычной высокоуровневая отладка без перекомпиляции.
За последние 20 лет мы почти покончили с использованием разделения времени как методологией разработки программного обеспечения. В 1975 году разделение времени только-только вытеснило пакетную обработку в качестве наиболее распространенной технологии. Сеть использовалась для того, чтобы дать разработчику программного обеспечения доступ как к общим файлам, так и к большим вычислительным мощностям для компиляции, компоновки и тестирования. Сегодня вычислительную мощность обеспечивает персональная рабочая станция, а сеть используется в основном для обеспечения совместного доступа к файлам бригады, разрабатывающей продукт. Клиент-серверные системы меняют и упрощают технологию общего доступа для загрузки, сборки и выполнения контрольных примеров.
Сходный прогресс произошел с пользовательскими интерфейсами. Интерфейс WIMP обеспечивает гораздо большие удобства при редактировании текстов программ и текстов на естественном языке. Экран размером 24 строки на 72 колонки сменился полностраничным или даже двухстраничным экраном, поэтому программисты могут видеть изменения, которые они делают, в значительно более широком контексте.
Целая новая программная отрасль — коробочные пакеты
Рядом с классической индустрией программных продуктов широко развилась еще одна. Продажи программных продуктов числятся сотнями тысяч и даже миллионами. Целые мощные пакеты можно приобрести по цене меньшей, чем стоимость оплаты одного рабочего дня программиста. Эти две отрасли во многом различны и существуют параллельно.
Классическая программная индустрия. В 1975 году программная индустрия имела несколько отдельных и до некоторой степени различных составных частей, существующих по сей день:
• Производители компьютеров, поставляющие также операционные системы, компиляторы и утилиты для своих продуктов.
• Пользователи приложений, например, в информационно-управляющих системах, банках, страховых компаниях, правительственных учреждениях, создающие пакеты программ для собственного употребления.
• Разработчики заказных программ, работающие по контракту с пользователем. Многие из этих подрядчиков специализируются на приложениях для военной сферы, где требования, стандарты и маркетинговые процедуры носят специфический характер.
• Разработчики коммерческих пакетов, в то время разрабатывавшие, в основном, большие приложения для специфических рынков, такие как пакеты статистического анализа и автоматического проектирования.
Том Демарко отмечает фрагментацию классической индустрии разработки программного обеспечения, особенно в части пользователей приложений:
Я не ожидал, что эта область распадется на отдельные ниши. Приемы работы в большей степени определяются нишей, чем использованием общих методов анализа систем, языков программирования и технологий тестирования. Ada был последним из языков общего назначения, и он стал языков ниши.
В нише обычных коммерческих приложений значительный вклад сделан языками четвертого поколения (4GL). Бём пишет, что «наиболее удачные из 4GL явились результатом написания какой-либо части области приложений на языке опций и параметров». Наиболее широко распространенными из этих 4GL являются генераторы приложений и комбинированные пакеты баз данных и связи с языками запросов.
Миры операционных систем объединились. В 1975 году было изобили операционных систем — у каждого производителя компьютеров была, по крайней мере, одна патентованная операционная система для каждой производственной серии, а часто и две. Насколько изменилось положение сегодня! Лозунгом дня стали открытые системы, и осталось лишь пять главных операционных сред, для которых создаются пакеты приложений (в хронологическом порядке):
• IBM MVS и VM
• DEC VMS
• Unix в том или ином варианте
• IBM PC, будь то DOS, OS/2 или Windows
• Apple Macintosh.
Индустрия коробочных продуктов. Экономические законы для разработчиков в этой отрасли совершенно отличны от тех, которые действуют в классической индустрии: стоимость разработки нужно делить на большое количество экземпляров, расходы на упаковку и маркетинг высоки. В классической индустрии при внутрифирменной разработке график работ и набор функций могли быть изменены, в отличие от стоимости разработки. На открытом рынке жесткой конкуренции сроки и функциональность полностью доминируют над затратами на разработку.
Как и следовало ожидать, столь различные экономические требования породили весьма различающиеся культуры программирования. В классической индустрии лидирующее положение заняли крупные фирмы с установившимися стилями управления и культурой работы. В коробочной индустрии, напротив, возникли сотни начинающих фирм, ничем не связанных и сосредоточенных на конечной цели, а не на процессе. В такой атмосфере талант отдельного программиста всегда ценится значительно выше, и существует подспудное ощущение, что выдающиеся проекты создаются выдающимися архитекторами. Во вновь возникшей культуре есть возможность вознаграждать «звезд» соответственно их вкладу. В классической индустрии социальная политика фирм и их принципы оплаты труда всегда это затрудняли. Неудивительно поэтому, что многие звезды нового поколения были втянуты в орбиту пакетной индустрии.
Покупай и создавай: коробочные продукты в качестве компонентов
Радикально улучшить устойчивость программных продуктов и производительность труда при их создании можно, лишь поднявшись на один уровень и изготавливая программы из модулей или объектов. Особенно многообещающей тенденцией становится использование рыночных пакетов в качестве платформ, на которых создаются более богатые и специализированные продукты. Система управления движением грузовиков создается с помощью коробочной базы данных и коммуникационного пакета, также как и информационная система для студентов. Объявления в журналах предлагают сотни стеков для Hypercard, специализированных шаблонов для Excel, десятки специальных функций на Pascal для MiniCad или функций на AutoLisp для AutoCad.
Метапрограммирование. Стеки для Hypercard, специализированные шаблоны для Excel, функции для MiniCad часто называют метапрограммированием, созданием нового слоя, приспосабливающего функции к нуждам определенной группы пользователей пакета. Идея метапрограммирования не нова, она вернулась и получила свое название. В начале 60-х многие производители компьютеров и вычислительные центры больших информационно-управляющих систем образовывали небольшие группы специалистов, создававших целые языки прикладного программирования с помощью макросов, написанных на ассемблере. В вычислительном центре Eastman Kodak был создан язык прикладного программирования на базе макроассемблера для IBM 7080. Аналогично, в телекоммуникационной программе Queued Telecommunications Access Method для IBM OS/360 можно было на многих страницах кода, написанного предположительно на языке макроассемблера, не найти ни одной команды машинного уровня. Сейчас блоки, создаваемые метапрограммистом, значительно больше, чем тогдашние макроопределения. Такое развитие вторичного рынка очень обнадеживает: пока мы ждали возникновения активного рынка классов C++, незаметно возник рынок метапрограмм многократного использования.
Это действительно наступление на сущность. Поскольку на среднего программиста информационно-управляющих систем феномен разработки на основе пакетов еще не оказал воздействия, он пока не очень замечаем программной инженерией. Тем не менее, это направление будет быстро развиваться, поскольку затрагивает сущность моделирования концептуальных конструкций. Коробочный пакет предоставляет большой функциональный модуль со сложным, но точным интерфейсом, а его внутреннюю концептуальную структуру вовсе не требуется проектировать. Программные продукты с функциями высокого уровня, такие как Excel и 4th dimension, действительно являются большими модулями, но служат понятными, документированными, отлаженными модулями, с помощью которых можно создавать заказные системы. Разработчики приложений следующего уровня получают богатство функций, сокращение времени разработки, отлаженные компоненты, улучшенную документацию и резко сниженную цену.
Сложность, конечно, в том, что коробочные пакеты разработаны как самостоятельные объекты, функции и интерфейсы которых метапрограммисты не могут изменить. Кроме того, более существенно то, что разработчики коробочных пакетов, кажется, не слишком стремятся сделать свои продукты пригодными в качестве модулей более крупных систем. Думаю, что такое понимание неверно, и существует неудовлетворенный рынок для пакетов, способствующих использованию метапрограммирования.
Так что же требуется? Можно выделить четыре уровня пользователей коробочных продуктов:
• Пользователь как таковой, просто использующий приложение и удовлетворенный функциями и интерфейсом, предоставленными разработчиками.
• Метапрограммист, строящий шаблоны и функции поверх отдельного приложения с использованием имеющихся интерфейсов, главным образом, для обеспечения труда конечного пользователя.
• Разработчик внешних функций, вводящий в приложение дополнительные функции. Это, по сути, новые примитивы языка прикладного программирования, обращающиеся к отдельным модулям, написанным на языке общего назначения. Необходима возможность интерфейса этих новых функций с приложением через перехватываемые команды, обратные вызовы или перегружаемые функции.
• Метапрограммист, использующий одно и, в особенности, несколько приложений в качестве компонентов более крупной системы. Это пользователь, чьи нужды сегодня слабо удовлетворяются. Это тот вид использования, который обещает наибольший рост производительности при создании новых приложений.
Для этого последнего типа пользователей коробочный продукт должен иметь дополнительный документированный интерфейс — интерфейс
метапрограммирования. Он должен предоставлять несколько возможностей. Прежде всего, метапрограмма должна управлять ансамблем приложений, несмотря на то, что каждое приложение, как правило, считает, что управляет самим собой. Этот ансамбль должен управлять интерфейсом пользователя, хотя обычно само приложение считает, что делает это. Ансамбль должен быть в состоянии вызвать любую функцию приложения, как если бы его командная строка исходила от пользователя. Выходные данных приложения должны передаваться ему, а не на экран, причем в виде логических блоков подходящих типов данных, а не текстовой строки, которую нужно отобразить. В некоторых приложениях, например, FoxPro, есть дырочки, позволяющие передать командную строку, но возвращаются скудные и неразобранные данные. Такая дырочка — заплатка на скорую руку, в то время как требуется общее проработанное решение.
Большие возможности дало бы наличие языка сценариев для управления взаимодействием приложений, входящих в ансамбль. Такого рода функции впервые предоставила Unix с помощью каналов и стандарта файлов в формате ASCII-строк. Сегодня неплохим решением является AppleScript.
Состояние и будущее программной инженерии
Однажды я попросил Джима Феррелла (Jim Ferrell), председателя химико-технологического факультета университета штата Северная Каролина поведать о
развитии химических технологий вне связи с химией, на что он экспромтом выдал мне замечательный рассказ, продолжавшийся час, начиная с существовавших с античных времен различных производственных процессов для многих продуктов — от стали до хлеба и парфюмерных изделий. Он рассказал, как профессор Артур Д. Литтл (Arthur D. Little) в 1918 году основал в МТИ факультет прикладной химии для исследования, разработки и обучения общим фундаментальным технологиям всех процессов. Сначала были практические правила, затем эмпирические номограммы, затем рецепты проектирования отдельных компонентов, затем математические модели распространения тепла, масс, количества движения в отдельных емкостях.
По ходу рассказа Феррелла я поразился обилию параллелей между разработкой химических технологий и развитием программных технологий, происходившим почти полвека спустя. Парнас утверждает, что я вообще пишу о «программной инженерии». Он противопоставляет программотехнику как науку электротехнику и считает, что называть наше занятие инженерией самонадеянно. Возможно, он прав в том, что эта область никогда не станет инженерной дисциплиной с такой точной и всеохватывающей основой, какая есть у электротехники. В конце концов, программная инженерия, подобно химической технологии, занята нелинейными задачами увеличения масштабов до промышленных процессов и, подобно организации промышленного производства, постоянно ставится в тупик сложностями человеческого поведения.
Тем не менее характер и временные рамки развития химической технологии приводят меня к мысли, что программная инженерия в возрасте 27 лет не столько безнадежна, сколько является незрелой, какой химическая промышленность была в 1945 году. Лишь после Второй мировой войны химики-технологи реально обратились к взаимосвязанным поточным системам с замкнутым циклом.
Сегодня характерные задачи программной инженерии звучат точно так же, как они изложены в главе 1:
• Как проектировать и строить программы, образующие системы.
• Как проектировать и строить программы и системы, являющиеся надежным, отлаженным, документированным и сопровождаемым продуктом.
• Как осуществлять интеллектуальный контроль в условиях большой сложности.
В смоляной яме программной инженерии еще долго придется вязнуть. Можно ожидать, что человечество продолжит опыты с системами как внутри, так и за пределами наших возможностей. Программные системы являются, возможно, наиболее запутанными человеческими творениями. Это сложное ремесло требует непрерывно развивать эту дисциплину, учиться создавать из более крупных блоков, наилучшим образом использовать новые инструменты, старательно осваивать опробованные методы управления инженерией, щедро использовать здравый смысл и смиренно сознавать свою подверженность ошибкам и ограниченность наших возможностей.
Эпилог Пятьдесят лет удивления, восхищения и радости
В моей памяти все еще живы удивление и восторг, с которым я — мне тогда было 13 лет — читал отчет от 7 августа 1944 года об освящении компьютера Mark I, архитектором которого был Говард Айкен (Howard Aiken), а проектировщиками — инженеры Клер Лейк (Clair D. Lake), Бенджамин Дурфи (B. M. Durfee) и Фрэнсис Гамильтон (F. E. Hamilton). Такой же вызывающей ощущение чуда была статья Ванневара Буша (Vannevar Bush) «That We May Think» в апрельском 1945 года номере «Atlantic Monthly», в которой он предложил организовать знания в виде огромной гипертекстовой паутины и обеспечить пользователей машинами для переходов по существующим ссылкам и создания новых ассоциативных следов.
Новый толчок моя страсть к компьютерам получила в 1952 году, когда, работая летом на IBM в Эдинкоте, штат Нью-Йорк, я получил практический опыт программирования для IBM 604 и формальное обучение программированию для IBM 701, их первой машины с хранимой программой. Аспирантура у Айкена и Иверсона в Гарварде сделала реальностью мои мечты о профессии, и я связал с ней всю свою жизнь. Немногим Бог дает право зарабатывать на жизнь тем, чем они с радостью занимались бы по собственной воле, по увлечению. Я благодарен судьбе.
Для человека, влюбленного в компьютеры, трудно было бы придумать иное время, когда так радостно было жить. От механических устройств до вакуумных ламп, транзисторов и интегральных схем шло бурное развитие технологии. Первый компьютер, на котором я работал сразу после выпуска из Гарварда, был суперкомпьютер IBM Stretch. Этот компьютер царствовал над миром как самый быстрый с 1961 по 1964 годы; было изготовлено 9 экземпляров. Мой сегодняшний Macintosh Powerbook не только быстрее, с большей памятью и большим диском, но и в тысячу раз дешевле (в пять тысяч раз дешевле с учетом инфляции). Мы были свидетелями того, как поочередно произошли компьютерная революция, революция электронных компьютеров, революция миникомпьютеров и революция микрокомпьютеров, в результате каждой из которых компьютеров становилось на порядки больше.
Область связанных с компьютерами знаний претерпела взрыв, как и соответствующая технология. Будучи аспирантом в середине 50-х, я мог прочесть все журналы и труды конференций. Я мог оставаться на современном уровне во всей научной дисциплине. Сегодня же мне в моей интеллектуальной жизни приходится с сожалением расставаться с интересами то в одной, то в другой подобласти, поскольку количество документов превысило всякую возможность справиться с ними. Масса интересов, масса замечательных возможностей для учебы, исследований, размышлений. Чудесное затруднение! Не только конца не видно, но и шаг не замедляется. В будущем нас ожидают многие радости.
Примечания и ссылки
Глава 1
1.1. А. П. Ершов полагает, что это не только печаль, но отчасти и радость. A. P. Ershov. Aesthetics and the human factor in programming // CACM. 1972. Vol. 15, N 7. July. P. 501-505
Глава 2
2.1. В. А. Высоцкий из Bell Telephone Laboratories считает, что большой проект может выдержать до 30% прироста числа сотрудников в год. При большем увеличении затрудняется и даже подавляется развитие важной неформальной структуры и ее коммуникационных связей, о чем говорится в главе 7. Ф. Дж. Корбато из МТИ отмечает, что в длительном проекте следует ожидать ежегодной смены 20% сотрудников, и новые работники должны как получить техническую подготовку, так и влиться в формальную структуру.
2.2. Ч. Портман из International Computers Limited говорит: «Если все работает и объединено в систему, значит, осталось работы на четыре месяца». Некоторые другие способы распределения графика приведены в статье: Wolverton R. W. The cost of developing large-scale software // IEEE Trans. on Computers. 1974. Vol. C-23, N 6. June. P. 615-636.
2.3. Рисунками 2.5-2.8 я обязан Джерри Огдину, который, цитируя мой пример из более ранней публикации этой главы, значительно улучшил иллюстрации. Ogdin, J. L. The Mongolian hordes versus superprogrammer // Infosystems. 1972. Dec. P. 20-23.
Глава 3
3.1. Sackman H., Erikson W. J., Grant E. E. Exploratory experimentation studies comparing online and offline programming performance // CACM. 1968. Vol. 11, N 1. Jan. P. 3-11.
3.2. Mills H. Chief programmer team, principles, and procedures // IBM Federal Systems Division Report FSC 71-5108. Gaithersburg, Md., 1971.
3.3. Baker F. T. Chief programmer team management of production programming // IBM Sys. J. 1972. Vol. 11, N 1.
Глава 4
4.1. Eschapasse M. Reims Cathedral, Caisse Nationale des Monuments Histiriques. Paris, 1967.
4.2. Brooks F. P. Architectural Philosophy // Buchholz W. (Ed.). Planning a Computer System. New York: McGraw-Hill, 1962.
4.3. Blaauw G. A. Hardware requirements for the fourth generation // Gruenberger F. (ed.). Fourth Generation Computers. Englewood Cliffs, N. J.: Prentice-Hall, 1970.
4.4. Brooks F. P., Iverson K. E. Automatic Data Processing, System/360 Edition. New York: Wiley, 1969. Ch. 5.
4.5. Glegg G. L. The Design of Design. Cambridge : Cambridge Univ. Press, 1969: «На первый взгляд кажется, что мысль о том, чтобы наложить на творческий ум какие-то правила или принципы, скорее помешает ему, чем окажет помощь, но на практике это совершенно неверно. Дисциплинированное мышление скорее концентрирует вдохновение, чем подавляет его».
4.6. Conway R. W. The PL/C Compiler // Proceedings of a Conf. on Definition and Implementation of Universal Programming Languages. Stuttgard, 1970.
4.7. Хорошее обсуждение необходимости программных технологий см.: Reynolds C. H. What’s wrong with computer programming management? // Weinwurm G. F. (Ed.). On the Management of Computer Programming. Philadelphia : Auerbach, 1971. P. 35-42.
Глава 5
5.1. Strachey C. Review of Planning a Computer System // Comp. J. 1962. Vol. 5, N 2. July. P. 152-153.
5.2. Это относится только к управляющим программам. Некоторые бригады, разрабатывающие компиляторы для проекта OS/360, создавали уже свой третий или четвертый продукт, и отличное качество их продуктов это подтверждает.
5.3. Shell D. L. The Share 709 system: a cooperative effort; Greenwald I. D., Kane M. The Share 709 system: programming and modification; Boehm E. M., Steel T. B., Jr. The Share 709 system: machine implementation of symbolic programming. Все статьи // JACM. 1959. Vol. 6, N 2. Apr. P. 123-140.
Глава 6
6.1. Neustadt R. E. Presidential Power. New York: Wiley, 1960. Ch. 2.
6.2. Backus J. W. The syntax and semantics of the proposed international algebraic language // Proc. Intl. Conf. Inf. Proc. UNESCO, Paris, 1959 // Oldenbourg R., Munich and Butterworth. (Eds.). London. Кроме того, целая подборка статей на эту тему содержится в: Steel T. B., Jr. (Ed.). Formal Language Description Languages for Computer Programming. Amsterdam: North Holland, 1966.
6.3. Lucas P., Walk K. On the formal description of PL/I // Annual Review in Automatic Programming Language. New York: Wiley, 1962. Ch. 2. P. 2.
6.4. Iverson K. E. A Programming Language. New York: Wiley, 1962. Ch. 2.
6.5. Falkoff A. D., Iverson K. E., Sussenguth E. H. A formal description of System/360 // IBM Systems Journal. 1964. Vol. 3, N 3. P. 198-261.
6.6. Bell C. G., Newell A. Computer Structures. New York: McGraw-Hill, 1970. P. 120-136, 517-541.
6.7. Bell C. G. Частное сообщение.
Глава 7
7.1. Parnas D. L. Information distribution aspects of design methodology. Carnegie-Mellon Univ., Dept. Of Computer Science Technical Report. 1971. February.
7.2. Copyright 1939, 1940 Street & Smith Publications; Copyright 1950, 1967 Роберта А. Хайнлайна (Robert A. Heinlein). Публикуется по соглашению с Spectrum Literary Agency.
Глава 8
8.1. Sackman H., Erikson W. J., Grant E. E. Exploratory experimentation studies comparing online and offline programming performance // CACM. 1968. Vol. 11, N 1. Jan. P. 3-11.
8.2. Nanus B., Farr L. Some cost contributors to large-scale programs // AFIPS Proc. SJCC. Spring 1964. Vol. 25. P. 239-248.
8.3. Weinwurm G. F. Research in the management of computer programming // Report SP-2059, System Development Corp. Santa Monica, 1965.
8.4. Morin L. H. Estimation of resources for computer programming projects // M. S. thesis. Chapel Hill: Univ. Of North Carolina, 1974.
8.5. Portman C. Частное сообщение.
8.6. В неопубликованном исследовании 1964 года, которое провел E. F. Bardain, показано, что программисты продуктивно используют 27% рабочего времени. (Процитировано в: Mayer D. B., Stalnaker A. W. Selection and evaluation of computer personnel // Proc. 23d ACM Conf., 1968. P. 661.)
8.7. Aron J. Частное сообщение.
8.8. Доклад, сделанный на совещании и включенный в AFIPS Proceedings.
8.9. Wolverton R. W. The cost of developing large-scale software // IEEE Trans. On Computers. 1974. Vol. C-23, N 6. June. P. 615-636. В этой недавней важной статье содержатся данные по многим вопросам, обсуждаемым в этой главе, также подтверждающие выводы о производительности труда.
8.10. Corbato F. J. Sensitive issues in the design of multi-use systems // Лекция на открытии Технологического центра электронной обработки данных компании Honeywell, 1968.
8.11. W. M. Taliaffero также сообщает о постоянной проиводительности 2400 операторов в год на ассмблере, Fortran и Cobol. См.: Modularity. The key to system growth potential // Software. 1971. Vol. 1, N 3. July. P. 245-257.
8.12. В отчете Report TM-3225, Management Handbook for Estimation of Computer Programming Costs (Nelson E. A. из System Development Corp.) говорится о росте производительности 3:1 при использовании языка высокого уровня (стр. 66-67), хотя дисперсия высока.
Глава 9
9.1. Brooks F. P., Iverson K. E. Automatic Data Processing, System/360 Edition. New York: Wiley, 1969. Ch. 6.
9.2. Knuth D. E. The Art of Computer Programming. Vols. 1-3. Reading, Mass.: Addison-Wesley, 1968. ff.
Глава 10
10.1. Conway M. E. How do committees invent? // Datamation. 1968. Vol. 14, N 4. Apr. P. 28-31.
Глава 11
11.1. Речь в Оглеторпском университете 22 мая 1932 года.
11.2. Поучительный отчет об опыте использования MULTICS для создания двух систем имеется в: Corbaty F. J., Saltzer J. H., Clingen C. T. MULTICS — the first seven years // AFIPS Proc SJCC. 1972. Vol. 40. P. 571-583.
11.3. Cosgrove J. Needed: a new planning framework // Datamation. 1971. Vol. 17, N 23. Dec. P. 37-39.
11.4. Изменение проекта — сложная проблема, и здесь я ее чрезмерно упрощаю. См.: Saltzer J. H. Evolutionary design of complex systems // Eckman D. (Ed.). Systems : Research and Design. New York : Wiley, 1961. Все же, когда все сказано и сделано, я советую создать опытную систему, которую планируется выбросить.
11.5. Campbell E. Report to the AEC Computer Information Meeting. 1970. Dec. Это явление обсуждается также в: Ordin J. L. Designing reliable software // Datamation. 1972. Vol. 18, N 7. July. P. 71-78. Мнения моих опытных знакомых делятся примерно на равные части в отношении того, опускается ли кривая в конце.
11.6. Lehman M., Belady L. Programming systems dynamics. Представлено на ACM SIGOPS Third Symposium on Operating Systems Principles в октябре 1971 г.
11.7. Lewis C. S. Mere Christianity. New York : Macmillan, 1960. P. 54.
Глава 12
12.1. См. также: Pomeroy J. W. A guide to programming tools and techniques // IBM Sys. J. 1972. Vol. 11, N 3. P. 234-254.
12.2. Landy B., Needham R. M. Software engineering techniques used in the development of the Cambridge Multiple-Access System // Software. 1971. Vol. 1, N 2. Apr. P. 167-173.
12.3. Corbato F. J. PL/I as a tool for system programming // Datamation. 1969. Vol. 15, N 5. May. P. 68-76.
12.4. Hopkins M. Problems of PL/I for system programming // IBM Research Report RC 3489. 1971, August 5. Yorktown Heights, N. Y.
12.5. Corbato F. J., Saltzer J. H., Clingen C. T. MULTICS – the first seven years // AFIPS Proc SJCC. 1972. Vol. 40. P. 571-582. «Лишь около полудюжины кусков, написанных на PL/I, были перепрограммированы на машинном языке, чтобы выжать максимальную скорость. Несколько программ, первоначально написанных на машинном языке, были переписаны на PL/I, чтобы облегчить их сопровождение.»
12.6. Цитирую статью Корбато (ссылка 3 настоящей главы): «PL/I уже есть, а альтернативы пока не проверены». Однако совершенно противоположный и обоснованный взгляд представлен в Henricksen J. O., Merwin R. E. Programming language efficiency in real-time software systems // AFIPS Proc SJCC. 1972. Vol. 40. P. 155-161.
12.7. Не все с этим согласны. Гарлан Миллз отмечает в частном сообщении: «Опыт начинает подсказывать мне, что в промышленном программировании за терминал нужно посадить секретаря. Программирование следует сделать более общественным занятием при общем рассмотрении участников команды, а не частным занятием».
12.8. Yarr J. Programming Experience for the Number 1 Electronic Switching System. Доклад на SJCC 1969 г.
Глава 13
13.1. Vyssotsky V. A. Common sense in designing testable software. Лекция на симпозиуме по методам отладки компьютерных программ, Chapel Hill, N. C., 1972. Большая часть лекции содержится в Hetzel W. C. (Ed.). Program Test Methods. Englewood Cliffs, N. J. : Prentice-Hall, 1972. P. 41-47.
13.2. Wirth N. Program development by stepwise refinement // CACM. 1971. Vol. 14, N 4. Apr. P. 221-227. См. также: Mills H. Top-down programming in large systems // Rustin R. (Ed.). Debugging Techniques in Large Systems. Englewood Cliffs, N. J. : Prentice-Hall, 1971. P. 41-55; Baker F. T. System quality through structured programming // AFIPS Proc FJCC. 1972. Vol. 41-I. P. 339-343.
13.3. Dahl O. J., Dijkstra E. W., Hoare C. A. R. Structured programming. London ; New York : Academic Press, 1972. В этой книге содержится наиболее полное изложение. См. также основополагающее письмо Дейкстры: GOTO statement considered harmful // CACM. 1968. Vol. 11, N 3. March. P. 147-148.
13.4. Bцhm C., Jacopini A. Flow diagrams, Turing machines, and languages with only two formation rules // CACM. 1966. Vol. 9, N 5. May. P. 366-371.
13.5. Codd E. F., Lowry E. S., McDonough E., Scalzi C. A. Multiprogramming STRETCH: Feasibility considerations // CACM. 1959. Vol. 2, N 11. Nov. P. 13-17.
13.6. Strachey C. Time sharing in large fast computers // Proc. Int. Conf. On Info. Processing. 1959, June. UNESCO. P. 336-341. См. также замечания Кодда на стр. 341, где он сообщает о ходе работы, подобной предложенной в статье Стрейчи.
13.7. Corbato F. J., Merwin-Daggett M., Daley R. C. An experimental time-sharing system // AFIPS Proc SJCC. 1962. Vol. 2. P. 335-344. Перепечатано в: Rosen S. Programming Systems and Languages. New York : McGraw-Hill, 1967. P. 683-698.
13.8. Gold M. M. A methodology for evaluating time-shared computer system usage. Ph. D. dissertation. Carngie-Mellon University, 1967. P. 100.
13.9. Gruenberger F. Program testing and validating // Datamation. 1968. Vol. 14, N 7. July. P. 39-47.
13.10. Ralston A. Introduction to Programming and Computer Science. New York : McGraw-Hill, 1971. P. 237-244.
13.11. Brooks F. P., Iverson K. E. Automatic Data Processing, System/360 Edition. New York : Wiley, 1969, P. 296-299.
13.12. Проблемы разработки спецификаций, создания и тестирования систем хорошо изложены Трапнелом Ф. М. в: Trapnell F. M. A systematic approach to the development of system programs // AFIPS Proc SJCC. 1969. Vol. 34. P. 411-418.
13.13. Для системы реального времени потребуется модель окружения. См., например: Ginzberg M. G. Notes on testing real-time system programs // IBM Sys. J. 1965. Vol. 4, N 1. P. 58-72.
13.14. Lehman M., Belady L. Programming systems dynamics. Представлено в октябре 1971 г. на ACM SIGOPS Third Symposium on Operating Systems Priciples.
Глава 14
14.1. См.: Reynolds C. H. What’s wrong with computer programming management? // Weinwurm G. F. (Ed.). On the Management of Computer Programming. Philadelphia : Auerbach, 1971. P. 35-42.
14.2. King W. R., Wilson T. A. Subjective time estimates in critical path planning — a preliminary analysis // Mgt. Sci. 1967. Vol. 13, N 5. Jan. P. 307-320; King W. R., Witterrongel M., Hezel K. D. On the analysis of critical path time estimating behavior // Mgt. Sci. 1967. Vol. 14, N 1. Sept. P. 79-84.
14.3. Более подробное обсуждение см. Brooks F. P., Iverson K. E. Automatic Data Processing, System/360 Edition. New York : Wiley, 1969. P. 428-230.
14.4. Частное сообщение.
Глава 15
15.1. Goldsteine H. H., Neumann J. von. Planning and coding problems for en electronic computing instrument. Part II. Vol. 1. Отчет, подготовленный для U.S. Army Ordinance Department, 1947. Перепечатано в: Neumann J. von. Collected Works // Taub A. H. (Ed.). Vol. V. New York : Macmillan. P. 80-151.
15.2. Частное сообщение, 1957. Доказательство опубликовано в: Iverson K. E. The use of APL in Teaching. Yorktown, N.Y. : IBM Corp., 1969.
15.3. Другой список приемов для PL/I опубликован в: Walter A. B., Bohl M. From better to best — tips for good programming // Software Age. 1969. Vol. 3, N 11. Nov. P. 46-50. Эти же приемы можно использовать в Algol и даже Fortran. У Д. Е. Ланга из университета штата Колорадо есть написанная на Fortran программа форматирования под названием STYLE, с помощью которой можно получить такой результат. См. также: McCracken D. D., Weinberg G. M. How to write a readable FORTRAN program // Datamation. 1972. Vol. 18, N 10. Oct. P 73-77.
Глава 16
16.1. Очерк, озаглавленный «No Silver Bullet», взят из: Information Processing 1986, the Proceedings of the IFIP Tenth World Computing Conference под редакцией Х.-Й. Куглера, 1986, стр. 1069-1076. Перепечатано с любезного разрешения IFIP и Elsevier Science B. V., Амстердам, Нидерланды.
16.2. Parnas D. L. Designing software for ease of extension and contraction // IEEE Trans on SE. 1979. Vol. 5, N 2. March. P. 128-138.
16.3. Booch G. Object-oriented design // Software Engineering with Ada. Menlo Park, Calif. : Benjamin/Cummings, 1983.
16.4. Special Issue on Artificial Intelligence and Software Engineering // Mostow J. (Ed.). IEEE Trans. on SE. 1985. Vol. 11, N 11. Nov.
16.5. Parnas D. L. Software aspects of strategic defense systems // Communications of the ACM. 1985. Vol. 28, N 12. Dec. P. 1326-1335. См. также: American Scientist. 1985. Vol. 73, N 5. Sept.-Oct. P. 432-440.
16.6. Balzer R. A 15-year perspective on automatic programming в Mostow, цит. соч.
16.7. Mostow, см. примечание 4.
16.8. Parnas, 1985, см. примечание 5.
16.9. Raeder G. A survey of current graphical programming techniques // Grafton R. B., Ichikawa T. (Eds.). Special Issue on Visual Programming // Computer. 1985. Vol. 18, N 8. Aug. P. 11-25.
16.10. Тема обсуждается в главе 15 настоящей книги.
16.11. Mills H. Top-down programming in large systems // Rustin R. (Ed.). Debugging Techniques in Large Systems. Englewood Cliffs, N. J. : Prentice-Hall, 1971.
16.12. Boehm B. W. A spiral model of software development and enhancement // Computer. 1985. Vol. 20, N 5. May, P. 43-57.
Материал, цитируемый без ссылки, взят из частных сообщений.
1. Brooks F. P. No silver bullet — essence and accidents of software engineering // Kugler H. J. (Ed.). Information Processing 86. Amsterdam : Elsevier Science, North Holland, 1986. P. 1069-1076.
2. Brooks F. P. No silver bullet — essence and accidents of software engineering // Computer. 1987. Vol. 20, N 4. Apr. P. 10-19.
3. Несколько писем в ответ появились в июльском 1987 года выпуске «Computer». Особенно приятно заметить, что в то время как «СПН» не получила наград, Брюс М. Сквирски (Bruce M. Skwiersky) получил награду за лучший обзор, опубликованный в «Computer Reviews» в 1988 году. В редакционной статье Е. А. Вайса в «Computer Reviews» (июнь, 1988) на с. 283-284 объявляется о награде и перепечатывается обзор Сквирски. В обзоре есть существенная ошибка: вместо «шестикратно» должно быть «10[6].
4. «По Аристотелю и философии схоластиков, акциденция есть качество, которое принадлежит вещи не благодаря ее важной или существенной природе, а возникает в ней в результате действия иных причин». Webster’s New International Dictionary of the English Language, 2d ed., Springfield, Mass. : G. C. Merriam, 1960.
5. Sayers D. L. The Mind of the Market. New York : Harcourt, Brace, 1941.
6. Glass R. L., Conger S. A. Research software talks : Intellectual or clerical? // Information or Management. 1992. Vol. 23, N 4. Авторы сообщают, что разработка технических требований к программному обеспечению на 80% интеллектуальная и на 20% — канцелярская работа. Fjelstadt и Hamlen (1979) получили фактически такие же результаты для поддержки прикладных программ. Мне неизвестны попытки изменить эту долю для всей задачи от начала до конца.
7. Herzberg F., Mausner B., Sayderman B. B. The Motivation to Work. 2nded. London : Wiley, 1959.
8. Cox B. J. There is a silver bullet // Byte. 1990. Oct. P. 209-218.
9. Harel D. Biting the silver bullet : Toward a brighter future for system development // Computer. 1992. Jan. P. 8-20.
10. Parnas D. L. Software aspects of strategic defense systems // Communication of the ACM. 1985. Vol. 28, N 12. Dec. P. 1326-1335.
11. Turski W. M. And no philosophers’ stone, either // Kugler H. J. (Ed.). Information Processing 86. Amsterdam : Elsevier Science, North Holland, 1986. P. 1077-1080.
12. Glass R. L., Conger S. A. Research software tasks : Intellectual or clerical? // Information and Management, 1992. Vol. 23, N 4. P. 183-192.
13. Review of Electronic Digital Computers, Proceedings of a Joint AIEEIRE Computer Conference (Philadelphia, Dec. 10-12, 1951). New York : American Institute of Electrical Engineers. P. 13-20.
14. Ibid. Pp. 36, 68, 71, 97.
15. Proceedings of the Eastern Joint Computer Conference (Washington, Dec. 8-10, 1953). New York : Institute of Electrical Engineers. P. 45-47.
16. Proceedings of the 1955 Western Joint Computer Conference (Los Angeles, March 1-3, 1955). New York : Institute of Electrical Engineers.
17. Everett R. R., Zraket C. A., Bennington H. D. SAGE — a data processing system for air defense // Proceedings of the Eastern Joint Computer Conference (Washington, Dec. 11-13, 1957). New York : Institute of Electrical Engineers.
18. Harel D., Lachover H., Haamad A., Pnueli A., Politi M., Sherman R., Shtul-Traurig A. Statemate: A working environment for the development of complex reactive systems // IEEE Trans. on SE. 1990. Vol. 16, N 4. P. 403-444.
19. Jones C. Assessment and Control of Software Risks. Engltwood Cliffs, N. J. : Prentice-Hall, 1994. P. 619.
20. Coqui H. Corporate survival : The software dimension. Focus ’89, Cannes, 1989.
21. Coggins J. M. Designing C++ libraries // C++ Journal. 1990. Vol. 1, N 1. June. P. 25-32.
22. В будущем времени. Мне неизвестны какие-либо сообщения о результатах пятого использования.
23. Jones, см. примеч. 19. P. 604.
24. Huang Weigiao. Industrializing software production // Proceedings ACM 1988 Computer Science Conference. 1988. Atlanta. Боюсь, что при такой организации будет недостаточный личный профессиональный рост.
25. Весь сентябрьский 1994 года номер IEEE Software посвящен повторному использованию.
26. Jones, см. примеч. 19. P. 323.
27. Jones, см. примеч. 19. P. 329.
28. Yourdon E. Decline and Fall of the American Programmer. Englewood Cliffs, N. J. : Yourdon Press, 1992. P. 221.
29. Glass R. L. Glass (колонка) // System Development. 1988. Jan. P. 4-5.
Глава 18
18.1. Boehm B. W. Software Engineering Economics. Englewood Cliffs, N. J. : Prentice-Hall, 1981. P. 81-84.
18.2. McCarthy J. 21 Rules for Delivering Great Software on Time // Software World USA Conference, Washington (Sept. 1994).
Глава 19
Материал, цитируемый без ссылки, взят из частных сообщений.
19.1. По этой болезненной теме см. также: Niklaus Wirth. A plea for lean software // Computer. 1995. Vol. 28, N 2. Feb. P. 64-68.
19.2. Coleman D. Word 6.0 packs in features; update slowed by baggage // MacWeek. 1994. Vol. 8, N 38. Sept. 26. P. 1.
19.3. Опубликовано много обзоров частотных характеристик команд машинного языка и языка программирования, сделанных после выпуска. См., например: Hennessy J., Patterson D. Computer Architecture. Эти частотные данные очень полезны для создания последующих продуктов, хотя никогда в точности не применимы. Мне неизвестны публикации оценок, полученных до разработки продукта, а тем более — сравнений априорных данных с апостериорными. Кен Брукс полагает, что доски объявлений в Интернете предоставляют теперь дешевый способ запросить данные у предполагаемых пользователей нового продукта, даже несмотря на то что отвечают только желающие.
19.4. Conklin J., Begeman M. gIBIS : A hypertext Tool for Exploratory Policy Descussion // ACM Transactions on Office Information Systems. 1988. Oct. P. 303-331.
19.5. Englebart D., English W. A research center for augmenting human intellect // AFIPS Conference Proceedings, Fall Joint Computer Conference. San Francisco (Dec. 9-11, 1968). P. 395-410.
19.6. Apple Computer, Inc. Macintosh Human Interface Guidelines. Reading, Mass. : Addison-Wesley, 1992.
19.7. Кажется, шина Apple Desk Top Bus могла бы аппаратно поддерживать две мыши, но операционная система такой возможности не предоставляет.
19.8. Royce W. W. Managing the development of large software systems: Concepts and techniques // Proceedings, WESCON (Aug., 1970). Перепечатано в ICSE 9 Proceedings. Ни Ройс, ни другие не считали, что можно завершить процесс разработки, не пересматривая начальных документов. Модель была предложена в качестве идеальной. См.: Parnas D. L., Clements P. C. A rational design process : How and why to fake it // IEEE Transactions on Software Engineering. 1986. Vol. SE-12, N 2. Feb. P. 251-257.
19.9. В результате значительной переработки DOD-STD-2167 появился DOD-STD-2167A (1988), который допускает новые модели, например спиральную, но не обязывает более к их применению. К сожалению, MILSPECS, на который ссылается 2167A, и приведенные в качестве иллюстрации примеры по-прежнему, как сообщает Бём, используют каскадную схему. Специальная группа научного совета по обороне под руководством Ларри Друффела и Джорджа Хейлмейера в отчете 1994 года «Report of the DSB task force on acquiring defense software commercially» рекомендовала повсеместное использование новых моделей.
19.10. Mills H. Top-down programming in large systems // Rustin R. (Ed.). Debugging Techniques in Large Systems. Englewood Cliffs, N. J. : Prentice-Hall, 1971.
19.11. Parnas D. L. On the design and development of program families // IEEE Trans. on Software Engineering. 1976. Vol. SE-2, N 1. March, P. 1-9; Parnas D. L. Designing software for ease of extension and construction // IEEE Trans. on Software Engineering. 1979. Vol. SE-5, N 2. March. P. 128-138.
19.12. Harel D. Biting the silver bullet // Computer. 1992. Jan. P. 8-20.
19.13. Следующие статьи являются основополагающими в вопросе скрытия данных: Parnas D. L. Information distribution aspects of design methodology // Carnegie-Mellon Univ., Dept. Of Computer Science Technical Report. 1971. Feb.; Parnas D. L. A technique for software module specification with examples // Comm. ACM. 1972. Vol. 5, N 5. May. P. 330-336; Parnas D. L. (1972). On the criteria to be used in decomprosing systems into modules // Comm. ACM. 1972. Vol. 5, N 12. Dec. P. 1053-1058.
19.14. Идею объектов первоначально набросали Hoare и Dijkstra, но первое и наиболее важное развитие они получили в языке Simula-67, который разработали Dahl и Nygaard.
19.15. Boehm B. W. Software Engineering Economics. Englewood Cliffs, N. J. : Prentice-Hall, 1981. P. 83-94; 470-472.
19.16. Abdel-Hamid T., Madnick S. Software Project Dynamics : An Integrated Approach. Ch. 19 // Model enhancement and Brooks’s law. Englewood Cliffs, N. J. : Prentice-Hall, 1991.
19.17. Stutzke R. D. A mathematical expression of Brooks’s Law // Ninth International Forum on COCOMO and Cost Modeling. Los Angeles, 1994.
19.18. DeMarco T., Lister T. Peopleware : Productive Projects and Teams. New York : Dorset House, 1987.
19.19. Pius XI. Encyclical Quadragesimo Anno // Ihm, Claudia Carlen. (Ed.). The Papal Encyclicals 1903-1939. Raleigh, N. C. : McGrath. P. 428.
19.20. Schumacher E. F. Small Is Beautiful : Economics as if People Mattered. Perennian Library Edition. New York : Harper and Row, 1973. P. 244.
19.21. Schumacher, см. примеч. 20. P. 34.
19.22. Наводящий на мысли настенный плакат гласит: «Свобода печати принадлежит тому, у кого он есть». (Компьютер)
19.23. Bush V. That we may think // Atlantic Monthly. 1945. Vol. 176, N 1. Apr. P. 101-108.
19.24. Кен Томпсон из Bell Labs, создатель Unix, давно понял значение большого экрана для программиста. Он придумал, как на свою примитивную электронную трубку Tektronix выводить 120 строчек текста в две колонки. Он держался за свой терминал, пока сменилось целое поколение быстрых трубок с маленьким экраном.
Комментарии к книге «Мифический человеко-месяц, или Как создаются программные системы», Фредерик Брукс
Всего 0 комментариев