<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Александр Нездемина</title><generator>teletype.in</generator><description><![CDATA[Александр Нездемина]]></description><image><url>https://img4.teletype.in/files/bc/e5/bce53397-f094-4513-aed6-8fffb0924dde.png</url><title>Александр Нездемина</title><link>https://teletype.in/@proanalitika</link></image><link>https://teletype.in/@proanalitika?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=proanalitika</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/proanalitika?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/proanalitika?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Tue, 11 Aug 2026 01:20:09 GMT</pubDate><lastBuildDate>Tue, 11 Aug 2026 01:20:09 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@proanalitika/3yKc1Pg6eqX</guid><link>https://teletype.in/@proanalitika/3yKc1Pg6eqX?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=proanalitika</link><comments>https://teletype.in/@proanalitika/3yKc1Pg6eqX?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=proanalitika#comments</comments><dc:creator>proanalitika</dc:creator><title>Как правильно распределять данные в REST API</title><pubDate>Tue, 16 Jun 2026 20:13:47 GMT</pubDate><description><![CDATA[Когда мы проектируем REST API, один из первых практических вопросов звучит так: какие данные куда класть в запросе?]]></description><content:encoded><![CDATA[
  <p id="093E">Когда мы проектируем REST API, один из первых практических вопросов звучит так: <strong>какие данные куда класть в запросе?</strong></p>
  <p id="9cHU">У нас есть путь, query‑параметры, заголовки и тело — и каждый из этих элементов решает свою задачу.</p>
  <p id="A3Mh">В этой статье разберёмся на конкретном кейсе: витрина каталога товаров в мобильном приложении.</p>
  <hr />
  <h2 id="ru5h">Кейс: витрина каталога и «глупый» фронт</h2>
  <p id="Isdb">Представим, что у нас есть фронт: iOS, Android и мобильный веб.<br />Фронт максимально &quot;глупый&quot;: он просто ходит в мидл‑сервисы и хочет получить:</p>
  <ul id="NXo1">
    <li id="UZlM">витрину с каталогом товаров</li>
    <li id="CJKA">категории товаров</li>
    <li id="aKtZ">корзину пользователя</li>
  </ul>
  <p id="gQCn">При этом, вместе с запросом фронт передаёт:</p>
  <ul id="GMbp">
    <li id="dszd">авторизационный токен</li>
    <li id="4zXu">информацию о приложении (версия, тип устройства, операционная система)</li>
  </ul>
  <p id="xWQR">Задача: <strong>понять, в какую часть HTTP‑запроса какие данные класть, чтобы запросы были логичными, безопасными и удобными для поддержки.</strong></p>
  <p id="SXWR"></p>
  <h2 id="http">Четыре места для данных в HTTP‑запросе</h2>
  <p id="7W7z">В типичном REST API у нас есть четыре основных &quot;слота&quot;, куда можно положить данные:</p>
  <ol id="MFy5">
    <li id="WjlR">Путь (Path) — часть URL, которая описывает, к какому ресурсу мы обращаемся.</li>
    <li id="VmSp">Параметры запроса (Query) — строка после <code>?</code> в URL, используется для фильтров, сортировок и прочих модификаторов выборки.</li>
    <li id="bfcM">Заголовки (Headers) — метаданные запроса: авторизация, формат данных, информация о клиенте.</li>
    <li id="iXlA">Тело (Body) — основное содержимое: то, что мы создаём, изменяем или отправляем как сложный запрос.</li>
  </ol>
  <p id="9XFV">Дальше разложим наш кейс по этим четырём местам.</p>
  <p id="u4wG"></p>
  <h3 id="UFNp">Авторизационный токен: заголовок Authorization</h3>
  <p id="1ZUD"><strong>Bearer‑токен</strong> (или любой другой токен авторизации) логичнее всего передавать в заголовке <code>Authorization</code>.<br />Это де‑факто стандарт для REST API и рекомендованный способ передачи авторизационных данных.</p>
  <pre id="994l">GET /api/v1/products
Authorization: Bearer eyJhbGciOiJIUz...</pre>
  <p id="FLop">Почему именно заголовок:</p>
  <ul id="dkJ8">
    <li id="ErPf">токен не попадает в URL, а значит — не засветится в истории браузера или прокси</li>
    <li id="old7">многие инструменты и библиотеки по умолчанию ожидают токен именно в <code>Authorization</code></li>
    <li id="BqUw">это согласуется с практиками OAuth 2.0 и большинством публичных API</li>
  </ul>
  <p id="ttbL"></p>
  <h3 id="2ZEE">Метаданные клиента: тип приложения, версия, ОС</h3>
  <p id="FAvi">Информация о том кто обращается, мобилка, веб.  Это <strong>метаданные</strong>: они описывают не ресурс, а того, <em>кто</em> делает запрос.<br />Примеры:</p>
  <ul id="QHoR">
    <li id="REpG">тип приложения (mobile/web)</li>
    <li id="87vV">версия приложения</li>
    <li id="qdrX">операционная система и её версия</li>
  </ul>
  <p id="LlJz">Эти данные нужны серверу, чтобы:</p>
  <ul id="lpJ7">
    <li id="bFBb">принимать решения по фичефлагам (например, отключать функциональность для старых версий)</li>
    <li id="12cN">логировать и анализировать трафик по типам клиентов</li>
    <li id="UXH8">внедрять ограничения: «для версии ниже 1.5 не отдаём новый тип карточек товара»</li>
  </ul>
  <p id="4WB3">Так как эти данные нужны <strong>при любом запросе</strong>, а не только при конкретных методах, логично передавать их в заголовках.</p>
  <p id="Eskq">Пример:</p>
  <pre id="VESp">X-App-Type: ios
X-App-Version: 1.2.3
X-OS-Name: iOS
X-OS-Version: 16.4</pre>
  <p id="IY7h">Исторически было принято использовать префикс <code>X-</code> для кастомных заголовков, но сейчас его применение считается устаревшей практикой.<br />Можно использовать более нейтральные варианты, например: <code>App-Type</code>, <code>App-Version</code>, <code>Client-OS-Name</code>.</p>
  <p id="HLet">Ключевой момент: <strong>не класть эти метаданные в тело</strong>, потому что:</p>
  <ul id="iIzD">
    <li id="aPhx">у GET‑запросов тела обычно нет, а метаданные нам нужны и там</li>
    <li id="TfmE">нам важна предсказуемость: любой запрос несёт одни и те же заголовки клиента</li>
    <li id="SqIR">прокси и кэширующие слои чаще учитывают заголовки, чем тело, для принятия решений</li>
  </ul>
  <h3 id="x3Uw">Фильтры и сортировка: параметры запроса (query)</h3>
  <p id="p9YH">Когда речь идёт о <strong>фильтрации</strong>, <strong>поиске</strong> или <strong>сортировке</strong>, первый кандидат — <strong>query‑параметры</strong>.<br />Они позволяют явно описать, какую выборку мы хотим получить.</p>
  <p id="pvr2">Пример запроса витрины:</p>
  <pre id="KEle">GET /api/v1/products?sort=price&amp;category=electronics&amp;page=1&amp;limit=20</pre>
  <p id="zx0w">Здесь:</p>
  <ul id="zV59">
    <li id="gIkP"><code>sort=price</code> — сортировка по цене</li>
    <li id="XRq5"><code>category=electronics</code> — фильтрация по категории</li>
    <li id="HnQ6"><code>page</code> и <code>limit</code> — параметры пагинации</li>
  </ul>
  <p id="fGjg">Рекомендации по фильтрам через query:</p>
  <ul id="J1Za">
    <li id="0dHp">использовать понятные названия (<code>price</code>, <code>category</code>, <code>brand</code>, <code>sort</code>)</li>
    <li id="C9Bw">делать параметры консистентными: например, <code>page</code>/<code>limit</code> везде, а не <code>page</code>/<code>perPage</code> в одном методе и <code>offset</code>/<code>count</code> в другом.</li>
    <li id="XNon">для сложных фильтров применять единый формат (например, <code>filter[field]=value</code> или <code>filter=field:op:value</code>)</li>
  </ul>
  <p id="N9O7"></p>
  <h3 id="EDMW">Когда фильтры уходят в тело запроса</h3>
  <p id="O4Tc">Бывает, что фильтрация становится настолько сложной, что query‑строка становится:</p>
  <ul id="v0IG">
    <li id="Rkkf">слишком длинной</li>
    <li id="DkH9">с трудом читаемой</li>
    <li id="3nf8">плохо валидируемой и документируемой</li>
  </ul>
  <p id="Zsk0">В таких случаях разумно <strong>перенести фильтры в тело запроса</strong> и использовать <code>POST</code> для получения данных по сложному запросу.</p>
  <pre id="EyOn">POST /api/v1/products/search
Content-Type: application/json

{
  &quot;sort&quot;: { &quot;field&quot;: &quot;price&quot;, &quot;direction&quot;: &quot;asc&quot; },
  &quot;filters&quot;: {
    &quot;category&quot;: [&quot;electronics&quot;, &quot;appliances&quot;],
    &quot;price&quot;: { &quot;gte&quot;: 1000, &quot;lte&quot;: 5000 },
    &quot;inStock&quot;: true
  },
  &quot;page&quot;: 1,
  &quot;limit&quot;: 20
}</pre>
  <p id="fwTh">Такой подход встречается, когда нужны:</p>
  <ul id="zwff">
    <li id="ZF5v">сложные комбинированные фильтры</li>
    <li id="CaWe">вложенные структуры</li>
    <li id="Z4ta">массивы значений и сложные условия</li>
  </ul>
  <p id="zOfE">Правило, которое удобно держать в голове:<br /><strong>простые фильтры — в query, сложные и структурированные — в теле запроса.</strong></p>
  <h3 id="SGK9"></h3>
  <p id="9nji">И финальное, все данные, которые мы получаем о товарах мы забираем из тела запроса. </p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@proanalitika/5Y-SWcSDysw</guid><link>https://teletype.in/@proanalitika/5Y-SWcSDysw?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=proanalitika</link><comments>https://teletype.in/@proanalitika/5Y-SWcSDysw?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=proanalitika#comments</comments><dc:creator>proanalitika</dc:creator><title>Как правильно оформлять коды ошибок в API</title><pubDate>Sat, 06 Jun 2026 20:59:30 GMT</pubDate><description><![CDATA[Ошибка в API — это не просто «что-то пошло не так». Для нормальной интеграции важно, чтобы ошибка была предсказуемой, однозначной и удобной для обработки и людьми, и программам.]]></description><content:encoded><![CDATA[
  <p id="eN3y">Если мы говорим про проектирование, то аналитики часто продумывают формат запроса и ответа API, но забывают о том, как должны выглядеть ошибки. Часто это происходит потому, что в компании уже принят какой-то стандарт, и все привыкают работать по накатанной. Такой подход хорошо работает в устоявшихся проектах, но если у вас новый проект, лучше самостоятельно продумать ответ на случай, если что-то пойдёт не так. Ведь ошибки — это часть контракта, и если вы не дадите конкретики, разработчики сделают так, как им кажется правильным.</p>
  <h2 id="suK9"><br />Из чего состоит хорошая ошибка?</h2>
  <p id="JiSI">Любая ошибка должна отвечать на три вопроса: что произошло, почему и что с этим делать. </p>
  <p id="arlt">Пройдёмся по этим пунктам.</p>
  <h3 id="j8xV">Что произошло?</h3>
  <p id="nYWK">Ответ на этот вопрос обычно закрывают коды ответов 4xx и 5xx. <br />Например: <br />400 Bad Request — некорректные данные от клиента; <br />401 Unauthorized — пользователь не аутентифицирован (нет токена или он недействителен); <br />403 Forbidden — аутентификация есть, но нет прав доступа; <br />404 Not Found — ресурс не найден; <br />409 Conflict — конфликт состояния (например, такой email уже зарегистрирован); <br />422 Unprocessable Entity — данные приняты, но не прошли бизнес-валидацию; <br />429 Too Many Requests — превышен лимит запросов; <br />500 Internal Server Error — ошибка на стороне сервера; <br />503 Service Unavailable — сервис временно недоступен.<br /><br />Но достаточно ли этого? В некоторых кейсах да, но иногда лучше вместе с кодом отправлять в теле ответа мнемонику, например: USER_NOT_FOUND, VALIDATION_ERROR, DUPLICATE_ORDER. Если это указать, клиенту будет проще разобраться и сделать обработку более персонализированной</p>
  <h3 id="4ZWa">Почему это произошло?</h3>
  <p id="H6j0">Частая ситуация: клиент получает ошибку, но, чтобы понять реальную причину, приходится лезть в логи и вручную разбираться. Поэтому лучше сразу дать пояснение. Для этого в ответ, помимо мнемоники, добавляют поле message с понятным описанием проблемы. В него не стоит включать технические трейсы или детали, которые не будут понятны пользователю. </p>
  <h3 id="2on6">Что с этим делать?</h3>
  <p id="OKy3">В идеале — добавить инструкцию по исправлению ошибки. Например: «повторить запрос через N секунд», «исправить данные», «обратиться в поддержку». Иногда даже передают номер телефона или другие контакты поддержки.</p>
  <p id="s87X"><br />В теории всё звучит хорошо. Теперь давай разберёмся, как это реализовать и как может выглядеть такой ответ.</p>
  <p id="fLjZ"></p>
  <h2 id="m7Fq">Структура тела ошибки</h2>
  <p id="mKEn">Если ошибки во всех эндпоинтах выглядят одинаково, клиентам проще писать обработчики. Именно поэтому лучше использовать единый формат.<br /><br />Хороший базовый формат тела ошибки:</p>
  <pre id="h1AF">{
  &quot;code&quot;: &quot;VALIDATION_ERROR&quot;,
  &quot;message&quot;: &quot;Ошибка валидации&quot;,
  &quot;errors&quot;: [
    {
      &quot;field&quot;: &quot;email&quot;,
      &quot;code&quot;: &quot;INVALID_FORMAT&quot;,
      &quot;message&quot;: &quot;Неправильный формат email&quot;
    }
  ]
}</pre>
  <p id="oTsL">code — машиночитаемая мнемоника, по которой клиент понимает, что делать.<br />message — человекочитаемое описание ошибки.<br />errors — массив, позволяющий вернуть все проблемы валидации за один запрос, а не по одной. Это особенно важно для форм, но лучше, чтобы контракт был единым для всех эндпоинтов.</p>
  <p id="kYwd">Иногда вместо errors, если API простое и не требует детальной валидации, добавляют поле details или messageDetails, чтобы описать, как исправить ситуацию:</p>
  <pre id="FI1M">{  
 &quot;code&quot;: &quot;DUPLICATE_ORDER&quot;,  
 &quot;message&quot;: &quot;Заказ с id 12345 уже существует&quot;,  
 &quot;messageDetails&quot;: &quot;Заказ с номером 12345 уже существует. Если это ошибка, напишите в чат поддержки&quot; 
}</pre>
  <p id="hWG0"></p>
  <p id="N88q">Еще один хороший паттерн — добавлять идентификатор запроса, чтобы можно было отследить всю цепочку вызовов. Обычно его передают в поле traceId или correlationId.</p>
  <pre id="pFwS">{  
 &quot;code&quot;: &quot;DUPLICATE_ORDER&quot;,  
 &quot;message&quot;: &quot;Заказ с id 12345 уже существует&quot;,  
 &quot;traceId&quot;: &quot;abc-123-xyz&quot; 
}</pre>
  <p id="Gw3r"></p>
  <h2 id="8etR">Частые антипаттерны, которые я встречаю на практике</h2>
  <p id="RQRJ">1)Отвечать HTTP-кодом 200 на любые ответы, а реальный код ошибки передавать в теле ответа. Например:</p>
  <pre id="eo1I">{
 &quot;code&quot;: &quot;404&quot;,
 &quot;message&quot;: &quot;NOT FOUND&quot;
}</pre>
  <p id="kPST"></p>
  <p id="zgm2">2) Использовать разные форматы ошибок в разных эндпоинтах. В одном месте {&quot;error&quot;: &quot;...&quot;}, в другом {&quot;message&quot;: &quot;...&quot;}. В этом случае клиенту или сервису, который с вами интегрируется, придётся делать отдельный парсер для каждого варианта ошибки и затем унифицировать их.</p>
  <p id="09zg">3) Передавать стандартные сообщения вроде «что-то пошло не так» или технические ошибки типа NullPointerException в message. Такой формат не даёт никакой полезной информации. <br /></p>
  <h2 id="KrvN">Что фиксировать в требованиях при проектировании API</h2>
  <ul id="8ikc">
    <li id="NDiS">HTTP-статус должен соответствовать типу ошибки, а не всегда быть 200.</li>
    <li id="ve1r">Указывать поле code с машиночитаемой мнемоникой.</li>
    <li id="T0DD">Добавлять поле message без внутренних деталей и стек-трейсов.</li>
    <li id="a2Fq">Делать единый формат ошибки во всех эндпоинтах.</li>
    <li id="zHxQ">Если есть валидация, возвращать массив ошибок с описанием всех проблем, а не по одной.<br /></li>
  </ul>
  <h2 id="LXub">И ключевое</h2>
  <p id="9fKY">Помните, что плохо спроектированные ответы об ошибках могут усложнить работу вам и вашей команде. Из-за этого можно потратить много часов на дебаг и разбор обращений от поддержки. При этом, если в команде или компании уже есть принятый формат, не стоит его ломать. Лучше сначала разобраться, почему он устроен именно так и какие ограничения за этим стоят.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@proanalitika/lu_GijFBCIK</guid><link>https://teletype.in/@proanalitika/lu_GijFBCIK?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=proanalitika</link><comments>https://teletype.in/@proanalitika/lu_GijFBCIK?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=proanalitika#comments</comments><dc:creator>proanalitika</dc:creator><title>Как использовать метод DELETE так, чтобы не получить по шапке?</title><pubDate>Tue, 17 Feb 2026 13:22:23 GMT</pubDate><description><![CDATA[Метод DELETE под собой БАЗОВО подразумевает, что вызвав его - мы удалим полностью данные.]]></description><content:encoded><![CDATA[
  <p id="Bn43"><strong>Метод DELETE</strong> под собой <strong>БАЗОВО</strong> подразумевает, что вызвав его - мы <strong>удалим полностью данные</strong>.</p>
  <p id="96V7">Но что делать, если есть сомнение: <strong><em>а действительно ли надо удалять ресурс? Может его надо обновить и просто скрыть без удаления, вдруг понадобится?<br /><br /></em></strong>Если такой вопрос возникает, значит нам надо понять как действовать, потому что если мы неправильно спроектируем взаимодействие и удалим данные, которые нужны на самом деле, то есть большой риск, что компания получит убытки, а вы по шапке.<br />Приведу примеры на нескольких кейсах.<br /></p>
  <h3 id="jat3"><strong>Кейс 1️⃣.  Удаление банковской транзакции</strong></h3>
  <p id="2bPU">Вы совершили отложенный перевод денежных средств в банк клиенте. Заявка в статусе на отправку, но деньги еще не ушли и вы хотите ее удалить.</p>
  <p id="vs07"><strong>Что делать?</strong></p>
  <p id="apaR">Если мы просто удалим заявку на денежный перевод и она не ушла, то наверное ничего страшного, однако, это финансовая операция и поэтому у нее должен быть жесткий учет, значит DELETE в данном случае использовать нельзя.</p>
  <p id="20VV">➡️ можно сделать SOFT DELETE и просто прокинуть статус disable, а лучше поменять статус на &quot;отменена&quot; и тогда сохранится историчность.</p>
  <p id="xIlr"></p>
  <h3 id="A4u8"><strong>Кейс 2️⃣. Удаление товара из системы в интернет-магазине.</strong></h3>
  <p id="mOEu">У вас есть справочник товаров, которым управляют сотрудники. Они могут добавлять товары и удалять.</p>
  <p id="DDxO">У вас есть старые товары, которые уже перестали продаваться в магазине. Сотрудник хочет их удалить.</p>
  <p id="VkjR"><strong>Что делать?</strong></p>
  <p id="xgAk">Тут у нас двоякая ситуация, потому что с одной стороны, товар уже не используется, но не факт что он не использовался раньше, и отсутствует в заказах, поэтому здесь можно пойти таким путем:</p>
  <p id="CapI">Мы проверяем, был ли товар добавлен хотя бы в 1 заказ.</p>
  <p id="MmvX">➡️ Если был, то удалять такой товар нельзя и его нужно архивировать, так как, если мы его удалим, у нас умрут связи и это повлияет не только на историю заказов, но может затронуть финансовые операции, расчеты, а это очень больно, уж поверьте. Используем SOFT DELETE.</p>
  <p id="iET6">➡️ Если товар ни с чем не связан, то спокойно делаем DELETE.</p>
  <p id="ZiyL"></p>
  <h3 id="p8XP"><strong>Кейс 3️⃣. Удаление учётной записи пользователя в интернет-магазине</strong></h3>
  <p id="FxhC">У вас есть учетная запись и функциональность по удалению этой учетки. Как ее реализовать?</p>
  <p id="k8t4">Тут как и в предыдущем пункте - два варианта:</p>
  <p id="a9bL">➡️ Если у пользователя не было покупок → можно удалить его аккаунт так:</p>
  <pre id="Nn8T">DELETE /users/{id}</pre>
  <p id="Qc0N">➡️ Если он совершал заказы → удалять нельзя, потому что его данные связаны с чеками, гарантиями, возвратами, заказами.</p>
  <p id="Zw7Z">Но если бы я реализовывал именно этот кейс, то не закладывал бы сложную логику, потому что я не люблю усложнять. Сделать бы так:</p>
  <p id="C8y5">➡️ во всех случаях, когда Клиент удаляет учетку, я бы делал <strong>SOFT DELETE</strong> и еще добавил бы анонимность данных.</p>
  <p id="km9l">➖➖➖</p>
  <p id="RbEF">А дальше дело техники</p>
  <p id="6dDl"></p>
  <h2 id="jTWT">Как оформить запрос при <strong>DELETE и SOFT DELETE?</strong></h2>
  <h3 id="7lqO"><strong>«Полное» удаление</strong> <strong>(DELETE)</strong></h3>
  <p id="GmaU">• <strong>Метод</strong>: DELETE</p>
  <p id="XqkH">• <strong>Endpoint</strong>: /resource/{id}<br /></p>
  <h3 id="oCMx"><strong>«Мягкое» удаление (SOFT DELETE)</strong></h3>
  <p id="CNrP">• <strong>Метод</strong>: чаще PATCH или PUT</p>
  <p id="WG5M">• <strong>Endpoint</strong>: resource/{id}, где передаём значение поля is_deleted = true или archived = true или status = &quot;cancelled&quot;.</p>
  <p id="rvOV">Пример:</p>
  <pre id="bacd">PATCH /api/v1/products/123

Headers:
Content-Type: application/json

Body:
{
&quot;is_archived&quot;: true,
&quot;archived_at&quot;: &quot;2025-02-26T12:00:00Z&quot;
}</pre>
  <p id="8tMi"></p>
  <h2 id="90zf">Почему при SOFT DELETE мы не используем метод DELETE?</h2>
  <p id="he1b">В целом, мы можем делать и soft delete и обычное удаление через метод DELETE, но в этом случае такой запрос не очевидно читается. И внутри придется делать дополнительную логику. <br /><br />⚡️⚡️⚡️</p>
  <p id="ZFQF">Не важно через какой метод вы это делаете, важно лишь то, что вы понимаете БАЗОВЫЕ принципы и  логику, а еще используете мышление системного аналитика для решения таких задач.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@proanalitika/KqnkMgBIYqi</guid><link>https://teletype.in/@proanalitika/KqnkMgBIYqi?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=proanalitika</link><comments>https://teletype.in/@proanalitika/KqnkMgBIYqi?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=proanalitika#comments</comments><dc:creator>proanalitika</dc:creator><title>Как правильно описать USE CASES, когда описываешь спеку на разработку UI интерфейса, чтобы команда не приходила потом с 1000 вопросов потом?</title><pubDate>Wed, 21 May 2025 07:36:36 GMT</pubDate><description><![CDATA[Предлагаю сразу на примере:]]></description><content:encoded><![CDATA[
  <p id="YZCJ">Предлагаю сразу на примере:</p>
  <p id="TFCN">У нас есть трекер калорий и него есть классная фича- сканирование штрих-кода для автозаполнения КБЖУ.</p>
  <p id="PYTR">Данные по штрих-кодам мы получаем из нескольких источников внешней системы, но агригируем все у себя на бэке.</p>
  <p id="M0OI">Тебе <strong>поставили задачу - описать требования к UI. </strong></p>
  <p id="jGIf">И один из способов это сделать –  использовать USE CASES</p>
  <p id="Mt4u">Классически USE CASE выглядит так:</p>
  <p id="6Dpo">✔️ Название,</p>
  <p id="8SXb">✔️ Актёры,</p>
  <p id="kkyS">✔️ Предусловия,</p>
  <p id="aJ6j">✔️ Основной сценарий,</p>
  <p id="tOdC">✔️ Альтернативные/ошибочные потоки,</p>
  <p id="Vk6u">✔️ Результат.</p>
  <p id="Xpgv">Теперь применяем это к нашему примеру:</p>
  <p id="ouox">✔️ <strong>Название</strong>:</p>
  <p id="SXFZ">UC‑1 Быстрое добавление продукта по штрих‑коду</p>
  <p id="cogJ">✔️ <strong>Основной актёр</strong>:</p>
  <p id="K2rc">Пользователь приложения</p>
  <p id="5niQ"><strong>Системы</strong>:</p>
  <p id="OpJC">Мобильное приложение, Back-сервис.</p>
  <p id="dJdP">✔️ <strong>Предусловия</strong>:</p>
  <p id="rmOJ">- Приложение получило разрешение на доступ к камере.</p>
  <p id="uOHw">- Устройство подключено к интернету.</p>
  <p id="ao6X">✔️ <strong>Основной сценарий:</strong></p>
  <p id="NPDa">1. Пользователь открывает экран «Добавить продукт» и нажимает «Сканер штрих‑кода»;</p>
  <p id="tzJN">2. Камера считывает шрих-код и отправляет POST /barcode/scan {code} на Backend;</p>
  <p id="5hri">3. Backend ищет у себя в кэше.</p>
  <p id="Uwre">- Если найден, возвращает нутриенты и калории.</p>
  <p id="EfEn">- Если не найден, то идет во внешних API.</p>
  <p id="Z7Kq">4. API отвечает 200 OK, Backend нормализует данные, рассчитывает калории по формуле, кладёт результат в кэш.</p>
  <p id="o9jW">5. Приложение показывает карточку продукта с БЖУ и кнопкой «Добавить в дневник».</p>
  <p id="ovR2">✔️ <strong>Альтернативы:</strong></p>
  <p id="y6fA">2А. Камера не запустилась — приложение предлагает ввести код вручную;</p>
  <p id="kbWy">3А. Внешний API вернул 404 — открывается форма ручного ввода нутриентов;</p>
  <p id="438p">3B. API отвалилась по таймауту — показывается заглушка «Сервис недоступен», предлагается сфотографировать этикетку;</p>
  <p id="tV4e">✔️ <strong>Постусловия:</strong></p>
  <p id="x2Pg">- При успешном сценарии - продукт сохранён в дневнике, данные кэшированы;</p>
  <p id="HKsV">- При ошибках пользователь получил понятный способ продолжить.</p>
  <p id="r79a">➖➖➖</p>
  <p id="XjeF"><strong>Такой подход</strong> к описанию постановки <strong>можно найти в Гугл, </strong>когда ты пытаешься экстренно разобраться, как решить задачу, которую перед тобой поставили, а ты не понимаешь с чего начать, а он предательски тебе выдал &quot;вот классный способ постановки&quot;.</p>
  <p id="KyCq">➖➖➖</p>
  <p id="I77N">Но <strong>что в этом подходе не так? </strong></p>
  <p id="iRBJ">❗️А то, что front разработчику вообще не нужно знать, что происходит на стороне back, а back разработчику может и важно, что там делает фронт, но скорее нет = <strong>ИЗБЫТОЧНОСТЬ, которая и порождает за собой лишние вопросы со стороны команды. </strong></p>
  <p id="B3Xh">➖➖➖</p>
  <p id="Olbb">Так <strong>что</strong> же <strong>важно</strong>, <strong>когда</strong> мы <strong>описываем UI</strong>?</p>
  <p id="KTCv">❗️<strong>Я в своей практике использую такой подход: разбиваю USE CASE на шаги и расписываю отдельно действия пользователя, и отдельно - системы, в рамках одного шага. </strong></p>
  <p id="1vJS">Вернемся к нашему примеру,</p>
  <p id="Hxyu">✔️ <strong>Название:</strong></p>
  <p id="ypwp">UC‑1 Быстрое добавление продукта по штрих‑коду</p>
  <p id="ZnHB"><strong>Шаг 1: </strong>Сканирование штрих-кода</p>
  <p id="dto5"><em>Действие пользователя: </em></p>
  <p id="5kN0">- Пользователь находится на экране добавления продукта;</p>
  <p id="x8a0">- Пользователь нажал кнопку «Сканировать штрих-код».</p>
  <p id="pO1b"><em>Действие системы:</em></p>
  <p id="a4xI">1. Система считывает штрих‑код и отправляет запрос:</p>
  <p id="myHM">Request: POST /barcode/scan {code} на Backend.</p>
  <p id="O1hn">Response: JSON</p>
  <p id="Ojvl">- если данные получены, то перейти к шагу: отображение карточки продукта с БЖУ;</p>
  <p id="k1Wm">- если данные не пришли, то перейти к шагу: ввод данных вручную.</p>
  <p id="Ttwh">Используя такой подход аналитик делает свои доки читаемыми и однозначными, что помогает избежать лишних вопросов со стороны команды 🥂</p>
  <p id="oWKX">➖➖➖</p>
  <p id="Ktwl"><strong>Почему самообучение — не всегда выход? </strong></p>
  <p id="rtyV">Когда ты ищешь информацию в инете, то часто она уровня &quot;обыватель&quot;.</p>
  <p id="TXbh">В итоге:</p>
  <p id="29TV">✖️ неясно, <strong>что действительно нужно учить, а что — пустая трата времени</strong>;</p>
  <p id="hcgG">✖️ нет обратной связи — ты <strong>не понимаешь, правильно ли всё усвоил;</strong></p>
  <p id="pyY9"><strong>✖️ </strong>нет структуры и целостного понимания.</p>
  <p id="0nfk"><strong>Что даёт мой курс? </strong></p>
  <p id="hMXk">✔️ <strong>БАЗУ</strong>, которая нужна и для работы, и техсобесов,</p>
  <p id="JImV">✔️ Много <strong>практики</strong>,</p>
  <p id="ONAA">✔️ Подробные комментарии к домашкам,</p>
  <p id="JOTp">✔️ И главное — <strong>мой личный опыт и подходы</strong>, которые превращают тебя не просто в аналитика, а в незаменимого специалиста, которого ценит команда</p>
  <p id="iIsW"></p>
  <h3 id="YxVT">ПОДПИСЫВАЙСЯ НА МОИ СОЦ СЕТИ:</h3>
  <p id="y7Gc"><strong><a href="https://instagram.com/pro.analitica" target="_blank">ИНСТА </a>| <a href="https://t.me/proanalitica" target="_blank">ТЕЛЕГРАМ </a>| <a href="https://www.youtube.com/@proanalitika" target="_blank">YOUTUBE </a>| <a href="https://vk.com/proanalitica" target="_blank">VK</a></strong></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@proanalitika/hUNapw3wQri</guid><link>https://teletype.in/@proanalitika/hUNapw3wQri?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=proanalitika</link><comments>https://teletype.in/@proanalitika/hUNapw3wQri?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=proanalitika#comments</comments><dc:creator>proanalitika</dc:creator><title>%D0%A2%D0%AB%20%D0%9A%D0%A0%D0%A3%D0%A2%D0%9E%D0%99%20%D0%90%D0%9D%D0%90%D0%9B%D0%98%D0%A2%D0%98%D0%9A</title><pubDate>Wed, 21 May 2025 07:35:25 GMT</pubDate><description><![CDATA[Как часто вы встречали такую крокозябру в текстах или в URL запросе?]]></description><content:encoded><![CDATA[
  <p id="jnOn">Как часто вы встречали такую крокозябру в текстах или в URL запросе?</p>
  <blockquote id="Msm8">Курс только начался, а у ребят уже есть вопросы на эту тему и я хочу поделится ответом и с вами тоже.</blockquote>
  <p id="C3sh">Кто-то думает, что это защита шифрование SSL, но нет это не так.</p>
  <p id="q8pe">✔️ Это <strong>encoding</strong> — это когда твоя строка превращается в безопасный формат для URL.</p>
  <p id="Byrp">Любой браузер, может передать ограниченные символы и если мы хотим передать, например, кириллицу или кавычку, то чтобы сервер или браузер не свалились, нам понадобится их превратить в разрешенные.</p>
  <p id="XaTx">Самый частый пример, где мы можем встретить encoding, это в поисковиках. Попробуйте вбить в Google слово матрешка и посмотрите в консоль разработчика.</p>
  <p id="1oFU">Там вы увидите вместо нормального слова - это</p>
  <p id="isWI">https://www.google.com/search?q=%D0%BC%D0%B0%D1%82%D1%80%D0%B5%D1%88%D0%BA%D0%B0</p>
  <p id="XhJv">Еще, понимание, что это такое, может нам пригодится при разборе логов, потому что запрос прилетит именно в таком виде.</p>
  <p id="rlBV">➖➖➖</p>
  <p id="Wxnk">Но, как понять, что закодировано в сообщении, если мы не знаем изначальный запрос?</p>
  <p id="nswW">✔️ Нам нужно сделать <strong>decoding</strong> – обратное превращение закодированной строки в обычную.</p>
  <p id="uOus">Обычно, если мы отправили запрос из браузера на сервер, то <strong>декодингом занимается сервер,</strong> но если вдруг вам нужно понять, что в тексте, то <strong>вы можете сделать декодинг сами. </strong></p>
  <p id="QX6t">Самый сложный вариант - это найти <strong>таблицу UTF-8</strong> и посмотреть, что значит конкретный символ.</p>
  <p id="jpMO">Например, <strong>буква М будет выглядеть так %D0%BC</strong></p>
  <p id="c8Ag">Этим заниматься - это как-будто откатиться в прошлое и воспользоваться бумажным словарем для перевода английского слова вместо переводчика, поэтому лучше - <strong>воспользоваться спец сервисом по декодингу или нейронкой. </strong></p>
  <p id="8EoR">Сервисов много.</p>
  <p id="Iwqt">💾 Например, <strong>https://www.urldecoder.org/ru</strong></p>
  <p id="KMRc">✔️ переходим по ссылке,</p>
  <p id="CCDY">✔️ вбиваем наши кракозябры,</p>
  <p id="J5fy">✔️ нажимаем декодировать</p>
  <p id="O9gM">🪄 <strong>вуаля, у вас нормальная строка</strong></p>
  <p id="vVyM">Го декодировать заголовок  🥂</p>
  <p id="LkqN"></p>
  <p id="Vso9"></p>
  <h3 id="YxVT">ПОДПИСЫВАЙСЯ НА МОИ СОЦ СЕТИ:</h3>
  <p id="y7Gc"><strong><a href="https://instagram.com/pro.analitica" target="_blank">ИНСТА </a>| <a href="https://t.me/proanalitica" target="_blank">ТЕЛЕГРАМ </a>| <a href="https://www.youtube.com/@proanalitika" target="_blank">YOUTUBE </a>| <a href="https://vk.com/proanalitica" target="_blank">VK</a></strong></p>

]]></content:encoded></item></channel></rss>