Искусство программирования для Unix
Шрифт:
13.4. Необходимый размер программы
Для Unix-идеологии использования небольших, точных инструментов характерна скрытая двойственность; фон настолько неявный, что многие Unix-практики не замечают его или замечают не больше, чем рыба замечает воду, в которой плавает. Этим фоном являются интегрирующие структуры приложений (frameworks).
Небольшие точные инструменты в Unix-стиле сталкиваются с трудностями при совместном использовании данных, если они не находятся внутри структуры, облегчающей их взаимодействие. Emacs является примером такой структуры, а единообразное управление общим контекстом достигается ценой необязательной сложности Emacs. Практическое влияние единообразного управления общим контекстом заключается в
В Unix старой школы единственной интегрирующей структурой были конвейеры, перенаправление и shell. Интеграция осуществлялась с помощью сценариев, а общим контекстом была (по существу) сама файловая система. Однако на этом развитие не закончилось.
Программа Emacs объединила файловую систему с множеством текстовых буферов и вспомогательных процессов, почти совершенно оставляя структуру shell позади. Редактор Wily также предполагает использование буферов и вспомогательных процессов, но содержит в себе структуру shell. Современные настольные среды предоставляют GUI-интерфейсам структуру для обмена данными и тоже оставляют структуру shell позади. Каждая интегрирующая структура приложений имеет свои сильные и слабые стороны. Структуры приложений стали "жилищами" для множества инструментальных средств — shell для сценариев, Emacs для Lisp-режимов, а настольные среды для групп приложений, обменивающихся данными в GUI как посредством технологии "перетащить и отпустить", так и с помощь более "эзотерических" способов, таких как объектные брокеры.
Это выдвигает правило минимальности: необходимо выбирать общий контекст, которым требуется управлять, и создавать настолько малые программы, насколько позволяют данные границы. То есть "так просто, как только возможно, но не проще", но основное внимание в данном случае уделяется выбору общего контекста. Правило применимо не только к структурам, но и к приложениям и программным системам.
Однако очень легко ошибиться при определении необходимых размеров общего контекста. Над разработчиком довлеет сила, выраженная законом Завински, - склонность приложений к совместному использованию контекста в целях удобства использования. Вовсе нетрудно, в конце концов, получить чрезмерный размер, слишком большое количество предположений и писать большие программы с излишней сложностью. Так, URL
Средство исправления данной тенденции приходит прямо из "священных книг" Unix — правило экономии: писать большую программу следует только в том случае, когда после демонстрации становится ясно, что ничего другого не остается, т.е. когда попытки расчленить проблему были предприняты, но потерпели неудачу. Данный принцип предполагает строгий скептицизм в отношении больших программ и стратегию, позволяющую избежать их создания: прежде всего, следует искать решение на основе небольшой программы. Если одна небольшая программа не решает задачу, необходимо попытаться создать инструментарий, состоящий из небольших взаимодействующих программ внутри существующей структуры. И только в том случае, если оба подхода оказались безуспешными, традиции Unix позволяют разработчику создать крупную программу (или новую структуру приложения), не чувствуя себя при этом побежденным сложностью проектной задачи.
При написании интегрирующей структуры приложений необходимо помнить правило разделения. Структуры приложений должны быть механизмом и заключать в себе как можно меньше политики. В большинстве случаев вообще без политики. Необходимо выделять как можно больше поведения в модули, которые используют структуру приложений. Одним из преимуществ написания или повторного использования структуры является то, что она позволяет выделить код, который в противном случае состоял бы из огромных монолитов политики, в отдельные модули, режимы или инструментальные средства, т.е. блоки, которые можно полезно комбинировать с другими.
Данные правила эмпирические, однако конфликт в сердце Unix-традиции не может быть разрешен несколькими априорными рецептами по оптимальному размеру любого заданного проекта. Обстоятельства изменяют решения, а гармония правильного мышления и хорошего стиля — основная задача разработчиков программного обеспечения. Аналогично тому, как в Дзэн путешествие является целью, "просветления" приходится каждый раз достигать заново путем повседневной практики.
Часть III
Реализация
14
Языки программирования: С или не С?
Границы моего языка — границы моего мира.
14.1. Многообразие языков в Unix
В Unix поддерживается более широкий по сравнению с любой другой операционной системой диапазон языков прикладного программирования. Фактически Unix способна поддерживать больше различных языков, чем все вместе взятые операционные системы в истории вычислительной техники [117] .
Существует по крайней мере две весомые причины столь значительного разнообразия. Во-первых, широкое использование операционной системы Unix как исследовательской и обучающей платформы. Второй причиной (гораздо более значимой для работающих программистов) является тот факт, что подбор подходящего языка (или языков) для конструкции приложения может привести к огромным различиям в продуктивности программиста. Следовательно, Unix-традиции поддерживают проектирование узкоспециальных языков (как было сказано в главах 7 и 9) и языков, которые в настоящее время обычно называются языками сценариев, разработанных специально для связывания между собой других приложений и инструментальных средств.
117
Подробности на странице <ftp://ftp.idiom.com/pub/compilers-list/free-compilers> (Список бесплатных компиляторов и интерпретаторов).
Понятие "язык сценариев" (scripting language), вероятно, происходит от термина "сценарий" (script), который применялся к заранее подготовленному вводу для программы, обычно работающей в интерактивном режиме, в частности, sh или ed — гораздо более уместный термин, чем "runcom", унаследованный Unix от предка, операционной системы CTSS. Слово "script" появляется в руководстве для системы V7 (1979). Я не помню, кто именно придумал это название.
В действительности термин "язык сценариев" несколько неудобен. Многие из основных языков, обычно описываемых как языки сценариев (Perl, Tcl, Python и другие), уже переросли первоначальные задачи создания сценариев и в настоящее время являются самостоятельными универсальными языками программирования значительной мощности. Данный термин склонен срывать сильное сходство в стиле с другими языками, которые обычно не причисляются к этой группе, особенно с Lisp и Java. Единственным аргументом, оправдывающим нынешнее использование данного понятия, является тот факт, что лучшего термина еще никто не придумал.
Частично причиной того, что данные языки можно объединить в группу "языков сценариев" является то, что все они имеют почти совершенно идентичный онтогенез. Наличие динамической среды для интерпретации также сравнительно облегчает автоматизацию управления динамической памятью. Автоматизация управления динамической памятью требует использования ссылок (трудных для понимания адресов памяти, которые разработчик не в состоянии вычислять) вместо распространения копий значений или явных указателей. Использование ссылок делает динамический полиморфизм и ОО-методики следующим простым этапом.