Функциональная архитектура цифровых продуктов, часть 2

Cценарии, уровень абстракции, функциональная иерархия, итерационность и взаимосвязи функций.

7-8 минут на прочтение
Функциональная архитектура цифровых продуктов, часть 2

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

Вместо вступления

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

На самом деле, цель этого цикла проста: показать возможности ФА и привести несколько примеров её формирования. Я не покажу ни одного «универсального» решения. Многие схемы и таблицы будут так или иначе взяты из реальной документации, со всеми присущими ей проектными ограничениями.

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

Этапы

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

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

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

Теория

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

Уровень абстракции

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

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

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

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

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

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

Пластичная функциональная архитектура

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

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

Начало работ

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

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

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

Практика

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

Функциональная иерархия

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

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

Да, в навигационной модели тоже могут быть разделы «регистрация», «настройки», «профиль», «новости», но и только.

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

В примере выше функциональный раздел «Логин и регистрация» включает в себя дочерние разделы:

  1. Регистрация.
  2. Аутентификация (логин).
  3. Восстановление доступа.
  4. Авторизация (проверка прав).

В свою очередь, внутри подраздела «Аутентификация» на клиенте могут находиться уже конкретные функции:

  1. Отображение окна логина.
  2. Заполнение формы.
  3. Валидация формы.
  4. Отправка формы на сервер.
  5. Обработка ответа сервера.
  6. Показ сообщений (например, об ошибках).

При этом та же функция «валидации формы» чаще всего включает дочерние функции, вроде «проверки корректности e-mail», «проверки сложности пароля» и «проверки на обязательное поле».

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

Действия пользовательские и системные

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

Проще всего выявлять конкретный перечень функций продукта через его функциональные сценарии. Они часто строятся на основе детального CJM, user flow или аналогов, но включают в себя отнюдь не только пользовательские маршруты. Смотрите.

Компоненты

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

Типы функций

Кроме того, все функции можно условно поделить на несколько типов:

  • пользовательские (в схеме логина ниже представлены синими блоками);
  • системные (белые блоки);
  • проверка условий (ромбы);
  • негативные (с красной обводкой);
  • позитивные (с зелёной обводкой).

Функциональный сценарий

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

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

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

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

Взаимосвязи и общие функции

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

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

  • «Главная» (список всех новостей).
  • «Категория» (список новостей, относящихся к определённой тематике).

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

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

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

Кроме того, некоторые функции могут блокировать выполнение других, или быть их «предвестниками», но об этом мы поговорим позже.

В следующей серии

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

Павел Шерер, продюсер IT-решений

Канал в Telegram

Раньше тут были комментарии, но я решил не плодить сущности. Есть что сказать или спросить — велкам в телеграм-канал:

Обсудить в Telegram