Ранее уже упоминалась одна ситуация, при которой два критерия изменяются в противоположных направлениях: пользовательский интерфейс, который разрабатывался в основном для сохранения простоты реализации или небольшого размера кодовой базы, может просто перекладывать низкоуровневые задачи на пользователя. (В качестве грубого примера, едва ли вообразимого Unix-программистом, но слишком распространенного в других средах, можно представить редактор, не имеющий функции глобальной замены.) Хотя такой вид неудачной конструкции является чрезвычайно распространенным, он не имеет традиционного названия. В данной книге он называется
Стремление сохранить небольшой размер кодовой базы с помощью чрезвычайно плотных и сложных методик реализации может вызвать нарастание сложности реализации в системе, ведущее к неразберихе, которую невозможно исправить. Ранее такое часто случалось, когда для того чтобы втиснуть программу в очень малую систему, приходилось программировать на ассемблере или использовать такие нетривиальные технические приемы, как самомодифицирующийся код. В наши дни такая проблема не распространена, кроме случаев со встроенными системами, но и в них она быстро становится редкой. Данный вид неудачной конструкции не имеет традиционного названия, однако эту проблему можно назвать
Ловушка уплотнения не рассматривается в учебных примерах данной книги, она определена для контраста с противоположной ей проблемой. Вполне возможны ситуации, когда разработчики проекта будут настолько осторожны в вопросе сложности реализации, что постараются отказаться от сложного, но единообразного пути для разрешения целого класса проблем в пользу большого количества дублирующегося специального кода, последовательно решающего каждую задачу. В результате такого подхода увеличивается размер кодовой базы и появляются проблемы сопровождения, более сложные, чем в случае использования унифицированного метода. Например, Web-проект, где для наполнения страниц действительно необходима централизованная реляционная база данных, может вместо этого содержать несколько различных индексированных файлов данных, содержащих информацию, которую необходимо интегрировать заново при каждом создании страницы. Данный вид неудачной конструкции является слишком распространенным. Он не имеет традиционного названия, однако его можно назвать
Выше описаны три вида сложности, а также некоторые ловушки, в которые попадают разработчики, пытающиеся избежать сложности[110]. Примеры рассматриваются далее в настоящей главе.
13.1.2. Компромиссы между сложностью интерфейса и реализации
Одно из наиболее ярких замечаний о Unix-традиции, сделанных когда-либо сторонним наблюдателем, содержится в статье Ричарда Гэбриэла (Richard Gabriel), которая называется
В статье утверждалось, что Unix и С обладают характеристиками вирусов и что в эволюционной борьбе конструкций программного обеспечения такие особенности, как простота реализации и переносимость, которые ведут к быстрому распространению (заражаемости), являются более эффективными, чем корректность и завершенность конструкции. Гэбриэл в своем предвидении так близко подошел к влиянию экспертной оценки на программное обеспечение с открытым исходным кодом, что сообщество открытого исходного кода приняло его как одного из своих теоретиков.
Не так часто вспоминается то, что главный аргумент Гэбриэла относился к весьма специфическому компромиссу между сложностью реализации и сложностью интерфейса, который довольно точно вписывается в рассмотренные выше категории. Гэбриэл сопоставляет философию MIT, в которой наиболее ценится простота интерфейса, с философией Нью-Джерси, где выше всего ценится простота реализации. Затем он утверждает, что хотя MIT-философия приводит к появлению программного обеспечения, которое абстрактно лучше, модель Нью-Джерси (худшая) обладает лучшими характеристиками распространения. Со временем люди уделяют больше внимания программному обеспечению, написанному в стиле Нью-Джерси, поэтому оно быстрее улучшается, и худшее становится лучшим.
В действительности, философия MIT и Нью-Джерси имеет аналоги как конфликтующие направления в самой Unix-традиции проектирования. Один тип Unix-мышления придает особое значение небольшим точным инструментам, конструкциям, разработанным с нуля, а также простым и последовательным интерфейсам. Дуг Макилрой решительно отстаивает данную точку зрения. Другой тип мышления акцентирует внимание на простых реализациях, которые работают и быстро распространяются, даже если используются методы грубой силы, а некоторые граничные случаи необходимо устранить. Код Кена Томпсона, а также его принципы программирования часто и очевидно склоняются к этому направлению.
Конфликт между данными подходами возникает именно потому, что иногда программист может получить простой интерфейс, если согласен заплатить за него сложностью реализации, и наоборот. Оригинальный пример Гэбриэла о том, как системные вызовы, выполняющие длительные операции, обрабатывают прерывания, которые не способны удержать или замаскировать, до сих пор остается одним из лучших. В MIT-философии правильный путь заключается в выходе из системного вызова и автоматическом его возобновлении, как только прерывание будет обработано. Данную методику труднее реализовать, однако она ведет к созданию более простого интерфейса. В философии Нью-Джерси системный вызов возвращает ошибку, указывающую на то, что вызов был прерван и пользователь должен перезапустить его. Такой подход значительно проще в реализации, но приводит к программному интерфейсу, который труднее использовать.
На практике применяются оба подхода. Unix-разработчики старой школы немедленно подумают о сравнении System V и BSD-стилей обработки программных сигналов. Последний следует MIT-философии, тогда как System V-стиль происходит из Нью-Джерси. В основе выбора между ними лежит сложный вопрос, который непосредственно не касается распространения программного обеспечения: если цель заключается в ограничении глобальной сложности, что разработчик охотнее всего принесет в жертву? Что ему
Одним эпохальным примером, не упомянутым Гэбриэлом, являются распределенные гипертекстовые системы. Ранние проекты распределенных гипертекстовых систем, такие как NLS и Xanadu, были жестко ограничены предположениями MIT-философии о том, что ссылки, указывающие на несуществующий объект, являются недопустимой неполадкой в пользовательском интерфейсе. Это ограничивало системы либо просмотром только контролируемого, закрытого набора документов (как, например, на одном CD-ROM), либо реализацией различного тиражирования со все возрастающей сложностью, кэширующих и индексирующих методов в попытке предотвратить случайное исчезновение документов. Тим Бернерс-Ли (Tim Berners-Lee) разрубил этот гордиев узел, разрешив проблему в классическом стиле Нью-Джерси. Простота реализации, достигнутая им благодаря разрешению ответа '404: Not Found', была тем, что сделало систему World Wide Web достаточно легковесной, чтобы она могла успешно распространяться.
Сам Гэбриэл придерживался мнения о том, что 'худшее' более заразительно и, в конце концов, стремится к победе. Несмотря на это, он неоднократно публично менял свое мнение относительно основополагающего вопроса, связанного со сложностью: сложность — это хорошо или плохо? Его непостоянство отражает множество продолжающихся споров в Unix-сообществе.
Автору данной книги не представляется возможным сформулировать универсальный ответ. Как и большинство других важнейших вопросов в данной главе, хороший вкус и инженерное мышление предполагают различные ответы в разных ситуациях. Важно развить привычку тщательно обдумывать данную проблему для всех и для каждой разрабатываемой конструкции. Как отмечалось ранее при