Процесс разработки программного обеспечения ICONIX

В предыдущих статьях я рассказывал про некоторые диаграммы UML — все эти статьи были из одного цикла, целью которого является описание полноценного процесса проектирования ICONIX:

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

Описание процесса ICONIX

ICONIX — процесс разработки программного обеспечения, использующий UML. Один из авторов процесса (Дуг Розенберг) утверждает: «ICONIX — нечто среднее между RUP и XP».

RUP — процесс разработки, с использованием более десяти диаграмм UML, продвигаемый Гради Бучем (разработчиком UML) [UML-Buch]. Чаще всего именно именно RUP преподается в ВУЗах. Основной недостаток RUP — высокая сложность, с одной стороны разработчикам сложно выбрать нужный набор диаграмм (некоторые диаграммы UML являются взаимозаменяемыми), с другой — очень сложен переход от диаграммы прецедентов (фактически, технического задания) к диаграммам взаимодействия.

Подход XP (экстремального программирования) заключается в отсутствии этапа детального проектирования, продвигается Кентом Беком [XP-Beck]. При этом, постоянно проводится «игра в планирование» с участием заказчика (или его представителем), в результате которой формируется план работ на ближайшее время. Кент Бек исходит из того, что требования заказчика постоянно меняются. Проблемы подхода: такой тесный и постоянный контакт с заказчиком возможен не всегда; заказчик может хотеть сразу знать конечную стоимость разработки (если ТЗ меняется и вы не пытаетесь его фиксировать в каком-то состоянии — то указать стоимость невозможно). Экстремальное программирование подходит далеко не для всех типов проектов, а экономия времени на проектировании может выйти боком. Тем не менее, из XP можно вынести ряд полезных практик [XP-Auer].

В ICONIX и RUP часть этапов совпадает, при этом они оба являются итеративными. При этом, ICONIX проще, в нем используется лишь 4 вида диаграмм — ведь даже по словам Буча «80% задач можно решить, используя 20% UML». Одной из этих диаграмм является диаграмма пригодности (ее нет в UML, но она внесена в приложение к стандарту), не используемая в RUP, но упрощающая переход от прецедентов к диаграммам взаимодействия.

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

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

iconix

Процесс разработки ICONIX


Розенберг пишет, что до начала проектирования заказчик должен предоставить вам свои представления об интерфейсе, а на первом этапе осуществляется построение модели предметной области и только затем — прецеденты. На самом деле, далеко не всегда заказчик предоставит что-то типа диаграммы потока экранов, часто во время разработки прецедентов заказчик уточняет свои требования к интерфейсу. Кроме того, часто разработка модели предметной области ведется параллельно с разработкой прецедентов — об этом, также, пишет Фаулер [UML-Fauler]. Возможно, на первом этапе вам придется заняться одновременно построением прецедентов и модели предметной области — побочным продуктом такого процесса будет диаграмма потока экранов.

Предположим, что наш заказчик хочет получить приложение для телефона и написал следующее, как он думает, понятное, техническое задание:

Функциональные требования:
• пользователь может выбрать уровень в меню;
• при прохождении уровня, пользователь сначала рисует по подсказкам системы (запоминает), а затем — повторяет тот же процесс без подсказок (по памяти);
• если уровень пройден (рисунок по памяти выполнен без ошибок) — в меню он помечается галочкой, если не пройден — процесс повторяется.
Нефункциональные требования:
• должно работать на Android 4.0 и выше;
• apk файл должен занимать не более 15 МБ.

Процесс разработки как в ICONIX, так и в RUP начинается с построения диаграмм вариантов использования, т. к. именно этот вид диаграмм позволяет четко сформулировать функциональные требования к системе.

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

Подробно процесс построения этого вида диаграмм, рекомендации и типичные ошибки описаны в отдельной статье [UML-use-case]. Важно, что приведенное выше описание программы нельзя назвать полноценным техническим заданием и, наверняка, если если мы разработаем по нему программу — заказчика она не устроит. Было бы хорошо, если бы заказчик мог сам написать техническое задание, но он никогда этого не сможет сделать без помощи программиста, т. к. только программист (пусть даже не самой высокой квалификации) может определить какие детали важны для реализации проекта, а какие — нет. При составлении use-case диаграмм важно, чтобы заказчик и программист поняли друг друга.

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

use-case-diagram

Диаграмма вариантов использования

При определении прецедентов можно попросить заказчика нарисовать нам примерный интерфейс:

user-interface

Пример схемы пользовательского интерфейса

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

problem-domain-model

Модель предметной области

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

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

Название прецедента: выбор уровня
Действующие лица: пользователь
Основной поток:
Предусловия: открыто меню выбора уровня (MenuScreen)
Цель: выбрать уровень
Действия:
1. загружается список уровней, в котором уровни представлены с иконками, отображающими уменьшенный рисунок, который требуется выполнить при прохождении. Успешно пройденные уровни помечаются галочкой;
2. пользователь, просматривая список уровней, проматывает его пальцем на нужную позицию;
3. нажатием на иконку пользователь выбирает уровень.
Постусловия: открывается GameScreen, в котором работает выбранный уровень
Примечания: Выбор уровня и проматывание различаются расстоянием, на которое перемещался курсор (палец) после нажатия (перед отпусканием). Если было смещение более чем на 10 пикселей — значит производится проматывание.

Название прецедента: изменение громкости
Действующие лица: пользователь
Основной поток:
Предусловия: —
Цель: включить/выключить звук
Действия:
1. пользователь нажимает на кнопку включения/выключения звука;
2. звук включается/выключается;
3. кнопка меняет свой вид в соответствии с текущим состоянием звука.
Постусловия: звук включен/выключен, настройки звука сохранены (после перезапуска приложения должны быть установлены эти же параметры).

Название прецедента: смотреть правила
Действующие лица: пользователь
Основной поток:
Предусловия: открыто окно просмотра правил (HelpScreen)
Цель: посмотреть правила игры
Действия:
1. пользователь просматривает правила игры.
2. Если правила не умещаются на экране — они могут проматываться пальцем.
Постусловия: —

Название прецедента: переключать экраны
Основной поток:
Предусловия: —
Цель: смена экрана приложения
Действия:
1. нажатием на кнопки в тулбаре или выполнением других действий пользователь может менять текущий экран в соответствии с приведенной ниже диаграммой потока экранов.
Постусловия: —

screen-flow

Диаграмма потока экранов

Название прецедента: повернуть телефон
Общие для всех потоков предусловия: на телефоне включено отслеживание поворота экрана
Действующие лица: пользователь

Поток для MenuScreen:
Предусловия: открыто меню выбора уровня (MenuScreen)
Цель: просмотр MenuScreen в другой ориентации телефона
Действия:
1. пользователь поворачивает телефон;
2. меню перестраивается так, что размер иконок не изменяется (иконка квадратная — размер берется таким, чтобы в min(ширина, высота) входило заданное в коде число иконок);
3. область с кнопками звука и выхода перемещается в нижнюю часть экрана.
Постусловия: меню перестроено с учетом требований, список уровней может как автоматически быть промотан в начало, так и остаться на позиции, открытой до поворота (на выбор программиста);

Поток для GameScreen:
Предусловия: открыто меню игры (GameScreen)
Цель: просмотр GameScreen в другой ориентации телефона
Действия:
1. пользователь поворачивает телефон
2. GameScreen перестраивается:
◦ размер области игры (GameWidget) изменится, а его содержимое должно быть отмасштабировано без искажений пропорций;
◦ область, содержащая подсказки (TipWidget) должна быть перемещена в нижнюю часть экрана (сразу после поворота она окажется сбоку);
◦ область с кнопками открытия помощи, перехода на предыдущий экран, звука и выхода должна быть перемещена в нижнюю часть экрана.
Постусловия: GameScreen перестроен с учетом требований.

Поток для HelpScreen:
Предусловия: открыт экран помощи (HelpScreen)
Цель: просмотр HelpScreen в другой ориентации телефона
Действия:
1. пользователь поворачивает телефон
2. HelpScreen перестраивается:
◦ содержимое HelpScreen (текст и рисунки) масштабируется по ширине экрана без изменения пропорций;
◦ область с кнопками перехода на предыдущий экран, звука и выхода должна быть перемещена в нижнюю часть экрана.
Постусловия: HelpScreen перестроен с учетом требований.

Название прецедента: прохождение уровня
Действующие лица: игрок
Поток — успешное прохождение уровня:
Предусловия: пользователь выбрал уровень
Цель: пройти уровень
Действия:
1. отображается виджет с подсказками (TipWidget), в котором в виде стрелочки и расстояния показывается следующая точка рисунка;
2. выполняется прецедент «выполнение рисунка», при этом после каждого хода обновляется TipWidget;
3. TipWidget скрыт;
4. выполняется прецедент «выполнение рисунка»;
5. уровень помечается как пройденный. Информация сохраняется и после перезапуска программы уровень также остается пройденным;
6. загружается MenuScreen.
Постусловия: пользователь находится в MenuScreen, пройденный уровень отображен в меню соответствующим образом.

Название прецедента: выполнение рисунка
Предусловия: пользователь находится на игровом экране
Цель: выполнить рисунок
Действия:
1. на экране отображается сетка и начальная точка рисунка;
2. пользователь нажимает на узлы сетки (система выбирает тот узел, к которому ближе всего было выполнено нажатие);
3. если пользователь выбрал точку правильно — между ней и последней точкой рисунка рисуется линия, проигрывается звук рисования. Новая точка добавляется к рисунку (становится последней). В случае ошибки выполненная часть рисунка становится красной на 1 секунду, проигрывается звук ошибки, рисование начинается сначала;
4. если пользователь нарисовал все точки рисунка — рисунок считается выполненным.
Постусловия: рисунок выполнен успешно

Анализ прецедентов

На этапе анализа прецедентов Розенберг [Rosenberg] рекомендует проверять что:
1. созданные прецеденты описывают всю требуемую функциональность системы;
2. для каждого прецедента четко и кратко прописана главная последовательность действий, а также все альтернативные последовательности;
3. выделены (с помощью того или иного удобного для вас механизма) сценарии, общие для нескольких прецедентов.

Для этого следует перечитать внимательно тексты прецедентов вместе с заказчиком. Я же советую посмотреть также не допущены ли вами типичные ошибки при проектировании use-case диаграмм [UML-use-case].

При анализе диаграммы робастности (это следующий этап, но упомяну об этом сейчас, т. к. привел конечный вариант use-case диаграммы) я по-разному пытался разделить прецедент прохождения уровня. Пробовал выделять прецеденты «прохождение с подсказками» и «прохождение без подсказок», также пробовал описать все в одном прецеденте — каждый раз переписывая тексты. Это оказалось достаточно трудоемко, однако в результате функциональная часть ТЗ читается очень легко, кроме того я уверен, что за счет этого удалось избежать некоторых возможных ошибок проектирования.

Я не сразу пришел к использованию диаграммы потока экранов (которую продвигает Фаулер [UML-Fauler], оказалось очень удобно. Проще нарисовать, чем писать. Прецедент «переключать экраны» тоже появился не сразу. Перед этим в каждом прецеденте была куча альтернативных последовательностей, описывающих возможные переходы. Дальше будет показано, что выделение такого прецедента — также является ошибкой, лучше просто прилагать диаграмму потока экранов.

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

problem-domain-model-2

Модель предметной области после анализа прецедентов

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

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

Разработка диаграмм пригодности и их анализ

Подробно диаграммы пригодности (робастности) были рассмотрены ранее [UML_rubustness_diagrams], при этом приводилось два подхода к построению диаграмм — через рассмотрение последовательно каждого предложения сценария и по «алгоритму». В примере к той статье я использовал первый способ, а сейчас воспользуюсь алгоритмом, напомню его:
1. добавить граничные объекты для каждого важного элемента интерфейса;
2. добавить контроллеры для управления сценарием (действия пользователя с граничным объектом);
3. добавить контроллеры для бизнес-правил (правила поведения объектов, ограничения);
4. добавить контроллеры для активностей, включающих несколько разных элементов (включающих сущности и бизнес правила, например);
5. добавить сущности;
6. добавить варианты использования (как контроллеры).

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

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

Ниже приведены некоторые диаграммы пригодности в их конечном виде:

Диаграмма пригодности включения/выключения звука:

sound_on_off_robustness_diagram

Диаграмма робастности управления звуком

Диаграмма робастности выполнения рисунка:

drawing-robustness

Диаграмма пригодности выполнения рисунка

Диаграмма пригодности прецедента выбора уровня:

select_level_robustness

Диаграмма пригодности прецедента выбора уровня

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

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

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

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

Разработка диаграмм последовательности и классов

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

Диаграмма последовательности прецедента «выбор уровня»:

select_level-sequence

Диаграмма последовательности выбора уровня

Диаграмма последовательности прецедента «прохождение уровня»:

game_level_sequence

Диаграмма последовательности прецедента прохождение уровня

Диаграмма последовательности прецедента «выполнение рисунка»:

drawing-sequence

Диаграмма последовательности прецедента выполнение рисунка — 1

drawing-sequence-2

Диаграмма последовательности прецедента выполнение рисунка — 2

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

Для построения диаграммы классов достаточно обновить модель предметной области, добавив классам методы, выявленные при разработке диаграмм последовательности:

class-finall

Диаграмма классов

Видно, что диаграмма чуть-чуть изменилась, т. к. на последнем этапе процесса ICONIX — рецензирование окончательного проекта я посмотрел на диаграмму и прецеденты еще раз, при этом проверил, чтобы все прецеденты можно было выполнить (у классов было достаточно данных для выполнения своих обязанностей). На этом же этапе стоит подумать о возможности повторного использования частей проекта и применении шаблонов проектирования. Я добавил паттерн Publish-Subscriber чтобы при изменении базы данных уровней (прохождении уровня) оповещать игровое меню. Вероятно, базы данных уровней и настроек, а также SoundManager будут реализованы за счет паттерна Одиночка — на это указывают линии ассоциации (мы не знаем в какой объект должны быть включены экземпляры этих классов).

Да построении диаграммы классов процесс проектирования заканчивается. Диаграмма может быть преобразована в исходный код (заготовки классов и методов). Написанием кода игрушки и публикацией ее на Google Play мы займемся в следующей статье…

Список литературы по теме

  • [XP-Beck] Кен Ауэр, Рой Миллер: «Экстремальное программирование: постановка процесса с первых шагов и до победного конца» — Питер, 2003
  • [XP-Beck] Кент Бек: Экстремальное программирование — Питер, 2002
  • [UML-Buch] Буч Градди Объектно-ориентированный анализ и проектирование с примерами приложений, 3-е изд. / Буч Градди, Максимчук Роберт А., Энгл Майкл У., Янг Бобби Дж., Коналлен Джим, Хьюстон Келли А.: Пер с англ. — М.: ООО «И.Д. Вильямс», 2010. — 720 с.
  • [UML-Fauler] Фаулер, М. UML. Основы / М. Фаулер, К. Скотт; пер. с англ. – СПб.: Символ – Плюс, 2002. – 192 с.
  • [UML_use-case] Основы UML — диаграммы использования (use-case).- URL: https://pro-prof.com/archives/2594
  • [UML_rubustness_diagrams] Процесс ICONIX. Диаграммы пригодности.- URL: https://pro-prof.com/archives/2723
  • [UML_class] Диаграммы классов UML. — URL: https://pro-prof.com/archives/3212
  • [UML_sequence] Основы UML. Диаграммы последовательности. — URL: https://pro-prof.com/archives/2769
  • [SOLID] SOLID принципы. Рефакторинг. — URL: https://pro-prof.com/archives/1914
  • [Singleton] Паттерн Singleton. Описание. Пример использования.- URL: https://pro-prof.com/archives/1546
  • [Rosenberg] Розенберг Д., Скотт К. Применение объектного моделирования с использованием UML и анализ прецедентов.: Пер. с англ. М.: ДМК Пресс, 2002

Добавить комментарий