Среда, 22 Май 2024, 23:21
Uchi.ucoz.ru
Меню сайта
Форма входа

Категории раздела
Учителю физики [224]
Учителю химии [112]
Учителю биологии [744]
Учителю информатики [147]
Учителю математики [110]
Учителю русского языка [250]
Учителю астрономии [437]
Учителю иностранного языка [182]
Учителю истории (открытые уроки) [151]
Учителю обществознания [53]
Учителю истории [354]
Учителю труда [14]
Учителю ОБЖ [2]
Учителю искусствоведения [0]
Изо
Учителю белорусского языка и литературы [1]
Учителю допризывной и медицинской подготовки [0]
Учителю географии [9]
Учителю МХК [1]
Учителю музыки [3]
Учителю физкультуры [15]
Учителю черчения [0]
Новости
Чего не хватает сайту?
500
Статистика
Зарегистрировано на сайте:
Всего: 51637


Онлайн всего: 1
Гостей: 1
Пользователей: 0
Яндекс.Метрика
Рейтинг@Mail.ru

Каталог статей


Главная » Статьи » По предмету » Учителю информатики

РАЗРАБОТКА СТРУКТУРЫ ПРОГРАММЫ И МОДУЛЬНОЕ ПРОГРАММИРОВАНИЕ
1. Цель модульного программирования.
Приступая к разработке каждой программы ПС, следует иметь в виду, что она, как правило, является большой системой, поэтому мы должны принять меры для ее упрощения. Для этого такую программу разрабатывают по частям, которые называются программными модулями. А сам такой метод разработки программ называют модульным программировани-ем. Программный модуль  это любой фрагмент описания процесса, оформляемый как само-стоятельный программный продукт, пригодный для использования в описаниях процесса. Это означает, что каждый программный модуль программируется, компилируется и отлажи-вается отдельно от других модулей программы, и тем самым, физически разделен с другими модулями программы. Более того, каждый разработанный программный модуль может включаться в состав разных программ, если выполнены условия его использования, декла-рированные в документации по этому модулю. Таким образом, программный модуль может рассматриваться и как средство борьбы со сложностью программ, и как средство борьбы с дублированием в программировании (т.е. как средство накопления и многократного исполь-зования программистских знаний).
Модульное программирование является воплощением в процессе разработки программ обоих общих методов борьбы со сложностью: и обеспечение независимости компонент сис-темы, и использование иерархических структур. Для воплощения первого метода формули-руются определенные требования, которым должен удовлетворять программный модуль, т.е. выявляются основные характеристики «хорошего» программного модуля. Для воплощения второго метода используют древовидные модульные структуры программ (включая деревья со сросшимися ветвями).

2. Основные характеристики программного модуля.
Не всякий программный модуль способствует упрощению программы. Выделить хо-роший с этой точки зрения модуль является серьезной творческой задачей. Для оценки при-емлемости выделенного модуля используются некоторые критерии. Так, предложены сле-дующие два общих таких критерия:
• хороший модуль снаружи проще, чем внутри;
• хороший модуль проще использовать, чем построить.
Майерс предлагает для оценки приемлемости программного модуля использовать более кон-структивные его характеристики:
• размер модуля,
• прочность модуля,
• сцепление с другими модулями,
• рутинность модуля (независимость от предыстории обращений к нему).
Размер модуля измеряется числом содержащихся в нем операторов или строк. Модуль не должен быть слишком маленьким или слишком большим. Маленькие модули приводят к громоздкой модульной структуре программы и могут не окупать накладных расходов, свя-занных с их оформлением. Большие модули неудобны для изучения и изменений, они могут существенно увеличить суммарное время повторных трансляций программы при отладке программы. Обычно рекомендуются программные модули размером от нескольких десятков до нескольких сотен операторов.
Прочность модуля  это мера его внутренних связей. Чем выше прочность модуля, тем больше связей он может спрятать от внешней по отношению к нему части программы и, сле-довательно, тем больший вклад в упрощение программы он может внести.
Функционально прочный модуль  это модуль, выполняющий (реализующий) одну ка-кую-либо определенную функцию. При реализации этой функции такой модуль может ис-пользовать и другие модули. Такой класс программных модулей рекомендуется для исполь-зования.
Информационно прочный модуль  это модуль, выполняющий (реализующий) несколь-ко операций (функций) над одной и той же структурой данных (информационным объек-том), которая считается неизвестной вне этого модуля. Для каждой из этих операций в таком модуле имеется свой вход со своей формой обращения к нему. Такой класс следует рассматривать как класс программных модулей с высшей степенью прочности. Информационно прочный модуль может реализовывать, например, абстрактный тип данных.
В модульных языках программирования как минимум имеются средства для задания функционально прочных модулей (например, модуль типа FUNCTION в языке ФОРТРАН). Средства же для задания информационно прочных модулей в ранних языках программиро-вания отсутствовали. Эти средства появились только в более поздних языках. Так в языке программирования Ада средством задания информационно прочного модуля является пакет.
Сцепление модуля  это мера его зависимости по данным от других модулей. Характе-ризуется способом передачи данных. Чем слабее сцепление модуля с другими модулями, тем сильнее его независимость от других модулей. Для оценки степени сцепления Майерс пред-лагает упорядоченный набор из шести видов сцепления модулей. Худшим видом сце-пления модулей является сцепление по содержимому. Таким является сцепление двух модулей, когда один из них имеет прямые ссылки на содержимое другого модуля (например, на константу, содержащуюся в другом модуле). Такое сцепление модулей недопустимо. Не рекомендуется использовать также сцепление по общей области  это такое сцепление модулей, когда несколько модулей используют одну и ту же область памяти. Такой вид сцепления модулей реализуется, например, при программировании на языке ФОРТРАН с использованием блоков COMMON. Единственным видом сцепления модулей, который рекомендуется для использования современной технологией программирования, является параметрическое сцепление (сцепление по данным)  это случай, когда данные передаются модулю либо при обращении к нему как значения его параметров, либо как результат его обращения к другому модулю для вычисления некоторой функции. Такой вид сцепления модулей реализуется на языках программирования при использовании обращений к процедурам (функциям).
Рутинность модуля  это его независимость от предыстории обращений к нему. Мо-дуль будем называть рутинным, если результат (эффект) обращения к нему зависит только от значений его параметров (и не зависит от предыстории обращений к нему). Модуль будем называть зависящим от предыстории, если результат (эффект) обращения к нему зависит от внутреннего состояния этого модуля, изменяемого в результате предыдущих обращений к нему. Майерс не рекомендует использовать зависящие от предыстории (непредсказуемые) модули, так как они провоцируют появление в программах хитрых (неуловимых) ошибок. Однако такая рекомендация является неконструктивной, так как во многих случаях именно зависящий от предыстории модуль является лучшей реализаций информационно прочного модуля. Поэтому более приемлема следующая (более осторожная) рекомендация:
• всегда следует использовать рутинный модуль, если это не приводит к плохим (не ре-комендуемым) сцеплениям модулей;
• зависящие от предыстории модули следует использовать только в случае, когда это не-обходимо для обеспечения параметрического сцепления;
• в спецификации зависящего от предыстории модуля должна быть четко сформулирова-на эта зависимость таким образом, чтобы было возможно прогнозировать поведение (эффект выполнения) данного модуля при разных последующих обращениях к нему.
В связи с последней рекомендацией может быть полезным определение внешнего представления (ориентированного на информирование человека) состояний зависящего от предыстории модуля. В этом случае эффект выполнения каждой функции (операции), реали-зуемой этим модулем, следует описывать в терминах этого внешнего представления, что су-щественно упростит прогнозирование поведения данного модуля.

3. Методы разработки структуры программы.
Как уже отмечалось выше, в качестве модульной структуры программы принято ис-пользовать древовидную структуру, включая деревья со сросшимися ветвями. В узлах такого дерева размещаются программные модули, а направленные дуги (стрелки) показывают ста-тическую подчиненность модулей, т.е. каждая дуга показывает, что в тексте модуля, из кото-рого она исходит, имеется ссылка на модуль, в который она входит. Другими словами, каж-дый модуль может обращаться к подчиненным ему модулям, т.е. выражается через эти моду-ли. При этом модульная структура программы, в конечном счете, должна включать и сово-купность спецификаций модулей, образующих эту программу. Спецификация программного модуля содержит
• синтаксическую спецификацию его входов, позволяющую построить на используемом языке программирования синтаксически правильное обращение к нему (к любому его входу),
• функциональную спецификацию модуля (описание семантики функций, выполняемых этим модулем по каждому из его входов).
Функциональная спецификация модуля строится так же, как и функциональная специфика-ция ПС.
В процессе разработки программы ее модульная структура может по-разному формиро-ваться и использоваться для определения порядка программирования и отладки модулей, указанных в этой структуре. Поэтому можно говорить о разных методах разработки структу-ры программы. Обычно в литературе обсуждаются два метода: метод восходящей разработки и метод нисходящей разработки.
Метод восходящей разработки заключается в следующем. Сначала строится модульная структура программы в виде дерева. Затем поочередно программируются модули програм-мы, начиная с модулей самого нижнего уровня (листья дерева модульной структуры программы), в таком порядке, чтобы для каждого программируемого модуля были уже запрограммированы все модули, к которым он может обращаться. После того, как все модули программы запрограммированы, производится их поочередное тестирование и отладка в принципе в таком же (восходящем) порядке, в каком велось их программирование. Такой порядок разработки программы на первый взгляд кажется вполне естественным: каждый модуль при программировании выражается через уже запрограммированные непосредственно подчиненные модули, а при тестировании использует уже отлаженные модули. Однако, современная технология не рекомендует такой порядок разработки программы. Во-первых, для программирования какого-либо модуля совсем не требуется наличия текстов используемых им модулей  для этого достаточно, чтобы каждый используемый модуль был лишь специфицирован (в объеме, позволяющем построить правильное обращение к нему), а для тестирования его возможно (и даже, как мы покажем ниже, полезно) используемые модули заменять их имитаторами (заглушками). Во-вторых, каждая программа в какой-то степени подчиняется некоторым внутренним для нее, но глобальным для ее модулей соображениям (принципам реализации, предположениям, структурам данных и т.п.), что определяет ее концептуальную целостность и формируется в процессе ее разработки. При восходящей разработке эта глобальная информация для модулей нижних уровней еще не ясна в полном объеме, поэтому очень часто приходится их перепрограммировать, когда при программировании других модулей производится существенное уточнение этой глобальной информации (например, изменяется глобальная структура данных). В-третьих, при восходящем тестировании для каждого модуля (кроме головного) приходится создавать ведущую программу (модуль), которая должна подготовить для тестируемого модуля необходимое состояние информационной среды и произвести требуемое обращение к нему. Это приводит к большому объему «отладочного» программирования и в то же время не дает никакой гарантии, что тестирование модулей производилось именно в тех условиях, в которых они будут выполняться в рабочей про-грамме.
Метод нисходящей разработки заключается в следующем. Как и в предыдущем методе сначала строится модульная структура программы в виде дерева. Затем поочередно про-граммируются модули программы, начиная с модуля самого верхнего уровня (головного), переходя к программированию какого-либо другого модуля только в том случае, если уже запрограммирован модуль, который к нему обращается. После того, как все модули про-граммы запрограммированы, производится их поочередное тестирование и отладка в таком же (нисходящем) порядке. При этом первым тестируется головной модуль программы, кото-рый представляет всю тестируемую программу и поэтому тестируется при «естественном» состоянии информационной среды, при котором начинает выполняться эта программа. При этом те модули, к которым может обращаться головной, заменяются их имитаторами (так называемыми заглушками). Каждый имитатор модуля представляется весьма простым про-граммным фрагментом, который, в основном, сигнализирует о самом факте обращения к имитируемому модулю, производит необходимую для правильной работы программы обра-ботку значений его входных параметров (иногда с их распечаткой) и выдает, если это необ-ходимо, заранее запасенный подходящий результат. После завершения тестирования и от-ладки головного и любого последующего модуля производится переход к тестированию од-ного из модулей, которые в данный момент представлены имитаторами, если таковые име-ются. Для этого имитатор выбранного для тестирования модуля заменяется самим этим мо-дулем и, кроме того, добавляются имитаторы тех модулей, к которым может обращаться вы-бранный для тестирования модуль. При этом каждый такой модуль будет тестироваться при «естественных» состояниях информационной среды, возникающих к моменту обращения к этому модулю при выполнении тестируемой программы. Таким образом, большой объем «отладочного» программирования при восходящем тестировании заменяется программиро-ванием достаточно простых имитаторов используемых в программе модулей. Кроме того, имитаторы удобно использовать для того, чтобы подыгрывать процессу подбора тестов пу-тем задания нужных результатов, выдаваемых имитаторами. При таком порядке разработки программы вся необходимая глобальная информация формируется своевременно, т.е. лик-видируется весьма неприятный источник просчетов при программировании модулей. Неко-торым недостатком нисходящей разработки, приводящим к определенным затруднениям при ее применении, является необходимость абстрагироваться от базовых возможностей используемого языка программирования, выдумывая абстрактные операции, которые позже нужно будет реализовать с помощью выделенных в программе модулей. Однако способность к таким абстракциям представляется необходимым условием разработки больших программных средств, поэтому ее нужно развивать.
Особенностью рассмотренных методов восходящей и нисходящей разработок (которые мы будем называть классическими) является требование, чтобы модульная структура про-граммы была разработана до начала программирования (кодирования) модулей. Это требо-вание находится в полном соответствии с водопадным подходом к разработке ПС, так как разработка модульной структуры программы и ее кодирование производятся на разных эта-пах разработки ПС: первая завершает этап конструирования ПС, а второе  открывает этап кодирования. Однако эти методы вызывают ряд возражений: представляется сомнительным, чтобы до программирования модулей можно было разработать структуру программы доста-точно точно и содержательно. На самом деле это делать не обязательно, если несколько мо-дернизировать водопадный подход. Ниже предлагаются конструктивный и архитектурный подходы к разработке программ, в которых модульная структура формируется в процессе программирования (кодирования) модулей.

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


Рис. 7.2. Второй шаг формирования модульной структуры программы при конструк-тивном подходе.

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

В классическом методе нисходящей разработки рекомендуется сначала все модули раз-рабатываемой программы запрограммировать, а уж затем начинать нисходящее их тестиро-вание, что опять-таки находится в полном соответствии с водопадным подходом. Однако такой порядок разработки не представляется достаточно обоснованным: тестирование и отладка модулей может привести к изменению спецификации подчиненных модулей и даже к изменению самой модульной структуры программы, так что в этом случае программиро-вание некоторых модулей может оказаться бесполезно проделанной работой. Нам представ-ляется более рациональным другой порядок разработки программы, известный в литературе как метод нисходящей реализации, что представляет некоторую модификацию водопадного подхода. В этом методе каждый запрограммированный модуль начинают сразу же тестиро-вать до перехода к программированию другого модуля.
Все эти методы имеют еще различные разновидности в зависимости от того, в какой последовательности обходятся узлы (модули) древовидной структуры программы в процессе ее разработки. Это можно делать, например, по слоям (разрабатывая все модули одного уровня, прежде чем переходить к следующему уровню). При нисходящей разработке дерево можно обходить также в лексикографическом порядке (сверху вниз, слева направо). Воз-можны и другие варианты обхода дерева. Так, при конструктивной реализации для обхода дерева программы целесообразно следовать идеям Фуксмана, которые он использовал в предложенном им методе вертикального слоения. Сущность такого обхода заключается в следующем. В рамках конструктивного подхода сначала реализуются только те модули, ко-торые необходимы для самого простейшего варианта программы, которая может нормально выполняться только для весьма ограниченного множества наборов входных данных, но для таких данных эта задача будет решаться до конца. Вместо других модулей, на которые в та-кой программе имеются ссылки, в эту программу вставляются лишь их имитаторы, обеспе-чивающие, в основном, сигнализацию о выходе за пределы этого частного случая. Затем к этой программе добавляются реализации некоторых других модулей (в частности, вместо некоторых из имеющихся имитаторов), обеспечивающих нормальное выполнение для неко-торых других наборов входных данных. И этот процесс продолжается поэтапно до полной реализации требуемой программы. Таким образом, обход дерева программы производится с целью кратчайшим путем реализовать тот или иной вариант (сначала самый простейший) нормально действующей программы. В связи с этим такая разновидность конструктивной реализации получила название метода целенаправленной конструктивной реализации. Дос-тоинством этого метода является то, что уже на достаточно ранней стадии создается рабо-тающий вариант разрабатываемой программы. Психологически это играет роль допинга, резко повышающего эффективность разработчика. Поэтому этот метод является весьма при-влекательным.
Подводя итог сказанному, на рис. 7.3 представлена общая классификация рассмотрен-ных методов разработки структуры программы.



Рис. 7.3. Классификация методов разработки структуры программ.

4. Контроль структуры программы.
Для контроля структуры программы можно использовать три метода:
• статический контроль,
• смежный контроль,
• сквозной контроль.
Статический контроль состоит в оценке структуры программы, насколько хорошо про-грамма разбита на модули с учетом значений рассмотренных выше основных характеристик модуля.
Смежный контроль сверху  это контроль со стороны разработчиков архитектуры и внешнего описания ПС. Смежный контроль снизу  это контроль спецификации модулей со стороны разработчиков этих модулей.
Сквозной контроль  это мысленное прокручивание (проверка) структуры программы при выполнении заранее разработанных тестов. Является видом динамического контроля так же, как и ручная имитация функциональной спецификации или архитектуры ПС.
Следует заметить, что указанный контроль структуры программы производится в рам-ках водопадного подхода разработки ПС, т.е. при классическом подходе. При конструктив-ном и архитектурном подходах контроль структуры программы осуществляется в процессе программирования (кодирования) модулей в подходящие моменты времени.
Категория: Учителю информатики | Добавил: Wrecker (31 Июл 2012)
Просмотров: 2072 | Теги: Модульное, программирование, структуры, Разработка, Программы | Рейтинг: 1.0/ 9 Оштрафовать | Жаловаться на материал
Похожие материалы
Всего комментариев: 0

Для блога (HTML)


Для форума (BB-Code)


Прямая ссылка

Профиль
Среда
22 Май 2024
23:21


Вы из группы: Гости
Вы уже дней на сайте
У вас: непрочитанных сообщений
Добавить статью
Прочитать сообщения
Регистрация
Вход
Улучшенный поиск
Поиск по сайту Поиск по всему интернету
Наши партнеры
Интересное
Популярное статьи
Портфолио ученика начальной школы
УХОД ЗА ВОЛОСАМИ ОЧЕНЬ ПРОСТ — ХОЧУ Я ЭТИМ ПОДЕЛИТ...
Диктанты 2 класс
Детство Л.Н. Толстого
Библиографический обзор литературы о музыке
Авторская программа элективного курса "Практи...
Контрольная работа по теме «Углеводороды»
Поиск
Главная страница
Используются технологии uCoz