пятница, 19 августа 2011 г.

С чего начать проектирование программы? Часть 1


С чего начать проектирование программы? Классический объектно-ориентированный подход даёт нам однозначный ответ на этот вопрос: с выявления ключевых абстракций и построения объектной модели предметной области.

Джеймс Рамбо, один из создателей языка UML и Rational Unified Process'а, в своей книге "UML 2.0. Объектно-ориентированное моделирование и разработка" предлагает нам такой алгоритм проектирования:

  1. Изучить предметную область и выделить классы предметной области.
  2. Удалить лишние классы (несущественные или избыточные).
  3. Связать классы ассоциациями.
  4. Выделить в классах атрибуты.
  5. Реструктуризовать классы при помощи наследования.
  6. Добавить классы приложения.
  7. Добавить операции.

Дж. Рамбо, М. Блаха. UML 2.0. Объектно-ориентированное моделирование и разработка. 2-е изд. – СПб.: Питер, 2007, стр. 218 – 285.

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

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


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

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

Вернёмся к вопросу, вынесенному в заголовок. С чего начать проектирование программы?

Чтобы ответить на этот вопрос, сделаем небольшое отступление. Это отступление важно, потому что многие начинающие программисты о нём забывают. Его суть – любая техника разрабатывается для выполнения какой-либо полезной функции. Например, функция автомобиля – перемещение его владельца из пункта А в пункт Б. И программы здесь – не исключение. У каждой программы тоже должно быть определённое назначение, например, редактирование текста, редактирование таблиц или развлечение пользователя. Приступая к проектированию программы, разработчик должен чётко понимать её назначение.

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

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

Иными словами, прежде чем проектировать конструкцию программы, нужно сначала спроектировать технологический процесс.

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

Его можно описать в текстовом виде при помощи вариантов использования (см.:  Коберн, Алистер. Современные методы описания функциональных требований к системам/Пер. с англ. – М.: Издательство «Лори», 2002 г. – 263 с.: ил.) и в виде диаграммы (например, блок-схемы, flowchart).

Рассмотрим предложенноый подход на примере. В качестве примера возьмём задачу про датчики и метеостанцию из книги Гради Буча и продемонстрируем, как можно подойти к решению данной задачи иным образом, чем это изложено у Г. Буча.

Требования к метеорологической станции
Система должна обеспечивать автоматический мониторинг следующих первичных погодных параметров:
  • скорость и направление ветра;
  • температура;
  • барометрическое давление;
  • влажность воздуха.
Система также должна вычислять некоторые производные параметры, в число которых входят:
  • коэффициент резкости погоды;
  • точка росы;
  • относительное изменение температуры;
  • относительное изменение барометрического давления.
В системе должна быть предусмотрена возможность определения текущего времени и даты, которые будут использоваться при генерации сообщении о максимальных и минимальных значениях первичных параметров за последние 24 часа.
Система должна обеспечивать постоянный вывод на дисплей текущих значений всех восьми первичных и производных параметров, а также текущее время и дату. Пользователь должен иметь возможность увидеть максимальные и минимальные значения любого из первичных параметров за 24 часа, сопровождаемые информацией о времени произведения соответствующего замера.
Система должна позволять пользователю проводить калибровку датчиков по известным опорным значениям, а также устанавливать текущие время и дату.
Буч Г. Объектно-ориентированный анализ и проектирование с примерами приложений на C++, 2-е изд./Пер с англ. – М.: "Издательство Бином", СПб: "Невский диалект", 1998 г., стр. 284, или: http://www.helloworld.ru/texts/comp/other/oop/ch08.htm

Начнём проектирование системы с описания процесса измерения и отображения температуры.

Первая диаграмма будет довольно простой:


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

Внесём в диаграмму изменения:


В новой диаграмме тоже есть погрешность: данные на порт посылаются по определённому протоколу. Чтобы прочитать их, нужен модуль, который "понимает" этот протокол.

Внесём соответствующие изменения:


Сообщение от датчика температуры, скорее всего, закодировано в определённом формате (например, в формате json или в специализированном XML). Соответственно, потребуется парсер, который понимает этот формат:


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

Отобразим этап преобразования градусов на диаграмме:


Наконец, температуру нужно показать в определённом месте экрана (или в определённом окне).

Внесём изменения в схему:


Получилось достаточно подробное описание процесса измерения и отображения температуры.

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

В этом случае, диаграмма процесса будет выглядеть так:


Наряду с такими компонентами, как:

  • парсер атмосферного давления,
  • конвертер атмосферного давления (например, из кило-паскалей в мм. ртутного столба) и
  • окном для вывода давления,

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

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

Приведём список классов и операций:

Port
Читает данные, пришедшие на порт.
Protocol
Читает данные с порта по определённому протоколу.
Dispatcher
Определяет, от какого датчика поступило сообщение, и пересылает его соответствующему обработчику.
Temperature Parser
Разбирает сообщение от датчика температуры.
Barometric Pressure Parser
Разбирает сообщение от датчика атмосферного давления.
Temperature Converter
Преобразует температуру из одних единиц в другие.
Barometric Pressure Converter
Преобразует атмосферное давление из одних единиц в другие.
Temperature Window
Отображает температуру в специальном окне.
Barometric Pressure Window
Отображает атмосферное давление в специальном окне.
Screen
Отображает окна на экране.


ЛИТЕРАТУРА:

1.      Буч Г. Объектно-ориентированный анализ и проектирование с примерами приложений на C++, 2-е изд./Пер с англ. – М.: "Издательство Бином", СПб: "Невский диалект", 1998 г. Или: http://www.helloworld.ru/texts/comp/other/oop/index.htm
4.      Рамбо Дж., Блаха М. UML 2.0. Объектно-ориентированное моделирование и разработка. 2-е изд./Пер. с англ. – СПб.: Питер, 2007. – 544 с.: ил.
5.      С.В. Сычев, К.А. Лебедев. Освобождение узников оператора IF - http://www.triz-ri.ru/themes/method/creative/creative57.asp