Страница:
Благодаря этим успехам среды программирования стали предметом многих сегодняшних исследований в программной инженерии. В следующем параграфе мы рассмотрим, что от них можно ожидать, и какие им присуще ограничения.
Надежды на серебро
Рассмотрим теперь те технические достижения, которые чаще всего выдвигаются кандидатами на роль серебряной пули. К каким задачам они обращаются? Задачам, относящимся к сущности, или остаткам наших акцидентных сложностей? Предлагают ли они революционное развитие или пошаговое продвижение?
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, теперь шаблонно решается с помощью этих инструментов.
Многие пользователи изо дня в день применяют свои компьютеры для разных приложений, никогда не написав ни одной программы. На практике многие из этих пользователей и не могут писать для своих машин новые программы, но тем не менее приверженцы решению возникающих задач с их помощью.
Я считаю, что сегодня для многих организаций самая правильная политика для повышения производительности разработки программного обеспечения — это установить своим не имеющим компьютерных знаний работникам умственного труда компьютеры и хорошие общие программы для обработки текстов, рисования, работы с файлами и электронными таблицами и отпустить их в вольное плавание. Такая же политика в отношении распространенных математических и статистических пакетов, а также некоторых навыков программирования подойдет сотням ученых, работающих в лабораториях.
Уточнение требований и быстрое макетирование. Самая трудная отдельная задача в разработке программной системы — это точно решить, что разрабатывать. Ни одна другая задача работы над концепциями не является столь трудной, как разработка подробных технических требований, включая все интерфейсы пользователей, машинные интерфейсы и интерфейсы к другим программным системам. Ни одна другая часть работы не наносит такого ущерба готовой системе, если сделана неправильно. Ни одна другая часть не исправляется позднее с бульшим трудом.
Поэтому наиболее важной функцией, осуществляемой разработчиками для своих клиентов, является повторяющееся получение и уточнение требований к продукту. Правда заключается в том, что клиенты не знают, чего хотят. Обычно они не знают, на какие вопросы нужно дать ответ, и почти никогда не задумывались над задачей настолько детально, как это нужно указать в спецификации. Даже простой ответ — «сделайте так, чтобы новая программная система работала так, как наша старая ручная система обработки информации» — оказывается в действительности слишком упрощенным. Клиенты никогда не хотят этого в точности. Более того, сложные программные системы действуют, движутся, работают. Динамику этого действия трудно себе представить. Поэтому при планировании любых действий необходимо оставить резерв для многократного взаимодействия между клиентом и проектировщиком при описании системы.
Надежды на серебро
Рассмотрим теперь те технические достижения, которые чаще всего выдвигаются кандидатами на роль серебряной пули. К каким задачам они обращаются? Задачам, относящимся к сущности, или остаткам наших акцидентных сложностей? Предлагают ли они революционное развитие или пошаговое продвижение?
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, теперь шаблонно решается с помощью этих инструментов.
Многие пользователи изо дня в день применяют свои компьютеры для разных приложений, никогда не написав ни одной программы. На практике многие из этих пользователей и не могут писать для своих машин новые программы, но тем не менее приверженцы решению возникающих задач с их помощью.
Я считаю, что сегодня для многих организаций самая правильная политика для повышения производительности разработки программного обеспечения — это установить своим не имеющим компьютерных знаний работникам умственного труда компьютеры и хорошие общие программы для обработки текстов, рисования, работы с файлами и электронными таблицами и отпустить их в вольное плавание. Такая же политика в отношении распространенных математических и статистических пакетов, а также некоторых навыков программирования подойдет сотням ученых, работающих в лабораториях.
Уточнение требований и быстрое макетирование. Самая трудная отдельная задача в разработке программной системы — это точно решить, что разрабатывать. Ни одна другая задача работы над концепциями не является столь трудной, как разработка подробных технических требований, включая все интерфейсы пользователей, машинные интерфейсы и интерфейсы к другим программным системам. Ни одна другая часть работы не наносит такого ущерба готовой системе, если сделана неправильно. Ни одна другая часть не исправляется позднее с бульшим трудом.
Поэтому наиболее важной функцией, осуществляемой разработчиками для своих клиентов, является повторяющееся получение и уточнение требований к продукту. Правда заключается в том, что клиенты не знают, чего хотят. Обычно они не знают, на какие вопросы нужно дать ответ, и почти никогда не задумывались над задачей настолько детально, как это нужно указать в спецификации. Даже простой ответ — «сделайте так, чтобы новая программная система работала так, как наша старая ручная система обработки информации» — оказывается в действительности слишком упрощенным. Клиенты никогда не хотят этого в точности. Более того, сложные программные системы действуют, движутся, работают. Динамику этого действия трудно себе представить. Поэтому при планировании любых действий необходимо оставить резерв для многократного взаимодействия между клиентом и проектировщиком при описании системы.