Чтение онлайн

на главную

Жанры

Искусство программирования для Unix

Реймонд Эрик Стивен

Шрифт:

С момента возникновения полемики по поводу структурного программирования в 60-х годах, начинающих программистов, как правило, учат, что верный подход заключается в проектировании сверху вниз. То есть в поэтапном усовершенствовании, где на абстрактном уровне определяется, для чего предназначена данная программа, и постепенном заполнении пустот реализации до тех пор, пока не будет образован точно работающий код. Нисходящий подход становится хорошей практикой, когда выполняются три предусловия: (а) можно с большой точностью определить, для решения каких задач предназначена данная программа, (b) значительные изменения спецификации в ходе реализации маловероятны и (с) большая свобода выбора на низком уровне, каким образом программа будет выполнять свои функции.

Данные условия наиболее часто выполняются в

программах, расположенных сравнительно близко к пользователю и высоко в стеке программ, т.е. в прикладном программировании. Однако даже в этом случае указанные предусловия часто не выполняются. Невозможно заранее определить "правильный" режим работы текстового редактора или графической программы до тех пор, пока пользовательский интерфейс не пройдет тестирование среди конечных пользователей. Исключительно нисходящее программирование часто характеризуется чрезмерным вложением трудозатрат в код, который придется удалить за ненадобностью и перестроить, поскольку интерфейс не проходит проверку в реальных условиях.

Для того чтобы обезопасить себя, программисты пытаются использовать оба подхода — описывают абстрактную спецификацию как нисходящую логику приложения и собирают множество низкоуровневых примитивов предметной области в функциях или библиотеках с тем, чтобы в случае изменения высокоуровневой конструкции их можно было использовать повторно.

Unix-программисты наследуют традицию, которая является центральной в системном программировании, где низкоуровневыми примитивами являются операции аппаратного уровня, которые имеют постоянный характер и чрезвычайно важны. Следовательно, "благодаря приобретенному инстинкту" они более склонны к восходящему программированию.

Независимо от того является программист системным или нет, восходящий подход также может выглядеть более привлекательно при программировании исследовательским способом, когда пытаются получить контроль над феноменами аппаратного или программного обеспечения или реальными феноменами, которые еще не полностью понятны. Восходящее программирование предоставляет время и пространство для уточнения нечеткой спецификации. Кроме того, восходящее программирование "апеллирует к естественной человеческой лени" программистов: когда требуется удалить часть кода и перестроить его, при работе в нисходящем направлении приходится удалять более крупные фрагменты, чем при работе в восходящем направлении.

Таким образом, создание реального кода склоняется к использованию как нисходящего, так и восходящего подходов. Нередко нисходящий и восходящий код является частью одного и того же проекта. В таком случае возникает необходимость использования связующих уровней.

4.3.2. Связующие уровни

Довольно часто столкновение нисходящего и восходящего подходов является причиной некоторого беспорядка. Верхний уровень логики приложения и нижний уровень основных примитивов необходимо согласовать с помощью уровня связующей логики.

Один из уроков, которые Unix-программисты осваивали десятилетиями, состоит в том, что связующая технология представляет собой опасное нагромождение, и жизненно важным является сохранение связующих уровней как можно более тонкими. Связующий уровень должен соединять другие уровни, но его не следует использовать для сокрытия "изломов" и "шероховатостей" в них.

В примере с Web-браузером связующий уровень включал бы в себя код визуализации, который преобразовывает объект документа, полученный из входящего HTML- файла в сглаженное визуальное изображение в виде растра в буфере экрана, используя для формирования изображения основные примитивы GUI-интерфейса. Данный код визуализации печально известен как наиболее подверженная ошибкам часть браузера. Он содержит в себе ухищрения, направленные на разрешение проблем, которые связаны как с синтаксическим анализом HTML-кода (ввиду большого количества неверно сформированной там разметки), так и в инструментальном наборе GUI (в котором могут отсутствовать действительно необходимые примитивы).

Связующий уровень Web-браузера должен служить промежуточным звеном не только между спецификацией и основными примитивами, но и между несколькими различными внешними спецификациями:

работой сети, описанной в протоколе HTTP, структурой HTML-документа и различными графическими мультимедийными форматами, а также поведенческими ожиданиями пользователей при работе с GUI-интерфейсом.

Однако один единственный чреватый ошибками связующий уровень не является наибольшей проблемой. Разработчик, который знает о существовании связующего уровня и пытается организовать его в средний уровень вокруг собственного набора структур данных или объектов, может в итоге получить два связующих уровня — один выше среднего уровня, а другой ниже. Талантливые, но неопытные программисты особенно склонны попадать в эту ловушку. Они правильно выбирают все основные наборы классов (логику приложения, средний уровень и примитивы предметной области) и переделывают их подобно примерам из учебников, и только сбиваются с пути по мере того, как величина нескольких связующих уровней, необходимых для интеграции всего привлекательного кода, становится все больше и больше.

Принцип тонкого связующего уровня можно рассматривать как уточнение правила разделения. Политика (т.е. логика приложения) должна быть четко обособлена от механизма (то есть основных примитивов), однако очень большой код, который не является ни политикой, ни механизмом, скорее всего, свидетельствует о том, что его функции минимальны и что он только увеличивает общую сложность в системе.

4.3.3. Учебный пример: язык С считается тонким связующим уровнем

Язык С является хорошим примером эффективности тонкого связующего уровня.

В конце 90-х годов Джеррит Блаау (Gerrit Blaauw) и Фред Брукс (Fred Brooks) в книге "Computer Architecture: Concepts and Evolution" [4] отмечали, что архитектура всех поколений компьютеров (от ранних мэйнфреймов, мини-компьютеров и рабочих станций до PC) стремилась к конвергенции. Чем более поздней была конструкция в своем технологическом поколении, тем плотнее она приближался к тому, что Блаау и Брукс назвали "классической архитектурой" (classical architecture): двоичное представление, линейное адресное пространство, разграничение памяти и рабочего хранилища (регистров), универсальные регистры, определение адреса, занимающего фиксированное число байтов, двухадресные команды, порядок следования байтов [45] и типы данных как последовательное множество с размерами, кратными 4, либо 6 (6-битовые семейства в настоящее время устарело).

45

Архитектурный выбор порядка интерпретации битов в машинном слове — "обратный" и "прямой" (big-endian и little-endian). Хотя канонический адрес отсутствует, поиск в Web по фразе "On Holy Wars and a Plea for Peace" позволит найти классическую и интересную статью по данной теме.

Томпсон и Ритчи разрабатывали язык С как подобие структурированного ассемблера для идеализированной архитектуры процессора и памяти, которую, как они ожидали, можно было смоделировать на большинстве традиционных компьютеров. По счастливой случайности, их моделью для идеализированного процессора был компьютер PDP-11, весьма продуманная и изящная конструкция мини-компьютера, которая вплотную приближалась к классической архитектуре Блаау и Брукса. Здраво рассуждая, Томпсон и Ритчи отказались внедрять в С большинство характерных особенностей (таких как порядок байтов) там, где PDP-11 ему не соответствовал [46] .

46

Широко распространенное мнение о том, что автоинкрементная и автодекрементная функции вошли в С, поскольку они представляли машинные команды PDP-11, — это не более чем миф. Согласно воспоминаниям Денниса Ритчи, данные операции были предусмотрены в предшествующем языке В еще до появления PDP-11.

Поделиться:
Популярные книги

Последний Паладин. Том 3

Саваровский Роман
3. Путь Паладина
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин. Том 3

Последний попаданец 5

Зубов Константин
5. Последний попаданец
Фантастика:
юмористическая фантастика
рпг
5.00
рейтинг книги
Последний попаданец 5

Убивать чтобы жить 6

Бор Жорж
6. УЧЖ
Фантастика:
боевая фантастика
космическая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 6

6 Секретов мисс Недотроги

Суббота Светлана
2. Мисс Недотрога
Любовные романы:
любовно-фантастические романы
эро литература
7.34
рейтинг книги
6 Секретов мисс Недотроги

Измена

Рей Полина
Любовные романы:
современные любовные романы
5.38
рейтинг книги
Измена

Курсант: Назад в СССР 13

Дамиров Рафаэль
13. Курсант
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Курсант: Назад в СССР 13

Газлайтер. Том 6

Володин Григорий
6. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 6

Купидон с топором

Юнина Наталья
Любовные романы:
современные любовные романы
7.67
рейтинг книги
Купидон с топором

Виконт. Книга 3. Знамена Легиона

Юллем Евгений
3. Псевдоним `Испанец`
Фантастика:
фэнтези
попаданцы
аниме
7.00
рейтинг книги
Виконт. Книга 3. Знамена Легиона

Попаданка в деле, или Ваш любимый доктор - 2

Марей Соня
2. Попаданка в деле, или Ваш любимый доктор
Любовные романы:
любовно-фантастические романы
7.43
рейтинг книги
Попаданка в деле, или Ваш любимый доктор - 2

Усадьба леди Анны

Ром Полина
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Усадьба леди Анны

Титан империи 2

Артемов Александр Александрович
2. Титан Империи
Фантастика:
фэнтези
боевая фантастика
аниме
5.00
рейтинг книги
Титан империи 2

Вечный. Книга I

Рокотов Алексей
1. Вечный
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Вечный. Книга I

Убивать чтобы жить 5

Бор Жорж
5. УЧЖ
Фантастика:
боевая фантастика
космическая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 5