Те, кто не понимает Unix, приговорены к ее созданию, несчастные.
Это книга о программировании в операционной системе Unix, но в ней неоднократно затрагиваются такие понятия, как "культура", "искусство" и "философия". Читателю, который не является программистом, или программисту, мало связанному с миром Unix, это может показаться странным. Однако операционная система Unix обладает собственной культурой; ей присуще особое искусство программирования и особая философия проектирования. Понимание этих традиций позволит разработчику создавать лучшее программное обеспечение, даже если оно не предназначено для Unix-платформ.
Каждой отрасли техники и проектирования присуща своеобразная техническая культура. В большинстве отраслей техники неписаные традиции являются частью образования практикующего специалиста, которая столь же важна, как официальные учебники и справочные руководства (а по мере накопления опыта часто является даже более важной). Старшие инженеры обнаруживают колоссальные объемы скрытых знаний, которые передаются их ученикам "особым путем" (как у Дзэн-буддистов), т.е. знания "распространяются посредством особой передачи вне священного писания".
Разработка программного обеспечения в общем случае является исключением из данного правила. Технология изменяется столь стремительно, программные среды появляются и исчезают настолько быстро, что т.н. техническая культура определяется как кратковременная и неустойчивая. В то же время это исключение также не всегда справедливо. Очень немногие программные технологии подтвердили свою долговечность, достаточную для развития устойчивой технической культуры, особого искусства и связанной с ним философии проектирования, которые передаются от поколения к поколению инженеров.
Одним из примеров такой культуры является культура операционной системы Unix. Другим примером является культура Internet. Однако в двадцать первом веке можно утверждать, что обе эти культуры представляют собой единое целое. Обе они сформировались, и с начала 80-х годов прошлого века разделять их становится все труднее, поэтому в данной книге четкие границы между ними не проводятся.
Операционная система Unix родилась в 1969 году и с момента возникновения находится в процессе постоянного использования и развития. Unix пережила несколько эпох, ограниченных стандартами компьютерной индустрии, — она старше, чем персональные компьютеры, рабочие станции, микропроцессоры или даже терминалы с видеодисплеями, и является современником первых полупроводниковых модулей памяти. Из всех современных систем разделения времени (timesharing systems) только о VM/CMS производства корпорации IBM можно утверждать, что она существует более продолжительный период, однако Unix-машины обеспечили в сотни тысяч раз больше служебных часов. Действительно, Unix, вероятно, поддерживает больший объем компьютерных вычислений, чем все остальные системы разделения времени.
Unix нашла свое применение в более широком диапазоне машин, чем любая другая операционная система. От суперкомпьютеров, рабочих станций и серверов, персональных и мини-компьютеров до карманных компьютеров и встроенного сетевого оборудования, Unix поддерживала и поддерживает, вероятно, больше архитектур и более разнообразное аппаратное обеспечение, чем какие-либо три другие операционные системы вместе взятые.
Операционная система Unix поддерживает невероятно широкий диапазон использования. Ни одна другая операционная система не служит одновременно в качестве инструмента исследований, дружественной основы для узкоспециальных технических приложений, платформы для коммерческого программного обеспечения бизнес-процессов и жизненно важного компонента технологии Internet.
Сомнительные предсказания о том, что Unix иссякнет или будет вытеснена другими операционными системами, постоянно высказываются с момента ее возникновения. Но до сих пор Unix, воплощенная сегодня в Linux, BSD Solaris и MacOS X и около десятка других вариантов, выглядит сильнее, чем когда-либо.
Роберт Меткалф (Robert Metcalf), создатель Ethernet, говорит, что если кто-либо разработает технологию, заменяющую Ethernet, то она будет названа "Ethernet", поэтому Ethernet не умрет никогда[3]. Unix уже пережила несколько подобных трансформаций.
Как минимум одна из центральных технологий Unix — язык С — широко распространен за пределами данной операционной системы. Действительно, в наши дни трудно представить разработку программного обеспечения без С, повсеместно используемого в качестве общего языка системного программирования. В Unix также были представлены широко распространенное в наши дни древовидное пространство имен файлов с узлами каталогов и конвейеры (pipeline) для сообщения программ.
Долговечность и способность Unix адаптироваться поистине удивительны. Другие технологии появляются и исчезают, как бабочки-однодневки. Мощность машин выросла в тысячи раз, языки трансформировались, промышленная практика пережила множество революций, a Unix остается, продолжает функционировать, приносить доход и пользуется приверженностью со стороны множества лучших и талантливейших разработчиков программных технологий планеты.
Одним из многих последствий экспоненциального роста соотношения мощности и времени в вычислительной технике, а также огромных темпов разработки программного обеспечения является то, что знания специалиста наполовину устаревают каждые 18 месяцев. Операционная система Unix не устраняет данный феномен, но серьезно его сдерживает. Такие неизменные базовые элементы, как языки, системные вызовы и вызовы инструментальных средств, действительно можно использовать в течение многих лет и даже десятилетий. Для других же систем невозможно предсказать, что будет оставаться стабильным, поскольку даже целые операционные системы периодически выходят из употребления. В Unix прослеживается четкое отличие между временными и постоянными знаниями, и специалист может заранее узнать (с 90-процентной уверенностью), какая категория предмета вероятнее всего устареет в процессе его изучения. Такова лояльность Unix.
Во многом стабильность и успех рассматриваемой операционной системы связаны с конструкторскими решениями Кена Томпсона, Денниса Ритчи, Брайана Кернигана, Дуга Макилроя, Роба Пайка и других разработчиков первых версий Unix. Однако стабильность и успех Unix также связаны с проектной философией, искусством программирования и технической культурой, которые развивались вокруг Unix.
Долговечность Unix и ее техническая культура, несомненно, интересны тому, кто уже является приверженцем данной операционной системы, и, возможно, историкам, изучающим развитие технологии. Однако первоначальное применение Unix в качестве общецелевой системы разделения времени для средних и крупных компьютеров быстро теряет свою актуальность благодаря появлению и развитию персональных рабочих станций. Есть определенные сомнения в том, что Unix когда-либо достигнет успеха на современном рынке настольных бизнес-приложений, где в настоящее время доминирует корпорация Microsoft.
Непрофессионалы часто отвергают Unix, считая ее академической игрушкой или "песочницей для хакеров". Так, широко известный спор, Unix Hater's Handbook [27], длится почти столько же лет, сколько лет самой Unix, причем в ходе этого спора ее приверженцев слишком часто называли чудаками и неудачниками. Свою роль в этом, несомненно, сыграли колоссальные и повторяющиеся ошибки корпораций AT&T, Sun, Novell, а также других коммерческих поставщиков и консорциумов по стандартизации в позиционировании и маркетинговой поддержке Unix.
Даже "изнутри" данная система не выглядит стабильной и универсальной. Скептики говорят, что Unix слишком полезна, чтобы умереть, но слишком неудобна, чтобы вырваться из лабораторий, т.е. считают ее только "нишевой" операционной системой.
Более всего доводы скептиков опровергает подъем операционной системы Linux и других Unix-систем с открытым исходным кодом (таких как современные варианты BSD). Культура Unix показала себя "слишком живучей", чтобы разрушиться даже после десятка ошибок поставщиков. В настоящее время Unix-сообщество, принявшее на себя управление технологией и маркетингом, быстро и очевидно решает проблемы данной операционной системы (способы разрешения проблем более подробно рассматриваются в главе 20).
Для конструкции, начало которой было положено в 1969 году, в высшей степени трудно идентифицировать конструкторские решения, которые определенно являются ошибочными.
Так, Unix-файлы не имеют структур выше байтового уровня. Удаление файлов является необратимой операцией. Есть основания утверждать, что модель безопасности в Unix слишком примитивна. Управление задачами реализовано некачественно. Существует слишком много различных названий одних и тех же явлений. Целесообразность файловой системы вообще ставится под сомнение. Перечисленные технические проблемы рассматриваются в главе 20.
Однако, возможно, что наиболее веские возражения против Unix являются следствием одного из аспектов ее философии, впервые в явном виде выдвинутого разработчиками системы X Window. Система X стремится обеспечить "механизм, а не политику" ("mechanism, not policy"), поддерживая чрезвычайно общий набор графических операций и передвигая возможность выбора инструментального набора, а также внешнего вида интерфейса (то есть политику), на уровень приложения. Подобные тенденции характерны и для других служб системного уровня в Unix. Окончательный выбор режима работы все в большей степени определяется пользователем, для которого доступно целое множество оболочек (shells). Unix-программы обычно обеспечивают несколько вариантов работы и активно используют сложные средства представления.
Данная тенденция характеризует Unix как систему, разработанную главным образом для технических пользователей, и подтверждает, что пользователям известно о своих потребностях больше, чем разработчикам операционной системы.
Эта доктрина была четко определена в Bell Labs Диком Хеммингом (Dick Hamming)[4]. В 50-х годах прошлого века, когда компьютеры были редкими и дорогими, он настаивал на том, что система общественных вычислительных центров (open-shop computing), где клиенты имеют возможность писать собственные программы, является крайне необходимой. Он считал, что: "лучше решить правильно выбранную проблему неверным путем, чем верным путем решить не ту проблему".
Однако в результате такого подхода ("механизм, а не политика") определился следующий постулат: если пользователь может установить политику, он вынужден ее устанавливать. Нетехнических пользователей "ошеломляет" изобилие параметров и стилей интерфейсов в Unix, из-за чего они предпочитают системы, в которых, по крайней мере, создана видимость простоты.
В ближайшей перспективе "политика невмешательства" Unix может привести к потере большого количества нетехнических пользователей. Однако в долгосрочной перспективе может оказаться, что эта "ошибка" создает важнейшее преимущество, поскольку время жизни политики, как правило, коротко, и оно значительно меньше времени жизни механизма. Сегодняшняя мода на интуитивные интерфейсы слишком часто становится завтрашней тупиковой ветвью эволюции (как эмоционально скажут пользователи устаревших инструментальных средств X). Оборотная сторона заключается в том, что философия "механизм, а не политика" может позволить Unix восстановить свою актуальность после того, как конкуренты, которые сильнее привязаны к одному набору политик или вариантов интерфейсов, пропадут из вида[5].
Недавний взрывной рост популярности операционной системы Linux и возрастающая важность Internet дают весомые причины полагать, что доводы скептиков неверны. Однако даже если скептическая оценка справедлива, Unix-культуру стоит изучать, поскольку существует ряд моментов, которые в Unix реализованы гораздо лучше, чем в конкурирующих операционных системах.
Несмотря на то, что понятия "открытый исходный код" (open source) и "определение открытого исходного кода" (open source definition) были сформулированы в 1998 году, коллективная разработка свободно распространяемого исходного кода была ключевой особенностью культуры Unix с момента ее возникновения.
В течение первых десяти лет первоначальная версия Unix, разработанная корпорацией AT&T, и ее основной вариант Berkeley Unix обычно распространялись с исходным кодом, что способствовало возникновению большинства других полезных явлений, которые описываются ниже.
Unix остается единственной операционной системой, которая в гетерогенной среде компьютеров, поставщиков и специализированного аппаратного обеспечения способна представить связный и документированный программный интерфейс приложений (Application Programming Interface — API). Она является единственной операционной системой, которую можно масштабировать от встроенных микросхем и карманных компьютеров до настольных машин, серверов и всего спектра вычислительной техники, включая узкоспециальные вычислительные комплексы и серверы баз данных.
API-интерфейс Unix — ближайший элемент к независимому от аппаратного обеспечения стандарту для написания действительно совместимого программного обеспечения. Не случаен тот факт, что стандарт, первоначально названный институтом IEEE стандартом переносимых операционных систем (Portable Operating System Standard), вскоре приобрел соответствующий суффикс и стал называться POSIX. Unix-эквивалент API был единственной заслуживающей доверия моделью для такого стандарта.
Приложения для других операционных систем, распространяемые в двоичном виде, исчезают вместе с породившими их средами, тогда как исходные коды Unix вечны, по крайней мере, в технической культуре Unix, которая совершенствует и поддерживает их в течение десятилетий.
Контракт Министерства обороны США на первую реализацию набора протоколов TCP/IP был направлен группе разработчиков Unix, поскольку исходные коды данной операционной системы были в значительной степени открытыми. Кроме TCP/IP, Unix стала одной из необходимых центральных технологий индустрии ISP (Internet Service Provider — провайдер Internet-услуг). Со времени выхода из употребления семейства операционных систем TOPS в середине 80-х годов двадцатого века большинство Internet-серверов (а фактически все машины выше уровня персональных компьютеров) стали работать под управлением Unix.
Даже ошеломляющее маркетинговое влияние корпорации Microsoft не способно потеснить распространение операционной системы Unix в Internet. Хотя TCP/IP-стандарты (на которых основывается Internet) развивались в среде TOPS-10 и теоретически отделены от Unix, попытки заставить их работать в других операционных системах скованы несовместимостью, нестабильностью и ошибками. Теория и спецификации являются общедоступными, однако инженерные традиции, позволяющие преобразовать их в единую и работающую реальность, существуют только в мире Unix[6].
Слияние технической культуры Internet и Unix-культуры началось в начале 80-х годов прошлого века, и в настоящее время эти культуры нераздельно переплетены. Своей конструкцией технология World Wide Web, "современное лицо" Internet, настолько же обязана Unix, насколько и своей предшественнице — сети ARPANET. В частности, концепция универсального указателя ресурсов (Uniform Resource Locator — URL), центрального элемента Web является обобщением характерной для Unix идеи о едином пространстве именования файлов. Для того чтобы решать проблемы на уровне Internet-эксперта, понимание Unix и ее культуры является чрезвычайно важным.
Сообщество, первоначально сформированное вокруг ранних дистрибутивов Unix, уже никогда не исчезало. После бурного роста Internet в начале 90-х годов в его ряды было вовлечено все новое поколение увлеченных хакеров с домашними компьютерами.
В настоящее время это сообщество является мощной группой поддержки для всех видов разработки программного обеспечения. Мир Unix изобилует высококачественными средствами разработки с открытыми исходными кодами (многие из которых рассмотрены далее в настоящей книге). Unix-приложения с открытым исходным кодом обычно эквивалентны, а часто и превосходят свои частные аналоги [23]. Полные Unix-подобные операционные системы с совершенными инструментариями и пакетами основных приложений доступны для бесплатной загрузки через Internet. Зачем создавать программы с нуля, когда можно адаптировать, использовать повторно, перерабатывать и экономить 90% рабочего времени, используя общедоступный код?
Эта традиция совместного использования кода во многом зависит от тяжело дающегося опыта кооперативной разработки программ и их повторного использования, который накапливается не с помощью абстрактной теории, а в процессе длительной инженерной практики. Эти неочевидные правила разработки позволяют программам функционировать не только как изолированные однократно используемые решения, но и как синергетические части инструментального набора. Главной целью данной книги является разъяснение этих правил.
В настоящее время "расцветающее" движение открытого исходного кода приносит в Unix-традиции новую жизненную силу, новые технические подходы и обогащает достижениями целых поколений талантливых молодых программистов. Проекты с использованием открытого исходного кода, включая операционную систему Linux и тесно связанные с ней компоненты, такие как Web-сервер Apache и Web-браузер Mozilla, придали Unix-традиции беспрецедентный уровень известности и успеха в современном мире. Движение открытого исходного кода, по всей видимости, выигрывает право на определение компьютерной инфраструктуры завтрашнего дня, и стержнем этой инфраструктуры станут Unix-машины, работающие в Internet.
Многие операционные системы, называемые более "современными" или более "дружественными по отношению к пользователю", чем Unix, достигают "внешней красоты" путем связывания пользователей и разработчиков одной интерфейсной политикой. В таких системах предлагается программный интерфейс приложений, который при всей своей сложности является довольно ограниченным и жестким. Задачи, которые были предусмотрены проектировщиками, выполняются в них весьма просто, однако непредусмотренные задачи часто невозможно выполнить или их выполнение является крайне затруднительным.
С другой стороны, операционная система Unix обладает большой гибкостью. Множество способов, предусмотренных в Unix для соединения программ друг с другом, позволяет утверждать, что компоненты ее основного инструментального набора могут комбинироваться для создания полезных эффектов, которые разработчики отдельных частей этого набора не предусматривали.
Поддержка операционной системой Unix множества стилей программных интерфейсов (которая часто рассматривается как недостаток, поскольку увеличивает видимую сложность системы для конечных пользователей) также способствовала развитию гибкости; ни одна программа, которая должна быть просто блоком обработки данных, не несет на себе издержек, связанных со сложностью замысловатого графического пользовательского интерфейса (GUI).
В Unix-традиции значительный акцент сделан на сохранении сравнительно небольших размеров интерфейсов программирования, их чистоты и ортогональности, что также способствует гибкости систем. Несложные действия выполняются просто, а выполнение сложных действий, как минимум, возможно.
Люди, провозглашающие техническое превосходство системы Unix, часто не уделяют достаточного внимания, может быть, наиболее важному ее преимуществу. Исследование Unix представляет особый интерес.
Кажется, что адептам Unix иногда бывает почти стыдно это признать. Как будто признание того, что они испытывают интерес, так или иначе может повредить их репутации. Тем не менее, это правда. Unix была и остается операционной системой, с которой интересно экспериментировать и в которой интересно разрабатывать программы.
Следует отметить, что это можно сказать далеко не о многих системах. Действительно, напряжение и труд разработчика в других средах часто сравнивают с выталкиванием мертвого кита с мели[7]. Напротив, в мире Unix операционная система скорее вознаграждает усилия, чем вызывает разочарование. Программисты в Unix обычно видят в ней не противника, победа над которым является главной целью, а скорее соратника.
В этом есть реальное экономическое значение. Фактор занимательности, конечно, сыграл свою роль. Людям нравилась Unix, поэтому они разрабатывали для нее больше программ, которые сделали ее использование приятным. В наши дни целые Unix-системы промышленного качества с открытым исходным кодом создаются людьми, которые воспринимают такую свою деятельность как хобби. Для того чтобы понять насколько это удивительно, достаточно попытаться найти людей, которые интереса ради занимаются клонированием операционных систем OS/360, VAX/VMS или Microsoft Windows.
Таким образом, фактор "интереса" ни в коем случае не является малозначительным. Те люди, которые становятся программистами или разработчиками, испытывают "интерес", когда их попытки, направленные на разрешение задачи, требуют от них изобретательности, но находятся в пределах их возможностей. Следовательно, "интерес" — это знак максимальной эффективности. Среды, в которых разработка программ становится тягостной, попусту "растрачивают" труд и творческое мышление, а впоследствии приводят к огромным скрытым затратам времени и средств.
Даже если бы Unix не характеризовалась иными достоинствами, то ее инженерную культуру стоило бы изучать для понимания тех ее особенностей, которые поддерживают интерес к разработке, поскольку именно этот фактор делает разработчика умелым и продуктивным.
Unix-программисты аккумулировали десятилетия опыта, пока наступил тот момент, когда функции новаторской операционной системы принимаются как должное. Даже программисты, не работающие с Unix, могут получить пользу от изучения данного опыта Unix. Так как Unix делает применение передовых принципов проектирования и методов разработки сравнительно простым, она является превосходной платформой для их изучения.
Другие операционные системы обычно делают хорошую практику более трудной, однако даже в этом случае можно использовать некоторые из уроков культуры Unix. Большая часть кода Unix (включая все ее фильтры, основные языки сценариев и многие генераторы кода) переносится непосредственно в любую операционную систему, поддерживающую ANSI С (по той причине, что язык С был "порождением" Unix, а библиотека ANSI С охватывает значительную часть Unix-служб).
"Unix-философия" возникла вместе с ранними размышлениями Кена Томпсона о том, как сконструировать небольшую, но совершенную операционную систему с ясным служебным интерфейсом. Она развивалась по мере того, как Unix-культура изучала возможности получения максимального эффекта от проекта Томпсона, и в процессе этого развития впитывала уроки "предыдущей истории".
Философия Unix не является формальным методом проектирования. Она не была та свыше" как способ создания теоретически идеального программного обеспечения. Unix-философия (как удачные народные традиции в других инженерных дисциплинах) прагматична и основывается на опыте. Ее следует искать не в официальных методах и стандартах, а скорее в скрытых почти рефлекторных знаниях и опыте, который передается культурой Unix. Она культивирует чувство меры и достаточный скептицизм.
Дуг Макилрой, изобретатель каналов (pipes) в Unix и один из основателей Unix-традиции, сформулировал постулаты философии Unix следующим образом [52].
(i) Заставьте каждую программу хорошо выполнять одну функцию. Для решения новой задачи следует создавать новую программу, а не усложнять старые программы добавлением новых функций.
(ii) Будьте готовы к тому, что вывод каждой программы станет вводом другой, еще неизвестной программы. Не загромождайте вывод посторонней информацией. Избегайте строгих табличных или двоичных форматов ввода. Не настаивайте на интерактивном вводе.
(iii) Проектируйте и создавайте программное обеспечение, даже операционные системы, которые можно будет проверить в самом начале, в идеальном случае в течение нескольких недель. Без колебаний выбрасывайте громоздкие части и перестраивайте их.
(iv) Вместо неквалифицированной помощи используйте инструменты, облегчающие программирование, даже если инструменты приходится создавать "окольными" путями, зная, что некоторые из них будут удалены по окончании использования.
Позднее он обобщил эти положения (процитировано в книге "A Quarter Century of Unix" [74]).
Вот в чем заключается философия Unix: пишите программы, которые выполняют одну функцию и делают это хорошо; пишите программы, которые будут работать вместе; пишите программы, поддерживающие текстовые потоки, поскольку они являются универсальным интерфейсом.
Роб Пайк, который стал одним из великих мастеров языка С, в книге "Notes on С Programming" [62] предлагает несколько иной угол зрения.
Правило 1. Невозможно сказать, где возникнет задержка в программе. "Бутылочные горлышки" возникают в неожиданных местах, поэтому не следует пытаться делать предсказания и исправлять скорость до тех пор, пока не будет точно выяснено, где находится "бутылочное горлышко".
Правило 2. Проводите измерения. Не следует регулировать скорость до тех пор, пока не проведены измерения, и даже после измерений, если одна часть кода подавляет остальные.
Правило 3. Вычурные алгоритмы очень медленные, когда величина
n
является малой, а она обычно мала. Вычурные алгоритмы имеют большие константы. До тех пор, пока не известно, что n
периодически стремится к большим значениям, не следует усложнять алгоритмы. (Даже если n действительно достигает больших значений, сначала используйте правило 2.)
Правило 4. Вычурные алгоритмы более склонны к появлению ошибок, чем простые, и их гораздо сложнее реализовать. Используйте простые алгоритмы, а также простые структуры данных.
Правило 5. Данные доминируют. Если выбраны правильные структуры данных и все организовано хорошо, то алгоритмы почти всегда будут очевидными. Для программирования центральными являются структуры данных, а не алгоритмы[8].
Правило 6. Правила 6 нет.
Кен Томпсон, спроектировавший и реализовавший первую Unix, усилил четвертое правило Пайка афористичным принципом, достойным Дзэн-патриарха:
В случае сомнений используйте грубую силу.
Гораздо сильнее Unix-философия была выражена не высказываниями старейшин, а их действиями, которые воплощает сама Unix. В целом, можно выделить ряд идей.
1. Правило модульности: следует писать простые части, связанные ясными интерфейсами.
2. Правило ясности: ясность лучше, чем мастерство.
3. Правило композиции: следует разрабатывать программы, которые будут взаимодействовать с другими программами.
4. Правило разделения: следует отделять политику от механизма и интерфейсы от основных модулей.
5. Правило простоты: необходимо проектировать простые программы и "добавлять сложность" только там, где это необходимо.
6. Правило расчетливости: пишите большие программы, только если после демонстрации становится ясно, что ничего другого не остается.
7. Правило прозрачности: для того чтобы упростить проверку и отладку программы, ее конструкция должна быть обозримой.
8. Правило устойчивости: устойчивость— следствие прозрачности и простоты.
9. Правило представления: знания следует оставлять в данных, чтобы логика программы могла быть примитивной и устойчивой.
10. Правило наименьшей неожиданности: при проектировании интерфейсов всегда следует использовать наименее неожиданные элементы.
11. Правило тишины: если программа не может "сказать" что-либо неожиданное, то ей вообще не следует "говорить".
12. Правило исправности: когда программа завершается аварийно, это должно происходить явно и по возможности быстро.
13. Правило экономии: время программиста стоит дорого; поэтому экономия его времени более приоритетна по сравнению с экономией машинного времени.
14. Правило генерации: избегайте кодирования вручную; если есть возможность, пишите программы для создания программ.
15. Правило оптимизации: создайте опытные образцы, заставьте их работать, прежде чем перейти к оптимизации.
16. Правило разнообразия: не следует доверять утверждениям о "единственно верном пути".
17. Правило расширяемости: проектируйте с учетом изменений в будущем, поскольку будущее придет скорее, чем кажется.
Новичкам в Unix стоит поразмышлять над данными принципами. Технические тексты по разработке программного обеспечения рекомендуют большую их часть, однако в других операционных системах, как правило, имеется недостаток необходимых средств и традиций для их внедрения, поэтому большинство программистов не могут применять их последовательно. Они принимают несовершенные инструменты, плохие конструкции, перенапряжение и распухший код как должное, а впоследствии удивляются, почему все это раздражает поклонников Unix.
Как однажды заметил Браян Керниган, "управление сложностью является сущностью компьютерного программирования" [41]. Отладка занимает большую часть времени разработки, и выпуск работающей системы обычно в меньшей степени является результатом талантливого проектирования, и в большей — результатом должного управления, исключающего многократное повторение ошибок.
Трансляторы, компиляторы, блок-схемы, процедурное программирование, структурное программирование, "искусственный интеллект", языки четвертого поколения, объектно-ориентированные языки и бесчисленные методологии разработки программного обеспечения рекламировались и продавались как средство борьбы с этой проблемой. Все они потерпели неудачу, если только их успех заключался в повышении обычного уровня сложности программы до той точки, где (вновь) человеческий мозг едва ли мог справиться. Как заметил Фред Брукс [8], "серебряной пули не существует".
Единственным способом создания сложной программы, не обреченной заранее на провал, является сдерживание ее глобальной сложности, т.е. построение программы из простых частей, соединенных четко определенными интерфейсами, так что большинство проблем являются локальными, и можно рассчитывать на обновление одной из частей без разрушения целого.
Поскольку обслуживание является важным и дорогостоящим, следует писать такие программы, как если бы обмен наиболее важной информацией, осуществляемый программой, был связан не с компьютером, выполняющим данную программу, а с людьми, которые будут читать и поддерживать исходный код в будущем (включая и самого создателя программы).
В традициях Unix смысл данной рекомендации выходит за пределы простого комментирования кода. Хорошая Unix-практика также предполагает выбор алгоритмов и реализации с учетом дальнейшего обслуживания. Незначительный рост производительности ценой большого повышения сложности и запутанности методики относится к плохой практике не только потому, что сложный код, вероятнее всего, скрывает в себе ошибки, но также потому, что такой код будет тяжелее читать будущим кураторам (maintainers) программы.
С другой стороны, тот, кому впоследствии придется изменять программу, вряд ли будет поставлен в тупик изящным и ясным кодом — более вероятно, что он немедленно в нем разберется. Это особенно важно, если спустя несколько лет следующим куратором, возможно, будет сам создатель программы.
Не пытайтесь трижды расшифровывать хитроумный код. Однажды возможна неповторимая удача, однако, если придется разбираться в коде во второй раз, поскольку впервые он рассматривался слишком давно и детали позабыты, то это означает, что необходимо внести в код комментарии таким образом, чтобы третий раз был относительно безболезненным.
Если разрабатываемые программы не способны взаимодействовать друг с другом, то очень трудно избежать создания сложных монолитных программ.
Традиция Unix значительно способствует написанию программ, которые считывают и записывают простые текстовые форматы, ориентированные на потоки и не зависящие от устройств. В классической реализации Unix как можно больше программ создаются в виде простых фильтров (filters), которые на входе принимают простой текстовый поток и преобразовывают его в другой простой текстовый поток на выходе.
Вопреки распространенному мифу, такая практика широко распространена не потому, что Unix-программисты ненавидят графические пользовательские интерфейсы. Данная практика пользуется популярностью Unix-программистов, поскольку связывать вместе программы, не принимающие и не создающие на выходе простые текстовые потоки, гораздо труднее.
Текстовые потоки для Unix-инструментов являются тем же, чем являются сообщения для объектов в объектно-ориентированной среде. Простота интерфейса текстовых потоков усиливает инкапсуляцию инструментальных средств. Более сложные формы межпроцессного взаимодействия, такие как удаленный вызов процедур (remote procedure call), демонстрируют тенденцию к использованию программ с сильными внутренними зависимостями друг от друга.
Для того чтобы создавать компонуемые программы, их следует делать независимыми. Программа с одной стороны текстового потока как можно меньше должна зависеть от программы на другой стороне. Должна быть обеспечена возможность замены программы с одной стороны абсолютно другой реализацией без нарушения работы второй стороны.
GUI-интерфейсы могут быть разработаны на весьма высоком уровне. Иногда просто невозможно избежать сложных двоичных форматов данных какими-либо приемлемыми способами. Однако прежде чем создавать GUI-интерфейс, разумно будет изучить возможность выделения частей разрабатываемой программы со сложным взаимодействием в один блок, а основных алгоритмов — в другой, а также использования простого потока команд или прикладного протокола для связи двух блоков. Прежде чем изобретать нетривиальный двоичный формат для распространения данных, стоит экспериментальным путем проверить, имеется ли возможность задействовать простой текстовый формат и согласиться с небольшими затратами на синтаксический анализ в обмен на возможность обработки потока данных с помощью универсальных инструментальных средств.
В ситуации, когда сериализованный интерфейс, подобный протоколу, не является естественным для разрабатываемого приложения, конструкция "в духе Unix" заключается в том, чтобы, по крайней мере, организовать как можно больше программных примитивов в библиотеку с хорошо определенным API-интерфейсом. В таком случае открываются возможности вызова приложений путем связывания или привязки к приложению нескольких интерфейсов для различных задач.
Данная проблема подробнее обсуждается в главе 7.
В разделе "Что в Unix делается неверно" отмечалось, что разработчики системы X Window приняли основное решение о реализации "механизма, а не политики". Такой подход был направлен на то, чтобы сделать систему X общим сервером обработки графики и передать решение о стиле пользовательского интерфейса инструментариям и другим уровням системы. Это оправданно, если учесть, что политика и механизм стремятся к изменению на протяжении различных периодов времени, причем политика меняется гораздо быстрее, чем механизм. Мода на вид и восприятие GUI-инструментариев может прийти и уйти, но растровые операции и компоновка останутся.
Таким образом, жесткое объединение политики и механизма имеет два отрицательных эффекта. Во-первых, политика становится негибкой и усложняется ее изменение в ответ на пользовательские требования. Во-вторых, это означает, что попытка изменения политики имеет строгую тенденцию к дестабилизации механизмов.
С другой стороны, разделение двух этих элементов делает возможным экспериментирование с новой политикой без разрушения механизмов. Кроме того, облегчается написание хороших тестов для механизма (политика, ввиду своего быстрого изменения, часто не оправдывает вложений).
Данное правило проектирования широко применимо вне контекста GUI-интерфейсов. В целом оно подразумевает, что следует искать способы разделения интерфейсов и основных модулей.
Одним из способов осуществления такого разделения, в частности, является написание приложения в виде библиотеки служебных подпрограмм на С, которые приводятся в действие встроенным языком сценариев, а управляющая логика приложения вместо С написана на языке сценариев. Классическим примером такой модели является редактор Emacs, в котором для управления редактирующими примитивами, написанными на С, используется встроенный интерпретатор языка Lisp. Такой стиль программирования обсуждается в главе 11.
Другой способ заключается в разделении приложения на взаимодействующие процессы клиента (front-end) и сервера (back-end), которые обмениваются данными через специализированный протокол прикладного уровня посредством сокетов. Данный конструкторский подход рассматривается в главах 5 и 7. Во внешней или клиентской части реализуется политика, а во внутренней или серверной — механизм. Глобальная сложность данной пары часто является значительно меньшей, чем сложность одного процесса, в котором монолитно реализованы те же функции. Одновременно уменьшается уязвимость относительно ошибок и сокращаются затраты на жизненный цикл.
Многие факторы приводят к усложнению программ (а следовательно, делают их более дорогими и более уязвимыми относительно ошибок). Программисты — это зачастую яркие люди, которые гордятся (часто заслуженно) своей способностью справляться со сложностями и ловко обращаться с абстракциями. Часто они состязаются друг с другом, пытаясь выяснить, кто может создать "самые замысловатые и красивые сложности". Столь же часто их способность проектировать превалирует над способностью реализовывать и отлаживать, а результатом является дорогостоящий провал.
Мнение о "замысловатой и красивой сложности" является почти оксюмороном. Unix-программисты соперничают друг с другом за "простоту и красоту". Эта мысль неявно присутствует в данных правилах, но ее стоит сделать очевидной.
Еще чаще (по крайней мере, в мире коммерческого программного обеспечения) излишняя сложность исходит от проектных требований, которые скорее основаны на маркетинговой причуде месяца, а не на реальных пожеланиях заказчика или фактических возможностях программы. Множество хороших конструкций были раздавлены маркетинговым нагромождением "статей контрольного перечня" — функций, которые часто вообще не востребованы заказчиком. Круг замыкается; соперники полагают, что должны соревноваться с чужими "украшательствами" путем добавления собственных. Довольно скоро "массивная опухоль" становится индустриальным стандартом, и все используют большие, переполненные ошибками программы, которые не способны удовлетворить даже их создателей.
В любом случае, в конечном результате проигрывают все.
Единственным способом избежать этих ловушек является поощрение культуры программного обеспечения, представители которой знают, что компактность красива, и активно сопротивляются "раздуванию" и сложности кода. Речь идет об инженерной традиции, высоко оценивающей простые решения и ищущей способы разделения программных систем на небольшие взаимодействующие блоки, традиции, которая борется с попытками создания программ с большим количеством "украшательств" (или даже хуже — проектирования программ вокруг "украшательств").
Таковой была бы культура, во многом похожая на культуру Unix.
Под "большими программами" в здесь подразумеваются программы с большим объемом кода и значительной внутренней сложностью. Разрешая программе разрастаться, разработчик ставит под удар дальнейшее обслуживание данной программы. Поскольку люди неохотно расстаются с видимым результатом длительной работы, крупные программы привлекают излишние вложения в подходах, которые ошибочны или неоптимальны.
Проблема оптимального размера программного обеспечения более подробно рассмотрена в главе 13.
Поскольку отладка часто занимает три четверти или более времени разработки, раннее окончание работы в целях облегчения отладки может быть очень хорошим решением. Особенно эффективный способ простой отладки заключается в проектировании с учетом прозрачности (transparency) и воспринимаемости (discoverability).
Программная система прозрачна, если при ее минимальном изучении можно немедленно понять, что она делает и каким образом. Программа воспринимаема, когда она имеет средства для мониторинга и отображения внутреннего состояния, так что программа не только работает хорошо, но и позволяет понять признаки правильной работы.
Проектирование с учетом данных характеристик имеет ряд последствий на всем протяжении проекта. Как минимум, это означает, что отладочные возможности не должны запаздывать. Скорее они должны быть спроектированы с самого начала — с той точки зрения, что программа должна быть способна как продемонстрировать собственную корректность, так и передать будущим разработчикам ментальную модель решаемой программой проблемы, разработанную создателем программы.
Для того чтобы программа могла продемонстрировать свою корректность, в ней должны использоваться достаточно простые форматы входных и выходных данных, с тем чтобы можно было легко проверить соответствующую связь между допустимым вводом и корректным выводом.
Цель разработки с учетом прозрачности и воспринимаемости также должна поддерживать простые интерфейсы, которыми могут легко манипулировать другие программы, в особенности средства тестирования и мониторинга, а также отладочные сценарии.
Программное обеспечение называют устойчивым, когда оно выполняет свои функции в неожиданных условиях, которые выходят за рамки предположений разработчика, столь же хорошо, как и в нормальных условиях.
Большинство программ "являются хрупкими и переполненными ошибками, поскольку для человеческого мозга слишком сложно сразу понять всю программу целиком. Если нет возможности сделать корректный вывод о внутреннем устройстве программы, то нельзя быть уверенным в ее корректности, и ее невозможно исправить в случае поломки.
Следовательно, способ создания устойчивого программного обеспечения заключается в организации такого внутреннего устройства программ, которое было бы простым для понимания человеком. Существует два основных способа достижения этой цели: прозрачность и простота.
Для достижения устойчивости очень важным является проектирование, допускающее необычный или крайне объемный ввод. Этому способствует правило композиции; ввод, сгенерированный другими программами, известный для программ нагрузочных испытаний (например, оригинальный Unix-компилятор С по имеющимся сообщениям нуждался в небольшом обновлении, для того чтобы хорошо обрабатывать вывод утилиты Yacc). Используемые формы часто кажутся бесполезными для людей. Например, допускаются пустые списки, строки и т.д. даже в тех местах, где человек редко или никогда не вводит пустую строку. Это предотвращает особые ситуации при механическом генерировании ввода.
Один весьма важный тактический прием для достижения устойчивости при работе с необычным вводом заключается в том, чтобы избегать частных случаев в коде. Часто ошибки скрываются в коде для обработки частных случаев, а также возникают в процессе взаимодействия частей кода, предназначенных для обработки различных частных случаев.
Как отмечалось выше, программа является прозрачной в том случае, если при ее минимальном изучении немедленно становится ясно, что происходит. Программа является простой, если происходящее в ней не представляется сложным для восприятия человеком. Чем сильнее эти свойства проявляются в разрабатываемых программах, тем устойчивее они будут.
Модульность (простые блоки, ясные интерфейсы) является способом организации программ, позволяющим сделать их проще. Существуют и другие способы достижения простоты. Ниже описывается один из них.
Даже простейшую процедурную логику трудно проверить, однако весьма сложные структуры данных являются довольно простыми для моделирования и анализа. Для того чтобы убедиться в этом, достаточно сравнить выразительную и дидактическую силу диаграммы, например, дерева указателей, имеющего 50 узлов с блок- схемой программы, состоящей из 50 строк кода. Или сравнить инициализатор массива, выражающий таблицу преобразования, с эквивалентным оператором выбора. Различие в прозрачности и ясности поразительно. См. правило 5 Роба Пайка.
Данные более "податливы", чем программная логика. Это означает, что если можно выбирать между сложностью структуры данных и сложностью кода, следует выбирать первое. Более того, развивая проект, следует активно искать пути перераспределения сложности из кода в данные.
Первые оценки этого факта не связаны с Unix-сообществом, но множество примеров Unix-кода отражают его влияние. В частности, средство языка С, манипулирующее указателями, способствовало использованию динамически модифицируемых ссылочных структур на всех уровнях кода, начиная с ядра. Простое отслеживание указателей в таких структурах часто выполняет такие задачи, которые в других языках потребовали бы внедрения более сложных процедур.
Данные методики также описываются в главе 9.
Данное правило также широко известно под названием "Принцип наименьшего удивления" (Principle of Least Astonishment).
Простейшими в использовании являются программы, требующие наименьшего обучения пользователя, или, иными словами, простейшими в использовании программами являются программы, которые наиболее действенно ассоциируются с уже имеющимися у пользователя знаниями.
Таким образом, в дизайне интерфейса следует избегать беспричинной новизны и излишней "заумности". В программе-калькуляторе знак "+" всегда должен означать операцию сложения. Разрабатывая интерфейс, его следует моделировать с интерфейсов функционально подобных или аналогичных программ, с которыми пользователи вероятнее всего знакомы.
Необходимо учитывать характер предполагаемой аудитории. С программой могут работать конечные пользователи, другие программисты или системные администраторы.
Необходимо уделять внимание традиции. В мире Unix имеются довольно хорошо проработанные соглашения о таких элементах, как формат конфигурационных файлов, ключи командной строки и другие. Для существования этих традиций имеется весомая причина: они позволяют смягчить кривую освоения. Учитесь и используйте их.
Многие из этих традиций рассматриваются в главах 5 и 10.
Правило наименьшей неожиданности имеет оборотную сторону. Следует избегать выполнения внешне похожих вещей, слегка отличающихся в действительности. Это крайне опасно, поскольку кажущаяся привычность порождает ложные ожидания. Часто бывает лучше делать заметно отличающиеся вещи, чем делать их почти одинаковыми.
Одно из старейших и наиболее постоянных правил проектирования в Unix гласит: если программа не может "сказать" что-либо интересное или необычное, то ей следует "молчать". Правильно организованные Unix-программы выполняют свою работу "ненавязчиво", с минимальным шумом и беспокойством. Молчание — золото.
Правило "молчание — золото" развивалось изначально, поскольку операционная система Unix предшествовала видеодисплеям. На медленных печатающих терминалах в 1969 году каждая строка излишнего вывода вызывала серьезные потери пользовательского времени. В наши дни данное ограничение снято, однако веские причины для краткости остаются.
Я думаю, что лаконичность Unix-программ является главной чертой стиля. Когда вывод одной программы становится вводом другой, идентификация необходимых фрагментов должна быть простой. Остается актуальным и человеческий фактор — важная информация не должна смешиваться с подробными сведениями о внутренней работе программы. Если вся отображаемая информация является важной, то найти важную информацию просто.
Изящные программы трактуют внимание и сосредоточенность пользователя как ценный и ограниченный ресурс, который требуется только в случае необходимости.
Более подробно правило тишины и причины для его соблюдения описаны в конце главы 11.
Программное обеспечение должно быть столь же прозрачным при выходе из строя, как и при нормальной работе. Лучше всего, если программа способна справиться с неожиданными условиями путем адаптации к ним, однако наихудшими ошибками являются те, за которыми не следует восстановление, и проблема незаметно приводит к разрушению, проявляющемуся намного позднее.
Таким образом, следует писать программное обеспечение, которое как можно изящнее справляется с некорректным вводом и собственными ошибками выполнения. Однако если программа не способна справиться с ошибкой, то необходимо заставить ее прекратить выполнение таким способом, который на сколько это возможно упростит диагностику проблемы.
Рассмотрим также рекомендацию Постела (Postel)[9]: "Будьте либеральны к тому, что принимаете, и консервативны к тому, что отправляете". Постел говорил о программах сетевых служб, однако лежащая в основе такого подхода идея является более общей. Изящные программы сотрудничают с другими программами, извлекая как можно больше смысла из некорректно сформированных входных данных, и либо шумно прекращают свою работу, либо передают абсолютно четкие и корректные данные следующей программе в цепочке.
В то же время следует учитывать следующее предостережение.
Исходные HTML-документы рекомендовали "быть великодушными к тому, что принимаете", и с тех пор это сбивало нас с толку, поскольку каждый браузер принимает другое подмножество спецификаций. Именно спецификации должны быть "великодушны", а не их интерпретация.
Макилрой убеждает нас великодушно проектировать, а не компенсировать неадекватные стандарты с помощью всепозволяющих реализаций. Иначе, как он правильно отмечает, очень просто все закончится смешением разметки.
"В ранние мини-компьютерные времена Unix" вынесенная в заголовок идея была довольно радикальной (машины тогда работали намного медленнее и были более дорогими). В настоящее время, когда каждая группа разработчиков и большинство пользователей (за исключением нескольких лабораторий по моделированию ядерных взрывов или созданию 3D-анимации) обеспечены дешевыми машинными циклами, она может показаться слишком очевидной, чтобы о ней говорить.
Хотя почему-то практика, видимо, отстает от реальности. Если бы этот принцип принимался действительно серьезно в процессе разработки программного обеспечения, то большинство приложений были бы написаны на высокоуровневых языках типа Perl, Tcl, Python, Java, Lisp и даже на языках командных интерпретаторов — т.е. на языках, сокращающих нагрузку на программиста, осуществляя собственное управление памятью ([65]).
И это действительно происходит в мире Unix, хотя за его пределами большинство разработчиков приложений, кажется, не в состоянии отойти от стратегии старой школы Unix, предполагающей кодирование на С (или С++). Данная стратегия и связанные с ней компромиссы подробнее описаны далее в настоящей книге.
Другим очевидным способом сохранения времени программиста является "обучение машины" выполнять больше низкоуровневой работы по программированию, что приводит к формулировке следующего правила.
Известно, что люди плохо справляются с деталями. Соответственно, любой вид ручного создания программ является источником задержек и ошибок. Чем проще и более абстрактной может быть программная спецификация, тем более вероятно, что проектировщик реализует ее правильно. Сгенерированный код (на всех уровнях) почти всегда является более дешевым и более надежным, чем код, написанный вручную.
Общеизвестно, что это на самом деле так (в конце концов, именно поэтому созданы компиляторы и интерпретаторы), однако зачастую никто не задумывается о последствиях. Изобилующий повторениями код на языке высокого уровня, написание которого утомительно для людей, является такой же продуктивной целью для генератора кода, как машинный код. Использование генераторов кода оправдано, когда они могут повысить уровень абстракции, т.е. когда язык спецификации для генератора проще, чем сгенерированный код, и код впоследствии не потребует ручной доработки.
В традициях Unix генераторы кода интенсивно используются для автоматизации чреватой ошибками кропотливой работы. Классическими примерами генераторов кода являются грамматические (parser) и лексические (lexer) анализаторы. Более новые примеры — генераторы make-файлов и построители GUI-интерфейсов.
Данные методики рассматриваются в главе 9.
Самый основной аргумент в пользу создания прототипов впервые был выдвинут Керниганом и Плоджером (Plauger): "90% актуальной и реальной функциональности лучше, чем 100% функциональности перспективной и сомнительной". Первоначальное создание прототипов помогает избежать слишком больших затрат времени для получения минимальной выгоды.
По несколько другим причинам Дональд Кнутт (автор книги "Искусство компьютерного программирования", одного из немногих действительно классических трудов в своей области) популяризовал мнение о том, что "преждевременная оптимизация — корень всех зол"[10], и он был прав.
Поспешная оптимизация до выяснения узких мест в программе, возможно, является единственной ошибкой, которая разрушила больше конструкций, чем излишнее наращивание функциональности. Искаженный код и непостижимое расположение данных — результат приоритета скорости и оптимизации использования памяти или дискового пространства за счет прозрачности и простоты. Они порождают бесчисленные ошибки и выливаются в миллионы человеко-часов — часто только для того, чтобы получить минимальную выгоду от использования какого-либо ресурса, гораздо менее дорогостоящего, чем время отладки.
Нередко преждевременная локальная оптимизация фактически препятствует глобальной оптимизации (и, следовательно, снижает общую производительность). Преждевременно оптимизированная часть конструкции часто смешивается с изменениями, которые имели бы гораздо больший выигрыш для конструкции в целом, поэтому проект завершается одновременно с низкой производительностью и чрезмерно сложным кодом.
В мире Unix имеется общепринятая и весьма явная традиция (ярко проиллюстрированная приведенными выше комментариями Роба Пайка и принципом Кена Томпсона о грубой силе), которая гласит: создавайте прототипы, а затем шлифуйте их. Заставьте прототип работать, прежде чем оптимизировать его. Или: сначала заставьте прототип работать, а потом заставьте его работать быстро. Гуру "Экстремального программирования" Кент Бек (Kent Beck), работающий в другой культуре, значительно усилил данный принцип: "заставьте программу работать, заставьте ее работать верно, а затем сделайте ее быстрой".
Сущность всех приведенных цитат одинакова: прежде чем пытаться регулировать программу, необходимо верно ее спроектировать и реализовать неоптимизированной, медленной и занимающей большой объем памяти. Затем ее следует регулировать систематически, определяя места, в которых можно получить большую производительность ценой наименьшего возможного повышения локальной сложности.
Создание прототипов так же важно для конструкции системы, как и оптимизация — гораздо проще определить, выполняет ли прототип возложенные на него задачи, чем читать длинную спецификацию. Я помню одного менеджера разработки в Bellcore, который боролся против культуры "требований" задолго до того, как все заговорили о "быстром создании прототипов" (fast prototyping), или "гибкой разработке" (agile development). Он не стал бы выпускать длинные спецификации. Он связывал сценарии оболочки и awk-код в некоторую комбинацию, которая делала приблизительно то, что ему было нужно, а затем просил заказчиков направить к нему нескольких клерков на пару дней. После чего приглашал заказчиков прийти и посмотреть, как их клерки используют прототип, и сказать ему, нравится им это или нет.
В случае положительного ответа он говорил, что "промышленный образец может быть создан через столько-то месяцев и по такой-то цене". Его оценки были довольно точными, однако он проигрывал в культуре менеджерам, которые верили, что создатели требований должны контролировать все.
Использование прототипов для определения того, в каких функциях нет необходимости, способствует оптимизации производительности; нет необходимости оптимизировать то, что не написано. Наиболее мощным средством оптимизации можно назвать клавишу "Delete".
В один из наиболее продуктивных дней я удалил тысячу строк кода.
Более глубоко соответствующие соображения рассматриваются в главе 12.
Даже наилучшие программные инструменты ограничены воображением своих создателей. Никто не обладает умом, достаточным для оптимизации всего или для предвидения всех возможных вариантов использования создаваемой программы. Разработка негибкого, закрытого программного обеспечения, которое не будет сообщаться с остальным миром, является болезненной формой самолюбия.
Поэтому традиция Unix включает в себя здоровое недоверие к использованию "единственного верного пути" в проектировании или реализации программного обеспечения. В Unix допускается использование множества языков, открытых расширяемых систем и необходимой доработки.
Если доверять заявлениям других людей о "единственном верном пути" неблагоразумно, еще большим безрассудством будет вера в непогрешимость собственных разработок. Никогда не считайте себя истиной в последней инстанции. Следовательно, оставляйте пространство для роста форматов данных и кода. В противном случае часто будут возникать препятствия, связанные с прежними неразумными решениями, поскольку их невозможно изменить при поддержке обратной совместимости.
При проектировании протоколов или форматов файлов следует делать их достаточно самоописательными, для того чтобы их можно было расширять. Всегда, всегда следует либо включать номер версии, либо составлять формат из самодостаточных, самоописательных команд так, чтобы можно было легко добавить новые директивы, а старые удалить, "не сбивая с толку" код чтения формата. Опыт Unix свидетельствует: минимальные дополнительные издержки, которые позволяют сделать расположение данных самоописательным, тысячекратно окупаются возможностью развивать его без разрушения конструкции.
Проектируя код, следует организовывать его так, чтобы будущие разработчики могли включать новые функции в архитектуру без необходимости ее перестройки, Данное правило не является разрешением на добавление функций, которые еще не нужны; это совет, призывающий писать код так, чтобы облегчить последующее добавление новых функций, когда они действительно понадобятся. Необходимо сделать добавление новых функций гибким, а также вставлять в код комментарии, начинающиеся словами "если когда-нибудь потребуется сделать…". Это значительно облегчит работу тех, кто в последующем будет использовать и сопровождать код.
В их числе окажется и создатель программы, поддерживая код, который наполовину забудется под давлением более новых проектов. "Проектируя на будущее", можно сохранить собственное душевное равновесие.
Вся философия в действительности сводится к одному железному правилу ведущих инженеров, священному "принципу KISS":
Unix предоставляет великолепную основу для применения принципа KISS. В последующих главах данной книги описано, как его следует применять.
Описанные философские принципы не являются лишь неясными общими фразами. В мире Unix они приходят непосредственно из опыта и ведут к специфическим рецептам, часть из которых уже были сформулированы выше. Ниже приводится их список, не претендующий на полноту.
• Все, что может быть фильтром, независимым от отправителя и получателя, должно быть таким фильтром.
• Потоки данных должны быть, если такое вообще возможно, текстовыми (для того чтобы их можно было просматривать и фильтровать с помощью стандартных средств).
• Структура баз данных и протоколы приложений должны быть, если это возможно, текстовыми (доступными человеку для чтения и редактирования).
• Сложные клиенты (пользовательские интерфейсы) должны быть четко отделены от сложных серверов.
• При возможности перед кодированием на С всегда нужно создавать прототип на каком-либо интерпретируемом языке.
• Смешивание языков лучше, чем написание всей программы на одном языке, тогда и только тогда, когда использование одного языка чрезмерно усложняет программу.
• Будьте "великодушны" к тому, что поступает, и строги к тому, что выпускается.
• При фильтровании не следует отбрасывать излишнюю информацию.
• Малое прекрасно. Следует писать программы, которые выполняют минимум, достаточный для решения задачи.
Далее в настоящей книге будут рассматриваться правила Unix-проектирования и следующие из них рецепты, применяемые снова и снова. Не удивительно, что они стремятся к объединению с наилучшими практическими приемами из программной инженерии в других традициях[11].
Когда верное решение очевидно, его следует немедленно использовать — данный подход может показаться работоспособным только в краткосрочной перспективе, однако это путь наименьших усилий в продолжительном периоде. Если не известно, какое решение является правильным, следует сделать минимум, необходимый для решения задачи, по крайней мере, до тех пор, пока не выяснится, что является правильным.
Для того чтобы правильно применять философию Unix, необходимо быть верным своему искусству. Необходимо верить, что проектирование программного обеспечения является искусством, достойным интеллектуальных и творческих усилий, терпения и настойчивости, на которые только способен разработчик. В противном случае разработчик не увидит в прошлом простых, стереотипных способов дизайна и реализации; он бросится кодировать, когда следовало бы подумать. Он будет небрежно усложнять, когда следовало бы неуклонно упрощать — а в дальнейшем удивится, почему код распухает, а отладка становится такой сложной.
Для того чтобы правильно применять философию Unix, необходимо ценить свое время и никогда не тратить его впустую. Если проблема была уже однажды решена кем-либо, не позволяйте амбициям или "политическим" соображениям втягивать себя в повторное ее решение вместо повторного использования. И никогда не работайте "тяжелее", чем требуется; вместо этого работайте изобретательнее и берегите дополнительные усилия на случай, когда они понадобятся. Опирайтесь на доступные средства и автоматизируйте все, что можно.
Проектирование и реализация программного обеспечения должно быть радостным искусством, чем-то подобным интеллектуальной игре. Если эта позиция кажется читателю нелепой или весьма туманной, то ему следует остановиться, подумать и спросить себя, что упущено. Возможно, вместо разработки программ следует заняться чем-либо другим, чтобы зарабатывать деньги или убивать время. Программа должна стоить усилий ее разработчика.
Для того чтобы правильно применять философию Unix, необходимо прийти (или вернуться) к описанному подходу. Необходимо интересоваться. Необходимо экспериментировать. Необходимо усердно исследовать.
Авторы надеются, что читатель при изучении оставшейся части книги воспользуется этим подходом, или, по крайней мере, что данная книга поможет открыть этот подход заново.
Тот, кто не помнит своего прошлого, обречен на его повторение.
Прошлое освещает опыт. Операционная система Unix имеет долгую и колоритную историю, большая часть которой до сих пор живет в виде фольклора, предположений и (слишком часто) "боевых шрамов" в коллективной памяти Unix-программистов. Данная глава представляет собой обзор истории операционной системы Unix, который необходим для того, чтобы объяснить, почему в 2003 году современная Unix-культура выглядит именно так.
Печально известный "эффект второй системы" (second-system effect) часто поражает преемников небольших экспериментальных прототипов. Стремление добавить все, что было отложено в ходе первой разработки, слишком часто ведет к большой и чрезмерно сложной конструкции. Менее широко известен, ввиду своего менее широкого распространения, эффект третьей системы. Иногда после того, как вторая система потерпела крах "под своим весом", существует возможность вернуться обратно к простоте и сделать все действительно правильно.
Первоначальная Unix была третьей системой. Ее прародителем была небольшая и простая система CTSS (Compatible Time-Sharing System — совместимая система разделения времени), она была либо первой, либо второй из используемых систем разделения времени (в зависимости от некоторых вопросов определения, которые вполне можно не учитывать). Систему CTSS сменил революционный проект Multics, попытка создать "информационную утилиту" с группами функций, которая бы изящно поддерживала интерактивное разделение процессорного времени мэйнфреймов крупными сообществами пользователей. Увы, проект Multics рухнул "под собственным весом". Вместе с тем этот крах положил начало операционной системе Unix.
Операционная система Unix возникла в 1969 году как детище разума Кена Томпсона, компьютерного ученого Bell Laboratories. Томпсон был исследователем в проекте Multics. Этот опыт утомлял Томпсона из-за примитивности пакетных вычислений, которые господствовали практически повсеместно. Однако в конце 60-х годов идея разделения времени все еще была новой. Первые предположения, связанные с ней, были выдвинуты почти десятью годами ранее компьютерным ученым Джоном Маккарти (John McCarthy) (который также известен как создатель языка Lisp), а первая фактическая реализация состоялась в 1962 году, семью годами ранее, и многопользовательские операционные системы все еще оставались экспериментальными и непредсказуемыми.
Аппаратное обеспечение компьютеров в то время было еще более примитивным. Наиболее мощные машины в те дни имели меньшую вычислительную мощность и внутреннюю память, чем обычный современный сотовый телефон[12]. Терминалы с видеодисплеями находились в начальной стадии своего развития и в течение последующих шести лет не получили широкого распространения. Стандартным интерактивным устройством на ранних системах разделения времени был телетайп ASR-33 — медленное, шумное устройство, которое печатало только символы верхнего регистра на больших рулонах желтой бумаги. ASR-33 послужит прародителем Unix-традиции в плане использования кратких команд и немногословных откликов.
Когда Bell Labs вышла из состава исследовательского консорциума Multics, у Кена Томпсона остались некоторые идеи создания файловой системы, вдохновленные проектом Multics. Кроме того, он остался без машины, на которой мог бы играть в написанную им игру "Space Travel" (Космическое путешествие), научно-фантастический симулятор управления ракетами в солнечной системе. Unix начала свой жизненный путь на восстановленном мини-компьютере PDP-7[13] в качестве платформы для игры Space Travel и испытательного стенда для идей Томпсона о разработке операционной системы. Подобный компьютер показан на рис. 2.1.
Рис. 2.1. Мини-компьютер PDP-7
Полная история происхождения описана в статье [69] с точки зрения первого помощника Томпсона, Денниса Ритчи, который впоследствии стал известен как соавтор Unix и создатель языка С. Деннис Ритчи, Дуг Макилрой и несколько их коллег привыкли к интерактивным вычислениям в системе Multics и не хотели терять эту возможность.
Ритчи отмечает: "То, что мы хотели сохранить, было не только хорошей средой для программирования, но и системой, вокруг которой могло сформироваться братство. Мы знали по опыту, что сущностью совместных вычислений, которые обеспечивались с помощью удаленного доступа к машинам с разделением времени, является не только ввод программ с клавиатуры в терминал вместо использования клавишного перфоратора, но и поддержка тесного общения". В воздухе витала идея рассматривать компьютеры не просто как логические устройства, а как ядра сообществ. 1969 год был также годом изобретения сети ARPANET (прямого предка современной сети Internet). Тема "братства" будет звучать во всей последующей истории Unix.
Реализация игры Томпсона и Ритчи "Space Travel" привлекла к себе внимание. Вначале программное обеспечение PDP-7 приходилось перекомпилировать на GE-мэйнфрейме. Программные утилиты, которые были написаны Томпсоном и Ритчи на самом PDP-7, чтобы поддерживать развитие игры, стали каркасом Unix, хотя само название не было закреплено за системой до 1970 года. Исходный вариант написания представлял собой аббревиатуру "UNICS" (UNiplexed Information and Computing Service). Позднее Ритчи описывал эту аббревиатуру как "слегка изменнический каламбур на слово "Multics", которое означало MULTiplexed Information and Computing Service.
Даже на самых ранних стадиях развития PDP-7 Unix была весьма похожа на современные Unix-системы и предоставляла гораздо более приятную среду программирования, чем доступные в то время мэйнфреймы с использованием перфокарт. Unix была весьма близкой к первой системе, используя которую программист мог находиться непосредственно перед машиной и создавать программы на лету, исследуя возможности и тестируя программы в процессе их создания. На протяжении всей жизни Unix реализуется модель развития возможностей путем привлечения высокоинтеллектуальных, добровольных усилий со стороны программистов, которых раздражают ограничения других операционных систем. Эта модель возникла на раннем этапе внутри самой корпорации Bell Labs.
Unix-традиция легковесной разработки и неформальных методов также началась вместе с появлением операционной системы. Тогда как Multics была крупным проектом с тысячами страниц технических спецификаций, написанных до появления аппаратного обеспечения, первый работающий код Unix был создан тремя коллегами путем мозгового штурма и реализован Кеном Томпсоном в течение двух дней на устаревшей машине, которая была задумана как графический терминал для "настоящего" компьютера.
Первой реальной задачей Unix в 1971 году была поддержка того, что в наши дни назвали бы текстовым процессором, для патентного департамента Bell Labs. Первым Unix-приложением был предшественник программы для форматирования текста nroff(1). Этот проект оправдал приобретение гораздо более мощного мини-компьютера PDP-11. Руководство оставалось в счастливом неведении о том, что система обработки текста, которую создавали Томпсон и его коллеги, была инкубатором для операционной системы. Операционные системы не входили в планы Bell Labs — AT&T присоединилась к консорциуму Multics именно для того, чтобы избежать разработки собственной операционной системы. Тем не менее, завершенная система имела воодушевляющий успех, который утвердил Unix в качестве постоянной и ценной части системы вычислений в Bell Labs и привел к появлению другой темы в истории Unix — тесной связи со средствами набора и форматирования документов, а также средствами коммуникации. Справочник 1972 года говорил о 10 инсталляциях.
Позднее Дуг Макилрой напишет об этом периоде [53]: "Давление коллег и простая гордость своей квалификацией приводили к переписыванию или удалению больших фрагментов кода, по мере того, как появлялись лучшие или более фундаментальные идеи. Профессиональная конкуренция и защита сфер влияния были практически не известны: возникало так много хороших идей, что никому не требовалось быть собственником инноваций". Однако понадобится четверть века для того, чтобы сообществу стали ясны все выводы из этого наблюдения.
Первоначально операционная система Unix была написана на ассемблере, а ее приложения — на "смеси" ассемблера и интерпретируемого языка, который назывался "В". Его преимущество заключалось в том, что он был достаточно мал для работы на компьютерах PDP-7. Однако язык В не был достаточно мощным для системного программирования, поэтому Деннис Ритчи добавил в него типы данных и структуры, в результате чего появился язык С. Это произошло в начале 1971 года. А в 1973 году Томпсон и Ритчи наконец успешно переписали Unix на новом языке. Это был весьма смелый шаг. В то время для того чтобы получить максимальную производительность аппаратного обеспечения, системное программирование осуществлялось на ассемблере, и сама концепция переносимой операционной системы представлялась еще весьма сомнительной. Только в 1979 году Ритчи смог написать: "Кажется бесспорным, что в основном успех Unix обусловлен читаемостью, редактируемостью и переносимостью ее программного обеспечения, причем такие позитивные характеристики, в свою очередь, являются следствием ее написания на языках высокого уровня".
В 1974 году журнал Communications of the ACM [72] впервые представил Unix широкой общественности. В статье авторы описывали беспрецедентно простую конструкцию Unix и сообщали о более чем 600 инсталляций данной операционной системы. Все инсталляции производились на машинах, мощность которых была низкой даже по стандартам того времени, однако (как писали Ритчи и Томпсон) "ограничения способствовали не только экономии, но также и определенному изяществу дизайна".
После доклада в CACM исследовательские лаборатории и университеты по всему миру заявили о желании испытать Unix самостоятельно. По соглашению сторон об урегулировании антитрастового дела 1958 года корпорации AT&T (родительской организации Bell Labs) запрещалось входить в компьютерный бизнес. Таким образом, Unix невозможно было превратить в продукт. Действительно, в соответствии с положениями соглашения, Bell Labs должна была лицензировать свою нетелефонную технологию всем желающим. Кен Томпсон без огласки начал отвечать на запросы, отправляя ленты и дисковые пакеты, каждый из которых, согласно легенде, подписывался "с любовью, Кен" (love, ken).
Напомним, что эти события происходили задолго до появления персональных компьютеров. Аппаратное обеспечение, необходимое для работы Unix, было слишком дорогостоящим, для того, чтобы использоваться в индивидуальных исследованиях. Поэтому Unix-машины были доступны, только благодаря благоволению больших организаций с большим бюджетом: корпораций, университетов, правительственных учреждений. Но использование таких мини-компьютеров было менее контролируемым, чем использование больших мэйнфреймов, и Unix-разработка быстро "приобрела дух контркультуры". Это было начало 70-х годов прошлого века. Первопроходцами Unix-программирования были лохматые хиппи и те, кто хотел на них походить. Они наслаждались, исследуя операционную систему, которая не только предлагала им интересные испытания на переднем крае компьютерной науки, но также и подрывала все технические предположения и бизнес-практику, которая сопутствовала "большим вычислениям". Перфокарты, язык COBOL, деловые костюмы и пакетные мэйнфреймы IBM остались в "презренном прошлом". Unix-хакеры упивались тем, что одновременно строили будущее и играли с системой.
Энтузиазм тех дней описывается цитатой Дугласа Комера (Douglas Comer): "Многие университеты вносили свой вклад в Unix. В Университете Торонто кафедра приобрела принтер/плоттер с разрешением 200 точек на дюйм и создала программное обеспечение, которое использовало его для имитации фотонаборного аппарата. В Йельском университете (Yale University) студенты и компьютерные ученые модифицировали командный интерпретатор Unix. В Университете Пурдью (Purdue University) кафедра электротехники добилась значительного улучшения производительности, выпустив версию Unix, которая поддерживала большее количество пользователей. В Пурдью также разработали одну из первых компьютерных сетей на основе Unix. Студенты Калифорнийского университета в Беркли разработали новый командный интерпретатор и десятки небольших утилит. К концу 70-х годов, когда Bell Labs выпустила Version 7 UNIX, было ясно, что система решала вычислительные задачи многих факультетов и что она воплотила в себе множество появившихся в университетах идей. Конечным результатом стало появление укрепленной системы. Прилив идей послужил началом нового цикла интеллектуального взаимообмена академического мира и производственных лабораторий и в конечном итоге обусловил рост коммерческих вариантов Unix" [13].
Первой узнаваемой версией Unix была версия 7 (Version 7), выпущенная в 1979 году[14]. Первая группа пользователей Unix сформировалась за год до этого. К тому времени Unix использовалась для операционной поддержки всех систем Bell System [35], и получила распространение в университетах вплоть до Австралии, где заметки Джона Лайонза (John Lions) [49] в 1976 году по исходному коду Version 6 стали первой серьезной документацией по внутреннему устройству ядра Unix. Многие пожилые Unix-хакеры до сих пор свято хранят копии этих заметок.
Рис. 2.2. Кен Томпсон (сидя) и Деннис Ритчи перед PDP-11 в 1972 году
Книга Лайонза была самиздатовской сенсацией. Из-за несоблюдения авторских прав или чего-то еще ее нельзя было публиковать в США, поэтому везде "просачивались" копии копий. Я до сих пор храню свою, которая была копией как минимум шестого поколения. Не имея книги Лайонза, тогда невозможно было быть хакером ядра.
Первые годы Unix-индустрии также были временем объединения. Первая Unix- компания (Santa Cruz Operation, SCO) начала свою работу в 1978 году, и в том же году продала первый коммерческий компилятор С (Whitesmiths). К 1980 году малоизвестная компания, производитель программного обеспечения в Сиэтле, также вступила в Unix-игру, распространяя вариант АТ&Т-версии Unix для мини- компьютеров, который назывался XENIX. Но привязанность Microsoft к Unix как к продукту не была долгой (хотя Unix использовалась для большей части внутренней разработки компании вплоть до начала 1990-х годов).
Студенческий городок Калифорнийского университета в Беркли вначале был единственным важнейшим академическим центром Unix-разработки. Unix-исследо- вания начались здесь в 1974 году и получили мощный толчок, когда Кен Томпсон преподавал в университете в течение академического отпуска 1975-1976 годов. Первая BSD-версия была создана на базе лабораторной разработки в 1977 году неизвестным до этого аспирантом Биллом Джоем (Bill Joy). К 1980 году Беркли стал центром сети университетов, активно дополняющих свой вариант Unix. Идеи и код из Berkeley Unix (включая редактор vi(1)) были переданы из Беркли обратно в Bell Labs.
Затем в 1980 году Агентству передовых исследований Министерства обороны США (Defense Advanced Research Projects Agency — DARPA) потребовалась команда для реализации новейшего набора протоколов TCP/IP на компьютерах VAX под Unix. Компьютеры PDP-10, поддерживающие сеть ARPANET, в то время устарели, и в воздухе уже витали идеи о том, что DEC может быть вынуждена отказаться от PDP-10 для поддержки VAX. Агентство DARPA рассматривало принятие DEC для реализации TCP/IP, однако отказалась от этой идеи, поскольку вызывал беспокойство тот факт, что DEC может не согласиться на изменения в собственной операционной системе VAX/VMS [48]. Вместо этого агентство DARPA в качестве платформы выбрало Berkeley Unix, явно ввиду того, что ее исходный код был доступным и свободным [45].
Исследовательская группа компьютерных наук (Computer Science Research Group) в Беркли оказалась в нужное время в нужном месте с надежнейшими инструментами разработки. Это была, несомненно, наиболее важная поворотная точка в истории Unix с момента ее появления.
До того как реализация протокола TCP/IP была выпущена с версией BSD 4.2 в 1983 году, Unix имела только слабую поддержку сети. Ранние эксперименты с Ethernet были неудовлетворительными. Для распространения программного обеспечения через обычные телефонные линии посредством модема в Bell Labs было разработано неприглядное, но вполне функциональное средство, которое называлось UUCP (Unix to Unix Copy Program — программа копирования из Unix в Unix)[15]. С помощью UUCP можно было передавать Unix-почту между удаленными машинами. Кроме того, (после того, как в 1981 году была изобретена Usenet) UUCP поддерживала распределенные доски объявлений, которые позволяли пользователям широковещательно распространять текстовые сообщения везде, где были телефонные линии и Unix-системы.
Тем не менее, несколько Unix-пользователей, знакомых с яркими преимуществами ARPANET, испытывали существенные затруднения из-за отсутствия FTP и Telnet и очень ограниченного удаленного выполнения заданий и чрезвычайно медленных каналов. Ранее, до появления протоколов TCP/IP, Internet- и Unix-культуры не смешивались. Особое видение Деннисом Ритчи вопроса о компьютере как о способе "поддержки тесного общения" сформировало одно из университетских сообществ. Оно не расширилось до распределенной по всему континенту "сетевой нации", которую пользователи сети ARPA начали формировать в середине 70-х годов прошлого века. Первые пользователи ARPANET считали Unix грубой подделкой, "ковыляющей на смехотворно слабом аппаратном обеспечении".
После появления TCP/IP все изменилось. Началось слияние культур ARPANET и Unix. Это инициировало развитие, которое в конце концов спасло их от разрушения. Однако возникли новые проблемы, которые были результатом двух отдельных "бедствий": подъема Microsoft и падения AT&T.
В 1981 году корпорация Microsoft заключила свою историческую сделку с IBM по IBM PC. Билл Гейтс (Bill Gates) приобрел QDOS (Quick and Dirty Operating System), клон CP/M, собранный за шесть недель программистом Тимом Патерсоном (Tim Paterson), в Seattle Computer Products, где работал Тим Патерсон. Гейтс, скрывая от Патерсона и SCP сделку с IBM, приобрел права на систему за 50 тыс. долл. Затем он уговорил IBM разрешить Microsoft распространять на рынке операционную систему MS-DOS отдельно от аппаратного обеспечения PC. В течение следующего десятилетия выигрышный код, которого он не писал, сделал Билла Гейтса мультимиллиардером, а бизнес-тактика, еще более искусная, чем первоначальная сделка, принесли Microsoft монопольное положение на рынке настольных компьютеров. Операционная система XENIX как продукт была вскоре заброшена и в конце концов продана компании SCO.
В то время еще не было очевидно, насколько успешные (или деструктивные) действия собиралась предпринять Microsoft. Поскольку IBM PC-1 не обладала аппаратными возможностями поддержки Unix, пользователи Unix едва ли заметили эту платформу вообще (ирония в том, что операционная система DOS 2.0 затмила CP/M в основном из-за того, что один из основателей Microsoft Пол Аллен (Paul Allen) встроил в нее Unix-функции, включая подкаталоги и каналы). Рассмотрим события, которые кажутся более интересными, такие как возникновение в 1982 году компании Sun Microsystems.
Основатели Sun Microsystems, Билл Джой (Bill Joy), Андреас Бектолшейм (Andreas Bechtolsheim) и Винод Хосла (Vinod Khosla), начали создавать Unix-машину мечты со встроенной поддержкой сети. Они скомбинировали аппаратное обеспечение, спроектированное в Стэнфорде, с операционной системой Unix, разработанной в Беркли, и впоследствии основали индустрию рабочих станций. В то время никто не собирался контролировать доступ к исходному коду одной ветви дерева Unix, которая постепенно "высохла" в то время как Sun Microsystems начала вести себя все меньше как свободный проект и все больше как традиционная фирма. Университет в Беркли продолжал распространять BSD Unix вместе с исходным кодом. Официально лицензия на исходный код System III стоила 40 тыс. долл., однако Bell Labs закрывала глаза на рост количества распространяемых нелегальных лент с Bell Labs Unix, а университеты продолжали обмениваться кодом с Bell Labs. Складывалось впечатление, что коммерциализация Unix со стороны Sun — это лучшее, что могло произойти.
Также в 1982 году язык С впервые продемонстрировал признаки своего становления за пределами Unix-мира в качестве основного языка системного программирования. Всего через 5 лет С почти полностью вывел из употребления машинные ассемблеры. К началу 90-х годов языки С и С++ будут доминировать не только в системном, но и в прикладном программировании. К концу 90-х годов все остальные традиционные компилируемые языки фактически выйдут из употребления.
Когда в 1983 году DEC прекратила разработки по машине, которая являлась потомком PDP-10 (Jupiter), VAX-машины с использованием Unix стали занимать положение доминирующих Internet-машин, это положение они будут занимать до вытеснения их рабочими станциями Sun Microsystems. К 1985 году около 25% всех VAX-машин будут использовать Unix, причем несмотря на жесткое противостояние DEC. Однако самый долгосрочный эффект прекращения работ над проектом Jupiter был менее очевидным. Смерть хакерской культуры, развивавшейся вокруг компьютеров PDP-10 разработки MIT AI Lab, побудила программиста Ричарда Столлмена (Richard Stallman) к началу создания проекта GNU, полностью свободного клона Unix.
К 1983 году было не менее 6 Unix-подобных операционных систем для IBM-PC: uNETix, Venix, Coherent, QNX, Idris и вариант, поддерживаемый на низкоуровневой плате Sritek PC. Все еще не было вариантов ни версии System V, ни BSD-версии. Обе группы считали микропроцессор серии 8086 чрезвычайно маломощным и не планировали работать с ним. Ни одна из Unix-подобных операционных систем не добилась значительного коммерческого успеха, однако они показали значительную потребность в Unix на дешевом аппаратном обеспечении, которое ведущие производители оборудования не поставляли. Ни один человек не мог позволить себе приобрести лицензию на исходный код Unix.
Sun уже добилась успеха (с подражателями), когда в 1983 году Министерство юстиции США выиграло второй антитрастовый процесс против AT&T и раздробило корпорацию Bell System. Это освободило AT&T от соглашения 1958 года, препятствующего превращению Unix в продукт, и AT&T немедленно приступила к коммерциализации Unix System V. Этот шаг почти уничтожил Unix.
Это верно, но их маркетинг действительно распространил Unix по всему миру
Большинство сторонников Unix полагали, что разделение AT&T было хорошей новостью. Нам казалось, что новые условия дадут шанс здоровой Unix-индустрии — индустрии, использующей недорогие рабочие станции на основе процессоров 68000, что в конечном итоге разрушит монополию IBM.
Никто из нас в то время не осознавал, что превращение Unix в коммерческий продукт разрушит свободный обмен исходным кодом, который дал столько жизненной силы развивающейся системе. Не зная другой модели, кроме секретности для накопления прибыли от программного обеспечения и кроме централизованного управления разработкой коммерческого продукта, AT&T прекратила распространение исходного кода. Нелегальные ленты с Unix стали намного менее интересными, так как их использование могло повлечь за собой угрозу судебного преследования. Интеллектуальный вклад от университетов начал иссякать.
Осложняя положение, новые крупные игроки рынка Unix допускали большие стратегические ошибки. Одной из них было решение получить преимущество путем дифференцирования продуктов — тактика, которая в результате привела к тому, что в разных Unix-системах интерфейсы утратили идентичность. Это отбросило кроссплатформенную совместимость и фрагментировало рынок операционных систем Unix.
Другая менее очевидная ошибка заключалась в том, что все заинтересованные стороны вели себя так, будто персональные компьютеры и Microsoft не имеют отношения к перспективам Unix. В Sun Microsystems не разглядели того, что ставшие широко распространенными персональные компьютеры неизбежно начнут атаковать рынок рабочих станций Sun снизу. Корпорация AT&T, зациклившаяся на мини-компьютерах и мэйнфреймах, испытала несколько других стратегий, которые были направлены на то, чтобы стать главным игроком на рынке компьютеров, и крайне усугубила ситуацию. Для поддержки операционной системы Unix на PC-станциях были сформированы около десятка небольших компаний. Все они испытывали недостаток средств и уделяли основное внимание предоставлению своих услуг разработчикам и инженерам, т.е. никогда не ставили себе целью выход на рынок обслуживания предприятий и домашних пользователей, на который была нацелена Microsoft.
Действительно, в течение многих лет после падения AT&T Unix-сообщество было озабочено первой фазой Unix-войн — внутренними разногласиями и соперничеством между System V Unix и BSD Unix. Разногласия охватывали несколько уровней, ряд технических (сокеты против потоков, специальный терминальный интерфейс (tty) в BSD против общего терминального интерфейса (termio) в System V) и культурных вопросов. "Водораздел" пролегал приблизительно между хиппи и белыми воротничками. Программисты и технические специалисты склонялись к точке зрения Университета в Беркли и BSD Unix, а более ориентированные на бизнес специалисты — к точке зрения AT&T и System V Unix. Хиппи-программистам нравилось считать себя восставшими против корпоративной империи.
Однако в год разделения AT&T случилось нечто, что впоследствии приобрело более долгосрочную важность для Unix. Программист и лингвист по имени Ларри Уолл (Larry Wall) создал утилиту patch(1). Программа patch — простой инструмент, который применяет к базовому файлу изменения, сгенерированные утилитой diff(1). Она предоставила Unix-разработчикам возможность сотрудничать, передавая друг другу вместо полных файлов наборы "заплат", т.е. инкрементальные изменения кода. Это было важно не только потому, что заплаты были менее громоздкими, чем полные файлы, но и потому, что они часто применяются аккуратно, даже если большая часть базового файла претерпела изменения с тех пор, как отправитель заплаты получил свою копию. С помощью данного средства потоки разработки по общему базовому исходному коду могли разделяться, двигаться параллельно и сходиться снова. Программа patch сделала гораздо больше, чем любой другой инструмент, для активизации совместной разработки через Internet, т.е. активизации метода, который после 1990 года вдохнул в Unix новую жизнь.
В 1985 году корпорация Intel распространила первую микросхему 386-й серии, способную адресовать 4 Гбайт памяти с линейным адресным пространством. Неуклюжая сегментная адресация в процессорах 8086 и 286 очень быстро устарела. Это была важная новость, поскольку она означала, что впервые микропроцессор доминирующего семейства Intel стал способен работать под управлением Unix без болезненных компромиссов. Появление данного процессора предрекало грядущую катастрофу для Sun и других создателей рабочих станций, но они этого не заметили.
В том же году Ричард Столлмен опубликовал манифест GNU [78] и основал Фонд свободного программного обеспечения (Free Software Foundation). Очень немногие всерьез восприняли мнение Столлмена и его проект GNU, но он оказался прав. В независимой разработке того же года создатели системы X Window выпустили ее в виде исходного кода без указания права собственности, ограничений или лицензии. Как непосредственный результат этого решения возникла безопасно нейтральная зона для сотрудничества между Unix-поставщиками и потерпевшими поражение частными конкурентами с целью создания графической подсистемы Unix.
Кроме того, в 1983 году начались серьезные попытки по стандартизации согласования API-интерфейсов System V и Berkeley Unix вместе со стандартом /usr/group. За ним в 1985 году последовали стандарты POSIX, поддерживаемые институтом IEEE. В данных стандартах описывался пересекающийся набор вызовов BSD и SVR3 (System V Release 3), а также превосходная обработка сигналов Berkeley Unix и управление задачами, но с помощью терминального управления SVR3. Все последующие стандарты Unix будут базироваться на стандарте POSIX, а поздние Unix-системы будут строго его придерживаться. Единственным появившимся впоследствии главным дополнением к современному API-интерфейсу ядра Unix были BSD-сокеты.
В 1986 году Ларри Уолл, ранее разработавший утилиту patch(1), начал работу по созданию языка Perl, который станет первым и наиболее широко используемым языком написания сценариев с открытым исходным кодом. В начале 1987 года появилась первая версия GNU C-компилятора, а к концу того же года была определена основа инструментального набора GNU: редактор, компилятор, отладчик и другие базовые инструменты разработки. Тем временем система X Window начала появляться на относительно недорогих рабочих станциях. Эти компоненты в 90-х годах прошлого века послужили каркасом для Unix-разработок с открытым исходным кодом.
Также в 1986 году PC-технология освободилась от власти компании IBM, которая продолжала сохранять соотношение "цена-мощность" во всей линейке своих продуктов, что благоприятствовало ее высокодоходному бизнесу по поставке мэйнфреймов. IBM отказалась от процессора 386 в большей части своей новой линейки компьютеров PS/2 в пользу более слабого процессора 286-й серии. Серия PS/2, которую IBM разработала на основе частной архитектуры системной шины, для того чтобы оградить себя от создателей клонов, стала колоссально дорогим провалом[16]. Компания Compaq, самый активный создатель PC-клонов, превзошла IBM, выпустив первую машину с процессором 386. Даже при частоте процессора всего в 16 МГц, процессор 386-й серии сделал машину пригодной к использованию в среде Unix. Это был первый компьютер, который можно было назвать PC.
Проект Столлмена подтвердил возможность использовать машины 386-й серии для создания рабочих станций Unix по цене, почти на порядок меньшей, чем ранее. Как ни странно, видимо, никто в действительности не подумал об этом. Большинство Unix-программистов, "пришедших из мира мини-компьютеров и рабочих станций", продолжали пренебрегать дешевыми машинами 80x86, отдавая предпочтение более элегантным конструкциям на основе процессоров 68000. И хотя многие программисты способствовали успеху проекта GNU, большинство специалистов не видели его практических последствий в обозримом будущем.
Unix-сообщество никогда не теряло своего бунтарского духа. Однако, анализируя прошлое, становится ясно, что приверженцы Unix также не смогли правильно оценить новые тенденции. Даже Ричард Столлмен, который за несколько лет до этого провозгласил моральный крестовый поход против частного программного обеспечения, действительно не понимал, насколько сильно превращение Unix в коммерческий продукт повредило сообществу, объединенному вокруг данной операционной системы. Идеи Столлмена были более абстрактными и касались долгосрочных проблем. Остальные члены сообщества продолжали надеяться, что некое рациональное изменение корпоративной формулы разрешит проблемы фрагментации, скверного маркетинга и стратегического направления, а также восстановит былые перспективы Unix. Но худшее было еще впереди.
В 1988 году Кен Олсен (Ken Olsen), президент корпорации DEC, "провозгласил" Unix чуть ли не панацеей. DEC поставляла собственный вариант Unix на компьютерах PDP-11 с 1982 года, однако в действительности рассчитывала перевести бизнес на частную операционную систему VMS. Корпорация DEC и индустрия мини-компьютеров столкнулись с крупными проблемами, их захлестнула волна мощных дешевых машин, продаваемых Sun Microsystems и остальными поставщиками рабочих станций. На большинстве этих рабочих станций использовалась Unix.
Однако собственные проблемы Unix-индустрии становились еще труднее. В 1988 году AT&T приобрела 20% акций Sun Microsystems. Две эти компании, лидеры Unix-рынка, начинали восставать против угрозы, созданной PC-станциями, корпорациями IBM и Microsoft, и осознавать, что предыдущие 5 лет "кровопролития" ослабили их. Альянс AT&T/Sun и разработка технических стандартов вокруг POSIX положили конец разногласиям между направлениями System V и BSD Unix. Однако началась "вторая фаза войн", когда поставщики второго уровня (IBM, DEC, Hewlett-Packard и другие) учредили Фонд открытого программного обеспечения (Open Software Foundation) и "выстроились против" линии AT&T/Sun (представленной международным сообществом Unix). Последовали новые этапы противостояния Unix против Unix.
Тем временем Microsoft зарабатывала миллиарды на рынке компьютеров для дома и малого бизнеса, на что воюющие стороны не пожелали обратить внимание. Выпуск в 1990 году Windows 3.0 — первой успешной операционной системы с графическим интерфейсом из Рэдмонда — закрепил доминирующее положение Microsoft и создал условия, которые позволили корпорации выровнять цены и монополизировать рынок настольных приложений 90-х годов.
Годы с 1989 по 1993 были самыми мрачными в истории Unix. Выяснилось, что мечты всего Unix-сообщества провалились. Междоусобная вражда чрезвычайно ослабила Unix-индустрию, почти лишила ее возможности противостоять Microsoft. Элегантные процессоры компании Motorola, которые предпочитали Unix-программисты, проиграли неказистым, но недорогим процессорам Intel. Проект GNU оказался неспособен выпустить свободное ядро Unix, что было обещано еще в 1985 году, и после нескольких лет отговорок доверие к нему стало падать. PC-технология была безжалостно превращена в коммерческий продукт. Пионеры хакерского движения 70-х годов достигли среднего возраста и сбавили темп. Аппаратное обеспечение дешевело, но Unix оставалась и дальше чрезмерно дорогой системой. Приверженцы Unix с опозданием поняли, что прежняя монополия IBM сменилась новой монополией Microsoft, а плохо сконструированное программное обеспечение Microsoft все больше заполняло рынок.
В 1990 году первую попытку противостояния сделал Вильям Джолитц (William Jolitz), опубликовав серию журнальных статей о перенесении BSD Unix на машины с процессором 386-й серии. Такой перенос был вполне возможным, так как, частично под влиянием Столлмена, хакер из университета в Беркли, Кит Бостик (Keith Bostic), в 1988 году начал удалять частный код AT&T из исходных файлов BSD. Однако проект 386BSD получил сильный удар, когда в конце 1991 года Джойлитц покинул проект и погубил собственную работу. Существует ряд противоречивых объяснений этому факту, однако все они имеют общую линию: Джойлитц хотел выпустить свой код как свободный, и был огорчен тем, что корпоративные спонсоры проекта выбрали более частную модель лицензирования.
В августе 1991 года Линус Торвальдс (Linus Torvalds), тогда еще неизвестный студент из Финляндии, объявил о проекте операционной системы Linux. Торвальдс вспоминает, что одним из главных мотивирующих факторов для него послужила высокая цена операционной системы Unix производства Sun Microsystems в его университете. Торвальдс также отмечал, что если бы он знал о проекте BSD Unix, то скорее присоединился бы к нему, чем создавал бы собственный проект. Однако проект 386BSD не распространялся до начала 1992 года, т.е. несколько месяцев спустя после появления первой версии Linux.
Важность обоих проектов стала очевидной только через несколько лет. В то время они мало привлекали внимание даже внутри культуры Internet-хакеров. Эти проекты оставались единичными внутри более широкого Unix-сообщества, которое все еще было зациклено на более производительных машинах, чем PC, и на попытках примирения особых свойств Unix с традиционной частной моделью бизнеса по созданию программного обеспечения.
Потребовалось еще 2 года и взрывной рост Internet в 1993-1994 годах, прежде чем истинная важность Linux и дистрибутивов BSD с открытым исходным кодом стала очевидной для остальной части мира Unix. К несчастью для приверженцев BSD, судебное преследование BSDI (начинающей компании, которая поддерживала проект Джойлитца) поглощало большую часть времени и побудило нескольких ключевых разработчиков Berkeley Unix переключиться на Linux.
В то время немало было сказано о копировании кода и краже фирменных секретов. Контрафактный код не был идентифицирован в течение приблизительно 2 лет. Судебный процесс мог бы продлиться еще дольше, если бы корпорация Novell не приобрела USL у AT&T и не урегулировала спор. В конце концов, из 18 000 файлов, составляющих дистрибутив, было удалено 3, а в другие файлы были внесены незначительные изменения. В дополнение к этому, университет согласился добавить указание на авторские права USL в почти 70 файлов при условии, что данные файлы и далее будут распространяться свободно.
Достигнутое соглашение создало важный прецедент, освободив полностью работающую Unix от частного контроля, однако его результаты для самой BSD Unix были крайне неприятными. Проблем не убавилось, когда в 1992-1994 годах Исследовательская группа компьютерных наук (Computer Science Research Group) в Беркли прекратила свою работу. Впоследствии междоусобное противостояние внутри BSD-сообщества разделилось на 3 конкурирующих проекта. В результате BSD-ветвь в решающее время осталась позади Linux и уступила данной операционной системе лидирующие позиции в Unix-сообществе.
Усилия разработчиков операционных систем Linux и BSD были естественными для Internet, чего нельзя сказать о предыдущих Unix-системах. Они опирались на распределенную разработку и инструмент Ларри Уолла (patch(1)), а также привлекали разработчиков посредством электронной почты и групп новостей Usenet. Соответственно, они получили огромный подъем, когда в 1993 году благодаря изменениям в телекоммуникационной технологии и приватизации магистральных Internet-каналов начали распространяться компании-провайдеры Internet-услуг. Этот процесс выходит за рамки описываемой истории. Потребность в дешевом Internet-доступе была вызвана другим фактором: изобретением в 1991 году технологии World Wide Web, которая была в Internet "приложением-приманкой" (killer арр), технологией графического пользовательского интерфейса, которая сделала его дружественным для огромного числа нетехнических конечных пользователей.
Массовый маркетинг Internet одновременно увеличил число потенциальных разработчиков и сократил стоимость транзакций при распределенной разработке. Результаты проявились в проектах наподобие XFree86, в котором использовалась Internet-центрированная модель для создания более эффективной организации разработчиков, чем официальный Консорциум X (X Consortium). Первый выпуск сервера XFree86 в 1992 году обеспечил Linux и BSD подсистемой графического пользовательского интерфейса, которой им не доставало. В течение последующего десятилетия XFree86 будет лидировать среди X-разработок и основная деятельность Консорциума X будет состоять в отборе новаторских разработок, созданных в XFree86-сообществе, и направлении их обратно промышленным спонсорам консорциума.
К концу 1993 года операционная система Linux обладала как Internet-возможностями, так и системой X. Полный инструментарий GNU, обеспечивающий высококачественные средства разработки, поддерживался в Linux с самого начала. Более того, Linux была подобна чаше изобилия, притягивающей, накапливающей и концентрирующей 20 лет разработки программного обеспечения с открытым исходным кодом, которое до этого было рассеяно среди десятка различных частных Unix-платформ. Несмотря на то, что ядро Linux все еще официально представлялось бета-версией (уровня 0.99), оно было удивительно устойчивым. Размах и качество программного обеспечения в дистрибутивах Linux уже было таким же, как на действующих операционных системах.
Некоторые из Unix-разработчиков старой школы с более гибким мышлением стали отмечать, что долгожданная мечта о дешевой Unix-системе для каждого неожиданно начала воплощаться. Это происходило не благодаря AT&T, Sun или другому традиционному поставщику, и даже не благодаря организованным усилиям академических кругов. Это был бриколаж, созданный в Internet тем, что казалось спонтанным образованием, которое неожиданно заимствовало и комбинировало элементы Unix-традиции.
В стороне от этого процесса продолжалось корпоративное маневрирование. AT&T в 1992 году прекратила инвестировать Sun; затем в 1993 году продала свое подразделение Unix Systems Laboratories корпорации Novell. В 1994 году Novell передала торговую марку Unix группе разработки стандартов X/Open. В том же году AT&T и Novell присоединились к OSF, наконец положив конец Unix-войнам. В 1995 году компания SCO приобрела UnixWare (и права на оригинальные исходные коды Unix) у Novell. В 1996 году организации X/Open и OSF объединились, создав одну большую группу по разработке стандартов Unix.
Но традиционные поставщики Unix и последние сторонники противостояния казались все менее и менее значимыми. Активность и энергия в Unix-сообществе перемещалась к операционным системам Linux, BSD и разработчикам открытого исходного кода. К тому времени IBM, Intel и SCO анонсировали проект Monterey в 1998 году — последняя попытка объединить в одну большую систему все частные Unix-системы, оставшиеся "в стороне". Проект позабавил разработчиков и деловую прессу и внезапно прекратил существование в 2001 году после 3 лет движения в никуда.
Нельзя сказать, что промышленные транзакции были завершены до 2000 года, когда SCO продала UnixWare и оригинальные базовые исходные коды Unix компании Caldera, производителю дистрибутивов Linux. Но после 1995 года история Unix стала историей движения открытого исходного кода. У этой истории есть и другой аспект, и для того чтобы описать его, необходимо вернуться к событиям 1961 года и возникновению культуры Internet-хакеров.
Unix-традиция является скрытой культурой, а не просто набором технических приемов. Она передает совокупность ценностей, касающихся красоты и хорошего дизайна; в ней есть свои легенды и народные герои. С историей Unix-традиции переплелась другая неявная культура, четко обозначить которую еще труднее. В ней также есть собственные ценности, легенды и народные герои, частично совпадающие с традициями Unix, а частично унаследованные из других источников. Чаще всего ее называют "хакерской культурой", и с 1998 года она почти совершенно совпадает с тем, что в деловой компьютерной прессе называется "движением открытого исходного кода" (the open source movement).
Связи между Unix-традицией, хакерской культурой и движением открытого исходного кода неуловимые и сложные. Тот факт, что все три неявные культуры часто выражаются в поведении одних и тех же людей, не упрощает эти связи. Однако с 1990 года история Unix в значительной степени является историей того, как хакеры движения открытого исходного кода изменили правила и перехватили инициативу у частных поставщиков Unix старой линии. Таким образом, другая половина истории до современной Unix является историей хакеров.
Корни хакерской культуры прослеживаются до 1961 года, когда в MIT (Massachusetts Institute of Technology — Массачусетский технологический институт) появился первый мини-компьютер PDP-1. PDP-1 был одним из ранних интерактивных компьютеров, и (в отличие от других машин) в то время был достаточно недорогим, поэтому время работы на нем жестко не регламентировалось. Он привлек к себе внимание группы любознательных студентов из клуба "Tech Model Railroad Club", которые из интереса проводили на нем эксперименты. В книге "Hackers: Heroes of the Computer Revolution" [46] увлекательно описаны ранние дни клуба. Наиболее известным их достижением была "SPACEWAR" — игра, сюжет которой состоял в вольной трактовке космической оперы "Lensman" Эдварда Эльмара "Док" Смита (Е.Е. "Doc" Smith)[17]
Несколько экспериментаторов из клуба TMRC позднее стали главными членами Лаборатории искусственного интеллекта Массачусетского технологического института (MIT Artificial Intelligence Lab), которая в 60-70-х годах прошлого века стала одним из мировых центров прогрессивной компьютерной науки. Они позаимствовали некоторые сленговые выражения и шутки клуба TMRC, в том числе традицию тонко (но безвредно) организовывать розыгрыши, которые назывались "hacks" ("шпильки"). Программисты лаборатории искусственного интеллекта, вероятнее всего, первыми стали называть себя "хакерами".
После 1969 года лаборатория MIT AI подключилась через сеть ARPANET к остальным ведущим научно-исследовательским компьютерным лабораториям: в Стэнфорде, лаборатории компании Bolt Beranek & Newman, лаборатории Университета Карнеги-Меллон (Carnegie-Mellon University, CMU) и др. Исследователи и студенты впервые ощутили, как сеть с быстрым доступом стирала географические границы, способствовала сотрудничеству и дружбе.
Программное обеспечение, идеи, сленг и юмор передавались по экспериментальным каналам ARPANET. Начало формироваться нечто похожее на коллективную культуру. Так, многие помнят еще о т.н. "файле жаргона" (Jargon File) — списке широко используемых сленговых терминов, который возник в Стэнфорде в 1973 году и неоднократно перерабатывался в Массачусетском университете после 1976 года. Он аккумулировал в себе сленг из CMU, Йельского университета и других центров ARPANET.
Ранняя хакерская культура с технической точки зрения почти полностью поддерживалась мини-компьютерами PDP-10. На них использовались различные операционные системы, которые впоследствии вошли в историю: TOPS-10, TOPS-20, Multics, ITS, SAIL. Для программирования использовался ассемблер и диалекты LISP. Хакеры, работающие на PDP-10, взяли на себя поддержку самой сети ARPANET, поскольку других желающих выполнять эту работу не было. Позднее они стали основным кадровым составом IETF (Internet Engineering Task Force — инженерная группа по решению конкретной задачи в Internet) и основали традицию стандартизации посредством документов RFC (Requests For Comment — запросы на комментарии).
Это были исключительно талантливые молодые люди, чьим пристрастием стало программирование. Они склонялись к упорному отрицанию конформизма, спустя годы их будут называть "geeks" (помешанные). Они воспринимали компьютеры как устройства, создающие сообщество. Они читали Роберта Хейнлейна (Robert Heinlein) и Толкиена (J.R.R. Tolkien), играли в клубе "Общество творческого анахронизма" (Society for Creative Anachronism) и любили каламбуры. Несмотря на свои причуды (или, возможно, благодаря им), многие из них были в числе талантливейших программистов мира.
Они не были Unix-программистами. Unix-сообщество произошло в основном из той же массы "помешанных" в академических кругах, правительственных или коммерческих исследовательских лабораториях, однако эти культуры имели важные различия, которые были обусловлены слабой поддержкой сети в ранней Unix. До начала 80-х годов доступ к сети ARPANET на основе Unix практически не осуществлялся, и индивидуумы, входящие одновременно в оба лагеря, встречались нечасто.
Совместная разработка и совместное использование исходного кода было ценной тактикой для Unix-программистов. Для ранних ARPANET-хакеров, с другой стороны, это было больше, чем тактика. Для них это было скорее чем-то подобным общей религии, частично возникшей из академической идеи "опубликуй или погибни" (publish or perish) и (в наиболее крайних версиях) развившейся в почти шарденистский идеализм сетевых интеллектуальных сообществ. Наиболее известным представителем этой среды хакеров стал Ричард М. Столлмен.
После возникновения BSD-варианта TCP/IP в 1983 году началось взаимопроникновение культур Unix и ARPANET. Это стало вполне логичным результатом появления коммуникационных каналов, поскольку приверженцами обеих культур были в основном люди одного типа (а в действительности, зачастую те же люди). ARPANET-хакеры изучали С и начали употреблять жаргонные слова: каналы, фильтры и оболочки. Unix-программисты осваивали TCP/IP и стали называть друг друга "хакерами". Процесс слияния ускорился после того, как закрытие проекта Jupiter в 1983 году уничтожило будущее компьютеров PDP-10. К 1987 году две культуры сблизились настолько, что большинство хакеров программировали на С и небрежно использовали жаргон клуба "Tech Model Railroad Club" 25-летней давности.
(Если в 1979 году еще казались необычными прочные связи в обеих культурах, в Unix и ARPANET, то уже к середине 80-х годов они никого не удивляли. Когда в 1991 году автор этой книги расширил старый файл жаргона ARPANET в Новый словарь хакера (New Hacker's Dictionary) [66], две культуры практически смешались. Файл жаргона, созданный в ARPANET, но переработанный в Usenet, стал удачным символом этого слияния.)
Однако TCP/IP-сеть и сленг были не единственным наследием, которое после 1980 года хакерская культура получила благодаря своим "корням" в ARPANET. Эта культура стала неразрывно связана с именем Ричарда Столлмена.
Ричард М. Столлмен (широко известный под регистрационным именем RMS) к концу 1970 года уже доказал, что он является одним из наиболее способных современных программистов. Среди его многочисленных разработок был редактор Emacs. Для RMS закрытие проекта Jupiter в 1983 году только завершило дезинтеграцию культуры лаборатории MIT AI, которая началась несколькими годами ранее. RMS почувствовал себя изгнанным из хакерского рая и решил, что частное программное обеспечение достойно осуждения.
В 1983 году Столлмен основал проект GNU, целью которого было создание полностью свободной операционной системы. Хотя Столлмен никогда не был Unix-программистом, в условиях, создавшихся после 1980 года, реализация Unix-подобной операционной системы стала очевидной стратегией, которую следовало использовать. Большинство ранних помощников Столлмена были опытными ARPANET-хакерами, недавно влившимися в сообщество Unix.
В 1985 году Столлмен опубликовал Манифест GNU. В нем он сознательно создал идеологию из ценностей ARPANET-хакеров периода до 1980 года, полную новаторских этико-политических утверждений, независимых и характерных суждений. RMS ставил перед собой цель объединить рассеянное после 1980 года сообщество хакеров для достижения единой революционной цели. В его призывах явно прослеживались идеи Карла Маркса мобилизовать промышленный пролетариат против отчуждения результатов своего труда.
Манифест Столлмена разжег спор, который продолжается в хакерской среде и в наши дни. Его программа далеко выходила за рамки поддержки базового кода и, в сущности, подразумевала упразднение прав интеллектуальной собственности на программное обеспечение. Преследуя эту цель, Столлмен популяризировал понятие "свободное программное обеспечение" (free software), которое было первой попыткой определить продукт всей хакерской культуры. Столлмен написал Общедоступную лицензию (General Public License — GPL), которая должна была стать одновременно объединяющим началом и центром большой полемики по причинам, которые рассматриваются в главе 16. Дополнительные сведения, касающиеся позиции Столлмена и Фонда свободного программного обеспечения, приведены на Web-сайте проекта GNU
Понятие "свободное программное обеспечение" было частично описанием и частично попыткой определения культурной индивидуальности для хакеров. До Столлмена представители хакерской культуры воспринимали друг друга как коллег-исследователей и использовали тот же сленг, однако никого не заботили споры о том, кем являются или должны быть "хакеры". После него в хакерской культуре стало ярче проявляться самосознание. Харизматическая и поляризованная фигура RMS оказалась в центре хакерской культуры, Столлмен стал ее героем и легендой. К 2000 году его уже едва ли можно было отличить от его легенды. В книге "Free as in Freedom" [90] дана превосходная оценка его имиджа.
Аргументы Столлмена повлияли даже на поведение многих хакеров, которые продолжали скептически относиться к его теориям. В 1987 году он убедил попечителей BSD Unix в целесообразности удаления частного кода AT&T с целью выпустить свободную версию. Однако, несмотря на его решительные усилия, в течение более чем 15 лет после 1980 года хакерская культура так и не объединилась вокруг его идеологии.
Другие хакеры заново обнаруживали для себя открытые, совместные разработки без секретов по более прагматическим и менее идеологическим причинам. В конце 80-х годов, в нескольких зданиях офиса Ричарда Столлмена в Массачусетском технологическом университете, успешно трудилась группа разработки системы X. Она финансировалась поставщиками Unix, которые убедили друг друга быть выше проблем контроля и прав интеллектуальной собственности вокруг системы X Window, и не видели лучшей альтернативы, чем оставить ее свободной для всех. В 1987–1988-х годах разработка системы X послужила прообразом действительно крупных распределенных сообществ, которые пятью годами позже заново определят наиболее развитый участок исследований Unix.
Система X была одним из первых крупномасштабных проектов с открытым исходным кодом, разрабатываемым разнородным коллективом людей, работающих на различные организации и разбросанных по всему миру. К тому же электронная почта позволила быстро распространять идеи среди членов группы. Распространение программного обеспечения было вопросом нескольких часов, что позволяло согласованно функционировать всем участкам проекта. Сеть изменила способ разработки программного обеспечения.
X-разработчики не были последователями главного плана GNU, в то же время они не противодействовали ему активно. До 1995 года наиболее серьезное сопротивление плану GNU оказывали разработчики BSD. Приверженцы BSD, которые помнили, что они написали свободно распространяемое и модифицируемое программное обеспечение еще за годы до манифеста Столлмена, отвергали претензии проекта GNU на историческое и идеологическое главенство. Особенно они возражали против передающейся или "вирусной" собственности GPL, предлагая BSD-лицензию как "более свободную", поскольку она содержала меньше ограничений на повторное использование кода.
Это не помогало проекту Столлмена, и его попытки создания центральной части системы провалились, хотя его Фонд свободного программного обеспечения выпустил большую часть полного программного инструментария. Спустя 10 лет после учреждения проекта GNU, ядро GNU все еще не появилось. Несмотря на то, что отдельные средства, такие как Emacs и GCC, доказали свою потрясающую пользу, проект GNU без ядра не был способен ни угрожать гегемонии частных Unix-систем, ни предложить эффективное противодействие новой проблеме, связанной с монополией Microsoft.
После 1995 года спор вокруг идеологии Столлмена принял несколько иной оборот. Ее оппозиция стала ассоциироваться с именем Линуса Торвальдса, а также автора этой книги.
Даже когда проект HURD (GNU-ядро) "угасал", открывались новые возможности. В начале 90-х годов комбинация дешевых, мощных PC-компьютеров с простым Internet-доступом стала сильным соблазном для нового поколения молодых программистов, ищущих трудностей для испытания своего характера. Инструментарий пользователя, созданный Фондом свободного программного обеспечения, предложил весьма прогрессивный путь. Идеология следовала за экономикой, а не наоборот. Некоторые новички примкнули к крестовому походу Столлмена, приняв GNU в качестве его знамени, другим более импонировала традиция Unix в целом, и они присоединились к лагерю противников GPL, однако большинство вообще отказывалось от спора и просто писало код.
Линус Торвальдс искусно обошел противостояние, связанное с GPL, используя инструментальный набор GNU для окружения ядра Linux, созданного им, и лицензию GPL для его защиты, однако отказался от идеологической программы, которая следовала из лицензии Столлмена. Торвальдс заявлял, что в целом считает свободное программное обеспечение лучшим, чем частное, однако иногда использовал последнее. Его отказ становиться фанатиком даже в своем собственном деле делал его чрезвычайно привлекательным для большинства хакеров, которые чувствовали себя некомфортно под давлением разглагольствований Столлмена.
Жизнерадостный прагматизм Торвальдса и профессиональный, но скромный стиль, несомненно, способствовали удивительным победам хакерской культуры в 1993-1997 годах. Речь идет не только о технических успехах, но и о возникновении индустрии создания дистрибутивов, обслуживания и поддержки вокруг операционной системы Linux. В результате стремительно возрос его престиж и влияние. Торвальдс стал героем времени Internet. За 4 года (к 1995 году) он достиг таких "высот внутри культуры", для достижения которых Столлмену понадобилось 15 лет, причем он намного превзошел его рекорд в продаже "свободного программного обеспечения". В противоположность Торвальдсу, риторика Столлмена начала казаться резкой и неудачной.
Между 1991 и 1995 годами Linux перешла от тестовой среды, окружающей прототип ядра версии 0.1, к операционной системе, которая могла конкурировать по функциональности и производительности с частными Unix-системами, и превосходила их по таким важным характеристикам, как время непрерывной работы. В 1995 году Linux нашла свое приложение-приманку: Apache, Web-сервер с открытым исходным кодом. Как и Linux, Apache демонстрировал свою удивительную стабильность и эффективность. Linux-машины, поддерживающие Web-сервер Apache, быстро стали предпочтительной платформой для провайдеров Internet-услуг по всему миру; Apache поддерживает около 60% Web-сайтов[18], умело обыгрывая обоих своих главных частных конкурентов.
Единственное, чего не предложил Торвальдс, это новая идеология — новый рациональный или генеративный миф хакерского движения, позитивное суждение, заменяющее враждебность Столлмена к интеллектуальной собственности программой, более привлекательной для людей как внутри, так и вне хакерской культуры. Автор данной книги невольно восполнил этот недостаток в 1997 году, пытаясь понять, почему Linux-разработка несколько лет назад не была дезорганизована. Технические заключения опубликованных статей [67] приведены в главе 19. Здесь достаточно подчеркнуть, что при условии достаточно большого количества наблюдателей, все ошибки будут незначительными.
Это наблюдение подразумевает нечто такое, во что ни один представитель хакерской культуры не осмеливался действительно поверить в течение предыдущей четверти века, т.е. в надежные методы производства программного обеспечения, которое не просто более элегантно, но и более надежно, а значит, лучше, чем код частных конкурентов. Этот вывод весьма неожиданно совпал с представлением Торвальдса о "свободном программном обеспечении". Для большинства хакеров и почти всех нехакеров девиз "создавайте свободные программы, поскольку они работают лучше" стал более привлекательным, чем девиз "создавайте свободные программы, потому что все программы должны быть свободными".
Контраст между "соборным" (т.е. централизованным, закрытым, контролируемым, замкнутым) и "базарным" (децентрализованным, открытым, с тщательной экспертной оценкой) видами разработки обусловил новое мышление данной среды. Это неразрывно связано с мнением Дуга Макилроя и Денниса Ритчи о братстве и обоюдном влиянии этого братства и ранних академических традиций ARPANET, связанных с экспертной оценкой и идеалистическими представлениями распределенного сообщества разума.
В начале 1998 года новое мышление подтолкнуло компанию Netscape Communications опубликовать исходный код браузера Mozilla. Внимание прессы к этому событию привело Linux на Уолл Стрит, способствовало возникновению бума акций технологических компаний в 1999-2000 годах, и действительно стало поворотной точкой, как в истории хакерской культуры, так и в истории Unix.
К моменту выхода браузера Mozilla в 1998 году хакерское сообщество наиболее правильно было бы охарактеризовать как множество группировок или братств. В него входили: движение свободного программного обеспечения Ричарда Столлмена, Linux-сообщество, Perl-сообщество, BSD-сообщество, Apache-сообщество, сообщество X-разработчиков, Инженерная группа по решению конкретной задачи в Internet (IETF) и как минимум десяток других объединений. Причем эти группировки пересекались, и отдельные разработчики, весьма вероятно, входили в состав двух или более групп.
Братство могло формироваться вокруг определенного базового кода, который поддерживался его членами, вокруг одного или нескольких харизматических лидеров, вокруг языка или средства разработки, вокруг определенной лицензии на программное обеспечение или технического стандарта, или вокруг организации- попечителя для некоторой части инфраструктуры. Наиболее почитаемой является группа IETF, которая неразрывно связана с появлением ARPANET в 1969 году. BSD-сообщество, традиции которого формировались в конце 70-х годов, пользуется большим престижем, несмотря на меньшее, чем у Linux, количество инсталляций. Движение свободного программного обеспечения Столлмена, возникновение которого датируется началом 80-х годов, относится к числу старших братств, как по историческому вкладу, так и в качестве куратора нескольких интенсивно и повседневно используемых программных инструментов.
После 1995 года Linux приобрела особую роль и как объединяющая платформа для большинства дополнительных программ сообщества, и как наиболее узнаваемое в среде хакеров имя. Linux-сообщество продемонстрировало соответствующую тенденцию поглощать другие братства, а, следовательно, выбирать и поглощать хакерские группировки, связанные с частными Unix-системами. Хакерская культура в целом начала объединяться вокруг общей миссии: как можно дальше продвинуть Linux и общественную (bazaar) модель разработки.
Поскольку хакерская культура после 1980 года "очень глубоко укоренилась" в Unix, новая миссия была неявным результатом триумфа Unix-традиции. Многие из старших лидеров хакерского сообщества, примкнувшие к Linux-движению, одновременно были ветеранами Unix, продолжающими традиции культурных войн 80-х годов после раздела AT&T.
Выход браузера Mozilla способствовал дальнейшему развитию идей. В марте 1998 года беспрецедентная встреча собрала влиятельных лидеров сообщества, представляющих почти все главные братства, для рассмотрения общих целей и тактики. В ходе этой встречи было принято новое определение общего для всех групп метода разработки: открытый исходный код (open source).
В течение 6 последующих месяцев почти все братства в хакерском сообществе приняли "открытый исходный код" как новое знамя. Более ранние группы, такие как IETF и BSD-разработчики, станут применять данное понятие ретроспективно к тому, что они делали до этого момента. Фактически к 2000 году риторика исходного кода будет не только объединять в хакерской культуре существующую практику и планы на будущее, но и представлять в новом свете свое прошлое.
Побудительный эффект от анонсирования продукта Netscape и новой важности Linux вышел далеко за пределы Unix-сообщества и хакерской культуры. Начиная с 1995 года, разработчики различных платформ, стоящих на пути Microsoft Windows (MacOS, Amiga, OS/2, DOS, CP/M, более слабые частные Unix-системы, различные операционные системы для мэйнфреймов, мини-компьютеров и устаревших микрокомпьютеров), сгруппировались вокруг языка Java, разработанного в Sun Microsystems. Многие недовольные Windows-разработчики присоединились к ним в надежде получить, по крайней мере, некоторую номинальную независимость от Microsoft. Однако поддержка Java со стороны Sun была (как описывается в главе 14) неумелой и разрозненной. Многим Java-разработчикам пришлось по вкусу то, что пропагандировалось в зарождающемся движении поддержки открытого исходного кода, и они вслед за Netscape перешли в сообщество Linux и открытого исходного кода, так же как ранее, следуя примеру Netscape, перешли к языку Java.
Активисты движения открытого исходного кода охотно приняли "волну иммигрантов" отовсюду. Старые приверженцы Unix стали разделять мечты новых иммигрантов о том, чтобы не просто пассивно мириться с монополией Microsoft, но и фактически осваивать ее рыночные секреты. Сообщество открытого исходного кода в целом подготовило основную поддержку господствующей тенденции и начало охотно вступать в альянс с главными корпорациями, в которых росли опасения потери контроля над собственным бизнесом ввиду более решительной и захватывающей тактики Microsoft.
А что же Ричард Столлмен и движение свободного программного обеспечения? Понятие "открытый исходный код" было явно предусмотрено для замены понятия "свободного программного обеспечения", которое предпочитал Столлмен. Он полусерьезно воспринимал данное понятие, а впоследствии отверг его на том основании, что оно не способно представить моральную позицию, которая была центральной с его точки зрения. С тех пор движение свободного программного обеспечения настаивает на своей обособленности от "открытого исходного кода", создавая, вероятно, наиболее значительный политический раскол в хакерской культуре последних лет.
Другой (и более важной) целью внедрения понятия "открытый исходный код" было представление методов хакерского сообщества остальному миру (в особенности лидирующим компаниям) более приемлемым и менее конфронтационным для рынка способом. В этой роли, к счастью, "открытый исходный код" добился безоговорочного успеха — привел к возрождению интереса к традициям Unix, из которых и произошло данное понятие.
Наиболее крупномасштабная модель в истории Unix представляет следующее: Unix процветала там и тогда, когда она наиболее близко приближалась к практике открытого исходного кода. Попытки сделать ее частной неизменно приводили к застою и упадку.
Анализируя прошлое, можно заключить, что это должно было стать очевидным гораздо раньше. Мы потеряли 10 лет после 1984 года, анализируя этот урок, и он, вероятно, является для нас слишком болезненным, чтобы его забыть.
То, что мы были более талантливыми, чем кто-либо другой в решении важных, но узких проблем разработки программного обеспечения, не спасло нас от почти полного непонимания взаимосвязи между технологией и экономикой. Даже самые перспективные и дальновидные мыслители Unix-сообщества были в лучшем случае полуслепыми. Урок на будущее состоит в том, что чрезмерная привязанность к какой- либо одной технологии или модели бизнеса была бы ошибочной, а поддержка адаптивной гибкости программного обеспечения и сопутствующей ему традиции проектирования является, соответственно, жизненно важной.
Другой урок: никогда не следует противостоять дешевому и гибкому решению. Иными словами, низкоклассная/массовая аппаратная технология почти всегда в конце концов поднимает кривую мощности и выигрывает. Экономист Клейтон Кристенсен (Clayton Christensen) называет это пробивной технологией (disruptive technology) и в книге 'The Innovator's Dilemma" [12] демонстрирует, как это происходило с дисковыми накопителями, паровыми экскаваторами и мотоциклами. Мы видели это, когда мини-компьютеры заменили мэйнфреймы, рабочие станции и серверы сменили мини-компьютеры, а Intel-машины потребительского класса пришли на смену серверам и рабочим станциям. Движение открытого исходного кода выигрывает, потому что делает программное обеспечение потребительским товаром. Чтобы преуспеть, системе Unix необходимо выработать способность выбирать дешевое гибкое решение, а не пытаться бороться против него.
Наконец, Unix-сообщество старой школы потерпело неудачу в своих попытках быть "профессионалами", привлекая все управляющие механизмы традиционных корпоративных организаций, финансы и маркетинг.
Если ваша проблема выглядит неприступной, найдите пользователя Unix, который покажет, как ее решить.
Способы создания операционных систем, как очевидные, так и едва различимые, определяют стиль разработки программного обеспечения в них. Материал данной книги помогает лучше понимать взаимосвязи между конструкцией операционной системы Unix и развившейся вокруг нее философией проектирования программ. Поэтому считаем полезным представить сравнение стилей проектирования и программирования, свойственных системе Unix, и тех, которые характерны для остальных крупных операционных систем.
Прежде чем рассматривать те или иные операционные системы, необходимо определить "точку отсчета" для анализа способов, с помощью которых проектирование операционных систем может положительно или отрицательно повлиять на стиль программирования.
В целом, стили проектирования и программирования, связанные с различными операционными системами, вероятно, определяются тремя факторами: (а) замыслы разработчиков операционных систем, (b) единообразные формы, повлиявшие на конструкции посредством затрат и ограничений в среде программирования и (с) случайное культурное течение, ранние практические приемы, ставшие традиционными просто потому, что они были первыми.
Даже если принять как данность, что в каждом из сообществ, сформированных вокруг отдельных операционных систем, проявляются случайные культурные течения, оценка замыслов проектировщиков, а также затрат и ограничений, действительно позволяет обнаружить некоторые интересные модели. Сравнение этих моделей может способствовать более точному пониманию Unix-стиля. Выявить их можно путем анализа некоторых из наиболее важных различий операционных систем.
В операционной системе Unix имеется несколько унифицирующих идей или метафор, которые формируют ее API-интерфейсы и определяемый ими стиль разработки. Наиболее важными из них, вероятно, являются модель, согласно которой "каждый объект является файлом", и метафора каналов (pipes)[19], построенная на ее поверхности. Как правило, стиль разработки в определенной операционной системе строго обусловлен унифицирующими идеями, которые были заложены в данную систему ее разработчиками. Они проникают в прикладное программирование из моделей, обеспеченных системными инструментами и API-интерфейсами.
Соответственно, при сравнении Unix с другой операционной системой, прежде всего, необходимо определить, имеет ли она унифицирующие идеи, которые формируют ее разработку, и если да, то чем они отличаются от идей Unix.
Для того чтобы разработать систему, абсолютно противоположную Unix, следует отказаться от унифицирующей идеи вообще, и иметь только несогласованную массу узкоспециализированных функций.
Одним из основных отличий операционных систем является степень, с которой они способны поддерживать множество конкурирующих процессов. Операционная система самого низкого уровня (например DOS или CP/M), в сущности, представляет собой последовательный загрузчик программ без многозадачных возможностей. Операционные системы такого типа в настоящее время не конкурентоспособны на неспециализированных компьютерах.
Для операционной системы более высокого уровня может быть характерна невытесняющая многозадачность (cooperative multitasking). Системы такого рода способны поддерживать множество процессов, однако при этом должно быть предусмотрено такое взаимодействие последних, когда один процесс произвольно "уступает" ресурсы процессора, прежде чем появится возможность запуска следующего процесса (таким образом, простые ошибки программирования могут привести к быстрой блокировке всей машины). Данный стиль операционных систем был временным переходным решением для аппаратного обеспечения, которое было достаточно мощным для поддержки конкурентных процессов, но испытывало либо недостаток периодических прерываний от таймера[20], либо недостаток в блоке управления памятью (memory-management unit), или то и другое. Многозадачность такого типа в настоящее время также является устаревшей и неконкурентоспособной.
В операционной системе Unix используется вытесняющая многозадачность (preemptive multitasking), при которой кванты времени распределяются системным планировщиком, который регулярно прерывает или вытесняет запущенный процесс для передачи управления следующему процессу. Почти все современные операционные системы поддерживают данный тип многозадачности.
Следует заметить, что понятие "многозадачная система" не тождественно понятию "многопользовательская система". Операционная система может быть многозадачной, но однопользовательской. В таком случае система используется для поддержки одной консоли и нескольких фоновых процессов. Истинная поддержка многопользовательской работы требует разграничений привилегий пользователей.
Для того чтобы создать систему, абсолютно противоположную Unix, вообще не следует поддерживать многозадачность или поддерживать, но испортить ее, окружая управление процессами множеством запретов, ограничений и частных случаев, при которых фактическое использование системы вне многозадачности весьма затрудняется.
В случае Unix малозатратное создание дочерних процессов (Process-Spawning) и простое межпроцессное взаимодействие (Inter-Process Communication — IPC) делают возможным использование целой системы небольших инструментов, каналов и фильтров. Данная система будет рассматриваться в главе 7; здесь необходимо указать некоторые последствия дорогостоящего создания дочерних процессов и IPC.
Канал был технически тривиален, но производил мощный эффект. Однако он никогда не стал бы простым без фундаментальной унифицирующей идеи процесса как автономной вычислительной единицы с программируемым управлением. В операционной системе Multics командный интерпретатор представлял собой просто другой процесс; управление процессами "не пришло свыше" вписанным в JCL.
Если операционная система характеризуется дорогостоящим созданием новых процессов и/или управление процессами является сложным и негибким, то, как правило, проявляются описанные ниже последствия.
• Более естественным способом программирования становятся монолитные гигантские конструкции.
• Большая часть политики должна быть реализована внутри этих монолитов. Это подталкивает к использованию С++ и замысловатой многослойной внутренней организации кода, вместо С и относительно простых внутренних иерархий.
• Когда процессы не могут избежать взаимодействия, они производят обмен данными посредством механизмов, которые являются громоздкими, неэффективными и небезопасными (например, с помощью временных файлов), или путем сохранения чрезмерно большого количества сведений о реализациях других процессов.
• Мультипроцессная обработка (multithreading) широко применяется для задач, которые в Unix обрабатывались бы с помощью множества сообщающихся друг с другом легковесных процессов.
• Возникает необходимость изучения и использования асинхронного ввода-вывода.
Существует ряд примеров общих стилистических особенностей (даже в прикладном программировании), которые возникают в связи с ограничениями операционной системы.
Неочевидным, но важным свойством каналов и других классических IPC-методов Unix является то, что они требуют такой уровень простоты обмена данными между программами, который побуждает разделение функции. Напротив, отсутствие эквивалента каналов проявляется в том, что взаимодействие программ может быть реализовано только путем внедрения в них полного объема сведений о внутреннем устройстве друг друга.
В операционных системах без гибкого IPC-механизма и прочной традиции его использования программы обмениваются данными путем совместного применения сложных структур данных. Поскольку проблему связи необходимо решать заново для всех программ каждый раз при добавлении новой программы в набор, сложность данного решения возрастает как квадрат числа взаимодействующих программ. Еще хуже то, что любое изменение в одной из открытых структур данных может вызвать неочевидные ошибки в неопределенно большом числе других программ.
Word, Excel, PowerPoint и другие программы Microsoft обладают детальными, можно сказать безграничными, знаниями о внутреннем устройстве друг друга. В Unix программист пытается разрабатывать программы не только для взаимодействия друг с другом, но и с еще не созданными программами.
Данная тема также затрагивается в главе 7.
Для создания системы, абсолютно противоположной Unix, следует делать создание дочерних процессов очень дорогостоящим, управление процессами сложным и негибким, и оставлять IPC-механизм как неподдерживаемый или как наполовину поддерживаемое запоздалое решение.
В Unix действует предположение о том, что программист знает лучше (чем система). Система не остановит пользователя и не потребует какого-либо подтверждения при выполнении опасных действий с данными, таких как ввод команды
rm -rf *
. С другой стороны, Unix весьма заботится о том, чтобы не допустить одного пользователя к данным другого. Фактически Unix побуждает пользователя иметь несколько учетных записей, в каждой из которых имеются собственные и, возможно, отличные от других записей привилегии, позволяющие пользователю обезопасить себя от аномально работающих программ[21]. Системные программы часто обладают собственными учетными записями псевдопользователей, которые нужны для присвоения прав доступа только к определенным системным файлам без необходимости неограниченного доступа (или доступа с правами суперпользователя (superuser)).
В Unix имеется по крайней мере три уровня внутренних границ, которые защищают от злонамеренных пользователей или чреватых ошибками программ. Одним из таких уровней является управление памятью. Unix использует аппаратный блок управления памятью (Memory Management Unit — MMU), который препятствует вторжению одних процессов в адресное пространство памяти других. Вторым уровнем является реальное присутствие групп привилегий для множества пользователей. Процессы обычных пользователей (т.е. не администраторов) не могут без разрешения изменять или считывать файлы других пользователей. Третьим уровнем является заключение критичных к безопасности функций в минимально возможные участки благонадежного кода. В Unix даже оболочка (системный командный интерпретатор) не является привилегированной программой.
Целостность внутренних границ операционной системы является не просто абстрактным вопросом дизайна. Она имеет важные практические последствия для безопасности системы.
Чтобы разработать систему, полностью противоположную Unix, необходимо отказаться от управления памятью, с тем чтобы вышедший из-под контроля процесс мог разрушить любую запущенную программу или же заблокировать и повредить ее. В этом случае следует поддерживать слабые группы привилегий или не иметь их вообще, с тем чтобы пользователи могли без труда изменять чужие файлы и важные системные данные (например, макровирус, захвативший контроль над текстовым процессором, может отформатировать жесткий диск). Кроме того, следует доверять большим блокам кода, подобным оболочке и GUI-интерфейсу, так чтобы любая ошибка или успешная атака на данный код становилась угрозой для всей системы.
Unix-файлы не имеют ни структур записи (record structure), ни атрибутов. В некоторых операционных системах файлы имеют связанные структуры записи; операционная система (или ее служебные библиотеки) "знает" о файлах с фиксированной длиной записи или об ограничивающем символе текстовой строки, а также о том, следует ли читать последовательность CR/LF как один логический символ.
В других операционных системах файлы и каталоги имеют связанные с ними пары имя/атрибут — внешние данные, используемые (например) для связи файла документа с распознающим его приложением. (Классический способ поддержки таких связей в Unix заключается в том, чтобы заставить приложения опознавать "магические числа" или другие типы данных, находящиеся внутри самого файла.)
Одна из проблем оптимизации связана со структурами записи уровня операционной системы. Это гораздо более серьезная проблема, чем простое усложнение API-интерфейсов и работы программистов. Они подталкивают программистов использовать неясные форматы файлов, ориентированных на записи, которые невозможно соответствующим образом прочитать с помощью обычных инструментов, таких как текстовые редакторы.
Атрибуты файлов могут быть полезными, однако (как будет сказано в главе 20) они способны создавать некоторые каверзные проблемы семантики в среде каналов и инструментов, ориентированных на байтовые потоки. Когда атрибуты файлов поддерживаются на уровне операционной системы, они побуждают программистов использовать неясные форматы и опираться на атрибуты файлов для их связывания со специфическими интерпретирующими приложениями.
Для разработки системы, совершенно противоположной Unix, необходимо иметь громоздкий набор структур записи, которые заставят угадывать, способен ли какой- либо определенный инструмент прочесть файл в таком виде, каким он был создан в исходном приложении. Добавляйте файловые атрибуты и создавайте систему, сильно зависимую от них, с тем чтобы семантику файла нельзя было определить путем изучения данных внутри данного файла.
Если в операционной системе применяются двоичные форматы для важных данных (таких как учетные записи пользователей), вполне вероятно, что традиции использования читабельных текстовых форматов для приложений не сформируются. Более подробно о том, почему данный подход является проблемным, будет сказано в главе 5. Здесь достаточно упомянуть о нескольких последствиях.
• Даже если поддерживается интерфейс командной строки, написание сценариев и каналы, в системе будут развиваться только очень немногие фильтры.
• Доступ к файлам данных можно будет получить только посредством специальных средств. Для разработчиков главными станут данные средства, а не файлы данных. Следовательно, различные версии форматов файлов часто будут несовместимыми.
Для проектирования системы, полностью противоположной Unix, нужно сделать все форматы файлов двоичными и неясными, а также сделать обязательным использование тяжеловесных инструментов для их чтения и редактирования.
В главе 11 подробно рассматриваются различия между интерфейсами командной строки (Command-Line Interfaces — CLI) и графическими пользовательскими интерфейсами (Graphical User Interfaces — GUI). Выбор проектировщиком операционной системы одного из этих типов в качестве обычного режима представления влияет на многие аспекты конструкции от планирования процессов и управления памятью до программных интерфейсов приложений (Application Programming Interfaces — API), предоставленных приложениям для использования.
С момента появления первых компьютеров Macintosh понадобилось достаточно много лет, чтобы специалисты убедились в том, что слабые средства GUI-интерфейса в операционной системе являются проблемой. Опыт Unix противоположен: слабые средства CLI-интерфейса представляют собой менее очевидный, но не менее серьезный недостаток.
Если в операционной системе CLI-средства являются слабыми или их вообще нет, то проявляются описанные ниже последствия.
• Никто не будет разрабатывать программы, взаимодействующие друг с другом неожиданным способом, поскольку это будет невозможно. Вывод одной программы невозможно будет использовать в качестве ввода другой.
• Удаленное системное администрирование будет слабым и трудным в использовании, и будет потреблять больше сетевых ресурсов[22].
• Даже простые неинтерактивные программы будут нести на себе издержки графического интерфейса или замысловатого интерфейса сценариев.
• Программирование любым изящным способом серверов, системных служб и фоновых процессов будет, вероятно, невозможным или, по крайней мере, значительно затруднится.
Для разработки системы, полностью противоположной Unix, нужно отказаться от CLI-интерфейса и возможностей включения программ в сценарии, или использовать важные средства, управлять которыми с помощью CLI-интерфейса невозможно.
Дизайн той или иной операционной системы прямо зависит от ее потребителя. Некоторые операционные системы предназначены для лабораторий, другие — для настольных компьютеров. Одни системы разрабатываются для технических специалистов, иные — для конечных пользователей. Некоторые предназначены для обособленной работы в управляющих приложениях реального времени, другие — для работы в качестве среды для разделения времени и распределенных сетей.
К очень важным отличительным факторам относятся клиент и сервер. "Клиент" представляет собой легковесную систему, поддерживающую только одного пользователя. Такая система способна работать на небольших машинах и предназначена для включения в случае необходимости и отключения после завершения пользователем работы. Она не имеет вытесняющей многозадачности, оптимизирована по низкой задержке и выделяет большую часть своих ресурсов для поддержки вычурных пользовательских интерфейсов. "Сервер" — тяжеловесная система, способная работать продолжительное время и оптимизированная по пропускной способности. Для поддержки множества сеансов в такой системе используется полная вытесняющая многозадачность. Первоначально все операционные системы были серверными. Идея клиентской операционной системы возникла только в конце 70-х годов прошлого века с появлением PC, недорогого аппаратного обеспечения невысокой мощности. В клиентских операционных системах основное внимание уделяется визуально привлекательному для пользователя внешнему виду, а не бесперебойной работе 24 часа в сутки 7 дней в неделю.
Кроме того, на стиль разработки, конечно же, влияет допустимый с точки зрения целевой аудитории уровень сложности интерфейса и то, как эта сложность соотносится со стоимостью и производительностью. Об операционной системе Unix часто говорят, что она создана программистами для программистов, т.е. для целевой аудитории, которая известна своей терпимостью к сложности интерфейса.
Это скорее следствие, чем цель. Я испытываю отвращение к системе, разработанной для "пользователя", если в слове "пользователь" закодировано уничижительное значение "тупой и примитивный".
Для того чтобы разработать операционную систему, абсолютно противоположную Unix, ее нужно писать так, как будто она "знает" о намерениях пользователя больше, чем он сам.
Другой важной характеристикой, по которой различают операционные системы, является совокупность сложностей, препятствующих простым пользователям стать разработчиками. Существует два определяющих фактора. Одним из них является денежная стоимость средств разработки, а другим — затраты времени, необходимые для того, чтобы развить мастерство разработчика. В некоторых средах развиваются также социальные барьеры, однако они обычно являются следствием базовых технологических сложностей, а не первопричиной.
Дорогостоящие инструменты разработки и сложные неясные API-интерфейсы ведут к возникновению небольших элитных культур программирования. В таких культурах программные проекты являются крупными, каковыми они и должны быть, для того чтобы окупить вложения как финансового, так и интеллектуального (человеческого) капитала. Для крупных проектов характерно создание крупных программ (и, как следствие, это часто приводит к большим дорогостоящим провалам).
Недорогие инструменты и простые интерфейсы поддерживают любительское программирование, культуру увлеченных энтузиастов и исследования. Программные проекты могут быть небольшими (часто формальная структура проекта является явно излишней), а провалы не являются катастрофическими. Это меняет стиль разработки кода. Кроме прочих преимуществ, они демонстрируют меньшую склонность к неверным подходам.
Любительское программирование стремится к созданию большого количества небольших программ и сообщества знаний, которое самостоятельно укрепляется и расширяется. В мире дешевого аппаратного обеспечения присутствие или отсутствие такого сообщества становится все более важным фактором, определяющим, будет ли операционная система жизнеспособной в течение длительного времени.
Любительское программирование зародилось в Unix. Одним из новшеств, которое впервые появилось в Unix, была поставка компилятора и инструментов написания сценариев как части стандартного инсталляционного набора, доступного для всех пользователей. Это поддерживало культуру разработки программного обеспечения как хобби, которая охватила множество инсталляций. Множество любителей, писавших код в Unix, не считали свое занятие разработкой кода, они считали его написанием сценариев для автоматизации общих задач или настройкой своей среды.
Для того чтобы разработать систему, полностью противоположную Unix, нужно сделать любительское программирование невозможным.
Логика выбора конструкции Unix становится более очевидной в сравнении с другими операционными системами. Ниже приводится только общий обзор конструкций[23].
На рис. 3.1. отражены генетические связи между рассматриваемыми операционными системами разделения времени. Несколько других операционных систем (отмеченные серым цветом и не обязательно являющиеся системами разделения времени) включены для расширения контекста. Системы, названия которых обрамлены сплошными линиями, до сих пор существуют. Дата "рождения" представляет собой дату первой поставки[24], дата "смерти", как правило, — это дата, когда поставщик прекратил поставку системы.
Сплошные стрелки указывают на генетическую связь или очень сильное влияние дизайна (т.е. более позднюю систему с API-интерфейсом, умышленно переработанным путем обратного проектирования для соответствия более ранней системе). Штриховые линии указывают на значительное влияние конструкции, а пунктирные — наоборот, на слабое влияние конструкции. Не все генетические связи подтверждаются разработчиками. В действительности, некоторые из них были официально отвергнуты по соображениям законности или корпоративной стратегии, но являются открытыми секретами в индустрии.
Блок "Unix" включает в себя все частные Unix-системы, включая AT&T и ранние версии Berkeley Unix. Блок "Linux" включает в себя Unix-системы с открытыми исходными кодами, каждая из которых была основана в 1991 году. Они имеют генетическую наследственность от раннего Unix-кода, который был освобожден от частного контроля AT&T соглашением по судебному процессу 1993 года[25].
VMS — частная операционная система, первоначально разработанная для мини-компьютера VAX корпорации "Digital Equipment Corporation" (DEC). Впервые она была выпущена в 1978 году и была важной действующей операционной системой в 80-х и начале 90-х годов. Сопровождение данной системы продолжалось, когда DEC была приобретена компанией Compaq, а последняя — корпорацией Hewlett-Packard.
На момент написания книги операционная система VMS продолжала продаваться и поддерживаться[26]. VMS приведена в данном обзоре для демонстрации контраста между Unix и другими CLI-ориентированными операционными системами эры мини-компьютеров.
Рис. 3.1. Схема исторических связей между системами разделения времени
Операционная система VMS имеет полную вытесняющую многозадачность, однако создание дочерних процессов в ней весьма дорогостоящее. Файловая система в VMS имеет детально разработанное понятие типов записи (хотя в ней нет атрибутов). Данные черты приводят к тем же последствиям, которые рассматривались выше, в особенности в VMS проявляется тенденция к увеличению размеров программ и созданию тяжеловесных монолитов.
VMS характеризуется длинными, четкими системными командами, подобными инструкциям COBOL, и параметрами команд. В VMS имеется весьма полная интерактивная справочная система (не по API-интерфейсам, а по запускаемым программам и синтаксису командной строки). Фактически CLI-интерфейс VMS и ее справочная система являются организационной метафорой VMS. Хотя система X Window модифицирована для VMS, подробный CLI-интерфейс продолжает оказывать наиболее важное стилистическое влияние на проектирование программ. В связи с этим определяется ряд следующих факторов и последствий.
• Частота, с которой используются функции командной строки — чем длиннее команда, которую необходимо ввести, тем меньше пользователь хочет это делать.
• Размер программ — люди хотят вводить с клавиатуры меньше команд, а значит, использовать меньше программ и писать более крупные программы с большим количеством функций.
• Количество и тип принимаемых программой параметров — они должны соответствовать синтаксическим ограничениям, налагаемым справочной системой.
• Простота использования справочной системы — справка в VMS весьма полная, но поиск и поисковые средства в ней отсутствуют, кроме того, индексация справочной системы недостаточная. Это затрудняет получение четких сведений, поддерживает специализацию и препятствует любительскому программированию.
VMS имеет заслуживающую доверия систему внутренних границ. Она была разработана для действительно многопользовательской работы, и для того чтобы оградить процессы друг от друга, полностью использует аппаратный блок MMU. Системный интерпретатор команд является привилегированной программой, но инкапсуляция важных функций остается достаточно хорошей. Взломы системы безопасности VMS бывают редко.
Первоначально VMS-инструменты были дорогими, а интерфейсы сложными. Огромное количество программной документации для VMS доступны только в бумажной форме, поэтому поиск каких-либо сведений является продолжительной и трудоемкой операцией. Данные причины препятствовали исследовательскому программированию и изучению обширного инструментария. Только после того как поставщик VMS почти забросил данную систему, вокруг нее развилось любительское программирование и культура хобби, но данная культура не является особенно стойкой.
Подобно Unix, операционная система VMS предшествовала разграничению клиент/сервер. Она была успешной в свое время в качестве общецелевой операционной системы разделения времени. Целевую аудиторию главным образом представляли технические пользователи и преимущественно программные предприятия, допускающие умеренную сложность.
Операционная система Macintosh была разработана в компании Apple в начале 80-х годов прошлого века. Ее создателей вдохновила передовая работа по разработке GUI-интерфейсов, осуществленная ранее в Исследовательском центре Palo Alto (Palo Alto Research Center) компании Xerox. Она увидела свет вместе с Macintosh в 1984 году. С тех пор MacOS подверглась двум значительным преобразованиям конструкции, а в настоящее время претерпевает третье. Первое преобразование было связано с переходом от поддержки только одного приложения в тот или иной момент времени к невытесняющей многозадачности (MultiFinder). Вторым преобразованием был переход с процессоров серии 68000 на процессоры PowerPC, что позволило сохранить обратную бинарную совместимость с приложениями 68K, а также добавило для PowerPC-приложений усовершенствованную систему управления общими библиотеками, заменяющую исходную систему прерываний совместно используемых программ на основе инструкций процессора 68K. Третьим преобразованием было объединение в системе MacOS X конструкторских идей MacOS с Unix-производной инфраструктурой. В данном разделе рассматриваются предшествующие MacOS X версии данной системы, кроме случаев, где это будет отмечено особо.
В MacOS прослеживается очень сильное влияние унифицирующей идеи, которая весьма отличается от идеи Unix: нормы проектирования интерфейсов компьютеров Macintosh (Mac Interface Guidelines). Они подробнейшим образом определяют внешний вид графического интерфейса приложений и режимы его работы. Согласованность норм значительно влияет на культуру пользователей компьютеров Macintosh. Нередко просто перенесенные программы из DOS или Unix, не соблюдающие определенные нормы, немедленно отвергаются сообществом Mac-пользователей и терпят неудачи на рынке.
Одна из ключевых идей относительно норм заключается в том, что рабочие компоненты должны находиться там, куда их перенес пользователь. Документы, каталоги и другие объекты постоянно сохраняются на рабочем столе, не смешиваясь с системной информацией, а содержание рабочего стола сохраняется при перезагрузках.
Унифицирующая идея Macintosh проявляется настолько сильно, что большинство других вариантов конструкции, описанных выше, либо находятся под ее влиянием, либо незаметны. Во всех программах предусмотрены графические интерфейсы. Интерфейса командной строки не существует вообще. Средства сценариев есть в наличии, однако они используются значительно реже, чем в Unix; многие Mac-программисты никогда их не изучают. Присущая MacOS метафора неотделимого GUI-интерфейса (организованная вокруг единственного главного событийного цикла) обусловила наличие слабого планировщика задач без приоритетности обслуживания. Слабый планировщик и работа всех MultiFinder-приложений в одном большом адресном пространстве означают, что использовать отдельные процессы или даже параллельные процессы вместо поочередного опроса непрактично.
Вместе с тем приложения MacOS не являются неизменно огромными монолитами. Системный код поддержки графического интерфейса, который частично реализован в ПЗУ, поставляемом с аппаратным обеспечением, а частично в совместно используемых библиотеках, обменивается данными с MacOS-программами посредством интерфейса событий, который с момента возникновения является весьма стабильным. Таким образом, конструкция данной операционной системы поддерживает относительно четкое обособление ядра приложения от GUI-интерфейса.
В MacOS также имеется мощная поддержка для изоляции метаданных приложений, таких как структуры меню, от кода ядра. Файлы данной операционной системы имеют как "ветвь данных" (data fork) (блок байтов в Unix-стиле, который содержит документ или программный код), так и "ветвь ресурсов" (resource fork) (набор определяемых пользователем атрибутов файла). Mac-приложения часто проектируются так для того, чтобы (например) используемые в приложениях изображения и звук хранились в ветви ресурса и чтобы их можно было бы модифицировать отдельно от кода приложения.
Система внутренних границ MacOS является очень непрочной. Имеется жесткое предположение о том, что есть только один пользователь, поэтому групп привилегий не существует. Многозадачность определяется как невытесняющая. Все MultiFinder-приложения запускаются в одном адресном пространстве, поэтому некорректный код какого-либо приложения способен разрушить любые данные, находящиеся за пределами низкоуровневого ядра операционной системы. Взломать систему безопасности MacOS-машин весьма просто. Данная операционная система избавлена от вирусных эпидемий главным образом потому, что очень немногие заинтересованы в ее взломе.
Mac-программисты стремятся разрабатывать приложения в противоположном относительно Unix-программирования направлении, т.е. это направление от интерфейса к ядру, а не наоборот (некоторые последствия такого выбора будут рассмотрены в главе 20). Такой подход поощряется всей конструкцией MacOS.
Macintosh задумывалась как клиентская операционная система для нетехнических конечных пользователей, что предполагает очень низкую толерантность относительно сложности интерфейса. Разработчики в Mac-культуре достигли значительных успехов в проектировании простых интерфейсов.
Затраты пользователя, решившего стать разработчиком, при условии наличия компьютера Macintosh никогда не были высокими. Таким образом, несмотря на довольно сложные интерфейсы, в Mac-сообществе очень рано сложилась устойчивая культура энтузиастов. Наблюдается сильная традиция небольших инструментов, условно бесплатных программ и программного обеспечения, поддерживаемого пользователями.
Классическая система MacOS устаревает. Большинство имеющихся в ней средств импортируются в MacOS X, которая объединяет их с Unix-инфраструктурой, вышедшей из традиций университета в Беркли[27]. В то же время лидирующие Unix-системы, например Linux, начинают заимствовать у MacOS такие идеи, как использование атрибутов файлов (обобщение ветви ресурса).
Операционная система OS/2 зародилась как опытный проект компании IBM, называвшийся ADOS (Advanced DOS), один из трех претендентов на роль DOS 4. В то время компании IBM и Microsoft формально сотрудничали при разработке
операционной системы следующего поколения для компьютеров PC. OS/2 версии 1.0 впервые вышла в 1987 году для компьютеров с процессорами 286-й серии, но не имела успеха. Версия 2.0 для процессоров 386 появилась в 1992 году, но к этому времени альянс IBM/Microsoft уже распался. Microsoft с системой Windows 3.0 двигалась в другом (более выгодном) направлении. OS/2 привлекала преданное меньшинство последователей, но так и не смогла привлечь критическую массу разработчиков и пользователей. На рынке настольных систем она оставалась третьей позади Macintosh до тех пор, пока не была отнесена к Java-инициэтиве IBM 1996 года. Последней была версия 4.0 в 1996 году. Ранние версии нашли свое применение во встроенных системах и в момент написания книги (середина 2003 года) продолжают работать во многих машинах автоматизированных справочных служб во всем мире.
Подобно Unix, OS/2 была создана с поддержкой вытесняющей многозадачности и не работала бы без блока MMU (ранние версии имитировали MMU с помощью сегментации памяти в 286 процессорах). В отличие от Unix, OS/2 никогда не создавалась для работы в качестве многопользовательской системы. Создание дочерних процессов было относительно недорогим, но межпроцессное взаимодействие было сложным и ненадежным. Поддержка сети первоначально сводилась к LAN-протоколам, однако в более поздних версиях был добавлен набор протоколов TCP/IP. В OS/2 не было программ, аналогичных системным службам Unix, поэтому данная система никогда не обеспечивала многофункциональную поддержку сети.
В данной операционной системе были как CLI-, так и GUI-интерфейс. Большинство положительных отзывов, касающихся OS/2, относились к ее рабочему столу, Workplace Shell (WPS). Часть этой технологии была лицензирована у разработчиков AmigaOS Workbench, революционного графического интерфейса настольных систем, который до 2003 года имел верных почитателей в Европе[28]. Это одна из областей дизайна, где OS/2 приобрела такой потенциал, которого Unix, вероятно, еще не достигла. Оболочка WPS представляла собой четкую, мощную, объектно-ориентированную конструкцию с ясным режимом работы и хорошей расширяемостью. По прошествии нескольких лет она станет исходной моделью для Linux-проекта GNOME.
Конструкция WPS с иерархией классов была одной из унифицирующих идей операционной системы OS/2. Другой идеей была мультипроцессная обработка. OS/2-программисты использовали организацию параллельной обработки в большой степени как частичную замену IPC между равноправными процессами. Традиции создания взаимодействующих инструментов не развивались.
OS/2 имела внутренние границы, которые можно было бы ожидать в однопользовательской операционной системе. Работающие процессы были защищены друг от друга, пространство ядра было защищено от пользовательского пространства, но пользовательских групп привилегий не было. Это означало, что файловая система не была защищена от злонамеренного кода. Другим следствием было отсутствие аналога каталога "/home"; данные приложений были разбросаны по всей системе.
Еще одним следствием недостатка многопользовательских возможностей было то, что в пользовательском пространстве не могло быть осуществлено разграничение привилегий. Таким образом, разработчики были склонны доверять только коду ядра. Многие системные задачи, которые в Unix обрабатывались бы демонами пользовательского пространства, были нагромождены в ядре или WPS-оболочке, в результате чего обе эти подсистемы сильно разрастались.
OS/2 имела текстовый, а не двоичный режим (т.е. режим, в котором последовательность CR/LF читалась как один символ конца строки, в сравнении с режимом, в котором подобная интерпретация не осуществлялась), но другой структуры записи файлов не было. Описываемая система поддерживала атрибуты файлов, которые использовались для сохранения постоянства рабочего стола подобно Macintosh. Системные базы данных хранились главным образом в двоичных форматах.
Предпочтительным стилем пользовательского интерфейса постоянно оставалась оболочка WPS. Пользовательские интерфейсы часто были более эргономичными, чем в Windows, хотя и не достигали стандартов Macintosh (период наиболее активного применения OS/2 наблюдался относительно раньше). Подобно Unix и Windows, пользовательский интерфейс OS/2 был организован вокруг множества независимых групп окон для различных задач, вместо захвата рабочего стола действующим приложением.
Целевой аудиторией OS/2 были предприятия и нетехнические пользователи, в связи с чем предполагалась низкая толерантность относительно сложности интерфейса. Данная система использовалась как в качестве клиентской, так и в качестве файлового сервера и сервера печати.
В начале 90-х годов разработчики сообщества OS/2 начали переходить к Unix-подобной среде, эмулирующей POSIX-интерфейсы, которая называлась ЕМХ. Перенесенное с Unix программное обеспечение начало регулярно появляться в OS/2 во второй половине 90-х годов прошлого века.
Система ЕМХ была доступна для загрузки без ограничений и включала в себя коллекцию GNU-компиляторов и другие средства разработки с открытым исходным кодом. Компания IBM периодически предоставляла копии системной документации по инструментарию OS/2-разработчика, которая была доступна на многих BBS-системах и FTP-серверах. Вследствие этого размер FTP-архива, разработанного пользователями программного обеспечения для OS/2 ("Hobbes"), к 1995 году превысил гигабайт. Жизнеспособная традиция небольших инструментов, исследовательского программирования и условно бесплатных программ развивалась и привлекала верных последователей в течение нескольких лет после того, как OS/2 была отправлена на свалку истории.
После выхода операционной системы Windows 95, сообщество OS/2, находясь под влиянием окружения Microsoft и будучи поддерживаемым IBM, стало все более интересоваться языком Java. После того как в начале 1998 года был опубликован исходный код браузера Netscape, направление миграции изменилось (достаточно неожиданно) в сторону Linux.
OS/2 представляет интерес как учебный пример того, как далеко может продвинуться конструкция многозадачной, но однопользовательской операционной системы. Большинство наблюдений в этом учебном примере применимы к другим операционным системам того же общего типа, в особенности AmigaOS[29], и GEM[30]. Очень многие материалы по OS/2, включая несколько хороших архивов, в 2003 году все еще оставались доступными в Web[31].
Windows NT (New Technology) — операционная система корпорации Microsoft для использования на мощных персональных компьютерах и серверах. Она поставляется в нескольких вариантах, которые в контексте данного обзора могут рассматриваться как одно целое. Все операционные системы Microsoft с момента упадка Windows ME в 2000 году основываются на технологии Windows NT. Windows 2000 была NT версии 5, a Windows XP (текущая версия в 2003 году) — NT 5.1. Windows NT генетически произошла от операционной системы VMS, с которой она имеет несколько общих важных характеристик.
Windows NT выросла путем приращений, а поэтому испытывает недостаток унифицирующей метафоры, соответствующей идее Unix о том, что "каждый объект является файлом", или идее рабочего стола в MacOS[32]. Поскольку основные технологии не связаны в небольшом наборе устойчивых центральных метафор, они устаревают каждые несколько лет. Каждое из поколений технологии — DOS (1981), Windows 3.1 (1992), Windows 95 (1995), Windows NT 4 (1996), Windows 2000 (2000), Windows XP (2002) и Windows Server 2003 (2003) — требует, чтобы разработчики по-новому повторно изучали фундаментальные принципы, при этом прежний путь объявляется устаревшим и более не поддерживается на достаточном уровне.
Имеются также другие последствия такого подхода.
• Средства GUI неудобно соседствуют со слабым, отжившим интерфейсом командной строки, унаследованным от DOS и VMS.
• Программирование сокетов не имеет унифицирующего объекта данных, аналогичного Unix-идее "каждый объект является файлом", поэтому мультипрограммирование (multiprogramming) и сетевые приложения, являющиеся простыми в Unix, предполагают наличие нескольких более фундаментальных концепций в Windows NT.
Windows NT имеет атрибуты файлов в некоторых типах ее файловых систем. Они используются ограниченным способом для реализации списков доступа в некоторых файловых системах и не очень сильно влияют на стиль разработки. Кроме того, данная система характеризуется тем, что запись текстовых и двоичных файлов осуществляется по-разному, и это приводит к определенным неудобствам (как NT, так и OS/2 унаследовали этот симптом от DOS).
Хотя в системе поддерживается вытесняющая многозадачность, создание дочерних процессов является затратным, правда, не таким, как в VMS, но (на уровне 0,1 с на создание подпроцесса) почти на порядок более затратными, чем в современных Unix-системах. Средства создания сценариев слабые, и операционная система вынуждает широко использовать двоичные форматы. В дополнение к ожидаемым последствиям, которые были рассмотрены выше, рассмотрим ряд менее очевидных.
• Большинство программ вообще невозможно связать в сценарий. Для взаимодействия друг с другом программы опираются на сложные, неустойчивые методы удаленного вызова процедур (Remote Procedure Call — RPC), которые являются причиной многочисленных ошибок.
• Общих инструментов вообще не существует. Документы и базы данных невозможно читать или редактировать без специализированных программ.
• С течением времени CLI-интерфейс все более игнорируется, поскольку все реже используется в среде. Проблемы, связанные со слабым CLI-интерфейсом, скорее усугубляются, нежели решаются. (Отчасти в Windows Server 2003 предпринята попытка изменить данную тенденцию.)
Системные и конфигурационные данные пользователей централизованы в главном системном реестре, а не разбросаны во многих скрытых пользовательских файлах конфигурации и системных файлах данных, как в Unix. Это также имеет несколько последствий для всей конструкции.
• Реестр делает систему полностью неортогональной. Одиночные сбои в приложениях могут повредить данные реестра, часто делая невозможным использование всей системы и вызывая необходимость переустановки.
• Феномен сползания реестра (registry creep): по мере роста реестра увеличивающиеся затраты на доступ замедляют работу всех программ.
NT-системы в Internet печально известны своей уязвимостью для "червей", вирусов, повреждениями и взломами всех видов. Для этого имеется множество причин, некоторые из них более существенные, чем другие. Наиболее фундаментальной причиной является то, что внутренние границы в NT являются чрезвычайно проницаемыми.
В Windows NT предусмотрены списки управления доступом, с помощью которых возможна реализация групп привилегий пользователей, но большое количество унаследованного кода игнорирует их, а операционная система допускает это для того, чтобы не повредить обратной совместимости. Отсутствуют средства управления безопасностью сообщений между GUI-клиентами[33], а их добавление также нарушило бы обратную совместимость.
Несмотря на то, что в NT используется MMU, в версиях данной системы после 3.5, исходя из соображений производительности, графический интерфейс системы встроен в то же адресное пространство, что и привилегированное ядро. Последние версии содержат в пространстве ядра даже Web-сервер в попытке достичь скорости, присущей Web-серверам на основе Unix.
Подобные бреши во внутренних границах производят синергетический эффект, делая действительную безопасность NT-систем фактически невозможной[34]. Если нарушитель может запустить код как практически любой пользователь (например, используя способность программы Outlook обрабатывать почтовые макросы), то данный код может фальсифицировать сообщения через систему окон к любому другому запущенному приложению. Любое переполнение буфера или взлом в GUI-интерфейсе или Web-сервере также может быть использован для захвата контроля над всей системой.
Поскольку Windows должным образом не управляет контролем версий программных библиотек, данная система страдает от хронической конфигурационной проблемы, которая называется "DLL hell" (ад DLL). Данная проблема связана с тем, что при установке новых программ возможно случайное обновление (или напротив, запись более старых версий поверх новых) библиотек, от которых зависят существующие программы. Это относится как к системным библиотекам, поставляемым производителем, так и к библиотекам приложений: нередко приложения поставляются с определенными версиями системных библиотек, и в случае их отсутствия аварийно завершают работу[35].
К важнейшим свойствам Windows NT можно отнести предоставление данной системой достаточных средств для поддержки технологии Cygwin, которая представляет собой уровень совместимости, реализующий Unix как на уровне утилит, так и на уровне API-интерфейсов, с необыкновенно малым количеством компромиссов[36]. Cygwin позволяет C-программам использовать как Unix, так и Windows API-интерфейсы, а поэтому пользуется чрезвычайной популярностью у Unix-хакеров, вынужденных работать на Windows-системах.
Целевой аудиторией операционных систем Windows NT главным образом являются нетехнические конечные пользователи, которые характеризуются низкой толерантностью относительно сложности интерфейса. Windows NT используется как в роли клиентской, так и в роли серверной системы.
В начале своей истории корпорация Microsoft зависела от сторонних разработчиков, поставляющих приложения. Первоначально Microsoft публиковала полную документацию на Windows API и сохраняла невысокий уровень цен на средства разработки. Однако со временем и по мере исчезновения конкурентов, стратегия Microsoft сместилась в сторону поддержки собственных разработок, компания стала скрывать API-функции от внешнего мира, а средства разработки стали более дорогими. С выходом Windows 95 Microsoft стала требовать неразглашения соглашений в качестве условия приобретения профессиональных средств разработки.
Культура разработчиков-любителей и энтузиастов, которая выросла вокруг DOS и ранних версий Windows, была достаточно распространенной, чтобы оставаться самодостаточной вопреки нарастающим усилиям Microsoft, которая пыталась блокировать разработчиков (включая такие меры, как сертификационные программы, разработанные для того, чтобы объявить любителей вне закона). Условно бесплатные программы не исчезали, и политика Microsoft после 2000 года начала отчасти разворачиваться в обратном направлении под давлением рынка операционных систем с открытыми исходными кодами и языка Java. Однако Windows-интерфейсы для "профессионального" программирования с годами становились все более сложными, представляя увеличивающиеся барьеры для любительского (или серьезного) программирования.
В результате произошло предельно четкое разделение стилей разработки практикуемых любителями и профессиональными NT-разработчиками. Две эти группы только общаются. Тогда как любительская культура небольших инструментов и условно бесплатных программ весьма жива, профессиональные NT-проекты склонны к созданию огромных монолитов, даже более громоздких, чем программы, характерные для "элитных" операционных систем, наподобие VMS.
Unix-подобные средства оболочки, наборы команд и библиотечные API-интерфейсы доступны в Windows посредством библиотек сторонних разработчиков, включая UWIN, Interix и библиотеку с открытым исходным кодом Cygwin.
Компания Be Inc. была основана в 1989 году как производитель аппаратного обеспечения в виде передовых многопроцессорных машин на основе микросхем PowerPC. Операционная система BeOS была попыткой компании Be повысить стоимость аппаратного обеспечения путем создания новой, сетевой модели операционной системы, учитывающей уроки Unix и MacOS, но не являющейся подобием одной из них. В результате появилась изящная, ясная и интересная конструкция с превосходной производительностью в предопределенной для нее роли мультимедийной платформы.
Унифицирующими идеями данной BeOS были "заполняющая параллельная обработка" (pervasive threading), мультимедийные потоки и файловая система, выполненная в виде базы данных. BeOS была спроектирована для минимизации задержек в ядре, что делало его применимым для обработки в реальном времени больших объемов таких данных, как аудио- и видео-потоки. "Пареллельные процессы" (threads) BeOS по существу были легковесными процессами в терминологии Unix, так как они поддерживали локальную память процесса и, следовательно, не обязательно совместно использовали все адресное пространство. Межпроцессный обмен данными посредством совместно используемой памяти был быстрым и эффективным.
BeOS придерживалась модели Unix в том, что не имела файловой структуры выше байтового уровня. Подобно MacOS, операционная система BeOS поддерживала и использовала атрибуты файлов. По сути, файловая система BeOS была базой данных с возможностью индексации по любому атрибуту.
Одним из элементов, заимствованных BeOS у Unix, была логичная конструкция внутренних границ. В описываемой системе полностью использовался блок MMU, и работающие процессы были надежно изолированы друг от друга. Несмотря на то, что BeOS представлялась как однопользовательская операционная система (без необходимости регистрации в системе), в ее файловой системе и во всем внутреннем устройстве поддерживались Unix-подобные группы привилегий. Они использовались для защиты важнейших системных файлов от воздействия ненадежного кода. В терминологии Unix пользователь во время загрузки регистрировался в системе как анонимный гость, а другим единственным "пользователем" был root. Полная многопользовательская функциональность потребовала бы небольших изменений в верхних уровнях системы и по сути была представлена утилитой BeLogin.
BeOS более стремилась к использованию двоичных форматов файлов и собственной базе данных, встроенной в файловую систему, чем к Unix-подобным текстовым форматам.
Предпочтительным стилем пользовательского интерфейса был GUI и он весьма склонялся к опыту MacOS в области дизайна интерфейсов. Вместе с тем также полностью поддерживались CLI-интерфейс и сценарии. Оболочкой командной строки была перенесенная с Unix программа bash(1), доминирующая Unix-оболочка с открытым исходным кодом, работающая посредством библиотеки совместимости POSIX. Благодаря такой конструкции, преобразование программного обеспечения Unix CLI было очень простым. В системе присутствовала инфраструктура для поддержки всего разнообразия сценариев, фильтров и служебных демонов, сопутствующих Unix-модели.
BeOS была предназначена для работы в качестве клиентской операционной системы, специализирующейся на обработке мультимедийных данных (особенно обработке звука и видео) почти в реальном времени. Целевая аудитория данной системы включала в себя технических и деловых конечных пользователей, предполагающих умеренную толерантность к сложности интерфейса.
Препятствия на пути к разработке BeOS-приложений были небольшими. Несмотря на то, что операционная система была частной, средства разработки были недорогими, и доступ к полной документации не представлял сложности. Проект BeOS начался как часть усилий по освобождению от аппаратного обеспечения Intel с RISC-технологией, и после взрывного роста Internet продолжался исключительно как программный проект. Его стратеги изучили опыт периода формирования Linux в начале 90-х годов и были полностью осведомлены о значении крупной базы любительской разработки. Фактически они преуспели в привлечении верных последователей; в 2003 году не менее пяти отдельных проектов пытались возродить операционную систему BeOS в открытом исходном коде.
К сожалению, в отличие от технического дизайна, окружавшая BeOS бизнес- стратегия была не столь мудрой. Программное обеспечение BeOS первоначально было привязано к специализированному аппаратному обеспечению и продавалось только с неопределенными указаниями о целевых приложениях. Позднее (в 1998 году) операционная система BeOS была перенесена на общее аппаратное обеспечение PC, а мультимедийным приложениям было уделено более пристальное внимание, но система так и не привлекла критическую массу приложений или пользователей. Наконец, в 2001 году BeOS уступила комбинации антиконкурентного маневрирования Microsoft (судебный процесс продолжался в 2003 году) и конкуренции со стороны вариантов операционной системы Linux, адаптированных для обработки мультимедиа.
MVS (Multiple Virtual Storage) — ведущая операционная система IBM для мэйнфреймов корпорации. Ее происхождение связывают с OS/360, операционной системой IBM, появившейся в середине 60-х годов прошлого века. IBM планировала, что данная система будет использоваться клиентами на новых в то время компьютерных системах System/360. Потомки этого кода остаются основой сегодняшних операционных систем для мэйнфреймов IBM. Хотя код был почти полностью переписан, основная конструкция осталась почти совершенно нетронутой. Обратная совместимость поддерживается настолько тщательно, что приложения, написанные для OS/360, работают без модификаций в MVS для 64-битовых мэйнфреймов z/Series, появившихся на 3 архитектурных поколения позже.
Из всех рассматриваемых здесь операционных систем только MVS может считаться более старшей, чем Unix. Данная система также менее остальных подверглась влиянию идеи и технологии Unix и представляет надежнейшую конструкцию, противоположную последней. Унифицирующей идеей MVS является то, что вся работа формируется в виде пакета. Система разработана для наиболее эффективного использования машины для пакетной обработки больших объемов данных с минимальной необходимостью взаимодействия с пользователями.
Собственные MVS-терминалы (серии 3270) функционируют только в режиме блокировки. Пользователю предоставлен экран, который он заполняет, модифицируя локальную память терминала. Прерывание не происходит до тех пор, пока пользователь не нажмет клавишу отправки. Взаимодействие с помощью командной строки, подобное Unix-режиму непосредственного ввода данных с клавиатуры, невозможно.
Оснастка TSO, ближайший эквивалент интерактивной среды Unix, ограничена в собственных возможностях. Каждый пользователь TSO представлен остальной системе в виде условного пакетного задания. Данное средство является настолько дорогим, что круг его пользователей обычно ограничен программистами и обслуживающим персоналом. Обычно пользователи, которым необходимо только запускать приложения из терминала, почти никогда не используют TSO. Вместо этого они работают через мониторы транзакций, которые являются одним из видов многопользовательского сервера приложений, поддерживающего невытесняющую многозадачность и асинхронный ввод-вывод. В сущности, каждый вид монитора транзакций представляет собой специализированный дополнительный модуль разделения времени (отчасти подобный Web-серверу, выполняющему CGI-программу).
Другое следствие архитектуры, ориентированной на пакетную обработку, заключается в том, что создание подпроцессов является медленной операцией. В данной системе намеренно большая пропускная способность достигается ценой дорогостоящей установки (и связанной с этим задержки). Подобный подход хорошо соответствует пакетным операциям, но плохо сказывается на интерактивном отклике. Предсказуемым результатом является то, что сегодняшние пользователи TSO почти все время проводят в диалоговой интерактивной среде, ISPF. В редких случаях программисты делают что-либо внутри собственной среды TSO за исключением запуска экземпляра ISPF. Это устраняет издержки создания дочерних процессов ценой введения очень большой программы, которая выполняет все, кроме включения кофеварки.
Операционная система MVS использует аппаратный блок MMU. Процессы выполняются в отдельных адресных пространствах. Межпроцессный обмен данными осуществляется через совместно используемую память. В системе имеются средства для организации параллельной обработки (которая в MVS называется "созданием подзадач" (subtasking)), однако они используются незначительно, главным образом ввиду того, что данное средство легко доступно только из программ, написанных на ассемблере. Вместо этого типичное пакетное приложение представляет собой короткие серии вызовов тяжеловесных программ, связанных вместе с помощью JCL (Job Control Language — язык управления заданиями), обеспечивающим создание сценариев трудоемким и негибким способом. Программы в задании сообщаются посредством временных файлов. Фильтры и подобные им средства почти невозможно реализовать удобным способом.
Каждый файл имеет формат записи. Иногда формат подразумевается (например, предполагается, что встроенные в JCL файлы ввода имеют формат записи фиксированной длины (80 байт), унаследованный от перфокарт), но чаще он указывается в явном виде. Многие файлы системной конфигурации имеют текстовый формат, но файлы приложений обычно записываются в двоичных форматах, специфичных для определенного приложения. Некоторые общие инструменты для просмотра файлов развились из абсолютной необходимости, но до сих пор не являются простой для разрешения проблемой.
Безопасность файловой системы была поздним дополнением к первоначальной конструкции. Однако когда выяснилось, что безопасность необходима, IBM добавила соответствующие функции оригинальным способом: разработчики определили общий API-интерфейс функций безопасности, а затем все запросы на доступ к файлам перед обработкой направили через данный интерфейс. В результате существует по крайней мере три конкурирующих пакета обеспечения безопасности с различной философией дизайна, и все они весьма хороши, учитывая то, что известных взломов между 1980 и 2003 годами не было. Это многообразие позволяет при инсталляции выбрать пакет, который наилучшим образом подходит для локальной политики безопасности.
Сетевые средства также были добавлены с опозданием. В описываемой системе отсутствует понятие одного интерфейса для сетевых соединений и локальных файлов. Их программные интерфейсы разделены и полностью различны. Это действительно позволило набору протоколов TCP/IP достаточно безболезненно вытеснить собственную модель сети IBM — SNA (Systems Network Architecture — системная сетевая архитектура), которая считалась предпочтительным сетевым протоколом. В 2003 году все еще можно было увидеть использование обеих архитектур в определенной инсталляции, однако SNA все же отмирает.
Любительское программирование для MVS почти отсутствует. И существует только внутри сообщества крупных предприятий, использующих данную операционную систему. Это связано не столько с затратами на сами инструменты, сколько со стоимостью среды. Когда предприятие вынуждено израсходовать несколько миллионов долларов на компьютерную систему, несколько сотен долларов, потраченных в месяц на компилятор, считаются почти мелкими расходами. Однако внутри данного сообщества существует процветающая культура свободно доступного программного обеспечения, главным образом средств программирования и системного администрирования. Первая группа компьютерных пользователей SHARE была основана пользователями IBM в 1955 году, и с тех пор устойчиво развивается.
При рассмотрении значительных архитектурных различий примечательным является тот факт, что MVS была первой операционной системой, имеющей стиль, отличный от System V, т.е. соответствовала единому стандарту Unix (это не столь заметно, чем то, что перенесенные Unix-программы имеют сильную склонность к нестабильной работе с проблемами символьного набора ASCII-EBCDIC). Запустить оболочку Unix из TSO вполне возможно; файловые системы Unix являются специально отформатированными группами данных MVS. Набор символов MVS Unix является специальной кодовой страницей EBCDIC с замененными символами новой строки и перевода строки. То, что в Unix представлено как перевод строки, в MVS выглядит как новая строка. Однако системные вызовы являются действительно системными вызовами, реализованными в ядре MVS.
Поскольку стоимость среды резко снижается, уже определилась небольшая, но растущая группа пользователей последней свободно распространяемой версии MVS (3.8, датированной 1979 годом). Эта система, как и все средства разработки, а также эмулятор для их запуска, доступны по цене компакт-диска[37].
MVS всегда предназначалась для работы в сопровождении. Как VMS и сама Unix, операционная система MVS предшествовала разделению клиент/сервер. Сложность интерфейса для пользователей сопровождения не только допустима, но и желательна в целях сокращения затрат дорогостоящих ресурсов на интерфейсы, а значит, выделения больших ресурсов для основной работы.
VM/CMS — другой пример операционной системы для мэйнфреймов. Ее вполне можно назвать "родственницей" системы Unix: их общим предком является система CTSS, созданная в Массачусетском технологическом институте приблизительно в 1963 году и работавшая на мэйнфрейме IBM 7094. Группа, разработавшая CTSS, позднее приступила к написанию Multics, прямого предка Unix. IBM учредила в Кембридже группу по созданию системы разделения времени для IBM 360/40, модифицированного компьютера 360-й серии со страничным (впервые для систем IBM) диспетчером MMU[38]. Программисты MIT и IBM впоследствии в течение многих лет продолжали взаимодействовать. Новая система приобрела пользовательский интерфейс, очень сходный с CTSS, укомплектованный оболочкой, которая называлась EXEC, а также большим запасом утилит аналогичных используемым в Multics и позднее в Unix.
В другом смысле VM/CMS и Unix являлись видоизмененными "отражениями" друг друга. Унифицирующая идея системы, обеспеченная компонентом VM, воплощена в виртуальных машинах, которые выглядят как физические машины. Они поддерживают вытесняющую многозадачность и работают либо с однопользовательской операционной системой CMS, либо с полностью многозадачной операционной системой (обычно MVS, Linux или другой экземпляр самой VM). Виртуальные машины соответствуют Unix-процессам, демонам и эмуляторам, а обмен данными между ними осуществляется путем соединения виртуального карточного перфоратора одной машины с виртуальным считывателем перфокарт другой машины. В дополнение к этому, внутри системы обеспечивается многоуровневая инструментальная среда, которая называется CMS Pipelines (конвейеры CMS), непосредственно смоделированная с каналов Unix, но архитектурно расширенная для поддержки множества вводов и выводов.
В ситуации, когда обмен данными между виртуальными машинами явно не установлен, они полностью изолированы друг от друга. Данная операционная система характеризуется тем же высоким уровнем надежности, расширяемости и безопасности, что и MVS, а также имеет гораздо большую гибкость и проще в использовании. В дополнение к этому, VM-компонент, который обслуживается полностью обособленно, вовсе не обязательно должен доверять частям CMS, подобным ядру.
Несмотря на то, что CMS является операционной системой, ориентированной на структуры записи, эти записи, в сущности, эквивалентны строкам, используемым текстовыми инструментами в Unix. Базы данных значительно полнее интегрированы в CMS Pipelines, чем обычно в Unix, где большинство баз данных полностью отделены от операционной системы. В последние годы операционная система CMS была дополнена для полной поддержки единого стандарта Unix.
Стиль пользовательского интерфейса в CMS является интерактивным и диалоговым, весьма отличающимся от MVS, но похожим на пользовательские интерфейсы VMS и Unix. Интенсивно используется полноэкранный редактор XEDIT.
VM/CMS предшествовала разделению клиент/сервер и в настоящее время используется почти полностью как серверная операционная система с эмуляцией IBM-терминалов. До того как Windows стала полностью доминировать на рынке настольных систем, VM/CMS предоставляла службы обработки текстов и электронную почту как внутри IBM, так и между участками пользователей мэйнфреймов. Действительно, многие VM-системы были инсталлированы исключительно для запуска таких приложений благодаря доступной расширяемости VM (десятки тысяч пользователей).
Язык сценариев REXX поддерживает программирование в стиле, не отличающемся от shell, awk, Perl или Python. Следовательно, любительское программирование (особенно системными администраторами) является весьма важным в системе VM/CMS. Администраторы, располагающие недорогими ресурсами, часто предпочитают запускать действующую MVS в виртуальной машине, а не непосредственно на физической машине, для того чтобы CMS также была доступна и можно было использовать преимущества ее гибкости. (Существует ряд CMS-инструментов, предоставляющих доступ к файловым системам MVS.)
Прослеживаются поразительные параллели между историей VM/CMS внутри корпорации IBM и Unix внутри Digital Equipment Corporation (которая создавала компьютеры, где впервые работала Unix). Компании IBM потребовались годы, чтобы осознать стратегическую важность ее неофициальной системы разделения времени, в течение этого периода появилось сообщество программистов VM/CMS, поведение которого было весьма сходно с поведением раннего Unix-сообщества. Они обменивались идеями, открытиями в исследовании систем, а главное — обменивались исходным кодом для утилит. Независимо от того, как часто IBM пыталась объявлять о смерти системы VM/CMS, сообщество, которое включало в себя собственно разработчиков системы MVS в IBM, настаивало на поддержании ее в рабочем состоянии. Операционная система VM/CMS прошла тот же путь от открытого исходного кода (де-факто) к закрытому и обратно, хотя этот процесс и не был столь явно выраженным, как в Unix.
Однако системе VM/CMS не хватает какого-либо реального аналога для языка С. Как VM, так и CMS были написаны на ассемблере и остаются такими и поныне. Единственным эквивалентом С были различные сокращенные версии языка PL/I, который использовался в IBM для системного программирования, однако клиентам компании не предоставлялся. Таким образом, данная система остается в ловушке ее собственной архитектурной линии, хотя она выросла и расширилась по мерее того, как архитектура 360 перерастала в серию 370, серию XA и наконец в современную серию z/Series.
С 2000 года IBM очень активно продвигает операционную систему VM/CMS на мэйнфреймах как способ одновременной поддержки тысяч виртуальных Linux-машин.
Операционная система Linux, созданная Линусом Торвальдсом в 1991 году, лидирует среди Unix-систем новой школы с открытым исходным кодом, появившихся в 1990 году (в их число также входит FreeBSD, NetBSD, OpenBSD и Darwin), и представляет направление конструирования, принятое данной группой в целом. Тенденции Linux могут быть приняты как типичные для всей группы.
Linux не включает в себя код из дерева исходных кодов первоначальной Unix, но данная система была сконструирована на основе Unix-стандартов и работает подобно Unix. В остальной части данной книги неоднократно подчеркивается преемственность между Unix и Linux. Эта преемственность чрезвычайно сильна, как в аспекте технологии, так и в отношении главных разработчиков, однако здесь подчеркиваются и некоторые направления Linux, которые демонстрируют отклонение от "классических" традиций Unix.
Многие разработчики и активисты Linux-сообщества стремятся к тому, чтобы данная операционная система заняла прочные позиции на рабочих столах конечных пользователей. Это делает целевую аудиторию Linux несколько шире, чем в случае какой- либо из Unix-систем старой школы, которые в основном были нацелены на рынки серверов и рабочих станций технических пользователей. Данное обстоятельство, конечно же, влияет на способ разработки программного обеспечения Linux-хакерами.
Наиболее очевидным новшеством является смена предпочтительных стилей интерфейса. Unix первоначально была разработана для использования на телетайпах и медленных печатающих терминалах. На протяжении большей части своей истории она была жестко связана с символьными видеотерминалами с недостатком либо графических возможностей, либо возможностей передачи цвета. Большинство Unix-программистов долго оставались прочно привязанными к командной строке, после того как большое количество пользовательских приложений перешло на графические GUI-интерфейсы в X Window, и конструкция как операционных систем Unix, так и приложений для них все еще отражает данный факт.
С другой стороны, пользователи и разработчики Linux привыкли учитывать характерную для нетехнических пользователей боязнь командной строки. Они перешли к созданию GUI-интерфейсов и GUI-средств гораздо более интенсивно, чем это было в случае с Unix старой школы, или даже в случае современных частных Unix-систем. В меньшей, но все же значительной степени это справедливо и для других Unix-систем с открытым исходным кодом.
Желание склонить на свою сторону конечных пользователей также заставило Linux-разработчиков гораздо больше интересоваться проблемами простоты инсталляции и распространения программного обеспечения, чем это принято при разработке частных Unix-систем. В результате в Linux появились более развитые системы бинарных пакетов, чем какие-либо аналоги в частных Unix-системах. Данные системы имеют интерфейсы, спроектированные (в 2003 году) в более приемлемой для нетехнических пользователей манере.
Linux-сообщество стремится (более чем когда-либо) превратить свое программное обеспечение в некий универсальный канал связи между различными средами. Поэтому Linux предоставляет поддержку чтения и (нередко) записи форматов файловых систем и методов сетевого взаимодействия, характерных для других операционных систем. Linux также поддерживает возможность выбора операционной системы при начальной загрузке на одном и том же аппаратном обеспечении (мультизагрузку), а также программную эмуляцию данных систем внутри самой себя. Долгосрочной целью является поглощение; Linux эмулирует другие системы, а значит, может абсорбировать их[39].
В целях поглощения конкурентов и привлечения конечных пользователей Linux-разработчики перенимают конструкторские идеи из операционных систем, не относящихся к семейству Unix. Это настолько распространено, что традиционные Unix-системы выглядят довольно ограниченными. Примером могут послужить Linux-приложения, использующие для конфигурации .INI-файлы формата Windows; данная тема рассматривается в главе 10. Внедрение в ядро 2.5 Linux расширенных атрибутов файлов, которые среди прочего можно использовать для эмуляции семантики ветви ресурса в Macintosh, — наиболее яркий пример на момент написания данной книги.
В тот день, когда Linux выдаст Mac-сообщение о невозможности открыть файл ввиду отсутствия соответствующего приложения, Linux перестанет быть Unix.
Остальные частные Unix-системы (такие как Solaris, HP-UX, AIX и другие) разрабатываются как большие продукты для больших IT-бюджетов. Их рыночная ниша поддерживает конструкции, оптимизированные под максимальную мощность на высококлассном, инновационном аппаратном обеспечении. Поскольку частично Linux связана со средой энтузиастов PC, особое значение в данной системе уделяется выполнению большего количества задач при меньших затратах. Частные Unix-системы настраиваются на многопроцессорные и кластерные операции на низкопроизводительном, маломощном аппаратном обеспечении. А основные разработчики Linux-систем открыто выбрали неприятие большей сложности и затрат на малопроизводительных машинах ради незначительного прироста производительности высококлассной аппаратуры.
Несомненно, значительная часть сообщества пользователей Linux понимает, что перед нами стоит задача извлечь максимальную пользу из аппаратуры, настолько же технически устаревшей сегодня, насколько в 1969 году устаревшим был компьютер Кена Томпсона PDP-7. Как следствие, Linux-разработчики вынуждены оставлять приложения скудными и неприятными, с чем их коллеги в частных Unix-системах не сталкиваются.
Эти тенденции, конечно же, скажутся на будущем Unix в целом. Данная тема рассматривается в главе 20.
В данной главе для сравнения были выбраны системы разделения времени, которые либо в настоящее время, либо в прошлом составляли конкуренцию Unix. Достойных кандидатов не много. Большинство подобных систем (Multics, ITS, DTSS, TOPS-10, TOPS-20, MTS, GCOS, MPE и, возможно, десяток других) исчезли так давно, что почти стерлись из коллективной памяти компьютерной отрасли. Отмирают системы VMS и OS/2, MacOS поглощается Unix-производными. Операционные системы MVS и VM/CMS были ограничены одной частной линейкой мэйнфреймов. Только Microsoft Windows остается жизнеспособным конкурентом, независимым от традиций Unix.
Преимущества Unix рассматривались в главе 1, и они, несомненно, составляют некоторую часть объяснения. Однако, считаем, более полезным будет обсуждение другого очень важного аспекта данной проблемы: какие недостатки конкурентов Unix оставили их в проигрыше?
Наиболее очевидной общей проблемой является неспособность к переносу на другие платформы. Большинство конкурентов Unix, появившихся до 1980 года, были привязаны к какой-либо одной аппаратной платформе и исчезли вместе с ней. Единственной причиной того, что VMS просуществовала достаточно долго для того, чтобы рассматриваться здесь в качестве учебного примера, является то, что она была успешно перенесена с ее первоначального аппаратного обеспечения VAX на процессор Alpha (а в 2003 году переносился с Alpha на Itanium). MacOS была успешно перенесена с микросхем Motorola 68000 на PowerPC в конце 80-х годов прошлого века. Операционная система Microsoft Windows избежала данной проблемы, оказавшись в нужном месте, когда стремление превратить программное обеспечение в продукт массового потребления привело к заполнению рынка универсальными компьютерами монокультуры PC.
С 1980 года все более проявляется другой недостаток, характерный для различных операционных систем, которые либо были уничтожены Unix, либо просуществовали менее продолжительный период времени: неспособность обеспечить изящную поддержку сети.
В мире распространяющихся сетей даже операционная система, спроектированная для однопользовательской работы, нуждается в многопользовательских средствах (множество групп привилегий), поскольку без таких средств любая сетевая транзакция, которая способна обманным путем вынудить пользователя запустить злонамеренный код, может разрушить всю систему (макровирусы в Windows являются только верхушкой этого айсберга). Без мощной многозадачности способность операционной системы одновременно обрабатывать сетевой трафик и выполнять пользовательские программы будет ослаблена. Операционная система также должна обладать эффективным IPC-механизмом, для того чтобы ее сетевые программы могли обмениваться данными друг с другом и другими приоритетными пользовательскими приложениями.
Windows, имея серьезные недостатки в данных областях, избегает упадка только благодаря тому, что она получила монопольное положение еще до того, как сетевое взаимодействие стало действительно важным, а также благодаря множеству пользователей, которые в силу определенных условий вынуждены принимать как должное аварийные отказы и бреши в системе безопасности, количество которых шокирует. Данную ситуацию нельзя назвать стабильной. Сторонники Linux успешно ее использовали (в 2003 году), для того чтобы проникнуть на рынок серверных операционных систем.
Приблизительно в 1980 году во время расцвета персональных компьютеров проектировщики операционных систем отклонили Unix и традиционную технологию разделения времени как тяжеловесную, Громоздкую и несоответствующую новым условиям, определяемым средой однопользовательских персональных машин. Вместе с тем GUI-интерфейсы требовали внедрения многозадачности, для того чтобы справляться с исполняемыми потоками, связанными с различными окнами и их элементами управления. Направленность на клиентские операционные системы была настолько сильной, что серверные операционные системы были отклонены подобно реликтам на паровой тяге из прошлой эпохи.
Но, как отметили разработчики BeOS, требования распространяющихся сетей невозможно удовлетворить без реализации какой-либо технологии, весьма близкой к общецелевому разделению времени. Однопользовательские клиентские операционные системы не способны преуспеть в Internet-мире.
Данная проблема привела к новому объединению клиентских и серверных операционных систем. Первые (до появления Internet) попытки равноправного сетевого взаимодействия через локальные сети в конце 80-х годов начали выявлять неадекватность конструкторской модели клиентских операционных систем. Для совместного использования данных в сети необходимы точки рандеву (rendezvous points) для этих данных. Следовательно, работа без серверов невозможна. В то же время опыт клиентских операционных систем Macintosh и Windows поднял уровень минимальных пользовательских навыков, которой устроил бы потребителей.
С не-Unix моделями разделения времени, фактически исчезнувшими к 1990 году, существовало не много возможных решений, которые проектировщики клиентских операционных систем могли противопоставить данной проблеме. Они могли выделить Unix (как это было в MacOS X), изобрести заново приблизительно эквивалентные функции по частям (как это сделано в Windows), или попытаться заново создать весь мир (как попыталась и не смогла BeOS). Однако тем временем в Unix-системах с открытым исходным кодом росли клиентские возможности по использованию GUI-интерфейсов, а также возможности работы на недорогих персональных машинах.
Данные факторы оказались, однако, не настолько уравновешенными, как это может показаться из приведенного выше описания. Модернизация таких функций серверных операционных систем, как множество классов привилегий и полная многозадачность, в клиентской операционной системе представляется очень трудной задачей, и, весьма вероятно, нарушит совместимость с предыдущими версиями клиента, а также приведет к многочисленным проблемам безопасности. С другой стороны, проблем связанных с внедрением GUI-интерфейса в серверную операционную систему, вполне можно избежать при условии наличия высококвалифицированного персонала и недорогих аппаратных ресурсов. Как и в строительстве, восстановить надстройку на поверхности прочного фундамента проще, чем заменить фундамент без разрушения надстройки.
Кроме наличия собственных архитектурных преимуществ серверной операционной системы, Unix всегда скептически относилась к целевой аудитории. Разработчики и создатели никогда не допускали, что знают все потенциально возможные способы применения системы.
Следовательно, конструкция операционной системы Unix проявила гораздо большие возможности по модернизации в качестве клиента, чем любая из клиентских операционных систем-конкурентов продемонстрировала возможности по модернизации в качестве сервера. Хотя возрождению Unix в 90-х годах прошлого века способствовало и множество других факторов, как технологических, так и экономических, но именно вышеупомянутые возможности выходят на первый план при обсуждении стиля проектирования операционных систем.