1.10. МОДЕЛИРОВАНИЕ И ПРОГРАММИРОВАНИЕ. ПОНЯТИЕ СПЕЦИФИКАЦИЙ

1.10. МОДЕЛИРОВАНИЕ И ПРОГРАММИРОВАНИЕ. ПОНЯТИЕ СПЕЦИФИКАЦИЙ

Один объект или система может выступать в роли модели другого объекта или системы, если между ними установлено сходство в каком-то смысле. Моделью системы (или какого-либо другого объекта или явления) может быть формальное описание системы, в котором выделены основные объекты, составляющие систему, и отношения между этими объектами.

Построение моделей — широко распространенный способ изучения сложных объектов и явлений. В модели опущены многочисленные детали, усложняющие понимание. Моделирование широко распространено в науке, технике и программировании.

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

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

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

Любые достаточно большие программы являются сложными системами. Проблема сложности преодолевается путем декомпозиции задачи. Базовая парадигма в подходе к любой большой задаче ясна: необходимо «разделять и властвовать».

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

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

Отдельные виды абстракций определяют наиболее эффективный способ декомпозиции применительно к конкретным целям. Верно опознав абстракции, можно получить модели, доступные для понимания как отдельными людьми, так и коллективом участников проекта.

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

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

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

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

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

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

Уже в первичных спецификациях можно выделить две части: функциональную и эксплуатационную.

Первичная функциональная спецификация в первую очередь описывает:

— объекты, участвующие в задаче (что делает программа и что делает человек, работающий с этой программой);

— процессы и действия — эвроритмы для человека, алгоритмы методов решения задачи в машине с указанием сути и порядка обработки информации (с занимаемым информацией и программой размером оперативной памяти);

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

То есть вначале фиксируются внешние функциональные спецификации, а затем и внутренние.

В общем случае внешние функциональные спецификации включают:

— описание того, что делает программа;

— определение, что делает человек, а что машина (по каким эвроритмам работает человек, откуда он берет информацию и как ее готовит к вводу в ЭВМ);

— спецификации входных и выходных данных;

— реакции на исключительные ситуации.

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

К внутренним спецификациям относятся описания состава внутренних частей программы, описания их взаимосвязи, а также внутренние функциональные спецификации.

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

Изложенные далее абстракции процедуры, данных и объектов лежат в основе многих методов разработки программного обеспечения. В общем случае любую программу можно представить набором процедурных абстракций (рис. 1.2). Анализируя рис. 1.2, можно получить обобщенную абстракцию процедуры, изображенную на рис. 1.3. Абстракции процедур наиболее полно воплотились в технологии структурного программирования.

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

Рис. 1.2. Абстракция программы как набора процедур, обрабатывающих данные

Рис. 1.3. Абстракция процедуры

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

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

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

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

Правило 2. Можно ограничиться только той информацией, которую подразумевает конечное условие.

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

Второе правило показывает, что на самом деле имеем дело с абстракцией: абстрагируясь от тела процедуры, можно не обращать внимания на несущественную информацию. Именно такое «игнорирование» информации и отличает абстракцию от декомпозиции. Конечно, анализируя тело процедуры, можно извлечь некоторое количество информации, не следующей из конечного условия (как, например, то, что найденный элемент первый или последний в рассмотренном выше примере). В спецификации подобная информация о возвращаемом результате отбрасывается.

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

Например, абстракцию SQRT (извлечение квадратного корня) можно сравнить с операцией: она абстрагирует отдельное событие или задачу. Мы будем ссылаться к абстракциям такого рода, как к процедурным абстракциям. Отметим, что абстракция SQRT включает в себя как абстракцию через параметризацию, так и абстракцию через спецификацию.

На процедурной абстракции основана разработка структуры программы в технологии структурного программирования. Базовая компонента технологии структурного программирования — модуль, которому обычно соответствует подпрограмма (процедура или функция на языках программирования высокого уровня).

Рассматривая программу не как набор процедур, а прежде всего как некоторые наборы данных, каждый из которых имеет разрешенную группу процедур, получаем абстрактное представление программы, представленное на рис. 1.4. Анализ рис. 1.4 позволяет также получить абстракцию данных, показанную на рис. 1.5.

В технологии абстрактных данных Дейкстры применяется функциональная модель в виде набора диаграмм потоков данных (далее — ДПД; DFD — Data Flow Diagram), которые описывают смысл операций и ограничений. ДПД отражает функциональные зависимости значений, вычисляемых в системе, включая входные значения, выходные значения и внутренние хранилища данных. ДПД — это граф, на котором показано движение значений данных от их источников через преобразующие их процессы к их потребителям в других объектах. Фрагменты ДПД показаны на рис. 1.6.

Рис. 1.4. Абстракция программы как набора данных, обрабатываемых процедурами

Рис. 1.5. Абстракция данных

Поток данных соединяет выход объекта (или процесса) с входом другого объекта (или процесса). Он представляет промежуточные данные вычислений.

Хранилище данных — это пассивный объект в составе ДПД, в котором данные сохраняются для последующего доступа. Хранилище данных допускает доступ к хранимым в нем данным в порядке, отличном от того, в котором они были туда помещены. Агрегатные хранилища данных, как, например, списки и таблицы, обеспечивают доступ к данным в порядке их поступления либо по ключам.

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

Рис. 1.6. Фрагменты диаграммы потоков данных (ДПД):

а — копирование данных (числа); б — расщепление данных; в — активный объект «Клиент» посредством операции «Нахождение цены» работает с хранилищем «Прайс-лист»

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

Если в структурном программировании главными являются функции и процедуры (действия), то в технологии абстрактных данных Дейкстры во главе ставятся данные.

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

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

Шаг 1. Основываясь на потоке данных в задаче, выделите 3—10 смысловых частей обработки данных.

Шаг 2. Доопределите главный входной и выходной потоки данных задачи.

Шаг 3. Проследите, как следует входной поток от части к части, от входа к концу обработки, найдите эту точку. Проследите от конца к началу, как следует выходной поток; найдите абстрактную точку, где он появился (рис. 1.7).

Найденные точки делят задачу на две или три наиболее независимые (по данным) части.

Шаг 4. Представьте независимые части подпрограммами и определите их функции. Эти подпрограммы будут подчиненными по отношению к модулю, разбиение которого выполняется.

Шаг 5. Определите сопряжения подпрограмм по данным.

Рис. 1.7. Превращение главного входного потока информации в выходной поток:

1 — участок соответствует преобразованию информации входного потока в промежуточную информацию; 2 — участок соответствует получению выходной и промежуточной информации из входной и промежуточной информации; 3 — участок соответствует получению выходной информации из промежуточной информации

Современная, вытесняющая технологии структурного программирования и абстракции данных объектно-ориентированная технология сочетает в себе абстракции процедур и данных в новой абстракции — объекте (рис. 1.8). Понятие абстракции данных расширено до того, что как внутренние данные, так и код процедур рассматриваются как новый тип данных — объект.

Объектная модель базируется на двух постулатах: все есть объекты; объекты взаимодействуют передачей сообщений.

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

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

Рис. 1.8. Абстракция объекта

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

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

Размещенный в отдельном файле набор связанных процедур вместе с данными, которые они обрабатывают, называют программной единицей (Unit). Часто слово «Unit» переводят как модуль. Так возник термин «модульное программирование». В модульном программировании акцент сместился от проектирования процедур в сторону организации данных. Помимо прочего, это явилось отражением факта увеличения размеров программ. Парадигма: реши, какие требуются модули; разбей программу так, чтобы скрыть данные в модулях.

В объектно-ориентированном программировании абстракция данных является фундаментальным аспектом качественного проектирования. Парадигма: программа представляется набором объектов, которые, взаимодействуя друг с другом посредством сообщений, меняют себя и окружающие объекты. Принцип модульного программирования используется и в объектно-ориентированном программировании. Обычно в одном Unit описывается либо один класс, либо несколько классов, наследуемых от одного класса. Механизмы Unit реализуют сокрытие информации. Объектно-ориентированный подход характеризуется разнонаправленностью и разнородностью информационных потоков.