<?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/development/feed/" rel="self" type="application/rss+xml" /><link>https://sherer.pro/blog/category/development/</link><description>Продюсер, аналитик, продуктовый дизайнер IT-решений</description><lastBuildDate>Wed, 10 Dec 2025 13:37:07 +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/development/</link><width>32</width><height>32</height></image> <item><title>Дизайн данных (часть 7). Прототипирование.</title><link>https://sherer.pro/blog/dizajn-dannyh-chast-7-prototipirovanie/</link><comments>https://sherer.pro/blog/dizajn-dannyh-chast-7-prototipirovanie/#comments</comments><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Tue, 02 Jul 2019 10:57:23 +0000</pubDate><category><![CDATA[Разработка]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[гайд]]></category><category><![CDATA[дизайн данных]]></category><guid isPermaLink="false">https://sherer.pro/?p=922</guid><description><![CDATA[<p>Техническое прототипирование API и баз данных - полный хардкор во имя ускорения и стабилизации разработки. Завершающий пост цикла про data design.</p><p>Запись <a href="https://sherer.pro/blog/dizajn-dannyh-chast-7-prototipirovanie/">Дизайн данных (часть 7). Прототипирование.</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p>Это завершающий пост цикла про data design. Самый хардкорный и &#8212; самый полезный. Разумеется, до него добрались лишь немногие. Слабые и юные отсеялись на предыдущих статьях, остались лишь закалённые суровым проектированием передачи и хранения данных.</p><p>Если же вы по какой-то невероятной причине решились сходу нырнуть в прототипирование, не испытав свой характер шестью предыдущими статьями &#8212; я искренне вам сочувствую. И рекомендую, всё же, начать с лайтового, плавного погружения в тему.</p><p>А мы пока продолжим.</p><h2 class="wp-block-heading">Проблема</h2><p>Никто не проектирует большие сервисы заранее и целиком. Это нерационально, вредно для сердца и кошельков инвесторов. Но всегда есть базовый этап проектирования, который нужно закончить, прежде чем первая строчка кода опасливо выползет из IDE программиста в командный git-репозиторий.</p><p>Уровень продуктового дизайнера определяет, в числе прочего, и то, насколько глубоким будет этот самый базовый этап. Кому-то хватит лишь концепции продукта и первой пары вайрфреймов, а кто-то упорется по продумыванию гибкой и масштабируемой архитектуры. И только совсем матёрые попробуют с самого начала заложить основу для стабильной работы продуктовой команды. Так вот ниже я расскажу, как стабилизировать и ускорить разработку за счёт технического прототипирования.</p><h3 class="wp-block-heading">Первый этап позади</h3><p>Представим, что вот вы добрались до финальной стадии первого этапа проектирования. Опрошены толпы респондентов, собрана тонны инфы о рынке и ЦА. Команда разработки уже считает вас своей роднёй &#8212; столько времени вы провели с ними, выпытывая тонкости будущей реализации (а если команды пока нет &#8212; такой же роднёй считает вас гугл). Всё это время вы не забывали про дизайн данных, и информационная архитектура будущего сервиса стала прекраснее рассвета в швейцарских горах.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d3df5f&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d3df5f" class="wp-block-image wp-lightbox-container"><img fetchpriority="high" decoding="async" width="1314" height="547" 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/2019/07/sunset.jpg" alt="Рассвет в швейцарских горах" class="wp-image-1737" srcset="https://sherer.pro/content/uploads/2019/07/sunset.jpg 1314w, https://sherer.pro/content/uploads/2019/07/sunset-768x320.jpg 768w, https://sherer.pro/content/uploads/2019/07/sunset-1048x436.jpg 1048w" sizes="(max-width: 1314px) 100vw, 1314px" /><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>Жизнь восхитительна, несмотря на поседевшие за время проектирования виски. И, вроде бы, можно начинать&#8230; но какая-то мелкая заноза не даёт вам &#171;спустить курок&#187; разработки. Что это? Перфекционизм или паранойя?</p><p>Скорее всего, это смутное осознание того, что ни один проект не разрабатывается строго по документации. Даже NASA, с их жёсткими, как Борис Бритва, стандартами &#8212; и те вносят изменения в продукт по ходу его реализации. А это значит, что часть вашей работы, ваш пот и кровь, будут тупо слиты в канализацию нестабильной разработки и поздних исследований. И ничего с этим не поделаешь. Вроде бы.</p><p>На самом деле, ещё как поделаешь. Идеального проектирования не бывает, и документация не высечена в камне, чтобы быть неизменной. Однако мы в состоянии минимизировать эти изменения &#8212; или, хотя бы, сделать их появление разумным и ожидаемым.</p><p>Давайте рассмотрим одну из фундаментальных причин того, почему в 90% случаев разработка ведётся, мягко говоря, не оптимально.</p><h3 class="wp-block-heading">Мягко говоря</h3><p>Какой бы методологии не придерживалась ваша проектная команда, почти всегда есть один фактор, снижающий динамику разработки. Он же заставляет программистов скакать из контекста в контекст, переключаясь между задачами, делая их работу менее эффективной.</p><p>Этот фактор звучит просто: <strong>&#171;клиент ждёт сервер&#187;</strong>. Этой проблеме столько лет, что она уже стала частью проектной практики &#8212; и самые крутые продакты и тимлиды заранее закладывают в бюджет небольшой простой разработчиков.</p><p>Как это выглядит. Серверный программист написал фичу, клиентский (например, мобильный) &#8212; заюзал эту фичу в приложении. Пока приложение на стороне клиента не может получить информацию по API, фича не может быть до конца разработана и протестирована. Для наглядности вот вам картинка:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d3e33f&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d3e33f" class="wp-block-image aligncenter size-full wp-lightbox-container"><img decoding="async" width="2096" height="676" 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/client-server-wait.png" alt="" class="wp-image-3882" srcset="https://sherer.pro/content/uploads/2023/12/client-server-wait.png 2096w, https://sherer.pro/content/uploads/2023/12/client-server-wait-1048x338.png 1048w, https://sherer.pro/content/uploads/2023/12/client-server-wait-768x248.png 768w" sizes="(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>Красные области &#8212; это время, которое клиентские разработчики ждут, пока метод API заработает на сервере. В самом начале такой области нет, потому что на старте проекта мобильным или веб-разработчикам ещё не до API, они пишут основную архитектуру. Зато потом&#8230;</p><p>Простаивающие разработчики &#8212; это деньги, выброшенные впустую. Это даже хуже, чем классический пример с водкой и пивом &#8212; потому что там у вас остаётся хотя бы один ингредиент. В случае с разработчиками же у вас не остаётся ничего. Компания платит им зарплату за то, что они <strong>не</strong> работают. И даже если на свой стартап вы набрали фрилансеров, получающих почасовую оплату, это всё равно обернётся для вас дополнительными расходами. Хотя бы потому, что фрилансер, почуяв простой (а значит, отсутствие денег) возьмёт еще одну подработку &#8212; а значит, по возвращению у него будет период переключения контекста. Его работа будет менее эффективна.</p><p>То же самое справедливо и для случаев, когда в компании тимлид пытается закрыть простои дополнительными задачами. Типа <em>&#171;о, сервер будет готов только через два дня; давай-ка ты пока пофиксишь вон тот баг с низким приоритетом&#187;</em>. Контекст меняется, эффективность падает. Меняются планы, сползает роадмап, теряются деньги. В какой-то момент команда отказывается от реализации нескольких мелких фич, потому что внезапно начинает подкрадываться овербаджет.</p><p>Продукт получается хуже и дороже, чем мог бы быть.</p><h2 class="wp-block-heading">Решение</h2><p>А теперь представьте, что API готов с самого начала. Может, не полностью, но в той мере, которая нужна клиентским разработчикам, чтобы никого не ждать, а просто пилить свой чёртов код.</p><p>Что, если вы, крутой дизайнер данных, с самого-самого начала предоставите им <strong>рабочий прототип API</strong>? Там будут фейковые данные, не будет сложной логики &#8212; но это будут методы, которые отдают реальный формат ответов.</p><h3 class="wp-block-heading">Серверная разработка</h3><p>Имея на старте такой прототип, серверный программист просто &#171;транслирует&#187; ваш API через реальный сервер. Получается, что с самого старта все методы готовы, но отдают &#171;прототипированную&#187; информацию. Назовём такие методы &#171;заглушками&#187;. По мере работы, наш программист просто заменяет &#171;заглушки&#187; на реальные методы, возвращающие уже самые что ни на есть реальные данные.</p><p>Сервер изначально знает все форматы ответов. Ничего не нужно выдумывать, стараться унифицировать, бояться что-то пропустить. Разработка без страха. Мечта прям.</p><h3 class="wp-block-heading">Клиентская разработка</h3><p>Просто пишет код. Да, мобильные или веб-разработчики оглядываются на то, что изначально данные приходят фейковые. Возможно (если ваш прототип простенький), обработку некоторых ошибок на первых порах придётся делать, руководствуясь исключительно документацией. Тестировщикам порой придется прогонять тест-кейсы дважды &#8212; но в этом нет ничего плохого.</p><p>Клиентские программисты никого не ждут. Теперь они не вынуждены постоянно синхронизироваться с динамикой серверной разработки. Они решают задачи в порядке приоритетов, а не основываясь на собственной занятости.</p><h3 class="wp-block-heading">Визуально</h3><p>Если совсем упростить, то получается примерно вот такая схемка:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d3e7af&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d3e7af" class="wp-block-image aligncenter size-full wp-lightbox-container"><img decoding="async" width="2096" height="1440" 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/project-status.png" alt="" class="wp-image-3883" srcset="https://sherer.pro/content/uploads/2023/12/project-status.png 2096w, https://sherer.pro/content/uploads/2023/12/project-status-1048x720.png 1048w, https://sherer.pro/content/uploads/2023/12/project-status-768x528.png 768w" sizes="(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">Схематичный статус разработки при использовании прототипа API</figcaption></figure><p>Конечно, не всегда клиент обгоняет сервер по скорости запила фич в продакшн. Однако такая схема позволяет вообще переосмыслить последовательность разработки каждого компонента &#8212; сервер, например, может сначала сделать то, что удобно с точки зрения архитектуры, не оглядываясь на потребности клиентской части. Серверный и клиентский кодинг теперь практически независимы друг от друга.</p><h3 class="wp-block-heading">Да ну нафик</h3><p>Но это всё в теории, скажите вы. На практике, чтобы зафигачить такой прототип, нужно уметь кодить. Да ещё иметь собственный сервер, чтобы разместить там этот код. Да и вообще, это занимает тьму тьмущую времени &#8212; не факт, что оплата работы дизайнера не превысит потенциальную выгоду от пресловутой стабилизации разработки.</p><p>И это было бы так, если бы человечество постоянно не развивалось &#8212; и в какой-то момент его представители не подарили бы миру целый ворох потрясающих сервисов и инструментов для быстрого прототипирования всего и вся, включая API. Несколько ниже мы пройдёмся по некоторым из них, а пока давайте-ка вернёмся к нашему прекрасному приложению про миграцию тюленей &#8212; пора переходить к более практической части.</p><h2 class="wp-block-heading">Прототипирование API</h2><p>Любое прототипирование начинается с документации. Тем более, прототипирование техническое. А значит, нам сперва нужно описать запросы и ответы будущего API.</p><p>В <a href="https://sherer.pro/blog/dizajn-dannyh-chast-6-matchast-api/">предыдущей статье</a> про дизайн данных мы с вами очень подробно разобрали все сущности нашего сервиса, их свойства и даже типы данных, а в <a href="https://sherer.pro/blog/dizajn-dannyh-chast-3-menjaemsja/">третьей статье</a> проходились по конкретным запросам. Если вы знакомились с ними давно &#8212; возможно, стоит освежить в памяти <a href="https://sherer.pro/blog/dizajn-dannyh-chast-3-menjaemsja/#seal-requests">логику их формирования</a>, ибо сейчас мы уже начнём составлять реальные методы API.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>И ещё момент. Если вы еще не знакомы с синтаксисом <a href="https://ru.wikipedia.org/wiki/JSON" target="_blank" rel="noreferrer noopener" aria-label="JSON (откроется в новой вкладке)">JSON</a>, крайне рекомендую это сделать &#8212; все запросы и ответы будут формироваться именно в этом формате. Он не сложный.</p><p>А при возникновении сомнений в правильности написанного вами json-запроса/ответа, всегда можно воспользоваться одним из <a href="https://www.google.com/search?q=json+validator" target="_blank" rel="noreferrer noopener" aria-label="валидаторов JSON (откроется в новой вкладке)">валидаторов JSON</a>.</p></blockquote><h3 class="wp-block-heading">Запросы и ответы</h3><p>Итак, поехали. Для каждого метода я кратко напоминаю его суть &#8212; и сразу даю текст/код запросов ответов. Не переходите к следующему, пока не разобрались в текущем.</p><h4 class="wp-block-heading">Регистрация и аутентификация</h4><p>Здесь на сервер мы отправляем номер телефона, а обратно получаем статус и глобальный идентификатор. Ну и, разумеется, помним про заголовки (<code>userSecretKey</code> и <code>userGuid</code> оставляем пустыми) .</p><p><strong>Название запроса</strong></p><pre class="wp-block-preformatted">registration</pre><p><strong>Запрос</strong></p><pre class="wp-block-code"><code>Headers

    userSecretKey: 
    userGuid: 
    appVersion: 1.0.1
    appDeviceId: 2fc4b5912826ad1
    appPlatform: iOS

Body

    {
        "dt_request": "registration",
        "phone": 79667778899
    }</code></pre><p><strong>Положительный ответ</strong></p><pre class="wp-block-code"><code>Body

    {
        "dt_status": "success",
        "userGuid": "c0deaca4-db8a-4178-8863-eaf2494833b9"
    }</code></pre><h4 class="wp-block-heading">Подтверждение номера телефона</h4><p>Здесь на сервер отправляется код из СМС, глобальный идентификатор пользователя и идентификатор устройства, а обратно улетает статус и секретный ключ.</p><p><strong>Название запроса</strong></p><pre class="wp-block-preformatted">confirm</pre><p><strong>Запрос</strong></p><pre class="wp-block-code"><code>Headers

    userSecretKey: 
    userGuid: c0deaca4-db8a-4178-8863-eaf2494833b9
    appVersion: 1.0.1
    appDeviceId: 2fc4b5912826ad1
    appPlatform: iOS

Body

    {
        "dt_request": "confirm",
        "code": 4509
    }</code></pre><p><strong>Положительный ответ</strong></p><pre class="wp-block-code"><code>Body

    {
        "dt_status": "success",
        "userSecretKey": "4af0744c305991c098753117a6a19690"
    }</code></pre><h4 class="wp-block-heading">Получение списка точек</h4><p>В заголовках запроса мы указываем глобальный идентификатор пользователя, идентификатор устройства и секретный ключ, а в параметрах — отступ и область видимости. В ответ же получаем статус и массив (список) точек.</p><p><strong>Название запроса</strong></p><pre class="wp-block-preformatted">getPoints</pre><p><strong>Запрос</strong></p><pre class="wp-block-code"><code>Headers

    userSecretKey: 4af0744c305991c098753117a6a19690
    userGuid: c0deaca4-db8a-4178-8863-eaf2494833b9
    appVersion: 1.0.1
    appDeviceId: 2fc4b5912826ad1
    appPlatform: iOS

Body

    {
        "dt_request": "getPoints",
        "offset": 0,
        "scope": 60
    }</code></pre><p><strong>Положительный ответ</strong></p><pre class="wp-block-code"><code>Body

    {
        "dt_status": "success",
        "points": &#91;
            {
                "dateTime": "2019-09-12T19:05:12-03",
                "coords": {
                    "long":"59.5194488",
                    "lat":"150.4879161"
                },
                "thumb": {
                    "url":"/thumbs/uat12ia.jpg",
                    "hash":"05991c09f0744a4c38756903117a6a19"
                },
                "picture": {
                    "url":"/picture/hrdt6q7.jpg",
                    "hash":"305991c094af0744c876a1969053117a"
                }
            },
            {
                "dateTime": "2019-09-13T19:075:13-12",
                "coords": {
                    "long":"59.5110862",
                    "lat":"150.7186927"
                },
                "thumb": {
                    "url":"/thumbs/uiwy66q.jpg",
                    "hash":"04c876a305991c1969053471194af07a"
                },
                "picture": {
                    "url":"/picture/wad5h7a1.jpg",
                    "hash":"9a455991a6c387690310c017a19f0744"
                }
            }
        ]
    }</code></pre><h4 class="wp-block-heading">Ошибки</h4><p>Конечно, не забываем про ошибки. Это крайне важно, потому что унификация обработки ошибок существенно упрощает разработку и (главное) поддержку и развитие проекта.</p><p>Ошибки могут быть <strong>универсальными</strong> и <strong>не-универсальными</strong>. Первые сервер может вернуть в ответ на различные запросы, тогда как вторые всегда принадлежат конкретному методу. В нашем случае, например, ошибка валидации номера телефона может возникнуть только в тот момент, когда мобильное приложение отправляет на сервер запрос о регистрации пользователя &#8212; потому что больше нигде номер телефона не используется. Это не-универсальная ошибка. Универсальной же, к примеру, можно считать ошибку &#171;пользователь не найден&#187;.</p><p>В идеале, при создании документации не-универсальные ошибки нужно описывать в конкретном методе, а универсальные можно вынести в отдельный раздел (или просто указать, что это универсальная ошибка). Разумеется, при описании тех запросов, которые потенциально могут вернуть универсальные ошибки, нужно об этом прямо заявить. Но так как мы не создаём реальные доки, все ошибки мы засунем в единый раздел &#8212; так вам будет проще.</p><p>Итак, ошибки. У каждой будет статус, код и текст.</p><p><strong>Пользователь не найден</strong></p><p>Возвращается в случае, если пользователя с указанными <code>userGuid</code> нет в БД. Универсальная ошибка.</p><pre class="wp-block-code"><code>Body

    {
        "dt_status": "error",
        "dt_errorCode": &#91;110],
        "dt_errorMessage": "User is not found"
    }</code></pre><p><strong>Не пройдена авторизация</strong></p><p>Возвращается в случае, если передан некорректный <code>userSecretKey</code>. Универсальная ошибка.</p><pre class="wp-block-code"><code>Body

    {
        "dt_status": "error",
        "dt_errorCode": &#91;120],
        "dt_errorMessage": "Authorisation Error"
    }</code></pre><p><strong>Некорректный номер телефона</strong></p><p>Возвращается в случае, если номер телефона не соответствует нужному формату. Может возникнуть только при выполнении метода <code>registration</code>.</p><pre class="wp-block-code"><code>Body

    {
        "dt_status": "error",
        "dt_errorCode": &#91;210],
        "dt_errorMessage": "Wrong phone number"
    }</code></pre><p><strong>Неверный код из СМС</strong></p><p>Возвращается в случае, если передан некорректный код из СМС. Может возникнуть только при выполнении метода <code>confirm</code>.</p><pre class="wp-block-code"><code>Body

    {
        "dt_status": "error",
        "dt_errorCode": &#91;220],
        "dt_errorMessage": "Invalid SMS code"
    }</code></pre><p><strong>Переданы неверные параметры</strong></p><p>Возвращается в случае, если переданы некорректные параметры запроса (например, в запросе <code>getPoints</code> значение <code>scope</code> не кратно значению <code>offset</code>). Универсальная ошибка.</p><pre class="wp-block-code"><code>Body

    {
        "dt_status": "error",
        "dt_errorCode": &#91;310],
        "dt_errorMessage": "Invalid parameters passed"
    }</code></pre><p>Разумеется, это не весь список. Обязательно нужно предусмотреть совсем пограничные ситуации, вроде &#171;неизвестной ошибки сервера&#187; (когда мы по какой-то причине не можем сообщить на клиент, в чём именно проблема). Есть ещё ситуации, когда запрос улетел, а сервер не ответил, потому что упал (или пропала связь).</p><p>У меня в проектах словарь ошибок, как правило, насчитывает от 40 до 70 различных кодов. При этом все они разделены на группы: например, ошибки, связанные с пользователем, имеют коды 1XX, а ошибки, связанные конкретно с регистрацией/аутентификацией/авторизацией (вроде &#171;некорректного кода из СМС&#187;) &#8212; коды 2XX. И так далее.</p><h3 class="wp-block-heading">Инструменты</h3><p>Чуть ранее я обещал рассказать вам про инструментарий прототипирования API. На самом деле, таких инструментов &#8212; лютая тьма, но я их субъективно делю на три условных группы:</p><ul class="wp-block-list"><li>базовые инструменты;</li><li>сервисы;</li><li>фреймворки.</li></ul><h4 class="wp-block-heading">Базовые инструменты</h4><p>Как правило, обладают довольно узким набором возможностей. Например, умеют преобразовывать разметку <a href="https://ru.wikipedia.org/wiki/Markdown">Markdown</a> в конкретный код. Или умеют валидировать HTTP-запросы.</p><p>Пример такого инструмента &#8212; <a href="https://apiblueprint.org/" target="_blank" rel="noreferrer noopener" aria-label="API Blueprint (откроется в новой вкладке)">API Blueprint</a>. Это довольно крутой высокоуровневый язык описания API в уже упомянутом Markdown. Есть ещё <a href="https://dredd.org" target="_blank" rel="noreferrer noopener" aria-label="Dredd (откроется в новой вкладке)">Dredd</a>, который может автоматически тестировать API (хотя он, скорее, фреймворк, просто очень узкоспециализированный).</p><p>Прототипируя API, использовать такие инструменты по отдельности довольно сложно &#8212; придётся их связывать между собой.</p><h4 class="wp-block-heading">Сервисы</h4><p>Вот это &#8212; вариант большинства дизайнеров данных. В состав таких сервисов уже входят связки различных базовых инструментов. Прототипирование в них не требует каких-то особенных знаний, кроме языка разметки и понимания того, что ты делаешь. Платить за простоту приходится какими-то ограничениями: например, нельзя настроить логику обработки запросов или тип запроса всегда указывается в URL (а не отдельным параметром, как у нас в приложении про тюленей). Но с этим можно жить.</p><p>Хорошие примеры таких сервисов &#8212; <a href="https://apiary.io/" target="_blank" rel="noreferrer noopener" aria-label="Apiary (откроется в новой вкладке)">Apiary</a> и <a href="https://swagger.io/" target="_blank" rel="noreferrer noopener" aria-label="Swagger (откроется в новой вкладке)">Swagger</a>. Обратите внимание на первый, к нему мы ещё вернёмся.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d3f207&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d3f207" class="wp-block-image wp-lightbox-container"><img decoding="async" 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/2019/07/apiary-workplace-scaled.jpg" alt="" class="wp-image-1753"/><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">Рабочая область сервиса Apiary</figcaption></figure><p>Ещё рекомендую посмотреть на целую программу для быстрого прототипирования &#8212; <a href="https://getmateria.com/" target="_blank" rel="noreferrer noopener" aria-label="Materia (откроется в новой вкладке)">Materia Designer</a> (устарело, в настоящее время не поддерживается — прим.). Она умеет не только API, но и базы данных, и даже сервер. Там всё очень визуально и нужно уметь проектировать БД, но бонусом идёт практически настоящий серверный код. Я лично знаю несколько маленьких проектов, которые крутятся именно на ней.</p><h4 class="wp-block-heading">Фреймворки</h4><p>А вот это уже для тех, кто в своей жизни познал некоторое количество кодинга. По сути, это набор готовых решений на каком-либо языке программирования. Работа с ними занимает несколько больше времени, чем с сервисами (плюс надо хотя бы немного знать язык), но и возможностей у них побольше.</p><p>Примеров приводить не стану, так как выбор здесь всегда очень и очень индивидуален для каждого проекта/дизайнера.</p><h3 class="wp-block-heading">Реальный прототип</h3><p>Чтобы не быть голословным, я действительно собрал в Apiary простенький, но рабочий прототип API нашего несуществующего приложения. Да, там методы указаны в URL (а не параметром). Да, нет серверной логики (всегда возвращаются положительные ответы, вне зависимости от заголовков и параметров). Но этого достаточно, чтобы реализовать базовую функциональность мобильного приложения. А ошибки обрабатывать согласно документации. <a href="https://sealsapp.docs.apiary.io" target="_blank" rel="noreferrer noopener" aria-label="Полюбуйтесь (откроется в новой вкладке)">Полюбуйтесь</a>, в общем.</p><p>Более того, на моём полудохлом гитхабе даже есть <a href="https://github.com/sherer-pro/sealsapp/blob/master/apiary.apib" target="_blank" rel="noreferrer noopener" aria-label="текст (откроется в новой вкладке)">разметка</a> этого прототипа. Вы можете самостоятельно завести новый проект в <a href="https://apiary.io/" target="_blank" rel="noreferrer noopener">Apiary</a>, скопипастить в него текст по ссылке и поэкспериментировать (осторожно, возможно отравление Markdown&#8217;ом).</p><p>На этом с прототипированием API мы закончили. Если у вас остались вопросы (а странно, если это не так), велкам в комментарии.</p><h2 class="wp-block-heading">На десерт &#8212; прототипирование БД</h2><p>Я специально оставил эту часть напоследок, как менее важную. По статистике, до этой части полутехнического лонгрида доживают считанные единицы. И всё же, я не могу не коснуться темы прототипирования базы данных &#8212; просто потому, что реальные профи data design должны уметь хотя бы читать <a href="https://sherer.pro/blog/dizajn-dannyh-chast-5-matchast-bazy-dannyh/#visualization" target="_blank" rel="noreferrer noopener" aria-label="ER-диаграммы (откроется в новой вкладке)">ER-диаграммы</a>. А в идеале &#8212; создавать базовую структуру БД уже на старте проекта.</p><h3 class="wp-block-heading">Зачем делать прототип базы данных?</h3><p>Причина, на самом деле, довольно простая, и я о ней уже говорил. Стабилизация. Плюс &#8212; упрощение развития и поддержки проекта, оптимизация скорости работы продукта.</p><p>В большинстве случаев база данных создаётся серверным программистом в одиночку. Очень и очень редко у вас будет под рукой выделенный архитектор, способный запихнуть в свою гениальную голову весь проект &#8212; и в итоге выдать структуру базы. Чаще всего БД создаётся поэтапно, по мере того, как разработчик доходит в реализации до какого-то нового участка. Требовать от него какого-то идеала сложно &#8212; как правило, они очень функциональные люди, и мыслят соответственно. Выйти на уровень абстракции всего проекта они, конечно, могут &#8212; но сделать это правильно способны только сеньоры или очень и очень крепкие мидлы.</p><p>Чем больше проект, тем чаще в нём остаются какие-то рудименты в виде неиспользуемых свойств сущностей, странных и порой очень запутанных связей, неверных типов данных и так далее. Индексировать такую базу сложно, возрастает нагрузка на сервер. В итоге БД работает медленнее, чем могла бы. Её куда сложнее поддерживать и практически невозможно отрефакторить.</p><h3 class="wp-block-heading">Что нужно сделать?</h3><p>Самый простой способ &#8212; поговорить с серверным разработчиком и дать ему полный список сущностей и свойств проекта. Желательно также отдельно указать на их взаимосвязи (конечно, разработчик должен быть знаком с проектом хотя бы на уровне концепции). Нормально, если он после этого сможет дать какие-то рекомендации и дизайнер доработает свою документацию.</p><p>Это был минимум. Максимум &#8212; нужно научиться выбирать <a href="https://sherer.pro/blog/dizajn-dannyh-chast-5-matchast-bazy-dannyh/#types-of-databases" target="_blank" rel="noreferrer noopener" aria-label="тип базы данных (откроется в новой вкладке)">вид базы данных</a>, формировать её структуру и составлять правильную визуализацию. Если же делать эту самую визуализацию в правильном инструменте, то можно сразу выгнать дамп структуры базы &#8212; он-то и станет основой прототипа БД.</p><h3 class="wp-block-heading">Инструменты</h3><p>Выбор правильного инструмента во многом зависит от вида БД, и даже иногда от конкретной <a href="https://sherer.pro/blog/dizajn-dannyh-chast-5-matchast-bazy-dannyh/#dbms" target="_blank" rel="noreferrer noopener" aria-label="СУБД (откроется в новой вкладке)">СУБД</a>. Но так как чаще всего весь мир мобильной и веб-разработки использует реляционные БД, то рассматривать мы будем именно их.</p><p>И тут у нас довольно большой выбор. Есть онлайн-сервисы, вроде <a href="https://www.vertabelo.com/" target="_blank" rel="noreferrer noopener" aria-label="Vertabelo (откроется в новой вкладке)">Vertabelo</a>, есть десктопные приложения, вроде <a href="https://www.mysql.com/products/workbench/" target="_blank" rel="noreferrer noopener" aria-label="MySQL Workbench (откроется в новой вкладке)">MySQL Workbench</a> или уже упоминаемой <a href="https://getmateria.com/" target="_blank" rel="noreferrer noopener">Materia</a>. Онлайн удобен, когда над БД работают несколько человек, а десктопные программы хороши, когда нужно собрать сложную SQL-логику или в оффлайне.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d3f702&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d3f702" class="wp-block-image wp-lightbox-container"><img loading="lazy" decoding="async" width="2038" height="1264" 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/2019/07/materia-entities.png" alt="Интерфейс прототипирования БД в Materia" class="wp-image-1768" srcset="https://sherer.pro/content/uploads/2019/07/materia-entities.png 2038w, https://sherer.pro/content/uploads/2019/07/materia-entities-768x476.png 768w, https://sherer.pro/content/uploads/2019/07/materia-entities-1048x650.png 1048w" sizes="auto, (max-width: 2038px) 100vw, 2038px" /><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">Интерфейс прототипирования БД в Materia</figcaption></figure><p>Если вас заинтересовала тема, можете пощупать эти софтины или поискать другие &#8212; благо, гуглятся они довольно легко.</p><h2 class="wp-block-heading">Риски прототипирования API и БД</h2><p>Как обычно, есть и ложка дёгтя. Она небольшая, но в нашем случае бочку с мёдом испортит безвозвратно. Если коротко, то она звучит как &#171;хреново спроектировал&#187;. И это не шутка. Если отнестись к прототипированию халатно, то вместо оптимизации разработки вы получите обратную ситуацию, дестабилизацию.</p><p>На самом деле, такое прототипирование здорово расслабляет программистов. Они рассчитывают на вас, ваши доки и прототипы. И если в обычной ситуации им бы пришлось нести за всё ответственность самим (что, по понятным причинам, повышает внимательность к архитектурным деталям), то в этом случае они могут и не заметить какого-то недостатка, пока не станет слишком поздно.</p><p>Ниже я собрал наиболее вероятные ошибки прототипирования БД и API.</p><h3 class="wp-block-heading">Унификация</h3><p>Не унифицировали имена параметров, сущностей, методов и тп (либо не прописали правила такого именования) &#8212; в результате при развитии API и БД получили целый зоопарк разных названий, не связанных единой семантикой. Погружение новых участников в проект стало происходить медленнее, а старым участникам стало требоваться больше времени, чтобы разобрать собственный код месячной давности.</p><h3 class="wp-block-heading">Не полная картина проекта</h3><p>В силу своей лени или неопытности, забыли про несколько методов API. Когда мобильная разработка дошла до этой части проекта, сервер был занят совершенно другой работой. В итоге вернулись к смене контекста, ухудшению производительности. Дизайнер понёс репутационные потери.</p><h3 class="wp-block-heading">Обработка ошибок</h3><p>По какой-то причине не были задокументированы (в случае простого прототипа) или реализованы (в случае прототипа сложного) некоторые ошибки API. Программисты справедливо рассудили, что &#171;нет в доках &#8212; не делаем&#187;. Приложение стало крашиться или вести себя непредсказуемо. На отладку и обратный инжиниринг стало уходить много времени.</p><h3 class="wp-block-heading">Связи, сущности и свойства</h3><p>Забыли про связи между некоторыми сущностями (или упустили их свойства), из-за чего была неверно создана база данных. Так как существующая часть БД оказалась уже задействована, пришлось вводить дополнительные таблицы. Усложнилось развитие и масштабирование продукта.</p><h3 class="wp-block-heading">Коммуникации</h3><p>Не создали у рабочей группы единого понимания задач и смысла прототипов. Программисты стали воспринимать их как часть документации, а не инструмент для оптимизации работы. Вред небольшой, но работа дизайнера данных полетела псу под хвост.</p><h2 class="wp-block-heading">Заканчиваем</h2><p>Вот, собственно, и всё. Цикл постов про дизайн данных завершён. Вероятнее всего, я ещё буду что-то добавлять в блог по мере появления идей, но этих семи статей уже должно хватить для старта и базового погружения в область. Помните, что продуктовый дизайн &#8212; это не только про картинки, это про продукт целиком.</p><p>И спасибо, что дочитали до конца.</p><p>Запись <a href="https://sherer.pro/blog/dizajn-dannyh-chast-7-prototipirovanie/">Дизайн данных (часть 7). Прототипирование.</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded><wfw:commentRss>https://sherer.pro/blog/dizajn-dannyh-chast-7-prototipirovanie/feed/</wfw:commentRss><slash:comments>2</slash:comments></item><item><title>Дизайн данных (часть 6). Матчасть: API.</title><link>https://sherer.pro/blog/dizajn-dannyh-chast-6-matchast-api/</link><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Sun, 09 Jun 2019 15:56:02 +0000</pubDate><category><![CDATA[Разработка]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[гайд]]></category><category><![CDATA[дизайн данных]]></category><guid isPermaLink="false">https://sherer.pro/?p=1289</guid><description><![CDATA[<p>В этой статье речь снова пойдёт об обмене информацией между компонентами системы. Однако на этот раз мы коснёмся более глубоких тем: рассмотрим, как создаётся философия API и даже пощупаем реальные примеры запросов.</p><p>Запись <a href="https://sherer.pro/blog/dizajn-dannyh-chast-6-matchast-api/">Дизайн данных (часть 6). Матчасть: API.</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p>Это шестой, предпоследний, пост цикла. И он же третий про матчасть дизайна данных.</p><p>В этой статье (как и в третьей, <a href="https://sherer.pro/blog/dizajn-dannyh-chast-3-menjaemsja/">&#171;Меняемся?&#187;</a>) речь снова пойдёт об обмене информацией между компонентами системы. Однако на этот раз мы коснёмся более глубоких тем: рассмотрим, как создаётся философия API и даже пощупаем реальные примеры запросов.</p><p>Предупреждаю, дальше вас ожидает полный хардкор &#8212; просьба убрать от мониторов несовершеннолетних детей, иллюстраторов и прочих убеждённых юайщиков.</p><p>Погнали.</p><h2 class="wp-block-heading">Виды API</h2><p>Как я уже упоминал, видов API огромное множество, ведь API &#8212; это лишь общее название всех программных интерфейсов. Например, есть API, позволяющий умному холодильнику коннектиться к Амазону и заказывать продукты, если они вдруг у вас кончились. При том у этого же холодильника есть ПО, которое с помощью уже другого API получает данные с внутренних сканеров (чтобы понять, каких продуктов не хватает). А также еще один API для доступа к микрофону, чтобы вы могли велеть своему холодильнику купить молока (и там же рядом API, передающий ваши слова на сервер для обработки). И еще один, чтобы синхронизироваться с вашими умными весами, и на основании их данных составлять примерное меню. И так до бесконечности, насколько хватило фантазии у дизайнеров упомянутого холодильника.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d40dfa&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d40dfa" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="722" 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/api-types.png" alt="" class="wp-image-3880" srcset="https://sherer.pro/content/uploads/2023/12/api-types.png 2096w, https://sherer.pro/content/uploads/2023/12/api-types-1048x361.png 1048w, https://sherer.pro/content/uploads/2023/12/api-types-768x265.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>Суть в том, что в примере выше есть &#171;физические&#187; API, которые дают возможность взаимодействовать с различным &#171;железом&#187; (типа сканеров или микрофона), а есть другие, которые позволяют обмениваться данными с различными внешними источниками (вроде серверов Амазона). Мы будем рассматривать исключительно вторые, так как именно с ними чаще всего придётся работать продуктовому дизайнеру.</p><h2 class="wp-block-heading">Немножко лирики</h2><p>Догадливый читатель уже смекнул, что без понимания того, как эти API работают (и есть ли они вообще), невозможно спроектировать полноценную функциональность нашего холодильника (это я уже молчу о пользовательском опыте).</p><p>Ну и разумеется, сей тезис касается не только физических предметов: большинству дизайнеров даже не придёт в голову изучить вопрос внешних интеграций перед тем, как приступить к созданию нового цифрового продукта. Редкий проектировщик гуглит сервисы пуш-уведомлений (например), чтобы понять, какие у них есть ограничения.</p><p>Подавляющее большинство создаваемых нами сайтов и приложений обменивается информацией с серверами. Сейчас это просто данность, и дизайнер не имеет права игнорировать этот аспект своей работы. Хотя бы просто потому, что именно он (а не программный архитектор или, тем более, рядовой программист) знает создаваемый продукт лучше всех. Дизайнер может не разбираться в деталях, постоянно обращаться за помощью к технарям &#8212; но он должен понимать, как данные будут жить внутри его приложения, как они будут обмениваться с сервером и какие потенциальные риски могут при этом образоваться.</p><p>В одной статье я не научу вас создавать пуленепробиваемый API &#8212; но это и не нужно. Для начала хватит самого базового погружения. А дальше всё сделает опыт.</p><h2 class="wp-block-heading">Философия API</h2><p>На самом деле, термин &#171;Философия API&#187; на проектном уровне употребляется довольно редко. Однако, по моему субъективному мнению, именно он как нельзя лучше передаёт суть подхода. По факту, упомянутая философия &#8212; это набор основополагающих правил, по которым создаётся и развивается конкретный API.</p><p>Философия API описывает то, как именно будут обмениваться между собой стороны (например, мобильное приложение и сервер). Это некие верхнеуровневые правила, которые задают тон всему остальному. Без них развивать и поддерживать API довольно сложно: любой программист, добавляя тот или иной метод, руководствуется собственными представлениями о валидации (например). Единая философия позволяет унифицировать запросы/ответы, не ограничивая возможностей разработки.</p><p>Чем разжёвывать дальше, лучше приведу фрагмент документации одного из моих последних проектов:</p><div class="wp-block-group highlighted is-layout-constrained wp-block-group-is-layout-constrained"><h3 class="wp-block-heading">Общие принципы</h3><p>Описываемый в настоящем документе API является общим для всех сторон, если иное не указано отдельно. Это сделано в целях унификации обмена данными и упрощения развития API впоследствии.</p><p>Обмен информацией между Сторонами осуществляется только по защищенному SSL протоколу.</p><h3 class="wp-block-heading">Именование методов/параметров</h3><p>При обмене данными действует правило именования параметров: имена всех служебных параметров, которые касаются непосредственно сторон (параметры авторизации, названия запросов и т.д.), имеют префикс <code>dt_</code>, все прочие параметры его не имеют.</p><p>Все названия методов и параметров начинаются с маленькой буквы.</p><p>В названиях методов, состоящих из нескольких слов, определяющих сущность и действие, в качестве разделителя используется точка (например, <strong><code>user.registration</code></strong>).</p><p>В документации вложенность элементов (свойства сущностей) также разделяется точкой (например, <strong><code>user.id</code></strong>).</p><p>В названиях параметров, состоящих из нескольких слов, используется &#171;CamelCase&#187;: например, <code><strong>secretKey</strong> </code>(исключением являются аббревиатуры, состоящие из заглавных букв &#8212; например, <strong>SMS</strong>). Это не относится только к префиксу <strong><code>dt_</code></strong>.</p><h3 class="wp-block-heading">Форматы значений</h3><p>В значениях всех параметров:</p><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><code>integer</code></td><td><code>XXXXXXXXXXX</code></td><td><code>79554447788</code></td><td>11 цифр в междуна-родном формате без +</td></tr><tr><td>Дата и время</td><td><code>string</code></td><td><code>YYYY-MM-DDThh:mm:ss±hh</code></td><td><code>2005-08-09T18:31:42-03</code></td><td>ISO Date</td></tr><tr><td>Булевы значения</td><td><code>string</code></td><td></td><td><code>true</code></td><td>Всегда true|false</td></tr></tbody></table></figure><p>Допустима передача пустых массивов в случае возвращения функцией списка, состоящего из 0 сущностей. Во всех остальных случаях следует возвращать <strong><code>false</code></strong>.</p><p>Не допускаются значения <strong><code>null</code></strong>, <strong><code>undefined</code></strong> и подобные.</p><h3 class="wp-block-heading">Формат сообщений</h3><p>Все запросы и ответы передаются в кодировке <strong>UTF-8</strong> методом <strong>POST </strong>в формате <strong>JSON</strong>.</p><p>Сервер всегда отвечает HTTP-кодом <strong>200</strong>, даже в случае попытки неавторизованного доступа (в этом случае сервер возвращает код ошибки из словаря ошибок).</p><h4 class="wp-block-heading">Обязательные параметры</h4><p>В запросах и ответах есть ряд обязательных параметров, без которых сообщение не обрабатывается.</p><h5 class="wp-block-heading">Запрос</h5><p>Во всех запросах обязательно должны присутствовать параметры:</p><figure class="wp-block-table"><table><thead><tr><th>Поле</th><th>Тип</th><th>Пример</th><th>Описание</th></tr></thead><tbody><tr><td><code>dt_request</code></td><td><code>string</code></td><td><code>user.logout</code></td><td>Параметр, отвечающий за тип запроса. В рамках одной области типов может быть несколько.</td></tr></tbody></table></figure><h5 class="wp-block-heading">Ответ</h5><p>Во всех ответах обязательно должны присутствовать параметры:</p><figure class="wp-block-table"><table><thead><tr><th>Поле</th><th>Тип</th><th>Пример</th><th>Описание</th></tr></thead><tbody><tr><td><code>dt_status</code></td><td><code>string</code></td><td><code>success</code></td><td>Статус выполнения запроса, допустимые значения&nbsp;<strong>success</strong>|<strong>error</strong>.</td></tr><tr><td><code>dt_errorCode</code></td><td><code>array</code></td><td><code>[1800]</code></td><td>Является обязательным только в случае, если&nbsp;<strong>status==error</strong>. Принимает значения соответствующего кода ошибки из словаря ошибок.</td></tr></tbody></table></figure></div><p>Обычно я дополняю философию еще несколькими примерами запросов, чтобы архитектор и разработчики точно представляли, о чём речь. И в самом конце статьи я как раз представлю один такой.</p><h2 class="wp-block-heading">Назад к тюленям</h2><p>Это была теория. Давайте теперь вернёмся в нашему восхитительному приложению, позволяющему отслеживать миграцию тюленей на берегу Охотского моря.</p><p>В <a href="https://sherer.pro/blog/dizajn-dannyh-chast-3-menjaemsja/">одной из предыдущих статей</a> мы создали графическую схему запросов нашего выдуманного приложения. Если кто запамятовал, то вот она:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d4149c&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d4149c" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="1320" 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/datadesign-api-4.png" alt="" class="wp-image-3868" srcset="https://sherer.pro/content/uploads/2023/12/datadesign-api-4.png 2096w, https://sherer.pro/content/uploads/2023/12/datadesign-api-4-1048x660.png 1048w, https://sherer.pro/content/uploads/2023/12/datadesign-api-4-768x484.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">API: заголовки и методы запросов</figcaption></figure><p>Учитывая, что у нас здесь только схема <em>запросов</em>, а не <em>ответов</em>, последние будем додумывать на ходу. Благо, во <a href="https://sherer.pro/blog/dizajn-dannyh-chast-2-kak/">втором посте</a> цикла мы создали диаграмму со структурой данных нашего приложения:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d4175d&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d4175d" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2184" height="2200" 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/data-design-entities-operations-properties-full-save.png" alt="" class="wp-image-3861" srcset="https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save.png 2184w, https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save-1048x1056.png 1048w, https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save-768x774.png 768w, https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save-60x60.png 60w, https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save-120x120.png 120w" sizes="auto, (max-width: 2184px) 100vw, 2184px" /><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>Теперь, руководствуясь описанной выше философией, проименуем сущности, их свойства и методы API.</p><h3 class="wp-block-heading">Сущности</h3><p>Итак, наши сущности, их всего четыре:</p><ul class="wp-block-list"><li>пользователь —&nbsp;<strong><code>user</code></strong>;</li><li>мобильное приложение —&nbsp;<strong><code>app</code></strong>;</li><li>точка —&nbsp;<strong><code>point</code></strong>;</li><li>список точек —&nbsp;<strong><code>pointList</code></strong>.</li></ul><h3 class="wp-block-heading">Свойства</h3><p>Тут посложнее. Будем отталкиваться от сущностей:</p><h4 class="wp-block-heading">Пользователь</h4><p>У пользователя пять свойств:</p><ul class="wp-block-list"><li>номер телефона &#8212; <strong><code>phone</code></strong>;</li><li>внутренний идентификатор &#8212; <strong><code>id</code></strong> (не участвует в обмене данными);</li><li>глобальный идентификатор &#8212; <strong><code>guid</code></strong>;</li><li>секретный ключ &#8212; <strong><code>secretKey</code></strong>;</li><li>дата и время регистрации &#8212; <strong><code>regTime</code></strong>.</li></ul><h4 class="wp-block-heading">Мобильное приложение</h4><p>Здесь всего три свойства:</p><ul class="wp-block-list"><li>версия &#8212; <strong><code>version</code></strong>;</li><li>идентификатор устройства &#8212; <strong><code>deviceId</code></strong>;</li><li>платформа &#8212; <strong><code>platform</code></strong>.</li></ul><h4 class="wp-block-heading">Точка</h4><p>У точки, как и у пользователя, пять свойств, но три из них сложные:</p><ul class="wp-block-list"><li>внутренний идентификатор &#8212; <code><strong>id</strong> </code>(не участвует в обмене данными);</li><li>дата и время &#8212; <strong><code>dateTime</code></strong>;</li><li>координаты &#8212; <strong><code>coords</code></strong>, которые состоят из двух параметров:<ul class="wp-block-list"><li>долгота &#8212; <strong><code>long</code></strong>;</li><li>широта &#8212; <strong><code>lat</code></strong>;</li></ul></li><li>миниатюра изображения &#8212; <strong><code>thumb</code></strong>, состоящая также из двух параметров:<ul class="wp-block-list"><li>ссылка &#8212; <strong><code>url</code></strong>;</li><li>хэш &#8212; <strong><code>hash</code></strong>;</li></ul></li><li>полноразмерное изображение &#8212; <strong><code>picture</code></strong>, аналогично предыдущему свойству:<ul class="wp-block-list"><li>ссылка &#8212; <strong><code>url</code></strong>;</li><li>хэш &#8212; <strong><code>hash</code></strong>.</li></ul></li></ul><p>Те, кто помнит, как мы проектировали кэширование, понимает, зачем нужны такие сложности с последними двумя свойствами.</p><h4 class="wp-block-heading">Список точек</h4><p>У списка всего два свойства, используемых для адаптации под возможности конкретного девайса:</p><ul class="wp-block-list"><li>отступ &#8212; <strong><code>offset</code></strong>;</li><li>область видимости &#8212; <strong><code>scope</code></strong>.</li></ul><h3 class="wp-block-heading">Методы API</h3><p>Методов у нас всего три:</p><ul class="wp-block-list"><li>регистрация &#8212; <strong><code>registration</code></strong>;</li><li>подтверждение номера телефона &#8212; <strong><code>confirm</code></strong>;</li><li>получение списка точек &#8212; <strong><code>getPoints</code></strong>.</li></ul><h2 class="wp-block-heading">Единая таблица свойств</h2><p>Теперь нам надо определиться с типом данных каждого свойства (я рассказывал про типы в <a href="https://sherer.pro/blog/dizajn-dannyh-chast-4-matchast-osnovy/">четвёртом посте</a> цикла про дизайн данных). Здесь всё просто: выбираем наиболее подходящий тип и не забываем поглядывать в философию нашего API:</p><figure class="wp-block-table"><table><thead><tr><th><strong>Название параметра</strong></th><th><strong>Тип данных</strong></th><th><strong>Пример</strong></th></tr></thead><tbody><tr><td><code>user.phone</code></td><td><code>integer</code></td><td><code>79554447788</code></td></tr><tr><td><code>user.id</code></td><td><code>integer</code></td><td><code>3</code></td></tr><tr><td><code>user.guid</code></td><td><code>string</code></td><td><code>c0deaca4-db8a-4178-8863-eaf2494833b9</code></td></tr><tr><td><code>user.secretKey</code></td><td><code>string</code></td><td><code>4af0744c305991c098753117a6a19690</code></td></tr><tr><td><code>user.regTime</code></td><td><code>string</code></td><td><code>2019-06-09T16:28:19-03</code></td></tr><tr><td><code>app.version</code></td><td><code>string</code></td><td><code>1.0.1</code></td></tr><tr><td><code>app.deviceId</code></td><td><code>string</code></td><td><code>2fc4b5912826ad1</code></td></tr><tr><td><code>app.platform</code></td><td><code>string</code></td><td><code>iOS</code></td></tr><tr><td><code>point.id</code></td><td><code>integer</code></td><td><code>32</code></td></tr><tr><td><code>point.dateTime</code></td><td><code>string</code></td><td><code>2019-09-12T19:05:12-03</code></td></tr><tr><td><code>point.coords.long</code></td><td><code>integer</code></td><td><code>59.5194488</code></td></tr><tr><td><code>point.coords.lat</code></td><td><code>integer</code></td><td><code>150.4879161</code></td></tr><tr><td><code>point.thumb.url</code></td><td><code>string</code></td><td><code>/thumbs/uat12ia.jpg</code></td></tr><tr><td><code>point.thumb.hash</code></td><td><code>string</code></td><td><code>05991c09f0744a4c38756903117a6a19</code></td></tr><tr><td><code>point.picture.url</code></td><td><code>string</code></td><td><code>/picture/hrt6q7.jpg</code></td></tr><tr><td><code>point.picture.hash</code></td><td><code>string</code></td><td><code>305991c094af0744c876a1969053117a</code></td></tr><tr><td><code>pointList.offset</code></td><td><code>integer</code></td><td><code>20</code></td></tr><tr><td><code>pointList.scope</code></td><td><code>integer</code></td><td><code>60</code></td></tr></tbody></table></figure><p>В общем-то, такой таблицы нам достаточно для того, чтобы приступить к описанию самого обмена данными. Однако есть еще пара нюансов, на которые я хотел бы обратить внимание.</p><h2 class="wp-block-heading">Типы указания метода</h2><p>В философии выше указано, что одним из обязательных параметров запроса является его тип. Так мы однозначно говорим серверу, что нужно сделать с данными, которые он получил (например, если этот параметр &#8212; <strong><code>registration</code></strong>, сервер попробует на основании остальных параметров зарегистрировать пользователя, отправить ему СМС и так далее).</p><p>Однако описанное &#8212; лишь один из способов указать серверу на конкретный набор действий. В современной разработке чаще всего используется два варианта:</p><ol class="wp-block-list"><li>Указание типа запроса <strong>в теле самого запроса</strong> (параметром, наш вариант).</li><li>Указание типа запроса <strong>в URL</strong>, по которому идёт обращение.</li></ol><p>Если с первым всё более или менее понятно (в нашем случае параметр <strong><code>dt_request </code></strong>может равен либо <strong><code>registration</code></strong>, либо <strong><code>confirm</code></strong>, либо <strong><code>getPoints</code></strong>), то во втором варианте мы в запросах не указываем <code><strong>dt_request</strong> </code>вообще, передавая только параметры, нужные серверу для обработки информации. Здесь клиент (мобильное приложение или сайт) будут добавлять к основному URL конкретный адрес, указывающий на тип запроса. Например:</p><ul class="wp-block-list"><li>запросы с <strong>регистрацией </strong>будут прилетать на sitename.ru/api/v1/<strong>registration/</strong>;</li><li>подтверждение номера &#8212; на sitename.ru/api/v1/<strong>confirm/</strong>;</li><li>а для получения точек нужно будет постучаться на sitename.ru/api/v1/<strong>get-points/</strong>.</li></ul><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Вне зависимости от того, какой вы выбрали вариант, я крайне рекомендую именно такой порядок формирования URL вашего API &#8212; с указанием версии. Проще будет поддерживать.</p></blockquote><p>Тут, в общем-то, всё. Каких-то особенных преимуществ нет ни у одного из вариантов (хотя кто-то говорит, что второй более наглядный; фиг знает, я люблю первый).</p><h2 class="wp-block-heading">Форматы передачи</h2><p>Еще одним аспектом является формат передаваемых сообщений (я вкратце об этом писал в <a href="https://sherer.pro/blog/dizajn-dannyh-chast-3-menjaemsja/">третьей части</a> цикла про дизайн данных). Форматов лютая тьма, но самыми популярными на сегодняшний день являются <a rel="noreferrer noopener" href="https://developer.mozilla.org/ru/docs/%D0%A1%D0%BB%D0%BE%D0%B2%D0%B0%D1%80%D1%8C/JSON" target="_blank">JSON</a> и <a rel="noreferrer noopener" href="https://developer.mozilla.org/ru/docs/%D0%A1%D0%BB%D0%BE%D0%B2%D0%B0%D1%80%D1%8C/XML" target="_blank">XML</a> (хотя последний &#8212; это целый язык разметки, а не просто формат).</p><p>Если упростить, то в данном контексте формат &#8212; это то, как именно структурируются данные: как указываются параметры, а как &#8212; значения этих параметров.</p><p>Вот пример простейшего запроса в XML:</p><pre class="wp-block-code"><code><request&gt;
    <dt_request&gt;registration</dt_request&gt;
    <phone&gt;79558887722</phone&gt;
</request&gt;</code></pre><p>А вот &#8212; он же, но в JSON:</p><pre class="wp-block-code"><code>{
    "dt_request":"registration",
    "phone":79558887722
}</code></pre><p>Я стараюсь использовать JSON везде, где это не противоречит здравому смыслу &#8212; он проще и нагляднее (когда твои запросы не становятся совсем уж монструозными). Однако у XML есть некоторые преимущества: например, его проще валидировать в автоматическом режиме.</p><h2 class="wp-block-heading">HTTP-методы</h2><p>Ну и напоследок я расскажу о различиях между <a href="https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/POST" target="_blank" rel="noreferrer noopener">POST</a> и <a href="https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/GET" target="_blank" rel="noreferrer noopener">GET</a>-запросами. Вообще, с терминологией в IT так себе. Есть методы у <strong>HTTP-запросов </strong>(как раз эти вот <strong>POST </strong>и <strong>GET</strong>), а есть методы у конкретного API (в нашем случае, например, <strong><code>registration</code></strong>, <strong><code>confirm</code> </strong>и <strong><code>getPoints</code></strong>). Тут главное не перепутать.</p><p>Если совсем упростить, то POST содержит параметры в теле запроса (вон примеры чуть выше), тогда как GET &#8212; в URL (с помощью знака вопроса и амперсандов).</p><p>Вот пример GET-запроса:</p><pre class="wp-block-code"><code>sitename.ru/api/v1/?dt_request=registration&amp;phone=79558887722</code></pre><p>Параметры в GET начинаются после знака вопроса (<strong>?</strong>) и разделяются амперсандами (<strong>&amp;</strong>): <code>dt_request</code> и <code>phone</code>. Хороший и наглядный пример реализации API через GET можно глянуть на моём <a rel="noreferrer noopener" href="https://fish-text.ru/api" target="_blank">сайте рыбатекста</a>.</p><p>Просто, да? Нет. Потому что помимо GET и POST есть еще <a rel="noreferrer noopener" href="https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/PUT" target="_blank">PUT</a>, <a rel="noreferrer noopener" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE" target="_blank">DELETE</a>, <a rel="noreferrer noopener" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/CONNECT" target="_blank">CONNECT</a> и ещё <a rel="noreferrer noopener" href="https://developer.mozilla.org/ru/docs/Web/HTTP/Methods" target="_blank">некоторое количество</a> методов. Но истинное их предназначение ныне используется довольно редко. Указанных POST и GET чаще всего хватает за глаза.</p><h2 class="wp-block-heading">Итого</h2><p>Если кто-то ожидал, что в этой статье я представлю полное описание API нашего мегакрутого приложения про тюленей, то &#8212; сорри &#8212; нет. Это мы с вами сделаем в следующей, последней статье цикла. Не переключайтесь:</p><ul class="wp-block-list"><li><a href="https://sherer.pro/blog/dizajn-dannyh-chast-7-prototipirovanie/">Дизайн данных (часть 7). Прототипирование.</a><em><a href="https://sherer.pro/blog/dizajn-dannyh-chast-7-prototipirovanie/"></a></em></li></ul><p>Запись <a href="https://sherer.pro/blog/dizajn-dannyh-chast-6-matchast-api/">Дизайн данных (часть 6). Матчасть: API.</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded></item><item><title>Дизайн данных (часть 5). Матчасть: базы данных.</title><link>https://sherer.pro/blog/dizajn-dannyh-chast-5-matchast-bazy-dannyh/</link><comments>https://sherer.pro/blog/dizajn-dannyh-chast-5-matchast-bazy-dannyh/#comments</comments><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Sat, 18 May 2019 15:32:44 +0000</pubDate><category><![CDATA[Разработка]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[гайд]]></category><category><![CDATA[дизайн данных]]></category><guid isPermaLink="false">https://sherer.pro/?p=1286</guid><description><![CDATA[<p>Краткое погружение в хранение информации: связи данных, какие типы БД бывают и как базы визуализируются.</p><p>Запись <a href="https://sherer.pro/blog/dizajn-dannyh-chast-5-matchast-bazy-dannyh/">Дизайн данных (часть 5). Матчасть: базы данных.</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p>Те, кто читает мой цикл про дизайн данных регулярно, уже наверняка приметил, что каждую статью я начинаю с того, что советую сперва ознакомиться с первыми частями. Делаю я это по понятным причинам: если сразу залезть в дебри, можно очень быстро растерять мотивацию, ибо нифига не понятно.</p><p>В прошлый раз мы говорили про самый базис матчасти: хранение, передачу информации, типы данных. Так вот эта статья будет посвящена именно хранению информации в БД, а следующая &#8212; передаче данных по API.</p><p>Мы не будем упарываться и съедать мозг сложными техническими историями &#8212; чаще всего продуктовому дизайнеру достаточно лишь верхнеуровневого понимания работы и различий между базами данных. </p><h2 class="wp-block-heading">Зачем это дизайнеру</h2><p>Затем же, зачем и остальной data design. Понимая, каким образом данные могут храниться и соотноситься между собой, грамотный продуктовый дизайнер может выстроить определенную модель отношений между сущностями в проекте. Стабилизация дальнейшей разработки стоит того, чтобы в самом начале потратить немного времени на выбор, например, подходящего типа БД.</p><p>При этом я вовсе не призываю всех дизайнеров бросать фигму и мчаться проектировать базы данных. Чаще всего, этим должен заниматься более технически подкованный человек (архитектор или даже специальный &#171;дизайнер баз данных&#187; &#8212; такой тоже есть). Однако понимание основ такого проектирования позволит существенно упростить работу этого самого архитектора. А заодно сделать более качественно проработанный продукт.</p><h2 class="wp-block-heading">Немного вводных</h2><p>Для начала &#8212; давайте вкратце пройдёмся по терминологии. </p><h3 class="wp-block-heading">СУБД</h3><p>Как я уже рассказывал в предыдущей статье, для управления базами данных требуется определённый софт. Без него БД &#8212; это просто файлы. Которые, к тому же, нельзя открыть обычными программами, вроде блокнота (чаще всего). Этот софт, необходимый для манипуляций с базами данных, называется СУБД &#8212; Системы Управления Базами Данных. Они позволяют создавать базы, структурировать, изменять/удалять/добавлять данные, защищать их и так далее.</p><h3 class="wp-block-heading">Связи</h3><p>Данные в БД должны быть связаны друг с другом. В основном, используются три вида таких связей (их ещё называют &#171;кардинальность&#187;):</p><ul class="wp-block-list"><li>связь &#171;один к одному&#187;;</li><li>связь &#171;один ко многим&#187;;</li><li>связь &#171;многие ко многим&#187;.</li></ul><p>В чем их различие, понятно из названия. Но я всё равно немного расскажу об этом.</p><h4 class="wp-block-heading">Один к одному (1:1)</h4><p>Этот тип связи встречается довольно редко.</p><p>При связи &#171;один к одному&#187; объект из одной части БД может быть связаны только с одним объектом из другой части. Сложно, поэтому покажу на примере.</p><p>Классический пример связи &#171;один к одному&#187; &#8212; это серия и номер паспорта. Здесь каждый номер привязан к серии и наоборот. Серия паспорта без номера бессмысленна, равно как и номер без серии.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d433da&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d433da" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="522" 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/one-to-one.png" alt="" class="wp-image-3873" srcset="https://sherer.pro/content/uploads/2023/12/one-to-one.png 2096w, https://sherer.pro/content/uploads/2023/12/one-to-one-1048x261.png 1048w, https://sherer.pro/content/uploads/2023/12/one-to-one-768x191.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">Связь &#171;один к одному&#187;</figcaption></figure><p>Иногда оказывается, что связь 1:1 — это просто ошибка проектирования. В нашем примере куда правильнее было бы сделать элемент &#171;паспорт&#187; со свойствами &#171;серия&#187; и &#171;номер&#187;. А вот, например, связь «человек» и «паспорт» — хороший пример адекватного решения «один ко одному».</p><p><strong>Где применяется:</strong></p><ul class="wp-block-list"><li>Когда данные логически разделены, но принадлежат одной сущности.</li><li>Когда часть данных вынесена в отдельную таблицу по соображениям безопасности или производительности.</li></ul><p><strong>Как реализуется в БД:</strong></p><ul class="wp-block-list"><li>Через внешний ключ, который является <strong>уникальным</strong> в обеих таблицах.</li><li>Иногда — просто объединением таблиц, если нет причин их разделять.</li></ul><h4 class="wp-block-heading">Один ко многим (1:N)</h4><p>В этом случае один объект может быть связан с одним или несколькими объектами в другой части БД. Но эти &#171;вторые&#187; объекты могут связаны только с одним &#171;первым&#187; объектом. Давайте снова на примере.</p><p>Есть база данных торгового предприятия. В базе есть клиенты и их заказы. Так вот у одного клиента может быть несколько заказов, тогда как заказ всегда относится только к одному клиенту.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d437b7&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d437b7" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="682" 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/one-to-many.png" alt="" class="wp-image-3874" srcset="https://sherer.pro/content/uploads/2023/12/one-to-many.png 2096w, https://sherer.pro/content/uploads/2023/12/one-to-many-1048x341.png 1048w, https://sherer.pro/content/uploads/2023/12/one-to-many-768x250.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">Связь &#171;один ко многим&#187;</figcaption></figure><p><strong>Где применяется:</strong></p><ul class="wp-block-list"><li>Самый частый тип связи в реальных моделях.</li><li>Используется, когда есть чёткая «главная» и «зависимая» сущность.</li></ul><p><strong>Как реализуется в БД:</strong></p><ul class="wp-block-list"><li>В таблице «многих» хранится внешний ключ на «одного».</li><li>Например: в таблице <code>ordres</code> есть колонка <code>client_id</code>, ссылающаяся на таблицу <code>clients</code>.</li></ul><h4 class="wp-block-heading">Многие ко многим (M:N)</h4><p>Этот тип связи походит, когда связи могут &#171;перекрещиваться&#187; &#8212; когда один объект может иметь отношение к нескольким объектам из другой части БД, но и эти &#171;вторые&#187; объекты могут относиться к нескольким &#171;первым&#187; объектам.</p><p>Хороший пример &#8212; кино и актёры. В одном фильме могут сниматься несколько актёров (множественная связь &#171;фильм-актёр&#187;), но и у одного актёра может быть несколько фильмов, в которых он снимался (множественная связь &#171;актёр-фильм&#187;).</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d43b56&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d43b56" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="682" 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/many-to-many.png" alt="" class="wp-image-3875" srcset="https://sherer.pro/content/uploads/2023/12/many-to-many.png 2096w, https://sherer.pro/content/uploads/2023/12/many-to-many-1048x341.png 1048w, https://sherer.pro/content/uploads/2023/12/many-to-many-768x250.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">Связь &#171;многие ко многим&#187;</figcaption></figure><p>Такой тип связи очень популярен в реляционных БД, о которых мы поговорим ниже.</p><p><strong>Где применяется:</strong></p><ul class="wp-block-list"><li>Когда обе стороны равноправны и могут иметь множество связей друг с другом.</li></ul><p><strong>Как реализуется в БД:</strong></p><ul class="wp-block-list"><li>Через <strong>промежуточную таблицу</strong>, которая хранит пары связей.</li><li>Например: таблица <code>actors_films</code> с полями <code>actor_id</code> и <code>film_id</code>.</li></ul><h2 class="wp-block-heading">Виды баз данных</h2><p>Все БД можно очень чётко разделить на виды &#8212; в зависимости от модели данных, которую они используют.</p><h3 class="wp-block-heading">Иерархическая БД</h3><p>В иерархической БД данные хранятся, как папки на компьютере: всегда есть родительские элементы, а есть дочерние. Этот вид является самым &#171;древним&#187; &#8212; первые БД были преимущественно именно иерархическими. В современном мире они применяются редко, разве что для очень специфических задач.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d43f3c&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d43f3c" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="992" 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/hierarchical-database.png" alt="" class="wp-image-3876" srcset="https://sherer.pro/content/uploads/2023/12/hierarchical-database.png 2096w, https://sherer.pro/content/uploads/2023/12/hierarchical-database-1048x496.png 1048w, https://sherer.pro/content/uploads/2023/12/hierarchical-database-768x363.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; &#8212; а это очень часто требуется в проектировании. Отчасти поэтому иерархический вид БД не особенно популярен.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d441f7&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d441f7" class="wp-block-image wp-lightbox-container"><img loading="lazy" decoding="async" width="1600" height="612" 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/2019/05/windows-registry.jpg" alt="Пример иерархической БД - реестр Windows" class="wp-image-1389" srcset="https://sherer.pro/content/uploads/2019/05/windows-registry.jpg 1600w, https://sherer.pro/content/uploads/2019/05/windows-registry-768x294.jpg 768w, https://sherer.pro/content/uploads/2019/05/windows-registry-1048x401.jpg 1048w" sizes="auto, (max-width: 1600px) 100vw, 1600px" /><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">Классический пример иерархической БД &#8212; реестр Windows. </figcaption></figure><p>Иерархические БД следует использовать только в том случае, когда данные в вашем проекте всегда подчиняются строгой иерархии, а неожиданных связей между ними не возникнет даже при развитии системы.</p><p>Пример СУБД для иерархической базы данных &#8212; <a href="https://ru.wikipedia.org/wiki/IMS_(%D0%A1%D0%A3%D0%91%D0%94)" target="_blank" rel="noreferrer noopener" aria-label="IMS (откроется в новой вкладке)">IMS</a> от IBM.</p><h3 class="wp-block-heading">Сетевая БД</h3><p>Сетевая база данных &#8212; это те же иерархическая, но на стероидах. В ней можно устанавливать какие угодно связи: дочерний объект может обращаться к &#171;предку предка&#187; напрямую, минуя лишние шаги.</p><p>Здесь (обычно) тоже нельзя использовать связи типа &#171;многие ко многим&#187;, но это компенсируется скоростью работы с большим количеством связанных данных.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d44509&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d44509" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="944" 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/network-database.png" alt="" class="wp-image-3877" srcset="https://sherer.pro/content/uploads/2023/12/network-database.png 2096w, https://sherer.pro/content/uploads/2023/12/network-database-1048x472.png 1048w, https://sherer.pro/content/uploads/2023/12/network-database-768x346.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;<a rel="noreferrer noopener" aria-label="графовые (откроется в новой вкладке)" href="https://ru.wikipedia.org/wiki/%D0%93%D1%80%D0%B0%D1%84%D0%BE%D0%B2%D0%B0%D1%8F_%D0%B1%D0%B0%D0%B7%D0%B0_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85" target="_blank">графовые</a>&#187; БД &#8212; разновидность сетевых. Не буду на них останавливаться, если интересно, загуглите сами.</p><p>Пример сетевой графовой СУБД, распространяемой по свободной лицензии &#8212; <a rel="noreferrer noopener" aria-label="OrientDB (откроется в новой вкладке)" href="https://ru.wikipedia.org/wiki/OrientDB" target="_blank">OrientDB</a>.</p><h3 class="wp-block-heading">Реляционная БД</h3><p>Самый распространённый вид баз данных. Особенность реляционных БД в чёткой и понятной структуре информации, представленной в виде двумерных таблиц. В каждой такой таблице есть строки (собственно, объекты данных) и столбцы (свойства этих объектов). При этом столбцы, как правило, подчиняются очень чёткой типизации: конкретный столбец может содержать только один тип данных &#8212; например, строку или число. При этом одинаковых строк (элементов) в таблице не может быть.</p><p>На рисунке ниже &#171;столбцы&#187; представлены &#171;строками&#187; не только для удобства восприятия, но и потому что именно так обычно визуализируются реляционные БД (об этом я расскажу чуть ниже).</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d4481e&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d4481e" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="952" 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/relational-database.png" alt="" class="wp-image-3878" srcset="https://sherer.pro/content/uploads/2023/12/relational-database.png 2096w, https://sherer.pro/content/uploads/2023/12/relational-database-1048x476.png 1048w, https://sherer.pro/content/uploads/2023/12/relational-database-768x349.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>Вот так выглядит реляционная база данных в редакторе. По сути, каждая такая БД &#8212; это просто список тех самых двумерных таблиц:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d44acd&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d44acd" class="wp-block-image wp-lightbox-container"><img loading="lazy" decoding="async" width="1917" height="841" 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/2019/05/relational-database-tables.jpg" alt="Таблицы реляционной БД" class="wp-image-1441" srcset="https://sherer.pro/content/uploads/2019/05/relational-database-tables.jpg 1917w, https://sherer.pro/content/uploads/2019/05/relational-database-tables-768x337.jpg 768w, https://sherer.pro/content/uploads/2019/05/relational-database-tables-1048x460.jpg 1048w" sizes="auto, (max-width: 1917px) 100vw, 1917px" /><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>&#171;meta_id&#187;</em>, <em>&#171;post_id&#187;</em>, <em>&#171;meta_key&#187;</em> и <em>&#171;meta_value&#187;</em> &#8212; это те самые &#171;столбцы&#187;, которые несут в себе свойства элементов:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d44d8b&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d44d8b" class="wp-block-image wp-lightbox-container"><img loading="lazy" decoding="async" width="1600" height="170" 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/2019/05/relational-database-structure.jpg" alt="Структура таблицы реляционной БД" class="wp-image-1440" srcset="https://sherer.pro/content/uploads/2019/05/relational-database-structure.jpg 1600w, https://sherer.pro/content/uploads/2019/05/relational-database-structure-768x82.jpg 768w, https://sherer.pro/content/uploads/2019/05/relational-database-structure-1048x111.jpg 1048w" sizes="auto, (max-width: 1600px) 100vw, 1600px" /><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>И вот, наконец, уже сами данные этой самой таблицы. Здесь строки &#8212; это элементы (объекты данных), а у столбцов <em>&#171;meta_id&#187;</em>, <em>&#171;post_id&#187;</em>, <em>&#171;meta_key&#187;</em> и <em>&#171;meta_value&#187;</em> есть конкретные значения &#8212; свойства этих элементов:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d4501c&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d4501c" class="wp-block-image wp-lightbox-container"><img loading="lazy" decoding="async" width="1172" height="331" 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/2019/05/relational-database-data.jpg" alt="Данные отдельной таблицы реляционной БД" class="wp-image-1443" srcset="https://sherer.pro/content/uploads/2019/05/relational-database-data.jpg 1172w, https://sherer.pro/content/uploads/2019/05/relational-database-data-768x217.jpg 768w, https://sherer.pro/content/uploads/2019/05/relational-database-data-1048x296.jpg 1048w" sizes="auto, (max-width: 1172px) 100vw, 1172px" /><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>Если данные в вашем проекте структурированы, по ним нужен быстрый поиск, то ваш выбор однозначно должен пасть на реляционную БД. Да и вообще, если сомневаетесь &#8212; используйте именно этот вид.</p><p>Сейчас самая популярная реляционная СУБД &#8212; <a rel="noreferrer noopener" aria-label="MySQL (откроется в новой вкладке)" href="https://ru.wikipedia.org/wiki/MySQL" target="_blank">MySQL</a> от Oracle.</p><h3 class="wp-block-heading">Остальные виды</h3><p>На самом деле, существует еще довольно много других видов БД: объектно- или документо-ориентированные, функциональные и разные смеси, вроде объекто-реляционных баз. Но это, чаще всего, диковинки, заточенные под выполнение конкретных, довольно специфических задач. Но если тема вас зацепила, можете погуглить.</p><h2 class="wp-block-heading">Визуализация</h2><p>Результатом проектирования БД должен стать какой-то графический или текстовый объект &#8212; здесь всё понятно. Обычно это схема или несколько таблиц, связанных между собой. Человечество придумало огромное количество способов передать структуру данных, но наибольшее распространение получила так называемая ER-модель (её ещё называют ER-диаграммой).</p><p>По сути, это и есть диаграмма, в которой указаны все элементы, свойства и связи между ними. Стилизованную ER-диаграмму вы можете увидеть на всех миниатюрах к этому циклу статей. Вот она без лишней графики:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d45372&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d45372" class="wp-block-image aligncenter wp-lightbox-container"><img loading="lazy" decoding="async" width="2400" height="1600" 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/2019/05/er-datadesign.jpg" alt="ER-диаграмма" class="wp-image-1448" srcset="https://sherer.pro/content/uploads/2019/05/er-datadesign.jpg 2400w, https://sherer.pro/content/uploads/2019/05/er-datadesign-416x277.jpg 416w, https://sherer.pro/content/uploads/2019/05/er-datadesign-848x564.jpg 848w, https://sherer.pro/content/uploads/2019/05/er-datadesign-768x512.jpg 768w, https://sherer.pro/content/uploads/2019/05/er-datadesign-1048x699.jpg 1048w, https://sherer.pro/content/uploads/2019/05/er-datadesign-832x554.jpg 832w" sizes="auto, (max-width: 2400px) 100vw, 2400px" /><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">Пример ER-диаграммы</figcaption></figure><p>А вот &#8212; настоящая ER-диаграмма (к слову, отнюдь не самая большая):</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d455ba&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d455ba" class="wp-block-image wp-lightbox-container"><img loading="lazy" decoding="async" width="1697" height="1370" 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/2019/05/er-diagram.jpg" alt="ER-диаграмма" class="wp-image-1449" srcset="https://sherer.pro/content/uploads/2019/05/er-diagram.jpg 1697w, https://sherer.pro/content/uploads/2019/05/er-diagram-768x620.jpg 768w, https://sherer.pro/content/uploads/2019/05/er-diagram-1048x846.jpg 1048w" sizes="auto, (max-width: 1697px) 100vw, 1697px" /><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">ER-диаграмма</figcaption></figure><p>Наверное, стоило бы рассказать про ER-модель поподробнее, но мне, признаться, лень создавать еще один материал на эту тему. Нотация описана уже миллион раз и без проблем гуглится.</p><h2 class="wp-block-heading">В заключение</h2><p>Конечно, это только начало. Я многое не рассказал, и не собираюсь &#8212; просторы интернета ломятся от серьезных, вдумчивых статей про базы данных. Но подступаться к ним с нулевого уровня знаний всегда очень сложно. Теперь же вы хотя бы немного погружены в контекст. Хотя бы понимаете, куда копать &#8212; если захотите, конечно.</p><p>Запись <a href="https://sherer.pro/blog/dizajn-dannyh-chast-5-matchast-bazy-dannyh/">Дизайн данных (часть 5). Матчасть: базы данных.</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded><wfw:commentRss>https://sherer.pro/blog/dizajn-dannyh-chast-5-matchast-bazy-dannyh/feed/</wfw:commentRss><slash:comments>2</slash:comments></item><item><title>Дизайн данных (часть 4). Матчасть: основы.</title><link>https://sherer.pro/blog/dizajn-dannyh-chast-4-matchast-osnovy/</link><comments>https://sherer.pro/blog/dizajn-dannyh-chast-4-matchast-osnovy/#comments</comments><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Mon, 18 Mar 2019 14:24:24 +0000</pubDate><category><![CDATA[Разработка]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[гайд]]></category><category><![CDATA[дизайн данных]]></category><guid isPermaLink="false">https://sherer.pro/?p=855</guid><description><![CDATA[<p>Задача этой статьи - дать базис, ввести в терминологию матчасти data design. Чтобы потом каждый из вас мог посоветоваться с техническими специалистами, не испытывая при этом "эффекта вавилонской башни". А то и вообще самостоятельно прогуглить "белое пятно" знаний о проекте.</p><p>Запись <a href="https://sherer.pro/blog/dizajn-dannyh-chast-4-matchast-osnovy/">Дизайн данных (часть 4). Матчасть: основы.</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p>Если ваше знакомство с дизайном данных начинается только сейчас, советую притормозить. Чтобы не сломать мозг и на втором разделе не утратить связь с реальностью, настоятельно рекомендую сперва прочитать первые три статьи цикла.</p><p>Здесь (как и в следующих двух постах) речь пойдёт о самой трэшовой части дизайна данных: о хранении, передаче и типах данных, о работе и визуализации БД, даже о философии API и формировании запросов. В общем, полный фарш. Если честно, редкий продуктовый дизайнер владеет технической составляющей проекта на таком уровне. Более того, чаще всего он и не обязан всё это знать. Но ведь мы хотим быть лучшими из лучших, верно? </p><p>Разумеется, в рамках одной статьи невозможно рассказать всё. Поэтому моя задача сейчас &#8212; дать базис, ввести в терминологию. Чтобы потом каждый из вас мог посоветоваться с техническими специалистами, не испытывая при этом &#171;эффекта вавилонской башни&#187;. А то и вообще самостоятельно прогуглить &#171;белое пятно&#187; знаний. </p><p>Итого, зачем изучать матчасть дизайна данных? Основных причин всего две:</p><ul class="wp-block-list"><li><em>глубокое понимание того, как будет работать ваш продукт;</em></li><li><em>умение общаться с разработчиками на одном языке.</em></li></ul><p>Однако вся соль не в причинах, а в результатах. Знание матчасти позволяет:</p><ul class="wp-block-list"><li><em>создавать куда более качественные и комплексно проработанные продукты;</em></li><li><em>здорово стабилизировать разработку, экономя время и деньги инвесторов;</em></li><li><em>снизить коммуникационные барьеры между дизайном и разработкой;</em></li><li><em>получать больше денег за свою работу (о да, гарантирую).</em></li></ul><p>Если я вас не убедил &#8212; добро пожаловать в комментарии, обсудим. Но сперва попробуйте прочитать статью полностью.</p><p>Плавного погружения, к сожалению, не получится. Будем считать, что предыдущие статьи цикла про дизайн данных &#8212; и есть &#171;предыстория&#187;. Поэтому мне, вероятно, стоит извиниться перед теми, кто хвалил меня за простую подачу материала &#8212; в случае с матчастью подача будет такой же хардкорной, как и сама тема.</p><p>Погнали.</p><h2 class="wp-block-heading">Способы хранения</h2><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Данные хранятся.</p><cite>Кэп<br></cite></blockquote><p>Кэп прав. Абсолютно в любом IT-продукте любая информация должна где-то храниться. И от того, верный ли способ хранения выбран, во многом зависит безопасность продукта и быстродействие интерфейса. Особенно это заметно во всяких админках с огромным количеством сложных графиков и таблиц. </p><p>Если вы помните структуру данных из <a href="https://sherer.pro/blog/dizajn-dannyh-chast-2-kak/">второго поста цикла</a>, то там у нас получилась простейшая разбивка на сервер и клиент. Разумеется, там речь шла о физическом, постоянном хранении информации:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d469a8&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d469a8" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2184" height="2200" 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/data-design-entities-operations-properties-full-save.png" alt="" class="wp-image-3861" srcset="https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save.png 2184w, https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save-1048x1056.png 1048w, https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save-768x774.png 768w, https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save-60x60.png 60w, https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save-120x120.png 120w" sizes="auto, (max-width: 2184px) 100vw, 2184px" /><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">Структура данных приложения<br></figcaption></figure><p>То есть данные в красной области сохранялись на сервере, а в жёлтой &#8212; на клиенте (в нашем случае клиентом было выдуманное мобильное приложение; однако в случае сайта, например, клиентом выступает браузер). На диаграммке видно, что часть данных находится на стыке областей &#8212; то есть они хранятся и на клиенте, и на сервере. </p><p>При этом в обоих случаях (клиент и сервер) способы хранения информации примерно одинаковые. Чаще всего, применяется три типа хранения данных:</p><h3 class="wp-block-heading">БД</h3><p>Базы данных всех мастей. Программы, обычно применяются для записи информации, к которой нужен постоянный и оперативный доступ. Второй случай &#8212; когда данных много и их необходимо структурировать. Информация в БД записывается на диск в виде обычных файлов, как и в следующем варианте, но читать эти файлы умеет только сама БД. Даже в вашем браузере есть собственная локальная база данных, в которую сайт при желании может что-нибудь сохранить.</p><h3 class="wp-block-heading">Файлы</h3><p>Да, обычные файлы. Чаще всего, вообще текстовые. Без проблем читаются любыми программами, умеющими читать текст. Файлы используются, в основном, для хранения статичной информации: вроде логов (например, история действий пользователя в консоли или ошибок работы сервера) или конфигурационных параметров (версия приложения, доступы к БД, URL API и прочее). Еще один пример хранения информации в файлах &#8212; это куки (cookies) в вашем браузере.</p><h3 class="wp-block-heading">Память</h3><p>Та самая, оперативная. Часть данных всегда хранится в памяти приложений (как клиентских, так и серверных). То, как приложение работает с памятью, всегда зависит от языка, на котором написано приложение. Например, <a rel="noreferrer noopener" aria-label="PHP (откроется в новой вкладке)" href="https://ru.wikipedia.org/wiki/PHP" target="_blank">PHP</a> выполняет код только в процессе запроса &#8212; и память там чаще всего нужна только для обработки данных (но есть и исключения). Когда вы вводите пин-код в мобильном приложении, в большинстве случаев он сохраняется именно в памяти &#8212; и потом берется оттуда для подтверждения выполнения важных операций (например, для расшифровки пароля, записанного в БД). В случае с нашим выдуманным приложением про тюленей, данные о точках получаются с сервера и хранятся в памяти всё время сессии (или пока не выгрузятся оттуда специальным механизмом).</p><p>Далее мы будем рассматривать работу БД в деталях, а вот файлов и памяти больше не коснемся совсем. С файлами все просто, а чтобы описать работу памяти, не хватит и десятка таких статей.</p><h2 class="wp-block-heading">Способы обмена</h2><p>Кэп сказал бы, что хранить данные и не передавать их &#8212; странно. Способы обмена данными &#8212; это довольно сложная тема, которую мы затронем лишь вскользь. Вряд ли в работе даже самого матёрого продуктового дизайнера пригодится углублённое понимание различий между TCP и UDP. Однако базовые знания всё равно нужны.</p><p>Давайте попробуем разобраться.</p><h3 class="wp-block-heading">Протоколы</h3><p>В сети всё завязано на протоколах. Если упростить, то протокол &#8212; это набор правил, по которым происходит отправка и приём данных. Если вы занимаетесь дизайном данных, понимание различий между протоколами необходимо хотя бы на самом верхнем уровне. Наиболее часто используемые сетевые протоколы:</p><ul class="wp-block-list"><li><strong>HTTP</strong> &#8212; де-факто стандарт работы всех этих сайтов, мобильных приложений и прочего. Имеет две версии: просто <strong>HTTP</strong> и <strong>HTTP/2</strong>. У последнего приличное количество нововведений &#8212; например, параллельное выполнение нескольких запросов к серверу. <strong>HTTPS</strong> (наверняка слышали) является просто расширением <strong>HTTP</strong> для безопасной передачи данных. Всё, что мы будем обсуждать в этой статье относительно этой самой передачи, будет работать именно с <strong>HTTP</strong>.</li><li><strong>FTP</strong> используется исключительно для передачи файлов. Когда админ что-то заливает на сервер, он часто делает это именно по <strong>FTP</strong> (или по <strong>FTPS</strong> &#8212; расширению <strong>FTP</strong>, заточенным на безопасность).</li><li><strong>SSH</strong> &#8212; тоже протокол, но используется для доступа к серверу. Сам по себе является защищённым, позволяет выполнять команды и вообще управлять операционной системой на удалённой машине. Ваш админ 100% юзает <strong>SSH</strong>.</li><li><strong>SMTP</strong>, <strong>POP3</strong> и <strong>IMAP</strong> &#8212; протоколы получения и отправки электропочты. Мы вообще о них не будем говорить. Гляньте в свой почтовый клиент, там вы найдёте именно их.</li></ul><p>Особенно редкие или сложные случаи, а также всякие надстройки, специализированные протоколы и пакеты протоколов, мы рассматривать не будем. Если интересно, загуглите TCP/IP, SOAP, TELNET.</p><h3 class="wp-block-heading">Форматы и структуры</h3><p>В предыдущих статьях мы уже рассматривали, что такое API. По сути, это заранее описанные правила обмена данными между компонентами системы, где указываются формат и структура передачи и получения данных.</p><p>Способов структурирования обмена данными лютая тьма. Но в этом цикле про data design мы говорим преимущественно про мобильную и веб-разработку &#8212; а в ней почти всегда используется именно API. Чуть дальше я расскажу об этом подробнее.</p><h3 class="wp-block-heading">Запросы: общая схема</h3><p>Чтобы у вас не сформировалось впечатление, будто весь веб работает исключительно на апишках, разъясню один нюанс. Представьте, что у вас есть сайт. Он может работать по двум схемам: делать запросы к серверу последовательно, по мере загрузки (просмотра) страницы или перехода пользователя от блока к блоку; или же грузить всю страницу сразу, за один запрос. Зависит это, конечно, от технологии, которая была выбрана при реализации, &#8212; но выбор ее, в свою очередь, уже зависит от бизнес-требований и, собственно, дизайна данных. Например, gmail.com используется первый вариант, а medium.com &#8212; второй.</p><p>Так вот во втором случае использовать API не нужно. Весь контент грузится сразу, за один присест. Перешли к новому посту &#8212; страница обновилась, выполнился новый запрос. А вот в случае со SPA (Single Page Application, коим является тот же gmail) &#8212; последовательно выполняется множество запросов, в зависимости от действий пользователя. Часто второй способ (medium.com) называют <em>синхронной </em>передачей данных, а первый (gmail.com) &#8212; <em>асинхронной</em>.</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d46efc&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d46efc" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="722" 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/requests.png" alt="" class="wp-image-3870" srcset="https://sherer.pro/content/uploads/2023/12/requests.png 2096w, https://sherer.pro/content/uploads/2023/12/requests-1048x361.png 1048w, https://sherer.pro/content/uploads/2023/12/requests-768x265.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>При этом часто встречается, что эти два способа комбинируются. Например, вы <em>синхронно </em>загрузили страницу админки, на которой графики грузятся <em>асинхронно</em> &#8212; и перестраиваются по вашему требованию, не перезагружая страницу. При грамотном подходе такие графики грузятся именно по API, тогда как сама страница &#8212; нет. </p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d47198&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d47198" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="1236" 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/example-asynch-page.png" alt="" class="wp-image-3871" srcset="https://sherer.pro/content/uploads/2023/12/example-asynch-page.png 2096w, https://sherer.pro/content/uploads/2023/12/example-asynch-page-1048x618.png 1048w, https://sherer.pro/content/uploads/2023/12/example-asynch-page-768x453.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>Большинство сайтов не работает на основе API &#8212; банально потому что так проще и дешевле. А вот большинство мобильных приложений &#8212; наоборот, целиком построены на взаимодействии с сервером посредством именно API. Продиктовано это, в первую очередь, технологиями. Например, тот же PHP может совмещать в себе логику и представление &#8212; то есть в одном файле на сервере производить манипуляции с данными, тут же превращать это в HTML и отдавать браузеру (хотя, признаться, это не очень хорошая практика). В случае с мобильным приложением так не получится: всё представление целиком лежит на клиенте, а логика ограничена только манипуляциями с информацией, полученной от сервера.</p><p>Конечно, частенько встречаются исключения. Если эта тема вам интересна, начните с изучения <a rel="noreferrer noopener" href="https://ru.wikipedia.org/wiki/Model-View-Controller" target="_blank">MVC</a> и аналогов. </p><h3 class="wp-block-heading">Запросы: реальность</h3><p>В вебе есть еще один нюанс. Даже в случае классической схемы (одна страница &#8212; один запрос) на самом деле страница всё равно обращается к серверу несколько раз. После получения документа (основного запроса) браузер начинает подтягивать файлы стилей, JavaScript, картинки и тп, указанные в этом документе. </p><p>То есть запросы веб-страницы делятся на несколько типов. Вот основные:</p><ul class="wp-block-list"><li><strong>document</strong> &#8212; основной запрос, в ходе которого получается разметка страницы, а также указание на то, какие еще файлы нужно получить и запросы выполнить;</li><li><strong>stylesheet</strong> &#8212; таблицы стилей (CSS), которые отвечают за внешний вид элементов на странице;</li><li><strong>script</strong> или <strong>javascript</strong> &#8212; файлы JavaScript, регулирующие логику страницы (чаще всего именно они инициируют дальнейшую асинхронную загрузку);</li><li><strong>jpeg</strong> или <strong>png</strong> или <strong>gif</strong> или <strong>svg+xml</strong> и прочие &#8212; изображения, растровые и векторные;</li><li><strong>font</strong> &#8212; файлы со шрифтами, которые используются на странице;</li><li><strong>text/html</strong> &#8212; собственно, HTML, который потом может быть встроен в разметку;</li><li><strong>xhr</strong> &#8212; асинхронные запросы, те самые, которые обращаются к серверу, не требуя перезагрузки страницы.</li></ul><p></p><p>Например, этот сайт не использует API, его страницы грузятся <em>синхронно</em> &#8212; что не мешает ему создавать более тридцати запросов к серверу во время просмотра страницы:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d4756e&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d4756e" class="wp-block-image size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="1600" height="790" 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/2019/03/http-requests.jpg" alt="HTTP-запросы" class="wp-image-1315" srcset="https://sherer.pro/content/uploads/2019/03/http-requests.jpg 1600w, https://sherer.pro/content/uploads/2019/03/http-requests-768x379.jpg 768w, https://sherer.pro/content/uploads/2019/03/http-requests-1048x517.jpg 1048w" sizes="auto, (max-width: 1600px) 100vw, 1600px" /><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">HTTP-запросы</figcaption></figure><p>Понимаю, что вот так сразу может это может показаться сложным. На самом деле, все просто. Есть <em>синхронные </em>запросы к документам (тип <strong>document</strong>), которые требуют перезагрузки страницы, а есть <em>асинхронные</em> (тип <strong>xhr</strong>), которые перезагрузки не требуют. И есть все остальные (картинки, стили, скрипты, шрифты и тп), которые выполняются в зависимости от того, какой результат вернули <strong>document</strong> и <strong>xhr</strong>.</p><h2 class="wp-block-heading"> Типы данных</h2><p>Весь data design состоит из &#171;атомов&#187; &#8212; самых базовых единиц информации. Это самый глубокий слой, до которого вам предстоит дойти: научиться не только описывать логику, конкретные запросы и параметры, но и понимать, какими свойствами обладает информация, как её нужно валидировать. Одинаковые с точки зрения логики данные могут быть абсолютно различными в глазах разработчиков. К примеру: обычная цифра 5 является <em>числом</em> ровно до тех пор, пока вы не обернете её в кавычки. После этого она уже становится <em>строкой</em>. А если вы описываете структуру API, то такую ошибку допустить проще простого.</p><p>Любые данные делятся на типы: начиная от переменных в коде и заканчивая параметрами, передаваемыми по API. Я постарался собрать самые простые и наиболее часто встречающиеся типы в одном месте &#8212; однако важно понимать, что типизация очень сильно зависит от конкретного языка или платформы. Например, для обычных текстовых строк в JavaScript предусмотрен один тип, а в MySQL &#8212; целых шесть. Поэтому перед началом работы крайне рекомендую проконсультироваться с разработкой или тщательно прогуглить предметную область.</p><h3 class="wp-block-heading">Строки</h3><p>Их еще называют символьными типами. <em>Строки </em>содержат обычный текст постоянной или переменной длины. Например, как я уже упоминал, в MySQL шесть типов данных, которые могут содержать текст разной длины. Обычно строки оборачиваются в одинарные или двойные кавычки.</p><p>Наиболее употребимые обозначения строк: <strong>string</strong>, <strong>varchar</strong>, <strong>text</strong>.</p><p>Пример сроки:</p><pre class="wp-block-preformatted">"Дизайнил-дизайнил, да не выдезайнил"</pre><h3 class="wp-block-heading">Числа</h3><p>Чаще всего делятся на целые и с плавающей точкой. Например, для обозначения целых чисел в разных языках используются <strong>number</strong>, <strong>int</strong>, <strong>integer</strong>. Тип чисел с плавающей точкой чаще всего называется <strong>float</strong> или <strong>double</strong>.</p><p>Пример целого числа:</p><pre class="wp-block-preformatted">79</pre><p><br>Пример числа с плавающей точкой:</p><pre class="wp-block-preformatted">34.98</pre><h3 class="wp-block-heading">Дата и время</h3><p>Чаще всего используется именно в базах данных. В языках программирования зачастую (да и в том же API) представлен или числом, или строкой. Я объединил здесь дату и время, но они могут быть представлены и по отдельности. Форматы их довольно сильно отличаются, приведу примеры из MySQL.</p><p>Пример даты, тип <strong>date</strong>:</p><pre class="wp-block-preformatted">2019-03-19</pre><p><br>Пример времени, тип <strong>time</strong>:</p><pre class="wp-block-preformatted">23:48:37</pre><p><br>Пример даты и времени, тип <strong>datetime</strong>:</p><pre class="wp-block-preformatted">2019-03-19 23:48:37</pre><p><br>Пример числовой записи даты и времени (количество секунд, прошедшее с 00:00:00 UTC 1 января, 1970 года), тип <strong>timestamp</strong>:</p><pre class="wp-block-preformatted">1553028517000 </pre><h3 class="wp-block-heading">Логический тип</h3><p>Самый простой тип, используемый в языках программирования. Может содержать только два значения: правду (<em>true</em>) или ложь (<em>false</em>). При этом очень часто <em>true</em> может быть заменено единицей, а <em>false</em> &#8212; нулём. Например, тот же MySQL не поддерживает логического типа в чистом виде, его тут заменяет <em>tinyint</em> (самое маленькое число), принимающий значение 0 или 1. Чаще всего для обозначения логического типа данных используются обозначения <strong>bool</strong> или <strong>boolean</strong>.</p><p>Пример булева значения:</p><pre class="wp-block-preformatted">true</pre><h3 class="wp-block-heading">Массив</h3><p>В отличии от остальных, <em>массив</em> является сложным, <em>составным</em> типом. Мы рассматривали его, когда в предыдущих статьях говорили о координатах точек или параметрах изображений в нашем прекрасном приложении про тюленей. Массив включает в себя список значений или список наборов &#171;<em>ключ: значение&#187;</em>.</p><p>Пример массива:</p><pre class="wp-block-preformatted">["яблоко", "ананас", "груша"]<br></pre><p><br>И еще, более сложный (иногда такой называется <em>объектом</em> или <em>словарём</em> &#8212; в зависимости от языка и контекста).</p><pre class="wp-block-preformatted">{<br>   name: "Василий",<br>   surname: "Иванов",<br>   year: 1980<br>}  </pre><h2 class="wp-block-heading">Выдохнули</h2><p>На этом вводная в матчасть закончена. Дальше будем говорить про БД, API и прототипирование всего этого дела. Если, конечно, у вас хватит сил &#8212; я очень хорошо понимаю, что для дизайнеров, пришедших в профессию из графики, всё это реально тёмный лес. Что ж, давайте его освещать.</p><p>Запись <a href="https://sherer.pro/blog/dizajn-dannyh-chast-4-matchast-osnovy/">Дизайн данных (часть 4). Матчасть: основы.</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded><wfw:commentRss>https://sherer.pro/blog/dizajn-dannyh-chast-4-matchast-osnovy/feed/</wfw:commentRss><slash:comments>3</slash:comments></item><item><title>Дизайн данных (часть 3). Меняемся?</title><link>https://sherer.pro/blog/dizajn-dannyh-chast-3-menjaemsja/</link><comments>https://sherer.pro/blog/dizajn-dannyh-chast-3-menjaemsja/#comments</comments><dc:creator><![CDATA[Павел Шерер]]></dc:creator><pubDate>Sat, 19 Jan 2019 09:10:12 +0000</pubDate><category><![CDATA[Разработка]]></category><category><![CDATA[Технический дизайн]]></category><category><![CDATA[гайд]]></category><category><![CDATA[дизайн данных]]></category><guid isPermaLink="false">https://sherer.pro/?p=1016</guid><description><![CDATA[<p>Третий пост, посвященный дизайну данных. Что такое API, как и зачем проектировать обмен данными между компонентами системы.</p><p>Запись <a href="https://sherer.pro/blog/dizajn-dannyh-chast-3-menjaemsja/">Дизайн данных (часть 3). Меняемся?</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></description><content:encoded><![CDATA[<p>Вы читаете третью статью из цикла &#171;дизайн данных&#187;, она посвящена обмену данными между компонентами системы. Чтобы вообще понять, что здесь происходит, я рекомендую ознакомиться с первыми двумя.</p><h2 class="wp-block-heading">Освежаем память</h2><p>Итак, в прошлом посте у нас появилось великолепное приложение, которое позволяет отслеживать миграцию полосатых тюленей на берегах Охотского моря. Внутри у нас есть регистрация/аутентификация пользователей, список точек, кэширование изображений.</p><p>Среди архитектурных компонентов мы рассматриваем только мобильное приложение и сервер (middleware). Нам не важно, откуда берутся данные о миграции (админка ли это, внешняя интеграция &#8212; плевать). Также мы не станем описывать запросы к сервису СМС-рассылок, которые будут генерить необходимый для регистрации код. Наша задача &#8212; научиться в data design, а не спроектировать полноценный сервис.</p><p>Базовая структура данных приложения выглядит вот так:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d4886d&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d4886d" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2184" height="2200" 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/data-design-entities-operations-properties-full-save.png" alt="" class="wp-image-3861" srcset="https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save.png 2184w, https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save-1048x1056.png 1048w, https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save-768x774.png 768w, https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save-60x60.png 60w, https://sherer.pro/content/uploads/2023/12/data-design-entities-operations-properties-full-save-120x120.png 120w" sizes="auto, (max-width: 2184px) 100vw, 2184px" /><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>Теперь нам нужно придумать, каким образом клиент (мобильное приложение) будет перекидываться запросами с сервером. Для этого сперва чуток окунемся в матчасть.</p><h2 class="wp-block-heading">Страшное слово API</h2><p>Вполне вероятно, что сейчас я не открою никому Америки, но, все же: API &#8212; это интерфейс обмена данными. Но не тот интерфейс, что на экране. Программный интерфейс: набор методов, с помощью которых сервер и мобильное приложение/сайт сообщают друг другу, что делать. Конечно, реальное использование API куда шире этого (взять те же IoT-устройства), однако нам пока хватит рассмотрения web и mobile.</p><p>На самом деле, в большинстве &#171;апишек&#187; нет ничего сложного &#8212; при условии, что они хорошо документированы; а дизайнер, изучающий их, малость прошарен в технической стороне вопроса.</p><p>Вообще, документация API &#8212; это важно. В случае <a href="https://sherer.pro/blog/svetlaya-storona-pereproektirovaniya/">перепроектирования</a> сервиса, например, она позволяет заранее учесть некоторые ограничения и даже спланировать развитие продукта в разрезе обмена данными. Но чтобы понимать такую документацию (и, в перспективе, самому ее составлять), нужно знать кое-какие нюансы, термины. И да, в этой статье мы начнем изучать именно их.</p><p>Разумеется, я не стану погружать вас в пучину кодинга и рассказывать о сигнатурах, функциях, классах. Мы обойдем даже такие популярные темы, как <a rel="noreferrer noopener" aria-label="REST (откроется в новой вкладке)" href="https://developer.mozilla.org/en-US/docs/Glossary/REST" target="_blank">REST</a> и &#171;физические&#187; случаи, вроде <a rel="noreferrer noopener" aria-label=" (откроется в новой вкладке)" href="https://developer.mozilla.org/en-US/docs/Web/API/Keyboard_API" target="_blank">Keyboard API</a>. Особо упорные могут копнуть эти темы самостоятельно &#8212; или же дождаться следующих постов цикла про дизайн данных.</p><h3 class="wp-block-heading">Методы</h3><p>Начнем, собственно, с уже упомянутых методов. По сути, это <strong>программно описанные способы взаимодействия компонентов</strong> (например, сервера и сайта). </p><p>Даже вот так проще: каждый запрос на сервер содержит в себе метод, в котором описывается, какие именно данные нужно получить. Если у метода есть параметры &#8212; они тоже указываются в запросе. И ещё кое-что, но об этом ниже.</p><p>Важный момент: не путайте <em>методы API</em> и <a rel="noreferrer noopener" href="https://developer.mozilla.org/ru/docs/Web/HTTP/Methods" target="_blank"><em>HTTP-методы</em></a>. </p><p>Как правило, каждая отдельная операция имеет свой собственный метод. В нашем приложении методами API будут:</p><ul class="wp-block-list"><li>регистрация/аутентификация;</li><li>подтверждение номера телефона (код из СМС);</li><li>получение списка точек;</li></ul><p>Заметьте, мы не сделали два отдельных метода: получение и обновление списка точек. Первичное получение списка точек и подгрузка точек при скролле получаются с помощью одного и того же метода &#8212; просто мы указываем разные параметры в этих двух запросах. Оба раза нам возвращается одинаковый тип данных: список точек.<br><br>Такая же история с регистрацией и аутентификацией. Технически в обоих случаях мы отправляем на сервер одни и те же данные (номер телефона), а получаем статус (отправилась ли СМС с кодом) и глобальный идентификатор пользователя. В нашем случае даже интерфейсная, визуальная часть здесь будет одинаковой.</p><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Но тут есть один нюанс. Если потом по какой-то причине &#171;вход&#187; станет отличаться от регистрации сценарно, мы с высокой вероятностью воткнемся в необходимость куда больших доработок. А значит, повысится стоимость реализации.</p></blockquote><p>Иногда название метода API зашивается в адрес (например, <code>https://<...&gt;/points/get/</code>), иногда &#8212; указывается прямо рядом с параметрами запроса, а порой даже эти два способа комбинируются. Мы, чтобы не усложнять, будет рассматривать только второй вариант.</p><h3 class="wp-block-heading">Параметры</h3><p>Здесь все просто. Именно в параметрах мы указываем дополнительную информацию для сервера. Как правило, параметр имеет пару &#171;<em>ключ: значение&#187;</em>. Например, <em>&#171;name: Вася&#187;</em>, где <em>&#171;name&#187;</em> &#8212; это ключ, а <em>&#171;Вася&#187;</em> &#8212; значение.</p><p>Иногда в запросе указывается только метод, без параметров. Помните, в прошлой статье мы говорили о свойствах списка точек? Если мы договоримся, что по умолчанию отступ всегда равен нулю, а область видимости &#8212; двадцати, то при запросе этого списка с сервера мы можем указать только название метода, без параметров. Тогда сервер вернет нам последние двадцать точек.</p><p>Если вы внимательно читали предыдущую статью, то должны помнить, что свойства сущностей могут быть сложными, включающими в себя несколько значение. С параметрами этот фокус тоже работает &#8212; вы можете указать внутри одного <em>ключа</em> ещё несколько пар <em>&#171;ключ: значение&#187;</em>.</p><h3 class="wp-block-heading">Заголовки</h3><p>Это такая магическая штука, которая позволяет нам не дублировать одну и ту же информацию в каждом методе. </p><p>В частности, в заголовки очень часто пихают авторизационные данные. Например, нам нужно в каждом запросе от мобильного приложения к серверу передавать какую-то информацию, на основании которой сервер решает, есть ли у этого пользователя права на получение вразумительного ответа. И есть ли такой пользователь вообще. </p><p>Мы можем, конечно, каждому методу добавить дополнительные параметры, за это отвечающие. А также версию приложения, платформу и тьму прочих данных. Представляете, как распухает каждый метод? У нас пойдет дублирование &#8212; и если потом мы решим, что для аналитики нам нужно с каждым запросом передавать ещё что-то&#8230; Да, придется переписывать все методы как на сервере, так и на клиенте. Не очень удобно, дорого и ненадежно.</p><p>Кроме того, заголовки почти всегда несут в себе тьму служебной информации, которая необходима принимающей стороне для классификации и правильной обработки запросов/ответов &#8212; но сейчас, разумеется, нас это не будет тревожить.</p><h3 class="wp-block-heading">Ошибки</h3><p>Мы не станем подробно останавливаться на этом пункте, хотя он заслуживает отдельного раздела, книги, оды и дифирамбов. Если бы вы знали, сколько денег, сил и времени человечество потратило из-за плохой унификации и неверной обработки ошибок API &#8212; вы бы не удержались от слёз.</p><p>Ошибки, их типы, коды и способы обработки должны быть продуманы заранее. Вы банально не сможете унифицировать UI, если к каждой новой ошибке вам придется рисовать новое состояние формы, сообщение-плашку или даже целый экран.</p><p>В двух словах об этом не рассказать. На текущем этапе будет достаточно, если вы просто будете знать, что ошибки нужно делить на типы (например, &#171;ошибки получения данных&#187;, &#171;ошибки авторизации&#187; и тп), и внутри каждого типа создавать список кодов каждой ошибки (например, &#171;неверный код из СМС&#187;, &#171;пользователь не найден&#187;, &#171;секретный ключ устарел&#187; и так далее). Разумеется, приложение должно уметь работать с каждым типом и кодом. И чем более универсально &#8212; тем лучше.</p><h3 class="wp-block-heading">Схема</h3><p>Итого, очень упрощенная схема запросов (requests) и ответов (responses) выглядит так:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d48ebd&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d48ebd" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="892" 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/datadesign-request-response.png" alt="" class="wp-image-3864" srcset="https://sherer.pro/content/uploads/2023/12/datadesign-request-response.png 2096w, https://sherer.pro/content/uploads/2023/12/datadesign-request-response-1048x446.png 1048w, https://sherer.pro/content/uploads/2023/12/datadesign-request-response-768x327.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>Безусловно, это не отражает всех возможных вариантов. Параметры могут вообще указываться в URL, и тогда тело запроса окажется пустым. Просто знайте это.</p><h2 class="wp-block-heading">Запросы к тюленям</h2><p>Итак, вводная часть закончена, подбираемся к самому вкусному &#8212; примерам. Разумеется, в качестве основы возьмем наше выдуманное приложение для отслеживания миграции самых милых в мире млекопитающих.</p><h3 class="wp-block-heading">Структура запросов</h3><p>Сперва нам надо решить, где какие данные мы будем передавать: какие в теле запроса, а какие в заголовках. Для этого же достаточно определить, какая информация должна передаваться на сервер при каждом запросе.</p><p>В нашем случае каждый раз мы будем передавать:</p><ul class="wp-block-list"><li><strong>глобальный идентификатор пользователя</strong> (получаем с сервера после отправки номера телефона);</li><li><strong>секретный ключ</strong> (получаем после успешной регистрации/аутентификации); </li><li><strong>версию мобильного приложения</strong> (вшита в код приложения);</li><li><strong>идентификатор устройства</strong> (уникальный набор символов, присущий только этому устройству); </li><li><strong>платформу устройства</strong> (iOS или Android).</li></ul><p>Поэтому эти данные мы вынесем в <strong>заголовки</strong>. Всё остальное пускай отправляется в теле запроса.</p><p>Вот так у нас будет выглядеть первый набросок схемы запросов к API:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d4931b&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d4931b" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="948" 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/datadesign-api-1.png" alt="" class="wp-image-3865" srcset="https://sherer.pro/content/uploads/2023/12/datadesign-api-1.png 2096w, https://sherer.pro/content/uploads/2023/12/datadesign-api-1-1048x474.png 1048w, https://sherer.pro/content/uploads/2023/12/datadesign-api-1-768x347.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">API: заголовки запросов</figcaption></figure><p>Я не стану дополнять эту схемку ответами (responses), так как это довольно простая часть. Запросы же (requests) буду вносить постепенно, чтобы сформировалась общая картина. Если кому-то вдруг понадобится визуальное представление ответов сервера, содержащих свойства сущностей (например, точек миграции), у него всегда есть возможность вернуться в начало статьи и еще раз рассмотреть изображение со структурой данных.</p><h3 class="wp-block-heading">Регистрация и аутентификация</h3><p>Так как наше приложение предусматривает регистрацию, начнем именно с нее. Общую схему мы уже рассматривали в <a href="https://sherer.pro/blog/dizajn-dannyh-chast-2-kak/#handling_and_storage" target="_blank" rel="noreferrer noopener" aria-label=" (откроется в новой вкладке)">предыдущей статье</a>. Теперь давайте более подробно разберемся в том, что происходит, когда пользователь вводит свой номер телефона и запрос улетает на сервер:</p><ol class="wp-block-list"><li>Со стороны нашего сервера к внешнему сервису СМС-рассылок отправляется запрос на формирование кода, сервис возвращает этот код. Эту часть детально описывать не будем.</li><li>Сервер ищет в БД пользователя с указанным номером телефона.</li><li>Если пользователь не найден:<ol class="wp-block-list"><li>Формируются два идентификатора пользователя:<ul class="wp-block-list"><li>внутренний (для собственных нужд);</li><li>глобальный (для общения с миром). </li></ul></li><li>В базу данных на сервере записывается:<ul class="wp-block-list"><li>полученный номер телефона;</li><li>код, который вернул сервис;</li><li>дата и время регистрации;</li><li>внутренний идентификатор;</li><li>глобальный идентификатор. </li></ul></li></ol></li><li>Если пользователь найден в БД по номеру телефона, то на этом шаге мы просто обновляем ему код, который нам вернул СМС-сервис.</li><li>В мобильное приложение возвращается информация о том, что &#171;всё хорошо, жди кода в СМС&#187; (статус) и глобальный идентификатор пользователя. В случае ошибок (например, СМС-сервис вдруг сдох), мы возвращаем в приложение соответствующее сообщение.</li></ol><p>Таким образом, на сервер мы отправляем <strong>номер телефона</strong>, а оттуда ждем <strong>статус</strong> и <strong>глобальный идентификатор</strong> (который записывается локально на устройстве пользователя).</p><p>В момент отправки запроса мы ничего не знаем о нашем пользователе, поэтому заголовки <strong>глобальный идентификатор</strong> и <strong>секретный ключ</strong> оставляем <strong>пустыми</strong>.</p><p>Добавляем первый метод в схемку, указывая единственный параметр, который в него передаем:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d49816&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d49816" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="1028" 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/datadesign-api-2.png" alt="" class="wp-image-3866" srcset="https://sherer.pro/content/uploads/2023/12/datadesign-api-2.png 2096w, https://sherer.pro/content/uploads/2023/12/datadesign-api-2-1048x514.png 1048w, https://sherer.pro/content/uploads/2023/12/datadesign-api-2-768x377.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">API: заголовки и методы запросов (1)</figcaption></figure><h3 class="wp-block-heading">Подтверждение номера телефона</h3><p>Пользователь вводит код из СМС и отправляет его на сервер. Чтобы нам понять, кто вообще прислал нам этот код, мы вместе с ним отправляем глобальный идентификатор пользователя, полученный на предыдущем шаге, а также &#8212; идентификатор устройства.</p><p>Далее, на сервере:</p><ol class="wp-block-list"><li>Осуществляется поиск в БД по полученному идентификатору пользователя.</li><li>Если пользователь не найден, на клиент возвращается сообщение об ошибке.</li><li>Если пользователь найден, полученный код сверяется с записанным в БД.<ol class="wp-block-list"><li>Если коды не совпадают, в приложение снова улетает ошибка.</li><li>Если коды совпадают:<ol class="wp-block-list"><li>Формируется секретный ключ.</li><li>В базу данных записывается сформированный только что ключ и полученный идентификатор устройства. Причем записываются они в связке, взаимозависимыми. </li></ol></li></ol></li><li>В мобильное приложение возвращается сообщение о том, что &#171;всё ok&#187; и секретный ключ.</li></ol><p>Итого, клиент отправляет <strong>код из СМС</strong>, <strong>глобальный идентификатор пользователя</strong> и <strong>идентификатор устройства</strong>, а получает <strong>статус</strong> и <strong>секретный ключ</strong> (его, как и глобальный идентификатор, мы сохраняем локально).</p><p>На этапе формирования запроса у нас еще нет <strong>секретного ключа</strong>, поэтому в запросе соответствующий заголовок остается <strong>пустым</strong>.</p><p>Всё, вроде, просто &#8212; но только если вы понимаете общую структуру данных. Будь наш пример чуть сложнее, то на уровне чистого (незамутненного техническими заморочками) юикса можно было бы нагородить такие костыли, что бедные разработчики потом умывались бы кровавым потом. Или напротив, сделали бы &#171;по-своему&#187;, со всеми вытекающими.</p><p>В любом случае, метод и параметр улетели в общую схемку:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d49c7d&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d49c7d" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="1028" 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/datadesign-api-3.png" alt="" class="wp-image-3867" srcset="https://sherer.pro/content/uploads/2023/12/datadesign-api-3.png 2096w, https://sherer.pro/content/uploads/2023/12/datadesign-api-3-1048x514.png 1048w, https://sherer.pro/content/uploads/2023/12/datadesign-api-3-768x377.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">API: заголовки и методы запросов (2)</figcaption></figure><h3 class="wp-block-heading">Получение списка точек</h3><p>Самый объемный метод, включающий в себя не только формирование и получение списка точек, но и пару нюансов, однозначно заслуживающих внимания. Начнем с них.</p><h4 class="wp-block-heading">Авторизация</h4><p>После того, как пользователь зарегистрировался или вошел в аккаунт, каждый запрос на сервер должен быть подтвержден секретным ключом. Ибо чужим не место в нашем уютном мирке наблюдателей за тюленями.</p><p>Итак, для авторизации мы в заголовках запроса передаем <strong>секретный ключ</strong>. Включаем paranoiac mode и (как уже решили выше) добавляем к запросам <strong>уникальный идентификатор устройства</strong>. Как мы помним, они у нас связаны на сервере &#8212; как раз для того, чтобы секретным ключом не могли воспользоваться с другого девайса плохие дяди.</p><p><em>Маленькое веб-отступление. На сайтах для авторизации чаще всего используют файлы куки (cookies). Если проектируете веб-приложение, копните их тоже.</em></p><h4 class="wp-block-heading">Инициализация</h4><p>Обычно инициализация &#8212; это отдельный запрос, осуществляемый при открытии приложения. В нем чаще всего нет параметров, только заголовки. Так приложение узнает, не устарело ли оно, работает ли вообще сервер и есть ли какие-то новости, которые нужно сообщить пользователю в первую очередь. </p><p>Также при инициализации может происходить проверка на устаревшие данные (например, профиля) для обновления кэша. Или проверять статус синхронизации состояний, если ваш продукт поддерживает <a href="https://sherer.pro/blog/besshovnyj-ux-streljaem-sebe-v-nogu/" target="_blank" rel="noreferrer noopener" aria-label="бесшовное взаимодействие (откроется в новой вкладке)">бесшовное взаимодействие</a>.</p><p>Инициализация рекомендуется везде и всегда, однако в нашем случае его функцию будет выполнять запрос на получение точек &#8212; просто потому что других запросов от авторизованных пользователей у нас нет. А пилить инициализацию для неавторизованных в нашем простейшем случае явный перебор.</p><h4 class="wp-block-heading">Собственно, получение точек</h4><p>Всё, регистрация или аутентификация прошла успешно, пользователь получил секретный код, пришло время дать ему то, зачем он вообще пришел &#8212; информацию о миграции тюленей на берегах Охотского моря.</p><p>Для этого приложение совершает запрос к серверу, указывая в параметрах метода отступ и область видимости. Напомню, что у нас это динамические параметры, принцип их формирования мы уже проговаривали в предыдущей статье цикла.</p><p>Получив запрос, сервер первым делом проверяет версию приложения и, если оно устарело, сообщает об этом. Нам важно, чтобы наблюдатели за тюленями пользовались свежим софтом. Если все нормально, сервер ищет пользователя в БД по глобальному идентификатору:</p><ol class="wp-block-list"><li>Если пользователь найден, секретный ключ, полученный в запросе, сравнивается с аналогом в БД у пользователя:<ol class="wp-block-list"><li>Если ключи совпадают, проверяется соответствие идентификатора устройства из запроса с сохраненным в БД (и связанным с секретным ключом):<ol class="wp-block-list"><li>Если идентификаторы не совпадают, сервер формирует ответ с ошибкой и отправляет его в мобильное приложение.</li><li>И только если идентификаторы устройств совпадают, происходит формирование списка точек: осуществляется запрос к БД, в котором в качестве параметров указываются отступ (по факту, количество дней от начала, которые надо пропустить) и область видимости (просто количество дней, за которые нужно получить данные). Полученный массив, вместе со статусом &#171;всё ok&#187;, отправляется на клиент. </li></ol></li><li>Если ключи не совпадают, сервер прерывает операцию и сообщает об этом мобильному приложению. </li></ol></li><li>Если пользователь не найден, сервер возвращает сообщение об ошибке.</li></ol><p>Получается, что в заголовках запроса мы указали <strong>глобальный идентификатор пользователя</strong>, <strong>идентификатор устройства</strong> и <strong>секретный ключ</strong>, а в параметрах &#8212; <strong>отступ</strong> и <strong>область видимости</strong>. В ответ же получили <strong>статус</strong> и <strong>массив (список) точек</strong>.</p><p>Точки приходят нам простым списком, отсортированные по времени. Мы обрабатываем их и &#171;пакуем&#187; по дням, чтобы нормально отобразить в интерфейсе. Всё.</p><p>Вот наша финальная схемка запросов:</p><figure data-wp-context="{&quot;imageId&quot;:&quot;69d5ca0d4a0b7&quot;}" data-wp-interactive="core/image" data-wp-key="69d5ca0d4a0b7" class="wp-block-image aligncenter size-full wp-lightbox-container"><img loading="lazy" decoding="async" width="2096" height="1320" 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/datadesign-api-4.png" alt="" class="wp-image-3868" srcset="https://sherer.pro/content/uploads/2023/12/datadesign-api-4.png 2096w, https://sherer.pro/content/uploads/2023/12/datadesign-api-4-1048x660.png 1048w, https://sherer.pro/content/uploads/2023/12/datadesign-api-4-768x484.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">API: заголовки и методы запросов (3)</figcaption></figure><p>К слову об ошибках. Посмотрите, сколько в сценарии выше их может возникнуть. Целых 4 штуки, не считая технических (типа &#171;сервер упал&#187;, &#171;нет интернета&#187; и тп). А в мобильном приложении каждую из них нужно грамотно обработать и показать пользователю. И это суперпростой пример.</p><h2 class="wp-block-heading">Оптимизация &#8212; сестра UX</h2><p>Готово, обмен совершен. Всё работает, пользователь доволен. Но давайте малость отмотаем назад, до регистрации/аутентификации. Не кажется, что можно что-то оптимизнуть? Вот у нас прошел запрос на подтверждение номера телефона, мы получили секретный ключ &#8212; и выполняем новый запрос, на получение точек. Зачем? Что будет видеть пользователь всё то время, пока выполняются два запроса подряд? Лоадер, заглушку, плейсхолдеры? </p><p>Ведь мы знаем, что после успешных регистрации или аутентификации всегда показывается экран со списком точек. Что будет, если в параметры запроса с кодом из СМС мы сразу включим отступ и область видимости? О да, мы сделаем на один запрос меньше, а наш горячо любимый юзер получит результат на секунду-две раньше. Если хотите, попробуйте расписать сценарий обмена данными с учетом этого &#8212; простенькое упражнение, но оно гарантирует, что посыл этой статьи выветрится у вас из памяти несколько позже. </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>Прочитав этот пост и вдоволь погуглив, можете копнуть остальные составляющие запросов и другие технические детали обмена данными. Тут уже вас ожидает полное мерлинство: это и уже упомянутые HTTP-методы, и коды статусов, и сжатие ответов, и схемы/корсы/юзер-агенты, и прочие адовы полчища терминов, технологий и возможностей. Если же у вас остались вопросы &#8212; смело задавайте их в комментариях. Настоящий дизайнер не должен быть стеснительным.</p><h2 class="wp-block-heading">Что дальше?</h2><p>А дальше, в следующих статьях цикла, ваш мозг ждут куда более серьезные испытания: я приступлю к описанию технических нюансов (вроде типов данных) и даже научу собирать на коленке прототип API &#8212; чтобы разработчики, едва вас завидев, тут же склонялись в почтительном поклоне <a href="https://ru.wikipedia.org/wiki/%D0%9E%D0%B4%D0%B7%D0%B8%D0%B3%D0%B8" target="_blank" rel="noreferrer noopener">одзиги</a>.</p><p>Запись <a href="https://sherer.pro/blog/dizajn-dannyh-chast-3-menjaemsja/">Дизайн данных (часть 3). Меняемся?</a> первой появилась на <a href="https://sherer.pro">Павел Шерер</a>.</p>]]></content:encoded><wfw:commentRss>https://sherer.pro/blog/dizajn-dannyh-chast-3-menjaemsja/feed/</wfw:commentRss><slash:comments>6</slash:comments></item></channel></rss>