3. Условия успешного применения и оценка нисходящего подхода

· Условия успешного применения

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

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

3. Следует точно, кратко, емко формулировать подзадачи: должно быть ясно, какие величины обрабатываются и что должно получиться. Это требование одновременно является критерием правильности выделения подзадач.

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

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

Абстракцию можно раскрыть как последовательность действий?

Да. Раскрыть, довести до программы на этом же уровне и отладить.

Нет. Можно ли раскрыть абстракцию как условное действие?

Да. Четко сформулировать условие и соответствующие действия; раскрыть, довести до программы на этом же уровне и отладить.

Нет. Раскрыть абстракцию как повторяющееся действие. Четко сформулировать условия начала, продолжения и окончания повторений и повторяющиеся действия; раскрыть, довести до программы на этом же уровне и отладить.

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

НЕ нашли? Не то? Что вы ищете?

6. Реализацию каждой из абстракций (спецификация – алгоритм – программа) следует записывать на одном листе. Это обеспечит наглядность разработки.

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

Пп. 1 – 3 определяют условия правильного выделения и описания подзадач; п. 4 предписывает не откладывать исправление обнаруженных неувязок проекта. Общий смысл этих пунктов: главное – хороший проект. Пп. 5, 6 содержат рекомендации по раскрытию абстракций (подзадач); в п. 7 приводятся общие рекомендации по проектированию и содержанию начальных этапов.

· Оценка

ŸŸ Эффективность нисходящего подхода как принципа разработки

Нисходящий подход применим на всех этапах жизненного цикла программы.

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

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

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

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

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

ŸŸ Эффективность программного воплощения: реализация посредством механизма процедур

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

В общих чертах можно оценить аппарат процедур с разных точек зрения:

-  как средство повышения качества программы за счет улучшения структуры и наглядности последней;

-  как средство накопления труда программистов: однажды написанный модуль может быть записан в библиотеку и использоваться многократно.

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

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

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

ŸŸ Нисходящий подход и сложность задач

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

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

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

Усилия, затрачиваемые программистом в ходе разработки программы, можно отобразить в виде графика, приведенного на рис. 3.2.

Рис. 3.2. Затрачиваемые усилия на разработку

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

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

ŸŸ Препятствия в применении нисходящего подхода

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

-  отсутствие умения абстрагироваться от деталей, переходить от общего к частному и наоборот, рассматривать задачу с разных сторон;

-  привычку применять только операторы и мелкие типы конкретного языка программирования, выработанную в процессе обучения или на личном опыте;

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

4. Восходящий подход как альтернатива нисходящему.
Соотношение подходов

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

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

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

-  элементов нисходящего проектирования (в лучшем случае плохо документируемых);

-  неупорядоченного кодирования;

-  восходящего тестирования.

О затраченных усилиях и качестве получаемого программного продукта сказано выше.

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

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

Приведем высказывания классиков, подтверждающие вышеизложенное (цитируется по кн. Дж. Хьюза[1], с. 50:

«Кнут соотносит талант к программированию и уровни абстракции следующим образом:

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

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

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

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

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

[1] Дж. Хьюз, Дж. Мичтом. Структурный подход к программированию. – М., Мир. – 1980. – 278 с.