воскресенье, 31 октября 2010 г.

Проектирование: как выполнять декомпозицию задачи?

Нередко формулировка задачи, полученная от заказчика, вызывает у проектировщика шок:

  • "Спроектируйте графический редактор".
  • "Спроектируйте игру для девочек 4 – 8 лет".
  • "Спроектируйте GPS-навигационную систему для мобильного телефона".

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

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

  1. выполнить декомпозицию задачи на подзадачи;
  2. оценить объём полученных подзадач;
  3. составить план работы, упорядочив подзадачи во времени и распределив их между участниками команды.

Рассмотрим эту процедуру на примере проектирования графического редактора.


Шаг 1. Определение назначения системы
Укажите назначение проектируемой системы.

Примечание: Необходимо избегать размытых формулировок вида: "Система для хранения данных".

ПРИМЕР. Назначение графического редактора – создание/редактирование поздравительных открыток.

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

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

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

ПРИМЕР. Построим модель функционирования графического редактора.

На первой итерации она будет выглядеть так:

А) в виде списка:

  1. Загрузка документа (из файла).
  2. Редактирование документа.
  3. Сохранение документа (в файле).

Б) в виде рисунка:



На второй итерации детализируем функции "загрузка" и "сохранение", т.к. это сделать проще всего.

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

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




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



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

Далее, заметим, что устройство ввода тоже влияет на документ не напрямую, а через различные GUI-элементы, такие как: меню, тулбары, selection'ы, различные модификаторы (например, для масштабирования фигуры используется рамка с точками, за которые можно потянуть мышью).

Эти GUI-элементы вызывают команды редактирования, которые уже непосредственно изменяют документ.

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

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

Шаг 3. Составление списка задач
Составьте список задач. Для его составления следует использовать модель функционирование системы.

При этом нужно руководствоваться такими правилами:

  1. Если действие сформулировано чётко и понятно, то оно переносится в список задач без изменений.
  2. Если действие трудно назвать или его название выглядит слишком общо, то следует проверить, не является ли это действие преобразованием из одного в другое (например, преобразование команд от устройства ввода в команды от элементов GUI).

ПРИМЕР. Для графического редактора получаем:

  1. Редактирование документа (== составить список операций над документом и его элементами).
  2. Растеризация документа.
  3. Загрузка документа из файла.
  4. Сохранение документа в файле.
  5. Преобразование документа из неродного формата в родной.
  6. Преобразование документа в неродной формат из родного.
  7. Преобразование действий пользователя в команды от устройства ввода.
  8. Преобразование команд от устройств ввода в команды от элементов GUI.
  9. Преобразование команд от элементов GUI в команды редактирования.

Шаг 4. Объединение задач в группы
Объедините задачи в группы, если:
  • задачи похожи по смыслу;
  • задачи противоположны друг другу.
Например, задача "загрузка" противоположна по смыслу задаче "сохранение". Эти задачи можно объединить в группу "загрузка/сохранение".

ПРИМЕР. После группировки получаем такой список задач:

  1. Редактирование.
  2. Растеризация.
  3. Загрузка/сохранение.
  4. Преобразование из формата в формат.
  5. Преобразование действий пользователя в команды от устройства ввода.
  6. Преобразование команд от устройств ввода в команды от элементов GUI.
  7. Преобразование команд от элементов GUI в команды редактирования.

Шаг 5.  Упорядочение задач во времени и пространстве
Расположите задачи в порядке, необходимом для получения решения. Если задача позволяет решить другую задачу, то она должна быть расположена раньше неё. Если задача не может быть решена без решения другой задачи, то она должна быть расположена позже неё.

ПРИМЕР. Самой главной задачей в нашем примере является задача "редактирование". Чтобы выполнить остальные задачи, нам нужно знать либо перечень операций над документом, либо структуры данных, которые будут использованы для представления документа. Поэтому задачу "редактирование"  расположим в самом начале.

Следующей по важности задачей является задача "преобразование действий пользователя в команды от устройств ввода". Эту задачу мы ставим раньше задачи 6 ("преобразование команд от устройств ввода в команды от элементов GUI ") и задачи 7 ("преобразование команд от элементов GUI в команды редактирования "), т.к. вид и функции GUI-элементов нередко определяются возможностями устройств ввода.

На пятое место ставим сразу три задачи:

  1. загрузка и сохранение;
  2. преобразование из/в;
  3. растеризация.

Эти задачи могут выполняться параллельно.

В виде графической схемы план разработки графического редактора выглядит так:



Задачи, которые могут выполняться параллельно, можно делегировать сразу нескольким разработчикам. Более сложные задачи (например, "редактирование") следует отдавать более опытным разработчикам.

Примечание: После составления схемы плана разработки можно ещё раз взглянуть на задачи и, если получится, объединить некоторые из них в группы. В нашем случае задачи "преобразование действий пользователя в команды от устройств ввода" и "преобразование команд от устройств ввода в команды GUI" можно объединить в задачу "проектирование ввода". А задачу "преобразование команд от GUI в команды редактирования" можно назвать по-другому – "проектирование GUI".

С учётом изменений получится:

Резюме
В данном посте предложен алгоритм, который позволяет:

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

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

11 комментариев:

  1. Хотя здесь нет никаких противоречий с вашим подходом, я всегда начинаю декомпозицию с определения "действующих лиц" системы (Actors) и основной последовательности действий (Use Cases / Workflow). А еще в моем анализе обязательно присутствует шаг "Попытка упростить модель"...

    ОтветитьУдалить
  2. План вида Requirements Model, Use Case Model, Activity Diagram, Domain Model для меня является привычным и проверенным средством разобраться в задаче. Сия статья в принципе описывает то же самое но без точных названий, принятых в мировой практике.

    ОтветитьУдалить
  3. 1) Google не находит такого понятия, как Requirements Model. Можете убедиться сами: http://www.google.ru/search?source=ig&hl=ru&rlz=&q=Requirements+Model&btnG=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA+%D0%B2+Google&aq=&oq=

    2) Activity Diagram - это лишь определенный вид диаграммы, с помощью которой можно описать некий процесс. А не руководство по описанию процесса.

    3) Use Case Model в данной статье не рассматривалась и будет рассматриваться позже, когда речь зайдет о проектировании отдельных функциональных модулей.

    4) Про Domain Model тоже скажу, но значительно позже. Здесь она тоже не рассматривалась.

    Спасибо!

    ОтветитьУдалить
  4. неплохая статья получилась, можно рекомендовать
    но удалите, плиз теги, вида
    в IE они точно отображаются

    ОтветитьУдалить
  5. опа, а теги сюда не попали, сорри, за ложнокоммент
    теги вида: <!--[endif]-->

    ОтветитьУдалить
  6. Прочитал предыдущий пост: http://askofen.blogspot.com/2010/10/blog-post_17.html

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

    В идеале же все цели (не требования) не только должны быть явно записаны, но и должен быть критерий достижения этих целей.

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

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

    ОтветитьУдалить
  7. В этом посте, конечно же, не описан процесс дизайна. Более-менее разумное описание займёт несколько постов, которые я размещу попозже.

    Здесь я лишь рассказывал о том, как выполнить предварительную оценку проекта: прикинуть, какие будут задачи, и в каком порядке они будут решаться.

    Кратко: проектировщик прикинул, что надо будет реализовать модули редактирования, загрузки и сохранения, фильтры для конвертации в различные форматы, а также - спроектировать ввода (выполнить эргономическое проектирование) и UI. Вот и всё.

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

    ОтветитьУдалить
  8. Автор предлагает задачу проектирования сверху вниз, используя функциональный подход:
    "Шаг 2. Описание модели функционирования системы
    Опишите то, как будет функционировать система. Для этого необходимо указать основные действия системы и упорядочить их во времени.

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

    ОтветитьУдалить
  9. В том-то и дело, что сначала полезнее прикинуть функции и то, в каком порядке они будут выполняться. И только затем - думать над тем, каким типам данных их стоит делегировать.

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

    ОтветитьУдалить
  10. Спасибо за Вашу статью! Она натолкнула меня на пару очень полезных мыслей :)

    ОтветитьУдалить