Рассмотрев диаграмму вариантов использования, мчимся дальше, и на очереди у нас диаграмма классов — весьма полезная штука (а точнее модельки, которые с её помощью можно заколбасить).
Как и раньше, система обозначений:
Голубой цвет — то, что не продиктовано UML, а взято как полезный совет/правило из иных теорий и практик.
Курсив — примеры.
Диаграмма классов (UML Class Diagram) — это структурная диаграмма UML, которая показывает структуру чего-либо в терминах классов и отношений между ними. Ее изначальная цель в UML — показать структуру классов программной системы, построенной с применением объектно-ориентированного подхода (ибо UML, а он как раз про такой подход). Ну то есть буквально показать классы в программном коде — это популярный в объектно-ориентированной парадигме подход к структуризации программного кода, и вы увидите далее, что именно под это и заточены средства диаграммы, предлагаемые языком. Только вот а) аналитику это нафиг не надо, б) это слишком узкое применение для такой классной диаграммы. Поэтому аналитики решили извратить оригинальное понимание этой диаграммы и использовать для более полезных для себя задач.
Когда применять:
Типовые задачи для бизнес-аналитика две (при этом ими полет фантазии не ограничивается):
1) Модель бизнес-домена (Business Domain Model, BDM): модель, которая показывает бизнес-область (предметную область, домен) заказчика — ее структуру: субъекты, объекты, термины, понятия этой области, и как все это дело между собой связано. Применяется чаще всего на этапе изучения AS IS (дабы познать и систематизировать для себя и других область, которую мы будем автоматизировать с помощью решения). Но можно строить и для TO BE, т. е. показать, как будет выглядеть целевая область, когда мы в нее всунем нашу систему. 2) Модель данных — можно показать любой уровень работы с данными, в котором варится аналитик, но чаще всего это логическая модель данных. Вообще аналитики иногда упарываются и выделяют аж 3+ уровня проектирования данных, но я не вижу в этом смысла и предлагаю осмыслить только логический и физический. Логическая модель данных (Logical Data Model, LDM) показывает то, какой информацией будет оперировать система, и как эта информация между собой связана. Логический взгляд свободен от реализации (т. е. от того, как это задевелопят разработчики), и именно поэтому он идеально подходит для аналитика, который работает с требованиями, а не с их реализацией. Т. е. грубо говоря, аналитик такой моделью диктует, что, мол, в системе будут Товары, Каталоги, Пользователи, и вот как они между собой логически связаны (Товары входят в Каталоги, причем в Каталоге может быть не более 10 товаров). Будет ли эта информация храниться в системе в виде данных, как именно будет (база данных, текстовые файлы, кэш, зашитой в сам код) и как эти данные будут внутри физического хранилища организованы — все это аналитика не особо волнует. Это впоследствии решит архитектор, ну или системный аналитик, но я уже отмечал в предыдущей заметке, что такую вариацию мы тут не рассматриваем — мы говорим про IT бизнес-аналитиков, работающих с требованиями.
Модель бизнес-домена — это специфичный инструмент, используемый и любимый не всеми, плюс я уже разбирал эту штуку в первой части вот этой заметки (там про Ведьмака, кстати, есть, ага😉). Разбирать диаграмму классов мы будем на примере логической модели данных — это та модель, которую я советую аналитикам иметь всегда, когда для вашего решения актуально в принципе такое понятие как данные/информация, которыми решение оперирует. А если ещё и словарем данных её сопроводите, то вы вообще архимаг сотого левела в работе с требованиями. Подчеркну, что среди типовых упускаемых аналитиками вещей (по незнанию, неумению или нежеланию) работа с требованиями к данным и эта модель в частности — на моей практике одна из самых полезных в плане влияния на качество требований штук.
Элементы:
Есть всего один полезный для БА элемент — класс (Class). Класс — это строительный блок диаграммы, т .е. учитывая, что диаграмма показывает структуру чего-либо, класс — это элемент этой структуры. Показывается прямоугольником. Соответственно, рассматривая эту диаграмму в применимости к логической модели данных, классы в этой модели — это сущности/классы данных (блоки данных, которые состоят из более мелких кусочков данных).
Если вы не хотите детализировать то, из каких более мелких кусочков состоит блок, то класс — это просто прямоугольник с названием:
И тут стоит упомянуть, что в объектно-ориентированном подходе разделяют понятия "класс" и "объект" (именно поэтому в UML есть диаграмма классов и диаграмма объектов). Нам пригодится это для понимания того, что именно мы моделируем и как смотрим на содержимое диаграммы классов. Класс — это некий шаблон, абстракция. Объект — это отдельно взятый реальный экземпляр класса. Т. е. на диаграмме выше и в любой модели на основе диаграммы классов мы говорим, что наша система оперирует Товарами и Каталогами как понятиями в принципе — это классы. Когда юзеры начнут пользовать нашу систему, ее база данных заполнится объектами этих классов — десятками конкретных товаров и каталогов (каждый из которых будет соответствовать тому описанию эти классов, которое мы как аналитики заложим в модель). Имеем в виду разницу между этими понятиями, когда встретим эти термины далее в заметке.
В чуть более продвинутом варианте в классе могут быть детализирующие его атрибуты (Attributes). Атрибуты — это атомарные кусочки данных, которыми характеризуется сущность/класс данных. У объектов этих классов атрибуты будут иметь конкретные значения (например, у какого-то из объектов Наименование будет “Apple iPhone X 64GB”).
Рекомендации:
LDM: Когда вы нарезаете данные на классы и атрибуты, если данные не атомарны (т. е. внутри что-то еще более мелкое можно выделить), трактуйте это как класс данных; если же они атомарны (неделимы), то это уже атрибут.
LDM: Всегда показывайте атрибуты классов, если у вас нет словаря данных; иначе — опишите их там, а в модели не показывайте, дабы не дублировать требования и не усложнять себе их поддержку.
BDM: Нарезайте сущности и показывайте атрибуты по желанию — эта модель отражает ваш взгляд на предметную область и в первую очередь — для вашего же ее личного анализа.
Для атрибутов также полезно указывать их типы данных:
Рекомендации:
Типы данных в LDM также рекомендую оставлять на логическом (человеческом) уровне — например, Текст (а не Char (100)) или Целое число (а не Int (32)). В “технические” типы данных они превратятся в физической модели за авторством других людей, когда уже будет понятна физическая реализация этих данных.
Часто встречающиеся типы данных (но вообще их выбор и название — на ваше усмотрение): Текст, Число (целое, дробное), Логический (да/нет), Дата (и/или Время), Изображение, Видео.
Полезный тип данных: Перечисление (Enumeration) — это одно из известного заранее списка значений. В отличие от Текста, где значение атрибута может быть произвольным (не предсказуемым заранее), перечисление для любого объекта может принять только одно из допустимых значений: например, Статус будет всегда «Одобрен», «Отклонен» либо «Не проверен». Что именно это за значения, вы укажете в словаре данных или прочих поясняющих модель материалах.
Еще один полезный тип данных: отсылка на другой класс в виде его названия. И тут надо сфокусироваться и внимательно вчитаться, дабы мозг не сколлапсировал. Такой тип данных полезно применять, когда классы между собой связаны. Давайте представим, что у нас в системе есть Комментарии и Пользователи как сущности данных. Будут ли они как-то между собой связаны? Да, Пользователи оставляют Комментарии. Соответственно, у Комментария одним из атрибутов будет Автор. Какой у него тип данных? Первое, что логически приходит на ум — текст. Но красивее и полезнее было бы показать, что это не текст, а отсылка на какого-то Пользователя — на объект класса Пользователь, ведь по сути так и есть: любой Комментарий в виде Автора имеет какого-то Пользователя. И вот такую отсылку красиво как раз показать так, как описано выше. Т. е. не Автор: Текст как описание атрибута, а Автор: Пользователь (подразумевая, что это ссылка на объект класса данных Пользователь).
Связи:
Обобщение (Generalization)(иногда называют Наследованием). Если вы читали предыдущую заметку о диаграмме вариантов использования, вы с этим уже знакомы. В любом случае, продублирую: связь между элементами (классами в нашем случае), показывающая то, что в объектно-ориентированном подходе называют наследованием. Прямая линия с полым треугольником на конце, идущая от потомка к родителю.
Обобщение показывает, что класс-потомок Б — это дальнейшее уточнение родителя А, т. е. потомок конкретизирует родителя, проясняет, добавляет деталей. Иными словами, наследник — это то же самое, что и родитель, но с дополнительными деталями/спецификами.
У наследника — все те же свойства, что и у родителя (т. е. атрибуты в нашем случае), но могут добавляться и свои, новые.
Использование: ровно, как и описано — показать, что какие-то из классов могут иметь подвиды.
Две следующие связи очень схожи по своей сути: агрегация (aggregation)икомпозиция (composition). Обе связи показывают отношение «часть-целое». Переведу на наш сельский: включение одного элемента в другой. Если композиция или агрегация идет от А к Б, это означает, что класс А является составной частью класса Б. Т. е. направление можно читать как «входит в».
В чем разница между этими двумя связями? Визуально агрегация изображается сплошной линией с незакрашенным ромбом на конце, а композиция — с закрашенным. Так что красьте связи кисточкой аккуратно 🙂 Агрегация считается слабой связью, композиция — сильной. Если в случае концептуального разрушения объекта-родителя (применительно к вашей системе это может означать то, что вы сами решите: физическое удаление, архивирование, отмену и пр. вещи, которые считаются “уничтожением” класса) дочерний класс также “разрушается”, то связь сильная (композиция). Если же дочерний класс продолжает существовать, то связь слабая (агрегация).
Пример: Студент - Группа. Если представить, что студент может одновременно посещать и курс по бизнес-анализу, и курс по UX, и прочие тренинги от некоего учебного центра, то вопрос таков: при расформировании группы по бизнес-анализу теряют ли смысл/“уничтожаются” ли ее Студенты? Нет, студентом учебного центра человек остается, и он все еще может быть частью группы по UX, а может и не быть частью никакой группы — просто быть в базе учебного центра как прошлый или будущий Студент. Поэтому здесь уместна агрегация.
Пример: Курс учебного центра – Учебный центр. Если учебный центр расформируется, такого понятия как Курс учебного центра не станет. Все курсы также концептуально уничтожатся. Это сильная связь — композиция.
Использование: ровно, как и описано — показать, что класс является частью другого класса.
Ассоциация (Association). У связи то же оформление, что и для диаграммы вариантов использования: сплошная линия, которая может быть направленной (с открытой стрелкой) и нет. Ассоциация — это любое смысловое или структурное отношение между классами. Мы рассматриваем ее в последнюю очередь, потому что использование таково: если между классами на ум приходит какая-то связь, но ее нельзя описать с помощью наследования, агрегации или композиции — используйте ассоциацию.
Рекомендация: в описанных моделях для БА всегда делайте ассоциации направленными и всегда их именуйте (подписывайте названием). Без этого понять, что означает ассоциация в каждом конкретном случае (учитывая ее крайне абстрактное значение) невозможно.
У связей также могут быть (и весьма-таки рекомендуется, чтобы были) множественности (Multiplicity). Множественность показывает, какое количество объектов класса привязано к связи.
Давайте разберем такой пример:
Читаем по направлениям связей, которые имеют негласное название “Входит в” и учимся задавать правильные вопросы для определения циферок:
1) 1..* Товаров входят в 1 Каталог.
1.1) Чтобы поставить цифры у Товара: Какое количество Товаров может название связи (в нашем текущем случае это “Входить”) в 1 Каталог? Пытаемся сразу думать интервалом — от-до. От 1 (потому что мы решили, что не может быть Каталогов без Товаров — пустые каталоги на сайте нам важно не допускать) и до бесконечности (показывается звездочкой) (потому что верхнего лимита нет).
1.2) Чтобы поставить цифры у Каталога: какое количество Каталогов может название связи в обратном направлении (в нашем случае это “Содержать”) 1 Товар? Снова пытаемся думать интервалом. От 1 (потому что если Товар есть, то он обязан принадлежать какому-то каталогу) и до 1 (то есть интервала у нас не получилось: более, чем одному Каталогу Товар не может принадлежать — таковы у нас, допустим, требования).
2) 1..4 Товара могут входить в 0..* Заказов.
2.1) Какое количество Товаров может входить в 1 Заказ? К примеру, есть у заказчика такое ограничение: пользователи в одном заказе могут заказать не более 4-х товаров. Ок, от 1 (Заказа без Товаров не должно быть) до 4.
2.2) Частью какого количества Заказов может быть один Товар? Может быть ни разу не заказан (от 0), а может быть заказан много (*) раз.
Рекомендации:
LDM: Обязательно применяйте множественности для всех связей, кроме Обобщения. Множественности — источник очень полезных вопросов клиенту и бизнес-правил, которые должны найти отражение в системе.
BDM: Применение на ваше усмотрение, т. е. в тех случаях, где видите полезность.
Давайте вернемся к примеру, который мы начали изучать в предыдущей заметке про диаграмму вариантов использования. Напомню его условие:
У нас есть система видеохостинга — сильно покоцанный и местами неудобный аналог YouTube. Что в нем есть:
Регистрация и вход/выход
Просмотр (через ленту на домашней странице) и заливка видосиков
Комментирование и модерирование комментов
Добавление видосиков в плейлист Watch Later
Построим его логическую модель данных:
Давайте разберем интересные моменты:
В системе будут следующие данные (классы): Пользователи (людям надо как-то регистрироваться и логиниться впоследствии), Видео, Комментарии.
У Пользователей среди прочих атрибутов должна быть Роль, т. к. у нас пользователи разных категорий (как минимум есть модераторы). Это будет перечисление, т. к. роль должна быть значением из списка заранее известных.
У Видоса помимо прочих атрибутов будет Автор, который является отсылкой на класс Пользователь — мы выше рассматривали такой подход. У Коммента то же самое.
Каждый Пользователь может являться Автором (загружать в систему) от 0 до кучи Видосов. Аналогично и для Комментов.
Отдельно мы подсветили, что подтипом Пользователя являются Модераторы, которые могут быть связаны с Комментом и иной связью — вынесением решения по нему. Множественности этой связи показывают, что каждый Коммент должен отмодерировать 1 Модератор (но может никто и не модерировать — Коммент будет висеть, ожидая решения).
Каждый Коммент — это часть какого-то Видоса, причем композиционная (при удалении видео все комментарии также снесутся).
Добавлена интересная связь: агрегация от Коммента к Комменту. И тут снова надо напрячь мозх. Она показывает, что Коммент может быть частью другого Коммента — этим мы покажем такую штуку, как дерево комментариев (Комменты-реплайи под Комментами). Это также отражено в том, что у Коммента как класса есть атрибут Родительский коммент — как раз для таких случаев. Возникнет вопрос: а почему агрегация? А потому что в нашей парадигме мы решили, что удаление Коммента-родителя не должно приводить к удалению дочерних Комментов-реплайев: пусть они показываются, а вместо родителя будет на висеть “Комментарий удален”. Разберем также циферки: каждый комментарий (каждый объект класса Коммент) может иметь от 0 до * дочерних Комментов (то есть у него может быть много реплайев, а может и не быть в принципе); каждый комментарий может быть реплайем для 0..1 Коммента (то есть любой произвольно взятый объект класса Коммент — это либо реплай на что-то родительское, либо самостоятельный комментарий, не связанный с другими).
Пара продвинутых аспектов диаграммы (ими UML Class Diagram не исчерпывается — есть еще много интересного, хотя едва ли для аналитика):
В более полном варианте в классе могут быть также операции, плюс ряд дополнительных маркеров для уже описанного. Аналитику это вряд ли пригодится, но на всякий случай вкратце о них, чтобы умели читать и понимали, куда думать, если увидите на диаграммах:
До названия атрибута может идти так называемый модификатор доступа: минусик, плюсик или некоторые иные значения. В разработке (для классов программного кода) это определяет, виден ли атрибут внешним объектам снаружи класса или нет. Если упрощенно и на пальцах, то возьмем Студент как класс: такой его атрибут как Оценка виден снаружи (например, тренеру) — собственно, тренером он и устанавливается. Его модификатор доступа будет public (”плюс”). Если взять атрибут Уверенность, то это, скорее, внутренний атрибут, который не виден никому, кроме самого текущего объекта — его модификатор доступа private (”минус”).
Кроме атрибутов в отдельном отсеке могут также быть Операции (Operations). Опять-таки, это для классов программного кода: либо операции, которые можно выполнить над классом, либо те, которые объекты этого класса сами могут выполнять. У операций также есть модификаторы доступа, типы данных, которые они возвращают и (в скобках после названия) данные, которые эти операции могут принимать на вход.
Классы также могут быть абстрактными. Опять-таки, мы рассматривали уже это в предыдущей заметке для юз кейсов, но повторюсь: у абстрактных элементов (классов в нашем случае) название элемента пишется курсивом. Что это означает: абстрактный элемент не является “реальным”, и нужен он лишь для каких-то побочных целей. Типовым вариантов применения абстрактных классов является использование их в комбинации с обобщением.
Читается это так: все товары в нашей системе — это только телевизоры. То есть реально в качестве данных в системе будут только телевизоры.Товар — это всего-лишь обобщение телевизоров в нечто более абстрактное на будущее — когда появятся еще и Телефоны, и прочие Товары.
Типовые ошибки: Вначале совершим их все на одной диаграмме (можно, кстати, потренироваться и попробовать обдумать каждую до того, как повалят спойлеры):
Неверные направления связей
С ассоциациями все довольно просто, если пользоваться рекомендацией и всегда их именовать — по направлению чтения. А вот с остальными связями можно и запутаться. Обобщение рисуется от потомка к родителю и читается как "обобщается в", "абстрагируется в". Композиция и агрегация также рисуются от дочернего класса ("частного") к родительскому ("целому") и читаются "входит в".
Путаница между обобщением и агрегацией/композицией.
Обобщение/наследование — это А является дальнейшим уточнением Б. Агрегация/композиция — это А входит в Б как составная часть. Между этими понятиями большая разница. В примере выше Модератор не может являться частью Пользователя. Модератор — это подвид Пользователя.
LDM: путаница между "система хранит" и "система оперирует"
Когда я говорю "путаница", я имею в виду: 1) если вы не знаете, какой будет физическая реализация данных, т. е. не знаете, будет ли храниться кусок информации в БД или иных местах, используйте термин "оперирует" в построении вашей LDM: система оперирует информацией X. 2) если вы чуть более технически подкованный аналитик и точно знаете/узнали, что как информация будет сохраняться, а что — нет, используйте термин "хранит". Пример из картинки: считать ли Email (отсылаемые системой письма-уведомления юзерам) частью LDM? Наиболее простой вариант, если вы без понятия, считать или нет, — включить это в LDM как информацию, которой система оперирует. Разработчики сами потом решат, что с этими письмами делать, причем, скорее всего, совместно с вами. Продвинутый вариант, если вы качнулись в своем познании мира: "я знаю, что эти письма частью нашей БД не будут, а потому не буду включать их в модель". Или "я знаю, что все письма надо бы сохранить для истории/логов, а потому включу их в модель". Используйте этот вариант только, если уверены в своих умозаключениях касательно того, как это будет реализовано (или если уже проконсультировались с разрабами).
LDM: скатывание в физическую модель данных
Чем логическая модель данных отличается от физической, мы уже рассмотрели. Не включайте в вашу модель айдишники (ID) записей, пометки primary и foreign keys, промежуточные таблицы для хранения "многое-ко-многим", технические типы данных и прочие подобные вещи, которыми ваш технический бэкграунд "засорил" вам мозг. Это все актуально только, если физической реализацией будет, например, реляционная БД и только если этот ваш подход является оптимальным. У меня, например, есть бэкграунд разработчика, но даже если я знаю, что, например, БД у нас будет в виде MySQL, я сознательно поостерегусь принимать решение о том, что будет ID для каждого класса, какие будут таблицы в БД и о прочих подобных вещах. Я должен осознавать, что в команде есть эксперты, более профессионально заточенные на принятие таких решений. И если не в моей зоне ответственности проектировать БД для системы (у явно выраженного системного аналитика может быть иная ситуация), я не должен этого делать и налагать своей неаккуратностью лишние ограничения на креатив того, кто этим будет заниматься.