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

7-8 минут на прочтение
Функциональная архитектура

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

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

§ Общие функции

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

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

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

§ Выявление

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

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

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

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

§ Пример

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

§ Разница подходов

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

два подхода к функциональному проектированию
Пример разницы подходов к функциональному проектированию

Это сделано не случайно, а в качестве иллюстрации к основному посылу всего цикла:

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

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

§ Зависимые функции

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

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

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

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

Выявить взаимосвязь функций — значит правильно расставить приоритеты реализации

§ Иерархическая зависимость

Вот смотрите. Допустим, функция отправки SMS используется нами лишь в одном месте: когда пользователь подтверждает номер телефона. Мы совершенно уверены, что больше никто и нигде не будет отправлять SMS в нашем проекте. Это значит, что отправка SMS — не общая функция, и приступить к её разработке можно будет, когда мы доберёмся до, собственно, подтверждения номера.

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

§ Линейная зависимость

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

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

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

Пример запрета на предоставление email при регистрации через ВКонтакте

Конечно, это всё решаемо. Поля в БД можно добавить, регистрацию переписать. Только зачем, если можно с самого начала сделать правильно? Спроектировать сразу обе, передать разработчикам и сказать, что пока нужно делать только одну?

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

§ Серверные и клиентские функции

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

Снова приведу пример. Вот есть у вас общая функция валидации с переданным параметром «email». Что она должна уметь делать? Проверять корректность введённых или переданных данных — и всё, вроде. Но нет.

§ Клиент

На клиенте (например, в браузере) она должна проверять корректность введённых данных и:

§ Сервер

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

И это — только банальная валидация. Представьте, насколько сложно на таком уровне грамотно спроектировать даже привычную нам функцию регистрации?

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

Перекладывать проектирование клиент-серверного взаимодействия на обычных программистов — это всё равно что предоставить строителям возможность определять технические характеристики многоэтажного дома.

§ Итог

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

Кроме того, некоторые свои мысли на этот (и не только) счёт я планирую закидывать вам на обсуждение в свой tg-канал, присоединяйтесь.

Павел Шерер
Павел Шерер

Продюсер, аналитик, продуктовый дизайнер IT-решений, Telegram-канал

Поделиться:

Предыдущая статья Почему на сложных проектах необходим IT-продюсер

Комментарии (0)

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

Нет соединения с сервером.Сервер получил неверные данные, попробуйте еще раз.
Войдите, чтобы комментировать статью: