<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
><channel><title>Технический дизайн | Павел Шерер</title><atom:link href="https://sherer.pro/blog/category/technical-design/feed/" rel="self" type="application/rss+xml" /><link>https://sherer.pro/blog/category/technical-design/</link><description>Продюсер, аналитик, продуктовый дизайнер IT-решений</description><lastBuildDate>Wed, 10 Dec 2025 13:39:50 +0000</lastBuildDate><language>ru-RU</language><sy:updatePeriod>hourly</sy:updatePeriod><sy:updateFrequency>1</sy:updateFrequency><generator>https://wordpress.org/?v=6.9.4</generator><image><url>https://sherer.pro/content/uploads/2018/01/cropped-favicon-60x60.jpg</url><title>Технический дизайн | Павел Шерер</title><link>https://sherer.pro/blog/category/technical-design/</link><width>32</width><height>32</height></image> <item><title>Информационная архитектура: сущности (практика, vol.2)</title><link>https://sherer.pro/blog/informacionnaya-arhitektura-sushchnosti-vol-3/</link><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Thu, 30 Oct 2025 12:35:32 +0000</pubDate><category><![CDATA[UX/UI]]></category><category><![CDATA[Аналитика]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[аналитика]]></category><category><![CDATA[гайд]]></category><category><![CDATA[информационная архитектура]]></category><guid isPermaLink="false">https://sherer.pro/?p=4735</guid><description><![CDATA[<p>Третья часть про сущности в ИА: фиксация свойств, паттерны их моделирования и схематизация итогового результата.</p><p>Запись <a href="https://sherer.pro/blog/informacionnaya-arhitektura-sushchnosti-vol-3/">Информационная архитектура: сущности (практика, vol.2)</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p>В прошлой статье мы разобрали первые пять этапов проработки информационных сущностей. Теперь давайте поговорим об оставшихся двух: фиксации свойств и итоговой схематизации.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Если эта первая статья, с которой вы знакомитесь с информационной архитектурой, примите мои соболезнования: вам может быть непонятно. Рекомендую идти в начало цикла.</p></blockquote><p>В одной из предыдущих статей у нас был простенький <a href="https://sherer.pro/blog/informacionnaya-arhitektura-sushchnosti-vol-1/#3-2-primer-opisaniya-svoystv">пример</a> фиксации свойств. Теперь мы его расширим. Но сначала давайте выясним, каким образом вообще моделируются свойства информационных сущностей.</p><h2 class="wp-block-heading">Паттерны моделирования свойств</h2><p>Как мы уже знаем, все свойства можно поделить на несколько типов: базовые, ссылочные, составные, вычисляемые, технические и ограничительные. И если с базовыми всё плюс-минус понятно, то что делать с остальными — отнюдь не всегда ясно. </p><p>Да и с базовыми, если честно, порой могут возникнуть проблемы. Например, у нас есть свойство «Цвет». Оно простое: ни на кого не ссылается, это не таксономия — это, скорее, словарь, сквозное свойство. Как с ним быть? Или с полем «Описание» — оно тоже простое, но активно участвует в индексации и поиске, об этом тоже нужно подумать.</p><p>Давайте разбираться.</p><h3 class="wp-block-heading">Нормализованные словари</h3><p>Их ещё называют «справочниками», а разработчики — ENUM, перечислением. Мы их уже касались вскользь. Поля такого типа могут принимать только значения из конкретного, определённого перечня.</p><p><strong>Правила</strong>:</p><ul class="wp-block-list"><li>Значения — всегда конечные и контролируемые, добавление новых происходит только по процессу ревью.</li><li>Поддерживают алиасы/синонимы для поиска, но в БД хранится нормализованное значение (ключ).</li><li>Если значения словаря локализуются (переводятся на другие языки), то внутренний ключ остаётся неизменным.</li></ul><p><strong>Пример</strong>:</p><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><p>У товара есть поле <code>brand</code>, которое ссылается на запись из справочника брендов. В справочнике брендов есть конечный перечень записей обо всех брендах, представленных в системе.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba5766e8&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba5766e8" class="wp-block-image aligncenter size-full wp-lightbox-container"><img fetchpriority="high" decoding="async" width="1446" height="560" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2025/11/ia-entities-7.png" alt="" class="wp-image-4833" style="object-fit:cover" srcset="https://sherer.pro/content/uploads/2025/11/ia-entities-7.png 1446w, https://sherer.pro/content/uploads/2025/11/ia-entities-7-1048x406.png 1048w, https://sherer.pro/content/uploads/2025/11/ia-entities-7-768x297.png 768w" sizes="(max-width: 1446px) 100vw, 1446px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure></div><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><p>Фильтр «Бренд» в каталоге работает по полю <code>brand</code> товара. В текстовом поиске же мы учитываем не только прямое название бренда, но и алиасы/синонимы. </p><p>Например, при вводе в поле поиска «Nike», «nike» и «Найк» система понимает, что это одно и то же — и выдаёт одинаковый результат.</p><p>Справочник брендов:</p><figure class="wp-block-table"><table><thead><tr><th>Ключ</th><th>Алиасы (в нижнем регистре)</th></tr></thead><tbody><tr><td>adidas</td><td>adidas, адидас, addidas, adiddas, adidac, adibas</td></tr><tr><td>nike</td><td>nike, найк, наик, nake, niks, nikee</td></tr><tr><td>reebok</td><td>reebok, рибок, reeboc, reebokk, rebok, ribok</td></tr></tbody></table></figure></div><p><strong>Риски</strong>:</p><ul class="wp-block-list"><li>Избыточная детализация (когда в словаре много синонимов или значений) может привести к «шуму» в фасетах. Например, когда в словаре «Цвет» появляются сотни почти одинаковых значений: алый, бордо, вишнёвый, винный и тп.</li><li>Из-за отсутствия владельца, ответственного за словарь, повышается риск появления дублей и рассинхронизации.</li><li>Использование ENUM в БД для часто меняющихся списков почти всегда усложняет разработку и деплой.</li></ul><h3 class="wp-block-heading">Ссылочные поля</h3><p>Поля, указывающие на другие сущности через внешние ключи. Главное их отличие от <strong>нормализованных словарей</strong> в том, что <strong>ссылочные поля</strong> связывают сущности между собой и с другими объектами (например, с терминами таксономий). Тогда как значения ENUM из предыдущего примера не являются отдельными объектами, они просто строчка в фиксированном списке.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Ссылочные поля — это «мостики» между сущностями: товар связан с категорией, тегами, продавцом, заказами. Благодаря им карточка не живёт в вакууме, а встраивается в общую систему.</p></blockquote><p><strong>Правила</strong>:</p><ul class="wp-block-list"><li>Для «один‑ко‑многим» 1:N (категория → товары) у товара хранится ссылка на свою категорию. </li><li>Для «многие‑ко‑многим» M:N (товар ↔ тег) связи хранятся отдельно. </li><li>Важно продумать, что происходит при удалениях: кого переносим, кого архивируем, а где просто убираем связь.</li></ul><p><strong>Пример</strong>:</p><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><p>У товара есть одна «Категория», но множество «Тегов». </p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba576cb0&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba576cb0" class="wp-block-image aligncenter size-full wp-lightbox-container"><img decoding="async" width="1446" height="1310" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2025/11/ia-entities-8.png" alt="" class="wp-image-4841" srcset="https://sherer.pro/content/uploads/2025/11/ia-entities-8.png 1446w, https://sherer.pro/content/uploads/2025/11/ia-entities-8-1048x949.png 1048w, https://sherer.pro/content/uploads/2025/11/ia-entities-8-768x696.png 768w" sizes="(max-width: 1446px) 100vw, 1446px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p>Если удалить тег — товар останется. Если удалить категорию — нужно заранее решить, куда товар переедет.</p></div><p><strong>Риски</strong>:</p><ul class="wp-block-list"><li>Непродуманные правила удаления ведут к потере данных или поломке логики. Я видел случаи, когда при удалении рубрики в CMS, из базы данных удалялись десятки статьей и сотни комментариев. </li><li>Когда связи между сущностями организованы неэффективно, системе приходится делать много лишних запросов, фильтровать данные или пересчитывать агрегаты на лету. Это замедляет скорость работы продукта.</li><li>Если связи построены небрежно, при массовых обновлениях могут случиться зависания или сбои. Например, любое изменение категории или продавца может вызвать ошибки в отображении связанных с ними карточках.</li></ul><h3 class="wp-block-heading">Вычисляемые поля</h3><p>Это свойства, которые не вводятся вручную, а считаются системой на основе других данных: средний рейтинг, количество просмотров, популярность, конверсия. Они помогают понять, насколько «живой» или успешный объект, не требуя ручного обновления.</p><p>Вычисляться такие поля могут «на лету», либо храниться в БД или кэше. </p><p><strong>Правила</strong>:</p><ul class="wp-block-list"><li>Нужно договориться, откуда берутся исходные данные и как часто обновляется результат — в реальном времени или каждый час, день, неделю. </li><li>Исходные данные и вычисленные результаты хранятся отдельно, чтобы не потерять возможность пересчёта. </li><li>Важно фиксировать формулы расчётов и их владельца — того, кто отвечает, если метрика «поплыла». </li><li>Полезно также указывать время последнего обновления, чтобы понимать, насколько данные свежие.</li></ul><p><strong>Пример</strong>:</p><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><p>В карточке показываем «4.6 из 5» и «124 отзыва». Эти значения не вводятся вручную — они считаются из всех отзывов с округлением до одной десятичной. Популярность товара рассчитывается как комбинация просмотров и добавлений в корзину за последние 7 дней.</p></div><p><strong>Риски</strong>:</p><ul class="wp-block-list"><li>«Расползание» цифр: в карточке одно, в отчёте другое. На момент написания статьи такое можно увидеть на Хабре, там два разных счётчика просмотров: один доступный всем, другой — только авторам.</li><li>Неочевидные формулы, спрятанные в глубинах кода. Показатели меняются, команда не понимает причин.</li><li>Слишком частые пересчёты. Система вычисляет показатели слишком часто, нагружая серверы без нужды. Или наоборот — слишком редкие обновления, из‑за которых пользователи видят устаревшие данные.</li></ul><h3 class="wp-block-heading">Диапазоны и интервальные фасеты</h3><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Кто-то считает <strong>интервальные фасеты</strong> лишь подмножеством <strong>вычисляемых полей</strong>, но я решил выделить их отдельно. Они чаще всего встречаются и имеют несколько специфичных свойств.</p></blockquote><p>Фильтры по числам и датам помогают пользователю быстрее находить подходящие товары. Мы редко ищем вещь за точно 2&nbsp;570 рублей — обычно хотим что-то «в районе двух‑трёх тысяч». Поэтому интерфейс должен позволять задавать диапазон значений: цену «от-до», вес или рейтинг. Пользователь мыслит не конкретными числами, а удобными «вилками» — например, «до 1000 рублей» или «от 4 звёзд и выше».</p><p><strong>Правила</strong>:</p><ul class="wp-block-list"><li>В системе хранится точное значение, а пользователю показываются готовые «умные» интервалы (например, на основе реального распределения цен). Если меняем цену, то принадлежность к интервальным полям изменяется автоматически.</li><li>Правила границ (включительно/исключительно) и округления задаются явно. Чтобы не было непонятно, входит «1000» в «до 1000» или в «1000-5&nbsp;000».</li><li>Должны быть продуманы правила обработки пустых/нулевых значений. Например, «цена не указана» — это отдельная группа, она не попадает в интервалы.</li></ul><p><strong>Пример</strong>:</p><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><p>Фильтр «Цена» может выглядеть так: готовые варианты «до 999&nbsp;рублей», «1000–4999&nbsp;рублей», «5000+», плюс ручной ввод. </p><p>Для сортировки и страниц используется точная цена из карточки. При этом явно указано, что «до 999&nbsp;рублей» — верхняя граница включительно, «1000–4999&nbsp;рублей» — обе границы включительно, а товары без цены попадают в отдельный блок «цена не указана».</p></div><p><strong>Риски</strong>:</p><ul class="wp-block-list"><li>Для денег и размеров нужно быть аккуратными с единицами и валютами. Если смешать сумму и валюту, это может плохо кончиться: фильтр по цене может стать бесполезен. </li><li>Непродуманные интервалы дают пустые результаты и раздражают пользователей. </li></ul><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Важный момент: некоторые фреймворки и базы данных умеют совершать очень быстрые арифметические операции, включая поиск по диапазону. Поэтому зачастую диапазоны и интервальные фасеты могут оказаться излишними. Уточняйте у разработчиков и архитекторов.</p></blockquote><h3 class="wp-block-heading">Составные и полуструктурированные поля</h3><p>Когда у сущности много разнородных характеристик (например, у товара есть изображения, материалы, дополнительные свойства) — удобнее собрать их в «пакеты». То есть не разбивать свойство на десятки отдельных полей, а объединить в один структурированный набор. Это помогает избежать перегруженности данных и сделать архитектуру более гибкой.</p><p>Во <a href="https://sherer.pro/blog/informacionnaya-arxitektura-primer-i-tipizaciya/">второй статье</a> цикла я писал о <em>сильной и слабой типизации</em>. Так вот составные поля — отличных пример признака слабой типизации.</p><p><strong>Правила</strong>:</p><ul class="wp-block-list"><li>Те свойства, которые часто используются для фильтрации, сравнения или сортировки (ширина, вес, цена), лучше выделить в отдельные простые поля. Остальное можно хранить в составе набора.</li><li>Важно сразу договориться о едином формате (например, JSON или таблица), чтобы не получилось сотни уникальных схем в разных объектах.</li><li>Также стоит помнить об ограничении глубины вложенности — чем проще структура, тем меньше ошибок при обновлениях.</li></ul><p><strong>Пример</strong>:</p><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><p>Для товара может быть важно хранить габариты в отдельных свойствах, так как по ним может осуществляться фильтрация. А вот данные изображения можно хранить в <strong>составном свойстве</strong>, потому что по отдельности их запрашивать не станут.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba57756e&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba57756e" class="wp-block-image aligncenter size-full wp-lightbox-container"><img decoding="async" width="1446" height="982" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2025/11/ia-entities-9.png" alt="" class="wp-image-4855" srcset="https://sherer.pro/content/uploads/2025/11/ia-entities-9.png 1446w, https://sherer.pro/content/uploads/2025/11/ia-entities-9-1048x712.png 1048w, https://sherer.pro/content/uploads/2025/11/ia-entities-9-768x522.png 768w" sizes="(max-width: 1446px) 100vw, 1446px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p>Таким образом, мы не делаем отдельные поля для тех свойств, которые используются только вместе.</p></div><p><strong>Риски</strong>:</p><ul class="wp-block-list"><li>Перестарались с «пакетами» — становится проблематично искать или менять параметры. </li><li>Если структура слишком сложная или неоднородная, новые данные перестают помещаться в общую логику, а интерфейс не справляется с отображением. </li><li>Есть риск дублирования свойств: если одно и то же поле хранится и внутри набора, и отдельно, это будет сбивать аналитику и создаст противоречия.</li></ul><h3 class="wp-block-heading">Поисковые поля</h3><p>Это поля, которые напрямую влияют на то, как пользователи находят нужный элемент через поиск. Именно они определяют качество и релевантность результатов. Обычно сюда входят: название, краткое описание, артикул и так далее. </p><p><strong>Правила</strong>:</p><ul class="wp-block-list"><li>Поиск должен «думать как человек»: учитывать разные формы слов («купить» и «покупка»), синонимы («ноутбук» и «laptop») и популярные опечатки. Именно поисковые поля должны лучше всего индексироваться.</li><li>Полезно задавать разный «вес» полям — название важнее описания, а описание важнее технических характеристик. </li><li>Важно поддерживать актуальный словарь синонимов и опечаток: он должен пополняться на основе статистики реальных поисковых запросов.</li></ul><p><strong>Пример</strong>:</p><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><p>Покупатель вводит «кеды», и поиск показывает ему как «кеды», так и «sneakers», даже если запрашиваемое слово вообще на другом языке.</p><p>Название и категория влияют сильнее, чем описание, поэтому карточки с точным совпадением появляются первыми. </p><p>Словарь запросов обновляется по статистике — если пользователи всё чаще ищут «скайшуз» или «кроссовки на платформе», система быстро учится понимать эти слова.</p></div><p><strong>Риски</strong>:</p><ul class="wp-block-list"><li>Сложные запросы без ограничений по размеру выдачи запросто могут «положить» поиск, перегрузив систему. </li><li>Если переусердствовать с синонимами, поиск начинает показывать нерелевантные результаты, будет слишком много «шума». </li><li>Несвоевременно обновляемый словарь приводит к тому, что люди начнут искать новые термины, которых в базе нет — и, не получив результатов, посчитают, что товара нет вовсе.</li></ul><h3 class="wp-block-heading">Технические поля</h3><p>Это служебные поля, которые фиксируют то, что пользователям знать не обязательно. Например: когда и кем запись создана/изменена, какой у неё статус, флаги индексации. Такие данные помогают поддерживать порядок, находить ошибки и понимать, как объект живёт во времени. Без них часто невозможно разобраться, кто и что сделал, особенно если с системой работает большая команда.</p><p>Очень часто при проработке информационной архитектуры про служебные поля забывают. Это приводит к тому, что в процессе реализации появляются самые разнообразные костыли, которые сильно мешают развитию системы.</p><p><strong>Правила</strong>:</p><ul class="wp-block-list"><li>Типовые значения указываются в едином формате: например, время — только в UTC+0. Это позволяет потом не путаться при реализации и анализе.</li><li>Важно заранее договориться о понятных статусах сущностей и допустимых переходах между ними, фиксировать автора, источник и причину изменений. </li><li>Желательно хранить историю правок хотя бы ключевых сущностей, чтобы при спорных ситуациях можно было восстановить ход событий. </li></ul><p><strong>Пример</strong>:</p><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><p>У сущности «Товар» есть поле «Статус» в виде нормализованного словаря, ENUM: «черновик → на проверке → опубликован → в архиве». </p><p>Система показывает, кто и когда вносил правки, а также из какой системы пришли изменения. Например, если товар был обновлён автоматически из ERP, это видно в истории. А комментарий «обновлены фотографии по новому каталогу» помогает понять контекст изменения.</p></div><p><strong>Риски</strong>:</p><ul class="wp-block-list"><li>«Прыгающие» даты из‑за разных часовых поясов, непонятные или дублирующие статусы, невозможность определить автора изменений. </li><li>Потеря истории при импорте или миграции: если данные перезаписать без сохранения временных меток, аналитика и отчёты станут недостоверными. </li></ul><h3 class="wp-block-heading">Ограничительные поля</h3><p>Это поля, которые определяют рамки доступности сущности: кто может её видеть, с ней взаимодействовать, где и при каких условиях. Они регулируют поведение системы и помогают избегать нарушений — например, продаж алкоголя несовершеннолетним или показ товаров, запрещённых к экспорту в конкретной стране. Также <strong>ограничительные поля</strong> фиксируют бизнес‑ограничения и ролевую модель вроде «только для админов» или «данные предоставляются по запросу».</p><p><strong>Правила</strong>:</p><ul class="wp-block-list"><li>Разделяйте «бизнес‑ограничения» (что показываем и кому) и «технические» (что разрешает система). Должно быть прозрачно, почему сущность или операция скрыта или недоступна. </li><li>Желательно сопровождать такие поля пояснениями — что именно ограничивает доступ и где отображается уведомление пользователю. </li><li>Все ограничения должны иметь понятные статусы (например, «активно», «ожидает проверки», «временно снято с продажи») и быть управляемыми, а не жёстко зашитыми в код.</li></ul><p><strong>Пример</strong>:</p><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><p>В e-com для разных товаров могут быть установлены разные ограничения: «показывать только B2B», «не продавать в определённых странах», «ограничение по возрасту 18+».</p><p>В CRM доступ ко всем сделкам может быть доступен только пользователям с отмеченным полем «Полный доступ».</p></div><p><strong>Риски</strong>:</p><ul class="wp-block-list"><li>Скрытые ограничения ломают пользовательский опыт. Если это не предусмотрено специально, всегда сообщайте об ограничениях тем, кого они касаются. </li><li>Разные правила на фронте и бэкенде почти всегда приводят к несоответствиям. Лучше делать основную логику на сервере, а клиенту (браузеру или приложению) доверять только визуальное отображение.</li><li>При массовых изменениях может возникнуть путаница. Например, когда правила блокировок не синхронизированы между странами или каналами продаж.</li></ul><h2 class="wp-block-heading">Собственно, фиксация</h2><p>Теперь, когда с паттернами стало немного понятнее, давайте попробуем всё это зафиксировать. </p><p>Для каждого свойства сущности я советую создавать структурированный паспорт, чтобы команда чётко и однозначно понимала его назначение, формат и роль в продукте. Такой подход помогает избежать путаницы, ускоряет разработку и облегчает коммуникацию между дизайнерами, аналитиками и разработчиками.</p><p>Ниже я буду рассказывать про каждый аспект фиксации свойств и приводить пример в виде таблицы. Но так как формат блога не способствует созданию больших (и читаемых) таблиц, то я буду приводить только тот фрагмент, который относится к разделу. В конце статьи вы найдёте полные примеры в виде файлов.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Местами кое-что может показаться вам избыточным — и, скорее всего, так оно и есть. То, что может быть полезным в крупных продуктах с множеством ролей и подсистем, в небольших проектах порой только разводит бюрократию.</p><p></p></blockquote><h3 class="wp-block-heading">Основная информация</h3><p>Опишите, как поле называется в системе (код), какой у него тип данных (текст, число, дата и тп), обязательно ли оно для заполнения, приведите примеры. Добавьте пояснение, зачем это поле нужно, какую задачу решает.</p><p>Пример основной информации о сущности «Товар»:</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Название</th><th>Код</th><th>Тип данных</th><th>Обяз.</th><th>Пример</th><th>Описание</th></tr></thead><tbody><tr><td>ID</td><td><code>id</code></td><td><code>int</code></td><td>Да</td><td>10245</td><td>Уникальный идентификатор записи, обязательное поле, помогает системе отличать товары друг от друга</td></tr><tr><td>Название</td><td><code>title</code></td><td><code>text</code></td><td>Да</td><td>Кроссовки Nike Air Zoom</td><td>Отображает название товара в каталоге, поиске и карточке товара</td></tr><tr><td>Цена</td><td><code>price</code></td><td><code>float</code></td><td>Да</td><td>1499</td><td>Хранит цену товара для отображения, сортировки и операций</td></tr><tr><td>Категория</td><td><code>category</code></td><td><code>ref</code></td><td>Да</td><td>Обувь</td><td>Определяет, к какому разделу относится товар</td></tr><tr><td>Цвет</td><td><code>color</code></td><td><code>enum</code></td><td>Нет</td><td>чёрный</td><td>Хранит название цвета, используется для фильтрации и отображения вариаций</td></tr></tbody></table></figure></div><p>Обратите внимание на тип данных: в различных системах типы данных могут обозначаться по-разному, при работе с IA желательно придерживаться какого-то единого, понятного всем, формата. Конкретно здесь:</p><ul class="wp-block-list"><li><code>int</code> — простое целое число;</li><li><code>text</code> — текст без явных ограничений в типе данных (не <a href="https://en.wikipedia.org/wiki/Varchar">varchar</a>, например);</li><li><code>float</code> — число с плавающей точкой (3.23);</li><li><code>ref</code> — ссылка на другую сущность, reference;</li><li><code>enum</code> — его вы уже знаете, нормализованный словарь.</li></ul><h3 class="wp-block-heading">Источник и валидация</h3><p>Откуда берётся значение и как проверяется. Укажите, поступает ли значение от пользователя, из импорта, внешней системы или вычисляется автоматически. Опишите правила проверки (валидации): допустимые диапазоны, форматы, обязательные символы. Также стоит указать, что происходит, если значение не проходит проверку (ошибка, предупреждение, автозамена).</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Название</th><th>Источник</th><th>Валидация</th></tr></thead><tbody><tr><td>ID</td><td>Генерируется автоматически системой</td><td>Проверяется на уникальность</td></tr><tr><td>Название</td><td>Вводится контент-менеджером</td><td>Проверяется на длину (не более 120 символов) и отсутствие запрещённых слов</td></tr><tr><td>Цена</td><td>Берётся из каталога поставщика</td><td>Проверяется на диапазон 1-999999, если меньше или больше — система выдаёт ошибку</td></tr><tr><td>Категория</td><td>Выбирается из справочника категорий</td><td>Если категория не найдена, выводится предупреждение, товар не заводится в систему</td></tr><tr><td>Цвет</td><td>Выбирается из списка доступных цветов</td><td>Проверяется по справочнику цветов и допустимым синонимам</td></tr></tbody></table></figure></div><h3 class="wp-block-heading">Индексация и поиск</h3><p>Как используется в поиске, фильтрах и аналитике. Опишите, участвует ли поле в поиске или фасетах, влияет ли оно на фильтрацию, сортировку и аналитику. Укажите, какие сценарии зависят от него (поиск по названию, сортировка по цене, фильтр по цвету). Добавьте, нужна ли регулярная переиндексация и как часто.</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Название</th><th>Индексация и поиск</th></tr></thead><tbody><tr><td>ID</td><td>Не участвует в поиске, используется для связи записей и аналитики</td></tr><tr><td>Название</td><td>Основное поисковое поле, влияет на релевантность результатов</td></tr><tr><td>Цена</td><td>Фасетное поле, используется для сортировки и фильтров «от‑до»</td></tr><tr><td>Категория</td><td>Участвует в навигации и фасетах; влияет на группировку и хлебные крошки</td></tr><tr><td>Цвет</td><td>Фасетное поле, помогает пользователям фильтровать товары по цвету</td></tr></tbody></table></figure></div><h3 class="wp-block-heading">Владение и контекст</h3><p>Кто отвечает за поле и где оно используется. Назначьте владельца поля — человека или роль, которая следит за его актуальностью (категорийный менеджер, контент-редактор, разработчик). Опишите, в каких интерфейсах поле отображается и кто взаимодействует с ним.</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Название</th><th>Ответственный</th><th>Где используется</th></tr></thead><tbody><tr><td>ID</td><td>Ответственность разработки</td><td>Используется системой, не отображается пользователям</td></tr><tr><td>Название</td><td>Контент-редактор</td><td>Отображается в каталоге, на карточке товара и в результатах поиска</td></tr><tr><td>Цена</td><td>Категорийный менеджер</td><td>Отображается в каталоге, корзине, аналитических отчётах</td></tr><tr><td>Категория</td><td>Маркетолог или контент-менеджер</td><td>Влияет на навигацию и структуру сайта, отображается в каталоге и карточке товара</td></tr><tr><td>Цвет</td><td>Контент-менеджер</td><td>Отображается в фильтрах и карточках товаров</td></tr></tbody></table></figure></div><h3 class="wp-block-heading">Жизненный цикл и обновление</h3><p>Как часто меняется поле. Разделите поля по типу обновления: редактируемые пользователем, автоматически пересчитываемые системой, импортируемые из внешних источников. Укажите частоту проверки актуальности и правила пересмотра.</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Название</th><th>Кем и как часто обновляется</th></tr></thead><tbody><tr><td>ID</td><td>Не меняется после создания</td></tr><tr><td>Название</td><td>Может редактироваться контент-редактором при обновлении ассортимента</td></tr><tr><td>Цена</td><td>Обновляется автоматически при изменении прайса, раз в сутки</td></tr><tr><td>Категория</td><td>Изменяется редко, при реструктуризации каталога</td></tr><tr><td>Цвет</td><td>Обновляется при появлении новых вариаций</td></tr></tbody></table></figure></div><h3 class="wp-block-heading">Нормализация и перевод значений</h3><p>Как поддерживается единообразие. Опишите, как поле очищается и приводится к общему формату: регистр, язык, синонимы, стандарты записи. Если данные многоязычные — уточните правила перевода. Добавьте примеры типичных ошибок и корректного вида.</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Название</th><th>Форматирование</th></tr></thead><tbody><tr><td>ID</td><td>Форматируется как число без ведущих нулей</td></tr><tr><td>Название</td><td>Очищается от лишних пробелов и специальных символов</td></tr><tr><td>Цена</td><td>Хранится как число в одной валюте (например, в рублях)</td></tr><tr><td>Категория</td><td>Нормализуется по справочнику категорий</td></tr><tr><td>Цвет</td><td>Приводится к единому значению («чёрный» = «black» = «черный»)</td></tr></tbody></table></figure></div><h3 class="wp-block-heading">Таблица свойств (Entity Attribute Matrix)</h3><p>В итоге для каждой сущности у вас появится единая таблица, где перечислены все поля с их типом, источником, обязательностью, правилами и владельцем. Она должна стать единым источником правды для всей проектной команды: от дизайнеров с аналитиками до разработчиков с архитекторами. Такая таблица поможет поддерживать актуальность архитектуры данных и синхронизировать работу API, интерфейсов и аналитики.</p><p>Обязательно ведите версионирование: когда и кем изменялась таблица, что именно было изменено. Это позволит, при необходимости, провести трассировку изменений (например, при расхождении информационной архитектуры с программной реализацией). </p><p>Ну и напоследок, как и обещал, полная таблица свойств из этой статьи:</p><div class="wp-block-file"><a id="wp-block-file--media-0fe6a47b-97b1-48ce-92ce-d15ae38b29d1" href="https://sherer.pro/content/uploads/2025/11/Primer-opisaniya-informacionnoy-sushchnosti-Tovar.xlsx">Пример описания информационной сущности Товар</a><a href="https://sherer.pro/content/uploads/2025/11/Primer-opisaniya-informacionnoy-sushchnosti-Tovar.xlsx" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-0fe6a47b-97b1-48ce-92ce-d15ae38b29d1">Скачать</a></div><p>Не переключайтесь, в цикле будет ещё как минимум две статьи.</p><p>Запись <a href="https://sherer.pro/blog/informacionnaya-arhitektura-sushchnosti-vol-3/">Информационная архитектура: сущности (практика, vol.2)</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded></item><item><title>Информационная архитектура: сущности (практика, vol.1)</title><link>https://sherer.pro/blog/informacionnaya-arhitektura-sushchnosti-vol-2/</link><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Tue, 28 Oct 2025 14:18:44 +0000</pubDate><category><![CDATA[UX/UI]]></category><category><![CDATA[Аналитика]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[аналитика]]></category><category><![CDATA[гайд]]></category><category><![CDATA[информационная архитектура]]></category><guid isPermaLink="false">https://sherer.pro/?p=4601</guid><description><![CDATA[<p>Вторая часть про сущности в ИА, теперь с упором на практику: от сбора данных до выявления связей и таксономий.</p><p>Запись <a href="https://sherer.pro/blog/informacionnaya-arhitektura-sushchnosti-vol-2/">Информационная архитектура: сущности (практика, vol.1)</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p>В предыдущей <a href="https://sherer.pro/blog/informacionnaya-arhitektura-sushchnosti-vol-1/">статье</a> цикла мы разобрались, что такое информационные сущности, какие бывают типы свойств и базовые связи, прошлись по таксономиям и классификациям. Теперь давайте приступим к более практической части. </p><h2 class="wp-block-heading">Небольшое вступление</h2><p>На самом деле, работу над информационной архитектурой не всегда можно унифицировать, загнать в стандарты и фиксированные этапы. Иногда вы будете что-то упускать и потом возвращаться, это нормально. А часто, напротив, какие-то ответы уже есть в проектной документации — и тогда нужно просто собрать всё в одном месте и раскрасить оставшиеся «белые пятна».</p><p>Рассматривайте шаги, описанные ниже, исключительно как советы опытного архитектора, и ни в коем случае не как чёткие инструкции, которым надо слепо следовать. Более того, в реальных продуктах я сам не всегда всё это делаю — просто потому что не всегда в этом есть необходимость.</p><h2 class="wp-block-heading">Подготовка: контекст и границы</h2><p>Многие советы из этого раздела так или иначе перекликаются с обычной работой над продуктом (формирование границ, фиксация метрик и прочее). Если у вас уже есть эти данные, прекрасно, переиспользуйте их. Если же нет, то это может стать неплохим поводом подсветить слабые места продуктового подхода.</p><h3 class="wp-block-heading">Цель продукта</h3><p>Начните с формулировки основной пользовательской ценности и трёх–пяти задач, ради которых продукт вообще существует. Например: «заказать доставку еды за 3 клика», «найти нужную деталь по артикулу», «сравнить тарифы по параметрам».</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>В сложных продуктах может быть сильно больше 3-5 ключевых задач. В этом случае рекомендую декомпозировать его на логические или функциональные компоненты — и в каждом из них уже выводить свои цели и задачи.</p></blockquote><p>Для каждой задачи задайте измеримые KPI: «среднее время до результата (time‑to‑task)», «конверсия в целевое действие», «доля успешных сценариев» и подобные.</p><h3 class="wp-block-heading">Границы домена</h3><p>Составьте карту предметной области: какие объекты и операции в неё входят, а какие находятся за её пределами. Например, для маркетплейса внутрь попадают товары, продавцы, категории и заказы, а расчёт комиссий или логистика могут быть вынесены в соседние сервисы. Это защитит команду от размывания фокуса и неконтролируемого расширения требований.</p><h3 class="wp-block-heading">Источник истины</h3><p>Определите, где хранятся все артефакты ИА: таблицы сущностей, словари терминов, фасеты, схемы связей и тд. Лучше всего, если это будет ваша внутренняя вики, типа <a href="https://www.atlassian.com/software/confluence" target="_blank" rel="noreferrer noopener nofollow">Confluence</a>. Для диаграмм и визуальных схем можете использовать <a href="https://www.drawio.com" target="_blank" rel="noreferrer noopener nofollow">draw.io</a> (благо, он встраивается почти куда угодно) или <a href="https://www.figma.com/figjam/" target="_blank" rel="noreferrer noopener nofollow">FigJam</a>.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Важно, чтобы был один актуальный источник, а не десяток несвязанных и противоречивых документов.</p></blockquote><p>Назначьте владельцев этих артефактов и регламент обновления: кто, как часто и по какому триггеру правит данные, кому сообщается об изменениях. </p><h3 class="wp-block-heading">Согласование терминологии</h3><p>Создайте единый глоссарий терминов, где каждое понятие имеет согласованное определение. Например: в интерфейсе, в аналитике и в БД термин «пользователь» должен значить одно и то же, а не три разных понятия: аккаунт, клиент и автор. Я встречал системы, где одна и та же информационная сущность в одном месте называлась «пользователь», в другом «клиент», а в третьем «посетитель». Не надо так.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Хорошо организованный глоссарий устраняет двусмысленности и предотвращает непонимание между аналитиками, дизайнерами и разработчиками. </p></blockquote><h2 class="wp-block-heading">Декомпозиция: перечень сущностей</h2><p>После того как определены контекст и границы продукта, наступает этап декомпозиции — разбиения системы на отдельные сущности. На этом шаге мы превращаем абстрактные понятия («контент», «пользователи», «данные») в конкретные элементы модели, с которыми можно работать, описывать их свойства и связи. </p><p>Цель здесь простая: увидеть полную картину того, из чего состоит продукт и как эти части взаимодействуют между собой.</p><h3 class="wp-block-heading">Определение типов</h3><p>Пройдитесь по всем сценариям вашего продукта и выпишите <strong>устойчивые типы информации</strong>: «товар», «категория», «метка/тег», «пользователь», «заказ», «корзина», «страница» и тп. Добавьте сюда <strong>вспомогательные</strong> и <strong>производные </strong>сущности, которые не видны пользователю напрямую, но обеспечивают работу системы — например, «транзакция», «сессия», «ревизия».</p><p>Скорее всего, на этом этапе вы упустите какие-то объекты, ничего страшного. Как я уже говорил, работа над IA — не всегда строго последовательный процесс. Вернётесь, как найдёте ошибку.</p><h3 class="wp-block-heading">Описание сущности</h3><p>Для каждой сущности кратко опишите: </p><ul class="wp-block-list"><li><strong>роль</strong> (что делает эта сущность, зачем она нужна);</li><li><strong>жизненный цикл</strong> (от создания до удаления или архивации);</li><li><strong>точки появления в интерфейсе</strong> (можно прям названия экранов);</li><li><strong>обязательные операции</strong> (создать/редактировать/найти/связать). </li></ul><p>Тут важно не уходить в дебри и не погружаться в детальное проектирование. Вот вам пара простых примеров: </p><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><p><strong>Товар</strong></p><p><strong>Роль:</strong> бизнес-сущность, описывает продаваемую единицу ассортимента и используется в каталоге, карточке товара и отчётности.</p><p><strong>Жизненный цикл:</strong> создаётся продавцом или контент-менеджером, редактируется при обновлении данных, архивируется при снятии с продажи.</p><p><strong>Точки появления:</strong> каталог, результаты поиска, карточка товара, блоки рекомендаций.</p><p><strong>Операции:</strong> создать, редактировать, связать с категорией и тегами, добавить в акцию или архивировать.</p></div><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><p><strong>Пользователь</strong></p><p><strong>Роль:</strong> системная сущность, представляет зарегистрированного клиента или участника системы.</p><p><strong>Жизненный цикл:</strong> создаётся автоматически при регистрации или импорте из CRM, обновляется при изменении профиля, может быть деактивирован или удалён.</p><p><strong>Точки появления:</strong> личный кабинет, заказы, отзывы, админ-панель.</p><p><strong>Операции:</strong> регистрация, авторизация, редактирование профиля, привязка к заказам или организациям.</p></div><h3 class="wp-block-heading">Проверка на дубликаты</h3><p>Проверьте, нет ли <strong>дублирующих или пересекающихся сущностей</strong>: если у вас есть и «автор», и «пользователь», возможно, это одно и то же с разными контекстами. Тогда их лучше объединить в одну сущность и добавить поле «роль» или «тип».</p><h3 class="wp-block-heading">Закрепление ответственных</h3><p>Для сложных систем составьте <strong>матрицу принадлежности</strong>: кто владелец данных по каждой сущности (продукт, контент, аналитика), где они хранятся и как обновляются. Опять же, не уходите в детали, здесь важно оставаться на высоком уровне абстракции.</p><p>Вот простенький пример такой матрицы для e-com:</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Сущность</th><th>Владелец</th><th>Хранилище</th><th>Канал обновления</th><th>Комментарий</th></tr></thead><tbody><tr><td>Товар</td><td>Продакт-менеджер,<br>Контент-отдел</td><td>CMS</td><td>Импорт из ERP, ручное редактирование</td><td>Данные синхронизируются ежедневно</td></tr><tr><td>Категория</td><td>Контент-отдел</td><td>CMS</td><td>Ручное обновление, ревью раз в квартал</td><td>Согласование с SEO и маркетингом</td></tr><tr><td>Пользователь</td><td>Аналитика</td><td>CRM</td><td>Регистрация, API</td><td>Обновление при каждом входе</td></tr><tr><td>Заказ</td><td>Финансы</td><td>ERP</td><td>Автоматическая синхронизация</td><td>Источник для отчётности</td></tr><tr><td>Тег</td><td>Контент-отдел</td><td>CMS</td><td>Ручное добавление, периодическая чистка</td><td>Проверка дубликатов перед публикацией</td></tr></tbody></table></figure></div><p>Такая таблица помогает выстроить процессы и избежать ситуаций, когда разные отделы изменяют одни и те же сущности без синхронизации.</p><h3 class="wp-block-heading">Выработка метрик</h3><p>Дополнительно укажите <strong>метрики для каждой сущности</strong> — показатели того, что она используется и актуальна. Вот несколько примеров:</p><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><p><strong>Доля заполненных полей</strong> — процент карточек, где заполнены все обязательные атрибуты (например, описание, фото, цена, категория).</p><p><strong>Частота обращений</strong> — сколько раз сущность запрашивается пользователями или системами в сутки/неделю (например, просмотры карточек товаров или загрузка профилей).</p><p><strong>Связность</strong> — среднее количество связей с другими сущностями (например, число тегов на статью, товаров в категории).</p><p><strong>Актуальность данных</strong> — доля сущностей, обновлённых за последние N дней.</p><p><strong>Ошибки и дубли</strong> — количество некорректных или дублирующих записей в системе.</p><p><strong>Использование в сценариях</strong> — сколько продуктовых сценариев или отчётов опираются на эту сущность.</p></div><p>Эти показатели помогут оценивать зрелость и здоровье информационной архитектуры, выявлять запущенные участки и планировать развитие модели данных.</p><h2 class="wp-block-heading">Классификация: таксономии, уровни и операции</h2><p>После того как сущности выделены и описаны, важно понять, как они группируются и взаимодействуют в структуре продукта. Этот этап превращает «список объектов» в осмысленную систему: мы определяем, какие сущности являются базовыми разделами, какие служат фильтрами или связками, и как пользователь перемещается между ними. </p><p>Классификация помогает превратить набор данных в удобную навигацию, а архитектуру — в понятную карту продукта.</p><h3 class="wp-block-heading">Типы таксономий</h3><p>Разведите <strong>иерархические</strong> (категории, разделы, рубрики) и <strong>плоские</strong> (теги, темы, ключевые слова) таксономии. Определите, какие сущности формируют структуру навигации, а какие служат только для связей или фильтрации. </p><p>Пример, по традиции, из e-com:</p><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><p>Категории формируют иерархическое дерево меню, которое задаёт маршрутизацию и навигацию: «Одежда» → «Женская» → «Блузки».</p><p>Теги «скидка», «новинка», «распродажа» или «эксклюзив» применяются как плоские фильтры — независимые признаки, не влияющие на структуру меню, но позволяющие пользователю собирать нужные срезы данных.</p><p>В результате одна и та же карточка товара может одновременно находиться в нескольких категориях и иметь множество тегов, отражающих её свойства или состояние.</p></div><h3 class="wp-block-heading">Уровни сущностей</h3><p>Назначьте <strong>уровень сущности</strong> — высокий, средний или низкий:</p><ul class="wp-block-list"><li>Высокие уровни — это корневые разделы и хабы, которые формируют скелет навигации и точку входа в систему. </li><li>Средние уровни — это страницы‑коллекции, объединяющие однотипные объекты. </li><li>Низкие уровни — карточки конкретных объектов, где реализуются операции и принимаются решения. </li></ul><p>Пример распределения сущностей по уровням:</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Уровень</th><th>Сущность</th><th>Тип задач пользователя</th><th>Тип контента</th></tr></thead><tbody><tr><td>Высокий</td><td>Каталог, Блог, Документация</td><td>Обзор, переход к разделу</td><td>Навигационный</td></tr><tr><td>Средний</td><td>Категория, Раздел, Проект</td><td>Сравнение, поиск</td><td>Коллекционный</td></tr><tr><td>Низкий</td><td>Товар, Статья, Пользователь</td><td>Изучение, действие, покупка</td><td>Объектный</td></tr></tbody></table></figure></div><p>Такое разделение помогает проектировать маршрут от главной страницы к объекту и обратно, управлять глубиной дерева и оптимизировать путь пользователя.</p><h3 class="wp-block-heading">Группы, фасеты и фильтры</h3><p>Сформируйте <strong>операционные группы</strong>, в которых будет понятно, где живёт каждая сущность (в каком разделе, хабе или подсистеме), какие фасеты с фильтрами к ней применимы и какие действия доступны. Это создаёт связь между информационной архитектурой и интерфейсом.</p><p>Пример разницы между статьёй и товаром:</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Сущность</th><th>Раздел</th><th>Фасеты и фильтры</th><th>Основные операции</th></tr></thead><tbody><tr><td>Товар</td><td>Каталог</td><td>Бренд, Цена, Размер, Цвет</td><td>Купить, Сравнить, Добавить в избранное</td></tr><tr><td>Статья</td><td>Медиа</td><td>Рубрика, Теги, Дата</td><td>Читать, Поделиться, Добавить в подборку</td></tr></tbody></table></figure></div><h3 class="wp-block-heading">Приоритеты и наследование</h3><p>Добавьте <strong>описание приоритетов и наследования таксономий</strong>: что отображается в интерфейсе, что используется для аналитики и SEO, а что служит внутренней классификацией. </p><p>Например:</p><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><p>Для корпоративного портала «Тип документа» может быть фасетом (для фильтрации и аналитики), а «Отдел» — иерархической категорией (для навигации и прав доступа).</p><p>В коммерции «Категория» и «Подкатегория» определяют URL и хлебные крошки, но не отображаются в фасетах, где остаются только фильтры «Бренд», «Цена», «Материал».</p></div><p>Обязательно фиксируйте ещё и правила наследования: категория → подкатегория → объект. В интерфейсе это проявляется как автоматическое применение фильтров при переходе на нижний уровень.</p><h3 class="wp-block-heading">Управление обновлениями</h3><p>Зафиксируйте <strong>методы актуализации</strong> таксономий: кто отвечает за создание новых терминов, их перевод, синхронизацию и архивирование. Опишите процессы ревизии, чтобы не допустить появления дубликатов или устаревших меток. </p><p>Например, контент‑отдел добавляет новые категории раз в квартал, SEO‑отдел проводит сверку алиасов, а аналитика проверяет наличие связанных данных. </p><p>Для крупных продуктов полезно ввести аудит изменений с фиксированием автора, даты пересмотра и краткого описания причины (например, «слияние категорий», «переименование фасета»).</p><h2 class="wp-block-heading">Выявление связей: кардинальности и контексты</h2><p>В теоретической части цикла мы <a href="https://sherer.pro/blog/informacionnaya-arhitektura-sushchnosti-vol-1/#4-svyazi-mezhdu-sushchnostyami">говорили</a> о кардинальностях, хранении, сценариях и индексах. Теперь давайте взглянем на то, как к этом прийти. </p><h3 class="wp-block-heading">Кардинальности</h3><p>Определение кардинальности было в прошлой статье, подробно на термине останавливаться не стану. Добавлю только, что для каждой связи крайне желательно описать:</p><ul class="wp-block-list"><li>с чем осуществляется связь,</li><li>тип связи, </li><li>глубину вложенности и </li><li>пример (при необходимости).</li></ul><p>Вот как это может выглядеть для сущности «товар»:</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Связан с</th><th>Кардин.</th><th>Глубина вложенности</th><th>Описание связи и кардинальности</th></tr></thead><tbody><tr><td>Категория</td><td>1:N</td><td>2-3 уровня</td><td>Иерархическая таксономия. Один товар принадлежит одной конечной категории, но категория содержит множество товаров. В родительской категории находятся все товары дочерних.</td></tr><tr><td>Тег</td><td>M:N</td><td>1 уровень</td><td>Плоская таксономия. Один товар может иметь несколько тегов, каждый тег применяется к нескольким товарам.</td></tr><tr><td>Заказ</td><td>M:N</td><td>1 уровень</td><td>Связанная сущность. Один товар может входить во множество заказов. В одном заказе может быть несколько товаров.</td></tr><tr><td>Отзыв</td><td>1:N</td><td>1 уровень</td><td>Связанная (дочерняя) сущность. У одного товара может быть множество отзывов.</td></tr><tr><td>Пользователь</td><td>M:N</td><td>1 уровень</td><td>Связанная сущность. Пользователь может взаимодействовать с несколькими товарами (просмотры, избранное, история покупок). С одним товаром могут взаимодействовать множество пользователей.</td></tr></tbody></table></figure></div><p>Такая таблица может стать отличным началом для дальнейшей проработки связей.</p><h3 class="wp-block-heading">Контекстные связи</h3><p>Речь о связях вроде «похожие», «часто вместе», «варианты», «альтернативы» и так далее. Они используются в карточках, рекомендациях и аналитике пользовательских сценариев. Например, в e-commerce это может быть «с этим товаром часто покупают», а в медиа — «похожие статьи» или «продолжение серии».</p><p>Важно разделять логические связи (на уровне ИА) и вычисляемые (на уровне аналитики и рекомендательных алгоритмов).</p><p>Вот тот же пример, но с добавленными контекстными связями. Здесь и дальше я буду удалять лишние столбцы для читаемости, но в реальной таблице их лучше бы оставлять (или делать перекрёстные таблицы):</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Связан с</th><th>Контекст</th><th>Тип контекста</th></tr></thead><tbody><tr><td>Категория</td><td>«Товары в этой категории» — аналогичные товары из категории.</td><td>Логический</td></tr><tr><td>Тег</td><td>«Похожие товары» — товары с пересекающимися тегами.</td><td>Логический</td></tr><tr><td>Заказ</td><td>&#8212;</td><td>&#8212;</td></tr><tr><td>Отзыв</td><td>&#8212;</td><td>&#8212;</td></tr><tr><td>Пользователь</td><td>«Вам понравится» — на основе поведенческих данных и предыдущих заказов.</td><td>Вычисляемый</td></tr></tbody></table></figure></div><p>Разумеется, эта табличка сильно упрощает реальность. Даже в простеньком интернет-магазине контекстная связь «Похожие товары» будет, скорее, <em>вычисляемой</em> на основе многих факторов, а не только тегов.</p><h3 class="wp-block-heading">Ключевые и вариативные связи</h3><p>Выделите два типа связей: </p><ul class="wp-block-list"><li><strong>ключевые (частые) связи</strong> — они должны быть быстрыми, индексируемыми, проверяемыми на целостность; </li><li><strong>вариативные</strong> — их можно хранить гибко, например, в JSON или агрегированных таблицах.</li></ul><p>Вот тот же пример:</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Связан с</th><th>Тип связи</th><th>Комментарий к типу связи</th></tr></thead><tbody><tr><td>Категория</td><td>Ключевая</td><td>Основная связь для навигации и фасетной фильтрации, требует строгой целостности и индексации.</td></tr><tr><td>Тег</td><td>Вариативная</td><td>Может меняться часто, используется для быстрых выборок и контекстных срезов, хранится гибко.</td></tr><tr><td>Заказ</td><td>Ключевая</td><td>Одна из бизнес‑критичных связей, формирует аналитику продаж и отчётность, требует транзакционной целостности.</td></tr><tr><td>Отзыв</td><td>Вариативная</td><td>Данные обновляются динамически пользователями; важно для контентных сервисов, но не влияет на бизнес‑логику.</td></tr><tr><td>Пользователь</td><td>Вариативная</td><td>Основана на поведенческих данных (просмотры, избранное, покупки), часто хранится в отдельных логах или кэше.</td></tr></tbody></table></figure></div><h3 class="wp-block-heading">Направление и зависимости связей</h3><p>Направления связей и зависимость объектов часто определяет их поведение. Заказ зависит от пользователя, а не наоборот. Комментарий зависит от поста, а не пост от комментария. Такие зависимости влияют на каскадное удаление и миграции, это очень важная часть ИА и дальнейшего проектирования баз данных.</p><p>Вот как это может выглядеть:</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Связан с</th><th>Направление связи</th><th>Зависимость</th><th>Описание</th></tr></thead><tbody><tr><td>Категория</td><td>Категория → Товар</td><td>Товар зависит от категории</td><td>При удалении категории товары должны быть перемещены, переназначены или архивированы.</td></tr><tr><td>Тег</td><td>Двусторонняя (M:N)</td><td>Независимая</td><td>При удалении тега удаляются только связи, товары остаются без изменений.</td></tr><tr><td>Заказ</td><td>Товар → Заказ</td><td>Заказ зависит от товара</td><td>Заказ хранит ссылки на товары. При удалении товара заказы сохраняют данные о позиции, помечая их как архивные или недоступные.</td></tr><tr><td>Отзыв</td><td>Товар → Отзыв</td><td>Отзыв зависит от товара</td><td>При удалении товара отзывы удаляются или помечаются как «осиротевшие».</td></tr><tr><td>Пользователь</td><td>Двусторонняя (поведение)</td><td>Частично</td><td>Поведенческие связи с товаром (просмотры, избранное) можно анонимизировать или обнулить при удалении пользователя.</td></tr></tbody></table></figure></div><p>На этом, пожалуй, можно завершить историю про выявление связей между сущностями. Мы и так одной ногой ступили на зыбкую почву <strong>дизайна баз данных</strong>. Дальше пусть взрослые разбираются.</p><h2 class="wp-block-heading">Итог</h2><p>Мы ещё не успели пройтись по самому интересному — выявлению и фиксации свойств сущностей, схематизации всего этого добра. Но статья и так вышла объёмной, об этом будет в следующей части серии.</p><p>Запись <a href="https://sherer.pro/blog/informacionnaya-arhitektura-sushchnosti-vol-2/">Информационная архитектура: сущности (практика, vol.1)</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded></item><item><title>Информационная архитектура: сущности (теория)</title><link>https://sherer.pro/blog/informacionnaya-arhitektura-sushchnosti-vol-1/</link><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Sat, 18 Oct 2025 15:02:24 +0000</pubDate><category><![CDATA[UX/UI]]></category><category><![CDATA[Аналитика]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[аналитика]]></category><category><![CDATA[гайд]]></category><category><![CDATA[информационная архитектура]]></category><guid isPermaLink="false">https://sherer.pro/?p=2411</guid><description><![CDATA[<p>Что такое информационные сущности, зачем они нужны и из чего состоят.</p><p>Запись <a href="https://sherer.pro/blog/informacionnaya-arhitektura-sushchnosti-vol-1/">Информационная архитектура: сущности (теория)</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p>Сущности — это «кирпичи» информационной архитектуры. Правильно выделенные сущности, их свойства и связи задают масштабируемость продукта, качество поиска и фильтрации, логику навигации и эволюцию данных. В этой статье мы поговорим о том, как выявлять сущности, описывать их свойства, моделировать связи и таксономии (не запутывая при этом команду и пользователей).</p><h2 class="wp-block-heading">Вокабуляр</h2><p>Для начала давайте вспомним некоторые определения, которые помогут вам ориентироваться в этой статье:</p><p><strong>Информационная сущность</strong> — устойчивый тип информации в домене продукта (товар, пользователь, заказ, пост, коллекция, организация и тп), обладающий набором свойств и связей.</p><p><strong>Свойство сущности</strong> — характеристика, описывающая сущность количественно или качественно (название, цена, цвет, дата создания и тп). Свойства могут быть разных типов, заполняться и проверяться по разным правилам, быть «зависимыми» или нет.</p><p><strong>Таксономия</strong> — управляемая схема классификации, объединяющая сущности по общим признакам (категории, метки и прочие). Она создаёт структуру смысловых связей между сущностями, помогает группировать объекты, облегчает поиск и делает навигацию предсказуемой.</p><p><strong>Термин таксономии</strong> — конкретная единица этой классификации (например, категория «Кроссовки» в таксономии «Обувь»).</p><p><strong>Фасет</strong> — нормализованный атрибут, используемый для фильтрации и уточнения поиска (бренд, цвет, размер и тп).</p><h2 class="wp-block-heading">Что такое «сущность» и чем она не является</h2><p>Сущность всегда:</p><ul class="wp-block-list"><li>имеет <strong>роль</strong> в домене (зачем она нужна, какую задачу выполняет);</li><li>несёт <strong>набор свойств</strong> (атрибутов);</li><li>находится в <strong>связях</strong> с другими сущностями или таксономиями;</li><li>проходит <strong>жизненный цикл</strong> (например: создание, модерация, публикация, удаление).</li></ul><p>Из-за того, что терминология, как обычно, размыта, сущности легко можно спутать с чем-то, что ими не является, например:</p><ul class="wp-block-list"><li>со страницей/экраном (это <strong>представление</strong> сущности в одном из контекстов);</li><li>с UI‑компонентом (это <strong>способ отображения</strong> свойства или связи);</li><li>с таблицей БД (это <strong>реализация хранения</strong>, одна сущность может жить в нескольких таблицах и наоборот);</li><li>с бизнес‑процессом (это <strong>поведение</strong> вокруг данных: процесс «оформить заказ» использует сущности «корзина», «заказ», «платёж»).</li></ul><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Небольшая оговорка: иногда название <strong>сущности </strong>совпадает с названием <strong>представления</strong>, это абсолютно нормально. В контент‑ориентированных продуктах (CMS, документация, лендинги) тип «Страница» может быть <strong>полноценной контент‑сущностью</strong> с собственными свойствами (название, ярлык, текст, автор и тп) и жизненным циклом. Тезис «страница — не сущность» касается только путаницы между <strong>сущностью домена</strong> и <strong>экраном интерфейса</strong> (UI‑представлением).</p></blockquote><p>Сложно? На самом деле нет. Вот вам простой тест. Объект — это сущность, если содержит хотя бы 3 из следующих признаков:</p><ul class="wp-block-list"><li>имеет собственные свойства;</li><li>имеет связи с другими объектами;</li><li>повторяется во множестве экземпляров;</li><li>нужен в отчётности/поиске;</li><li>имеет собственные правила валидации/жизненный цикл.</li></ul><h2 class="wp-block-heading">Свойства сущности</h2><p>Как мы уже выяснили, у сущностей есть свойства. Это, пожалуй, самое важное, что отличает их от остальных объектов цифрового продукта. Давайте поговорим об этом чуть подробнее.</p><h3 class="wp-block-heading">Типы свойств</h3><p>Свойства могут быть нескольких типов:</p><ul class="wp-block-list"><li><strong>Базовые:</strong> идентификатор, название, описания и прочие. Это простые поля, которые содержат типовую информацию. Базовые свойства не ссылаются на другие объекты и, как правило, представлены в виде простых <em>типов</em> данных (строка, число, дата и тп).</li><li><strong>Ссылочные:</strong> внешние ключи на другие сущности (например, «идентификатор пользователя» в сущности «заказ»), а также термины таксономий (категория, метка, группа). Ссылочные свойства нужны для того, чтобы гарантированно связать сущности между собой и с терминами таксономий.</li><li><strong>Составные:</strong> свойства, которые включают в себя сразу несколько значений, объединённых одной логикой. Составные свойства могут быть однородными и неоднородными:<ul class="wp-block-list"><li><strong>однородные </strong>списки (например, изображения: <code>{url, alt},...</code>);</li><li><strong>неоднородные </strong>комплекты (например, габариты: <code>{weight, width, height, depth}</code>).</li></ul></li><li><strong>Вычисляемые:</strong> свойства, для фиксации (сохранения, отображения и тп) которых нужно сначала произвести какие-то операции. Например, это могут быть: цена со скидкой, количество на складе, агрегированный рейтинг.</li><li><strong>Технические:</strong> SKU/артикул, временные отметки, статусы модерации/публикации, флаги индексации. Технические свойства редко используются в визуальном представлении (например, в карточке товара из десятка технических свойств будет выводиться только артикул).</li><li><strong>Ограничительные:</strong> права доступа (ACL), владельцы, видимость. Их очень легко спутать с техническими, так как они тоже используются больше в логике, чем в представлении. Если сомневаетесь, задайте себе вопрос: «это свойство влияет на возможности пользователей?» — если да, то перед вами именно ограничительное свойство.</li></ul><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p><em>И снова небольшое уточнение, чтобы избежать путаницы: типы&nbsp;<strong>свойств&nbsp;</strong>сущностей — не то же самое, что типы&nbsp;<strong>данных</strong>, которые эти свойства содержат. Например, если у нашей сущности «товар» есть свойство&nbsp;</em><code>title</code><em>&nbsp;(название), то тип&nbsp;свойства&nbsp;здесь —&nbsp;<strong>базовый</strong>, тогда как тип&nbsp;данных&nbsp;—&nbsp;<strong>строка</strong>. Подробнее о типах данных я писал&nbsp;</em><a href="https://sherer.pro/blog/dizajn-dannyh-chast-4-matchast-osnovy/#3-tipy-dannyh">здесь</a><em>.</em></p></blockquote><h3 class="wp-block-heading">Пример описания свойств</h3><p>Минимальный набор информации, которую желательно фиксировать при описании каждого свойства сущности:</p><ol class="wp-block-list"><li><strong>название</strong> — короткое имя свойства, одно-два слова;</li><li><strong>код</strong> — как это свойство будет называться в коде и базе данных;</li><li><strong>тип данных</strong> — строка, число, массив, объект, ссылка и тп;</li><li><strong>обязательность</strong> — обязано ли свойство быть заполненным, если отметка «да», то значение свойства не может быть пустым;</li><li><strong>пример</strong> — короткий пример заполнения свойства (если пример слишком длинный, он может быть обрезан);</li><li><strong>описание/комментарий</strong> — если требуется вносить какую-то дополнительную информацию.</li></ol><p>При желании, этот перечень можно дополнить дополнительными параметрами:</p><ol class="wp-block-list"><li><strong>источник </strong>— откуда берётся значение свойства (логика, подсистемы, интеграции и тп);</li><li><strong>валидации </strong>— базовое правило проверки значения свойства;</li><li><strong>индексация/поиск</strong> — участвует ли свойство в поиске и индексации, если да, то как;</li><li><strong>политика i18n</strong> — для локализуемых свойств: какие переводятся, какие нет;</li><li><strong>политикой заполнения</strong> — кто и когда обязан заполнить.</li></ol><p>Вот пример того, как могут фиксироваться свойства сущности «товар» (табличка получилась внушительная, скрольте влево):</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Название</th><th>Код</th><th>Тип данных</th><th>Обяза-тельно</th><th>Пример</th><th><strong>Описание/комментарий</strong></th><th>Источник</th><th>Валидация</th><th>И<strong>ндексация/поиск</strong></th></tr></thead><tbody><tr><td>Внутренний идентификатор</td><td><code>id</code></td><td><code>int</code></td><td>да</td><td><code>12345</code></td><td>Используется на бэкенде, на клиент не передаётся.</td><td>БД</td><td>уникальность</td><td>нет</td></tr><tr><td>Внешний идентификатор</td><td><code>sku</code></td><td><code>string</code></td><td>да</td><td><code>X-2025-01</code></td><td>Артикул, идентифицирует товар в URL.</td><td>БД</td><td>уникальность</td><td>точный</td></tr><tr><td>Название</td><td><code>title</code></td><td><code>string</code></td><td>да</td><td><code>Кроссовки X</code></td><td>&#8212;</td><td>ERP</td><td>5–120 символов</td><td>полнотекстовый</td></tr><tr><td>Описание</td><td><code>description</code></td><td><code>string</code></td><td>да</td><td><code>Летние кроссовки для самых...</code></td><td>&#8212;</td><td>ERP</td><td>200–2400 символов</td><td>полнотекстовый</td></tr><tr><td>Категория</td><td><code>category_id</code></td><td><code>ref</code></td><td>да</td><td><code>17</code></td><td>Идентификатор термина ключевой таксономии</td><td>Таксономия</td><td>существует</td><td>фасет</td></tr><tr><td>Габариты</td><td><code>dimensions</code></td><td><code>object</code></td><td>нет</td><td><code>{w:10,h:20,d:5}</code></td><td><code>w</code> &#8212; ширина,<br><code>h</code> &#8212; высота,<br><code>d</code> &#8212; глубина</td><td>ERP</td><td>диапазоны</td><td>фильтр</td></tr><tr><td>Изображения</td><td><code>images</code></td><td><code>list</code></td><td>да</td><td><code>['/upload/img1.jpg']</code></td><td>Список изображений товара, первое в списке — основное.</td><td>CDN</td><td>не пусто</td><td>нет</td></tr><tr><td>Цена</td><td><code>price</code></td><td><code>int</code></td><td>да</td><td><code>4990</code></td><td>Стоимость в рублях.</td><td>ERP</td><td>≥0</td><td>сортировка и фильтр</td></tr><tr><td>Скидка</td><td><code>discount</code></td><td><code>int</code></td><td>нет</td><td><code>20</code></td><td>Процент, на который снижается <code>price</code></td><td>ERP</td><td>целое число</td><td>нет</td></tr></tbody></table></figure></div><p>Такая фиксация свойств экономит кучу времени на разработке, интеграциях и отчётности. Дизайнеры и аналитики получают чёткий перечень с примерами, а разработчики намного более уверенно проектируют БД и жизненный цикл данных в продукте.</p><h3 class="wp-block-heading">Примеры по доменам</h3><p>Из-за того, что все продукты разные, домены в них тоже могут отличаться. В одном e-com сущность «товар» будет обладать одним набором свойств, в другом — совершенно иным. Порой очень хочется просто взять наработки с прошлого места работы и запихнуть их в текущую архитектуру «как есть». Призываю вас этого не делать, а всегда проектировать сущности, исходя из реалий продукта, процессов, потребностей пользователей и бизнес-задач.</p><p>Чтобы показать, насколько всё может отличаться от продукта к продукту, вот вам несколько примеров сущностей со свойствами из разных доменов:</p><div class="wp-block-group highlighted content-wide is-layout-constrained wp-block-group-is-layout-constrained"><figure class="wp-block-table"><table><thead><tr><th>Сущность</th><th>Свойства</th></tr></thead><tbody><tr><td>Пользователь</td><td><code>id</code>, <code>guid</code>, <code>email</code>, <code>login</code>, <code>password_hash</code>, <code>avatar</code>, <code>roles[]</code>, <code>org_id</code>, <code>created_at</code>, <code>last_seen_at</code></td></tr><tr><td>Каталог</td><td><code>id</code>, <code>type</code>, <code>parent_id</code>, <code>slug</code>, <code>default_facets[]</code>, <code>synonyms[]</code></td></tr><tr><td>Товар</td><td><code>id</code>, <code>sku</code>, <code>title</code>, <code>slug</code>, <code>description</code>, <code>images[]</code>, <code>price</code>, <code>currency</code>, <code>dimensions{}</code>, <code>weight</code>, <code>category_id</code>, <code>tags[]</code>, <code>stock_qty</code>, <code>rating</code>, <code>seller_id</code></td></tr><tr><td>Корзина</td><td><code>id</code>, <code>user_id</code>, <code>items[]</code>, <code>coupon</code>, <code>total_amount</code>, <code>currency</code>, <code>updated_at</code></td></tr><tr><td>Категория</td><td><code>id</code>, <code>parent_id</code>, <code>name</code>, <code>slug</code>, <code>synonyms[]</code>, <code>default_filters[]</code></td></tr><tr><td>Пост (медиа)</td><td><code>id</code>, <code>title</code>, <code>excerpt</code>, <code>body</code>, <code>author_id</code>, <code>category_id</code>, <code>tags[]</code>, <code>published_at</code>, <code>status</code></td></tr><tr><td>Организация (SaaS)</td><td><code>id</code>, <code>name</code>, <code>inn</code>, <code>slug</code>, <code>plan</code>, <code>seats</code>, <code>billing_account_id</code>, <code>status</code>, <code>created_at</code></td></tr></tbody></table></figure></div><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Обратите внимание, что категория здесь — информационная сущность, хотя она же — и термин таксономии. У терминов всегда есть собственные свойства, жизненный цикл и связи. Фиксировать ли их как сущности или описывать отдельно — решать вам.</p></blockquote><h2 class="wp-block-heading">Связи между сущностями</h2><p>Как я уже говорил, сущности почти всегда связаны как между собой, так и с терминами таксономии. Давайте теперь копнём поглубже.</p><h3 class="wp-block-heading">Кардинальности</h3><p>Кардинальность — это характеристика связи между двумя сущностями (таблицами, объектами, классами и т.д.), показывающая, сколько экземпляров одной сущности может быть связано с экземпляром другой. Проще говоря, это способ ответить на вопрос: «Сколько А может быть связано с одним B?» и наоборот.</p><p>Она лежит в основе информационной и логической архитектуры: без понимания кардинальностей невозможно правильно спроектировать базу данных, API, доменную модель или даже интерфейс.</p><p>Подробнее про кардинальности я <a href="https://sherer.pro/blog/dizajn-dannyh-chast-5-matchast-bazy-dannyh/#2-2-svyazi">писал</a> в цикле про дизайн данных, здесь пройдёмся коротко:</p><ul class="wp-block-list"><li><strong>Один-ко-одному, 1:1</strong> — связь, когда каждой записи одной сущности соответствует не более одной записи другой (аккаунт ↔ профиль). Используется для разделения личных и технических данных или выделения редко используемых атрибутов.</li><li><strong>Один-ко-многим, 1:N</strong> — наиболее частая связь: один объект верхнего уровня связан с множеством подчинённых (категория → товары; организация → проекты). Применяется для иерархий, коллекций и агрегатов.</li><li><strong>Многие-ко-многим, M:N</strong> — объект может быть связан с несколькими другими (товар ↔ теги; пост ↔ автор). Реализуется через промежуточные таблицы/сущности, содержащие идентификаторы обеих сторон и метаданные связи.</li></ul><h3 class="wp-block-heading">Хранение и производительность</h3><p>Выбор способа хранения связей напрямую влияет на скорость работы системы, гибкость изменений и устойчивость к росту данных. Здесь важно найти баланс между строгими структурированными связями и гибкими форматами, чтобы обеспечить масштабируемость, простоту поддержки и корректную работу поиска и аналитики.</p><p>Это ещё не дизайн баз данных, но первый шаг к нему.</p><h4 class="wp-block-heading">Ключевые, частые связи</h4><p>Реализуются как явными внешними ключами (Foreign Key, FK — ссылка из одной таблицы БД на запись другой таблицы), так и отдельными таблицами. Индексируются для быстрого поиска и каскадных операций (например, при удалении пользователя каскадом удаляются его профиль, способы оплаты и тп). Ключевые связи хорошо подходят для данных, которые часто запрашиваются и требуют согласованности.</p><p>Например, ключевой связью является связь пользователя и его профиля (1:1) или заказа и товара (1:N).</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba57bfc3&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba57bfc3" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="1168" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2025/11/ia-entities-1.png" alt="Ключевая связь между сущностями в информационной архитектуре" class="wp-image-4639" srcset="https://sherer.pro/content/uploads/2025/11/ia-entities-1.png 2096w, https://sherer.pro/content/uploads/2025/11/ia-entities-1-1048x584.png 1048w, https://sherer.pro/content/uploads/2025/11/ia-entities-1-768x428.png 768w" sizes="auto, (max-width: 2096px) 100vw, 2096px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><h4 class="wp-block-heading">Вариативные, редкие связи</h4><p>Удобнее хранить в агрегированных структурах (JSON, массивы, ключ-значение) или связующих таблицах без строгих FK. Такой подход облегчает эволюцию схемы и интеграции с внешними источниками.</p><p>Пример вариативной связи: товар и теги (M:N через JSON или связующую таблицу) или пост и связанные материалы (список ссылок в массиве).</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba57c315&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba57c315" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="1168" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2025/11/ia-entities-2.png" alt="Вариативная связь между сущностями в информационной архитектуре" class="wp-image-4640" srcset="https://sherer.pro/content/uploads/2025/11/ia-entities-2.png 2096w, https://sherer.pro/content/uploads/2025/11/ia-entities-2-1048x584.png 1048w, https://sherer.pro/content/uploads/2025/11/ia-entities-2-768x428.png 768w" sizes="auto, (max-width: 2096px) 100vw, 2096px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><h4 class="wp-block-heading">Комбинированный подход</h4><p>Сочетает строго типизированные связи для критичных сценариев (например, FK для заказов и пользователей) и гибкие структуры для второстепенных (например, свойства товара в JSON). Это компромисс между скоростью, расширяемостью и затратами на сопровождение.</p><p>Пример комбинированного подхода: заказ и пользователь (жёсткий FK) + история изменений в JSON, товар и его характеристики (основные поля + гибкое поле параметров).</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba57c5ff&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba57c5ff" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="736" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2025/11/ia-entities-3.png" alt="Комбинированный подход к связям между сущностями в информационной архитектуре" class="wp-image-4641" srcset="https://sherer.pro/content/uploads/2025/11/ia-entities-3.png 2096w, https://sherer.pro/content/uploads/2025/11/ia-entities-3-1048x368.png 1048w, https://sherer.pro/content/uploads/2025/11/ia-entities-3-768x270.png 768w" sizes="auto, (max-width: 2096px) 100vw, 2096px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><h3 class="wp-block-heading">Поисковые сценарии и индексы</h3><p>Вот вы открыли свой любимый маркетплейс. Вбили в поле поиска нужный товар, отфильтровали по бренду и отсортировали результат по цене. Поздравляю, вы только что покрыли практически все поисковые сценарии.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Поисковые сценарии — это практические случаи, когда пользователь взаимодействует с данными через поиск, фильтрацию и сортировку.</p></blockquote><p>Чтобы такие операции выполнялись быстро и точно, информационная модель должна поддерживать разные типы <em>индексов</em>. Индексы обеспечивают мгновенное обращение к нужным сущностям и позволяют формировать результаты без полного перебора данных.</p><p>Индексировать можно разные типы полей:</p><h4 class="wp-block-heading">Фасетные поля</h4><p>Категория, бренд, размер, цвет, материал и прочее. Хранятся в нормализованных словарях или связаны с терминами таксономий, индексируются отдельно. Это даёт возможность строить фильтры и считать количество элементов в каждой группе (это ещё называется «фасетные агрегации»). Чтобы ускорить отклик системы, важно хранить <em>предвычисленные частоты </em>— но это уже совсем мрак, оставим его архитекторам БД.</p><h4 class="wp-block-heading">Поисковые поля</h4><p>Используют полнотекстовые индексы и префиксные деревья для автодополнения и предложений. Помните, как вы вбиваете что-то в строку поиска, а вам показывают подсказки? Вот это оно. Здесь же добавляются морфологический анализ, поддержка синонимов, транслитерации и нечёткий поиск (<a href="https://habr.com/ru/articles/354032/">fuzzy search</a>).</p><h4 class="wp-block-heading">Сортировочные поля</h4><p>Числовые и временные индексы (цена, рейтинг, дата создания, популярность), обеспечивающие быстрые операции сортировки и пагинацию без нагрузки на базу данных.</p><h4 class="wp-block-heading">Сложно? Подождите, это ещё не всё</h4><p>Существует тьма технических приёмов, нацеленных на оптимизацию индексирования: применение комбинированных индексов по частым связкам <code>category_id + price</code>, денормализация популярных связей <code>product → category_name</code>, кэширование фасетных частот для снижения нагрузки и прочее. Но это вам так, если захочется погрузиться.</p><h2 class="wp-block-heading">Таксономии и «сквозные» свойства</h2><p>Правильная таксономия обеспечивает единый язык между пользователями, системой и бизнесом. Таксономии бывают нескольких типов, и каждая решает свою задачу:</p><h3 class="wp-block-heading">Иерархическая таксономия</h3><p>Древовидная структура терминов, где каждый элемент подчинён родительскому (например, дерево категорий или разделов). В таких таксономиях «родительство» обычно обеспечивается отдельным свойством, вроде <code>parent_id</code>.</p><p>Такая модель хорошо подходит для каталогов товаров, корпоративных порталов и CMS, где пользователи ожидают логичную последовательность разделов и вложенных подразделов.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba57caff&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba57caff" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="1446" height="680" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2025/10/ia-entities-4.png" alt="Пример иерархической таксономии" class="wp-image-4676" srcset="https://sherer.pro/content/uploads/2025/10/ia-entities-4.png 1446w, https://sherer.pro/content/uploads/2025/10/ia-entities-4-1048x493.png 1048w, https://sherer.pro/content/uploads/2025/10/ia-entities-4-768x361.png 768w" sizes="auto, (max-width: 1446px) 100vw, 1446px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p><strong>Преимущество:</strong> высокая предсказуемость навигации и простота в управлении.</p><p><strong>Недостаток:</strong> ограниченная гибкость и риск «похоронить» информацию слишком глубоко.</p><h3 class="wp-block-heading">Плоская таксономия</h3><p>Сеть меток, тем или ключевых слов, связанных с сущностями по принципу многие‑ко‑многим. Она добавляет горизонтальные связи и позволяет связывать контент по контексту: статьи с похожими тегами, продукты с общими характеристиками, документы одной темы.</p><p>Чаще всего плоские таксономии используется в медиа, блогах и SaaS‑платформах для тегирования и сквозных переходов между материалами.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba57cde8&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba57cde8" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="1446" height="360" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2025/10/ia-entities-5.png" alt="Пример плоской таксономии" class="wp-image-4693" srcset="https://sherer.pro/content/uploads/2025/10/ia-entities-5.png 1446w, https://sherer.pro/content/uploads/2025/10/ia-entities-5-1048x261.png 1048w, https://sherer.pro/content/uploads/2025/10/ia-entities-5-768x191.png 768w" sizes="auto, (max-width: 1446px) 100vw, 1446px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p><strong>Преимущество</strong>: простота расширения и гибкость.</p><p><strong>Недостаток:</strong> если не контролировать список терминов, со временем возможна потеря структурности и даже полная поломка логики (например, когда у вас есть 2 разных метки «UX» и «ux»).</p><h3 class="wp-block-heading">Фасетная таксономия</h3><p>Объединяет независимые классификации, например: категория, бренд, размер, цена, материал. Пользователь может фильтровать данные сразу по нескольким измерениям.</p><p>Такая модель характерна для маркетплейсов и аналитических панелей, где каждый фасет — это отдельная ось с набором значений.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba57d125&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba57d125" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="1446" height="680" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2025/10/ia-entities-6.png" alt="Пример фасетной таксономии" class="wp-image-4678" srcset="https://sherer.pro/content/uploads/2025/10/ia-entities-6.png 1446w, https://sherer.pro/content/uploads/2025/10/ia-entities-6-1048x493.png 1048w, https://sherer.pro/content/uploads/2025/10/ia-entities-6-768x361.png 768w" sizes="auto, (max-width: 1446px) 100vw, 1446px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p><strong>Преимущество</strong>: высокая управляемость фильтрацией и быстрый поиск.</p><p><strong>Недостаток:</strong> сложность проектирования и ухудшение управляемости при росте числа комбинаций.</p><h3 class="wp-block-heading">Сквозные свойства</h3><p>Например: материал, бренд, разрешение экрана. Сквозные свойства выполняют роль фасетов и служат мостом между таксономиями и данными:</p><ul class="wp-block-list"><li>живут в <strong>единых словарях</strong>, которые поддерживаются централизованно;</li><li>используются как <strong>фасеты</strong> и <strong>правила мерчендайзинга/рекомендаций</strong>;</li><li>имеют <strong>политику синонимов</strong>, нормализации значений и правила локализации;</li><li>могут быть <strong>жёстко типизированы</strong> (enum — о них чуть ниже) или <strong>гибкими</strong> (текстовые значения, появляющиеся из данных);</li></ul><p>Однако у сквозных свойств есть и обратная сторона. Давайте разберём на примере свойства товара «материал».</p><p>«Материал» — фасет <strong>только</strong> при наличии нормализованного словаря (ограниченный справочник материалов). Если материал хранится как произвольный текст (например, «металлический с пластиковыми вставками»), он <strong>не</strong> является фасетом и остаётся обычным полем: участвует в полнотекстовом поиске, но не в фасетной фильтрации.</p><h2 class="wp-block-heading">Противоречивые классификации</h2><p>Иногда классифицировать сущности оказывается сложно. Хороший пример такой противоречивой классификации — вопрос «где разместить арбуз»? Это <em>ягода </em>(что правильнее с точки зрения ботаники), <em>тыквина </em>(что ещё более правильно) или <em>фрукт </em>(ведь именно там его ищут пользователи)?</p><p>Когда один и тот же объект может относиться сразу к нескольким категориям, архитектору важно не выбрать «правильный» ответ, а установить управляемую логику принятия решений. Задача таксономии — не отражать условную «истину», а обеспечивать предсказуемость и согласованность между системами.</p><p>И для этого существует несколько правил:</p><ol class="wp-block-list"><li>Вводим <strong>приоритеты классификаций</strong> (биология < повседневные ожидания < бизнес‑цели каталога). Эти приоритеты задают уровень, на котором принимается решение — например, витрина каталога ориентируется на пользовательскую логику, а не на научную.</li><li>Формируем <strong>правила визуализации и информационные связи</strong>: как объект отображается в меню, поиске, фильтрах и фасетах, чтобы не было дублирования или рассинхронизации. В карточке сущности могут быть указаны обе принадлежности, но навигация использует только основную.</li><li>Фиксируем <strong>конфликты и владельцев решения</strong>: кто принимает решение, когда пересматривается структура, где фиксируются комментарии и примечания.</li><li>Документируем<strong> принципы разрешения конфликтов</strong> и <strong>исключения</strong>, чтобы разные подсистемы (поиск, рекомендации, SEO) пользовались единым источником правды.</li></ol><h2 class="wp-block-heading">Пример визуализации базы данных</h2><p>По итогу работы над информационной архитектурой обычно создаются спецификации API и дизайн БД. Про API здесь говорить пока рано, а вот про БД уже пора.</p><p>Ловите пример того, как может выглядеть простенькая база данных в виде ER-диаграммы:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba57d5ca&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba57d5ca" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="1095" height="526" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2025/11/er-diagram-example.png" alt="" class="wp-image-4653" srcset="https://sherer.pro/content/uploads/2025/11/er-diagram-example.png 1095w, https://sherer.pro/content/uploads/2025/11/er-diagram-example-1048x503.png 1048w, https://sherer.pro/content/uploads/2025/11/er-diagram-example-768x369.png 768w" sizes="auto, (max-width: 1095px) 100vw, 1095px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p>Здесь учитывается почти всё:</p><ul class="wp-block-list"><li>По типу соединения можно понять тип связей. Например, от <code>users.id</code> к <code>orders.user_id</code> соединение начинается одной линией, а заканчивается несколькими, разветвлением — это связь однин-ко-многим (1:N).</li><li>Иконка «ключика» возле названия поля обозначает первичный ключ (primary key), который уникально идентифицирует каждую запись. А иконка «заметки» говорит о том, что у поля есть дефолтное значение.</li><li>Если возле названия есть иконка «ссылки», то это внешний ключ (foreign key), и от него почти всегда будет связь 1:N к источнику. Например, от того же <code>orders.user_id</code> к <code>users.id</code>.</li><li>Две буквы «NN» в конце каждой строки — это «NOT NULL», поле не может быть пустым. Та самая <em>обязательность</em> из таблички, помните?</li><li>Буква «Е» в <code>orders.status</code> означает «ENUM» — набор именованных констант. Значение этого поля может быть заполнено только значениями из определённого словаря. В нашем случае статус заказа может быть только <code>pending</code>, <code>paid</code>, <code>shipped</code>, <code>delivered</code> или <code>canceled</code>.</li><li>Ну а всякие <code>varchar</code>, <code>int</code>, <code>decimal</code>, <code>datetime</code> и другие — всего лишь типы данных, которые хранятся в этом поле.</li></ul><p>Так нафига вообще тогда информационная архитектура, если можно сразу пилить ER-диаграммы и не париться? Да потому что они описывают только один слой IA — слой <strong>реализации хранения </strong>данных (в самом начале статьи мы об этом говорили). Огромный пласт информации, накопленной грамотным подходом к IA, здесь не учитывается. Примеры, политики заполнения и мультиязычности, правила валидации, источники данных и куча всего остального.</p><p>Так что не ER-диаграммами едиными.</p><h2 class="wp-block-heading">Что дальше</h2><p>А дальше мы поговорим о практической работе с сущностями: как их искать, формализовать и поддерживать, немного поговорим о частых ошибках и анти-паттернах. Отдельно я расскажу о том, как из сущностей и их связей формировать навигацию и поиск. Ну и бонусом, в следующих статьях будет несколько шаблонов, чек-листов и даже мини‑RFC для решения по сущностям.</p><p>Подписывайтесь на <a href="https://t.me/shererpro" target="_blank" rel="noreferrer noopener">канал</a>, там будут все новости.</p><p>Запись <a href="https://sherer.pro/blog/informacionnaya-arhitektura-sushchnosti-vol-1/">Информационная архитектура: сущности (теория)</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded></item><item><title>Функциональная архитектура цифровых продуктов, часть 5</title><link>https://sherer.pro/blog/funkcionalnaya-arhitektura-cifrovyh-produktov-chast-5/</link><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Mon, 17 Feb 2025 06:30:11 +0000</pubDate><category><![CDATA[Документация]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[гайд]]></category><category><![CDATA[функциональное проектирование]]></category><guid isPermaLink="false">https://sherer.pro/?p=3930</guid><description><![CDATA[<p>Детальное функциональное проектирование и частые, но не всегда очевидные подводные камни.</p><p>Запись <a href="https://sherer.pro/blog/funkcionalnaya-arhitektura-cifrovyh-produktov-chast-5/">Функциональная архитектура цифровых продуктов, часть 5</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p>Это — последняя часть цикла про функциональное проектирование. Здесь мы поговорим о детальном функциональном проектировании и разберём несколько подводных камней. </p><p>В целом, этого цикла должно быть достаточно, чтобы вы уверенно начали работать с функциональной архитектурой, не опасаясь заблудиться в нюансах.</p><h2 class="wp-block-heading">Детальное функциональное проектирование</h2><p>Как вы помните, в предыдущих статьях я различал высокоуровневое и детальное проектирование. И если о первом уже говорилось достаточно, то пришло время поглубже рассмотреть второе.</p><h3 class="wp-block-heading">Именование функций</h3><p>У каждой функции и каждого функционального раздела должно быть своё уникальное название. Названия должны быть максимально понятными и самодостаточными. Используйте английский язык — это обеспечит единое понимание в команде (особенно если она международная) и немного упростит работу программистов.</p><p>Удачное название функции упрощает её поддержку и снижает риск двусмысленности.</p><figure class="wp-block-table"><table><thead><tr><th>Примеры удачных названий</th><th>Примеры неудачных названий</th><th><strong>Причина &#171;неудачности&#187;</strong></th></tr></thead><tbody><tr><td><code>UserRegistration</code></td><td><code>Reg</code> </td><td>– Слишком краткое и абстрактное название, которое неясно передаёт смысл функции.<br>– Аббревиатура «Reg» может быть интерпретирована по-разному (например, &#171;регистрация&#187;, &#171;регион&#187; или даже &#171;регламент&#187;).</td></tr><tr><td><code>AddToCart</code></td><td><code>AddItem</code> </td><td>– Название «AddItem» не указывает на конкретное место назначения – куда именно добавляется элемент.<br>– В контексте онлайн-магазина важно подчеркнуть, что речь идёт о корзине (cart), а слово «Item» само по себе может использоваться в различных сценариях, не только в e-commerce.</td></tr><tr><td><code>SubmitReport</code></td><td><code>ReportSubmission</code> </td><td>– Использование существительного вместо глагола может сделать название менее динамичным и не столь интуитивно понятным.<br>– «SubmitReport» сразу сигнализирует о действии – отправке отчёта, тогда как «ReportSubmission» звучит как описание процесса или объекта, а не как команда для выполнения функции.</td></tr><tr><td><code>VerifyEmail</code></td><td><code>EmailCheck</code></td><td>– Название «EmailCheck» менее конкретно. Оно не уточняет, что именно проверяет функция: корректность или подлинность email-адреса.<br>– Глагол «Verify» в «VerifyEmail» чётко указывает на необходимость верификации (проверки) адреса, что более точно отражает суть задачи, в то время как «Check» может трактоваться как поверхностная проверка без гарантии достоверности.</td></tr></tbody></table></figure><p>Неудачные названия часто бывают слишком абстрактными или краткими, что затрудняет чтение и может привести к ошибкам при оценке и реализации. Следуйте нескольким простым правилам:</p><ul class="wp-block-list"><li><strong>Глаголы</strong>: название функции, как правило, должно отражать действие. Например, из названия <code>AddUser</code> сразу понятно, что происходит добавление пользователя.</li><li><strong>Минимум аббревиатур</strong>: если аббревиатура не общеизвестна, лучше её избежать. Если же совсем никак, заведите в проектной документации <a href="https://sherer.pro/blog/uchim-proektnuju-komandu-chitat/#3-6-slovar-terminov">словарь</a>.</li><li><strong>Ясность</strong>: человек должен понимать суть функции, даже если читает её название впервые.</li></ul><h3 class="wp-block-heading">Функциональные сценарии</h3><p>Функциональные сценарии прорабатываются итеративно: от самых простых к детализированным. К этому времени накапливается достаточное количество данных для их глубокой проработки.</p><p>Пример высокоуровневого сценария для <code>UserRegistration</code>:</p><ol start="1" class="wp-block-list"><li>Пользователь открывает страницу регистрации.</li><li>Вводит свои данные.</li><li>Нажимает кнопку &#171;Зарегистрироваться&#187;.</li><li>Валидация: система проверяет данные.<ul class="wp-block-list"><li>Если всё корректно, создаётся аккаунт, и на почту отправляется письмо для подтверждения.</li><li>Если данные некорректны, отображается ошибка.</li></ul></li><li>Подтверждение: пользователь переходит по ссылке в письме, чтобы подтвердить регистрацию.</li><li>Если почта не подтверждена в течение 24 часов, аккаунт удаляется, пользователю показывается сообщение об ошибке.</li></ol><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba57ed0a&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba57ed0a" class="wp-block-image size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2560" height="997" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2024/11/functional-arch-registration-scaled.jpg" alt="" class="wp-image-4341" srcset="https://sherer.pro/content/uploads/2024/11/functional-arch-registration-scaled.jpg 2560w, https://sherer.pro/content/uploads/2024/11/functional-arch-registration-1048x408.jpg 1048w, https://sherer.pro/content/uploads/2024/11/functional-arch-registration-768x299.jpg 768w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p>Теперь рассмотрим, как можно детализировать отдельный фрагмент такого сценария: например, <code>ConfirmEmail</code>:</p><ul class="wp-block-list"><li>Мы проработаем обмен данными и их сохранение.</li><li>Для каждой проверки будет выделена отдельная функция.</li></ul><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba57eff8&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba57eff8" class="wp-block-image size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2560" height="1376" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2024/11/functional-arch-confirm-email-scaled.jpg" alt="" class="wp-image-4344" srcset="https://sherer.pro/content/uploads/2024/11/functional-arch-confirm-email-scaled.jpg 2560w, https://sherer.pro/content/uploads/2024/11/functional-arch-confirm-email-1048x563.jpg 1048w, https://sherer.pro/content/uploads/2024/11/functional-arch-confirm-email-768x413.jpg 768w" sizes="auto, (max-width: 2560px) 100vw, 2560px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p>Обратите внимание, что над некоторыми клиентскими функциями указаны названия и состояния экранов (например, <code>ConfirmEmail.check</code>) — мы к этому ещё вернёмся.</p><h3 class="wp-block-heading">Описание функций</h3><p>Однако одних сценариев зачастую оказывается не достаточно. Передать абсолютно всю информацию о функции и её работе с помощью схем не всегда возможно. С этой задачей вообще слабо справляются любые графические средства, хоть ФС, хоть диаграммы последовательностей. Да, разного рода схемы позволяют однозначно определить сценарии и потоки данных, но какие-то вещи можно отобразить только в виде текста.</p><p>Описание функции должно быть лаконичным и понятным для всех участников команды: от разработчиков до уборщиков и бизнес-специалистов. Что обычно включает в себя описание функции:</p><ul start="1" class="wp-block-list"><li><strong>Назначение</strong>: зачем нужна функция и что она делает.</li><li><strong>Входные и выходные данные</strong>: какие данные функция принимает и что возвращает (если применимо).</li><li><strong>Зависимости</strong>: с чем функция взаимодействует, без чего не будет работать (например, функциональный раздел <code>confirmPhone</code> не получится реализовать до того, как будет готов <code>sendSMS</code>).</li><li><strong>Пример использования</strong>: когда и как функция применяется.</li></ul><p>Пример упрощённого описания функции <code>AddToCart</code>:</p><ul class="wp-block-list"><li><strong>Назначение</strong>: добавить товар в корзину для оформления заказа.</li><li><strong>Входные данные</strong>: идентификатор <code>sku</code> и количество <code>count</code> товаров, идентификатор пользователя <code>guid</code>.</li><li><strong>Выходные данные</strong>: обновлённое состояние корзины, массив <code>cardState</code>.</li><li><strong>Зависимости</strong>: <code>InventoryService</code> (для проверки наличия товара).</li><li><strong>Пример использования</strong>: пользователь добавляет товар в корзину, система проверяет наличие и обновляет состояние корзины.</li></ul><p>Здесь можно добавить User Stories, Use Cases и вообще всё, что вы посчитаете нужным. Главное, чтобы описание было трактуемым однозначно.</p><p>Итеративная работа над сценариями позволяет их улучшать по мере получения новой информации и обратной связи от связанных специалистов или пользователей.</p><h2 class="wp-block-heading">Названия и состояния экранов</h2><p>Практически каждая функция системы так или иначе связана с каким-либо экраном. Кажется очевидным, что экраны и функции нужно прорабатывать совместно, однако я часто встречал ситуации, когда дизайнеры работают независимо от аналитиков и разработчиков.</p><figure class="wp-block-pullquote"><blockquote><p>Проработка экранов и их состояний не может быть отделена от функционального проектирования.</p></blockquote></figure><p>Вспомните, сколько раз вы получали (или предоставляли) макеты, где нет &#171;нулевых&#187; состояний или не предусмотрены &#171;пограничные&#187; ситуации, вроде ошибки загрузки данных.</p><h3 class="wp-block-heading">Названия экранов</h3><p>Название экрана должно ясно объяснять его назначение. Если у вас в Figma экраны будут именованы так же, как в проектной документации, это упростит работу фронтендеров и сделает эту документацию более консистентной. </p><figure class="wp-block-table"><table><tbody><tr><td>Название экрана</td><td>Описание</td></tr><tr><td><code>Registration</code></td><td>Экран для регистрации новых пользователей.</td></tr><tr><td><code>ShoppingCart</code></td><td>Экран, на котором отображаются добавленные товары.</td></tr><tr><td><code>OrderConfirmation</code></td><td>Экран подтверждения деталей заказа перед покупкой.</td></tr></tbody></table></figure><h3 class="wp-block-heading">Состояния экранов</h3><p>Каждый экран может находиться в различных состояниях, которые важно предусмотреть заранее. Пример состояний для экрана <code>ShoppingCart</code>:</p><figure class="wp-block-table"><table><tbody><tr><td>Экран и состояние</td><td>Описание</td></tr><tr><td><code>ShoppingCart.default</code></td><td>Загруженное состояние. Отображаются товары, их количество и цена; пользователь может изменить количество или удалить товар.</td></tr><tr><td><code>ShoppingCart.empty</code></td><td>Пустое состояние. Нет товаров в корзине; выводится сообщение: «Ваша корзина пуста. Начните покупки прямо сейчас!»</td></tr><tr><td><code>ShoppingCart.error</code></td><td>Состояние ошибки. Отображается сообщение об ошибке и предложение повторить попытку позже или обратиться в поддержку.</td></tr></tbody></table></figure><p>Помните, в сценарии над некоторыми клиентскими функциями указывались названия и состояния экранов? А теперь представьте, что это — ссылки на конкретные фреймы в Figma. Разработчикам не нужно больше играть в &#171;найди 10 различий&#187;, они видят взаимосвязь функций и экранов напрямую.</p><h2 class="wp-block-heading">Подводные камни</h2><p>Как и везде, при работе над функциональной архитектурой, можно порядком наломать дров. Очень не хочется, чтобы ФА постигла <a href="https://sherer.pro/blog/personazhi-po-kuperu-kak-diskreditirovat-metodologiyu/">участь</a> куперовских персон. </p><p>Ниже я перечислил самые частные ошибки и недоработки, которые допускал сам или видел у других.</p><h3 class="wp-block-heading">Недостаточная проработка</h3><p>Иногда хочется приступить к разработке пораньше. Это желание понятно, я много раз слышал обвинения в &#171;вотерфольности&#187; моего подхода. И именно &#171;аджайлами&#187; люди частенько прикрывают нежелание или неумение нормально проектировать. Ну что ж, дело хозяйское.</p><p>Я хочу только отметить, что недостаточная глубина проработки архитектуры создаёт ложное ощущение безопасности. Проблемы проявляются позже, когда проект уже зашёл слишком далеко, и исправления становятся всё более дорогими и трудоёмкими. Действуйте итерациями, никто не предлагает сначала продумать всё, и только потом садиться разрабатывать.</p><p>Пример: </p><p class="highlighted">Как-то я участвовал в доработке внутреннего портала одной компании под нужды другой (частый кейс). Руководство надавило, и в разработку была отдана сырая архитектура. Позже выяснилось, что спроектированная система не полностью поддерживает необходимое согласование отпусков и расчёт налогов. Масштабная переработка, срок сдачи сдвинулся на полтора месяца.</p><h3 class="wp-block-heading">Уровень абстракции</h3><p>Я часто об этом говорю (например, <a href="https://sherer.pro/blog/funkcionalnaja-arhitektura-cifrovyh-produktov-chast-2/?highlight=%D0%B0%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%86%D0%B8%D0%B8#3-1-uroven-abstrakcii">здесь</a>), и повторю снова.</p><p>Правильный уровень абстракции — это баланс. Слишком высокий абстрагирует архитектуру от реальности, а слишком низкий перегружает деталями, усложняя восприятие и развитие.</p><p>Пример:</p><p class="highlighted">В одном из недавних проектов аналитик проявил чудеса самостоятельности и (пока никто не видел) расписал в деталях одну из подсистем. Но его работа не учитывала огромное количество нюансов других компонентов, которые к тому времени ещё не были спроектированы. Итог: вся работа в мусорку.</p><h3 class="wp-block-heading">Технические знания</h3><p>Казалось бы, странно требовать от дизайнеров каких-либо знаний в технических областях. Но нет, не странно. </p><figure class="wp-block-pullquote"><blockquote><p>Невозможно задизайнить сложную систему, не понимая, как она будет работать</p></blockquote></figure><p>Недостаток технических знаний у дизайнеров, архитекторов или аналитиков приводит к принятию необоснованных решений. Либо наоборот, авторам архитектуры даже не приходит в голову, что существуют технологии, способные существенно упростить пользовательский опыт.</p><p>Пример: </p><p class="highlighted">При проработке внутренней части корпоративного блога, дизайнеры и аналитики не продумали возможность взаимной блокировки редактора (это когда ты не можешь править текст, который правит кто-то другой). Разработчики тоже не додумались. В итоге какое-то время, пока не внедрили <a href="https://developer.mozilla.org/ru/docs/Web/API/WebSockets_API" target="_blank" rel="noreferrer noopener">веб-сокеты</a>, контент-менеджеры перезатирали изменения друг друга. </p><h3 class="wp-block-heading">Консультации с экспертами</h3><p>Этот &#171;камень&#187; логически проистекает из предыдущего. Невозможно знать всё. Но можно не стесняться подключать к проектированию специалистов смежных областей. И речь тут не только про технологии, но и про них тоже.</p><p>Чем раньше вы &#171;обстучите&#187; свои решения об ваших коллег, тем более надёжными они станут. Игнорирование консультаций с экспертами приводит к критическим проблемам на поздних стадиях проектирования, разработки и внедрения. Привлечение специалистов позволяет выявить уязвимости проектирования в целом и функциональной архитектуры в частности ещё до начала разработки.</p><p>Пример: </p><p class="highlighted">Делали мобильное приложение. Одной из метрик эффективности продуктового дизайна была конверсия. Однако для пользователей из разных каналов необходимо было создать уникальный опыт. Пришёл с YouTube — один сценарий, с Telegram — другой. Дизайнеры тупо добавили на начальный экран вопрос &#171;откуда вы пришли&#187;. Хотя достаточно было сходить к маркетологам или разрабам, чтобы они рассказали про такое чудо инженерной мысли, как <a href="https://habr.com/ru/companies/otus/articles/688728/" target="_blank" rel="noreferrer noopener">диплинки</a>.</p><h3 class="wp-block-heading">Донесение ценности до бизнеса</h3><p>Самый больной &#171;камень&#187;. Хотя он и не подводный вовсе, а очень даже надводный. Знали бы вы, сколько раз мне приходилось доказывать клиентам, что начинать разработку ещё слишком рано. Или что влитые в проектирование деньги сохранят бюджет проекта в дальнейшем. </p><p>Один мой клиент (Алексей, привет) нашёл прекрасную аналогию: <a href="https://vector-shpunt.ru/blog/raboty-nulevogo-tsikla-stroitelstva/" target="_blank" rel="noreferrer noopener nofollow">нулевой цикл строительства</a>. Это когда в здание уже влито много-много денег, но ни одного этажа ещё не построено. Проведены геологические исследования, получены все разрешающие документы, подведены коммуникации — но внешне всё остаётся практически таким же, как было в самом начале.</p><p>Если бизнес не понимает ценность архитектурных решений, проект не получит достаточной поддержки. Важно доносить ценность функционального проектирования до всех заинтересованных сторон. </p><p>Антипример: </p><p class="highlighted">Я смог донести до клиента важность проектирования и исследований. Сам ездил со специалистами, прикидываясь стажёром. Выкопали вообще все бизнес-процессы до самых корней. С момента начала проектирования до первой строчки кода прошло 9 месяцев. Зато релиз вышел почти через год после начала разработки. Итог: от первой встречи с клиентом до релиза — один год и 11 месяцев. Ключевой конкурент потратил на это почти 5 лет с командой, в 3 раза больше нашей.</p><h3 class="wp-block-heading">Лень и возврат к общей картине</h3><p>Как я уже говорил, продумать <strong>всё</strong> невозможно. Да, вы были хороши и ваша высокоуровневая архитектура прекраснее, чем «Битва кентавров» Микеланджело. Но будьте готовы, что в процессе детальных изысканий вам придётся возвращаться на высокий уровень. И не просто возвращаться, а кое-где существенно его изменять.</p><p>Увлечение деталями иногда мешает вернуться к общей концепции. Это ведёт к потере видения конечной цели и необходимости исправлений.</p><p>Пример: </p><p class="highlighted">Я проектировал одного из своих <a href="https://sherer.pro/pets/wlist/">питомцев</a>. Вроде, предусмотрел всё, всю свою маркерную доску испещрил сценариями, был готов приступать к разработке. Осталось совсем немного: добить механики копирования пункта в собственный вишлист. А это повлекло за собой пересмотр механик регистрации (потому что теперь это нужно было делать не с отдельной страницы) и механик создания вишлиста (по той же причине). Пришлось возвращаться на высокоуровневое проектирование и изменять структуру API. Хорошо, код писать не начал, переписывал бы.</p><h2 class="wp-block-heading">Итог</h2><p>Если вы дочитали эту статью до конца, значит, у вас достаточно мотивации, чтобы начать (или продолжить) делать правильно. Если же вы просто проскроллили вниз — мои соболезнования (и ноль процентов осуждения). Всё, что я мог сделать, чтобы стабилизировать процесс проектирования и разработки, я в этом цикле сделал. </p><p>Дальше дело за вами. </p><p>Запись <a href="https://sherer.pro/blog/funkcionalnaya-arhitektura-cifrovyh-produktov-chast-5/">Функциональная архитектура цифровых продуктов, часть 5</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded></item><item><title>Функциональная архитектура цифровых продуктов, часть 4</title><link>https://sherer.pro/blog/funkcionalnaya-arhitektura-cifrovyh-produktov-chast-4/</link><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Wed, 28 Feb 2024 13:14:53 +0000</pubDate><category><![CDATA[Документация]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[гайд]]></category><category><![CDATA[функциональное проектирование]]></category><guid isPermaLink="false">https://sherer.pro/?p=3132</guid><description><![CDATA[<p>Как доказать бизнесу необходимость функциональной архитектуры. Почему нет универсального процесса создания ФА и что с этим делать.</p><p>Запись <a href="https://sherer.pro/blog/funkcionalnaya-arhitektura-cifrovyh-produktov-chast-4/">Функциональная архитектура цифровых продуктов, часть 4</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p>Вообще, эта статья планировалась последней. В ней я хотел рассказать про детальное проектирование и сложности, с которыми можно столкнуться при проработке функциональной архитектуры. Однако всё, как обычно, пошло не по плану. В какой-то момент я понял, что есть ещё ряд моментов, которым стоит уделить отдельное внимание.</p><p>Поэтому в этой статье мы поговорим о том, как убедить бизнес в необходимости проработки ФА и как выстроить пуленепробиваемый (ну почти) процесс её создания.</p><p>Погнали.</p><h2 class="wp-block-heading">Зачем бизнесу функциональная архитектура</h2><p>Об этом я уже вскользь упоминал в предыдущих частях цикла, теперь же пришло время малость углубиться. И начнём мы, пожалуй, издалека.</p><h3 class="wp-block-heading">Укрепление стандартов</h3><p>Многие из вас если не работали, то хотя бы слышали о <a href="https://ru.wikipedia.org/wiki/V-Model" target="_blank" rel="noreferrer noopener">V-модели</a> разработки ПО, одной из вариаций <a href="https://aws.amazon.com/ru/what-is/sdlc/" target="_blank" rel="noreferrer noopener">SDLC</a>. Она прекрасно себя зарекомендовала, огромное количество компаний создают удивительные продукты на её основе. Однако V-модель, как многие другие, скрывает одну фундаментальную ошибку проектного процесса.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba580405&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba580405" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="1620" height="820" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2024/01/V-model.png" alt="V-модель разработки программного обеспечения" class="wp-image-3957" srcset="https://sherer.pro/content/uploads/2024/01/V-model.png 1620w, https://sherer.pro/content/uploads/2024/01/V-model-1048x530.png 1048w, https://sherer.pro/content/uploads/2024/01/V-model-768x389.png 768w" sizes="auto, (max-width: 1620px) 100vw, 1620px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p>V-модель делает отдельный акцент на тестировании, это позволяет выпускать стабильные продукты с оптимальным Time to Market. Однако стабильность вовсе не означает качество. В погоне за соблюдением стандартов мы часто нарушаем баланс в проектировании.</p><p>Давайте будем честны, в V-модели (как и в большинстве других) всегда есть «главные» направления, которые задают тон всему проектированию. Как правило, такими «главными» становятся либо аналитики, либо дизайнеры. То есть обычно варианта два:</p><ul class="wp-block-list"><li>дизайнеры рисуют макеты по функциональным требованиям;</li><li>аналитики пишут требования, исходя из макетов.</li></ul><p>Ясное дело, я сейчас упростил. Не только «макеты» и не только «требования». Порой просто «лидирующие», а не всегда прям «главные». Не всегда лишь аналитики и дизайнеры, иногда ещё какие-нибудь инженеры (привет, психбольница Купера). Но суть, полагаю, ясна: кто-то всегда отталкивается от видения другой стороны.</p><p>И в этом кроется дьявол. Аналитики (простите, друзья) нифига не шарят в юиксе. Дизайнеры (сорри, гайз) почти ничего не знают о технологических особенностях продукта. Юзерфлоу произрастает из функциональных <strong>требований</strong> и превращается в монстра Франкенштейна, а требования к продукту запросто игнорируют фундаментальные <strong>потребности </strong>пользователей.</p><p>Кроме того, само понятие «функциональных требований» вызывает лично у меня крайне неоднозначные эмоции. В <a href="https://sherer.pro/blog/funkcionalnaja-arhitektura-cifrovyh-produktov-chast-1/#funkcionalnye-trebovaniya-i-opisanie-4">первой статье</a> цикла я упоминал, что функциональные «требования» и «описание» — отнюдь не одно и то же. Так вот V-модель подразумевает, что в разработку передаются именно «требования». А это значит, что «строители» начинают принимать решения за «инженеров» и даже «архитекторов». Потому что архитектурный максимум, на который способна классическая V-модель, это архитектура «системы».</p><p>Готовые модели и фреймворки часто игнорируют внутреннюю гармонию продукта. Почти всегда есть некоторый перекос в сторону дизайна, аналитики или инженерии. Причём не важно, Agile это, Incremental Model, RAD или Iterative Model.</p><figure class="wp-block-pullquote"><blockquote><p>Важный аспект: я не говорю, что все эти модели ошибочные или неверные. Я говорю лишь, что все они упускают важную часть продуктового процесса. А функциональная архитектура способна восполнять эти пробелы. Она совместима с любой из методологий и только укрепляет каждую из них.</p></blockquote></figure><p>Думаю, вывод здесь очевиден: для бизнеса такой перекос означает снижение качества продукта. Что в конечном счёте увеличивает стоимость его улучшения и развития.</p><p>Во второй части статьи я расскажу, как синхронизировать активность всех направлений, создавая единое и гармоничное представление о продукте у проектной команды.</p><h3 class="wp-block-heading">Снижение продуктовой энтропии</h3><p>Изначальный хаос — неотъемлемая часть любого проектного процесса. На старте всегда белых пятен больше, чем раскрашенных. Мы к этому привыкли, и наше «раскрашивание» чаще всего также носит хаотичный характер. Исследователи, аналитики, дизайнеры и «проектировщики» почти всегда закапываются в детали, стараясь здесь и сейчас максимально развеять неизвестность. Из-за этого они часто принимают решения без оглядки на общую картину. Не учитывая фундамент, базис продуктовых механик. Всё это ведёт не к снижению энтропии, а к её усугублению, пусть и отложенному. Иллюзия упорядоченности заставляет нас думать, что ситуация под контролем, тогда как на самом деле всё ровно наоборот.</p><p>Другими словами, мы проектируем продукты по кускам, максимально углубляясь в ту часть, которой сейчас занимаемся. Продумываем экран каталога? Надо сразу понять, что и <strong>как</strong> отображать на каждой карточке товара. Проектируем чат? Давайте тут же решим, будет ли возможность преобразовывать текст в эмодзи. И не важно, что потом принятые нами решения станут барьерами, ограничениями продукта — потому что создавались без оглядки на общую картину. Ведь общей картины-то на тот момент и не было.</p><p>Приведу пример. На заре моего аналитического опыта был у меня проект по цифровому депонированию объектов интеллектуальной собственности. Такое электронное подтверждение авторства. Основой сервиса была форма загрузки контента, и я, по неопытности, сделал именно на ней основной акцент. Мы с аналитиками и дизайнерами вылизали эту форму до блеска. Она была идеальной, но абсолютно не учитывала категории пользователей. Как потом оказалось, жизненный цикл юридических и физических лиц в продукте отличается очень и очень сильно. Нам пришлось серьёзно переработать форму депонирования и её логику, так как с юридической точки зрения заполняемые поля значительно отличались. Мы потратили время и ресурсы на проработку того, что потом поменялось более чем на 70%. Более того, разработчики к тому времени уже сформировали определённый фундамент, и им тоже пришлось многое переделывать.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba580820&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba580820" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="940" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2023/12/functional-arch-steps.png" alt="Этапы проработки функциональной архитектуры" class="wp-image-3885" srcset="https://sherer.pro/content/uploads/2023/12/functional-arch-steps.png 2096w, https://sherer.pro/content/uploads/2023/12/functional-arch-steps-1048x470.png 1048w, https://sherer.pro/content/uploads/2023/12/functional-arch-steps-768x344.png 768w" sizes="auto, (max-width: 2096px) 100vw, 2096px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Высокоуровневое и детальное функциональное проектирование</figcaption></figure><p>Работа над функциональной архитектурой подразумевает этап высокоуровневого проектирования, и именно на нём выравниваются подобные моменты. Сначала продумали базис, и уже на него наложили детальное описание функций. Это позволяет не только стабилизировать проектирование и разработку, но и повышает общее качество продукта.</p><p>И нет, это не waterfall. Проектирование может и должно осуществляться итерационно.</p><h3 class="wp-block-heading">Снижение издержек</h3><p>Как обычно происходит передача требований в разработку? Берутся макеты, UX-спецификация (если вы крутые), какие-нибудь функциональные и нефункциональные требования, всякие User Stories, Use Cases, User Flows — и отправляются разработчикам. Которые анализируют все эти (зачастую разрозненные) артефакты и решают, как именно должна работать система. Иногда в процесс встраиваются системные аналитики, которые немного упрощают процесс анализа — но даже они не проектируют функции продукта. Максимум, прорабатывают интеграционные механики и глобальную (не функциональную) архитектуру.</p><p>При этом важно понимать, что чаще всего разработчики анализируют не всю систему, а только её часть. Ту часть, которая им прилетела в рамках очередной итерации/спринта. Это значит, что единой функциональной картины нет ни у кого. Одни и те же функции могут быть написаны два раза, другие могут не учитывать особенности уже написанных. Если проект действительно сложный, то со временем это приводит к накоплению так называемого «технического долга», который тоже почему-то стал нормой индустрии.</p><figure class="wp-block-pullquote"><blockquote><p>Мы с вами привыкли, что цифровые продукты уже в процессе своего создания включают в себя устаревшие фрагменты, legacy. Такое, блин, возможно только в IT.</p></blockquote></figure><p>Круто, если на проекте есть выделенный архитектор. Но даже он обычно проектирует не функциональную модель, а облачную или программную. Сильный техлид уменьшит количество проблемных участков кода, но даже он не способен постоянно помнить о всех функциях системы. Закон Миллера вполне конкретно <a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D0%B3%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D1%87%D0%B8%D1%81%D0%BB%D0%BE_%D1%81%D0%B5%D0%BC%D1%8C_%D0%BF%D0%BB%D1%8E%D1%81-%D0%BC%D0%B8%D0%BD%D1%83%D1%81_%D0%B4%D0%B2%D0%B0" target="_blank" rel="noreferrer noopener">определяет</a> количество элементов, которые может удержать в кратковременной памяти обычный человек: максимум 9. Даже если наш архитектор/техлид гений и может в два раза больше — это не сравнимо с количеством функций даже самой простой цифровой системы.</p><p>Разумеется, всё это приводит к усложнению поддержки и развития продукта. Дорабатывать его становится сложно, внедрение каждой новой фичи стоит всё больше и больше денег.</p><p>Функциональная архитектура — не серебряная пуля. Она не решит всех проблем. Но она, как минимум, снимет часть издержек за счёт изначальной стабилизации проектирования и разработки.</p><h2 class="wp-block-heading">Проектное взаимодействие</h2><p>Окей, с этим понятно. Но ведь бизнес — это не только про сокращение издержек и энтропии. Это ещё и про отлаженные и эффективные процессы. В том числе, про процессы проектирования, аналитики и продуктового дизайна в целом. Как же внедрить проработку функциональной архитектуры? Кто за неё отвечает и как она ложится на остальные проектные артефакты, вроде той же CJM или User Stories?</p><p>Давайте разбираться.</p><h3 class="wp-block-heading">Шаблонизация</h3><p>И начать я хочу с тезиса, который может вас немного разочаровать. Любые шаблоны в ФА — безусловное зло. Да, могут быть какие-то методологические форматы отдельных артефактов. Да, унификация документации важна (особенно, если над ней трудятся несколько человек одновременно). Но глобальных шаблонов, кочующих из проекта в проект, быть не должно.</p><figure class="wp-block-pullquote"><blockquote><p>Универсальных схем не существует, хотя вы все их и любите</p></blockquote></figure><p>Почему так? Потому что любая архитектура должна подстраиваться под продуктовые и проектные реалии. Но никак не наоборот. Когда вы начинаете выстраивать архитектуру (причём не только функциональную) с помощью жёстких шаблонов и «устоявшихся» паттернов, вы накладываете на продукт серьёзные ограничения. Причём ограничения, зачастую абсолютно ничем, кроме вашего опыта, не оправданные.</p><p>В <a href="https://sherer.pro/blog/funkcionalnaya-arxitektura-cifrovyx-produktov-chast-3/">предыдущей части</a> цикла я приводил пример того, как по-разному может проектироваться один и тот же набор общих функций. Всё зависит от особенностей проекта, начиная с его бюджета и заканчивая UX-тонкостями.</p><h3 class="wp-block-heading">Авторы функциональной архитектуры</h3><p>Кто читал <a href="https://sherer.pro/blog/funkcionalnaja-arhitektura-cifrovyh-produktov-chast-2/">вторую статью</a>, тот наверняка помнит функциональные сценарии. Это такая стероидная смесь из <a href="https://ru.wikipedia.org/wiki/BPMN">BPMN</a> и <a href="https://ru.wikipedia.org/wiki/%D0%94%D0%B8%D0%B0%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0_%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D0%B8" target="_blank" rel="noreferrer noopener">sequence diagram</a>:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba580cc8&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba580cc8" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="1660" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2023/12/functional-arch-login.png" alt="Функциональный сценарий логина" class="wp-image-3888" srcset="https://sherer.pro/content/uploads/2023/12/functional-arch-login.png 2096w, https://sherer.pro/content/uploads/2023/12/functional-arch-login-1048x830.png 1048w, https://sherer.pro/content/uploads/2023/12/functional-arch-login-768x608.png 768w" sizes="auto, (max-width: 2096px) 100vw, 2096px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p>Если внимательно присмотреться к ФС, то можно увидеть, что они, в числе прочего, описывают и пользовательский путь. А значит, включают в себя значительную часть UX. Но при этом здесь есть и серверная логика, и какие-то технологические особенности системы.</p><p>Типичный аналитик вряд ли способен качественно проработать навигацию и опыт пользователя. Даже хороший продуктовый дизайнер может не знать нюансы аутентификации через <a href="https://en.wikipedia.org/wiki/Identity_provider" target="_blank" rel="noreferrer noopener">IdP</a>. Но если ни дизайнер, ни аналитик не могут самостоятельно проработать функциональную архитектуру, то кто же должен ею заниматься? Вариантов несколько.</p><p>Иногда находится супердизайнер. Достаточно подкованный, чтобы решать базовые технические вопросы и достаточно опытный, чтобы отделить свои знания от незнаний — и сходить за последними к архитекторам и разработчикам.</p><p>Иногда аналитики работают с дизайнерами в такой плотной связке, что все вопросы решаются сами собой: эти два столпа проектирования решают всё в реальном времени (и даже учитывают мнение будущих разработчиков).</p><p>Оба упомянутых варианта хороши. У обоих есть определённые недостатки (вроде того же уровня абстракции), но оба в определённом контексте жизнеспособны. Однако я хочу предложить вам третий, более универсальный, подход.</p><h3 class="wp-block-heading">Перекрёстное опыление</h3><p>То, о чём я хочу рассказать, мой хороший друг Олег Будко назвал «перекрёстным опылением». Именно оно позволяет не допускать перекоса в сторону дизайна, аналитики или инженерии, а также создавать действительно <strong>консистентную</strong> проектную документацию.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba581005&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba581005" class="wp-block-image size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="3676" height="732" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2024/02/functional-arch-workflow.png" alt="" class="wp-image-4114" srcset="https://sherer.pro/content/uploads/2024/02/functional-arch-workflow.png 3676w, https://sherer.pro/content/uploads/2024/02/functional-arch-workflow-1048x209.png 1048w, https://sherer.pro/content/uploads/2024/02/functional-arch-workflow-768x153.png 768w" sizes="auto, (max-width: 3676px) 100vw, 3676px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Пример схемы проектирования функциональной архитектуры</figcaption></figure><p>Из этой схемы видно, что дизайн и аналитика синхронизируются минимум 5 раз при создании каждого функционального слоя: при проработке (и доработке) концепции, функциональной модели, сценариев, <a href="https://sherer.pro/blog/informacionnaya-arxitektura-kratkij-ekskurs/">информационной архитектуры</a> и сведения экранов и функций.</p><p>Давайте чуть подробнее пройдёмся по каждой вехе (за исключением IA, она вне рамок этой статьи).</p><h4 class="wp-block-heading">Концепция</h4><p>Чтобы приступить к осознанному проектированию функциональной архитектуры, нужно сперва собрать требования к продукту и провалидировать их.</p><p>Здесь дизайнеры прорабатывают базовую ролевую модель, потребности и особенности будущих пользователей системы. Аналитики вместе с ними, а также с бизнесом и технарями решают, каким образом продукт закрывает интересы всех заинтересованных сторон. В итоге у нас формируются ключевые механики, функциональные границы и (иногда) ролевая матрица создаваемой системы. Это объёмный этап, чуть подробнее я описывал его в небольшом <a href="https://sherer.pro/blog/pochemu-vashemu-proektu-nuzhna-koncepciya/">цикле</a> про концепцию.</p><h4 class="wp-block-heading">Функциональная модель</h4><p>После того, как мы решили, какими базовыми функциями должен обладать наш продукт на старте, самое время определить их иерархию и верхнеуровневую взаимосвязь. Один из способов это сделать — составить функциональную модель:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba58137c&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba58137c" class="wp-block-image size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2840" height="1482" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2024/02/functional-model.png" alt="Пример функциональной модели" class="wp-image-4087" srcset="https://sherer.pro/content/uploads/2024/02/functional-model.png 2840w, https://sherer.pro/content/uploads/2024/02/functional-model-1048x547.png 1048w, https://sherer.pro/content/uploads/2024/02/functional-model-768x401.png 768w" sizes="auto, (max-width: 2840px) 100vw, 2840px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Пример очень простой функциональной модели</figcaption></figure><p>Здесь горизонтальные свимлайны — это компоненты, микросервисы или просто логическое разделение функций. В примере выше это «пользователь», «новости» и «кабинет». Внутри свимлайнов находятся функциональные разделы, каждый из которых может включать в себя как дочерние разделы, так и отдельные функции.</p><p>В идеале, эта модель будет неизменной, ведь мы уже очертили границы продукта. Мы понимаем, <em>каким образом будем решать задачи бизнеса и удовлетворять потребности пользователей</em>.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Однако в реальности модель может изменяться и актуализироваться — особенно если проект действительно большой</p></blockquote><p>Дизайнеры пилят (или допиливают) CJM, опираясь на функциональную модель. Аналитики изучают CJM и мапят её со своей моделью. Если в модели отсутствует какой-то функциональный раздел, который подразумевается в CJM (например, онбординг), то это очень быстро выявляется.</p><p>После того, как первая версия модели готова, мы можем приступить к итерациям высокоуровневого проектирования. Например, начинаем прорабатывать логин и регистрацию.</p><h4 class="wp-block-heading">Функциональные сценарии и описание</h4><p>Аналитики расшивают функциональную модель на более мелкие разделы, внутри которых уже описывают функциональные сценарии и описание функций. Разумеется, подглядывая в доки дизайн-команды. Дизайнеры смотрят на эти сценарии и сравнивают их со своими user/screen flow, user stories и тп. Конкретный набор артефактов со стороны дизайна не важен, у каждого проекта/команды свой набор. Важна регулярная синхронизация.</p><p>На выходе мы получаем проработанную итерацию ФА, консистентную и согласованную.</p><h4 class="wp-block-heading">Экраны, состояния и функции</h4><p>Когда сценарии и описание функций завершены, можно приступать к финалу проектирования — дизайн-макетам и UX-спецификациям. Разумеется, к этому этапу должна быть проведена колоссальная работа вне рамок функциональной архитектуры: начиная от дизайн-концепции, тьмы исследований, детальной проработки UX — и заканчивая информационной архитектурой, навигационной моделью и тп. Однако мы здесь говорим, напоминаю, исключительно о функциональном слое.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba581771&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba581771" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2224" height="804" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2024/02/image-1.png" alt="" class="wp-image-4130" srcset="https://sherer.pro/content/uploads/2024/02/image-1.png 2224w, https://sherer.pro/content/uploads/2024/02/image-1-1048x379.png 1048w, https://sherer.pro/content/uploads/2024/02/image-1-768x278.png 768w" sizes="auto, (max-width: 2224px) 100vw, 2224px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Фрагмент функционального сценария</figcaption></figure><p>Обратите внимание, что над всеми системными функциями в верхней, клиентской, области есть названия и состояние экранов. Над функцией «Переход к состоянию успешной регистрации» есть надпись «Nav.Authn, ValidationSuccess». Так вот «Nav.Authn» — это название экрана, а «ValidationSuccess» — его состояние.</p><p>Такая нотация позволяет:</p><ul class="wp-block-list"><li>связывать функциональные сценарии с конкретными макетами (например, в той же Figma); </li><li>не заставлять разработчиков, аналитиков, сеошников и прочих продираться сквозь толщи документации и искать взаимосвязи там, где их нет.</li></ul><p>А теперь представьте, что текст «Nav.Authn, ValidationSuccess» может быть ссылкой, ведущей на конкретный фрейм в фигме (тот же draw.io позволяет это делать). И разработчику даже не нужно соотносить функции и экраны, за него это уже сделано! Он просто пишет код — то есть делает то, в чём реально хорош. Мы не заставляем его глубоко анализировать проектную документацию. У него есть функциональные сценарии и описание функций. Они слинкованы с конкретными макетами. Вся логика системы понятна и прозрачна.</p><h2 class="wp-block-heading">Итог</h2><p>Мы разобрали не только важность ФА для бизнеса и этапы её создания/синхронизации, но и одной ногой залезли в детальное функциональное проектирование. Это не страшно, в следующей статье я планирую ещё глубже раскрыть эту тему. </p><p>Здесь же главный посыл простой: ФА способна стабилизировать практически любую модель разработки ПО, и (при грамотном подходе) сделает это легко, изящно и с выгодой для бизнеса.</p><p>Запись <a href="https://sherer.pro/blog/funkcionalnaya-arhitektura-cifrovyh-produktov-chast-4/">Функциональная архитектура цифровых продуктов, часть 4</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded></item><item><title>Функциональная архитектура цифровых продуктов, часть 3</title><link>https://sherer.pro/blog/funkcionalnaya-arxitektura-cifrovyx-produktov-chast-3/</link><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Fri, 07 Oct 2022 08:21:00 +0000</pubDate><category><![CDATA[Документация]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[гайд]]></category><category><![CDATA[функциональное проектирование]]></category><guid isPermaLink="false">https://sherer.pro/?p=2509</guid><description><![CDATA[<p>Про общие функции, разницу подходов, зависимости и клиент-серверную функциональную архитектуру.</p><p>Запись <a href="https://sherer.pro/blog/funkcionalnaya-arxitektura-cifrovyx-produktov-chast-3/">Функциональная архитектура цифровых продуктов, часть 3</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p>Вы читаете третью статью цикла про функциональное проектирование. В <a href="https://sherer.pro/blog/funkcionalnaja-arhitektura-cifrovyh-produktov-chast-1/">первой</a> части мы говорили о задачах ФА, во <a href="https://sherer.pro/blog/funkcionalnaja-arhitektura-cifrovyh-produktov-chast-2/">второй</a> — о высокоуровневом проектировании. Если не читали их, настоятельно рекомендую. Будет проще вникнуть в текст ниже.</p><p>Для начала давайте вернёмся немного назад и ещё раз пройдёмся по терминам и проблемам, которые решает функциональная архитектура. Теперь немного с другого ракурса и чуть более глубоко.</p><h2 class="wp-block-heading">Общие функции</h2><p>Я уже писал о том, что происходит, когда разработчикам явно не указывают на <em>общие функции</em> продукта. В лучшем случае вы рискуете получить копипаст одной и той же функциональности. В худшем — один и тот же кусок ваших интерфейсов и логики будет написан два раза. Такие вещи серьёзно усложняют дальнейшую поддержку проекта, снижают динамику его развития. Рефакторинг становится неотъемлемой частью проектного процесса, на него уходит всё больше ресурсов. В итоге растут бюджеты, сдвигаются сроки. И когда вы захотите внедрить новую фичу, вдруг окажется, что этих самых ресурсов на неё уже не хватает.</p><p> В предыдущей статье я приводил в качестве примеров общих функций &#171;листинг&#187;, работу с формами, показ системных сообщений и другие. Однако подобных моментов в любом проекте намного больше. Общие функции отнюдь не всегда лежат на поверхности, зачастую выявление их становится отдельной задачей проектирования. </p><figure class="wp-block-pullquote"><blockquote><p>Научившись видеть, находить и формализовать &#171;сквозную&#187; функциональность вашего продукта, вы существенно повышаете его шансы на выживание</p></blockquote></figure><h3 class="wp-block-heading">Выявление</h3><p>Осталось всего лишь понять, как же выделять эти самые общие функции. Вам повезло, это как раз тот случай, когда правильно заданный вопрос несёт в себе значительную часть ответа.</p><p>Вы можете просто спрашивать себя, не используется ли эта конкретная функция где-то ещё — и для небольших проектов такого подхода может даже хватить. Но с увеличением сложности проекта будет расти и количество функций, их взаимосвязей. В какой-то момент окажется, что удержать в голове всю функциональность системы больше не представляется возможным.</p><p>Способов выявления общих функций множество. Можно составлять <em>матрицу функциональных свойств объектов</em>: на основе <a href="https://sherer.pro/blog/informacionnaya-arxitektura-kratkij-ekskurs/" target="_blank" rel="noreferrer noopener">информационной архитектуры</a> составить список всех сущностей и возможных манипуляций с ними. Или выстроить саму структуру документации так, чтобы она сама подсказывала вам места, где функции продукта пересекаются или повторяются.</p><p>К сожалению, этот цикл не задумывался как полноценное руководство — если вам интересно, пишите в комментариях. Может быть, сделаю отдельную статью по методологиям поиска и фиксации общей функциональности.</p><h3 class="wp-block-heading">Пример</h3><p>В любом случае, говорить об <strong>общих функциях</strong> абстрактно смысла не имеет. Нужна конкретика. Посему вот вам короткий пример таких разделов и функций, частенько встречающихся в мобильных и веб-приложениях:</p><ul class="wp-block-list"><li><strong>Показ системных сообщений.</strong> Общая функция вывода системных сообщений в интерфейс: негативных, информационных или позитивных. Может принимать параметры (статус, текст и приоритет).</li><li><strong>API.</strong> Объёмный функциональный раздел, отвечающий за обмен данными между клиентом (сайтом, мобильным приложением, голосовым помощником etc.) и сервером.<ul class="wp-block-list"><li><strong>Отправка запроса.</strong> Функция отправки запроса на сервер. Всегда включает в себя параметры (как минимум адрес и, собственно, передаваемые данные). Может совмещаться с авторизационными действиями: очень часто <em>тело </em>запроса содержит в себе данные, а <em>заголовки</em> запроса &#8212; авторизационную информацию (подробнее об этом в <a href="https://sherer.pro/blog/dizajn-dannyh-chast-3-menjaemsja/?highlight=%D0%B7%D0%B0%D0%B3%D0%BE%D0%BB%D0%BE%D0%B2%D0%BA%D0%B8#zagolovki">дизайне данных</a>).</li><li><strong>Обработка ответа.</strong> Вызывает другие функции, в зависимости от ответа сервера (у разработчиков это называется callback-функции). Например, может использовать функцию <strong>&#171;Показ системных сообщений&#187;</strong>.</li></ul></li><li><strong>Формы.</strong> Общий функциональный раздел для работы с формами.<ul class="wp-block-list"><li><strong>Валидация полей форм.</strong> Общая функция проверки на корректность заполнения полей форм, включает в себя дочерние функции:<ul class="wp-block-list"><li>проверка на обязательное поле,</li><li>проверка корректности email,</li><li>проверка корректности номера телефона,</li><li>проверка корректности даты и/или времени,</li><li>проверка корректности чисел,</li><li>проверка по <a href="https://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D0%B5_%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F" target="_blank" rel="noreferrer noopener">регулярному выражению</a> (сама регулярка передаётся параметром).</li></ul></li><li><strong>Показ сообщений форм.</strong> Показ сообщений о событиях форм (сообщение отправлено, поле &#171;email&#187; заполнено неверно и тп). Может использовать другую общую функцию <strong>&#171;Показ системных сообщений&#187;</strong>.</li><li><strong>Данные форм. </strong>Общая функция обмена данными форм с сервером.<ul class="wp-block-list"><li><strong>Отправка данных формы. </strong>Общая функция на клиенте (браузер, мобильное приложение), отвечающая за передачу данных формы на сервер. Может использовать функцию <strong>&#171;API → отправка запроса&#187;</strong>.</li><li><strong>Обработка ответа. </strong>В зависимости от ответа сервера, выполняет те или иные действия (показ сообщения об ошибке, перенаправление на другой экран и тп). Может использовать функцию <strong>&#171;API → обработка ответа&#187;</strong>.</li></ul></li></ul></li><li><strong>Наличие сети.</strong> Проверка наличия доступа к Интернету при загрузке экранов и отправке форм. Может включать в себя дочерние функции (например, для блокировки интерфейса мобильного приложения или <a href="https://developer.mozilla.org/ru/docs/Web/API/Service_Worker_API" target="_blank" rel="noreferrer noopener">отложенной отправки</a> данных форм, когда появится интернет).</li><li><strong>Обновление экрана. </strong>Обновление содержимого экрана мобильного приложения (например, по свайпу вниз). Всегда инициирует выполнение других функций.</li><li><strong>Аналитика.</strong> Общая функция отправки данных в аналитику.<ul class="wp-block-list"><li><strong>Переход.</strong> Отправка в аналитику перехода между экранами. Во многих SDK эта функция реализуется &#171;из коробки&#187;.</li><li><strong>Событие.</strong> Отправка в аналитику отдельного события (например, добавления товара в корзину или шэринга поста в соцсети).</li></ul></li></ul><h3 class="wp-block-heading">Разница подходов</h3><p>Внимательный читатель заметит, что общие функции в этой и предыдущей статьях формируются по несколько разным принципам. Например, в прошлой статье нет общей функции форм, всё сведено просто к данным. Зато там есть функция &#171;очередь сообщений&#187;, а здесь её нет — очередь сообщений формируется автоматически на основе параметра &#171;приоритет&#187;. </p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba5829b4&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba5829b4" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="3180" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2023/12/functional-arch-commons-dif.png" alt="" class="wp-image-3903" srcset="https://sherer.pro/content/uploads/2023/12/functional-arch-commons-dif.png 2096w, https://sherer.pro/content/uploads/2023/12/functional-arch-commons-dif-1048x1590.png 1048w, https://sherer.pro/content/uploads/2023/12/functional-arch-commons-dif-768x1165.png 768w" sizes="auto, (max-width: 2096px) 100vw, 2096px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Два подхода к выявлению общих функций</figcaption></figure><p>Это сделано не случайно, а в качестве иллюстрации к основному посылу всего цикла:</p><blockquote class="wp-block-quote is-style-default is-layout-flow wp-block-quote-is-layout-flow"><p>Вы сами решаете, какими будут структура и состав вашей функциональной архитектуры. Любая шаблонизация ставит под угрозу стабильность и результат проектирования. Руководствуйтесь здравым смыслом, не стесняйтесь консультироваться у специалистов.</p></blockquote><p>Вообще, возобладание шаблонов над разумом — бич современного проектирования. Думайте, сравнивайте подходы. Выстраивайте собственный рабочий флоу под специфику каждого проекта.</p><h2 class="wp-block-heading">Зависимые функции</h2><p>Об общих функциях мы поговорили. Настало время небольшой части про взаимосвязь функций, их зависимость друг от друга.</p><p>Современные цифровые продукты не создаются сами по себе. Они всегда состоят из огромного количества внешних компонентов, фреймворков, библиотек и плагинов. Даже простой лэндинг в 90% случаев верстался с использованием <a href="https://developer.mozilla.org/ru/docs/Glossary/CSS_preprocessor" target="_blank" rel="noreferrer noopener">препроцессоров</a>, систем <a href="https://ru.wikipedia.org/wiki/Webpack" target="_blank" rel="noreferrer noopener">сборки </a>и <a href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8F%D0%BC%D0%B8" target="_blank" rel="noreferrer noopener">контроля версий</a>, различных <a href="https://docs.npmjs.com/about-packages-and-modules" target="_blank" rel="noreferrer noopener">модулей</a>. Все эти штуки имеют собственные зависимости, без закрытия которых ваш проект просто не соберётся.</p><p>Так и в функциональной архитектуре. Функции имеют разный уровень и зависят друг от друга. Есть базовые, фундаментальные, на которых строится вся система. Есть более высокоуровневые, которые обеспечивают взаимодействие остальных.</p><p>Вот вам простой пример. Ваши разработчики не смогут написать функцию <em>подтверждения номера телефона</em>, пока не будут спроектированы и реализованы более фундаментальные функции <em>обработки запроса на сервере</em> и <em>отправки SMS</em>.</p><figure class="wp-block-pullquote"><blockquote><p>Выявить взаимосвязь функций — значит правильно расставить приоритеты реализации</p></blockquote></figure><h3 class="wp-block-heading">Иерархическая зависимость</h3><p>Вот смотрите. Допустим, функция <em>отправки SMS</em> используется нами лишь в одном месте: когда пользователь подтверждает номер телефона. Мы совершенно уверены, что больше никто и нигде не будет отправлять SMS в нашем проекте. Это значит, что <em>отправка SMS</em> — не общая функция, и приступить к её разработке можно будет, когда мы доберёмся до, собственно, подтверждения номера. </p><p>Тогда как функция <em>обработки запроса</em> является базовой, без неё не получится в принципе обеспечить обмен данными с клиентом (браузером или мобильным приложением). Следовательно, её стоит написать с самого начала, сделав её <strong>общей функцией</strong>. Однако и она, в свою очередь, тоже зависит от других: <em>валидация данных</em>, <em>очистка параметров</em> (для предотвращения <a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D1%8B%D0%B9_%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%B8%D0%BD%D0%B3" target="_blank" rel="noreferrer noopener">XSS-атак</a>, например). А значит, мы сперва должны спроектировать и реализовать именно их, иначе столкнёмся с ситуациями, описанными в <a href="https://sherer.pro/blog/funkcionalnaja-arhitektura-cifrovyh-produktov-chast-1/" target="_blank" rel="noreferrer noopener">первой части</a> цикла.</p><h3 class="wp-block-heading">Линейная зависимость</h3><p>Это был пример <strong>иерархической зависимости</strong> функций, когда уровень диктует порядок проектирования и реализации. </p><p>Но есть и другой вид — <strong>линейная</strong>, или <strong>параллельная</strong> <strong>взаимосвязь</strong>. Хороший пример: регистрация. Допустим, в вашем проекте можно зарегистрироваться с помощью email и через сервисы/соцсети. Классическая ситуация. Однако поразмыслив, вы решаете в первом релизе ограничиться какой-то одной, например, через email. Вы её проектируете, даёте задание разработчикам. Разработчики разрабатывают. Вы довольны. Но довольными вы будете ровно до тех пор, пока не придёт время реализовывать вторую часть, регистрацию через внешние сервисы.</p><p>Внезапно окажется, что в базе данных нет необходимых полей для фиксации типа соцсети и ключа, который она возвращает. А сама функция заведения аккаунта жёстко завязана на механику обработки формы с email и паролем. Кроме того, ваша регистрация не умеет обрабатывать ситуацию, когда у пользователя не указан email, а такое может случиться:</p><figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="1310" height="859" src="https://sherer.pro/content/uploads/2021/08/vk_restrict.png" alt="" class="wp-image-3058" srcset="https://sherer.pro/content/uploads/2021/08/vk_restrict.png 1310w, https://sherer.pro/content/uploads/2021/08/vk_restrict-768x504.png 768w, https://sherer.pro/content/uploads/2021/08/vk_restrict-1048x687.png 1048w" sizes="auto, (max-width: 1310px) 100vw, 1310px" /><figcaption class="wp-element-caption">Пример запрета на предоставление email при регистрации через ВКонтакте</figcaption></figure><p>Конечно, это всё решаемо. Поля в БД можно добавить, регистрацию переписать. Только зачем, если можно с самого начала сделать правильно? Спроектировать сразу обе, передать разработчикам и сказать, что пока нужно делать только одну?</p><p><strong>Линейная зависимость</strong> функций самая неочевидная. Вы даже не представляете, сколько велосипедов и костылей таится в тех продуктах, которыми мы пользуемся каждый день. Костылей, появившихся из-за того, что кто-то просто поленился подумать.</p><h2 class="wp-block-heading">Серверные и клиентские функции</h2><p>Все функции большинства цифровых продуктов можно разделить на два типа: клиентские и серверные — в зависимости от того, где они выполняются (иногда бывает ещё один слой — уровень баз данных, если в БД присутствует своя логика). Но зачем вообще требуется такое разделение?</p><p>Снова приведу пример. Вот есть у вас общая <em>функция валидации</em> с переданным<em> параметром</em> «email». Что она должна уметь делать? Проверять корректность введённых или переданных данных — и всё, вроде. Но нет.</p><h3 class="wp-block-heading">Клиент</h3><p>На клиенте (например, в браузере) она должна проверять корректность введённых данных и:</p><ul class="wp-block-list"><li>Если данные не валидны:<ul class="wp-block-list"><li>визуально изменять поле (изменять цвет текста и границ на красный);</li><li>выводить сообщение «некорректный email» рядом с полем;</li><li>запрещать отправку формы.</li></ul></li><li>Если данные валидны:<ul class="wp-block-list"><li>скрывать сообщение и возвращать визуальное состояние поля (если ранее оно было заполнено неверно);</li><li>передавать управление функции отправки данных на сервер.</li></ul></li></ul><h3 class="wp-block-heading">Сервер</h3><p>В то же время, на сервере должна быть своя валидация, потому что клиентскую легко обойти (и выполнить, например, <a href="https://ru.wikipedia.org/wiki/%D0%92%D0%BD%D0%B5%D0%B4%D1%80%D0%B5%D0%BD%D0%B8%D0%B5_SQL-%D0%BA%D0%BE%D0%B4%D0%B0" target="_blank" rel="noreferrer noopener nofollow">SQL-инъекцию)</a>. Поэтому серверная валидация также должна проверять корректность полученных данных:</p><ul class="wp-block-list"><li>Если данные некорректны:<ul class="wp-block-list"><li>возвращать на клиент ошибку с текстом «некорректный email» и признаком поля, рядом с которым нужно показать сообщение;</li><li>прерывать выполнение.</li></ul></li><li>Если данные корректны, возвращать управление функции обработки данных форм (например, регистрации), где уже происходит <em>очистка данных </em>и их запись в БД.</li></ul><p>И это — только банальная валидация. Представьте, насколько сложно на таком уровне грамотно спроектировать даже привычную нам <a href="https://sherer.pro/blog/registracija-i-login-na-steroidah/">функцию регистрации</a>?</p><p>Проектировать и описывать необходимо не только клиентскую часть. Серверная не менее важна, а чаще всего — даже более. Именно через уязвимости в логике кода на сервере и происходят всякие неприятные вещи, которые потом могут шарахнуть по пользователям и бизнесу.</p><figure class="wp-block-pullquote is-style-default"><blockquote><p>Перекладывать проектирование клиент-серверного взаимодействия на обычных программистов — это всё равно что предоставить строителям возможность определять технические характеристики многоэтажного дома.</p></blockquote></figure><h2 class="wp-block-heading">Итог</h2><p>Функциональное проектирование — это не просто перечисление функций будущего продукта. Это громадная работа по их анализу, выявлению взаимосвязей и потенциальных дубликатов. В следующей части я немного расскажу о том, как связывать функциональное проектирование, аналитику и UI/UX, а также о парочке неочевидных решений.</p><p>Запись <a href="https://sherer.pro/blog/funkcionalnaya-arxitektura-cifrovyx-produktov-chast-3/">Функциональная архитектура цифровых продуктов, часть 3</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded></item><item><title>User Story Mapping и функциональная архитектура</title><link>https://sherer.pro/blog/user-story-mapping-i-funkcionalnaya-arxitektura/</link><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Fri, 09 Jul 2021 08:49:47 +0000</pubDate><category><![CDATA[UX/UI]]></category><category><![CDATA[Аналитика]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[гайд]]></category><category><![CDATA[методологии]]></category><category><![CDATA[функциональное проектирование]]></category><guid isPermaLink="false">https://sherer.pro/?p=2985</guid><description><![CDATA[<p>Что общего у функциональной архитектуры и персонажей Купера? Как User Story Mapping решает проблемы со структуризацией требований, стратегией разработки и границами проекта.</p><p>Запись <a href="https://sherer.pro/blog/user-story-mapping-i-funkcionalnaya-arxitektura/">User Story Mapping и функциональная архитектура</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p>Каждый, кто запускал IT-проекты или участвовал в продуктовых исследованиях, наверняка слышал про метод <a href="https://onezero.medium.com/in-1983-i-created-secret-weapons-for-interactive-design-d154eb8cfd58" target="_blank" rel="noreferrer noopener"><strong>персон Алана Купера</strong></a> и <strong>User Story</strong>. И пусть некоторые считают персон нерабочей и устаревшей методологией — я убеждён, что это всего лишь результат многолетней <a href="https://sherer.pro/blog/personazhi-po-kuperu-kak-diskreditirovat-metodologiyu/" target="_blank" rel="noreferrer noopener">вандализации метода</a>.</p><p>В этой статье я хочу рассказать о том, как «продолжение» User Story может не только улучшить UX продуктов, но и решить кое-какие фундаментальные проблемы их разработки.</p><p>Цифровые продукты редко запускаются гладко. Правки к сценариям, функциональности и макетам зачастую возникают прямо в процессе реализации. Никто никогда не в курсе, куда несётся поезд продуктовой разработки — а обратное чувство, чаще всего, обманчиво.</p><p><strong>Персоны </strong>и <strong>User Story</strong> — это такая прикольная штуковина для того, чтобы погрузить всех участников в проектный процесс, выявить и подсветить истинные задачи пользователей. Однако сами по себе персоны практически не влияют на процесс создания продуктов, лишь на их функциональность. Чего нельзя сказать о следующем этапе развития пользовательских историй — о <strong>User Story Mapping</strong>.</p><p>Об этом подходе написано уже немало, в том числе и на русском языке. Но большинство таких статей (на мой субъективный взгляд) либо весьма поверхностны, либо имеют серьёзный перекос в сторону именно UX, практически игнорируя аспект управления и развития продукта. Однако я искренне благодарен авторам таких статей, ибо понахватал оттуда приличное количество тезисов и умозаключений.</p><h2 class="wp-block-heading">Проблемы</h2><p>Для начала давайте разберём некоторые глобальные трудности и барьеры, возникающие при создании цифровых продуктов.</p><h3 class="wp-block-heading">Требования к продукту плохо структурированы по отношению друг к другу</h3><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba583c92&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba583c92" class="wp-block-image aligncenter size-large wp-lightbox-container"><img loading="lazy" decoding="async" width="1200" height="400" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2021/07/usm-1.png" alt="" class="wp-image-3010" srcset="https://sherer.pro/content/uploads/2021/07/usm-1.png 1200w, https://sherer.pro/content/uploads/2021/07/usm-1-768x256.png 768w, https://sherer.pro/content/uploads/2021/07/usm-1-1048x349.png 1048w" sizes="auto, (max-width: 1200px) 100vw, 1200px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p>Нет иерархии и последовательности требований. Не всегда понятно, какая задача какую блокирует и от какой зависит. Чаще всего зависимость задачи проставляется исключительно командой разработчиков или тимлидом — но они не владеют общим видением продукта, руководствуясь только своими представлениями о локальном участке архитектуры. То есть они не видят всю связь, весь flow бизнеса и пользователя целиком. Не тот уровень абстракции.</p><p>Это, разумеется, влияет на глобальную архитектуру, на качество кода и самого продукта, на динамику разработки. Что, в свою очередь, приводит к многократному увеличению стоимости поддержки и развития. </p><p>Каждое требование — это определённая функция или функциональный раздел продукта. Если команда разработки не понимает взаимосвязи между функциями в создаваемой ими системе, то такие проекты гарантированно обречены на «историческое» развитие. Так рождаются огромные «монолиты», которые очень и очень быстро переходят в разряд с трудом поддерживаемых «<a href="https://en.wikipedia.org/wiki/Legacy_code" target="_blank" rel="noreferrer noopener">legacy</a>».</p><h3 class="wp-block-heading">Требования к продукту не приоритизированы с точки зрения ценности для пользователей</h3><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba583fc1&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba583fc1" class="wp-block-image aligncenter size-large wp-lightbox-container"><img loading="lazy" decoding="async" width="1200" height="400" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2021/07/usm-2.png" alt="" class="wp-image-3011" srcset="https://sherer.pro/content/uploads/2021/07/usm-2.png 1200w, https://sherer.pro/content/uploads/2021/07/usm-2-768x256.png 768w, https://sherer.pro/content/uploads/2021/07/usm-2-1048x349.png 1048w" sizes="auto, (max-width: 1200px) 100vw, 1200px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p>Порядок реализации задач формируется по наитию, по сложности разработки, по желанию клиента, по чему угодно — но только не по важности для пользователей. В итоге разработка и выпуск новых версий затягиваются.</p><p>Ядро функциональности, пресловутый MVP, собирается, исходя из представлений команды о продукте. Даже если команда думает, что полагается на результаты исследований — на сложных проектах эти результаты ещё необходимо как-то структурировать и визуализировать. Иначе высока вероятность «рассинхрона», отсутствия единого информационного поля внутри команды. </p><p>Последствия в этом случае весьма печальны, вплоть до полной невостребованности продукта аудиторией.</p><h3 class="wp-block-heading">Отсутствует единое понимание стратегии разработки, последовательности и состава релизов</h3><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba5842bf&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba5842bf" class="wp-block-image aligncenter size-large wp-lightbox-container"><img loading="lazy" decoding="async" width="1200" height="400" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2021/07/usm-3.png" alt="" class="wp-image-3012" srcset="https://sherer.pro/content/uploads/2021/07/usm-3.png 1200w, https://sherer.pro/content/uploads/2021/07/usm-3-768x256.png 768w, https://sherer.pro/content/uploads/2021/07/usm-3-1048x349.png 1048w" sizes="auto, (max-width: 1200px) 100vw, 1200px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p>Отсутствие стратегического подхода влечёт за собой не только архитектурные ошибки (опять), но и заставляет нервничать стейкхолдеров и владельцев продукта. Прогнозы в такой ситуации строить крайне сложно.</p><p>Как это решается в большинстве случаев? Продуктовая команда либо строит лишь краткосрочные планы, либо составляет план релизов буквально «наугад». Однако инвесторы не любят неопределенности. Если вы не можете предоставить им хотя бы примерный таймлайн или просто последовательность и функциональный состав релизов, то у меня для вас плохие новости. Ваш проект рискует остаться без финансирования.</p><p>Кто-то мне скажет, что это не всегда возможно. Часто исследования идут бок о бок с разработкой. Те же гибкие методологии, в конце концов. Однако даже здесь нужно опираться на определённый фундамент, базис. Ну и кроме того, гибкие методологии имеют весьма ограниченный ореол применения.</p><h3 class="wp-block-heading">Функциональные границы проекта очерчены слишком высокоуровнево или даже вовсе отсутствуют</h3><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba5845c3&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba5845c3" class="wp-block-image aligncenter size-large wp-lightbox-container"><img loading="lazy" decoding="async" width="1200" height="400" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2021/07/usm-4.png" alt="" class="wp-image-3013" srcset="https://sherer.pro/content/uploads/2021/07/usm-4.png 1200w, https://sherer.pro/content/uploads/2021/07/usm-4-768x256.png 768w, https://sherer.pro/content/uploads/2021/07/usm-4-1048x349.png 1048w" sizes="auto, (max-width: 1200px) 100vw, 1200px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p>Бизнес требует внедрения всё новых фич, разработка затягивается, бэклог растёт, команда выгорает. Продукт получается, мягко говоря, странным.</p><p>Случалось ли у вас, что клиент/начальник/инвестор начинал каждую неделю приносить новые функции в проект? И обычный вначале лендинг в итоге превращался в космолёт-монстр, с админкой, функцией телепортации и собственным мобильным приложением?</p><p>Фичи должны добавляться последовательно и обоснованно (см. предыдущие проблемы). Функция не может жить «сама по себе», в отрыве от остальных частей продукта. И вот конечный порядок и взаимосвязь функций системы, состав её компонентов — это и есть границы проекта.</p><h2 class="wp-block-heading">User Story Mapping</h2><p>Как я уже сказал, все эти проблемы (и не только) решают карты историй. Вот вам хорошее определение USM:</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Карта историй работает сразу в двух измерениях: показывает не только приоритет историй, но и то, как они связаны между собой и с более крупными задачами пользователей. Карта помогает команде понять, как можно скомпоновать истории, чтобы получить продукт, готовый к релизу.</p><cite><strong>Крис Симс</strong> (в переводе <em>Ольги Жолудовой</em> и <em>Рината Шайхутдинова</em>)</cite></blockquote><p>По факту, карта историй — это набор <em>упрощённых </em><strong>User Stories</strong>: собранные, отсортированные и приоритизированные. Сама методология простая, на высоком уровне с ней справится даже новичок. Но если копнуть глубже, то там окажется целое поле работы для исследователей, продактов и архитекторов.</p><p>В этой статье в качестве иллюстрации для составления USM мы будем использовать небольшую браузерную игру с программой лояльности какого-нибудь банка. В ней есть регистрация, игровой персонаж, его убежище, сражения и баллы лояльности.</p><p><em>Следующие ниже изображения-схемы могут быть не очень хорошо читаемы на небольших экранах мобильных устройств. В этом случае рекомендую посмотреть их на десктопе или перевернуть смартфон в &#171;ландшафт&#187;.</em></p><h3 class="wp-block-heading">Шаг 1. Выявляем активности</h3><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba5849b0&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba5849b0" class="wp-block-image size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="1201" height="211" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2021/07/user-story-mapping-1-activities.jpg" alt="User Story Mapping - активности пользователей" class="wp-image-3017" srcset="https://sherer.pro/content/uploads/2021/07/user-story-mapping-1-activities.jpg 1201w, https://sherer.pro/content/uploads/2021/07/user-story-mapping-1-activities-768x135.jpg 768w, https://sherer.pro/content/uploads/2021/07/user-story-mapping-1-activities-1048x184.jpg 1048w" sizes="auto, (max-width: 1201px) 100vw, 1201px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Активности пользователей</figcaption></figure><p>Сначала нужно собрать список основных <strong>активностей </strong>пользователей. В нашем примере игры их пять:</p><ol class="wp-block-list"><li>Регистрация и логин;</li><li>Работа над аватаром;</li><li>Работа над убежищем;</li><li>Участие в сражении;</li><li>Работа с баллами лояльности.</li></ol><p>Это — ключевые, главные «категории» действий пользователя в игре. Они включают в себя всю остальную деятельность. Если использовать терминологию <a href="https://sherer.pro/blog/funkcionalnaja-arhitektura-cifrovyh-produktov-chast-1/" target="_blank" rel="noreferrer noopener">функциональной архитектуры</a>, то здесь мы создаём <em>глобальные функциональные разделы</em>.</p><h3 class="wp-block-heading">Шаг 2. Разворачиваем активности в задачи</h3><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba584d2d&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba584d2d" class="wp-block-image size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2449" height="316" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2021/07/user-story-mapping-2-tasks.jpg" alt="User Story Mapping - задачи" class="wp-image-3018" srcset="https://sherer.pro/content/uploads/2021/07/user-story-mapping-2-tasks.jpg 2449w, https://sherer.pro/content/uploads/2021/07/user-story-mapping-2-tasks-768x99.jpg 768w, https://sherer.pro/content/uploads/2021/07/user-story-mapping-2-tasks-1048x135.jpg 1048w" sizes="auto, (max-width: 2449px) 100vw, 2449px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Разбивка активностей на задачи</figcaption></figure><p>Теперь мы раскладываем их (активности) на <strong>задачи</strong>. Например, <em>активность</em> «Регистрация и логин» превращается в три <em>задачи</em>:</p><ol class="wp-block-list"><li>Регистрация и логин через соцсети;</li><li>Регистрация и логин через e-mail;</li><li>Восстановление доступа.</li></ol><p>Заметьте, здесь нет отдельно «логина» или «регистрации». Это более глубокий уровень, задачи же — это такие «категории» пользовательских историй. В функциональной архитектуре это тоже <em>функциональные разделы</em>, но уже не глобальные, а обычные.</p><h3 class="wp-block-heading">Шаг 3. Задачи детализируем до конкретных историй</h3><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba585074&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba585074" class="wp-block-image size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2449" height="871" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2021/07/user-story-mapping-3-stories.jpg" alt="User Story Mapping - истории" class="wp-image-3020" srcset="https://sherer.pro/content/uploads/2021/07/user-story-mapping-3-stories.jpg 2449w, https://sherer.pro/content/uploads/2021/07/user-story-mapping-3-stories-768x273.jpg 768w, https://sherer.pro/content/uploads/2021/07/user-story-mapping-3-stories-1048x373.jpg 1048w" sizes="auto, (max-width: 2449px) 100vw, 2449px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Детализация задач историями</figcaption></figure><p>И, наконец, <strong>истории </strong>(жёлтые карточки) — они расположены в порядке приоритета &#8212; сверху критичные, внизу наименее важные. Приоритет обычно выстраивается, исходя из нескольких условий:</p><ul class="wp-block-list"><li>ценность для пользователей;</li><li>ценность для бизнеса;</li><li>сложность реализации.</li></ul><p>Именно в таком порядке: сначала пользователи, потом бизнес, потом технологии. Понятно, что зачастую бизнес-задачи оказываются важнее пользовательских, и в этом случае карточки немножко двигаются. Иногда реалии рынка действительно сильнее влияют на продукт, чем желания пользователей. Аккуратнее с этим, руководствуйтесь здравым смыслом.</p><p>В случае нашего примера, <em>задача </em>&#171;Регистрация и логин через e-mail&#187; разложилась на 2 <em>истории</em>:</p><ol class="wp-block-list"><li>Регистрация с помощью e-mail;</li><li>Логин через e-mail;</li></ol><p>Истории — это <em>функции</em> будущей системы. У них есть взаимосвязи и порядок. Например, мы не можем реализовать функцию <em>&#171;Выбор навыков аватара для улучшения&#187; по результатам сражения</em> до того, как, собственно, реализуем сам <em>&#171;Подбор параметров аватара&#187;</em> в момент создания персонажа.</p><p>В результате этапа мы понимаем, какая задача из каких историй состоит и к какой она относится активности. Мы понимаем, какие истории нужно сделать в первую очередь. Мы можем планировать спринты и релизы.</p><h3 class="wp-block-heading">Шаг 4. Делаем из приоритетов схему релизов</h3><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba585472&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba585472" class="wp-block-image size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2449" height="1081" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2021/07/user-story-mapping-4-releases.jpg" alt="User Story Mapping - релизы" class="wp-image-3021" srcset="https://sherer.pro/content/uploads/2021/07/user-story-mapping-4-releases.jpg 2449w, https://sherer.pro/content/uploads/2021/07/user-story-mapping-4-releases-768x339.jpg 768w, https://sherer.pro/content/uploads/2021/07/user-story-mapping-4-releases-1048x463.jpg 1048w" sizes="auto, (max-width: 2449px) 100vw, 2449px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Разделение задач на релизы</figcaption></figure><p>Напомню, что истории — это всего лишь функции будущей системы. Понимая это, мы просто переносим те истории, которые не критичны или требуют на этом этапе слишком много ресурсов, в следующий релиз. Точно так же можно выделить MVP.</p><p>Например, нам проще сделать логин и регистрацию через соцсети — и регистрацию через e-mail мы отодвигаем на второй релиз. Пользователям не так важна покупка амуниции — и она тоже вылетает из MVP.</p><h3 class="wp-block-heading">Дополнительно: цветовая индикация и структура</h3><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba5857f7&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba5857f7" class="wp-block-image size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2449" height="1081" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2021/07/user-story-mapping-5-structure.jpg" alt="User Story Mapping - структура" class="wp-image-3022" srcset="https://sherer.pro/content/uploads/2021/07/user-story-mapping-5-structure.jpg 2449w, https://sherer.pro/content/uploads/2021/07/user-story-mapping-5-structure-768x339.jpg 768w, https://sherer.pro/content/uploads/2021/07/user-story-mapping-5-structure-1048x463.jpg 1048w" sizes="auto, (max-width: 2449px) 100vw, 2449px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Структура User Story Mapping</figcaption></figure><p>Принято разделять USM на две структурных части:</p><ol class="wp-block-list"><li>Верхняя часть, с активностями и задачами, называется «backbone» (хребет), но я предпочитаю слово «скелет».</li><li>Нижняя часть, истории, называется «тело».</li></ol><p>И да, цветом стикеров можно помечать отдельные категории событий/действий, дополнительную важность (например, для бизнеса), типы пользователей и так далее. Всё, что посчитаете важным.</p><h2 class="wp-block-heading">Итог</h2><p>С помощью User Story Mapping можно не только планировать новые продукты, но и улучшать уже существующие &#8212; например, приоритизировать бэклог.</p><p>USM позволяет на очень простом визуальном языке донести до всех участников команды не только функциональный состав продукта, но и порядок проектирования и реализации. Если вы хотите выполнить глубокое функциональное проектирование будущего продукта, то User Story Mapping — отличное начало для этого.</p><p>Помните только, что слепое следование методологиями убивает профессионализм. Комбинируйте, не бойтесь отойти от канонов, если уверены в своих действиях.</p><p>Запись <a href="https://sherer.pro/blog/user-story-mapping-i-funkcionalnaya-arxitektura/">User Story Mapping и функциональная архитектура</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded></item><item><title>Информационная архитектура: пример и типизация</title><link>https://sherer.pro/blog/informacionnaya-arxitektura-primer-i-tipizaciya/</link><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Fri, 08 Jan 2021 11:47:09 +0000</pubDate><category><![CDATA[UX/UI]]></category><category><![CDATA[Аналитика]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[аналитика]]></category><category><![CDATA[гайд]]></category><category><![CDATA[информационная архитектура]]></category><guid isPermaLink="false">https://sherer.pro/?p=2863</guid><description><![CDATA[<p>На примере реального некоммерческого проекта разбираем проблему типизации данных в информационной архитектуре. </p><p>Запись <a href="https://sherer.pro/blog/informacionnaya-arxitektura-primer-i-tipizaciya/">Информационная архитектура: пример и типизация</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p><strong><em>Дисклеймер</em></strong><em>: если вы не знаете, что такое </em><strong><em>информационная архитектура</em></strong><em>, то крайне рекомендую сперва прочитать <a href="https://sherer.pro/blog/informacionnaya-arxitektura-kratkij-ekskurs/">вот этот</a> мой пост, а потом уже вернуться сюда. Иначе крайне высока вероятность того, что изложенный ниже текст не принесёт вам особенной пользы.</em></p><h2 class="wp-block-heading">О чём статья</h2><p>В первую очередь, речь пойдёт о проблеме информационной типизации в IT-проектах. В частности &#8212; о типизации конкретных свойств информационных сущностей. Однако рассказать об этом в отрыве от конкретики вряд ли получится, а если и получится, то выйдет долго и скучно. Поэтому в этой статье мы сперва разберём конкретный пример реального проекта, а уже затем сделаем кое-какие выводы.</p><h2 class="wp-block-heading">Типизация</h2><p><em>В языках программирования есть понятия &#171;сильной&#187; и &#171;слабой&#187;, &#171;статической&#187; и &#171;динамической&#187; типизаций. Если несколько упростить, то &#171;типизация&#187; диктует, как именно заполняются переменные в коде: можно ли одну и ту же переменную в разные периоды времени наполнить то текстом, то числом, то датой и тд.</em></p><p>Если с языками программирования всё более или менее ясно, то при работе с информационной архитектурой продукта типизацией мало кто заморачивается. Хотя именно она часто определяет часть возможностей к развитию продукта.</p><p>Информационные архитекторы, чаще всего, выполняют свою работу &#171;по наитию&#187; (разумеется, называя это &#171;логикой&#187; и &#171;опытом&#187;). Наверное, в этом нет ничего плохого или критичного &#8212; так делают все, и даже сложные продукты как-то создаются, живут и развиваются. Однако мы же хотим сделать мир лучше и совершеннее, не правда ли?</p><h2 class="wp-block-heading">Пример проекта</h2><p>У нас есть реальный проект, работа над которым ведётся прямо сейчас, пока пишется эта статья. Проект некоммерческий, никаких NDA. Плюс, он попутно выполняет некоторые образовательные цели &#8212; на нём обкатывает навыки информационного и функционального проектирования талантливая Евгения Шамрай.</p><h2 class="wp-block-heading">Информационная структура</h2><p>В проекте есть несколько информационных сущностей, у каждой есть некоторые свойства. Все сущности связаны между собой: какие-то напрямую, какие-то опосредованно.</p><p>Если попробовать изобразить иерархию сущностей графически, то получится что-то вроде этого:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba586a81&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba586a81" class="wp-block-image aligncenter size-large size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="1048" height="636" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2023/12/ia-example-sheme-1048x636.png" alt="" class="wp-image-3893" srcset="https://sherer.pro/content/uploads/2023/12/ia-example-sheme-1048x636.png 1048w, https://sherer.pro/content/uploads/2023/12/ia-example-sheme-768x466.png 768w" sizes="auto, (max-width: 1048px) 100vw, 1048px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p></p><ol class="wp-block-list"><li><strong>Инфоблок</strong> &#8212; самая низкоуровневая сущность, &#171;молекула&#187; информационной архитектуры, содержащая произвольную информацию (например, текст, цитату, изображение и тп). Из инфоблоков, собственно, и строится почти вся контентная часть продукта.</li><li><strong>Год</strong> &#8212; статическая среднеуровневая сущность, которая объединяет <em>инфоблоки </em>в разрезе определённых лет. Они единые для всех <em>композиторов</em>, но конкретные <em>годы </em>у конкретных <em>композиторов</em> могут не совпадать.</li><li><strong>Период</strong> &#8212; уникальная для каждого композитора среднеуровневая сущность, проходящая через все <em>слои</em> и объединяющая <em>годы</em> в определённый этап жизни <em>композитора</em>.</li><li><strong>Слой </strong>&#8212; статическая информационная сущность, объединяющая разные <em>периоды </em>в некий тематический срез творчества композитора. Слоёв ограниченное количество, они обязательны и одинаковы для всех <em>композиторов</em>.</li><li><strong>Композитор </strong>&#8212; высокоуровневая, главная сущность проекта.</li></ol><p>Если рассматривать эту модель как плоскую, то получается, что внутри одного <em>композитора </em>находится произвольное количество <em>инфоблоков</em>, которые объединяются в <em>годы</em>, которые объединяются в <em>периоды</em>, которые объединяются в <em>слои</em>.</p><p>У каждой сущности есть свои свойства. Мы не будем детально перечислять и описывать все такие свойства, так как это выходит за рамки темы статьи. Но мы помним, что у каждой сущности в проекте всегда есть как минимум одно свойство: внутренний <em>идентификатор</em> (уникальный для каждого <em>экземпляра </em>этой сущности).</p><h2 class="wp-block-heading">Навигационная модель</h2><p>Схема навигации в примере максимально простая:</p><ul class="wp-block-list"><li>Есть главная страница, на ней перечислены <em>композиторы</em>.</li><li>Внутри раздела каждого композитора есть список <em>слоёв</em>.</li><li>Каждый <em>слой </em>представлен отдельной страницей, на которой в иерархическом порядке расположены <em>периоды</em>, а в них &#8212; <em>годы</em>.</li></ul><p>Внутри каждого <em>года </em>может находится произвольное количество <em>инфоблоков</em> &#8212; я не стал их отображать на схеме, чтобы не усложнять восприятие:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba586ee5&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba586ee5" class="wp-block-image aligncenter size-large size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="1048" height="691" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2023/12/ia-example-navigation-1048x691.png" alt="" class="wp-image-3894" srcset="https://sherer.pro/content/uploads/2023/12/ia-example-navigation-1048x691.png 1048w, https://sherer.pro/content/uploads/2023/12/ia-example-navigation-768x506.png 768w" sizes="auto, (max-width: 1048px) 100vw, 1048px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Визуализированная навигационная модель</figcaption></figure><h2 class="wp-block-heading">Под капотом</h2><p>Важно понимать, как именно будет работать наша система &#8212; без этого зачастую невозможно выяснить все свойства и связи сущностей. Здесь мы уже одной ногой ступаем на зыбкую почву <a href="https://sherer.pro/blog/dizajn-dannyh-chast-3-menjaemsja/">дизайна данных</a>, но без этого никак. Мы должны построить схему обмена и формирования информации в нашем продукте.</p><figure class="wp-block-pullquote"><blockquote><p><strong>Информационная модель</strong> фиксирует сущности/свойства/связи (что есть), тогда как <strong>дата-модель</strong> — физическое хранение и индексы (как реализуем). В примере мы сознательно показываем оба слоя, чтобы не терять контекст.</p></blockquote></figure><p><strong>В нашем случае логика такова:</strong></p><ol class="wp-block-list"><li>пользователь загружает страницу конкретного <em>слоя</em> на сайте;</li><li>браузер делает запрос к серверу, в котором указывает идентификатор этого <em>слоя </em>и идентификатор <em>композитора;</em></li><li>сервер принимает эти параметры и делает соответствующий запрос в базу данных;</li><li>в результате у него появляется массив <em>инфоблоков</em>, которые ему теперь нужно отсортировать.</li></ol><p><strong>Как же происходит сортировка?</strong> Здесь тоже всё просто:</p><ol class="wp-block-list"><li>все <em>инфоблоки </em>разделяются на <em>периоды</em>;</li><li><em>периоды </em>сортируются по порядку;</li><li>внутри <em>периодов </em>происходит объединение <em>инфоблоков</em> по <em>годам</em>;</li><li><em>годы </em>также сортируются по порядку внутри <em>периодов</em>;</li><li>внутри каждого <em>года</em> по порядку сортируются сами <em>инфоблоки</em>.</li></ol><p>В результате в браузер пользователя прилетает <strong>многомерный массив</strong>, который потом просто разбирается на странице.</p><h2 class="wp-block-heading">Связи сущностей</h2><p>Как я уже говорил, все сущности связаны. Но связь эта не всегда прямолинейна.</p><p>Чтобы связать информационные элементы, к одной сущности нужно прикрепить ссылку на другую. В нашем случае &#8212; к &#171;дочерней&#187; нужно прикрепить ссылку на &#171;родительскую&#187;. Делать это правильнее (и проще) всего как раз с помощью идентификаторов.</p><ul class="wp-block-list"><li><strong>Композитор </strong>&#8212; главная и независимая сущность.</li><li><strong>Слои </strong>единые для всех <em>композиторов</em> и вообще &#8212; для всего проекта, они ни от чего не зависят.</li><li><strong>Период </strong>у нас уникален для каждого <em>композитора</em>, а значит, ссылается на него (имеет в своих свойствах идентификатор того <em>композитора</em>, которому принадлежит).</li><li><strong>Годы </strong>тоже едины для всего проекта, независимы от остальных сущностей.</li><li>И только <strong>инфоблоки</strong>, как низшая сущность, зависят от всех остальных информационных элементов системы. У них в свойствах прописаны идентификаторы всех остальных сущностей.</li></ul><p>Вот так выглядит схема зависимостей в нашем примере:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba5873e3&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba5873e3" class="wp-block-image aligncenter size-large size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="1048" height="181" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2023/12/ia-example-relations-1048x181.png" alt="" class="wp-image-3895" srcset="https://sherer.pro/content/uploads/2023/12/ia-example-relations-1048x181.png 1048w, https://sherer.pro/content/uploads/2023/12/ia-example-relations-768x133.png 768w" sizes="auto, (max-width: 1048px) 100vw, 1048px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Связь информационных сущностей</figcaption></figure><p>Больше всего свойств со связями в нашем случае будет именно у <em>инфоблоков</em>. Очевидно, что каждый раз, когда нам понадобится связать <em>инфоблок </em>с <em>композитором</em>, <em>слоем</em>, <em>периодом </em>или <em>годом</em>, мы просто прописываем ему соответствующий <strong>идентификатор </strong>в соответствующее поле.</p><h2 class="wp-block-heading">Проблема</h2><p>Мы понимаем, что самая &#171;насыщенная&#187; связями сущность &#8212; это <em>инфоблок</em>. Мы также понимаем, что продукт будет развиваться. В нём появятся дополнительные сущности, вроде <em>треков</em>, <em>плейлистов </em>или <em>событий</em>. И каждый <em>инфоблок </em>потенциально может оказаться связанным с этими новыми сущностями.</p><p>Какая здесь появляется проблема? Мы должны спроектировать <strong>хранение</strong> связей в <em>инфоблоке </em>таким образом, чтобы добавление новых сущностей и связывание их с <em>инфоблоками</em> (как минимум с ними) не вызывало особенных проблем.</p><p>Как такое проектирование происходит обычно? А никак. Когда добавится новый тип сущности, к <em>инфоблоку </em>в базе данных просто будет добавлено новое поле. У каких-то инфоблоков оно будет заполнено, у каких-то &#8212; нет. Где-то в интерфейсе будет обрабатываться его отсутствие, где-то &#8212; не будет. Где-то на странице вывалится ошибка, где-то пользователь обматерит очередное обновление, где-то тестировщик обольётся кровавыми слезами.</p><p>А что, если это связь нелинейная? Не &#171;один ко одному&#187;, а &#171;один ко многим&#187;? Если конкретный <em>инфоблок</em> может содержать в себе связь с несколькими <em>треками</em>? Сможем мы в одном свойстве <em>инфоблока </em>сохранить несколько идентификаторов <em>треков</em>? А если можем, то почему вообще все связи не хранить в одном свойстве?</p><h2 class="wp-block-heading">Решение</h2><p>А решения нет. По крайней мере, однозначного.</p><p>Да, мы можем в одном свойстве хранить сразу несколько (сколько угодно) связей. Но упростит ли нам это задачу? Не будет ли слишком &#171;дорогим&#187; с точки зрения программных ресурсов разбор такого &#171;комплексного&#187; свойства? А если наших инфоблоков несколько миллионов? Справится ли сервер с необходимостью получить их все, выяснить, какие из них относятся к конкретному композитору и конкретному слою?</p><p>Боюсь, я вас запутал. Давайте немножко упрощу.</p><p>У нас, казалось бы, два варианта:</p><ol class="wp-block-list"><li>Хранить каждую связь в конкретном свойстве инфоблока. Это в IA &#8212; признак <strong>&#171;строгой&#187;</strong> или, по другому, <strong>&#171;сильной&#187;</strong> типизации.</li><li>Хранить все связи в одном свойстве, массивом. Обычно это отличает <strong>&#171;слабую&#187;</strong> типизацию.</li></ol><p>&#171;Слабая&#187; типизация подразумевает больше свободы, &#171;строгая&#187; &#8212; больше стабильности. Но при этом каждая из них, возведённая в абсолют, может уничтожить все плоды ваших усилий.</p><p>Слишком слабая типизация приведёт ваш продукт к тому, что простая операция по извлечению и сортировке нужных инфоблоков будет занимать непозволительно много времени. Сайт будет грузиться медленнее, конверсия будет снижаться, бизнес (или кто там у вас вместо него) окажется недоволен.</p><p>Излишне сильная типизация в разы увеличит стоимость поддержки и развития продукта. Разработчики будут ещё сильнее, чем обычно, материть проектировщика/архитектора. Время внедрения и отладки даже маленькой новой фичи станет сопоставимо с операцией Барбаросса в 1941-ом (и, вероятно, закончится так же, &#8212; провалом).</p><h2 class="wp-block-heading">Настоящее решение</h2><p>Грамотный и осознанный баланс &#8212; вот залог действительно качественного продукта. Это в полной мере касается и информационной архитектуры.</p><p>В нашем случае я выберу комбинированный подход:</p><p>Для связей, которые могут понадобиться при &#171;выборке&#187; <em>инфоблоков</em> из базы данных, я выберу отдельные свойства. В нашем случае это будут уже упомянутые <em>композитор</em>, <em>слой</em>, <em>период </em>и <em>год</em>. Остальные, существующие или потенциально возможные, я запихну в отдельное свойство массивом.</p><figure class="wp-block-pullquote"><blockquote><p>Правило простое: частые и ключевые связи мы прописываем как явные поля, а редкие и вариативные — в агрегате или отдельной связующей таблице. Так мы держим и производительность, и гибкость.</p></blockquote></figure><p>В следующей статье разберём подробно, что же такое информационная сущность и из чего она состоит.</p><p>Запись <a href="https://sherer.pro/blog/informacionnaya-arxitektura-primer-i-tipizaciya/">Информационная архитектура: пример и типизация</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded></item><item><title>Информационная архитектура: краткий экскурс</title><link>https://sherer.pro/blog/informacionnaya-arxitektura-kratkij-ekskurs/</link><comments>https://sherer.pro/blog/informacionnaya-arxitektura-kratkij-ekskurs/#comments</comments><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Fri, 08 Jan 2021 11:44:32 +0000</pubDate><category><![CDATA[UX/UI]]></category><category><![CDATA[Аналитика]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[аналитика]]></category><category><![CDATA[гайд]]></category><category><![CDATA[информационная архитектура]]></category><guid isPermaLink="false">https://sherer.pro/?p=2850</guid><description><![CDATA[<p>Короткая статья про основы информационной архитектуры: трамплин для погружения в область.</p><p>Запись <a href="https://sherer.pro/blog/informacionnaya-arxitektura-kratkij-ekskurs/">Информационная архитектура: краткий экскурс</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p><em>Это короткая статья не претендует на полное раскрытие термина, ибо он настолько глубок, что даже для базового его изложения потребуется не одна статья. Здесь я опишу только самые фундаментальные принципы, остальное будет в других частях цикла.</em></p><h2 class="wp-block-heading">Что такое IA</h2><p>Очень ёмко об информационной архитектуре высказался Алексей Бородкин, основатель Гильдии Вольных Проектировщиков:</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Это описание связи всего со всем!</p></blockquote><p>И во многом он прав. Во время этапа проработки IA формируется информационная структура продукта, выявляются взаимосвязи между всеми его частями, определяется их важность и содержимое.</p><p>Грамотная информационная архитектура упрощает поддержку и развитие продукта, улучшает UX:</p><ul class="wp-block-list"><li>программисты не матерят своих предшественников (или себя) за неудобные для масштабирования роутинг и базы данных;</li><li>контент-менеджеры и администраторы больше не льют кровавые слёзы при работе с внутренней частью продукта;</li><li>пользователи легко и непринуждённо находят то, что им нужно и попадают именно туда, куда хотели;</li><li>сеошники и поисковые системы влюбляются в ваш сайт и не хотят оттуда никуда уходить.</li></ul><p>Притом, как это часто случается в IT, каждый специалист вкладывает немного собственного смысла в этот термин, поэтому любая формулировка рискует оказаться недостаточно точной. И всё же я постарался сформулировать максимально общее определение информационной архитектуре:</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Это совокупность данных об информационной структуре цифрового продукта, способствующая его правильной работе, выполнению задач и интуитивному доступу к содержимому.</p></blockquote><p>Стало не сильно понятней, да? Вот так, сходу, всё это может показаться немного запутанным или сложным. Поэтому давайте на каком-нибудь очень простом и понятном примере пройдёмся по базовым этапам создания IA. Пусть это будет абстрактный интернет-магазин одежды.</p><h2 class="wp-block-heading">Этапы создания IA</h2><p>Важно понимать, что каждый опытный архитектор выполняет эту работу немного по-своему. В формате этой &#171;вводной&#187; статьи я смогу рассказать только о ключевых моментах, основных вехах.</p><h3 class="wp-block-heading">Подготовка</h3><p>Работа над информационной архитектурой начинается сильно позже старта проектирования. Сперва определяется концепция, суть продукта. Нам нужен базис, от которого мы уже начнём выстраивать IA.</p><p>Мы должны как минимум очертить высокоуровневые границы проекта, сформировать базовое понимание его функциональности. И только на этом этапе приступать к информационному проектированию.</p><p>В нашем случае базис относительно простой: есть интернет-магазин, есть товары, категории и пользователи. Углубляться не станем, а то всё-таки скатимся к лонгриду.</p><h3 class="wp-block-heading">Декомпозиция</h3><p>На этом шаге мы разбираем проект на отдельные <em>информационные сущности</em>. Каждая такая сущность обладает определёнными <em>свойствами</em>. Некоторые сущности могут быть <em>вложенными </em>(каталог и товар, например), некоторые &#8212; <em>независимыми</em>.</p><p>Итак, пусть в нашем примере будет только 5 сущностей:</p><ol class="wp-block-list"><li><strong>Страница </strong>(статические сущности, содержащие какую-то информацию; например, страницы &#171;О компании&#187;, &#171;Доставка и оплата&#187;).</li><li><strong>Товар </strong>(да, обычный товар с описанием, фоточками, ценой и тп).</li><li><strong>Каталог </strong>(внезапно, но каталог &#8212; это тоже сущность; у него есть свои свойства, вроде параметров поиска или уровня вложенности).</li><li><strong>Корзина </strong>(которая обладает <em>динамическими</em> свойствами: вложенные товары и их количество, скидки, даже связь с конкретным пользователем).</li><li><strong>Пользователь </strong>(тут всё понятно: как минимум, у пользователя есть регистрационные данные, адрес доставки и платёжные реквизиты).</li></ol><p>Конечно, даже в самом простом e-commerce этих сущностей больше, а их свойства разнообразнее. Однако мы помним, что это пример, да? Для простоты мы в дальнейшем даже не будем детально разбирать почти ничего, кроме самих &#171;товаров&#187;.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Важная оговорка: в контент-проектах «Страница» — полноценная <strong>контент-сущность</strong>, но в UX-лексике «страница/экран» — это <strong>UI-представление</strong>, и она не равна сущности домена. Подробнее об этом будет в третьей статье цикла.</p></blockquote><p><em>На этом и последующих этапах присутствуют некоторые пересечения с <a href="https://sherer.pro/blog/dizajn-dannyh-chast-1-chto-i-zachem/" target="_blank" rel="noreferrer noopener">дизайном данных</a>, это не страшно и не противоречит концепции информационной архитектуры. Если проектировщик/архитектор хороший, он совмещает оба направления, экономя ресурсы компании</em>.</p><h3 class="wp-block-heading">Классификация</h3><p>Теперь надо классифицировать получившиеся сущности, но не только их. Для грамотного составления архитектуры, нам потребуется классифицировать ещё и возможные операции с этими сущностями.</p><p><strong>A. Классификация пользовательских потребностей</strong> (задач) в разрезе информационной архитектуры опирается, как правило, на результаты пользовательских же исследований. Мы должны понимать, что <em>действительно</em> нужно нашим потенциальным покупателям. Исходя из этой информации, мы выясним, как именно следует связать наши сущности как они будут друг к другу относиться.</p><p>Для нашего примера классификация задач пользователя будет очень простой:</p><ol class="wp-block-list"><li><strong>Найти товары</strong> (с помощью поиска, фильтрации и сортировки).</li><li><strong>Сравнить товары</strong> (выбрать наиболее подходящий вариант).</li><li><strong>Почитать про товары</strong> (ознакомиться с характеристиками).</li><li><strong>Купить товары</strong> (положить в корзину, оплатить и ждать доставку).</li></ol><p>Как видите, все действия напрямую связаны с товарами, и опосредованно &#8212; с остальными сущностями (например, <em>поиск товара</em> осуществляется в <em>каталоге</em>, а покупка &#8212; в <em>корзине</em>).</p><p>На этом шаге мы также определяем все возможные варианты и способы манипуляции с нашими сущностями: определяем, как будет осуществляться поиск, по каким параметрам мы будем сортировать товары и так далее.</p><p><strong>B. Классификация информационных сущностей</strong> &#8212; ещё один обязательный этап. Вся информация, которую видит пользователь, должна быть структурирована. Страницы должны объединяться в разделы, товары &#8212; в категории. И те, и другие должны быть доступны для поиска, а последние &#8212; ещё и для сортировки. У товаров могут быть общие свойства, вроде скрытых от глаз пользователя &#171;тегов/меток&#187; или доступных для просмотра &#171;размеров&#187;.</p><p>На этапе классификации сущностей мы решаем, по какому принципу они будут объединяться и как пользователю будет удобнее с ними обращаться. Попутно не забываем и про администраторов, которым тоже нужно упростить работу.</p><p>Но для начала немного терминологии:</p><ul class="wp-block-list"><li><strong>таксономия </strong>— это управляемая схема классификации;</li><li><strong>термины</strong> — атомы таксономии.</li></ul><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Например, таксономия &#171;Размер&#187; может содержать несколько терминов: &#171;XXL&#187;, &#171;XL&#187;, &#171;L&#187;, &#171;M&#187;, &#171;S&#187;, &#171;XS&#187;.</p></blockquote><p>В реальных продуктах часть терминов обрастает свойствами и становится «почти сущностями» — это нормально, фиксируем это явно.</p><p>В нашем примере добавляем три <em>таксономии</em> и одно общее <em>свойство</em>:</p><ol class="wp-block-list"><li><strong>Категория </strong>(иерархическая таксономия сущности &#171;товар&#187;).</li><li><strong>Метка </strong>(не-иерархическая таксономия сущности &#171;товар&#187;).</li><li><strong>Размер</strong> (не-иерархическая таксономия сущности &#171;товар&#187;).</li><li><strong>Цвет </strong>(общее свойство для всех экземпляров сущности &#171;товар&#187;).</li></ol><p>Иерархические таксономии могут быть вложенными: например, категория может иметь подкатегорию (зимняя одежда -&gt; пуховики). А вот у метки, например, родительского термина быть не может.</p><p><em>Некоторые архитекторы считают таксономии за отдельные сущности, однако мне такой подход не нравится, я предпочитаю отделять одно от другого. Вот &#171;термин&#187; таксономии вполне можно иногда посчитать за сущность, ибо порой термины обрастают таким количеством свойств, что сами по себе начинают претендовать на роль серьёзной информационной составляющей.</em></p><h3 class="wp-block-heading">Выявление связей</h3><p><em>На самом деле, этот этап (и следующий тоже) часто параллелятся с предыдущим, но излагать и воспринимать их удобнее именно так. Просто имейте в виду, что это не всегда прям последовательные шаги.</em></p><p>Итак, мы разобрались, что у нас за сущности и таксономии. Теперь нужно понять, как они будут между собой связаны. Связи сущностей могут быть совершенно разными. Если копнуть глубоко, то неподготовленный читатель слегка ошалеет от всех этих <em>&#171;от одного ко многим&#187;</em>, <em>&#171;от многих ко многим&#187;</em> и тп. Мы рассмотрим только простые варианты, когда связи являются либо <em>&#171;плоскими&#187;, либо &#171;иерархическими&#187;</em>.</p><p><strong>Плоские связи </strong>в нашем случае &#8212; это связь терминов таксономии &#171;метки&#187; между собой. У них нет родителей, они &#171;равны&#187;. Или связь товаров с одинаковыми &#171;метками&#187; &#8212; она тоже плоская. Кстати, связь самого товара с меткой &#8212; тоже плоская.</p><p><strong>Иерархическая связь</strong>, например, у терминов таксономии &#171;категории&#187; &#8212; они почти всегда вложенные. Также иерархическая связь будет между сущностями &#171;каталог&#187; и &#171;товар&#187;, так как первый всегда включает в себя несколько товаров. Если пойти дальше, то в игру вступают термины таксономии и у нас получается целая цепочка связей: <em>каталог </em>-&gt; <em>категория </em>-&gt; <em>товар</em>.</p><p>Иерархия сущностей &#8212; вообще отдельная песня. У хорошего архитектора почти все сущности в проекте делится на высоко-, средне- и низкоуровневые.</p><h3 class="wp-block-heading">Фиксация свойств</h3><p>Во время всей работы над информационной архитектурой мы всё время попутно выясняли, какие именно свойства будут у наших сущностей. Пришло время их зафиксировать.</p><p>Мы знаем, что у <strong>товаров </strong>есть как минимум 10 свойств:</p><ol class="wp-block-list"><li><strong>Идентификатор </strong>(внутренний, в базе данных, он есть у каждой сущности и термина таксономии).</li><li><strong>Артикул</strong> (внешний, для обмена данными, например, с системой складского учёта).</li><li><strong>Название</strong>.</li><li><strong>Описание</strong>.</li><li><strong>Основное изображение</strong> (используется в карточке товара в каталоге).</li><li><strong>Дополнительные изображения</strong> (используются в галерее изображений на странице товара).</li><li><strong>Цвет </strong>(общее свойство для всех товаров: оно не &#171;сквозное&#187;, как метки и категории, а может быть уникальным для каждого товара &#8212; например, «синий с белым узором»).</li><li><strong>Размер </strong>(прикреплённый термин таксономии).</li><li><strong>Категория</strong> (прикреплённый термин таксономии).</li><li><strong>Метки </strong>(несколько терминов таксономии, на основе которых будут показываться &#171;похожие&#187; товары).</li></ol><p>При этом мы знаем, что свойства 8 и 9 являются &#171;ссылками&#187; на конкретный термин таксономии, а десятое свойство &#8212; даже на несколько таких терминов.</p><p>Таким образом, мы составили информационную модельку нашего товара. Мы молодцы.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>На самом деле, конечно, не всё так просто. И в третьей статье цикла мы немного углубимся в тему свойств сущностей. Например, добавим понятие «контролируемый словарь», «<a href="https://ru.wikipedia.org/wiki/%D0%A4%D0%B0%D1%81%D0%B5%D1%82%D0%BD%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D1%8F" target="_blank" rel="noreferrer noopener">фасет</a>» и другие.</p></blockquote><h3 class="wp-block-heading">Схематизация</h3><p>Составление предметных и навигационных схем продукта. Самый последний и самый сложный этап. Причём его сложность чаще не в каких-то особенных нотациях или технических трудностях. Его главная сложность &#8212; в психологическом факторе. Я видел, как талантливые информационные архитекторы сводили на нет результаты всей своей работы из-за небрежного финального оформления.</p><p>Причина тут простая: в голове у архитектора картинка уже сложилась. Переносить её на бумагу (пусть и цифровую) кажется второстепенной задачей. Гештальт закрыт, мозг получил свою дозу дофамина.</p><p>Вот только без грамотного отчуждения практически любые знания бесполезны. Всё, что получилось выяснить, сопоставить и придумать во время работы над информационной архитектурой, должно быть зафиксировано в документации. В случае с IA эта документация состоит, по большей части из разного рода схем. Здесь и перечень/описание сущностей и их свойств, здесь взаимосвязи, задачи, операции и так далее. Самые крутые даже описывают предполагаемую программную реализацию, миксуя информационную архитектуру с дизайном данных.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Важно: информационная архитектура описывает «что и как связано» (сущности, свойства, таксономии), а навигация — «как по этому двигаться» (меню, крошки, фасеты, поиск).</p></blockquote><p>Об артефактах информационного проектирования можно написать не одну статью. И, возможно, я это ещё сделаю.</p><h2 class="wp-block-heading">Напоследок</h2><p>О сущностях, типах свойств и связей можно рассказывать очень долго. Как и об информационных моделях, например. Но об этом в следующих статьях.</p><p>Запись <a href="https://sherer.pro/blog/informacionnaya-arxitektura-kratkij-ekskurs/">Информационная архитектура: краткий экскурс</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded><wfw:commentRss>https://sherer.pro/blog/informacionnaya-arxitektura-kratkij-ekskurs/feed/</wfw:commentRss><slash:comments>1</slash:comments></item><item><title>Функциональная архитектура цифровых продуктов, часть 2</title><link>https://sherer.pro/blog/funkcionalnaja-arhitektura-cifrovyh-produktov-chast-2/</link><comments>https://sherer.pro/blog/funkcionalnaja-arhitektura-cifrovyh-produktov-chast-2/#comments</comments><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Fri, 23 Oct 2020 07:59:19 +0000</pubDate><category><![CDATA[Документация]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[гайд]]></category><category><![CDATA[функциональное проектирование]]></category><guid isPermaLink="false">https://sherer.pro/?p=2525</guid><description><![CDATA[<p>Cценарии, уровень абстракции, функциональная иерархия, итерационность и взаимосвязи функций.</p><p>Запись <a href="https://sherer.pro/blog/funkcionalnaja-arhitektura-cifrovyh-produktov-chast-2/">Функциональная архитектура цифровых продуктов, часть 2</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p>В предыдущей статье я уже <a href="https://sherer.pro/blog/funkcionalnaja-arhitektura-cifrovyh-produktov-chast-1/">рассказывал</a>, какие задачи и проблемы решает функциональная архитектура, давал её базовое определение. Теперь же предлагаю поговорить о более конкретных вещах. О том, как эта самая архитектура создаётся и какие подводные камни ожидают её создателей.</p><h2 class="wp-block-heading">Вместо вступления</h2><p>У этого поста (как и у всего цикла) нет задачи <strong>научить </strong>читателей функциональному проектированию. Равно как и дать им в руки универсальные шаблоны проектной документации. Это невозможно сделать и десятком таких статей, но вовсе не из-за сложности предметной области. Просто все проекты разные, а продуктовые подходы могут отличаться даже в рамках одной кампании. Шаблонизировать создание функциональной архитектуры — занятие неблагодарное и неблагородное.</p><p>На самом деле, цель этого цикла проста: показать возможности ФА и привести несколько примеров её формирования. Я не покажу ни одного &#171;универсального&#187; решения. Многие схемы и таблицы будут так или иначе взяты из реальной документации, со всеми присущими ей проектными ограничениями.</p><p>Тем не менее, мы довольно подробно пройдёмся по составляющим ФА и этапам её создания. Надеюсь, это сделает цифровой мир лучше, а хотя бы несколько продуктов надёжнее, качественнее и дешевле в разработке.</p><h2 class="wp-block-heading">Этапы</h2><p>Лично я предпочитаю разбивать работу над функциональной архитектурой на два ключевых этапа: <em>высокоуровневый</em> и <em>детальный</em>. Первый закладывает &#171;скелет&#187; продукта, тогда как во время второго этот &#171;скелет&#187; обрастает &#171;мясом&#187;. Детальное функциональное проектирование, чаще всего, является итерационной частью проектного процесса.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba589532&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba589532" class="wp-block-image aligncenter wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="940" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2023/12/functional-arch-steps.png" alt="" class="wp-image-3885" srcset="https://sherer.pro/content/uploads/2023/12/functional-arch-steps.png 2096w, https://sherer.pro/content/uploads/2023/12/functional-arch-steps-1048x470.png 1048w, https://sherer.pro/content/uploads/2023/12/functional-arch-steps-768x344.png 768w" sizes="auto, (max-width: 2096px) 100vw, 2096px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p>Конечно, это разделение порой весьма условно. Где-то приходится возвращаться к переосмыслению общих решений, а где-то нельзя продолжить без более глубокого погружения в область. И всё же, разбивка на этапы позволяет очень сильно сократить время на проработку архитектуры, делая процесс более структурированным.</p><p>В этой статье мы будем говорить преимущественно о базовых принципах, лишь изредка скатываясь в бездну детального проектирования.</p><h2 class="wp-block-heading">Теория</h2><p>Высокоуровневое функциональное проектирование — это первое, с чего стоит начать работу над FA. Кажется, что набросать общую структуру проекта проще, чем детально расписывать каждую функцию. Однако это не так. И сейчас я расскажу, почему.</p><h3 class="wp-block-heading">Уровень абстракции</h3><p>Помните, я говорил о том, что чаще всего программисты не охватывают проект целиком, а фокусируются на конкретном разделе? Хороший разработчик выстраивает невероятно сложный хрустальный замок вокруг той узкой задачи, над которой работает прямо сейчас. У него банально не хватает ресурсов, чтобы загрузить в голову <strong>всю </strong>функциональность большого продукта. И уж тем более, правильно её проанализировать.</p><p>То же самое справедливо и для многих продуктовых аналитиков/дизайнеров/проектировщиков. Они с самого начала начинают копать сильно глубоко, детально прорабатывают каждую ветку сценария. Но, в отличии от ситуации с разработчиками, на пользу проекту это не идёт. Из-за высокой степени неопределённости на старте, функциональная архитектура рискует оказаться проработанной неравномерно. Решения, принимаемые без оглядки на общую структуру, часто скрывают в себе ошибки. В лучшем случае вам придётся возвращаться к уже проработанным разделам, и полностью их перепроектировать. В худшем — проект с ошибками будет отправлен в разработку.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Когда <strong>архитектор </strong>начинает погружаться в детали, не составив общей картины продукта, он превращается в <strong>инженера</strong>. В мире цифровой разработки эти люди выполняют совершенно разные задачи. Да, вы можете быть сперва архитектором, а потом — инженером. Но не наоборот.</p></blockquote><p>В самом начале работы над FA крайне важно поддерживать необходимый уровень абстракции. Порой это бывает сложно, хочется сразу закрыть все &#171;белые пятна&#187;. Возникает чувство, что ты оставляешь в тылу опасного врага.</p><p><em>Нам обязательно нужно выяснить, как именно будет реализована сквозная аналитика в мобильном приложении. Мы с самого начала пытаемся представить внешний вид видеоплеера на сайте.</em></p><p>При высокоуровневом проектировании нам в обоих случаях достаточно лишь понимать, что такая возможность просто имеется: <em>да, мы можем отслеживать каналы привлечения и конверсию; да, плеер на сайте будет.</em></p><h3 class="wp-block-heading">Пластичная функциональная архитектура</h3><p>Функциональная архитектура должна быть гибкой. Если ваш проект сложнее лендинга, то гарантирую, что с первого раза вы не опишете <strong>всю</strong> его функциональность. Работа над FA — это всегда довольно кропотливое занятие. Вам часто придётся возвращаться к уже описанным функциям и дополнять их.</p><p>Дублирование данных, слабая структуризация, отсутствие единой семантики описания — всё это может вызвать (и обязательно вызовет) проблемы при детальном проектировании. Одной из задач высокоуровневой проработки архитектуры как раз и является предотвращение таких моментов.</p><h3 class="wp-block-heading">Начало работ</h3><p>Вообще, начинать работать над FA стоит лишь после того, как сформированы все ключевые сценарии продукта. Однако мы живём в реальном мире, и никто вам не даст дополнительный месяц или два на проектирование. Поэтому лично я начинаю высокоуровневое функциональное проектирование уже после того, как определены основные механики продукта. Да, это вносит дополнительные риски: хотя бы за счёт того, что значительная часть сценариев ещё не определена, и придётся многое переделывать. Да, есть риск снова стать <em>инженером</em>, а не <em>архитектором</em>.</p><p>Однако ранний старт позволяет не только серьёзно сократить сроки проектирования, но и более глубоко &#171;прочувствовать&#187; саму архитектуру.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba5899de&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba5899de" class="wp-block-image aligncenter wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="784" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2023/12/functional-arch-vectors.png" alt="" class="wp-image-3886" srcset="https://sherer.pro/content/uploads/2023/12/functional-arch-vectors.png 2096w, https://sherer.pro/content/uploads/2023/12/functional-arch-vectors-1048x392.png 1048w, https://sherer.pro/content/uploads/2023/12/functional-arch-vectors-768x287.png 768w" sizes="auto, (max-width: 2096px) 100vw, 2096px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button></figure><p>Параллельная проработка пользовательских сценариев, бизнес-процессов и технологической составляющей позволяет выявлять даже самые пограничные ситуации. Например, спроектировать <a href="https://sherer.pro/blog/registracija-i-login-na-steroidah/" target="_blank" rel="noreferrer noopener">правильную регистрацию</a>.</p><h2 class="wp-block-heading">Практика</h2><p>Окей, по теории прошлись. Теперь давайте обратимся к более практичным вещам. К тому, как формируется функциональная архитектура.</p><h3 class="wp-block-heading">Функциональная иерархия</h3><p>Как и почти в любой архитектуре, здесь тоже есть свои &#171;родители&#187; и &#171;потомки&#187;. Простейшие <em>функции </em>складываются в более крупные, которые, в свою очередь, входят в <em>функциональные разделы</em>. Разделы тоже могут быть <em>вложенными</em>.</p><p>На ранних этапах проектирования <em>функциональная</em> модель часто схожа с <em>навигационной</em>. Например, список функциональных разделов классического контентного приложения может выглядеть так:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba589d7a&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba589d7a" class="wp-block-image aligncenter wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="1298" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2023/12/functional-arch-hierarchy.png" alt="" class="wp-image-3887" srcset="https://sherer.pro/content/uploads/2023/12/functional-arch-hierarchy.png 2096w, https://sherer.pro/content/uploads/2023/12/functional-arch-hierarchy-1048x649.png 1048w, https://sherer.pro/content/uploads/2023/12/functional-arch-hierarchy-768x476.png 768w" sizes="auto, (max-width: 2096px) 100vw, 2096px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Высокоуровневая функциональная модель</figcaption></figure><p>Да, в навигационной модели тоже могут быть разделы &#171;регистрация&#187;, &#171;настройки&#187;, &#171;профиль&#187;, &#171;новости&#187;, но и только.</p><p>Во-первых, в навигации нет такого понятия, как <strong>общие функции</strong> (о них мы поговорим ниже) или, например, <strong>авторизация </strong>(не путать с <a href="https://habr.com/ru/company/avanpost/blog/480576/" target="_blank" rel="noreferrer noopener nofollow">аутентификацией</a>). Во-вторых, глобальные функциональные разделы первого уровня редко несут в себе конкретные интерфейсы, являясь лишь &#171;контейнером&#187; для других разделов. В-третьих, навигационные разделы не так сильно переплетены друг с другом, как функциональные (и об этом тоже будет чуть позже).</p><p>В примере выше функциональный раздел <strong>&#171;Логин и регистрация&#187;</strong> включает в себя дочерние разделы:</p><ol class="wp-block-list"><li>Регистрация.</li><li>Аутентификация (логин).</li><li>Восстановление доступа.</li><li>Авторизация (проверка прав).</li></ol><p>В свою очередь, внутри подраздела <strong>&#171;Аутентификация&#187;</strong> на клиенте могут находиться уже конкретные функции:</p><ol class="wp-block-list"><li>Отображение окна логина.</li><li>Заполнение формы.</li><li>Валидация формы.</li><li>Отправка формы на сервер.</li><li>Обработка ответа сервера.</li><li>Показ сообщений (например, об ошибках).</li></ol><p>При этом та же функция <strong>&#171;валидации формы&#187;</strong> чаще всего включает дочерние функции, вроде <strong>&#171;проверки корректности e-mail&#187;</strong>, <strong>&#171;проверки сложности пароля&#187;</strong> и <strong>&#171;проверки на обязательное поле&#187;</strong>.</p><p>Даже в простой форме логина может быть несметное количество функций (особенно если добавить вход через соцсети и двухфакторную аутентификацию). Однако на этапе высокоуровневого проектирования мы, чаще всего, описываем только <em>функциональные разделы</em> и <em>ключевые </em>функции будущего продукта. Иначе есть риск закопаться и своими руками выстроить себе заборы, которые потом придётся героически преодолевать.</p><h3 class="wp-block-heading">Действия пользовательские и системные</h3><p>Напомню, что <em>функцией </em>является <em>любое</em> событие — не важно, инициировано оно пользователем или самой системой. Функций всегда лютая тьма, их сходу даже в простой список не оформишь.</p><p>Проще всего выявлять конкретный перечень функций продукта через его функциональные сценарии. Они часто строятся на основе детального CJM, user flow или аналогов, но включают в себя отнюдь не только пользовательские маршруты. Смотрите.</p><h4 class="wp-block-heading">Компоненты</h4><p>Почти всегда у разрабатываемой системы есть как минимум три компонента: клиент (мобильное приложение или браузер), сервер и база данных (потому что она тоже может включать в себя функции-процедуры). Иногда они разрабатываются совместно, но чаще — нет, или только частично. Соответственно, функции необходимо прорабатывать так же, по отдельности.</p><h4 class="wp-block-heading">Типы функций</h4><p>Кроме того, все функции можно условно поделить на несколько типов:</p><ul class="wp-block-list"><li>пользовательские (в схеме логина ниже представлены синими блоками);</li><li>системные (белые блоки);</li><li>проверка условий (ромбы);</li><li>негативные (с красной обводкой);</li><li>позитивные (с зелёной обводкой).</li></ul><h4 class="wp-block-heading">Функциональный сценарий</h4><p>Подобные схемы позволяют наглядно представлять функциональные сценарии, сильно упрощая работу дизайнерам и программистам:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba58a206&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba58a206" class="wp-block-image aligncenter wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="1660" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2023/12/functional-arch-login.png" alt="" class="wp-image-3888" srcset="https://sherer.pro/content/uploads/2023/12/functional-arch-login.png 2096w, https://sherer.pro/content/uploads/2023/12/functional-arch-login-1048x830.png 1048w, https://sherer.pro/content/uploads/2023/12/functional-arch-login-768x608.png 768w" sizes="auto, (max-width: 2096px) 100vw, 2096px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Функциональный сценарий логина</figcaption></figure><p>Однако такая глубокая проработка уже попахивает настоящим <strong>детальным </strong>проектированием. А мы знаем, что начинать работу над архитектурой с него точно не стоит. С другой стороны, довольно сложно составить общую картину, выявить взаимосвязи и общие функции, не прорабатывая сценарии. И вот тут на сцену выходят профессионализм и тот самый уровень абстракции.</p><p>Сперва мы создаём самые базовые сценарии, углубляя их по мере появления более детальной информации о продукте. Например, в начале мы не знаем, как будет проходить обработка данных на сервере, но уверены, что он вернёт или положительный, или отрицательный ответ — и развиваем схему, исходя из этого.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba58a4de&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba58a4de" class="wp-block-image aligncenter wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="2764" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2023/12/functional-arch-evolution.png" alt="" class="wp-image-3889" srcset="https://sherer.pro/content/uploads/2023/12/functional-arch-evolution.png 2096w, https://sherer.pro/content/uploads/2023/12/functional-arch-evolution-1048x1382.png 1048w, https://sherer.pro/content/uploads/2023/12/functional-arch-evolution-768x1013.png 768w" sizes="auto, (max-width: 2096px) 100vw, 2096px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Пример итерационной детализации функциональных сценариев</figcaption></figure><p>Да, нам придётся иногда возвращаться назад и перепроектировать отдельные части функциональных сценариев. Но если мы изначально будем действовать правильно, такие переделки будут встречаться довольно редко.</p><h3 class="wp-block-heading">Взаимосвязи и общие функции</h3><p>Однако одних сценариев недостаточно. Помните, я говорил, что <em>функциональные </em>разделы куда более глубоко связаны между собой, чем <em>навигационные</em>?</p><p>Давайте вернёмся к нашему примеру с контентным приложением. У нас там есть глобальный функциональный раздел <strong>&#171;Новости&#187;</strong>, который включает в себя два схожих подраздела:</p><ul class="wp-block-list"><li><strong>&#171;Главная&#187;</strong> (список всех новостей).</li><li><strong>&#171;Категория&#187;</strong> (список новостей, относящихся к определённой тематике).</li></ul><p>В обоих случаях у нас есть список, есть пагинация (например, &#171;бесконечный&#187; скролл), есть типовой внешний вид карточки новости в таком списке. Получается, что эти два раздела во многом включают в себя одну и ту же функциональность. Более того, функциональность эта отнюдь не простая: тут и отображение списка новостей, их обновление, и подгрузка новых при скролле.</p><p>Логично вынести это в отдельный функциональный раздел (в схеме выше он назван <strong>&#171;Листинг&#187;</strong>). Тогда не придётся каждый раз отрисовывать один и тот же фрагмент, не придётся писать один и тот же код. Архитектура становится проще, продукт стабильнее.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5eba58a889&quot;}" data-wp-interactive="core/image" data-wp-key="69d5eba58a889" class="wp-block-image aligncenter wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="728" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://sherer.pro/content/uploads/2023/12/functional-arch-commons.png" alt="" class="wp-image-3890" srcset="https://sherer.pro/content/uploads/2023/12/functional-arch-commons.png 2096w, https://sherer.pro/content/uploads/2023/12/functional-arch-commons-1048x364.png 1048w, https://sherer.pro/content/uploads/2023/12/functional-arch-commons-768x267.png 768w" sizes="auto, (max-width: 2096px) 100vw, 2096px" /><button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="Увеличить"
data-wp-init="callbacks.initTriggerButton"
data-wp-on--click="actions.showLightbox"
data-wp-style--right="state.imageButtonRight"
data-wp-style--top="state.imageButtonTop"
><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"><path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /></svg></button><figcaption class="wp-element-caption">Взаимосвязь разделов через общие функции</figcaption></figure><p>Пример с листингом очень простой. Но знали бы вы, сколько раз я встречал копипаст в даже в таких очевидных местах. А что уж говорить о более сложных и редко встречающихся функциях, вроде обрезки изображений? Отправка и обработка форм, обновление экрана по свайпу вниз, показ системных сообщений — все эти функции (и многие другие) могут и должны быть вынесены вовне, в отдельный функциональный раздел.</p><p>Кроме того, некоторые функции могут блокировать выполнение других, или быть их &#171;предвестниками&#187;, но об этом мы поговорим позже.</p><h2 class="wp-block-heading">В следующей серии</h2><p>Остались ещё две статьи цикла. Там мы более глубоко погрузимся в практическую часть, разберём несколько потенциальных проблем, подробно пройдёмся по общим и &#171;зависимым&#187; функциям, рассмотрим примеры описания конкретных функций.</p><p>Запись <a href="https://sherer.pro/blog/funkcionalnaja-arhitektura-cifrovyh-produktov-chast-2/">Функциональная архитектура цифровых продуктов, часть 2</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded><wfw:commentRss>https://sherer.pro/blog/funkcionalnaja-arhitektura-cifrovyh-produktov-chast-2/feed/</wfw:commentRss><slash:comments>3</slash:comments></item></channel></rss>