Модель прецедентов

Как уже говорилось, сценарии в архитектурной модели 4+1 Филиппа Крухтена занимают центральное место. Однако набор сценариев не сразу обретает полноту и постоянство. а развивается по мере развития архитектуры системы.

Сегодня перед нами стоит относительно простая задача - создать модель прецедентов и отобразить её с помощью одноименной диаграммы UML.

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

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

Собственно, диаграмма прецедентов приведена в начале этой статьи. Обратить внимание надо на следующие вещи.

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

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

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

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

В-третьих, надо помнить об отличиях связей между прецедентами.

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

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

"Расширение" (extend) - это вызов, выполняемый по определённому условию. Связь показывает, что некоторый прецедент расширяет другой прецедент при выполнении заданного условия. Стрелка на диаграмме всегда направлена от расширяющего прецедента к расширяемому.

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

Ещё один момент заключается в том, что я указал оба пакета на одной диаграмме. Это сделано исключительно для наглядности данного материала. В реальности может потребоваться создавать большой набор диаграмм прецедентов. Обычно я на первой диаграмме отражаю иерархию акторов, а далее для каждого функционального пакета формирую свою диаграмму прецедентов. Т.е. в нашем случае диаграмм было бы минимум три: диаграмма акторов, диаграмма пакета Accounts и диаграмма пакета ServiceLog. Но из-за небольшой величины модели в данном конкретном примере я решился объединить все прецеденты на одной диаграмме.

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