Искусство программирования для Unix
Шрифт:
Еще хуже, когда ввод программы буферизируется (часто непреднамеренно, как в stdio). Программа, которая очевидно прекращает чтение в верной позиции, может, несмотря на это, впоследствии принять ввод.
Дуг Макилрой.
Программы, в которых главные процессы пытаются интерактивно обмениваться данными с подчиненными мини-языками, где данная проблема тщательно не проработана, подвержены взаимоблокировкам при рассинхронизации главного и подчиненного процессов (проблема, впервые упомянутая в главе 7).
Существуют обходные пути для управления мини-языками, разработанными не так тщательно. Прототипом для большинства из них является Tcl-пакет expect. Данный
В других языках доступны эквиваленты пакета expect. Полезную информацию можно найти в Web, используя в качестве поисковой фразы название языка с дополнительными ключевыми словами "Tel expect". Однако для разработчика мини-языка было бы недальновидно предполагать, что все пользователи являются специалистами по использованию пакета expect. Даже если они являются таковыми, данный подход является дополнительным связующим уровнем и местом возникновения ошибок.
При разработке мини-языка следует помнить о данной проблеме. Хорошей идеей может быть добавление опции, которая изменяет диалоговое поведение, и ответы становятся более похожими на протокол прикладного уровня с недвусмысленными разделителями конца вывода и аналогом заполнения байтами.
9 Генерация кода: повышение уровня спецификации
Попавший в тупик программист... часто может сделать больше, отходя от кода, останавливаясь и анализируя имеющиеся данные. Представление является сущностью программирования. "The Mythical Man-Month", юбилейное издание (1975-1995) —Фред Брукс
В главе 1 отмечалось, что людям гораздо удобнее мысленно представить себе данные, чем анализировать управляющую логику программы. Для того чтобы понять это, следует сравнить выразительность и дидактическую силу диаграммы 50-узло-вого дерева указателей с блок-схемой программы, состоящей из 50 строк. Или (что еще лучше) диаграмму инициализатора массива, выражающего таблицу преобразования, с эквивалентным оператором выбора. Различия в прозрачности и ясности поразительны'.
Данные более понятны, чем программная логика. Это верно независимо от того, являются ли данные обычной таблицей, декларативным языком разметки, системой шаблонов или набором макросов, которые расширяют программную логику. Хорошей практикой является перемещение как можно больше сложности конструкции из процедурного кода в данные, а также выбор форм представления данных, которые удобны для человека, осуществляющего сопровождение и манипулирующего этими данными. Преобразование таких форм в формы, пригодные для машинной обработки, — задача машин, а не людей.
Другим важным преимуществом высокоуровневых, более декларативных форм записи является то, что они лучше приспособлены к проверке во время компиляции. Для процедурных форм записи характерно сложное поведение во время выполнения программ, которое трудно анализировать на этапе компиляции. Декларативные нотации предоставляют гораздо больше возможностей для обнаружения ошибок, поскольку позволяют полнее понять запланированное поведение.
Генри Спенсер.
Это понимание
В главе 8 описывалось использование специализированных мини-языков. В главе 14 представлены аргументы в пользу языков очень высокого уровня. В данной главе рассматривается несколько примеров конструкции программ, управляемых данными, а также ряд примеров генерации особого кода. Некоторые средства генерации кода описаны в главе 15. Как и мини-языки, данные методы позволяют радикально сократить количество строк кода в программах и соответственно уменьшить время отладки и затраты на сопровождение.
9.1 Создание программ, управляемых данными
При создании программ, управляемых данными (data-driven programming), код и структуры данных, на которые он воздействует, четко отделяются друг от друга и проектируются так, чтобы можно было изменять логику программы путем редактирования не кода, а структуры данных.
Создание программ, управляемых данными, иногда путают с объектно-ориентированным программированием — еще одним стилем программирования, в котором самое важное значение имеет организация данных. Между данными стилями есть как минимум два отличия. Одно из них заключается в том, что в первом случае данные представляют собой не просто состояние некоторого объекта, а фактически определяют управляющую логику программы. Тогда как основной проблемой в ОО-програм-мировании является инкапсуляция, основная проблема при создании программ, управляемых данными, заключается в написании как можно меньшего количества фиксированного кода. Операционная система Unix имеет более устойчивые традиции в создании программ, управляемых данными, чем в ОО-программировании.
Разработку управляемых данными программ также часто путают с написанием конечных автоматов. Выразить логику конечного автомата в виде таблицы или структуры данных действительно возможно, однако запрограммированные вручную конечные автоматы обычно представляют собой жесткие блоки кода, которые гораздо труднее модифицировать, чем таблицу.
При выполнении любого вида генерации кода или создании программ, управляемых данными, необходимо помнить важное правило: решение проблемы всегда следует переносить на более высокие уровни. Не следует вручную улучшать сгенерированный код или любые промежуточные формы представления. Вместо этого следует задуматься о способе усовершенствования или замены средства трансляции. Иначе, вероятно, выяснится, что улучшение вручную кода, который должен был быть корректно сгенерированным машиной, превратится в бесконечную трату времени.
На верхней границе шкалы сложности создание управляемых данными программ сливается с написанием интерпретаторов для р-кода или простых мини-языков, которые рассматривались в главе 8. На других границах оно сливается с генерацией кода и программированием конечных автоматов. Различия фактически не так важны. Важной частью является перемещение логики программы из жестко закодированных управляющих структур в данные.
9.1.1. Учебный лример: ascii