Искусство программирования для Unix
Шрифт:
1.6.1. Правило модульности: следует писать простые части, связанные ясными интерфейсами
Как однажды заметил Браян Керниган, "управление сложностью является сущностью компьютерного программирования" [41]. Отладка занимает большую часть времени разработки, и выпуск работающей системы обычно в меньшей степени является результатом талантливого проектирования, и в большей — результатом должного управления, исключающего многократное повторение ошибок.
Трансляторы, компиляторы, блок-схемы, процедурное программирование, структурное программирование, "искусственный
Единственным способом создания сложной программы, не обреченной заранее на провал, является сдерживание ее глобальной сложности, т.е. построение программы из простых частей, соединенных четко определенными интерфейсами, так что большинство проблем являются локальными, и можно рассчитывать на обновление одной из частей без разрушения целого.
1.6.2. Правило ясности: ясность лучше, чем мастерство
Поскольку обслуживание является важным и дорогостоящим, следует писать такие программы, как если бы обмен наиболее важной информацией, осуществляемый программой, был связан не с компьютером, выполняющим данную программу, а с людьми, которые будут читать и поддерживать исходный код в будущем (включая и самого создателя программы).
В традициях Unix смысл данной рекомендации выходит за пределы простого комментирования кода. Хорошая Unix-практика также предполагает выбор алгоритмов и реализации с учетом дальнейшего обслуживания. Незначительный рост производительности ценой большого повышения сложности и запутанности методики относится к плохой практике не только потому, что сложный код, вероятнее всего, скрывает в себе ошибки, но также потому, что такой код будет тяжелее читать будущим кураторам (maintainers) программы.
С другой стороны, тот,.кому впоследствии придется изменять программу, вряд ли будет поставлен в тупик изящным и ясным кодом — более вероятно, что он немедленно в нем разберется. Это особенно важно, если спустя несколько лет следующим куратором, возможно, будет сам создатель программы.
Не пытайтесь трижды расшифровывать хитроумный код. Однажды возможна неповторимая удача, однако, если придется разбираться в коде во второй раз, поскольку впервые он рассматривался слишком давно и детали позабыты, то это означает, что необходимо внести в код комментарии таким образом, чтобы третий раз был относительно безболезненным.
Генри Спенсер
1.6.3. Правило композиции: следует разрабатывать программы, которые будут взаимодействовать с другими программами
Если разрабатываемые программы не способны взаимодействовать друг с другом, то очень трудно избежать создания сложных монолитных программ.
Традиция Unix значительно способствует написанию программ, которые считывают и записывают простые текстовые форматы, ориентированные на потоки и не зависящие от устройств. В классической реализации Unix как можно больше программ создаются в виде простых фильтров (filters),
Вопреки распространенному мифу, такая практика широко распространена не потому, что Unix-программисты ненавидят графические пользовательские интерфейсы. Данная практика пользуется популярностью Unix-программистов, поскольку связывать вместе программы, не принимающие и не создающие на выходе простые текстовые потоки, гораздо труднее.
Текстовые потоки для Unix-инструментов являются тем же, чем являются сообщения для объектов в объектно-ориентированной среде. Простота интерфейса текстовых потоков усиливает инкапсуляцию инструментальных средств. Более сложные формы межпроцессного взаимодействия, такие как удаленный вызов процедур (remote procedure call), демонстрируют тенденцию к использованию программ с сильными внутренними зависимостями друг от друга.
Для того чтобы создавать компонуемые программы, их следует делать независимыми. Программа с одной стороны текстового потока как можно меньше должна зависеть от программы на другой стороне. Должна быть обеспечена возможность замены программы с одной стороны абсолютно другой реализацией без нарушения работы второй стороны.
GUI-интерфейсы могут быть разработаны на весьма высоком уровне. Иногда просто невозможно избежать сложных двоичных форматов данных какими-либо приемлемыми способами. Однако прежде чем создавать GUI-интерфейс, разумно будет изучить возможность выделения частей разрабатываемой программы со сложным взаимодействием в один блок, а основных алгоритмов — в другой, а также использования простого потока команд или прикладного протокола для связи двух блоков. Прежде чем изобретать нетривиальный двоичный формат для распространения данных, стоит экспериментальным путем проверить, имеется ли возможность задействовать простой текстовый формат и согласиться с небольшими затратами на синтаксический анализ в обмен на возможность обработки потока данных с помощью универсальных инструментальных средств.
В ситуации, когда сериализованный интерфейс, подобный протоколу, не является естественным для разрабатываемого приложения, конструкция "в духе Unix" заключается в том, чтобы, по крайней мере, организовать как можно больше программных примитивов в библиотеку с хорошо определенным API-интерфейсом. В таком случае открываются возможности вызова приложений путем связывания или привязки к приложению нескольких интерфейсов для различных задач.
Данная проблема подробнее обсуждается в главе 7.
1.6.4. Правило разделения: следует отделять политику от механизма и интерфейсы от основных модулей
В разделе "Что в Unix делается неверно" отмечалось, что разработчики системы X Window приняли основное решение о реализации "механизма, а не политики". Такой подход был направлен на то, чтобы сделать систему X общим сервером обработки графики и передать решение о стиле пользовательского интерфейса инстру-ментариям и другим уровням системы. Это оправданно, если учесть, что политика и механизм стремятся к изменению на протяжении различных периодов времени, причем политика меняется гораздо быстрее, чем механизм. Мода на вид и восприятие GUI-инструментариев может прийти и уйти, но растровые операции и компоновка останутся.