Каркас архитектуры: различия между версиями

Содержимое удалено Содержимое добавлено
Нет описания правки
Нет описания правки
Строка 12:
 
Существует тесная связь между многократной используемостью и изменяемостью. Чтобы ее почувствовать, достаточно отметить следующие: части (в измененной программе), не затронутые модификациями → используются повторно. Это отменяет то представление объектного подхода, что повторно используемые части можно выделить в функции и потом использовать. Повторно используемые части должны обладать важным свойством – они постоянны и не подвержены изменениям. А функции как правило имеют тенденцию изменяться. Поэтому повторно использоваться может лишь каркас, обладающий постоянством, а объектные функции – суть изменяемые части, которые лишь при наличии специальных средств можно использовать многократно (а не повторно). Отсутствие таких средств делает повторное использование опасным как для окружения, так и для работоспособности. Такие специальные средства – это ''язык сборки'', в частности реализуется или препроцессором или интерпретатором метаданных.
 
 
== Эффективные механизмы в каркасном подходе ==
 
Каркасный подход это теоретическое построение, но обладает тем важным свойством, что многие практические современные парадигмы и инструменты языков программирования, почти не осознано, стремятся к реализации данной теории. Поэтому ниже приведена достаточно большая вставка, немного переработанная, чтобы более детально понимать что такое каркасный подход и какими механизмами он пользуется. После ознакомления с этим мы вернемся к рассмотрению вопросов построения архитектуры ПО, с использованием идей каркасного подхода.
 
=== Оформление варианта ===
 
Пусть на некоторой стадии создания программы удалось найти усиление для одного из входящих в нее и ранее уже отлаженных алгоритмов. Запрограммировав новый, более удачный алгоритм, обычно не спешат с окончательным уничтожением заменяемого им фрагмента программы, сознательно допуская на какое-то время сосуществование обоих фрагментов в программном фонде.
 
Дело в том, что при обнаружении каких-либо неполадок в новой версии программы проще всего отвести подозрения от нового участка, вернув на прежнее место старый фрагмент. Кроме того, нередко нет полной уверенности в том, что новый алгоритм по всем параметрам превосходит старый, и, следовательно, не исключается возможность отката к прежнему решению. В результате два или даже несколько вариантных алгоритмических фрагментов программы будут сосуществовать до тех пор, пока одному из решений не будет отдано безусловное предпочтение - только тогда его конкуренты окончательно ликвидируются.
Возможна ситуация, когда вариантные фрагменты присутствуют в программном фонде постоянно. Речь идет, конечно, не о старье, отслужившем свое и лишь по забывчивости не попавшем в свое время в мусорную корзину, а о сознательно сохраняемых, регулярно сменяющих друг друга в выполняемой программе равноправных вариантах. В последнем случае вариантные фрагменты представляют собой различные версии программы, отражающие, например, различные модификации модели исследуемого объекта.
 
Отметим, что сосуществование вариантных фрагментов в программном фонде вовсе не подразумевает их одновременного присутствия в выполняемой программе. Более того, одновременное присутствие фрагментов обычно нежелательно, а нередко и невозможно. Например, если альтернативой линейному поиску в некоторой таблице выбрано хеширование, то в выполняемой программе может работать либо один, либо другой соответствующий вариантный фрагмент, но не оба вместе. Включение обоих фрагментов не только перегружает программу, но и может привести к серьезным противоречиям, в частности из-за нестыковки описаний структур данных.
Для решения данной задачи используется механизм "Оформления варианта". Делается это следующим образом, сначала в исходном тексте программы выделяется вариантный фрагмент. Сделать это можно, например, посредством указания начального и конечного символов, но лучше, если квантами выделения будут синтаксические единицы языка программирования. Тем самым формируется вариантное гнездо, т.е. указывается место в тексте, предназначенное для подстановки одного из имеющихся вариантных фрагментов.
 
В момент формирования гнезда единственным претендентом на размещение в нем является только что выделенный вариантный фрагмент исходного текста. Однако теперь программист получает возможность образовать для вновь сформированного гнезда еще один вариантный фрагмент. Новый фрагмент можно объявить активным, т.е. включить в формируемую версию выполняемой программы, вытесняя из нее старый фрагмент. В то же время в программном фонде старый фрагмент сохраняется, там оба вариантных фрагмента сосуществуют на равных правах. Затем, разумеется, можно снова сделать активным старый фрагмент, или же образовать в данном гнезде еще один вариантный фрагмент и сделать активным его и т.д.
 
Любой из вариантных фрагментов можно уничтожить. Если у гнезда останется только один принадлежащий ему вариантный фрагмент, то можно ликвидировать и гнездо, т.е. сделать данный участок программы безвариантным. При ликвидации единственный принадлежащий гнезду вариантный фрагмент подставляется на место гнезда и полностью сливается с окружающим текстом программы.
Формальное определение вариантного гнезда в исходном тексте может задаваться предложением #VARIANT вида
 
#VARIANT имя_гнезда[.имя_компонента], где имя_компонента используется, если гнездо представляет собой односвязный компонент многосвязного гнезда. На место вариантного гнезда препроцессор подставляет текст ровно одного сменного модуля, назначенного этому гнезду в описании конфигурации собираемой программы.
 
В приведенном решении все изменения программы производятся безболезненно, не нарушая работоспособности отлаженных версий, поскольку ни на одной стадии процессов оформления и ликвидации варианта не требуется редактирование текста, существовавшего ранее. Исключается какое бы то ни было дублирование текстов программ. Наконец, вариант оформляется посредством специально предназначенных для этой цели конструкций, что позволяет легко распознать присутствие вариантности при последующем анализе программы.
 
Обсуждая безболезненность приведенного решения, имеет смысл рассмотреть еще одну грань данной проблемы. Пусть программа, в которой вы намереваетесь оформить вариантный фрагмент, интенсивно используется вашими коллегами для проведения важных расчетов. Тогда, обеспечивая безболезненность оформления варианта, необходимо в первую очередь позаботится о том, чтобы ваше экспериментирование не отразилось на работе соседей.
 
Точнее говоря, хотелось бы, чтобы все то время, которое вы посвятите отладке нового варианта, ваши коллеги могли бы не подозревать об ожидающем их сюрпризе – появлении новой модификации алгоритма – и продолжать работать со старой версией программы. Для этого достаточно слегка видоизменить предложенную выше схему, а именно считать, что старый вариантный фрагмент подставляется во вновь образованное вариантное гнездо по умолчанию. Тогда вам придется явно указывать новый вариантный фрагмент в описании конфигурации своей экспериментальной версии программы. А ваши коллеги в это время будут, как ни в чем не бывало использовать прежнее описание конфигурации, отражающее старую отлаженную версию.
 
Отметим, что здесь понятие безболезненности затрагивает уже не только тексты программ, но и описание конфигурации. Такое обобщение следует признать совершенно естественным. Ведь для ваших коллег практически безразлично, редактирование какого текста (программы или описания конфигурации) приведет к потере работоспособности.
 
=== Наборное гнездо ===
 
Потребности и в вариантных, и в наборных гнездах могут возникать в задачах из практически любой предметной области. Однако в вариантных гнездах наиболее остро нуждается относительно обособленная отрасль программирования – задачи вычислительного эксперимента. Наборные гнезда, являются некоторым обобщением вариантных гнезд, и поэтому могут быть использованы для более широкой области программирования.
Наборные гнезда каркаса программы предназначаются для подстановки на их место нескольких однородных модулей. Таким образом, наборное гнездо служит для оформления группы однородных смежных элементов программы, повышая наглядность и обеспечивая возможность безболезненного расширения этой группы. Наборное гнездо представляет собой цикл периода сборки программы. Цикл повторяется столько раз, сколько имеется в программном фонде однородных модулей, предназначенных данной конкретной конфигурацией для подстановки в наборное гнездо, а переменная цикла в это время последовательно пробегает все подставляемые модули.
 
#SET имя_набора
тело_гнезда
[ #DELIMITER разделитель ]
#END_OF_SET
 
Предложения #SET и #END_OF_SET очерчивают границы гнезда, а имя_набора задает подставляемый набор однородных модулей и одновременно служит в качестве переменной цикла, пробегающей по всем подставляемым модулям. В цикле многократно воспроизводится тело_гнезда, представляющее собой произвольный текст на исходном языке, в котором располагаются точки включения односвязных компонентов модуля. Точки включения задаются с помощью конструкций вставки вида
 
#имя_набора.имя_компонента
 
Если модуль односвязный, то имя компонента не указывается и конструкция вставки приобретает более простой вид:
 
#имя_набора
 
Для включения в формируемый текст имени очередного однородного модуля используется конструкция вставки, где на месте имени компонента записывается зарезервированное слово NAME:
 
#имя_набора.NAME
 
Сходным образом включается в текст номер текущего повторения цикла (NUMBER), общее число однородных модулей (SIZE) и т.д.
 
Часть #DELIMITER может быть опущена. Если она присутствует, то между повторениями цикла (но не вслед за последним повтрением) записыается разделитель.
В программе может располагаться несколько наборных гнезд, относящихся к одному набору. В каждом из этих гнезд элементы набора перебираются в одной и той же последовательности.
Описывая конкретную конфигурацию формируемой программы, для задания требуемого содержимого наборного гнезда можно использовать два механизма: перечислительный и ассоциативный. Безболезненность существенно зависит от того, которому из этих двух механизмов отдано предпочтение.
 
При перечислительной схеме в описании конфигурации явно перечисляются имена сменных модулей, размещаемых в гнезде. Если новые модули, пополняющие программный фонд, не должны участвовать в отлаженных ранее версиях программы, то с точки зрения безболезненности заполнение наборного гнезда по перечислительной схеме ничем не отличается от заполнения вариантного гнезда, т.е. применения перечислительной схемы безболезненно.
 
Однако, если вновь создаваемые сменные модули нужно подключать к имеющимся версиям, то перечислительная схема теряет даже свойство безболезненности для окружения. Ведь при этой схеме приходится вручную редактировать существующий первичный объект – описание конкретной версии программы, содержащее перечень входящих в нее модулей.
При ассоциативной схеме в наборном гнезде размещаются либо все имеющиеся в пакете модули, предназначенные для этого гнезда, либо только те из них, которые обладают некоторыми свойствами (атрибутами), указанными в описании конфигурации. Тут новый сменный модуль всегда может сразу же включиться в существовавшую ранее версию программы, поскольку назначение его производится не непосредственно (путем указания имени), а неявно (путем указания свойства).
 
С одной стороны, подключение происходит безболезненно для окружения. Ни соседние модули, ни тексты описаний конкретных конфигураций не меняются. Тем не менее, новый модуль не только огранично вливается в пакетное окружение, но и, возможно, сразу же на равных правах со всеми включается в работу.
 
С другой стороны, требованию безболезненности для работоспособности ассоциативная схема не удовлетворяет. Причина в том, что если в подключаемом модуле имеются ошибки, то его появление (из-за неявного указания) в ранее отлаженной версии программы может привести к потере работоспособности.
 
=== Рассредоточенный набор ===
 
Применение рассредоточенного набора, имеет достаточно большую область. Так как для данной работы полное рассмотрение возможного применения рассредоточенного набора не предоставляет интересса, мы ограничимся рассмотрением следующего примера.
 
Пусть программа должна осуществлять тщательный анализ входных данных, результатом которого является, в частности, значительное число выдаваемых диагностических сообщений. Вопрос заключается в том, где следует разместить тексты сообщений: записать их непосредственно в тех точках программы, в которых обнаруживаются диагностируемые ситуации, или же свести в единую таблицу. Каждая из альтернатив имеет свои сильные и слабые стороны.
 
Непосредственное размещение обладает целым рядом достоинств. Текст сообщения, является, как правило, наилучшим пояснением к фрагменту алгоритма, анализирующему диагностируемую ситуацию. При кодировании алгоритма значительно удобнее сразу разместить сообщение в создаваемой программе, чем записать его в таблицу, формируемую на отдельном листке бумаги или на какаом-либо его экранном аналоге, а в алгоритм включить ссылку на вновь записанную строку таблицы. Табличное решение требует постоянного внимания к целостности программы: добавляя или исключая некоторый фрагмент алгоритма, необходимо строго следить за тем, чтобы тексты выдаваемых там диагностических сообщений были добавлены в таблицу или, соответственно, исключены из нее. При непосредственном размещении оцелостности заботится не надо.
В то же время аргументы в пользу таблицы также достаточно весомы. Сводная таблица выдаваемых сообщений служит полезным дополнением к любой инструкции по эксплуатации программы. При изучении алгоритма таблица дает возможность увидеть текст программы в новом интересном ракурсе. Табличное представление позволяет избежать поиска разбросанных по программе текстов при необходимости создания экспортируемой за рубеж версии программы, выдающей сообщения на другом (иностранном) языке. Наконец, полный список сообщений долженбыть всегда под рукой у разработчика, заботящегося о стилистическом единстве существующих и вновь появляющихся текстов.
 
Располагая механизмом рассредоточенного набора, решить проблему размещения сообщений удается довольно легко. Тексты сообщений записываются непосредственно в программе, но оформляются в виде объявлений элементов набора. Искомая таблица сообщений в этом случае строится на основе наборного гнезда, в котором собираются все элементы рассредоточенного набора, т.е. все сообщения, объявленные в составляющих программу модулях. На месте же объявлений при сборке программы препроцессор сформирует обращения к построенной таблице. Нетрудно видеть, что данное решение успешно справляется со всеми перечисленными выше трудностями размещения сообщений.
 
Механизм рассредоточенного набора позволяет собрать воедино разбросанные по тексту программы однородные элементы. В тексте программы элемент рассредоточенного однородного набора объявляется посредством конструкции вида
 
{ #INSTALL_IN [LOCAL] имя_набора [SUBSET]
{имя_компонента : значение }}
[ #APPLY
применение]
#END_OF_INSTALL
 
В одной конструкции разрешается объявлять сразу несколько элементов различных рассредоточенных наборов (об этом говорят внешние фигурные скобки, окаймляющие первые две строки).
В строке #INSTALL_IN указывается имя_набора, в котором включается объявляемый элемент. Служебное слово LOCAL говорит о том, что область действия набора – текущий модуль трансляции; если LOCAL отсутствует, то область действия – вся программа. Служебное слово SUBSET указывает на то, что рассредоточенный набор высекает подмножество существующего в программном фонде регулярного однородного набора; в этом случае в объявлении присутствует только один компонент с именем NAME, значение которого задает имя включаемого в подмножество элемента регулярного набора. Вложенные фигурные скобки, окаймляющие вторую строку, означают, что записанная в них конструкция должна быть воспроизведена в одном или в нескольких экземплярах. Тем самым имеется возможность объявления составного элемента: каждый экземпляр конструкции вводит один из компонентов. Имя_компонента задается в левой части конструкции, а справа записывается значение объявляемого компонента.
 
Далее следует необязательная часть #APPLY. Там располагается то, что должно остаться в исходном тексте после обработки конструкции #INSTALL_IN препроцессором. Часть #APPLY представляет собой обычный текст, среди которого могут размещаться значения компонентов объявленного элемента рассредоточенного набора, задаваемые конструкцией вида #имя_набора.имя_компонента. Кроме того, в текст можно включать порядковый номер; он задается в виде #имя_набора.NUMBER.
 
 
== Литература ==