Стили и методы программирования

         

Переиспользование и стили


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

Рассмотрим ранее представленные стили с точки зрения их приспособленности к сочетанию со стилем переиспользования.

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

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

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

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

Как ни странно, немногим лучше приспособлено к сочетанию со стилем переиспользования структурное программирование. Требования к структуре информационного пространства задачи и к согласованию с ним других компонентов программы обеспечивают регламентированные связи между подзадачами, а значит, облегчается (но не исчезает) задача выделения самостоятельных компонентов. В дополнение к полностью самостоятельным переиспользуемым компонентам здесь можно указать на переиспользование, при котором в новом применении обеспечивается необходимая часть контекста (т. е. переиспользуются компонент и эта часть контекста; смотри модули языков Modula-2 и Object Pascal). Модули можно рассматривать как серые ящики для структурного программирования. Возможности модуляризации достаточно хорошо исследованы и корректно реализованы в упомянутых выше языках.

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



Внимание!

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

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

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

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

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


Общая причина тому - гибкие средства абстракции соответствующих языков и четкое отделение интерфейсов от реализаций. Это повышает потенциальные и реальные возможности переиспользования. Вместе с тем, скажем, объектно-ориентированный стиль эффективен лишь для достаточно больших систем и тем самым вдохновляет программистов на построение больших систем классов и объектов, которые сильно взаимосвязаны. А это, в свою очередь, заставляет технологизировать разработки. Технология в настоящее время связывается с наработкой типовых моделей фрагментов объектно-ориентированных систем. Создаются шаблоны проектирования (так называемые паттерны), которые предписано использовать, чтобы минимизировать связи в системе, обеспечивать ее развиваемость [8].

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

  1. Уровень приложений. В ходе ведения проекта заботятся о том, чтобы при декомпозиции и разработке компонентов системы выявлялись компоненты-кандидаты на переиспользование. Эти компоненты выделяются в самостоятельные единицы и оформляются независимо от проекта.
  2. Уровень спецификаций и документации. В спецификациях четко описываются стоящие за программой призраки, в документации отделяются подпорки от решений и не забывают о призраках.
  3. Уровень инструментов. Разработка проекта практически всегда включает в себя создание инструментальных средств, поддерживающих унификацию: единые библиотеки общедоступных для проекта средств, общий контекст и единообразные средства доступа к нему, средства поддержки выполнения технологических соглашений и регламентов, шаблоны проектирования и др. Этот инструментарий (или часть его) во многих случаях может быть оформлен независимо от проекта для возможного переиспользования в виде библиотек.
  4. Уровень решений. Ценность для переиспользования может представлять архитектурный уровень проекта. Хорошие архитектурные решения, как правило, допускают распространение за рамки конкретного проекта, в котором они появились.


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


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

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

Предупреждение!

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


Содержание раздела