Искусство программирования для Unix
Шрифт:
Этот аргумент весьма удобен. Его можно применять к другим конструкциям, интегрирующим инструментальные средства, таким как (неудобно большие) проекты настольных интегрированных пакетов GNOME и KDE. Что-то в нем притягивает. Кроме того, не следует доверять какой-либо "перспективе", предлагающей столь искусно разрешить все сомнения. Она может оказаться рационализацией и не решить основную проблему.
Поэтому необходимо избегать крайностей отрицания или принятия того, что Emacs является полезной и большой программой — это и есть аргумент против минимализма Unix. Что кроме этого предлагает анализ видов сложности? И существует ли причина верить, что данные уроки сводятся к общим законам?
13.4. Необходимый размер программы
Для Unix-идеологии
Небольшие точные инструменты в Unix-стиле сталкиваются с трудностями при совместном использовании данных, если они не находятся внутри структуры, облегчающей их взаимодействие. Emacs является примером такой структуры, а единообразное управление общим контекстом достигается ценой необязательной сложности Emacs. Практическое влияние единообразного управления общим контекстом заключается в том, что пользователь не обременен проблемами низкоуровневого присваивания имен и управления ресурсами.
В Unix старой школы единственной интегрирующей структурой были конвейеры, перенаправление и shell. Интеграция осуществлялась с помощью сценариев, а общим контекстом была (по существу) сама файловая система. Однако на этом развитие не закончилось.
Программа Emacs объединила файловую систему с множеством текстовых буферов и вспомогательных процессов, почти совершенно оставляя структуру shell позади. Редактор Wily также предполагает использование буферов и вспомогательных процессов, но содержит в себе структуру shell. Современные настольные среды предоставляют GUI-интерфейсам структуру для обмена данными и тоже оставляют структуру shell позади. Каждая интегрирующая структура приложений имеет свои сильные и слабые стороны. Структуры приложений стали "жилищами" для множества инструментальных средств — shell для сценариев, Emacs для Lisp-режимов, а настольные среды для групп приложений, обменивающихся данными в GUI как посредством технологии "перетащить и отпустить", так и с помощь более "эзотерических" способов, таких как объектные брокеры.
Это выдвигает правило минимальности: необходимо выбирать общий контекст, которым требуется управлять, и создавать настолько малые программы, насколько позволяют данные границы. То есть "так просто, как только возможно, но не проще", но основное внимание в данном случае уделяется выбору общего контекста. Правило применимо не только к структурам, но и к приложениям и программным системам.
Однако очень легко ошибиться при определении необходимых размеров общего контекста. Над разработчиком довлеет сила, выраженная законом Завински,-склонность приложений к совместному использованию контекста в целях удобства использования. Вовсе нетрудно, в конце концов, получить чрезмерный размер, слишком большое количество предположений и писать большие программы с излишней сложностью. Так, URL mailto: (типичный пример 1990-х годов) вызвал рост количества крупных почтовых клиентов, встроенных в Web-браузеры.
Средство исправления данной тенденции приходит прямо из "священных книг" Unix — правило экономии: писать большую программу следует только в том случае, когда после демонстрации становится ясно, что ничего другого не остается, т.е. когда попытки расчленить проблему были предприняты, но потерпели неудачу. Данный принцип предполагает строгий скептицизм в отношении больших программ и стратегию, позволяющую избежать их создания: прежде всего, следует искать решение на основе небольшой программы. Если одна небольшая программа не решает задачу, необходимо попытаться создать инструментарий, состоящий из небольших взаимодействующих программ внутри существующей структуры. И только в том случае, если оба подхода оказались
При написании интегрирующей структуры приложений необходимо помнить правило разделения. Структуры приложений должны быть механизмом и заключать в себе как можно меньше политики. В большинстве случаев воебще без политики. Необходимо выделять как можно больше поведения в модули, которые используют структуру приложений. Одним из преимуществ написания или повторного использования структуры является то, что она позволяет выделить код, который в противном случае состоял бы из огромных монолитов политики, в отдельные модули, режимы или инструментальные средства, т.е. блоки, которые можно полезно комбинировать с другими.
Данные правила эмпирические, однако конфликт в сердце Unix-традиции не может быть разрешен несколькими априорными рецептами по оптимальному размеру любого заданного проекта. Обстоятельства изменяют решения, а гармония правильного мышления и хорошего стиля — основная задача разработчиков программного обеспечения. Аналогично тому, как в Дзэн путешествие является целью, "просветления" приходится каждый раз достигать заново путем повседневной практики.
Часть III Реализация
14 Языки программирования: С или не С?
Границы моего языка — границы моего мира. Логико-философский трактат (Tractatus Logico-Philosophicus 5.6,1918) —Людвиг Виттгенштейн (Ludwig Wittgenstein).
14.1. Многообразие языков в Unix
В Unix поддерживается более широкий по сравнению с любой другой операционной системой диапазон языков прикладного программирования. Фактически Unix способна поддерживать больше различных языков, чем все вместе взятые операционные системы в истории вычислительной техники.
Существует по крайней мере две весомые причины столь значительного разнообразия. Во-первых, широкое использование операционной системы Unix как исследовательской и обучающей платформы. Второй причиной (гораздо более значимой для работающих программистов) является тот факт, что подбор подходящего языка (или языков) для конструкции приложения может привести к огромным различиям в продуктивности программиста. Следовательно, Unix-традиции поддерживают проектирование узкоспециальных языков (как было сказано в главах 7 и 9) и языков, которые в настоящее время обычно называются языками сценариев, разработанных специально для связывания между собой других приложений и инструментальных средств.
Понятие "язык сценариев" (scripting language), вероятно, происходит от термина "сценарий" (script), который применялся к заранее подготовленному вводу для программы, обычно работающей в интерактивном режиме, в частности, sh или ed — гораздо более уместный термин, чем "runcom", унаследованный Unix от предка, операционной системы CTSS. Слово "script" появляется в руководстве для системы V7 (1979). Я не помню, кто именно придумал это название.
Дуг Макилрой.
В действительности термин "язык сценариев" несколько неудобен. Многие из основных языков, обычно описываемых как языки сценариев (Perl, Tel, Python и другие), уже переросли первоначальные задачи создания сценариев и в настоящее время являются самостоятельными универсальными языками программирования значительной мощности. Данный термин склонен срывать сильное сходство в стиле с другими языками, которые обычно не причисляются к этой группе, особенно с Lisp и Java. Единственным аргументом, оправдывающим нынешнее использование данного понятия, является тот факт, что лучшего термина еще никто не придумал.