Полная версия

Главная arrow Информатика arrow Архитектура и проектирование программных систем

  • Увеличить шрифт
  • Уменьшить шрифт


<<   СОДЕРЖАНИЕ   >>

Слои программного продукта

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

Большинство известных специалистов [9, 12, 20] еще в 70-80-е гг. прошлого века пришли к заключению, что разбиение на уровни является стандартным способом восприятия сложных текстов (не только программ) независимо от того, помогает в этом автор текста или нет. Насколько хорошо понимают это основное правило разработчики программных систем, убедительно показывает пример выделения уровней в документации, сопровождающей большие программы: как правило, одна и та же программа описывается в нескольких документах, отражающих конкретные уровни абстракции (руководство пользователя, руководство оператора, руководство системного программиста и т.п.). Разнообразие руководств указывает на возможность создания различных абстрактных описаний одной и той же программы. Эти описания могут (но не обязательно должны) образовывать упорядоченное множество. Правда, на практике документация, предоставляемая разработчиками, во многих случаях вопреки декларируемым ими целям не является ни упорядоченной, ни полной.

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

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

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

Наконец, можно обнаружить еще модульное расслоение программы: слои, соответствующие множествам равнодоступных модулей. Отметим, что (пока еще неточное) понятие равнодоступности модулей освобождает от языковых ограничений: языковые конструкции могут облегчать модульное расслоение или даже обеспечивать синтаксическую единицу, соответствующую модульному слою, но и при отсутствии таких языковых средств можно различать модульные слои в программе. Дальнейшее изложение материала этого раздела следует В. Турскому [37].

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

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

Модули, построенные из модулей нулевого уровня, могут рассматриваться только как модули первого уровня. При этом не требуется, чтобы все модули первого уровня были равнодоступны. Например, в программах, написанных на языке, допускающем блочную структуру, некоторые модули первого уровня могут быть локализованы в каком-либо блоке и, следовательно, доступны только внутри этого блока и его подблоков.

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

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

лей Ь0. Процесс, описываемый ниже, введет более высокие уровни и отношение порядка.

Рассмотрим множество модулей М, не входящих в выделенные слои, и таких, что для каждого модуля те М имеем:

  • 1) если спецификация модуля т зависит от модуля т а модуль т1 принадлежит слою Ь, то 0 < г < п;
  • 2) хотя бы один из модулей, используемых в спецификации т, принадлежит слою Ьп.

Любое множество М, удовлетворяющее этим двум требованиям, формирует страту над слоем Ь„. Максимальной стратой БЦ,,) над слоем Ьп будем называть страту, содержащую все модули рассматриваемой программы, удовлетворяющие обоим условиям для страты.

Рассмотрим теперь множество всех модулей К(Ьп) таких, что для каждого модуля ке К(Ьп) выполняются:

  • 1) хотя бы один модуль, используемый в спецификации к, принадлежит слою Ь„;
  • 2) все модули, используемые в спецификации к, не являющиеся членами Ь0 и<5'//(Т0)и...иТ„_1 и)и, должны быть членами

Щя);

3) если т>к и те К(Ьп), то существует хотя бы один модуль ре К(Ьп), такой, чтор > т.

Множество 57/(1„) = К(Ьп) и называется покровом над слоем Ьп.

Таким образом, произвольная (или максимальна) страта над Ьп является некоторым (или конкретным) множеством (всех) модулей, специфицируемых с использованием слоев То, Ь, ..., Ь,„ которые по определению не могут быть реализованы при отсутствии доступа хотя бы к некоторым модулям слоя Ь„. На практике реализация модуля из страты над Т„ потребует, вероятно, также доступа к модулям из других слоев (Т0, Т|, •.Тя_ ]).

Взаимозависимые модули исключаются из страты, однако включаются в покровы как члены множеств К(Ь„). Для некоторых языков программирования понятия покровов совпадают с понятием максимальной страты.

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

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

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

Разбиение программы на слои показано на рис. 6.8, где отношение п > т обозначается стрелкой, проведенной из п в т. Базовый слой обозначен горизонтальной линией в нижней части рисунка. Модули А, В, Б, биН принадлежат максимальной страте над базовым слоем; модули С, Э, Е составляют множество К(Ь„). Следовательно, все модули самого нижнего ряда принадлежат покрову над базовым слоем. Модули А, В, С, Э, Е и Н равнодоступны «сверху» и, таким образом, принадлежат первому слою. Модули Б и О являются собственностью модуля М, что дает основание рассматривать эту группу модулей как единый модуль М, а модули Б и О - как модуляризованные компоненты модуля М.

Модули I, 3 и Б удовлетворяют условиям множества К(Ь„) и, следовательно, принадлежат покрову над первым слоем; действительно, поскольку они равнодоступны, они являются членами второго слоя.

Как классифицировать модуль М? Поскольку кроме базовых модулей он зависит только от модулей Б и О, которые являются членами страты над базовым слоем, не принадлежат никакому слою, модуль М принадлежит максимальной страте над нулевым слоем. Будучи также доступен, как и модули А, В, С, Е), Е и Н, модуль М должен рассматриваться как модуль первого слоя.

Разбиение программы на слои

Рис. 6.8. Разбиение программы на слои

При помощи аналогичных рассуждений можно показать, что модули I, I, Ь и О принадлежат второму слою, а третий и четвертый слои состоят каждый из одного модуля (ЫиР соответственно). Модуль Р - это, конечно, программа в целом.

Анализ представленного на рис. 6.8 примера выявляет несколько интересных аспектов.

Во-первых, несмотря на искусственно введенную иерархию модулей М, Б и О, все-таки правильно относить модуль М к первому слою.

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

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

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

Однако необходимо отметить, что во всех приведенных рассуждениях программа рассматривалась как готовый продукт, т.е. не рассматривались способы и средства получения данной структуры. Из многих возможных интерпретаций понятия «расслоение» использовано то, которое определено как структура из слоев равнодоступных модулей.

 
<<   СОДЕРЖАНИЕ   >>