<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <title>Tune IT</title>
  <link rel="self" href="" />
  <subtitle>Tune IT</subtitle>
  <id />
  <updated>2026-09-12T12:15:03Z</updated>
  <dc:date>2026-09-12T12:15:03Z</dc:date>
  <entry>
    <title>Проверяем SSO сессию в открытой вкладке</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21304495" />
    <author>
      <name>Maxim Kalabukhov</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21304495</id>
    <updated>2026-09-09T16:19:25Z</updated>
    <published>2026-09-09T16:15:00Z</published>
    <summary type="html">&lt;p&gt;В одном из проектов мне понадобилось отслеживать состояние SSO-сессии на уже открытой странице. Пользователь выходит из SSO через другое приложение, а наш фронт продолжает показывать прежний интерфейс. Хотелось, чтобы страница сама узнавала об изменении и подтягивала актуальное состояние пользователя.&lt;/p&gt;

&lt;p&gt;Механизм описан в &lt;a href="https://openid.net/specs/openid-connect-session-1_0.html"&gt;OpenID Connect Session Management 1.0&lt;/a&gt;. Дальше расскажу, как я встраивал этот механизм в проект на React и Django с Keycloak.&lt;/p&gt;

&lt;h2&gt;Как я это реализовал&lt;/h2&gt;

&lt;p&gt;Авторизация в приложении уже работала: браузер уходил в Keycloak, возвращался на callback, backend создавал Django сессию. Полученный при входе &lt;code&gt;session_state&lt;/code&gt; сохранялся на сервере. Его и предстояло передавать на фронт для последующих проверок.&lt;/p&gt;

&lt;p&gt;На фронте я вынес мониторинг в отдельный React-компонент &lt;code&gt;SsoSessionManager&lt;/code&gt;. Он подключается при наличии авторизованного пользователя, ничего не рисует и управляет двумя скрытыми iframe. Один живёт всё время работы manager, второй появляется только для уточнения состояния сессии. Авторизация и работа с токенами оставались на бэкенде, а фронту требовались конфигурация проверки и её результат.&lt;/p&gt;

&lt;p&gt;Чтобы фронт мог получить контекст мониторинга, а backend - отдельно от обычного логина уточнить SSO-сессию и обработать результат, я добавил три новые ручки: &lt;code&gt;GET /api/auth/sso-session&lt;/code&gt; отдаёт конфигурацию и сохранённый &lt;code&gt;session_state&lt;/code&gt;, &lt;code&gt;GET /auth/sso-session/start&lt;/code&gt; подготавливает временный флоу авторизации и перенаправляет iframe в Keycloak, а &lt;code&gt;GET /auth/sso-session/callback&lt;/code&gt; обрабатывает ответ Keycloak и возвращает HTML во временный iframe. Скрипт этого документа передаёт результат проверки родительской странице через postMessage.&lt;/p&gt;

&lt;p&gt;Постоянный iframe загружает &lt;code&gt;login-status-iframe.html&lt;/code&gt; из Keycloak. После загрузки &lt;code&gt;SsoSessionManager&lt;/code&gt; отправляет в него через &lt;code&gt;postMessage&lt;/code&gt; строку &lt;code&gt;client_id + " " + session_state&lt;/code&gt;. Пока вкладка скрыта, опрос SSO приостанавливается, а при возвращении проверка запускается снова. Всего, при опросе SSO, может вернуться 3 состояния: При &lt;code&gt;unchanged&lt;/code&gt; продолжаем проверять. При &lt;code&gt;changed&lt;/code&gt; останавливаем опрос и создаём временный iframe с адресом &lt;code&gt;/auth/sso-session/start&lt;/code&gt;. Сам по себе &lt;code&gt;changed&lt;/code&gt; ещё не сообщает, нужно ли завершать локальную сессию, поэтому дальше разбирается backend. При &lt;code&gt;error&lt;/code&gt; manager отключает мониторинг для текущей страницы.&lt;/p&gt;

&lt;p&gt;Ручка &lt;code&gt;/start&lt;/code&gt; проверяет локальную сессию, создаёт одноразовые &lt;code&gt;state&lt;/code&gt; и &lt;code&gt;nonce&lt;/code&gt;, сохраняет ожидаемого пользователя. Затем перенаправляет временный iframe на авторизационную ручку Keycloak с &lt;code&gt;prompt=none&lt;/code&gt;. Этот параметр запрещает показывать форму логина и другие интерактивные экраны. Keycloak пытается выполнить запрос на основе уже существующего входа в браузере: если это возможно, возвращает code, но если нужно участие пользователя, то возвращает ошибку. Для нас это способ уточнить состояние SSO в скрытом iframe, не уводя пользователя с открытой страницы и не заставляя его снова вводить пароль.&lt;/p&gt;

&lt;p&gt;Чтобы уточнить состояние входа в Keycloak без участия пользователя, &lt;code&gt;SsoSessionManager&lt;/code&gt; задаёт временному iframe &lt;code&gt;src="https://www.tune-it.ru/auth/sso-session/start"&lt;/code&gt;. Браузер проходит внутри этого iframe цепочку редиректов для проверки входа в Keycloak, а &lt;code&gt;/auth/sso-session/callback&lt;/code&gt; отдаёт небольшой HTML со скриптом, вызывающим &lt;code&gt;window.parent.postMessage&lt;/code&gt;, который отправляет результат родительской странице.&lt;/p&gt;

&lt;p&gt;Когда Keycloak возвращает code на &lt;code&gt;/auth/sso-session/callback&lt;/code&gt;, Django обменивает его на токены отдельным серверным запросом. Backend делает необходимые проверки, затем сверяет &lt;code&gt;sub&lt;/code&gt; с ожидаемым и текущим локальным пользователем. Если пользователь тот же, то сохраняется новый &lt;code&gt;session_state&lt;/code&gt;. Инные случаи приводят к завершению локальной сессии. &lt;code&gt;SsoSessionManager&lt;/code&gt; проверяет origin, окно-источник и структуру сообщения. Если пришёл &lt;code&gt;session_updated&lt;/code&gt;, забирает новый &lt;code&gt;session_state&lt;/code&gt;, удаляет временный iframe и возобновляет опрос SSO. Если &lt;code&gt;logged_out&lt;/code&gt; - отключает мониторинг и обновляет страницу.&lt;/p&gt;</summary>
    <dc:creator>Maxim Kalabukhov</dc:creator>
    <dc:date>2026-09-09T16:15:00Z</dc:date>
  </entry>
  <entry>
    <title>Продвинутая типографика в вебе, как делать текст быстрым и красивым</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21304195" />
    <author>
      <name>Алексей Кондратьев</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21304195</id>
    <updated>2026-09-08T21:07:57Z</updated>
    <published>2026-09-08T21:03:00Z</published>
    <summary type="html">&lt;p&gt;Каждый, кто пользуется интернетом, сталкивался с ситуацией, когда текст на сайте сначала показывается одним шрифтом, а через секунду «прыгает», меняя размер и положение, когда подгружается «правильное» начертание. Или страница вовсе отказывается показывать текст, пока не загрузятся все шрифты. Подобные сценарии не просто раздражают — они разрушают пользовательский опыт, портят поведенческие метрики и заставляют людей уходить, так и не дождавшись содержимого.&lt;/p&gt;

&lt;p&gt;Типографика в вебе — это всегда компромисс между красотой и скоростью. Между тем, как вы хотите, чтобы выглядел ваш проект, и тем, как быстро он будет загружаться.&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;Вариативные шрифты: Один файл вместо двадцати&lt;/h2&gt;

&lt;p&gt;Раньше, чтобы использовать шрифт в разных начертаниях, нужно было подключать отдельные файлы: Roboto Regular, Roboto Bold, Roboto Italic, Roboto Bold Italic… И так для каждого веса и стиля. Это создавало кучу HTTP-запросов и заставляло пользователя скачивать мегабайты данных. Вариативные шрифты решили эту проблему кардинально.&lt;/p&gt;

&lt;p&gt;Один файл — и внутри него все варианты: от самого тонкого до самого жирного, от узкого до широкого, с курсивом и без. Это дало колоссальную свободу. Вы больше не привязаны к фиксированным значениям вроде 400 или 700. Хотите вес 437? Пожалуйста. 582? Без проблем. Вы можете плавно менять толщину шрифта в зависимости от контекста, создавая более тонкую и выразительную типографику.&lt;/p&gt;

&lt;p&gt;Технически это работает через так называемые «оси вариаций» — параметры, которые можно настраивать. Основные оси стандартизированы: это вес (wght), ширина (wdth), и курсив (ital). Но производители шрифтов могут добавлять и свои, уникальные оси — например, для изменения наклона или даже размера засечек.&lt;/p&gt;

&lt;p&gt;Важный нюанс: если вы подключаете вариативный шрифт, в CSS вам не нужно указывать конкретный вес при загрузке. Вместо weight: '400' вы просто пишете weight: 'variable', а затем используете свойство font-variation-settings, чтобы управлять всеми доступными осями. Это невероятно гибко и мощно.&lt;/p&gt;

&lt;h2&gt;Модульные шкалы и математика текста&lt;/h2&gt;

&lt;p&gt;Красивая типографика не рождается из хаоса. Она подчиняется математике. В основе лежит понятие модульной шкалы — последовательности чисел, где каждое следующее получается из предыдущего путем умножения на постоянный коэффициент. Например, коэффициент 1.25 даёт малую терцию, 1.333 — чистую кварту, а 1.618 — знаменитое золотое сечение.&lt;/p&gt;

&lt;p&gt;Зачем это нужно? Чтобы все размеры текста на вашем сайте — от самого маленького подписи до огромного заголовка — были ритмически связаны друг с другом. Глаз чувствует эту гармонию, даже если вы не можете объяснить её словами. Это создает ощущение цельности и профессионализма.&lt;/p&gt;

&lt;p&gt;Современные инструменты позволяют автоматизировать этот процесс. Например, есть специальные утилиты, которые генерируют CSS-переменные для каждого шага шкалы, а заодно добавляют к ним плавную адаптивность . Задача дизайнера — не считать вручную, а выбрать правильное соотношение и проверить, насколько хорошо оно работает в контексте проекта.&lt;/p&gt;

&lt;h2&gt;Адаптивная типографика: Когда текст сам знает, где находится&lt;/h2&gt;

&lt;p&gt;Помните старый добрый способ: для мобильных экранов — один размер, для планшетов — чуть больше, для десктопов — ещё больше? Это работало, но с одним недостатком: на промежуточных размерах, между вашими брейкпоинтами, текст выглядел либо слишком маленьким, либо слишком большим.&lt;/p&gt;

&lt;p&gt;Современный подход — жидкая типографика (fluid typography) на основе CSS-функции clamp(). Вместо того чтобы задавать фиксированные значения для разных разрешений, вы определяете диапазон: минимальный размер, максимальный размер и скорость изменения между ними.&lt;/p&gt;

&lt;p&gt;Например, вы пишете: font-size: clamp(1rem, 2vw + 0.5rem, 2.5rem). Это значит: «На маленьких экранах размер будет не меньше 1rem, на больших — не больше 2.5rem, а между ними он будет плавно меняться в зависимости от ширины окна». Текст не делает резких скачков. Он словно «дышит» вместе с экраном.&lt;/p&gt;

&lt;p&gt;Некоторые системы идут дальше. Они генерируют целые шкалы clamp() — для каждого типографического уровня, от самого маленького до самого большого. И делают это не только для размера шрифта, но и для интерлиньяжа, отступов, ширины колонок . Результат — интерфейс, который выглядит одинаково гармонично на любом устройстве: от маленького телефона до огромного 4K-монитора.&lt;/p&gt;

&lt;h2&gt;Загрузка шрифтов: Битва с FOUT и FOIT&lt;/h2&gt;

&lt;p&gt;Самая большая боль веб-типографики — это то, как браузер ведёт себя, пока шрифт не загрузился. Здесь у нас два злодея:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;FOIT (Flash of Invisible Text) — текст не показывается вообще. Вы видите пустую страницу с картинками, но без единой буквы. Это ужасно для пользовательского опыта .&lt;/li&gt;
	&lt;li&gt;FOUT (Flash of Unstyled Text) — текст показывается системным шрифтом (например, Arial), а потом, когда загружается ваш красивый шрифт, он «перепрыгивает». В этот момент может произойти смещение макета, потому что размеры шрифтов отличаются . Это бьёт по показателю Cumulative Layout Shift (CLS) в Core Web Vitals.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;И то, и другое плохо. Спасает нас свойство font-display. Его можно задать внутри @font-face. Вариантов несколько:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;swap — показывает системный шрифт сразу, а когда загрузится ваш — заменяет его. Это даёт быстрый FCP (First Contentful Paint), но вы рискуете получить FOUT и смещение.&lt;/li&gt;
	&lt;li&gt;fallback — даёт браузеру 100 миллисекунд на ожидание (текст скрыт), потом показывает системный. Если через 3 секунды шрифт не загрузился — системный остаётся навсегда. Хороший компромисс.&lt;/li&gt;
	&lt;li&gt;optional — ещё более строгий вариант. Если шрифт не загрузился за 100 мс, он больше никогда не заменится. Это полностью предотвращает смещение, но ваш «красивый» шрифт может так и не появиться.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Самый надежный способ избежать проблем — использовать font-display: swap в сочетании с предзагрузкой (preload) критически важных шрифтов. Вы говорите браузеру: «Загрузи этот шрифт в первую очередь, он очень нужен». Это ускоряет загрузку, но злоупотреблять не стоит.&lt;/p&gt;

&lt;p&gt;Кстати, современные фреймворки вроде Next.js решают эту проблему автоматически. Они сами хостят шрифты на вашем сервере, подгружают их на этапе сборки, а сгенерированный CSS использует технику size-adjust, чтобы системный шрифт и ваш шрифт занимали одинаковое пространство. Таким образом, даже до загрузки вашего шрифта нет смещения макета — текст просто «обновляется» внешне, но не дергается.&lt;/p&gt;

&lt;h2&gt;Практические шаги к идеальной типографике&lt;/h2&gt;

&lt;ol&gt;
	&lt;li&gt;Выбор шрифта. Отдавайте предпочтение вариативным шрифтам. Это даёт гибкость и экономию трафика. Используйте WOFF2 — самый сжатый современный формат.&lt;/li&gt;
	&lt;li&gt;Построение модульной шкалы. Используйте инструменты для генерации типографической шкалы с выбранным коэффициентом (например, малая терция 1.25 или идеальная кварта 1.333). Сгенерируйте CSS-переменные для каждого размера.&lt;/li&gt;
	&lt;li&gt;Адаптивность. Примените clamp() к вашим переменным. Не для всех сразу, а с умом: для заголовков — более широкий диапазон (чтобы они были действительно разными на большом и маленьком экране), для основного текста — более узкий.&lt;/li&gt;
	&lt;li&gt;Загрузка. Используйте font-display: swap. Предзагружайте только один-два самых важных шрифта — те, что сразу видны на первом экране. Остальные могут загружаться лениво.&lt;/li&gt;
	&lt;li&gt;Проверка. Обязательно смотрите на сайт через Lighthouse. Он подскажет, нет ли проблем с CLS или с тем, что текст остаётся невидимым.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Типографика — это не просто «выбрать красивый шрифт». Это сложная инженерная задача, которая требует понимания как эстетики, так и технологий. Но когда вы находите правильный баланс, текст на вашем сайте становится не просто читаемым, а по-настоящему живым: быстрым, плавным и гармоничным. И это то, что пользователи чувствуют, даже если не могут объяснить почему.&lt;br /&gt;
&amp;nbsp;&lt;/p&gt;</summary>
    <dc:creator>Алексей Кондратьев</dc:creator>
    <dc:date>2026-09-08T21:03:00Z</dc:date>
  </entry>
  <entry>
    <title>Полезные Maven/Gradle плагины для Liferay разработки</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21303697" />
    <author>
      <name>Никита Рогаленко</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21303697</id>
    <updated>2026-09-07T15:38:55Z</updated>
    <published>2026-09-07T15:36:00Z</published>
    <summary type="html">&lt;p style="text-align: justify;"&gt;Разработка&amp;nbsp; корпоративных решений и интранет-порталов на базе Liferay требует управления сложной экосистемой, включая инициализацию серверов приложений, сборку различных модулей, работу с базой данных и REST-эндпоинтами. Чтобы ускорить разработку, Liferay предоставляет специализированный инструментарий в форме плагинов для популярных систем сборки, таких как Gradle и Maven.&amp;nbsp;В этой заметке мы представим краткий обзор некоторых таких плагинов, которые позволяют автоматизировать рутинные операции и сделать процесс разработки эффективнее. Сегодня в нашей подборке 4 плагина&lt;/p&gt;

&lt;h3 style="text-align: justify;"&gt;1. com.liferay.portal.tools.bundle.support&lt;/h3&gt;

&lt;p style="text-align: justify;"&gt;Представляет собой плагин для инфраструктуры,&amp;nbsp;управления окружением и CI/CD. Реализует парадигму «Инфраструктура как код», позволяя избавиться от ручного скачивания архивов портала, распаковки и самостоятельного копирования конфигураций. Этот плагин берет под свой контроль весь жизненный цикл Liferay бандла.&amp;nbsp;На основе указанного URL или версии плагин скачивает сборку сервера (например, Tomcat bundle) и кэширует архив в локальной файловой системе сборщика. Также плагин полностью очищает целевую директорию и разворачивает чистый инстанс Liferay, убирая все временные файлы, которые могут помешать деплою, исключая тем самым появление мусорных артефактов и кэша от старых запусков.&amp;nbsp;Плагин также может накладывать файлы настроек (такие как portal-ext.properties или system-ext.properties) поверх чистого лайфрея в зависимости от выбранного профиля сборки (например, local, dev, test). Конфигурация разбивается на шаги (executions) в рамках конкретных фаз жизненного цикла (покажем пример для maven):&lt;/p&gt;

&lt;pre class="brush:xml;"&gt;
&amp;lt;project xmlns="http://apache.org" 
         xmlns:xsi="http://w3.org"
         xsi:schemaLocation="http://apache.org http://apache.org"&amp;gt;
    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;

    &amp;lt;groupId&amp;gt;com.example.liferay&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;liferay-workspace-project&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.0.0-SNAPSHOT&amp;lt;/version&amp;gt;
    &amp;lt;packaging&amp;gt;pom&amp;lt;/packaging&amp;gt;

    &amp;lt;properties&amp;gt;
        &amp;lt;liferay.portal.tools.bundle.support.version&amp;gt;3.7.10&amp;lt;/liferay.portal.tools.bundle.support.version&amp;gt;
        &amp;lt;liferay.bundle.dir&amp;gt;${project.basedir}/bundles&amp;lt;/liferay.bundle.dir&amp;gt;
    &amp;lt;/properties&amp;gt;

    &amp;lt;build&amp;gt;
        &amp;lt;plugins&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;com.liferay&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;com.liferay.portal.tools.bundle.support&amp;lt;/artifactId&amp;gt;
                &amp;lt;version&amp;gt;${liferay.portal.tools.bundle.support.version}&amp;lt;/version&amp;gt;
                
                &amp;lt;executions&amp;gt;
                    &amp;lt;!-- Полная очистка перед сборкой новой среды --&amp;gt;
                    &amp;lt;execution&amp;gt;
                        &amp;lt;id&amp;gt;clean-local-bundle&amp;lt;/id&amp;gt;
                        &amp;lt;!-- Привязываем к стандартной фазе clean --&amp;gt;
                        &amp;lt;phase&amp;gt;clean&amp;lt;/phase&amp;gt;
                        &amp;lt;goals&amp;gt;
                            &amp;lt;goal&amp;gt;clean-bundle&amp;lt;/goal&amp;gt;
                        &amp;lt;/goals&amp;gt;
                    &amp;lt;/execution&amp;gt;

                    &amp;lt;!-- Скачивание и разворачивание чистого Liferay Bundle --&amp;gt;
                    &amp;lt;execution&amp;gt;
                        &amp;lt;id&amp;gt;initialize-liferay-server&amp;lt;/id&amp;gt;
                        &amp;lt;!-- Привязываем к фазе инициализации проекта --&amp;gt;
                        &amp;lt;phase&amp;gt;initialize&amp;lt;/phase&amp;gt;
                        &amp;lt;goals&amp;gt;
                            &amp;lt;goal&amp;gt;init-bundle&amp;lt;/goal&amp;gt;
                        &amp;lt;/goals&amp;gt;
                        &amp;lt;configuration&amp;gt;
                            &amp;lt;!-- URL для загрузки дистрибутива --&amp;gt;
                            &amp;lt;bundleURL&amp;gt;your URL&amp;lt;/bundleURL&amp;gt;
                            &amp;lt;!-- Куда распаковывать --&amp;gt;
                            &amp;lt;destDir&amp;gt;${project.basedir}&amp;lt;/destDir&amp;gt;
                        &amp;lt;/configuration&amp;gt;
                    &amp;lt;/execution&amp;gt;

                    &amp;lt;!-- Деплой  --&amp;gt;
                    &amp;lt;execution&amp;gt;
                        &amp;lt;id&amp;gt;deploy-global-configs&amp;lt;/id&amp;gt;
                        &amp;lt;!-- Выполняется на этапе валидации или перед деплоем модулей --&amp;gt;
                        &amp;lt;phase&amp;gt;validate&amp;lt;/phase&amp;gt;
                        &amp;lt;goals&amp;gt;
                            &amp;lt;goal&amp;gt;deploy&amp;lt;/goal&amp;gt;
                        &amp;lt;/goals&amp;gt;
                        &amp;lt;configuration&amp;gt;
                            &amp;lt;bundleDir&amp;gt;${liferay.bundle.dir}&amp;lt;/bundleDir&amp;gt;
                            &amp;lt;!-- Копируем кастомные конфиги --&amp;gt;
                            &amp;lt;configsDir&amp;gt;${project.basedir}/configs/local&amp;lt;/configsDir&amp;gt;
                        &amp;lt;/configuration&amp;gt;
                    &amp;lt;/execution&amp;gt;
                &amp;lt;/executions&amp;gt;
            &amp;lt;/plugin&amp;gt;
        &amp;lt;/plugins&amp;gt;
    &amp;lt;/build&amp;gt;
&amp;lt;/project&amp;gt;
&lt;/pre&gt;

&lt;p style="text-align: justify;"&gt;Кроме того, возможно использование локального бандла (уже собранного), что особенно актуально при использовании Wildfly:&lt;/p&gt;

&lt;pre class="brush:xml;"&gt;
 &amp;lt;configuration&amp;gt;
        &amp;lt;appServerType&amp;gt;wildfly&amp;lt;/appServerType&amp;gt;
        &amp;lt;appServerBundleDir&amp;gt;${project.basedir}/bundles/wildfly&amp;lt;/appServerBundleDir&amp;gt;
        &amp;lt;!-- директория Liferay Home для этого бандла --&amp;gt;
        &amp;lt;liferayHome&amp;gt;${project.basedir}/bundles&amp;lt;/liferayHome&amp;gt;
 &amp;lt;/configuration&amp;gt;&lt;/pre&gt;

&lt;h3 style="text-align: justify;"&gt;2. com.liferay.portal.tools.service.builder&lt;/h3&gt;

&lt;p style="text-align: justify;"&gt;Представляет собой плагин для генерации&amp;nbsp;слоя доступа к данным (Java-классы, интерфейсы, SQL-скрипты, Hibernate/Spring-конфигурации) на основе одного XML-файла описания. Создает интерфейсы и базовые реализации для сервисов, генерирует DDL, обновляет базу и многое другое:&lt;/p&gt;

&lt;pre class="brush:xml;"&gt;
&amp;lt;plugin&amp;gt;
    &amp;lt;groupId&amp;gt;com.liferay&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;com.liferay.portal.tools.service.builder&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.0.420&amp;lt;/version&amp;gt;
    &amp;lt;executions&amp;gt;
        &amp;lt;execution&amp;gt;
            &amp;lt;id&amp;gt;generate-service&amp;lt;/id&amp;gt;
            &amp;lt;!-- Привязываем генерацию к фазе generate-sources, до компиляции Java --&amp;gt;
            &amp;lt;phase&amp;gt;generate-sources&amp;lt;/phase&amp;gt;
            &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;build-service&amp;lt;/goal&amp;gt;
            &amp;lt;/goals&amp;gt;
            &amp;lt;configuration&amp;gt;
                &amp;lt;!-- Главный файл с описанием сущностей и базы данных --&amp;gt;
                &amp;lt;inputFile&amp;gt;${project.basedir}/src/main/resources/META-INF/service.xml&amp;lt;/inputFile&amp;gt;
                
                &amp;lt;!-- Куда сгенерируются интерфейсы и DTO --&amp;gt;
                &amp;lt;apiDir&amp;gt;${project.parent.basedir}/my-app-api/src/main/java&amp;lt;/apiDir&amp;gt;
                
                &amp;lt;!-- Куда сгенерируется бизнес-логика и реализация --&amp;gt;
                &amp;lt;implDir&amp;gt;${project.basedir}/src/main/java&amp;lt;/implDir&amp;gt;
                
                &amp;lt;!-- Папка для генерации SQL-скриптов создания таблиц и индексов --&amp;gt;
                &amp;lt;sqlDir&amp;gt;${project.basedir}/src/main/resources/META-INF/sql&amp;lt;/sqlDir&amp;gt;
                
                &amp;lt;!-- Включать ли генерацию REST/JSON веб-сервисов --&amp;gt;
                &amp;lt;buildRemoteService&amp;gt;true&amp;lt;/buildRemoteService&amp;gt;
               
                &amp;lt;!-- Включать ли генерацию локальных Java-сервисов --&amp;gt;
                &amp;lt;buildLocalService&amp;gt;true&amp;lt;/buildLocalService&amp;gt;

            &amp;lt;/configuration&amp;gt;
        &amp;lt;/execution&amp;gt;
    &amp;lt;/executions&amp;gt;
&amp;lt;/plugin&amp;gt;&lt;/pre&gt;

&lt;p style="text-align: justify;"&gt;Чтобы плагин сработал, ему нужен файл конфигурации, где разработчик декларативно описывает сущности базы данных и их связи. Плагин же создает сотни строк сопутствующего кода. Вот минимальный пример файла src/main/resources/META-INF/service.xml для таблицы БД:&lt;/p&gt;

&lt;pre class="brush:xml;"&gt;
&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 7.4.0//EN" "http://liferay.com"&amp;gt;

&amp;lt;service-builder dependency-injector="ds" package-path="com.example.myapp"&amp;gt;
    &amp;lt;namespace&amp;gt;MYAPP&amp;lt;/namespace&amp;gt;
    
        &amp;lt;!-- Первичный ключ --&amp;gt;
        &amp;lt;column name="bookId" type="long" primary="true" /&amp;gt;
        
        &amp;lt;!-- Поля таблицы --&amp;gt;
        &amp;lt;column name="title" type="String" /&amp;gt;
        &amp;lt;column name="author" type="String" /&amp;gt;
        &amp;lt;column name="createDate" type="Date" /&amp;gt;
        
        &amp;lt;!-- Индекс для быстрого поиска по автору --&amp;gt;
        &amp;lt;finder name="Author" return-type="Collection"&amp;gt;
            &amp;lt;finder-column name="author" /&amp;gt;
        &amp;lt;/finder&amp;gt;
    
&amp;lt;/service-builder&amp;gt;
&lt;/pre&gt;

&lt;h3 style="text-align: justify;"&gt;3. com.liferay.portal.tools.rest.builder&lt;/h3&gt;

&lt;p style="text-align: justify;"&gt;Представляет собой плагин для генерации API&amp;nbsp;(эндпоинты, схемы запросов/ответов). Разработчик описывает&amp;nbsp;контракт своего API в стандартном формате OpenAPI (YAML), а плагин автоматически генерирует JAX-RS эндпоинты, DTO-модели, валидацию и Jackson-маппинг. Разработчику остаётся только написать бизнес-логику в классах реализации. Кроме того, плагин автоматически разворачивает эндпоинты в интерфейсе Swagger UI портала, делая API доступным для тестирования фронтенд-разработчиками сразу после деплоя бандла. Подключается так:&lt;/p&gt;

&lt;pre class="brush:xml;"&gt;
&amp;lt;plugin&amp;gt;
    &amp;lt;groupId&amp;gt;com.liferay&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;com.liferay.portal.tools.rest.builder&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.0.475&amp;lt;/version&amp;gt;
    &amp;lt;executions&amp;gt;
        &amp;lt;execution&amp;gt;
            &amp;lt;id&amp;gt;generate-headless-api&amp;lt;/id&amp;gt;
            &amp;lt;phase&amp;gt;generate-sources&amp;lt;/phase&amp;gt;
            &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;build&amp;lt;/goal&amp;gt;
            &amp;lt;/goals&amp;gt;
            &amp;lt;configuration&amp;gt;
                &amp;lt;!-- Базовая папка, где лежат YAML схемы (rest-config.yaml, rest-openapi.yaml) --&amp;gt;
                &amp;lt;baseDir&amp;gt;${project.basedir}&amp;lt;/baseDir&amp;gt;
                
                &amp;lt;!-- Относительный путь к подмодулю API, куда попадут сгенерированные интерфейсы --&amp;gt;
                &amp;lt;apiDir&amp;gt;../my-headless-api/src/main/java&amp;lt;/apiDir&amp;gt;
                
                &amp;lt;!-- Путь в текущем модуле, куда попадет реализация REST --&amp;gt;
                &amp;lt;implDir&amp;gt;src/main/java&amp;lt;/implDir&amp;gt;
            &amp;lt;/configuration&amp;gt;
        &amp;lt;/execution&amp;gt;
    &amp;lt;/executions&amp;gt;
&amp;lt;/plugin&amp;gt;&lt;/pre&gt;

&lt;p style="text-align: justify;"&gt;Для генерации API требуются два файла в модуле:&lt;/p&gt;

&lt;ul&gt;
	&lt;li style="text-align: justify;"&gt;rest-openapi.yaml -- стандартное описание путей, методов (GET/POST/PUT) и моделей данных по спецификации OpenAPI 3.0.&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="brush:as3;"&gt;
openapi: 3.0.0
info:
  title: "My Custom API"
  version: v1.0
paths:
  /todos:
    get:
      operationId: getTodosPage
      description: "Получить список задач"
      responses:
        200:
          description: "Успешный ответ"
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Todo"
components:
  schemas:
    Todo:
      type: object
      properties:
        id:
          type: integer
          format: int64
        title:
          type: string
        completed:
          type: boolean
&lt;/pre&gt;

&lt;ul&gt;
	&lt;li style="text-align: justify;"&gt;rest-config.yaml -- служебный файл Liferay, задает метаданные плагина, включая базовые пакеты, автора и системный контекст для OSGi:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="brush:as3;"&gt;
apiPackagePath: "com.example.headless.api"
author: "Liferay Developer"
clientDir: "../my-headless-client/src/main/java" # если нужен клиент
compatibilityVersion: "7.4.0"
implPackagePath: "com.example.headless.internal"
jaxRsApplicationBaseUri: "/my-custom-api"
jaxRsApplicationName: "MyCustomAPI"&lt;/pre&gt;

&lt;h3 style="text-align: justify;"&gt;4. com.liferay.css.builder&lt;/h3&gt;

&lt;p style="text-align: justify;"&gt;Представляет собой плагин,&amp;nbsp;который компилирует файлы стилей Sass (.scss) в стандартный CSS.&amp;nbsp;В экосистеме Liferay этот плагин критически важен при сборке кастомных тем оформления, а также при стилизации отдельных портлетов и UI-компонентов. Он автоматически подтягивает глобальные стили ядра Liferay, обрабатывает импорты, миксины, переменные и минифицирует итоговый код. То есть&amp;nbsp;CSS Builder предстает как Java-обертка над компилятором Sass, полностью интегрированная в сборочные контейнеры Gradle и Maven. Подключение на примере Maven:&lt;/p&gt;

&lt;pre class="brush:xml;"&gt;
&amp;lt;plugin&amp;gt;
    &amp;lt;groupId&amp;gt;com.liferay&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;com.liferay.css.builder&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;3.1.2&amp;lt;/version&amp;gt;
    &amp;lt;executions&amp;gt;
        &amp;lt;execution&amp;gt;
            &amp;lt;id&amp;gt;compile-sass-to-css&amp;lt;/id&amp;gt;
            &amp;lt;!-- Привязываем компиляцию стилей к фазе генерации ресурсов --&amp;gt;
            &amp;lt;phase&amp;gt;generate-resources&amp;lt;/phase&amp;gt;
            &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;build&amp;lt;/goal&amp;gt;
            &amp;lt;/goals&amp;gt;
            &amp;lt;configuration&amp;gt;
                &amp;lt;!-- Директория, где лежат исходные файлы .scss --&amp;gt;
                &amp;lt;docRootDir&amp;gt;${project.basedir}/src/main/resources/META-INF/resources&amp;lt;/docRootDir&amp;gt;
                
                &amp;lt;!-- Подкаталог внутри docRootDir, где непосредственно искать .scss файлы --&amp;gt;
                &amp;lt;inputDir&amp;gt;/&amp;lt;/inputDir&amp;gt;
                
                &amp;lt;!-- Куда складывать скомпилированные .css файлы --&amp;gt;
                &amp;lt;outputDir&amp;gt;/&amp;lt;/outputDir&amp;gt;
                
                &amp;lt;!-- Включать ли генерацию Source Maps для удобной отладки в браузере --&amp;gt;
                &amp;lt;generateSourceMap&amp;gt;true&amp;lt;/generateSourceMap&amp;gt;
                
                &amp;lt;!-- Стили, которые нужно исключить из прямой компиляции  --&amp;gt;
                &amp;lt;compilerExcludes&amp;gt;**/_*.scss&amp;lt;/compilerExcludes&amp;gt;
                
                &amp;lt;!-- Пути к сторонним Sass-библиотекам или темам --&amp;gt;
                &amp;lt;importPaths&amp;gt;
                    &amp;lt;importPath&amp;gt;${project.basedir}/src/main/resources/META-INF/resources/node_modules&amp;lt;/importPath&amp;gt;
                &amp;lt;/importPaths&amp;gt;
            &amp;lt;/configuration&amp;gt;
        &amp;lt;/execution&amp;gt;
    &amp;lt;/executions&amp;gt;
&amp;lt;/plugin&amp;gt;&lt;/pre&gt;

&lt;h3 style="text-align: justify;"&gt;Итог&lt;/h3&gt;

&lt;p style="text-align: justify;"&gt;В заключение отметим, что комбинация этих четырех плагинов закрывает базовые потребности команды разработки, обеспечивая автоматизацию проекта на всех уровнях: от инфраструктурного слоя до баз данных, сетевых интерфейсов и визуального отображения.&lt;/p&gt;</summary>
    <dc:creator>Никита Рогаленко</dc:creator>
    <dc:date>2026-09-07T15:36:00Z</dc:date>
  </entry>
  <entry>
    <title>Введение в архитектуру ПО. Часть 2: Три парадигмы и сила ограничений</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21301163" />
    <author>
      <name>Romo Fedoroff</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21301163</id>
    <updated>2026-09-02T02:20:28Z</updated>
    <published>2026-09-02T02:00:00Z</published>
    <summary type="html">&lt;style type="text/css"&gt;

article p {
font-size:11pt;
font-family:Verdana, sans-serif;
text-align:justify;
color:#6a6a6a;
}

article img {
width: 90%;
}

article li {
 font-size:11pt;   
}

.centered {
text-align:center;
}


article .portlet-msg-info {
color: #232323;
background-color: #f9f9f9;
border-style: dashed;
border-color: #232323;
}

&lt;/style&gt;
&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Введение&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;В первой части мы говорили о том, что архитектура - это не про изощрённые решения, а про стоимость изменений. Про то, почему спешка на старте оборачивается неделями работы там, где раньше хватало дня, и как обсуждать всё это с руководством так, чтобы вас услышали.&lt;/p&gt;

&lt;p&gt;Но у любого разговора об архитектуре есть неудобный момент. Рано или поздно кто-то спрашивает: хорошо, я согласен, что нужна низкая связанность и высокая согласованность - а как именно её получить? Что конкретно я должен делать завтра утром, открыв редактор?&lt;/p&gt;

&lt;p&gt;Ответ начинается гораздо ниже уровня диаграмм и слоёв. Он начинается в коде.&lt;/p&gt;

&lt;p&gt;Архитектура не существует отдельно от кода - она из него собирается. Границы между компонентами проводятся не в документации, а вызовами функций и объявлениями интерфейсов. Поэтому, прежде чем обсуждать принципы проектирования и паттерны, стоит разобраться с тем, из чего вообще состоит наш инструментарий. А состоит он из трёх парадигм программирования, каждая из которых была открыта более полувека назад и с тех пор не менялась.&lt;/p&gt;

&lt;p&gt;Самое интересное в них - то, как именно они работают. Не так, как обычно предполагают.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Немного истории: как программы стали данными&lt;/h2&gt;

&lt;p&gt;Основы того, чем мы занимаемся каждый день, заложил Алан Тьюринг. Программируемые машины придумывали и до него, но именно Тьюринг в 1938 году сформулировал ключевую идею: программа - это данные. Не особая сущность, не механизм, а обычная информация, которую можно хранить, передавать и обрабатывать так же, как любую другую.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;К середине 1940-х он уже писал программы для реальных машин. И если сегодня посмотреть на его код, мы, приложив некоторое усилие, его прочитаем: там есть циклы, ветвления, присваивания, подпрограммы, стеки. Всё то же самое, чем мы пользуемся сейчас. Разница в том, что записывалось это двоичным кодом.&lt;/p&gt;

&lt;p&gt;Дальше история пошла быстро. В конце 1940-х появились ассемблеры - они избавили программистов от ручного перевода инструкций в машинные коды. В 1951 году Грейс Хоппер создала первый компилятор A-0 и ввела в оборот сам термин «компилятор». В 1953 году появился Fortran, за ним COBOL, PL/I, C, Pascal, C++, Java - и далее непрерывным потоком до сегодняшнего дня.&lt;/p&gt;

&lt;p&gt;Революция языков видна всем: о ней спорят на конференциях, из-за неё меняют место работы, ей посвящены бесконечные сравнительные таблицы. Но была и вторая революция, куда менее заметная и, если честно, куда более важная для архитектуры. Революция парадигм.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Что такое парадигма и почему это не то же самое, что язык&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Парадигма - это способ программирования, не привязанный к конкретному языку. Она определяет, какие конструкции вы используете и, что важнее, каких избегаете.&lt;/p&gt;

&lt;p&gt;Разницу между языком и парадигмой легко почувствовать на практике. Можно писать вполне объектно-ориентированный код на чистом C - через структуры и таблицы указателей на функции, именно так устроены многие драйверы и ядро Linux. И точно так же можно писать на Java или C# в откровенно процедурном стиле: класс с одним статическим методом на тысячу строк - это не объектно-ориентированное программирование, сколько бы ключевых слов из учебника там ни встретилось.&lt;/p&gt;

&lt;p&gt;Язык - это набор возможностей. Парадигма - это дисциплина их применения.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Для тех, кто только начинает:&lt;/strong&gt; представьте, что вам выдали полный набор столярных инструментов. Язык - это то, какие именно инструменты лежат в ящике. Парадигма - это принятая в мастерской практика: например, никогда не забивать шурупы молотком, даже если это быстрее и физически возможно. Инструмент никуда не делся, вы просто договорились им так не пользоваться.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Для тех, у кого есть опыт&lt;/strong&gt;: отсюда следует практический вывод. Переход на новый язык сам по себе не улучшает архитектуру. Команда, писавшая запутанный код на PHP, напишет ровно такой же запутанный код на Go или Kotlin, если не поменяется дисциплина. Меняет ситуацию не синтаксис, а то, от чего команда сознательно отказалась.&lt;/p&gt;

&lt;p&gt;Всего парадигм три: структурное программирование, объектно-ориентированное и функциональное. И у них есть общая особенность, которую редко замечают.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Главный парадокс: парадигмы ничего не дают&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Присмотритесь к тому, что делает каждая из трёх парадигм.&lt;/p&gt;

&lt;p&gt;Структурное программирование ограничивает прямую передачу управления - забирает у нас безусловные переходы.&lt;/p&gt;

&lt;p&gt;Объектно-ориентированное программирование ограничивает косвенную передачу управления - забирает свободное обращение с указателями на функции.&lt;/p&gt;

&lt;p&gt;Функциональное программирование ограничивает присваивание - забирает возможность менять значение в любой момент.&lt;/p&gt;

&lt;p&gt;Ни одна из них не добавляет новой выразительной мощности. Ни одна не позволяет написать программу, которую нельзя было написать раньше. Каждая только отнимает.&lt;/p&gt;

&lt;p&gt;Это звучит контринтуитивно, но именно в этом их ценность. Парадигмы говорят нам не столько что делать, сколько чего не делать. Они сужают пространство возможных решений - и тем самым делают код предсказуемым.&lt;/p&gt;

&lt;p&gt;Аналогия здесь простая. Правила дорожного движения не расширяют возможности автомобиля: он и без них способен ехать по встречной полосе. Правила именно что запрещают, и благодаря этому дорожное движение вообще существует как система, а не как набор случайных траекторий. Ценность ограничения - в предсказуемости, которую оно создаёт для всех остальных участников.&lt;/p&gt;

&lt;p&gt;В коде происходит то же самое. Когда я открываю незнакомый модуль, написанный в рамках знакомой мне дисциплины, я заранее знаю, чего там точно не будет. Не будет прыжка из середины одной функции в середину другой. Не будет тихой мутации объекта, который я передал третьей стороне. Это резко снижает объём того, что мне нужно держать в голове - ту самую когнитивную нагрузку, о которой шла речь в первой части.&lt;/p&gt;

&lt;p&gt;Обратите внимание и на исторический факт: все три парадигмы были открыты в промежутке примерно между 1958 и 1968 годами. За прошедшие с тех пор десятилетия не появилось ни одной новой. И это, скорее всего, не случайность: отнимать больше нечего. Три парадигмы забрали переходы, свободные указатели на функции и неограниченное присваивание - то есть все три способа, которыми программа может выйти из-под контроля.&lt;/p&gt;

&lt;p&gt;Разберём каждую подробно. В этой части мы остановимся на первой - структурном программировании. Она кажется самой очевидной и именно поэтому чаще всего применяется формально, без понимания сути.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Структурное программирование: как один спор изменил профессию&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Эдсгер Вибе Дейкстра родился в Роттердаме в 1930 году, пережил бомбардировки города и оккупацию Нидерландов, а в 1948 году окончил школу с лучшими оценками по математике, физике, химии и биологии. В 1952 году, в двадцать один год, он устроился в Математический центр Амстердама и стал, по сути, первым программистом в стране.&lt;/p&gt;

&lt;p&gt;Есть один эпизод, который хорошо передаёт дух той эпохи. В 1957 году Дейкстра женился, а голландские правила того времени требовали указать в документах профессию. Он написал «программист» - и документы не приняли, потому что о такой профессии никто не слышал. Пришлось указать «физик-теоретик».&lt;/p&gt;

&lt;p&gt;Работал он в условиях, которые сегодня трудно вообразить: ламповые машины, ввод программ с перфокарт, цикл «правка - компиляция - проверка» длиной в часы, а иногда и в сутки. Ошибка стоила дорого не в переносном смысле, а в самом прямом: день работы.&lt;/p&gt;

&lt;p&gt;Именно в такой среде Дейкстра сформулировал наблюдение, которое до сих пор определяет нашу профессию. Программирование - слишком сложная работа для человеческого мозга без вспомогательной дисциплины. В программе любого практического размера деталей больше, чем человек способен удержать. Достаточно упустить одну - и код, который выглядит работающим, откажет в самом неожиданном месте.&lt;/p&gt;

&lt;p&gt;Дейкстра искал способ доказывать правильность программ математически - выстроить для кода что-то вроде евклидовой иерархии из аксиом, теорем и следствий. В процессе он обнаружил интересную вещь.&lt;/p&gt;

&lt;p&gt;Неограниченные переходы - инструкция goto - ломали саму возможность такого доказательства. Когда управление может прыгнуть в произвольную точку, программу невозможно разложить на независимые части: каждый фрагмент связан со всеми остальными непредсказуемым образом. Принцип «разделяй и властвуй» перестаёт работать.&lt;/p&gt;

&lt;p&gt;Но не все переходы вели себя так. Дейкстра заметил, что «безвредные» случаи применения goto укладываются в несколько простых схем - те, что мы знаем как if/then/else и do/while. Модули, построенные только на таких конструкциях, разбирались на доказуемые части без проблем.&lt;/p&gt;

&lt;p&gt;И тут сошлись две линии. Двумя годами ранее Коррадо Бём и Джузеппе Якопини доказали теорему: любую программу можно записать, используя всего три конструкции - последовательность, выбор и итерацию. То есть минимальный набор, достаточный для написания чего угодно, в точности совпал с набором конструкций, при которых код остаётся анализируемым.&lt;/p&gt;

&lt;p&gt;Так родилось структурное программирование.&lt;/p&gt;

&lt;p&gt;В 1968 году Дейкстра опубликовал в журнале CACM своё знаменитое письмо о вреде оператора goto, и профессиональное сообщество взорвалось. Спор шёл около десяти лет - с письмами в редакции, резкими возражениями и не менее резкой поддержкой. Закончился он тем, что Дейкстра просто победил: языки эволюционировали, goto постепенно исчез, и сегодня большинство языков его либо не имеет вовсе, либо жёстко ограничивает границами одной функции.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Как это выглядит на практике&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Вот фрагмент в духе того кода, против которого Дейкстра выступал. Псевдокод намеренно упрощён:&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
 i = 0;
    total = 0;
loop:
    if (i &amp;gt;= n) goto done;
    if (items[i].valid == 0) goto next;
    if (items[i].amount &amp;lt; 0) goto error;
    total = total + items[i].amount;
next:
    i = i + 1;
    goto loop;
error:
    log("bad amount");
    goto next;
done:
    return total;&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Формально здесь всё работает. Но попробуйте ответить на вопрос: при каких условиях управление попадает на метку next? Придётся глазами просканировать весь фрагмент в поисках всех переходов. А в реальном коде тех лет такой фрагмент занимал не пятнадцать строк, а несколько сотен.&lt;/p&gt;

&lt;p&gt;То же самое в структурном виде:&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
int total = 0;
for (int i = 0; i &amp;lt; n; i++) {
    if (!items[i].valid) {
        continue;
    }
    if (items[i].amount &amp;lt; 0) {
        log("bad amount");
        continue;
    }
    total += items[i].amount;
}
return total;
&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Разница не в количестве строк - оно почти одинаковое. Разница в том, что теперь у фрагмента есть чёткая граница. Я вижу тело цикла целиком и знаю: управление войдёт сюда сверху и выйдет снизу, других вариантов нет. Мне не нужно проверять, не прыгает ли сюда кто-то ещё из соседнего модуля.&lt;/p&gt;

&lt;p&gt;Именно это свойство и есть суть парадигмы: у каждого блока кода один вход и один выход.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Современный goto, который никто так не называет&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Вот здесь начинается самое важное, и об этом обычно молчат. Считается, что тема закрыта: goto в языке нет, значит, структурное программирование соблюдается автоматически. Это не так.&lt;/p&gt;

&lt;p&gt;Ключевое слово исчезло, а само явление - нет. Неограниченная передача управления просто сменила форму. Вот несколько её современных обличий, которые я регулярно встречаю в рабочих проектах.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Исключения как штатный поток управления&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Когда исключение бросается не при аварии, а как обычный способ вернуть результат из глубины стека вызовов - это ровно тот же прыжок в неизвестное место, только легализованный синтаксисом:&lt;/p&gt;

&lt;pre class="brush:jscript;"&gt;
function findDiscount(user) {
  if (user.isVip) {
    throw new DiscountFound(0.2);   // это не ошибка, это возврат значения
  }
  // ...
}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Читатель функции findDiscount не может понять по её сигнатуре, что она вообще-то возвращает результат таким способом. Обработчик находится где-то на три уровня выше по стеку. Это метка goto, до которой сорок минут поиска по проекту.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Флаги состояния, управляющие ходом выполнения&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Классика:&lt;/p&gt;

&lt;pre class="brush:jscript;"&gt;
let shouldSkip = false;
let hasError = false;

for (const order of orders) {
  if (hasError) { break; }
  if (shouldSkip) { shouldSkip = false; continue; }
  // сто строк логики, где-то внутри которой
  // выставляются shouldSkip и hasError
}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Формально здесь только for, if, break и continue. Фактически - конечный автомат, спрятанный в переменных, и предсказать его поведение можно только выполнением в голове.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Глубокая вложенность&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Она не нарушает правил формально, но убивает то самое свойство «один вход, один выход», ради которого всё затевалось:&lt;/p&gt;

&lt;pre class="brush:jscript;"&gt;
function handleOrder(order) {
  if (order) {
    if (order.items.length &amp;gt; 0) {
      if (order.customer.isActive) {
        if (hasStock(order)) {
          if (paymentAllowed(order)) {
            // основная логика прячется здесь, на шестом уровне
          }
        }
      }
    }
  }
}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Хорошая новость в том, что лечится это одинаково - декомпозицией и ранними возвратами:&lt;/p&gt;

&lt;pre class="brush:jscript;"&gt;
function handleOrder(order) {
  const violation = validateOrder(order);
  if (violation) {
    return Result.rejected(violation);
  }

  reserveStock(order);
  return Result.accepted(createInvoice(order));
}

function validateOrder(order) {
  if (!order.items.length)        return 'EMPTY_ORDER';
  if (!order.customer.isActive)   return 'INACTIVE_CUSTOMER';
  if (!hasStock(order))           return 'OUT_OF_STOCK';
  if (!paymentAllowed(order))     return 'PAYMENT_BLOCKED';
  return null;
}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Функция handleOrder теперь читается за пять секунд и умещается на экране целиком. Проверки собраны в одном месте, и добавление новой не требует трогать основной сценарий. Это ровно та низкая связанность и высокая согласованность, о которых мы говорили в первой части - только выраженная не в терминах модулей, а в терминах пяти строк кода.&lt;/p&gt;

&lt;p&gt;Практический ориентир, который я советую держать в голове: если функция не помещается на один экран без прокрутки или содержит больше трёх-четырёх уровней вложенности - это сигнал, а не приговор. Обычно за таким фрагментом скрываются две-три самостоятельные операции, которые просто ещё не получили имён.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Функциональная декомпозиция: почему это работает&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Из структурного программирования следует важное практическое свойство - возможность рекурсивно разбивать программу на части.&lt;/p&gt;

&lt;p&gt;Большая задача раскладывается на несколько функций верхнего уровня. Каждая из них - на функции уровнем ниже. И так далее, пока не дойдём до фрагментов, которые целиком укладываются в голову. Именно на этом фундаменте в конце 1970-х и в 1980-х выросли дисциплины структурного анализа и структурного проектирования, которые продвигали Эд Йордан, Ларри Константин, Том Демарко и Меилир Пейдж-Джонс.&lt;/p&gt;

&lt;p&gt;Работает это не потому, что мелкие функции - это красиво. А потому, что у каждой части появляется определённый контракт: что она принимает на входе, что возвращает на выходе. Пока управление входит в блок только сверху и покидает его только снизу, такой контракт существует. Как только появляется свободный переход - контракта нет, и рассуждать о части в отрыве от целого больше невозможно.&lt;/p&gt;

&lt;p&gt;Простой пример из практики. Функция расчёта стоимости заказа на четыреста строк - это одно утверждение, которое либо верно, либо нет, и проверить его можно только целиком. Та же логика, разложенная на расчёт базовой суммы, применение скидок, начисление налога и учёт доставки - это четыре независимых утверждения. Каждое проверяется отдельно, и при ошибке в итоговой сумме вы сразу знаете, где искать.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Для специалистов с опытом&lt;/strong&gt;: отсюда же растёт и практическая ценность метрики цикломатической сложности. Она измеряет количество независимых путей исполнения через функцию - то есть, по сути, количество случаев, которые придётся разобрать, чтобы убедиться в её правильности. Это не абстрактный показатель для отчётности, а прямая оценка того, сколько усилий потребует проверка кода. Функцию со сложностью 3 держит в голове любой; функцию со сложностью 25 не держит никто, включая её автора через две недели после написания.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Доказательства, которых не случилось&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;У истории структурного программирования есть неожиданный финал, и он важнее самой истории.&lt;/p&gt;

&lt;p&gt;Мечта Дейкстры не сбылась. Евклидову иерархию доказанных теорем для программ так и не построили. Формальное доказательство правильности каждой функции оказалось настолько трудоёмким, что практическая индустрия от него отказалась. Сегодня формальная верификация применяется, но в узких областях, где цена ошибки исключительна: авионика, медицинское оборудование, криптографические примитивы. В обычной разработке её нет.&lt;/p&gt;

&lt;p&gt;Но отказ от доказательств не означал отказа от строгости. Просто строгость пришла из другой дисциплины.&lt;/p&gt;

&lt;p&gt;Разница между математикой и наукой принципиальна. Математика доказывает истинность утверждений. Наука так не умеет: невозможно доказать второй закон Ньютона. Можно провести множество экспериментов, измерить результат с любой точностью, но всегда остаётся вероятность, что следующий эксперимент покажет границы применимости закона - собственно, с ньютоновской механикой ровно это и произошло.&lt;/p&gt;

&lt;p&gt;Наука работает наоборот: она пытается опровергнуть. Утверждение, которое устояло после множества добросовестных попыток его опровергнуть, мы считаем истинным - до тех пор, пока не появится опровержение.&lt;/p&gt;

&lt;p&gt;Разработка программного обеспечения устроена по научному принципу, а не по математическому. И у Дейкстры есть на этот счёт афоризм, который стоит помнить любому, кто пишет тесты: «Тестирование показывает присутствие ошибок, а не их отсутствие».&lt;/p&gt;

&lt;p&gt;Тестами нельзя доказать, что программа правильная. Можно доказать только обратное - что она неправильная. Всё, что даёт нам зелёная сборка после достаточных усилий, - это обоснованная уверенность в том, что программа работает достаточно правильно для наших целей.&lt;/p&gt;

&lt;p&gt;И вот здесь замыкается вся логика этой части. Опровергать можно только то, что поддаётся разбору на части. Программу, в которой управление скачет произвольным образом, нельзя признать правильной ни при каком количестве тестов, потому что вы не можете изолировать проверяемое утверждение. Структурное программирование нужно нам ровно для того, чтобы получить тестируемые единицы.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Тестируемость - это архитектурное свойство&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Из сказанного следует вывод, который стоит отдельного разговора: если что-то трудно протестировать, проблема почти никогда не в тестах. Проблема в структуре.&lt;/p&gt;

&lt;p class="brush:jscript;"&gt;Посмотрите на функцию, которая на первый взгляд не вызывает вопросов:&lt;/p&gt;

&lt;pre class="brush:jscript;"&gt;
function isSubscriptionExpired(userId) {
  const user = db.query('SELECT * FROM users WHERE id = ?', userId);
  return user.expires_at &amp;lt; new Date();
}&lt;/pre&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Здесь три строки и одна простая мысль. Но чтобы её проверить, нужна база данных с подготовленными записями, а ещё нужно как-то подменить системное время - иначе тест на «подписка истекает завтра» сломается ровно завтра. В итоге вокруг трёх строк вырастает инфраструктура на сотню строк, которая работает медленно и ломается по не связанным с логикой причинам.&lt;/p&gt;

&lt;p&gt;Теперь то же самое, но с разделением решения и получения данных:&lt;/p&gt;

&lt;pre class="brush:jscript;"&gt;
// Чистая функция: решение. Никаких обращений вовне.
function isSubscriptionExpired(expiresAt, now) {
  return expiresAt &amp;lt; now;
}

// Оболочка: получение данных и побочные эффекты.
async function checkUserSubscription(userId, clock) {
  const user = await users.findById(userId);
  return isSubscriptionExpired(user.expiresAt, clock.now());
}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Проверка решения теперь не требует ничего:&lt;/p&gt;

&lt;pre class="brush:jscript;"&gt;
test('подписка считается истёкшей на следующий день после даты окончания', () =&amp;gt; {
  const expiresAt = new Date('2026-01-01T00:00:00Z');
  const now       = new Date('2026-01-02T00:00:00Z');

  expect(isSubscriptionExpired(expiresAt, now)).toBe(true);
});&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Ни базы, ни моков, ни зависимости от календаря. Тест выполняется за доли миллисекунды и падает только тогда, когда логика действительно сломана.&lt;/p&gt;

&lt;p&gt;Заметьте, что мы сделали. Мы не «написали тесты» - мы изменили структуру кода так, чтобы его вообще было о чём спрашивать. Время и база данных превратились из скрытых зависимостей в явные параметры. Это ровно то, чем занимается архитектор, только в масштабе одной функции: отделяет то, что решает, от того, что общается с внешним миром.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Практический признак для команды&lt;/strong&gt;: если в проекте регулярно звучит фраза «это невозможно нормально протестировать», у вас не проблема с тестированием. У вас диагноз архитектуры, и он бесплатный - его выдали вам сами тесты.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Что из этого следует для архитектуры&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Может показаться, что мы ушли далеко в сторону от темы. На самом деле нет: три парадигмы напрямую соответствуют трём опорам архитектуры.&lt;/p&gt;

&lt;p&gt;Структурное программирование даёт алгоритмическую основу для модулей - оно отвечает за функциональность и за то, что каждый модуль можно проверить по отдельности.&lt;/p&gt;

&lt;p&gt;Объектно-ориентированное программирование через полиморфизм даёт механизм пересечения архитектурных границ - оно отвечает за разделение компонентов и за возможность менять реализацию, не трогая тех, кто ею пользуется.&lt;/p&gt;

&lt;p&gt;Функциональное программирование накладывает ограничения на то, где живут данные и кто имеет право их менять - оно отвечает за управление состоянием.&lt;/p&gt;

&lt;p&gt;Функциональность, разделение компонентов, управление данными. Три парадигмы, три опоры, никаких совпадений.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Заключение&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Если собрать главное из этого материала, получится следующее.&lt;/p&gt;

&lt;p&gt;Парадигмы - это не про то, что язык вам позволяет, а про то, от чего вы сознательно отказались. Смена языка не улучшает архитектуру; меняет ситуацию только смена дисциплины.&lt;/p&gt;

&lt;p&gt;Каждая из трёх парадигм ограничивает, а не расширяет. Ценность ограничения - в предсказуемости: читая код, вы заранее знаете, чего в нём не будет, и это экономит вам главный ресурс - внимание.&lt;/p&gt;

&lt;p&gt;Отсутствие ключевого слова goto в языке не означает соблюдения структурного программирования. Исключения в роли возврата значений, флаги-переключатели и глубокая вложенность создают ровно ту же проблему, ради решения которой всё затевалось.&lt;/p&gt;

&lt;p&gt;Функциональная декомпозиция ценна не сама по себе, а тем, что превращает одно большое непроверяемое утверждение в набор маленьких проверяемых.&lt;/p&gt;

&lt;p&gt;Разработка ближе к науке, чем к математике. Мы не доказываем правильность - мы не смогли доказать неправильность и считаем это достаточным основанием. Отсюда и роль тестов: они не гарантия, а инструмент опровержения.&lt;/p&gt;

&lt;p&gt;Трудность тестирования - это не свойство тестов, а свойство архитектуры. Если что-то невозможно проверить без поднятия половины системы, проблема находится в коде, а не в инструментах.&lt;/p&gt;

&lt;p&gt;Спасибо, что дочитали до конца.&lt;/p&gt;

&lt;p&gt;В следующей части мы разберём вторую парадигму - объектно-ориентированное программирование. Поговорим о том, чем оно на самом деле является, почему полиморфизм оказался главным архитектурным изобретением за пятьдесят лет и как с его помощью развернуть направление зависимостей между модулями в нужную сторону.&lt;/p&gt;

&lt;p&gt;Следите за продолжением.&lt;/p&gt;</summary>
    <dc:creator>Romo Fedoroff</dc:creator>
    <dc:date>2026-09-02T02:00:00Z</dc:date>
  </entry>
  <entry>
    <title>Spring event bus. Гарантия выполнения метода после коммита транзакции.</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21290221" />
    <author>
      <name>Maxim Kalabukhov</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21290221</id>
    <updated>2026-08-07T18:52:24Z</updated>
    <published>2026-08-07T18:39:00Z</published>
    <summary type="html">&lt;p&gt;Сегодня коротко поговорим про Spring Event Bus и разберем одну&amp;nbsp;задачку.&lt;/p&gt;

&lt;p&gt;Недавно столкнулся с ситуацией - есть некий общий функционал, который вызывается из совершенно разных роутов. Сами роуты обернуты в транзакцию. Сообщение (ивент) в брокер об успешном выполнении этого общего функционала нужно отправлять прямо внутри этого небольшого метода. Но чтобы всё отработало безопасно, ивент должен улетать только после коммита транзакции.&lt;/p&gt;

&lt;p&gt;Конечно, первым на ум приходит запихивание отправки ивента в конец каждого верхнего роута. А хотелось бы просто опубликовать событие локально и быть уверенным, что оно улетит после успешного коммита внешней транзакции, кем бы она ни открывалась. И Spring event bus вместе с аннотацией &lt;code&gt;@TransactionalEventListener&lt;/code&gt; дают возможное решение данной ситуации.&lt;/p&gt;

&lt;p&gt;Шина событий в Spring - это такой встроенный publisher/subscriber внутри одного приложения: какой-то компонент системы может отправить событие в шину, а настроенные слушатели обработают его заданным образом.&lt;/p&gt;

&lt;p&gt;Создать событие в Kotlin можно проще простого, обычным &lt;code&gt;data class&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;
data class ActionCompletedEvent(
    val entityId: Long,
    val payload: String
)&lt;/pre&gt;

&lt;p dir="auto"&gt;В сервисе мы публикуем событие ровно там, где оно должно происходить по логике, и забываем про него. Публикуется оно, кстати, через &lt;code&gt;ApplicationEventPublisher&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;
@Service
class SomeService(
    private val someRepository: SomeRepository,
    private val eventPublisher: ApplicationEventPublisher
) {

    // Метод вызывается из разных транзакционных роутов
    fun performAction(entity: Entity, payload: String) {
        someRepository.save(...)
        // Публикуем событие локально. 
        // Что будет дальше - нас не волнует.
        eventPublisher.publishEvent(ActionCompletedEvent(entity.id, payload))
    }
}&lt;/pre&gt;

&lt;p dir="auto"&gt;Если мы в слушателе повесим обычный &lt;code&gt;@EventListener&lt;/code&gt;, он сработает прямо в момент вызова &lt;code&gt;publishEvent&lt;/code&gt;. То есть проблема с откатом транзакции останется -&amp;nbsp; ивент улетит до того, как внешняя транзакция подтвердит сохранение. Но у Spring есть &lt;code&gt;@TransactionalEventListener&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;
@Component
class ActionListener(
    private val kafka: kafkaClient
) {

    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    fun handleActionCompleted(event: ActionCompletedEvent) {
        // Этот код выполнится ТОЛЬКО после успешного коммита в БД.
        // Spring сам поймет, к какой внешней транзакции мы привязаны.
        kafka.sendEvent(event.entityId, event.payload)
    }
}&lt;/pre&gt;

&lt;p dir="auto"&gt;Видите фазу &lt;code&gt;AFTER_COMMIT&lt;/code&gt;? Spring сам отслеживает контекст транзакции. Мы можем легально вызывать &lt;code&gt;publishEvent&lt;/code&gt; в любом месте метода, сохраняя правильную семантику кода. А Spring гарантирует, что слушатели отработают только после успешного коммита самой верхней транзакции в стеке вызовов. Если что-то упадет и транзакция откатится, событие просто игнорируется.&lt;/p&gt;

&lt;p dir="auto"&gt;Единственный нюанс при использовании - это то, что по умолчанию &lt;code&gt;@TransactionalEventListener&lt;/code&gt; работает синхронно, в том же потоке, что и основной запрос. Если обработка ивента займет пару секунд, юзер будет сидеть и ждать ответа от сервера, хотя в базу данные уже записаны. Для решения данного казуса можно воспользоваться аннотацией &lt;code&gt;@Async&lt;/code&gt; над слушателем.&lt;/p&gt;

&lt;h2 dir="auto"&gt;Итого&lt;/h2&gt;

&lt;p dir="auto"&gt;Вместо того чтобы тащить отправку ивентов в конец верхних роутов, мы публикуем их локально. Spring берет на себя всю грязную работу по отслеживанию транзакций.&amp;nbsp;&lt;/p&gt;</summary>
    <dc:creator>Maxim Kalabukhov</dc:creator>
    <dc:date>2026-08-07T18:39:00Z</dc:date>
  </entry>
  <entry>
    <title>Этичный вайбкодинг: Как создавать AI-решения ответственно</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21289675" />
    <author>
      <name>Алексей Кондратьев</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21289675</id>
    <updated>2026-08-06T10:40:46Z</updated>
    <published>2026-08-06T10:27:00Z</published>
    <summary type="html">&lt;p&gt;Вайбкодинг (vibe coding) — это подход, при котором разработчик не пишет код построчно, а задаёт ИИ направление и общие параметры задачи на естественном языке, а модель генерирует решение . Это творческий, быстрый и демократичный способ создания ПО, где программист становится «дирижёром» . Однако эта свобода несёт и огромную ответственность.&lt;/p&gt;

&lt;p&gt;Кто отвечает за код, который вы не писали? За уязвимость, через которую украли данные пользователей? За дискриминационный алгоритм, который отказал человеку в услуге? В эпоху вайбкодинга эти вопросы перестают быть философскими. Они становятся вопросами профессиональной выживаемости.&lt;/p&gt;

&lt;h2&gt;Часть 1. Что такое «этичный вайбкодинг»?&lt;/h2&gt;

&lt;p&gt;Этичный вайбкодинг — это не просто «не нарушать закон». Это ответственное управление всем жизненным циклом AI-сгенерированного кода: от сбора данных для обучения моделей до развёртывания и сопровождения продукта .&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ar5iv.labs.arxiv.org/html/2507.19743"&gt;Исследователи из Университета Конкордии ввели понятие Ethically Sourced Code Generation (ES-CodeGen)&lt;/a&gt; — 11 измерений, которые определяют этичность кода, сгенерированного ИИ :&lt;/p&gt;

&lt;p&gt;&lt;img src="https://www.tune-it.ru/documents/portlet_file_entry/21107385/Screenshot+from+2026-08-06+13-30-36.png/dd88b269-b18f-d970-774b-c5576fe870dd?imagePreview=1" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://www.tune-it.ru/documents/portlet_file_entry/21107385/Screenshot+from+2026-08-06+13-30-10.png/c0c733ee-b806-9c83-7c80-26068c6cf85a?imagePreview=1" /&gt;&lt;/p&gt;

&lt;h2&gt;Часть 2. Основные риски неэтичного вайбкодинга&lt;/h2&gt;

&lt;h4&gt;1. Безопасность: «Доверяй, но проверяй»&amp;nbsp;&lt;/h4&gt;

&lt;p&gt;Вайбкодер часто берёт код AI без проверки. Это открывает дорогу уязвимостям.&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;AI-галлюцинации и «slopsquatting»: Злоумышленники мониторят запросы к AI и создают вредоносные пакеты с названиями, которые AI генерирует как «наиболее вероятные». Вайбкодер скачивает такой пакет — и получает бэкдор в систему.&lt;/li&gt;
	&lt;li&gt;Устаревшие и опасные паттерны: AI генерирует то, что чаще всего встречалось в обучающих данных, а это часто — небезопасные практики&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;2. Правовые риски: «AI скопировал чужой код, а платить — мне»&lt;/h4&gt;

&lt;p&gt;Исследования показывают, что 60% ответов AI-моделей содержат элементы плагиата . Если AI сгенерировал код, совпадающий с проприетарным, ответственность за нарушение лицензии ложится на вас .&lt;/p&gt;

&lt;h4&gt;3. Технический долг и потеря контроля&lt;/h4&gt;

&lt;p&gt;Когда код пишется быстро и без архитектурного планирования, накапливается «технический долг». Вайб-подход редко предполагает долгосрочное планирование, из-за чего системы сложно адаптировать под новые задачи. Через полгода такой код становится невозможно поддерживать.&lt;/p&gt;

&lt;h4&gt;4. Дезинформация и манипуляции&lt;/h4&gt;

&lt;p&gt;AI не предназначен для сообщения правды. Он генерирует вероятные утверждения на основе закономерностей в данных . Если вы используете AI для создания контента, вы рискуете распространять ложную информацию без злого умысла. Многие используют AI для генерации постов, статей, описаний. И забывают, что сгенерированный текст нужно маркировать как AI-контент. А когда этого не делают, возникает иллюзия, что текст написан человеком. Это дезинформация. Она может быть безобидной, когда речь идёт о рецепте запеканки, но смертельно опасной, когда — о медицинских рекомендациях или политических новостях.&amp;nbsp;&lt;/p&gt;

&lt;h4&gt;5. Профессиональная деградация&lt;/h4&gt;

&lt;p&gt;Постепенная утрата навыков ручного программирования и архитектурного мышления может привести к тому, что разработчики превращаются из архитекторов в операторов диалоговых интерфейсов, теряя контроль над критической инфраструктурой .&lt;/p&gt;

&lt;h2&gt;Часть 3. Как практиковать этичный вайбкодинг&lt;/h2&gt;

&lt;p&gt;Ответ простой. Вы не можете переложить ответственность на машину. Вы должны стать тем, кто держит руку на пульсе, потому что именно от вашего лица транслируется то, что вы создали. Безопасность и этичность – на ваших плечах, а &lt;strong&gt;незнание в этом случае не освобождает от ответственности.&lt;/strong&gt;&lt;br /&gt;
Что конкретно делать?&lt;/p&gt;

&lt;p&gt;Во-первых, &lt;strong&gt;научитесь разделять творчество и продукт&lt;/strong&gt;. Нейросети хороши для того чтобы развить идею, набросать черновик, понять, в каком направлении двигаться. Но когда речь идёт о коде, который будет работать с деньгами, медицинскими данными или критической инфраструктурой, здесь вайбкодинг — зона риска. Используйте его для вдохновения, но не для финального решения.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Вайбкодинг отлично подходит для:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Прототипирования и проверки гипотез .&lt;/li&gt;
	&lt;li&gt;Личных, pet-проектов.&lt;/li&gt;
	&lt;li&gt;Генерации «первого черновика» кода.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Не используйте вайбкодинг для:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Продуктов, работающих с чувствительными данными (финансы, медицина) .&lt;/li&gt;
	&lt;li&gt;Критической инфраструктуры.&lt;/li&gt;
	&lt;li&gt;Кода, который нельзя переписать с нуля в случае проблем.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Во-вторых, &lt;strong&gt;читайте код&lt;/strong&gt;. Да, это скучно. Да, AI написал его за вас. Но если вы не понимаете, что там происходит, вы не можете гарантировать его безопасность. Запускайте статические анализаторы, проверяйте лицензии всех библиотек, тестируйте граничные случаи. AI генерирует код, но только вы можете сказать: «Этот код правильный».&lt;/p&gt;

&lt;p&gt;В-третьих, требуйте от AI прозрачности. Спрашивайте, почему он выбрал именно это решение. Используйте технику цепочки рассуждений — когда AI не просто даёт ответ, а показывает ход мыслей. Это не только помогает вам понять логику, но и часто выявляет ошибки на раннем этапе. Если AI не может объяснить решение, возможно, это решение не стоит использовать.&lt;/p&gt;

&lt;p&gt;В-четвёртых, проектируйте ограничения заранее. Задавайте AI жёсткие рамки: «только компоненты из нашей дизайн-системы», «без внешних зависимостей», «с поддержкой доступности (WCAG)» . Это снижает риск «креативных», но опасных решений.&lt;/p&gt;

&lt;p&gt;И наконец, создавайте культуру ответственности в команде. Введите код-ревью для AI-сгенерированного кода. Разработайте политику использования AI-инструментов. И главное — признайте, что сгенерированный AI код — это ваша работа, и вы за неё отвечаете. Не говорите «это написал ChatGPT». Говорите «это сделал я с помощью ChatGPT». Разница колоссальная.&lt;/p&gt;

&lt;h2&gt;Часть 4. Дорога вперёд: от регулирования к осознанности&lt;/h2&gt;

&lt;p&gt;Этичный вайбкодинг требует не только технических изменений, но и культурных. Образование должно сместиться от «научить писать код» к «научить понимать код, управлять AI-инструментами и оценивать их результат». Иначе мы рискуем вырастить поколение операторов чат-ботов, которые не способны критически мыслить.&lt;/p&gt;

&lt;p&gt;Уже сейчас обсуждаются стандарты вроде AI Bills of Material — документирование всех компонентов AI-системы для обеспечения прозрачности. Почти 90% пользователей интернета выступают за регулирование генеративного AI. Вопрос не в том, будет ли регулирование, а в том, насколько разумным оно будет. Слишком жёсткое — задушит инновации. Слишком мягкое — приведёт к катастрофам.&lt;/p&gt;

&lt;h2&gt;Главное: творчество не отменяет ответственности&lt;/h2&gt;

&lt;p&gt;Вайбкодинг — это не «лёгкий путь» и не «читерство». Это новый способ создания, который требует от разработчика &lt;strong&gt;ещё большего профессионализма&lt;/strong&gt;, чем раньше. Потому что теперь вы отвечаете не только за свой код, но и за код, который сгенерировал AI.&lt;/p&gt;

&lt;p&gt;Адекватный вайбкодер не просто пишет промптики. Он проектирует архитектуру и задаёт ограничения. Он проверяет и тестирует каждое решение. Он понимает правовые и этические последствия. И — самое главное — он несёт ответственность за финальный продукт&lt;/p&gt;

&lt;p&gt;AI может написать код. Но только человек может сказать: «Этот код правильный, безопасный и этичный». И это — ваша работа. Это и есть этичный вайбкодинг.&lt;br /&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;</summary>
    <dc:creator>Алексей Кондратьев</dc:creator>
    <dc:date>2026-08-06T10:27:00Z</dc:date>
  </entry>
  <entry>
    <title>Краткий обзор NiFi 2.x - 5 важнейших (для меня) изменений</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21288875" />
    <author>
      <name>Никита Рогаленко</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21288875</id>
    <updated>2026-08-04T14:23:28Z</updated>
    <published>2026-08-04T14:23:00Z</published>
    <summary type="html">&lt;p style="text-align: justify;"&gt;В моем блоге уже было множество заметок на тему преобразования и передачи данных с использованием Apache NiFi, однако все наши предыдущие проекты разрабатывались на разных&amp;nbsp;подверсиях&amp;nbsp;NiFi 1.0. И вот, спустя несколько лет после официального выхода,&amp;nbsp; NiFi 2.0 наконец добрался и до нас, в связи с чем возникла потребность кратко описать самые существенные (с точки зрения моего&amp;nbsp;личного&amp;nbsp;опыта&amp;nbsp;и специфики наших проектов)&amp;nbsp;нововведения в обновленном и переработанном NiFi.&lt;/p&gt;

&lt;h3 style="text-align: justify;"&gt;1. NiFi Registry устарел, появилась удобная интеграция с Git&lt;/h3&gt;

&lt;p style="text-align: justify;"&gt;Раньше для версионирования потоков и совместной работы нужно было поднимать NiFi Registry как отдельный сервис, в котором хранятся JSON'ы наших потоков данных. В NiFi 2.0 управление версиями встроено прямо «из коробки» через Registry Clients. Теперь появилась возможность&amp;nbsp;напрямую подключить свои Process Groups к GitHub, GitLab или Bitbucket. Компонент&amp;nbsp;GitFlowRegistryClient был и раньше, но его настройка была сложна, а взаимодействие с репозиторием все равно проксировалось через Registry. Теперь все будет делаться напрямую и с меньшим количеством лишних действий.&lt;/p&gt;

&lt;h3 style="text-align: justify;"&gt;2. Упростилась настройка SSL контекста&lt;/h3&gt;

&lt;p style="text-align: justify;"&gt;Настройка TLS/SSL в NiFi 1.x с использованием Java Keystore (JKS) и Truststore требовала множество&amp;nbsp;лишних действий и сложных конвертаций с использованием keytool. Теперь же появился&amp;nbsp;Controller Service под названием&amp;nbsp;PEMEncodedSSLContextProvider, представляющий собой новую версию&amp;nbsp;интерфейса SSLContextProvider специально для прямой работы с PEM-файлами. Он позволяет сразу же использовать тот набор файлов, который вам с наибольшей вероятностью пришлет системный администратор (.pem, .crt, .key) без необходимости создавать .jks файлы.&lt;/p&gt;

&lt;h3 style="text-align: justify;"&gt;3. Добавили параметризацию Controller Services&lt;/h3&gt;

&lt;p style="text-align: justify;"&gt;В версиях 1.x существовало жесткое архитектурное ограничение:&amp;nbsp;в настройках процессора (например, в поле Database Connection Pool для ExecuteSQL)&amp;nbsp;приходилось жестко выбирать конкретный сервис из выпадающего списка кликом мыши. В Apache NiFi 2.x разработчики&amp;nbsp;реализовали принцип «Parameterize All The Things», добавив возможность передавать Controller Services через параметры. Теперь в свойство процессора можно напрямую вписать текстовый параметр вида &lt;code&gt;#{database_service_id}&lt;/code&gt;. Это&amp;nbsp;изменение избавляет от необходимости вручную менять множество процессоров при миграции потоков между контурами. Теперь достаточно в один клик изменить значение самого параметра на ID нужного контроллера в Parameter Context, и NiFi автоматически остановит зависимые компоненты, подменит реализацию сервиса&amp;nbsp;и запустит пайплайн обратно.&lt;/p&gt;

&lt;h3 style="text-align: justify;"&gt;4. Новый встроенный Stateless-движок&lt;/h3&gt;

&lt;p style="text-align: justify;"&gt;С NiFi 2.x&amp;nbsp;экспериментальный&amp;nbsp;движок&amp;nbsp;Stateless превратился в полноценный встроенный режим работы групп процессов. Если обычно NiFi протоколирует и сохраняет в свой репозиторий практически любые действия, то теперь переключателем в UI можно&amp;nbsp;перевести выбранный поток данных в режим обработки&amp;nbsp;строго в оперативной памяти, полностью исключив ресурсоемкую запись файлов потока на жесткий диск. Кроме колоссального прироста производительности и ультра-низкой задержки на потоках из тысяч мелких сообщений, Stateless-режим гарантирует строгую транзакционность.&amp;nbsp;При сбое NiFi автоматически откатит всю цепочку шагов назад. Это может быть особенно полезно&amp;nbsp;для контейнерных сред и Kubernetes (поддержка которого также расширена в NiFi 2.0), позволяя&amp;nbsp;создавать легковесные&amp;nbsp;поды в кластере, которым&amp;nbsp;не нужны&amp;nbsp;дисковые хранилища. Раньше возможность stateless-запуска была неудобной, так как требовала использование отдельной CLI-утилиты.&lt;/p&gt;

&lt;h3 style="text-align: justify;"&gt;5. Появилась поддержка процессоров на Python&lt;/h3&gt;

&lt;p style="text-align: justify;"&gt;И одно из самых интересных. Множество статей в этом блоге было написано на тему того, как писать на Groovy сложные скрипты для конвертации данных. Теперь же при желании можно использовать полноценный Python. Если старый процессор ExecuteScript опирался на движок Jython (Python внутри JVM), в котором недоступны многие современные библиотеки, то в&amp;nbsp;NiFi 2.x интеграцию с Python переписали с нуля, сделав его языком первого класса (First-Class Support). Благодаря нативной поддержке полноценного CPython, разработчики теперь могут писать кастомные процессоры на чистом Python и бесшовно подключать к потокам данных. NiFi берет на себя всю рутину по управлению инфраструктурой - платформа сама изолирует процессы, автоматически создает виртуальные окружения (venv) для каждого процессора и скачивает нужные зависимости. То есть теперь необязательно&amp;nbsp;добавлять процессор ExecuteScript, внутри которого пишется код, а можно написать собственный Python-скрипт и положить его в специальную папку на сервере NiFi (обычно python/extensions). После перезапуска NiFi&amp;nbsp;скрипт превращается в настоящий процессор в общем списке. Groovy, таким образом, можно оставить только для более простых и быстрых трансформаций. Подробнее см.&amp;nbsp;&lt;a href="https://nifi.apache.org/nifi-docs/python-developer-guide.html#processor_api"&gt;NiFi Python Developer’s Guide&lt;/a&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Вот пример процессора, который принимает входящий FlowFile, парсит JSON и добавляет новое поле с помощью&amp;nbsp;библиотеки numpy (NiFi сам скачает&amp;nbsp;через pip, если указать&amp;nbsp;в зависимостях):&lt;/p&gt;

&lt;pre class="brush:python;"&gt;
import json
import numpy as np
from nifiapi.flowfiletransform import FlowFileTransform, FlowFileTransformResult

class CalculateStats(FlowFileTransform):
    class Java:
        implements = ['org.apache.nifi.python.processor.FlowFileTransform']

    class ProcessorDetails:
        version = '2.0.0'
        description = 'Пример процессора NiFi 2.0'
        # Указываем внешние библиотеки, NiFi установит их автоматически через pip
        dependencies = ['numpy==1.26.4'] 

    def __init__(self, **kwargs):
        pass

    def transform(self, context, flowFile):
        content = flowFile.read().decode('utf-8')
        
        try:
            data = json.loads(content)
        except Exception:
            return FlowFileTransformResult(relationship="failure")

        data['generated_id'] = int(np.random.randint(1, 9))
        
        output_content = json.dumps(data)

        # Возвращаем обновленный контент в связь success
        return FlowFileTransformResult(
            relationship="success",
            contents=output_content.encode('utf-8')
        )
&lt;/pre&gt;

&lt;p style="text-align: justify;"&gt;&amp;nbsp;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Итак, сегодня мы рассмотрели наиболее значительные (на мой взгляд)&amp;nbsp;нововведения&amp;nbsp;NiFi 2.0 с точки зрения удобства и возможностей разработки. Кроме них существует еще множество изменений, среди которых более приятный визуал веб-интерфейса, различные оптимизации, добавление новых процессоров и удаление устаревших, и многое другое. Например, отдельно стоит выделить переход на более производительную Java 21 и отказ от поддержки устаревших версий систем (например, kafka 2.0). Таких внешне менее заметных изменений еще много, и для&amp;nbsp;каждого конкретного случая найдется свой процессор, контроллер сервисов и стратегии построения потоков&amp;nbsp;данных. Обо всем этом&amp;nbsp;мы еще поговорим в будущем.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&amp;nbsp;&lt;/p&gt;</summary>
    <dc:creator>Никита Рогаленко</dc:creator>
    <dc:date>2026-08-04T14:23:00Z</dc:date>
  </entry>
  <entry>
    <title>ChatGPT, Claude и Gemini в 2026 году: сравнение ИИ-помощников для разработчиков</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21287848" />
    <author>
      <name>Romo Fedoroff</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21287848</id>
    <updated>2026-08-01T18:24:42Z</updated>
    <published>2026-08-01T17:39:00Z</published>
    <summary type="html">&lt;style type="text/css"&gt;article p {
font-size:11pt;
font-family:Verdana, sans-serif;
text-align:justify;
color:#6a6a6a;
}

article img {
width: 90%;
}

article li {
 font-size:11pt;   
}

.centered {
text-align:center;
}


article .portlet-msg-info {
color: #232323;
background-color: #f9f9f9;
border-style: dashed;
border-color: #232323;
}
&lt;/style&gt;
&lt;h2&gt;Введение&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;За последние пару лет использование нейросетей в разработке перестало быть чем-то необычным - это часть повседневной работы. С их помощью пишут код, разбираются в чужих багах, готовят техническую документацию и обсуждают архитектурные решения ещё до того, как открыть IDE. Ни один серьёзный разговор о продуктивности разработчика в 2026 году уже не обходится без вопроса «а какой моделью ты пользуешься».&lt;/p&gt;

&lt;p&gt;К этому году на первый план вышли три инструмента: ChatGPT от OpenAI, Claude от Anthropic и Gemini от Google. У каждого - свой характер, своя философия и свои сильные стороны, и универсального победителя тут, забегая вперёд, не будет. Выбор скорее похож на выбор инструмента из ящика - гаечный ключ не заменяет отвёртку, даже если оба сделаны качественно. &lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Ниже - подробный разбор сильных и слабых сторон каждой модели и практических ориентиров, которые помогут понять, в каких сценариях разработки уместнее использовать ту или иную из них.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Сравнение по ключевым параметрам&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;table style="border-collapse: collapse; width: 100%;"&gt;
	&lt;thead&gt;
		&lt;tr style="border-bottom: 2px solid #ccc;"&gt;
			&lt;th style="padding: 8px; text-align: left;"&gt;Критерий&lt;/th&gt;
			&lt;th style="padding: 8px; text-align: left;"&gt;ChatGPT&lt;/th&gt;
			&lt;th style="padding: 8px; text-align: left;"&gt;Claude&lt;/th&gt;
			&lt;th style="padding: 8px; text-align: left;"&gt;Gemini&lt;/th&gt;
		&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
		&lt;tr style="border-bottom: 1px solid #ddd;"&gt;
			&lt;td style="padding: 8px;"&gt;Сложная логика&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Хорошо&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Высокий уровень&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Хорошо&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="border-bottom: 1px solid #ddd;"&gt;
			&lt;td style="padding: 8px;"&gt;Отладка&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Хорошо&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Высокий уровень&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Хорошо&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="border-bottom: 1px solid #ddd;"&gt;
			&lt;td style="padding: 8px;"&gt;Скорость выдачи решений&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Высокий уровень&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Хорошо&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Хорошо&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="border-bottom: 1px solid #ddd;"&gt;
			&lt;td style="padding: 8px;"&gt;Качество кода&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Хорошо&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Высокий уровень&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Хорошо&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="border-bottom: 1px solid #ddd;"&gt;
			&lt;td style="padding: 8px;"&gt;Размер контекста&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;32K токенов&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;200K токенов&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;1M токенов&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="border-bottom: 1px solid #ddd;"&gt;
			&lt;td style="padding: 8px;"&gt;Объяснение кода&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Высокий уровень&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Высокий уровень&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Хорошо&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="border-bottom: 1px solid #ddd;"&gt;
			&lt;td style="padding: 8px;"&gt;Работа с изображениями и файлами&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Хорошо&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Хорошо&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Высокий уровень&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="border-bottom: 1px solid #ddd;"&gt;
			&lt;td style="padding: 8px;"&gt;Интеграция с внешними сервисами&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Хорошо&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Хорошо&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Высокий уровень&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr style="border-bottom: 1px solid #ddd;"&gt;
			&lt;td style="padding: 8px;"&gt;Скорость работы&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Средняя&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Средняя&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Высокая&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td style="padding: 8px;"&gt;Стоимость&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;20$/мес.&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;17-20$/мес.&lt;/td&gt;
			&lt;td style="padding: 8px;"&gt;Бесплатно и 20$/мес.&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Цифры в таблице - это, конечно, упрощение: ни одна модель не сводится к набору баллов по шкале «плохо-хорошо». Но как отправная точка для дальнейшего разговора такая таблица вполне рабочая.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;ChatGPT: на все случаи жизни&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;ChatGPT остаётся, пожалуй, самым разносторонним инструментом из тройки. Модель одинаково уверенно чувствует себя в десятках языков и фреймворков, что неудивительно - за ней стоит один из самых больших массивов обучающих данных на рынке. Если нужно быстро получить рабочий вариант кода, ChatGPT почти всегда справляется без лишних вопросов и долгих раздумий.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Что в нём хорошо:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Широкий охват технологий - от классических языков вроде Java и C++ до узкоспециализированных библиотек и совсем новых фреймворков фронтенда.&lt;/li&gt;
	&lt;li&gt;Быстрое прототипирование: типовые задачи решаются буквально с первого запроса, без необходимости уточнять формулировку.&lt;/li&gt;
	&lt;li&gt;Встроенный Code Interpreter - можно выполнить Python-код прямо в чате, построить график, обработать датасет или проверить гипотезу, не переключаясь между окнами и средами.&lt;/li&gt;
	&lt;li&gt;Возможность создавать собственные GPT под конкретные задачи команды - от ревью пул-реквестов до генерации тестовой документации по шаблону.&lt;/li&gt;
	&lt;li&gt;Экосистема плагинов и интеграций, упрощающая связку с внешними сервисами - от систем управления задачами до баз данных.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Слабые места:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;На нестандартных алгоритмических задачах иногда проскальзывают логические неточности - код лучше перепроверять, особенно если он затрагивает граничные случаи или конкурентный доступ к данным.&lt;/li&gt;
	&lt;li&gt;Контекстное окно в 32K токенов заметно меньше, чем у конкурентов, и это ощущается при работе с крупными проектами: часть кода приходится подавать частями, теряя общую картину.&lt;/li&gt;
	&lt;li&gt;Знания о самых свежих версиях библиотек могут немного отставать от реальности, особенно если фреймворк выпустил breaking changes недавно.&lt;/li&gt;
	&lt;li&gt;При долгих диалогах модель иногда «забывает» ранние договорённости о стиле кода или структуре проекта.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Кому подходит: &lt;/strong&gt;тем, кто занимается разработкой общего профиля, быстро собирает прототипы или работает сразу с несколькими стеками технологий в течение дня.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Claude: вдумчивость и системность&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Anthropic делает ставку на глубину анализа, и это заметно буквально с первых секунд общения. Когда дело доходит до запутанных багов или проектирования архитектуры, Claude действует методично и редко торопится с выводами - модель скорее похожа на внимательного senior-разработчика, который сначала прочитает весь контекст, а потом уже начнёт писать код.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Сильные стороны:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Уверенно справляется со сложными алгоритмами, структурами данных и граничными случаями - часто разбирает задачу пошагово, прежде чем выдать итоговое решение, и проговаривает свои допущения вслух.&lt;/li&gt;
	&lt;li&gt;Хорошо находит нетипичные ошибки и умеет объяснить, откуда они взялись, а не просто предложить патч без объяснений - это особенно ценно при разборе чужого legacy-кода.&lt;/li&gt;
	&lt;li&gt;Пишет более аккуратный и идиоматичный код - с продуманными именами переменных, логичной структурой файлов и комментариями там, где они действительно нужны, а не «для галочки».&lt;/li&gt;
	&lt;li&gt;Контекст на 200K токенов позволяет держать в поле зрения сразу большой кусок кодовой базы - например, загрузить несколько связанных модулей и попросить модель проследить, как они взаимодействуют друг с другом.&lt;/li&gt;
	&lt;li&gt;Реже «додумывает» ответ там, где не уверена - вместо этого модель честно указывает на свою неуверенность и предлагает уточняющие вопросы, что снижает риск получить уверенно звучащую, но неверную рекомендацию.&lt;/li&gt;
	&lt;li&gt;Хорошо работает с рабочими артефактами: можно попросить модель собрать и отредактировать целый файл или небольшой проект, не разрывая диалог на десятки отдельных фрагментов кода.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Ограничения:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;На сложных запросах скорость ответа бывает ниже, чем у соседей по рынку - модель как будто действительно «думает», прежде чем ответить.&lt;/li&gt;
	&lt;li&gt;О совсем свежих фреймворках знания иногда требуют уточнения, особенно если библиотека вышла в последние месяцы.&lt;/li&gt;
	&lt;li&gt;Порой добавляет больше пояснений или проверок безопасности, чем требуется для короткой задачи, и в таких случаях приходится явно просить более краткий ответ.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Кому подходит:&lt;/strong&gt; для сложной отладки, код-ревью, архитектурных решений и вообще любых задач, где точность важнее скорости получения первого варианта.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Gemini: скорость и колоссальный контекст&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Флагман Google выигрывает там, где важны скорость и объём. Контекстное окно на миллион токенов - рекорд среди трёх моделей, а глубокая интеграция с экосистемой Google делает Gemini естественным выбором для соответствующих проектов и команд, уже завязанных на облако Google.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Плюсы:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Заметно быстрее генерирует ответы, чем ChatGPT и Claude, что особенно чувствуется при частых коротких запросах в течение рабочего дня.&lt;/li&gt;
	&lt;li&gt;Контекст в 1M токенов позволяет загружать целые репозитории и объёмную документацию за один раз - можно, например, скормить модели весь монорепозиторий среднего размера и попросить найти все места, где используется устаревший API.&lt;/li&gt;
	&lt;li&gt;Плотная интеграция с Firebase, Google Cloud Platform и разработкой под Android - от генерации конфигураций до отладки облачных функций.&lt;/li&gt;
	&lt;li&gt;Сильные мультимодальные возможности: модель уверенно работает со скриншотами интерфейсов, диаграммами архитектуры и даже видео, что удобно при разборе багов, которые проще показать, чем описать словами.&lt;/li&gt;
	&lt;li&gt;Есть функциональный бесплатный тариф, а для более требовательных задач - платный Gemini Pro.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Минусы:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Ответы на похожие запросы не всегда одинаковы по качеству - иногда одна и та же формулировка вопроса, заданная дважды, даёт заметно разные по глубине ответы.&lt;/li&gt;
	&lt;li&gt;Сгенерированный код рабочий, но нередко просит рефакторинга - стиль и структура не всегда соответствуют тому, что принято в конкретном проекте.&lt;/li&gt;
	&lt;li&gt;В глубокой логике заметно уступает Claude - на задачах с большим числом взаимосвязанных условий модель иногда упускает часть кейсов.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Кому подходит&lt;/strong&gt;: командам, завязанным на экосистему Google, работе с большими объёмами исходного кода и задачам, где скорость важнее идеальной чистоты первого варианта.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Стоимость и что за неё дают&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Формально ChatGPT Plus и Claude Pro стоят плюс-минус одинаково, и на первый взгляд выбор упирается только в качество ответов. Но на практике разница ощущается в лимитах: у ChatGPT более щедрые квоты на использование Code Interpreter и продвинутых моделей в течение дня, а у Claude - больший контекст, который в переводе на практическую пользу означает, что можно реже упираться в ограничение и чаще получать содержательный анализ большого куска кода за один запрос.&lt;/p&gt;

&lt;p&gt;Gemini здесь выделяется тем, что предлагает действительно рабочий бесплатный уровень - не урезанную демоверсию, а полноценный инструмент, которого хватает для большинства повседневных задач. Платный Gemini Pro добавляет доступ к более мощной модели и увеличенным лимитам, что имеет смысл в первую очередь для тех, кто уже работает в экосистеме Google Workspace и хочет получить нейросеть прямо в Docs, Sheets или Gmail без переключения контекста.&lt;/p&gt;

&lt;p&gt;Отдельная история - использование через API, где тарификация идёт за токены, а не по подписке. Здесь расклад может сильно отличаться от потребительских версий: для одних задач выгоднее окажется Claude из-за качества с первой попытки и меньшего числа повторных запросов, для других - Gemini из-за низкой цены на обработку больших объёмов текста.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Практическая проверка: рефакторинг медленного запроса с N+1-проблемой&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Чтобы сравнить модели не только на словах, каждой была дана одна и та же реальная по духу задача: есть обработчик заказов на Python (Django), который выводит список заказов вместе с данными о клиенте и товарах внутри каждого заказа. Страница подгружается медленно, а в логах видно классическую N+1-проблему - на каждый заказ уходит отдельный запрос к базе данных. Модели нужно было найти причину, объяснить её и предложить исправленную версию кода.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt; довольно быстро определил проблему и предложил использовать &lt;em&gt;select_related&lt;/em&gt;&amp;nbsp;и &lt;em&gt;prefetch_related&amp;nbsp;&lt;/em&gt;для нужных полей. Решение рабочее и действительно устраняет лишние запросы, но модель не стала проверять, как это скажется на сериализации связанных объектов, и в комментарии не упомянула, что для полей с большим количеством связанных записей &lt;em&gt;prefetch_related&lt;/em&gt;&amp;nbsp;стоит комбинировать с &lt;em&gt;Prefetch&lt;/em&gt;&amp;nbsp;и явной фильтрацией - это пришлось уточнять дополнительным вопросом.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude&lt;/strong&gt;&amp;nbsp;сначала попросил показать модель данных (или прямо уточнил структуру связей), после чего разложил проблему по шагам: показал, где именно возникает лишний запрос к базе, объяснил разницу между &lt;em&gt;select_related&amp;nbsp;&lt;/em&gt;для связей «один к одному» и &lt;em&gt;prefetch_related&lt;/em&gt;&amp;nbsp;для связей «один ко многим», и только затем предложил итоговый код с использованием &lt;em&gt;Prefetch&lt;/em&gt;&amp;nbsp;и аннотаций через &lt;em&gt;annotate&lt;/em&gt;, чтобы заодно избавиться от лишних вычислений на уровне Python. Решение сопровождалось короткими комментариями о том, почему выбран именно такой подход, и предупреждением о том, как изменение повлияет на существующие тесты.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gemini&amp;nbsp;&lt;/strong&gt;справился быстрее всех и предложил похожее решение с &lt;em&gt;select_related&lt;/em&gt;/&lt;em&gt;prefetch_related&lt;/em&gt;, но в первом варианте не учёл, что часть полей уже подгружается через сериализатор с собственной логикой, из-за чего оптимизация частично дублировала запросы. После уточняющего вопроса модель быстро скорректировала ответ.&lt;/p&gt;

&lt;p&gt;Победитель в этом тесте - &lt;strong&gt;Claude&lt;/strong&gt;, но с оговоркой: разница проявилась не в том, «заработает ли код», а в глубине понимания последствий изменения и во внимании к деталям, которые легко упустить при беглом ревью. Для задачи, где нужен рабочий вариант здесь и сейчас, разница между тремя моделями была бы куда менее заметна.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Как выбрать инструмент под задачу&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt; стоит выбрать, если:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;нужен быстрый рабочий вариант под типовую задачу и нет времени на долгие уточнения;&lt;/li&gt;
	&lt;li&gt;вы изучаете незнакомый фреймворк или технологию и хотите получить широкий обзор возможных подходов;&lt;/li&gt;
	&lt;li&gt;важен сбалансированный код с пояснениями по ходу работы;&lt;/li&gt;
	&lt;li&gt;проект затрагивает сразу несколько языков программирования в течение одного дня;&lt;/li&gt;
	&lt;li&gt;нужно быстро прогнать расчёты или обработать данные через встроенный интерпретатор кода.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Claude&lt;/strong&gt; подойдёт, если:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;нужно найти и исправить сложный или «плавающий» баг, который другие инструменты уже не смогли объяснить;&lt;/li&gt;
	&lt;li&gt;качество, чистота и предсказуемость кода важнее скорости получения первого варианта;&lt;/li&gt;
	&lt;li&gt;предстоит разобрать крупный модуль или весь проект целиком, держа в голове множество взаимосвязей;&lt;/li&gt;
	&lt;li&gt;принимаются архитектурные решения или проводится код-ревью, где важна аргументация, а не только итоговый код;&lt;/li&gt;
	&lt;li&gt;команда ценит, когда модель честно говорит «не уверен» вместо того, чтобы правдоподобно ошибаться.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Gemini&lt;/strong&gt; имеет смысл использовать, если:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;критична скорость ответа, а объём диалога в течение дня большой;&lt;/li&gt;
	&lt;li&gt;проект завязан на Google Cloud, Firebase или Android;&lt;/li&gt;
	&lt;li&gt;нужно передать модели большой объём кода, документации или даже видео и скриншотов;&lt;/li&gt;
	&lt;li&gt;важен бесплатный, но при этом достаточно сильный инструмент без необходимости сразу оформлять подписку.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Что касается вопроса, какой инструмент вообще «лучше» - тут, честно говоря, нет однозначного ответа, и это не попытка уклониться от прямой оценки. Практика показывает, что для сложной логики и отладки увереннее ведёт себя Claude: он реже допускает логические ошибки и лучше объясняет ход рассуждений. ChatGPT при этом остаётся самым универсальным решением на каждый день - если задача типовая, а времени мало, он почти всегда выдаёт рабочий вариант с первой попытки и охватывает при этом более широкий круг технологий. Gemini, в свою очередь, не столько соперничает с двумя другими моделями в глубине логики, сколько предлагает другой набор преимуществ - скорость и контекст, которых физически не хватает конкурентам, особенно при работе с большими кодовыми базами или проектами в экосистеме Google.&lt;/p&gt;

&lt;p&gt;Отдельно стоит сказать про написание кода как таковое. Если сравнивать именно чистоту и структуру итогового результата, а не только его работоспособность, Claude обычно выигрывает: переменные называются осмысленно, комментарии появляются там, где они правда нужны, а сама архитектура решения ближе к тому, что можно сразу отправить на код-ревью без правок. Код от ChatGPT и Gemini при этом тоже вполне рабочий и решает поставленную задачу - но чаще нуждается в стилистической доработке перед тем, как попасть в основную ветку проекта. Для команд, где на счету каждая минута ревью, это может оказаться решающим фактором.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Вместо заключения&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Если собрать всё сказанное воедино, получается следующая картина.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Во-первых, единого лидера среди трёх моделей нет - выбор всегда зависит от контекста: отладка, проектирование, быстрый прототип или работа с объёмной кодовой базой требуют разных сильных сторон, и ни один инструмент не закрывает все сценарии одинаково хорошо.&lt;/p&gt;

&lt;p&gt;Во-вторых, Claude - это выбор в пользу качества и предсказуемости. Он реже пропускает скрытые баги, пишет строго типизированный и аккуратный код и лучше других справляется с архитектурными задачами, где цена ошибки высока.&lt;/p&gt;

&lt;p&gt;В-третьих, ChatGPT остаётся самым универсальным вариантом - для повседневной разработки, быстрых проверок гипотез и знакомства с новыми технологиями он подходит лучше всего именно за счёт скорости и широты охвата.&lt;/p&gt;

&lt;p&gt;В-четвёртых, Gemini берёт скоростью и объёмом контекста - миллион токенов делает его по-настоящему удобным инструментом для анализа целых репозиториев и работы в стеке Google, а щедрый бесплатный тариф снижает порог входа.&lt;/p&gt;

&lt;p&gt;И наконец, на практике лучший результат чаще всего даёт не выбор одного-единственного инструмента на все случаи жизни, а осознанная комбинация всех трёх под конкретные этапы работы: быстрый прототип на ChatGPT, вдумчивое ревью и отладку на Claude, анализ большого объёма кода и работу с Google-сервисами на Gemini. Такой подход требует немного больше организационной дисциплины, зато позволяет использовать сильные стороны каждой модели именно там, где они действительно раскрываются.&lt;/p&gt;
&lt;/blockquote&gt;</summary>
    <dc:creator>Romo Fedoroff</dc:creator>
    <dc:date>2026-08-01T17:39:00Z</dc:date>
  </entry>
  <entry>
    <title>Java и деньги</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21278698" />
    <author>
      <name>Maxim Kalabukhov</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21278698</id>
    <updated>2026-07-09T16:13:11Z</updated>
    <published>2026-07-09T16:10:00Z</published>
    <summary type="html">&lt;p&gt;&lt;!-- obsidian --&gt;&lt;/p&gt;

&lt;p&gt;Главная проблема работа с деньгами в программировании заключается в том, что привычные нам десятичные дроби компьютер хранит в двоичной системе. Из-за этого &lt;code&gt;0.1 + 0.2&lt;/code&gt; в &lt;code&gt;double&lt;/code&gt; превращается в &lt;code&gt;0.30000000000000004&lt;/code&gt;. В финансовой сфере такая погрешность недопустима.&lt;/p&gt;

&lt;p&gt;В Java есть три основных способа обойти эту проблему. Разберем их:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Два &lt;code&gt;long&lt;/code&gt;: рубли и копейки отдельно&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Первое, что приходит в голову - разделить сумму на две части и хранить рубли и копейки в разных переменных типа &lt;code&gt;long&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;long rubles = 100;
long kopecks = 50;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Плюсы:&lt;/strong&gt; Максимальная точность, никаких проблем с двоичным представлением.&lt;br /&gt;
&lt;strong&gt;Минусы:&lt;/strong&gt; Любая математическая операция превращается в сложный код. Вам нужно вручную переносить разряды при сложении копеек, учитывать знаки при отрицательных суммах и т.д. В общем ад для разработчика.&lt;/p&gt;

&lt;ol start="2"&gt;
	&lt;li&gt;Один &lt;code&gt;long&lt;/code&gt;: всё в копейках&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Более прагматичный подход. Мы отказываемся от дробей и храним всю сумму в минорных единицах (в копейках, центах и т.д.).&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;long totalKopecks = 10050; // 100 рублей 50 копеек
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Плюсы:&lt;/strong&gt; Скорость работы примитивов, нет проблем с округлением при сложении и вычитании.&lt;br /&gt;
&lt;strong&gt;Минусы:&lt;/strong&gt; Проблемы начинаются при умножении и делении. Например, при расчете налога 13% от 100.50 рублей вы получите &lt;code&gt;1306.5&lt;/code&gt; копеек. Придется вручную реализовывать логику округления. Помимо этого становиться сложно работать с валютами, где нет минорных единиц.&lt;/p&gt;

&lt;ol start="3"&gt;
	&lt;li&gt;&lt;code&gt;BigDecimal&lt;/code&gt;: золото&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Основная часть профессиональных финансовых систем на Java использует &lt;code&gt;java.math.BigDecimal&lt;/code&gt;. Этот класс представляет число в виде массива цифр произвольной длины и отдельной переменной для позиции запятой. Он лишен проблем двоичного округления.&lt;/p&gt;

&lt;p&gt;Имейте ввиду&amp;nbsp;- создавать &lt;code&gt;BigDecimal&lt;/code&gt; из &lt;code&gt;double&amp;nbsp;&lt;/code&gt;это ошибка:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;// ТАК ДЕЛАТЬ НЕЛЬЗЯ
BigDecimal bad = new BigDecimal(0.1); // 0.1000000000000000055511151231257827021181583404541015625

// ТАК ПРАВИЛЬНО
BigDecimal good = new BigDecimal("0.1"); // Из строки
BigDecimal alsoGood = BigDecimal.valueOf(0.1); // Или через фабричный метод
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Главная сила &lt;code&gt;BigDecimal&lt;/code&gt; - строгий контроль над округлением. При делении всегда нужно указывать правило округления, иначе программа упадет с &lt;code&gt;ArithmeticException&lt;/code&gt;, если результат это бесконечная дробь.&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;BigDecimal total = new BigDecimal("100.00");
BigDecimal percent = new BigDecimal("0.13"); // 13%

// Делим нацело с округлением до копеек
// RoundingMode.HALF_EVEN — банковское округление
BigDecimal tax = total.multiply(percent)
                      .setScale(2, RoundingMode.HALF_EVEN);
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 data-heading="Итог"&gt;Итог&lt;/h3&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;&lt;code&gt;BigDecimal&lt;/code&gt;&lt;/strong&gt; - выбор для 99% бизнес-приложений, банковских систем. Он медленнее примитивов, но спасает от критических багов с округлением и потерей точности.&lt;/li&gt;
	&lt;li&gt;Хранение в минорных единицах - может подходить для того самого одно процента высоконагруженных систем, где важна каждая наносекунда.&lt;/li&gt;
	&lt;li&gt;Два &lt;code&gt;long&lt;/code&gt; - cложность поддержки перевешивает любые плюсы.&lt;/li&gt;
&lt;/ul&gt;</summary>
    <dc:creator>Maxim Kalabukhov</dc:creator>
    <dc:date>2026-07-09T16:10:00Z</dc:date>
  </entry>
  <entry>
    <title>Gstack: Как Гэрри Тан превращает вайб-кодинг в рабочий процесс</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21278583" />
    <author>
      <name>Vadim Mikhu</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21278583</id>
    <updated>2026-07-09T11:33:18Z</updated>
    <published>2026-07-09T10:25:00Z</published>
    <summary type="html">&lt;p data-sourcepos="3:1-3:406;66-471"&gt;Вайб-кодинг подкупает лёгкостью: описываешь словами, что нужно, и через минуту на экране рабочий прототип. Никаких тикетов, ревью и совещаний, поток идей сразу в код. Но у потока есть ограничения. Пока проект маленький, всё живёт; как только он вырастает, агент уверенно выдаёт код, который выглядит правильным, но таким не является, архитектура плывёт, баги всплывают в проде.&lt;/p&gt;

&lt;p data-sourcepos="3:1-3:406;66-471"&gt;В эту боль и целится gstack -&amp;nbsp;набор инструментов, который президент и CEO Y Combinator Гэрри Тан выложил в открытый доступ под лицензией MIT.&lt;/p&gt;

&lt;h2 data-sourcepos="7:1-7:11;843-853"&gt;Что это&lt;/h2&gt;

&lt;p&gt;&lt;img alt="gstack is not a dev tool. it's Garry Tan's brain on AI | by Luong NGUYEN |  Medium" src="https://miro.medium.com/0*XgShYxg9EqpOJTlQ" /&gt;&lt;/p&gt;

&lt;p data-sourcepos="9:1-9:704;855-1558"&gt;gstack это не приложение, а два с лишним десятка специализированных скиллов для Claude Code&amp;nbsp;и набор&amp;nbsp;инструментов. Значительную часть репозитория Тан написал в соавторстве с самим Claude. За пару недель репозиторий собрал десятки тысяч звёзд на GitHub. И это похоже на ожидаемый результат.&lt;/p&gt;

&lt;p data-sourcepos="11:1-11:296;1560-1855"&gt;Ставка тут почти еретическая для индустрии, привыкшей строить тулинг: правильный уровень абстракции для ИИ-разработки позволит копилоту стать настоящей командой, хоть и глупых, но полноценных разработчиков у вас под рукой. Выстраданные промпты, которые заставляют агента вести себя,&amp;nbsp;как дисциплинированная команда, больше похожи на должностные инструкции у реальных людей.&lt;/p&gt;

&lt;h2 data-sourcepos="13:1-13:38;1857-1894"&gt;Не умнее программисты, а лучше процесс&lt;/h2&gt;

&lt;p data-sourcepos="15:1-15:312;1896-2207"&gt;Идея простая. Разработчики одиночки проигрывают большим командам не из-за квалификации, они пропускают процесс распараллеливания задач&amp;nbsp;(очевидно, так как они одиночки). Кроме того, человек, вайбкодящий по вечерам очередной фитнес трекер, что-нибудь да соберёт, но у него нет ни осмысления задачи до старта, ни адекватной цели. А вся разница между рабочим продуктом и грудой техдолга живёт именно там.&lt;/p&gt;

&lt;p data-sourcepos="17:1-17:255;2209-2463"&gt;Gstack внедряет эти этапы в вайбкодинг&amp;nbsp;и превращает Claude Code из реактивного автодополнения в процесс с контрольными точками. Тан построил оргструктуру для выпуска софта и зашил в неё то, как сам оценивает продукты после тысяч стартапов, прошедших через YC.&lt;/p&gt;

&lt;p data-sourcepos="19:1-19:386;2465-2850"&gt;Один скилл играет CEO, который переосмысляет продукт. Другой — инженерного менеджера, фиксирующего архитектуру. Третий — дизайнера, отлавливающего генеративную серость, которую агент выдаёт по умолчанию. Четвёртый — параноидального ревьюера, что ищет баги до прода. Пятый — QA, который открывает настоящий браузер, кликает по приложению и заводит на вас баги.&lt;/p&gt;

&lt;h2 data-sourcepos="21:1-21:16;2852-2867"&gt;А что,&amp;nbsp;так&amp;nbsp;можно было&lt;/h2&gt;

&lt;p data-sourcepos="23:1-23:744;2869-3612"&gt;Отдельные умные промпты можно написать и без gstack. Отличают его хендоффы — передачи между этапами.&lt;/p&gt;

&lt;p data-sourcepos="23:1-23:744;2869-3612"&gt;&lt;code&gt;/office-hours&lt;/code&gt; не бросается кодить, а спорит с вашей формулировкой: сказали «приложение для утренней сводки» — получите ответ, что это персональный AI-начштаба, и вот пять возможностей, которые вы описали, сами того не заметив. Дальше&lt;/p&gt;

&lt;p data-sourcepos="23:1-23:744;2869-3612"&gt;&lt;code&gt;/plan-ceo-review&lt;/code&gt; ищет «десятизвёздочный продукт внутри запроса» в одном из четырёх режимов — от расширения замысла до сокращения. Проектный документ из &lt;code&gt;/office-hours&lt;/code&gt; читает инженерное ревью, пишет тест-план, а его подхватывает&amp;nbsp;&lt;code&gt;/qa&lt;/code&gt;.&lt;/p&gt;

&lt;p data-sourcepos="23:1-23:744;2869-3612"&gt;Эту цепочку случайным промптингом не воспроизвести. Последовательность&amp;nbsp;повторяет настоящий спринт: подумать, спланировать, собрать, проверить, протестировать, выкатить, отрефлексировать.&lt;/p&gt;

&lt;p data-sourcepos="23:1-23:744;2869-3612"&gt;Есть и защитные команды. &lt;code&gt;/careful&lt;/code&gt; предупреждает перед деструктивными командами, &lt;code&gt;/freeze&lt;/code&gt; запирает правки в одной директории, &lt;code&gt;/guard&lt;/code&gt; включает оба сразу, а &lt;code&gt;/investigate&lt;/code&gt; при отладке замораживает всё, кроме чинимого модуля, чтобы агент в запале не переписал полпроекта.&lt;/p&gt;

&lt;p data-sourcepos="23:1-23:744;2869-3612"&gt;&lt;code&gt;/codex&lt;/code&gt; зовёт независимое ревью от Codex CLI и показывает, где модели сходятся, а где спорят.&lt;/p&gt;

&lt;h2 data-sourcepos="27:1-27:13;4082-4094"&gt;Зачем это&lt;/h2&gt;

&lt;p data-sourcepos="29:1-29:288;4096-4383"&gt;Пайплайн и есть продукт, агент — рабочая сила. Проведя с ИИ-агентом достаточно времени, ты&amp;nbsp;перестаёшь видеть в нём гения-универсала, начинаешь управлять им как командой: каждой роли узкая задача и чистая передача дальше. Так всегда работали нормальные команды, просто теперь в терминале.&lt;/p&gt;

&lt;p data-sourcepos="31:1-31:287;4385-4671"&gt;Цифры Тан приводит бодрые: по его замерам он пишет примерно в восемьсот раз больше кода в день, чем в 2013-м, когда программировал сам. К таким метрикам стоит относиться со скепсисом, но порядок величины впечатляет.&lt;/p&gt;

&lt;h2 data-sourcepos="33:1-33:17;4673-4689"&gt;Кому подойдёт&lt;/h2&gt;

&lt;p data-sourcepos="35:1-35:240;4691-4930"&gt;gstack это всего лишь набор скиллов, и он ровно настолько точен, насколько конкретен ваш контекст: расплывчатое описание проекта даёт бесполезные роли.&lt;/p&gt;

&lt;p data-sourcepos="37:1-37:376;4932-5307"&gt;Лучше всего применение gstack ложится на основателя или инженера ранней стадии, которому надо закрывать продукт, инженерию и ресёрч. Хуже -&amp;nbsp;на большие команды с устоявшимся разделением ролей, где вся эта машинерия избыточна, и на тех, кто ждёт коробку без настройки: вложиться на старте придётся, и gstack рассчитывает, что свой продукт вы понимаете.&lt;/p&gt;</summary>
    <dc:creator>Vadim Mikhu</dc:creator>
    <dc:date>2026-07-09T10:25:00Z</dc:date>
  </entry>
  <entry>
    <title>Промпт-инжиниринг для дизайна и кода: Как разговаривать с AI, чтобы он делал работу, а не мусор</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21277811" />
    <author>
      <name>Алексей Кондратьев</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21277811</id>
    <updated>2026-07-07T15:20:47Z</updated>
    <published>2026-07-07T14:49:00Z</published>
    <summary type="html">&lt;p&gt;Вы когда-нибудь просили нейросеть нарисовать «современный интерфейс для интернет-магазина» и получали нечто, напоминающее сайт 2010 года с кислотными цветами и непонятными кнопками? Или просили сгенерировать компонент на React, а AI выдавал код, который невозможно поддерживать, полный устаревших практик и багов?&lt;/p&gt;

&lt;p&gt;Это не «глупая нейросеть». Это вы плохо объяснили задачу.&lt;/p&gt;

&lt;p&gt;Промпт-инжиниринг (prompt engineering) — это искусство формулировать запрос к AI так, чтобы на выходе получался качественный, пригодный к использованию результат. В эпоху, когда нейросети стали стандартным инструментом дизайнера и разработчика, умение писать хорошие промпты — это базовый профессиональный навык, не менее важный, чем знание Figma или React.&lt;/p&gt;

&lt;p&gt;Эта статья — практическое руководство по промпт-инжинирингу для дизайна и кода. Никакой магии. Только конкретные техники, примеры и принципы, которые работают прямо сейчас.&lt;/p&gt;

&lt;h2&gt;Часть 1. Почему промпт-инжиниринг — это новая суперсила&lt;/h2&gt;

&lt;p&gt;В 2026 году нейросети умеют очень многое. Midjourney и DALL-E 3 создают фотореалистичные изображения. Figma AI генерирует многостраничные прототипы по текстовому описанию. Lovable и v0 превращают промпт в работающее React-приложение за минуты.&lt;/p&gt;

&lt;p&gt;Но есть одна проблема: AI не читает ваши мысли.&lt;/p&gt;

&lt;p&gt;Он не знает ваш брендбук. Не понимает, что «современный» для вас — это минимализм с крупной типографикой, а не неоморфизм с кислотными градиентами. Не догадывается, что «быстрый компонент» означает без лишних зависимостей и с мемоизацией.&lt;/p&gt;

&lt;p&gt;Хороший промпт — это не «пожелание». Это техническое задание, написанное на языке, который AI понимает идеально.&lt;/p&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-aad178b6-7fff-776d-34e6-2932fd3e08cb"&gt;Разница между плохим и хорошим промптом&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://www.tune-it.ru/documents/portlet_file_entry/21107385/Screenshot+from+2026-07-07+18-06-08.png/c58185f1-bf8b-83fa-2dd7-111afee2ad88?imagePreview=1" /&gt;&lt;/p&gt;

&lt;p&gt;В первом случае AI гадает, что вы имели в виду. Во втором — у него есть чёткая инструкция, и он выдаёт предсказуемый, качественный результат.&lt;/p&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-0808a896-7fff-4224-1ed2-4c7995b9de7d"&gt;Почему это особенно важно для дизайна и кода?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Дизайн и код — это дисциплины с высокой ценой ошибки. Плохой дизайн убивает конверсию. Плохой код создаёт тонну технического долга. AI генерирует быстро, но он также быстро генерирует плохие решения, если вы не задали правильные ограничения.&lt;/p&gt;

&lt;h2&gt;Часть 2. Базовые принципы хорошего промпта&lt;/h2&gt;

&lt;p&gt;Прежде чем переходить к продвинутым техникам, давайте зафиксируем фундамент. Хороший промпт всегда содержит четыре компонента:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Контекст (Context)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI должен знать, для чего он это делает. Кто пользователь? В каком продукте будет использоваться результат? Какие ограничения накладывает среда?&lt;/p&gt;

&lt;p&gt;Плохо: «Нарисуй дашборд для аналитики»&lt;br /&gt;
Хорошо: «Создай дизайн дашборда для менеджеров интернет-магазина. Основные метрики: выручка за сегодня, конверсия, средний чек, количество заказов. Данные обновляются каждые 5 минут. Пользователи смотрят на дашборд на 24-дюймовых мониторах по 8 часов в день — информация должна быть плотной, без лишних отступов. Приоритет — быстрый поиск аномалий, не эстетика.»&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Роль (Role)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Скажите AI, кем он должен себя представлять. Это один из самых эффективных приёмов.&lt;/p&gt;

&lt;p&gt;Пример для дизайна: «Ты — senior-дизайнер с 10-летним опытом в B2B-продуктах. Ты специализируешься на дашбордах и аналитических интерфейсах. Твои работы — лаконичные, функциональные, без лишнего визуального шума.»&lt;/p&gt;

&lt;p&gt;Пример для кода: «Ты — ведущий фронтенд-разработчик, фанатик производительности и доступности. Ты не используешь неоправданные зависимости, пишешь чистый TypeScript и всегда добавляешь атрибуты aria-* для скрин-ридеров.»&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Конкретные требования (Specifications)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Чем детальнее — тем лучше. Цвета, шрифты, размеры, структура компонентов, поведение при ошибках, состояния загрузки.&lt;/p&gt;

&lt;p&gt;Приём «инвертирования»: скажите AI не только что делать, но и чего не делать.&lt;/p&gt;

&lt;p&gt;«Не используй синий цвет — он ассоциируется с конкурентом. Не делай анимацию длиннее 200 мс. Не добавляй карусели — исследования показывают, что их никто не листает. Не генерируй SVG-иконки, используй импорт из react-icons.»&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Формат вывода (Output Format)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Скажите AI, в каком виде вы хотите получить результат. JSON, HTML/CSS, React-компонент, описание дизайн-системы, список токенов.&lt;/p&gt;

&lt;p&gt;Пример: «Верни ответ в формате JSON с полями: "prompt" (использованный промпт), "reasoning" (почему выбрана такая структура), "code" (React-компонент), "designTokens" (цвета и шрифты в формате CSS-переменных).»&lt;/p&gt;

&lt;h2&gt;Часть 3. Продвинутые техники промпт-инжиниринга&lt;/h2&gt;

&lt;p&gt;Базовый уровень позволит вам получать «нормальные» результаты. Продвинутые техники — превращать AI в предсказуемого, профессионального ассистента.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.1. Chain-of-Thought (CoT) — цепочка рассуждений&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Вместо того чтобы просить AI дать готовый ответ, попросите его показать ход мыслей. Это невероятно повышает качество результата, особенно для сложных задач.&lt;/p&gt;

&lt;p&gt;Пример для дизайна:&lt;/p&gt;

&lt;p&gt;«Сначала подумай и напиши свои рассуждения в тег &amp;lt;thinking&amp;gt;. Проанализируй задачу: кто пользователь, какова его главная цель, какие болевые точки. Затем предложи 3 разных подхода к организации информации. Потом выбери лучший и обоснуй выбор. И только после этого создавай финальный дизайн в Figma-совместимом формате.»&lt;/p&gt;

&lt;p&gt;Пример для кода:&lt;/p&gt;

&lt;p&gt;«Прежде чем писать код, напиши в комментариях:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Какие состояния есть у этого компонента?&lt;/li&gt;
	&lt;li&gt;Какие побочные эффекты нужно учесть?&lt;/li&gt;
	&lt;li&gt;Какой подход к управлению состоянием выбран и почему?&lt;/li&gt;
	&lt;li&gt;Какие edge cases (пустые данные, ошибки, загрузка) обрабатываются? После этого — реализация.»&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;3.2. Few-shot examples — учим AI на примерах&lt;/p&gt;

&lt;p&gt;Самый мощный способ задать стиль, структуру или паттерн — показать пример. 1-3 примера достаточно, чтобы AI «схватил» нужный формат и тон.&lt;/p&gt;

&lt;p&gt;Пример для дизайна:&lt;/p&gt;

&lt;p&gt;Вот как я хочу, чтобы выглядела карточка товара. [Вставьте ссылку на Figma или скриншот]&lt;/p&gt;

&lt;p&gt;А вот как я не хочу: [вставьте контр-пример]&lt;/p&gt;

&lt;p&gt;Теперь создай карточку для категории "Спортивные товары", следуя тому же стилю.&lt;/p&gt;

&lt;p&gt;Пример для кода:&lt;/p&gt;

&lt;p&gt;Вот пример компонента, который я считаю эталонным по качеству:&lt;/p&gt;

&lt;pre class="brush:jscript;"&gt;
type ButtonVariantType =
  | "primary"
  | "destructive"
  | "secondary"
  | "blue-button"
  | "link"
  | "link-blue";

const VARIANT_COLOR_TEXT_MAP: Record&amp;lt;ButtonVariantType, ColorToken&amp;gt; = {
  primary: "white",
  destructive: "white",
  secondary: "black-800",
  link: "black-800",
  "blue-button": "white",
  "link-blue": "blue-1000",
};

const DISABLED_VARIANT_COLOR_TEXT_MAP: Partial&amp;lt;Record&amp;lt;ButtonVariantType, ColorToken&amp;gt;&amp;gt; = {
  secondary: "black-400",
};

const getSvgIconWithColor = (svgIcon: ReactNode, color: ColorToken) =&amp;gt; {
  if (!isValidElement&amp;lt;{ color?: ColorToken }&amp;gt;(svgIcon)) return svgIcon;

  return cloneElement(svgIcon, { color: svgIcon.props.color ?? color });
};

type SvgPositionType = "left" | "right";

type ButtonSizeType = "regular" | "small";
type ButtonRadiusType = "default" | "none";

export type ButtonProps = Props&amp;lt;
  {
    variant: ButtonVariantType;
    size?: ButtonSizeType;
    radius?: ButtonRadiusType;
    buttonJustify?: CSSProperties["justifyContent"];
    svgIcon?: ReactNode;
    svgPosition?: SvgPositionType;
    isLoading?: boolean;
    fitContent?: boolean;
  },
  true,
  ButtonHTMLAttributes&amp;lt;HTMLButtonElement&amp;gt;
&amp;gt;;

export const Button = componentWithRef&amp;lt;ButtonProps, HTMLButtonElement&amp;gt;(
  (
    {
      variant,
      svgIcon,
      svgPosition = "left",
      size = "regular",
      radius = "default",
      buttonJustify = "center",
      isLoading = false,
      fitContent = false,
      type = "button",
      disabled = false,
      children,
      className,
      style,
      ...rest
    },
    ref
  ) =&amp;gt; {
    const isDisabled = disabled || isLoading;
    const currentColor =
      (isDisabled &amp;amp;&amp;amp; DISABLED_VARIANT_COLOR_TEXT_MAP[variant]) ||
      VARIANT_COLOR_TEXT_MAP[variant];
    const svgIconWithColor = getSvgIconWithColor(svgIcon, currentColor);

    return (
      &amp;lt;button
        ref={ref}
        type={type}
        className={clsx(
          "pm-button",
          {
            [`button--${variant}`]: variant,
            [`button--${size}`]: size,
            [`button--radius-${radius}`]: radius,
            "button--fit-content": fitContent,
          },
          className
        )}
        style={{ ...style, justifyContent: buttonJustify }}
        disabled={isDisabled}
        {...rest}
      &amp;gt;
        {isLoading &amp;amp;&amp;amp; &amp;lt;Loader color={currentColor} /&amp;gt;}
        {svgPosition === "left" &amp;amp;&amp;amp; svgIconWithColor}
        &amp;lt;Text variant="text3" color={currentColor}&amp;gt;
          {children}
        &amp;lt;/Text&amp;gt;
        {svgPosition === "right" &amp;amp;&amp;amp; svgIconWithColor}
      &amp;lt;/button&amp;gt;
    );
  }
);
&lt;/pre&gt;

&lt;p&gt;Теперь создай похожий компонент для дропдауна с поиском. Используй те же паттерны: мемоизация, обработка клика вне компонента, TypeScript, JSDoc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.3. Ограничения (Constraints) — границы творчества&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI любит придумывать «креативные» решения, которые нарушают ваши требования. Задавайте жёсткие ограничения.&lt;/p&gt;

&lt;p&gt;Категории ограничений:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Контекст и среда: «Сайт будет работать в регионах с плохим интернетом. Все изображения должны быть оптимизированы, максимальный размер страницы — 500KB.»&lt;/li&gt;
	&lt;li&gt;Доступность: «Соответствие WCAG 2.2 уровня AA. Контраст текста 4.5:1, управление с клавиатуры, скрытие контента от скрин-ридеров там, где это нужно.»&lt;/li&gt;
	&lt;li&gt;Производительность: «Компонент не должен вызывать лишних ререндеров. Используй React.memo и useCallback. Анимации только через CSS transform и opacity — ничего, что вызывает reflow.»&lt;/li&gt;
	&lt;li&gt;Бренд: «Только фирменные цвета: #1E3A8A, #3B82F6, #F59E0B. Не используй красный — он триггерит негативные ассоциации. Типографика — только Inter.»&lt;/li&gt;
	&lt;li&gt;Технические ограничения: «Не используй сторонние библиотеки для UI. Только нативные CSS-модули. Поддержка браузеров: последние 2 версии Chrome, Firefox, Safari.»&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3.4. Итеративный промптинг&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Почти никогда первый результат не бывает идеальным. Но вместо того чтобы переписывать промпт с нуля, используйте диалог.&lt;/p&gt;

&lt;p&gt;Шаблон: «Результат хороший, но нужно исправить три вещи: (1) сделай отступы между карточками 24px вместо 16px, (2) измени цвет кнопки на акцентный (#F59E0B), (3) добавь состояние hover для карточек. Не меняй ничего больше.»&lt;/p&gt;

&lt;p&gt;Более продвинутый вариант — «аджайл-промптинг»: Разбейте большую задачу на маленькие итерации.&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;«Создай скелет страницы: хедер, основная область, футер. Пока без контента.»&lt;/li&gt;
	&lt;li&gt;«Теперь добавь три карточки товаров в основную область. Используй структуру: изображение, название, цена, кнопка.»&lt;/li&gt;
	&lt;li&gt;«Сделай карточки адаптивными: на десктопе — 3 колонки, на планшете — 2, на мобильном — 1.»&lt;/li&gt;
	&lt;li&gt;«Теперь добавь интерактив: при наведении на карточку — лёгкая тень и увеличение на 2% (transition 200ms).»&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;3.5. Негативный промптинг (Negative prompting)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Скажите AI не только что делать, но и что категорически нельзя.&lt;/p&gt;

&lt;p&gt;Для генерации изображений (Midjourney, DALL-E):&lt;/p&gt;

&lt;p&gt;Лендинг для IT-конференции. --no gradients, drop shadows, neon colors, 3D elements, stock photos, serif fonts, rounded corners on buttons&lt;/p&gt;

&lt;p&gt;Для кода:&lt;/p&gt;

&lt;p&gt;Создай хук useLocalStorage. Требования:&amp;nbsp;&lt;/p&gt;

&lt;p&gt;- НЕ используй try/catch (обработку ошибок я добавлю сам)&lt;br /&gt;
- НЕ используй useEffect для инициализации&lt;br /&gt;
- НЕ используй any в TypeScript&lt;br /&gt;
- НЕ генерируй лишних ререндеров&lt;/p&gt;

&lt;h2&gt;Часть 4. Промпты для дизайна: практические шаблоны&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;4.1. Генерация UI-компонента&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Роль: senior UI-дизайнер, специалист по доступным интерфейсам.&lt;/p&gt;

&lt;p&gt;Задача: создать карточку профиля пользователя для мобильного приложения соцсети.&lt;/p&gt;

&lt;p&gt;Контекст: приложение для людей 35+, цель — общение по интересам. Интерфейс должен быть понятным, без "молодёжного" дизайна.&lt;/p&gt;

&lt;p&gt;Требования:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Компоновка: аватар (слева), имя и статус (центр), кнопка "Написать" (справа).&lt;/li&gt;
	&lt;li&gt;Под аватаром — три иконки с числом друзей, фотографий, постов.&lt;/li&gt;
	&lt;li&gt;Цветовая схема: нейтральная (#F5F5F5 фон, #333 текст), акцент — #0066CC.&lt;/li&gt;
	&lt;li&gt;Адаптив: карточка растягивается на всю ширину экрана, внутренние отступы 16px.&lt;/li&gt;
	&lt;li&gt;Анимация: при нажатии на карточку — лёгкий ripple-эффект.&lt;/li&gt;
	&lt;li&gt;Доступность: контраст 4.5:1 для текста, фокус клавиатуры, атрибуты aria-label для иконок.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Не использовать: фотографии в кружочках (только квадратные с border-radius 12px), градиенты, выносные элементы.&lt;/p&gt;

&lt;p&gt;Верни результат как структуру Figma (слои, компоненты, стили) или как JSON-схему.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.2. Генерация дизайн-системы&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Роль: архитектор дизайн-систем.&lt;/p&gt;

&lt;p&gt;Задача: спроектировать дизайн-систему для B2B-платформы управления проектами.&lt;/p&gt;

&lt;p&gt;Требования:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Цвета: основной нейтральный (серый), акцентный (синий), предупреждения (жёлтый), ошибки (красный), успех (зелёный). Каждый цвет — в 10 градациях.&lt;/li&gt;
	&lt;li&gt;Типографика: системные шрифты, 7 уровней заголовков (от H1 до H7), 4 уровня текста. Метрики: line-height, letter-spacing.&lt;/li&gt;
	&lt;li&gt;Сетка: 12-колоночная на десктопе, 8 — на планшете, 4 — на мобильном. Отступы: 8, 16, 24, 32, 48, 64px.&lt;/li&gt;
	&lt;li&gt;Компоненты: кнопки (4 варианта), инпуты (3 состояния), карточки, модалки, тултипы, таблицы, дропдауны. Для каждого — все состояния (default, hover, active, disabled, loading, error).&lt;/li&gt;
	&lt;li&gt;Анимации: 5 стандартных easing-функций, длительности (100, 200, 300, 500ms).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Выдай результат как структуру JSON с полями: colors, typography, spacing, components, animations.&lt;/p&gt;

&lt;h2&gt;Часть 5. Промпты для кода: практические шаблоны&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;5.1. Генерация React-компонента&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Роль: senior фронтенд-разработчик, фанатик TypeScript и производительности.&lt;/p&gt;

&lt;p&gt;Задача: создать компонент Modal на React + TypeScript с порталом.&lt;/p&gt;

&lt;p&gt;Контекст: используется в дашборде с тяжёлыми графиками. Важна производительность и отсутствие лишних ререндеров.&lt;/p&gt;

&lt;p&gt;Требования:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Props: isOpen (boolean), onClose (() =&amp;gt; void), title (string), children (ReactNode), size ("sm" | "md" | "lg" | "full"), closeOnOverlayClick (boolean, default true).&lt;/li&gt;
	&lt;li&gt;При открытии — блокировка скролла body.&lt;/li&gt;
	&lt;li&gt;Закрытие: по Escape, клику на оверлей (если closeOnOverlayClick=true), кнопке "X".&lt;/li&gt;
	&lt;li&gt;Анимация: появление/исчезновение через CSS transition (opacity, transform). Длительность 200ms.&lt;/li&gt;
	&lt;li&gt;Доступность: role="dialog", aria-modal="true", focus trap (фокус не уходит из модалки), возврат фокуса при закрытии.&lt;/li&gt;
	&lt;li&gt;Технические ограничения: без внешних библиотек (кроме React и react-dom). Используй createPortal. CSS Modules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Выдай полный код компонента с комментариями, объясняющими ключевые решения.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.2. Генерация хука&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Роль: lead разработчик, специалист по пользовательским хукам.&lt;/p&gt;

&lt;p&gt;Задача: написать хук useDebounce.&lt;/p&gt;

&lt;p&gt;Требования:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Типизация: &amp;lt;T&amp;gt;(value: T, delay: number) =&amp;gt; T&lt;/li&gt;
	&lt;li&gt;Возвращает дебаунснутое значение.&lt;/li&gt;
	&lt;li&gt;Сброс таймера при размонтировании.&lt;/li&gt;
	&lt;li&gt;Поддержка опции immediate: если true — значение обновляется сразу, а потом игнорируется указанное время.&lt;/li&gt;
	&lt;li&gt;Использовать useRef для хранения таймера, useEffect для подписки/отписки.&lt;/li&gt;
	&lt;li&gt;Обработка edge cases: delay &amp;lt;= 0, изменение delay на лету, очистка при быстром переключении компонента.&lt;/li&gt;
	&lt;li&gt;JSDoc для каждого параметра.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Пример использования:&lt;br /&gt;
const [searchTerm, setSearchTerm] = useState('')&lt;br /&gt;
const debouncedSearch = useDebounce(searchTerm, 300, { immediate: false })&lt;/p&gt;

&lt;p&gt;Выдай код хука + пример использования в компоненте SearchInput.&lt;/p&gt;

&lt;h2&gt;Часть 6. Инструменты для промпт-инжиниринга&lt;/h2&gt;

&lt;p&gt;Писать хорошие промпты помогает не только голова, но и специальные инструменты.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Для работы с текстовыми AI (ChatGPT, Claude, Gemini)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;PromptPerfect — оптимизирует ваши промпты, предлагая улучшения для конкретной модели.&lt;/li&gt;
	&lt;li&gt;LangChain — фреймворк для создания цепочек промптов, памяти и инструментов.&lt;/li&gt;
	&lt;li&gt;Anthropic Console — встроенные шаблоны и режим "chain of thought" для Claude.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Для дизайна&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Figma AI — плагины вроде "Design System Prompter" помогают переводить текстовые требования в дизайн-токены.&lt;/li&gt;
	&lt;li&gt;Midjourney Prompt Helper — конструктор промптов с подсказками по стилям, параметрам и весам.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Для кода&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Cursor и Continue — AI-ассистенты, которые умеют работать с промптами прямо в редакторе кода, включая few-shot examples из ваших файлов.&lt;/li&gt;
	&lt;li&gt;Aider — утилита командной строки для промпт-инжиниринга в Git-репозиториях.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Часть 7. Заключение: промпт-инжиниринг как образ мышления&lt;/h2&gt;

&lt;p&gt;Промпт-инжиниринг — это не просто набор техник. Это способ мышления.&lt;/p&gt;

&lt;p&gt;Хороший промптист (а в 2026 году каждый уважающий себя дизайнер и разработчик должен им быть) мыслит как:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Инженер — чётко, структурированно, с учётом ограничений.&lt;/li&gt;
	&lt;li&gt;Психолог — понимает, как AI интерпретирует слова, и выбирает формулировки, исключающие двусмысленность.&lt;/li&gt;
	&lt;li&gt;Коммуникатор — умеет объяснить сложную задачу простыми словами, но с нужной степенью детализации.&lt;/li&gt;
	&lt;li&gt;Итератор — не ждёт идеального результата с первого раза, а последовательно улучшает его через диалог.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Главный совет на прощание:&lt;/p&gt;

&lt;p&gt;Не думайте о промпте как о «магическом заклинании». Это техническое задание, которое вы пишете для очень умного, но буквально мыслящего стажёра.&lt;/p&gt;

&lt;p&gt;Чем точнее и полнее вы опишете контекст, роли, требования и ограничения — тем меньше «магии» потребуется, чтобы результат оказался полезным. И тем больше времени вы сэкономите на бесконечных правках.&lt;/p&gt;

&lt;p&gt;Помните: AI делает то, что вы сказали, а не то, что вы имели в виду. Ваша задача — исключить разрыв между этими двумя понятиями. И хороший промпт — это единственный инструмент, который это позволяет.&lt;br /&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;</summary>
    <dc:creator>Алексей Кондратьев</dc:creator>
    <dc:date>2026-07-07T14:49:00Z</dc:date>
  </entry>
  <entry>
    <title>Циклическое кодирование времени для прикладных задач</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21275800" />
    <author>
      <name>Никита Рогаленко</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21275800</id>
    <updated>2026-07-03T10:00:03Z</updated>
    <published>2026-07-03T10:00:00Z</published>
    <summary type="html">&lt;p style="text-align: justify;"&gt;Сегодня мы поговорим о простом, но действенном математическом способе преобразования данных о времени из линейного промежутка в окружность, имитирующую циферблат часов. Необходимость таких трансформаций появляется в тех случаях, когда алгоритму машинного обучения или разрабатываемому нами сервису важно понимать, что время в сутках идет по кругу и что разница в отметках (например, времени входа) 23:59 и 00:01 незначительная. Подобным образом происходит трансформация&amp;nbsp;периодических временных признаков (не только часы, но и дни, месяцы) в непрерывные числовые значения, сохраняющие связь между концом и началом цикла. Это может использоваться, скажем, при обнаружении аномалий в поведении пользователя. Так, при моделировании профиля поведения нам важно знать, что активность, происходящая в ночь с одного дня на другой, принадлежит примерно к одному промежутку времени, а не к противоположным на временной оси точкам. Кроме того, применяться метод может при прогнозировании сезонных значений разного рода признаков от погоды и климата до числа продаж.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Итак, каким же образом мы можем&amp;nbsp;проецировать время на окружность, где 23:00 и 00:00 окажутся&amp;nbsp;рядом?&amp;nbsp;Для любого временного признака расчет выполняется через перевод значения в радианы внутри текущего цикла по формулам:&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;img src="https://www.tune-it.ru/documents/portlet_file_entry/20567281/sincos.png/4e860ccb-cfe7-e264-f160-1b90694fb09e?imagePreview=1" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;В этих формулах:&lt;/p&gt;

&lt;ul&gt;
	&lt;li style="text-align: justify;"&gt;t -&amp;nbsp;текущее значение времени:&amp;nbsp;час (0-23), месяц (1-12), день недели (0-6 или 1-7) и т.п.&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;T -&amp;nbsp;максимальный период цикла, т.е. количество делений в периоде: 24 для часов в сутках&amp;nbsp;(можно на 60 умножить для минут), 12 для месяцев, 7 для дней недели и т.п.&lt;/li&gt;
&lt;/ul&gt;

&lt;p style="text-align: justify;"&gt;Для примера возьмем случай, когда нам нужно анализировать время входа в приложение в часах и минутах. Покажем, как 23:15 и 00:45 в случае кодирования через синусы и косинусы оказываются примерно в одной области нашей воображаемой временной окружности. В первую очередь, переведем часы в минуты от начала суток (это будет значение t). В таком случае&amp;nbsp;23:15 превратится в 1395 минут, а&amp;nbsp;00:45 соответственно в 45 минут. Значение T в таком&amp;nbsp;случае будет 24*60=1440 минут.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Далее по формулам выше рассчитаем, что для 23:15:&lt;/p&gt;

&lt;ul&gt;
	&lt;li style="text-align: justify;"&gt;x&lt;sub&gt;sin&lt;/sub&gt;&amp;nbsp;= -0,195&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;x&lt;sub&gt;cos&lt;/sub&gt;&amp;nbsp;= 0,981&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;Итоговые координаты для кодирования времени: (x&lt;sub&gt;cos&lt;/sub&gt;&amp;nbsp;;&amp;nbsp;x&lt;sub&gt;sin&lt;/sub&gt;) = (0,981; -0,195)&lt;/li&gt;
&lt;/ul&gt;

&lt;p style="text-align: justify;"&gt;Для 00:45:&lt;/p&gt;

&lt;ul&gt;
	&lt;li style="text-align: justify;"&gt;x&lt;sub&gt;sin&lt;/sub&gt;&amp;nbsp;= 0,195&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;x&lt;sub&gt;cos&lt;/sub&gt;&amp;nbsp;= 0,981&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;Итоговые координаты для кодирования времени: (x&lt;sub&gt;cos&lt;/sub&gt;&amp;nbsp;;&amp;nbsp;x&lt;sub&gt;sin&lt;/sub&gt;) = (0,981; 0,195)&lt;/li&gt;
&lt;/ul&gt;

&lt;p style="text-align: justify;"&gt;Примерно так это будет выглядеть на тригонометрическом круге, имитирующем циферблат часов:&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;img src="https://www.tune-it.ru/documents/portlet_file_entry/20567281/sincos_circle.png/275e18ee-90c6-d0ea-efc1-364cec0f1471?imagePreview=1" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Как мы видим, 23:15 и 00:45&amp;nbsp;оказались достаточно близко, расстояние между ними небольшое (длина хорды около 0,4, тогда как для полуночи и полудня как самых отдаленных точек оно равняется 2,0). В связи с этим модель поймет, что данные временные отметки располагаются достаточно близко друг к другу, что события происходят примерно в одно время, тем самым&amp;nbsp;существенно повышая&amp;nbsp;точность решаемой задачи. Программная реализация в общем случае также не является сложной. Типичный пример кода на Python:&lt;/p&gt;

&lt;pre class="brush:python;"&gt;
import numpy as np

def encode_time_with_minutes(time_str):
    hours, minutes = map(int, time_str.split(':'))
    t = hours * 60 + minutes
    T = 24 * 60 
    sin_val = np.sin(2 * np.pi * t / T)
    cos_val = np.cos(2 * np.pi * t / T)
    return round(cos_val, 3), round(sin_val, 3)

print("23:15 -&amp;gt;", encode_time_with_minutes("23:15"))
print("00:45 -&amp;gt;", encode_time_with_minutes("00:45"))&lt;/pre&gt;

&lt;p style="text-align: justify;"&gt;Безусловно у этого метода есть и недостатки. Так, для кодирования временной отметки обязательно нужно два значения вместо одного (синус и косинус), а расстояние между точками на окружности растет нелинейно по мере удаления друг от друга. Данный метод подходит не для всех алгоритмов и методов машинного обучения, однако во многих случаях он все же предоставляет рабочее и элегантное решение для проблем преобразования временных отметок в циклическую форму.&lt;/p&gt;</summary>
    <dc:creator>Никита Рогаленко</dc:creator>
    <dc:date>2026-07-03T10:00:00Z</dc:date>
  </entry>
  <entry>
    <title>Git: как перенести проект на новый сервер без старой истории</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21275989" />
    <author>
      <name>Romo Fedoroff</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21275989</id>
    <updated>2026-07-02T21:32:09Z</updated>
    <published>2026-07-02T20:49:00Z</published>
    <summary type="html">&lt;style type="text/css"&gt;article p {
font-size:11pt;
font-family:Verdana, sans-serif;
text-align:justify;
color:#6a6a6a;
}

article img {
width: 90%;
}

article li {
 font-size:11pt;   
}

.centered {
text-align:center;
}


article .portlet-msg-info {
color: #232323;
background-color: #f9f9f9;
border-style: dashed;
border-color: #232323;
}
&lt;/style&gt;
&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Введение&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Рано или поздно перед любым разработчиком встает задача переноса проекта в новый репозиторий. Причины могут быть самыми разными: смена хостинга, передача проекта заказчику или публикация кода в открытом доступе. При этом часто хочется оставить в прошлом объемные логи, промежуточные черновики и устаревшие данные, и не тащить их в новое место.&lt;/p&gt;

&lt;p&gt;Хорошее решение в такой ситуации -&amp;nbsp;начать историю проекта заново: собрать один аккуратный &lt;em&gt;&lt;strong&gt;Initial commit&lt;/strong&gt;&lt;/em&gt; с текущим состоянием кода и перенести его на новый сервер. Сначала разберем простой алгоритм -&amp;nbsp;пять шагов, которых достаточно в большинстве случаев. А после -&amp;nbsp;уточним важные детали и нюансы, которые стоит знать перед тем, как применять этот способ на реальном проекте.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Простой алгоритм&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Перед началом работы откройте терминал и перейдите в корневую папку локального репозитория.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Шаг 1. Создание независимой ветки&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Создаем новую независимую (&lt;em&gt;&lt;strong&gt;orphan&lt;/strong&gt;&lt;/em&gt;) ветку. Она не тянет за собой историю предыдущих коммитов, позволяя начать с чистого листа. Назовем ее &lt;em&gt;temp-branch&lt;/em&gt;:&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
git checkout --orphan temp-branch
&lt;/pre&gt;

&lt;p&gt;После этой команды вы окажетесь в новой ветке. В ней пока нет ни одной записи в истории, но все файлы остаются на своих местах.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Шаг 2. Индексация файлов и создание коммита&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Добавляем все рабочие материалы проекта в индекс Git и фиксируем их первым коммитом:&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
git add -A
git commit -m "Initial commit"&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Теперь у вас есть ветка с единственным коммитом, который содержит актуальное состояние проекта.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Шаг 3. Замена старой ветки на новую&lt;/h3&gt;

&lt;p&gt;Убираем старую основную ветку (обычно &lt;em&gt;master&lt;/em&gt; или &lt;em&gt;main&lt;/em&gt;) и переименовываем временную ветку, делая ее главной:&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
# удаляем старую локальную ветку master
git branch -D master&lt;/pre&gt;

&lt;pre class="brush:bash;"&gt;
# переименовываем временную ветку в master
git branch -m master&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Шаг 4. Привязка нового сервера&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;На этом шаге есть два разных сценария, и важно сразу определить свой -&amp;nbsp;от этого зависит, какие команды выполнять дальше.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Вариант А. Старый сервер больше не нужен, работаем только с новым&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Это самый частый случай: вы полностью переезжаете на новый хостинг, а старый репозиторий планируете архивировать или удалить. Тогда просто заменяем адрес, на который указывает &lt;em&gt;origin&lt;/em&gt;:&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
git remote set-url origin &amp;lt;URL_НОВОГО_РЕПОЗИТОРИЯ&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Само имя &lt;em&gt;origin&lt;/em&gt; остается прежним -&amp;nbsp;меняется только URL за ним. Проверить результат можно командой:&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
git remote -v&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Вы увидите, что origin теперь указывает на новый адрес и для скачивания (fetch), и для отправки (push). Дальше все команды:&amp;nbsp;&lt;em&gt;git push, git pull&lt;/em&gt; - работают как обычно, без каких-либо изменений в синтаксисе, потому что Git по умолчанию обращается именно к &lt;em&gt;origin&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Вариант Б. Старый сервер должен остаться доступным&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Такой случай встречается, если старый репозиторий нужно временно сохранить как резервную копию, зеркало, или часть команды пока продолжает работать со старым сервером. В этой ситуации &lt;em&gt;origin&lt;/em&gt; не трогаем, а добавляем новый сервер под отдельным именем:&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
git remote add new-server &amp;lt;URL_НОВОГО_РЕПОЗИТОРИЯ&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Теперь у репозитория два адреса одновременно:&amp;nbsp;старый под именем &lt;em&gt;origin&lt;/em&gt; и новый под именем &lt;em&gt;new-server&lt;/em&gt;. Проверить это можно той же командой:&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
git remote -v&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;В выводе будут обе записи со своими адресами. Обратите внимание на важный нюанс: команда &lt;em&gt;git push&lt;/em&gt; без указания имени сервера по-прежнему будет отправлять изменения в &lt;em&gt;origin&lt;/em&gt;, то есть на старый сервер. Чтобы отправить коммит именно на новый сервер, имя нужно указывать явно:&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
git push -u new-server master&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Флаг &lt;strong&gt;&lt;em&gt;-u&lt;/em&gt;&lt;/strong&gt; в этом случае привязывает вашу локальную ветку &lt;em&gt;master&lt;/em&gt; к ветке &lt;em&gt;master&lt;/em&gt; на &lt;em&gt;new-server&lt;/em&gt; - после этого для последующих отправок туда достаточно будет просто &lt;em&gt;git push&lt;/em&gt;, находясь в этой ветке.&lt;/p&gt;

&lt;h3&gt;Шаг 5. Отправка коммита на новый сервер&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Если вы выбрали Вариант А из предыдущего шага, загружаем коммит стандартной командой -&amp;nbsp;она автоматически уйдет на новый сервер, так как &lt;em&gt;origin&lt;/em&gt; уже переключен:&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
git push -u origin master&lt;/pre&gt;

&lt;p&gt;Если же вы выбрали Вариант Б и добавляли новый сервер под именем &lt;em&gt;new-server&lt;/em&gt;, используйте это имя вместо &lt;em&gt;origin&lt;/em&gt; - команда та же, что приведена в шаге 4:&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
git push -u new-server master&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Если репозиторий на новом сервере уже создан и там есть автоматические базовые файлы (README.md, .gitignore), Git может предложить сначала объединить изменения. Поскольку задача - заменить содержимое одним новым коммитом, используем принудительную отправку:&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
git push -f -u origin master&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;На этом перенос завершен: в новом репозитории лежит аккуратная история из одного коммита с актуальным кодом проекта.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Пояснения и важные детали&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Пяти шагов выше достаточно, чтобы выполнить перенос технически. Но на практике есть нюансы, которые стоит знать заранее - они помогут избежать типичных ошибок и лучше понять, что происходит на каждом этапе.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Когда этот способ действительно оправдан&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Передача проекта заказчику. Вы работали над проектом полгода, использовали внутренние ветки для экспериментов, коммитили черновики и временные решения. Заказчику не нужна эта "внутренняя кухня" - ему нужен рабочий код в аккуратном репозитории с одним понятным коммитом.&lt;/li&gt;
	&lt;li&gt;Публикация в open source. В истории коммитов часто остаются следы конфигурационных файлов с внутренними адресами серверов, тестовыми учетными данными или устаревшими API-ключами. Даже если сейчас эти данные удалены из кода, они все равно доступны через &lt;em&gt;git log&lt;/em&gt; любому, кто клонирует репозиторий. Обнуление истории - самый надежный способ закрыть эту проблему.&lt;/li&gt;
	&lt;li&gt;Смена хостинга с оптимизацией репозитория. Если в истории когда-то были закоммичены большие бинарные файлы (архивы, видео, дампы баз данных), которые впоследствии удалили, файл .git все равно продолжает хранить эти данные. Перенос с чистой историей избавляет от этого балласта.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Если история коммитов важна для аудита изменений или юридических требований - обнулять ее не стоит. Здесь лучше подойдут более точечные инструменты вроде &lt;em&gt;git filter-repo&lt;/em&gt;, которые чистят историю выборочно, не удаляя ее целиком.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Что стоит проверить перед началом&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Резервная копия. Скопируйте проект целиком или создайте архив - операция необратима, и лучше иметь возможность вернуться к исходному состоянию.&lt;/li&gt;
	&lt;li&gt;Файл &lt;em&gt;.gitignore&lt;/em&gt;. Убедитесь, что в него добавлены node_modules, venv, dist и прочие директории со сборочными артефактами - они не должны попасть в новый &lt;em&gt;Initial commit&lt;/em&gt;.&lt;/li&gt;
	&lt;li&gt;Сабмодули. Если в проекте используются &lt;em&gt;git submodules&lt;/em&gt;, при создании orphan-ветки связи с ними могут потребовать переинициализации.&lt;/li&gt;
	&lt;li&gt;Незавершенная работа в других ветках. После обнуления истории прочие ветки продолжат указывать на старую историю. Если там есть что-то важное - смержите это в рабочую ветку заранее.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Уточнения к шагу 1: orphan-ветка&lt;/h2&gt;

&lt;p&gt;Проверить, что переключение прошло успешно, можно командой &lt;em&gt;git status&lt;/em&gt; - она покажет, что все файлы проекта отмечены как неотслеживаемые, и это нормально: для Git это действительно первая ветка без единой точки отсчета.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Например, если у проекта были ветки &lt;em&gt;master, feature/payments и feature/auth&lt;/em&gt;, после команды появится четвертая ветка &lt;em&gt;temp-branch&lt;/em&gt;, полностью изолированная от истории остальных трех. Посмотреть список всех веток можно командой &lt;em&gt;git branch -a&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Уточнения к шагу 2: индексация и коммит&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Флаг &lt;em&gt;&lt;strong&gt;-A&lt;/strong&gt;&lt;/em&gt; добавляет в индекс не только новые и измененные файлы, но и учитывает удаленные - это важно, если какие-то файлы должны остаться за пределами нового репозитория, но по ошибке все еще присутствуют на диске.&lt;/p&gt;

&lt;p&gt;После коммита стоит убедиться, что в истории действительно ровно одна запись:&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
git log --oneline&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Если строк больше одной - ветка была создана не как &lt;em&gt;orphan&lt;/em&gt;, и стоит вернуться к первому шагу. Если в проекте есть папка вроде logs/ с многолетними файлами отладки, которую забыли добавить в &lt;em&gt;.gitignore&lt;/em&gt;, эти файлы попадут в коммит и раздуют размер репозитория с самого начала - проверить состав будущего коммита удобно командой &lt;em&gt;git status&lt;/em&gt; до выполнения &lt;em&gt;git add -A&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Уточнения к шагу 3: замена ветки и очистка локального репозитория&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Если проект использует в качестве основной ветки main вместо master, используйте соответствующее имя в обеих командах.&lt;/p&gt;

&lt;p&gt;Важная деталь, которую часто упускают: удаление ветки командой &lt;em&gt;git branch -D&lt;/em&gt; убирает лишь указатель на историю - сами коммиты физически остаются в локальном хранилище .git до сборки мусора. Если в проекте были и другие второстепенные ветки, их тоже стоит удалить:&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
git branch -D feature/payments feature/auth&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Чтобы полностью очистить локальный репозиторий и уменьшить размер папки .git, выполните после удаления всех лишних веток:&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
git reflog expire --expire=now --all
git gc --prune=now --aggressive&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Оценить размер репозитория до и после очистки можно командой &lt;em&gt;du -sh .git&lt;/em&gt; - разница может быть весьма ощутимой, особенно если в истории раньше присутствовали крупные бинарные файлы.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Уточнения к шагу 4: подключение нового сервера&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Проверить, что адрес обновился корректно, можно командой &lt;em&gt;git remote -v&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Она выведет текущие адреса для чтения (fetch) и записи (push), оба должны указывать на новый сервер.&lt;/p&gt;

&lt;p&gt;При переносе, например, с GitLab на GitHub URL обычно меняется с git@gitlab.com:team/project.git на git@github.com:team/project.git. Если используется SSH-доступ, заранее убедитесь, что соответствующий ключ добавлен в настройках нового аккаунта, иначе push завершится ошибкой авторизации.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Уточнения к шагу 5: отправка и force push&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Force push&lt;/em&gt; перезаписывает историю на удаленном сервере безвозвратно. Если с репозиторием уже работают другие участники команды или от него сделаны форки, их локальные копии разойдутся с сервером, и им потребуется заново клонировать проект. Прежде чем выполнять &lt;em&gt;force push&lt;/em&gt; в уже используемый репозиторий, обязательно предупредите всех, кто с ним работает.&lt;/p&gt;

&lt;p&gt;На некоторых платформах основная ветка может быть защищена от принудительной отправки настройками по умолчанию - в этом случае временно снимите защиту в настройках репозитория, выполните &lt;em&gt;push&lt;/em&gt;, а затем включите ее обратно.&lt;/p&gt;

&lt;p&gt;После отправки проверить результат можно через веб-интерфейс хостинга или командой:&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
git ls-remote origin&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Что еще не переносится автоматически:&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Теги&lt;/strong&gt;. Ссылаются на старую историю и не переносятся вместе с кодом - их нужно создать заново поверх нового &lt;em&gt;Initial commit&lt;/em&gt; командой &lt;em&gt;git tag v1.0.0&lt;/em&gt;.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Настройки CI/CD&lt;/strong&gt;. Пайплайны, вебхуки и секреты придется настроить заново на новом сервере.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Права доступа и участники команды&lt;/strong&gt;. Список коллабораторов и ролей настраивается отдельно на новой платформе.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Локальные копии у коллег&lt;/strong&gt;. Даже после чистого переноса у других участников команды могут остаться клоны со старой историей. Лучше явно попросить их удалить старую папку и склонировать проект заново, чем полагаться на &lt;em&gt;git pull&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Заключение&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Чему мы сегодня научились:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Работать с независимыми ветками. Флаг &lt;strong&gt;&lt;em&gt;--orphan &lt;/em&gt;&lt;/strong&gt;в Git - удобный инструмент, который позволяет создавать ветки без привязки к прежней истории, что отлично помогает при реорганизации репозиториев или подготовке кода к публикации.&lt;/p&gt;

&lt;p&gt;Грамотно пересобирать локальную структуру. Мы узнали, как откреплять старые ветки (&lt;em&gt;git branch -D&lt;/em&gt;) и переименовывать текущие (&lt;em&gt;git branch -m&lt;/em&gt;), а также как полностью очищать .git от следов старой истории с помощью &lt;em&gt;git reflog expire&lt;/em&gt; и &lt;em&gt;git gc&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Управлять удаленными репозиториями. Теперь мы умеем не только переназначать адрес сервера через &lt;em&gt;git remote set-url&lt;/em&gt;, но и понимаем, когда вместо этого стоит добавить второй сервер через &lt;em&gt;git remote add&lt;/em&gt; - и как выбор между ними влияет на поведение &lt;em&gt;git push&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Правильно применять &lt;em&gt;Force Push&lt;/em&gt;. Мы закрепили понимание того, когда оправдан флаг &lt;em&gt;-f&lt;/em&gt;.&amp;nbsp;Он полезен, когда нужно полностью синхронизировать удаленный сервер с новой локальной историей, но требует предварительного предупреждения команды.&lt;/p&gt;

&lt;p&gt;Учитывать сопутствующие детали переноса. Теги, настройки CI/CD и права доступа не переносятся вместе с кодом автоматически - их нужно настроить заново уже на новом сервере.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Теперь в вашем арсенале есть понятный и надежный алгоритм для комфортного переезда проектов на новые репозитории!&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;</summary>
    <dc:creator>Romo Fedoroff</dc:creator>
    <dc:date>2026-07-02T20:49:00Z</dc:date>
  </entry>
  <entry>
    <title>Strapi в эпоху AI-coding: почему dev-first CMS выигрывает</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21266077" />
    <author>
      <name>Vadim Mikhu</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21266077</id>
    <updated>2026-06-10T09:31:36Z</updated>
    <published>2026-06-10T09:25:00Z</published>
    <summary type="html">&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;

&lt;h2&gt;Состояние рынка&lt;/h2&gt;

&lt;p&gt;Headless CMS перестал быть нишевой темой. Рынок оценивается в $3,94 млрд в 2026 году и прогнозируется к росту до $22 млрд к 2034-му (CAGR &amp;gt;21%). Для большинства команд это уже инфраструктурное, а не инструментальное решение.&lt;/p&gt;

&lt;p&gt;Рынок сложился в два лагеря:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enterprise-Grade Orchestrators&lt;/strong&gt; — Contentful, Sanity, Kontent.ai. Проприетарные SaaS-платформы с высоким ценовым порогом, позиционирующие себя как «Composable DXP» или «Content Operating System». Высокий уровень managed-сервисов, global CDN из коробки, но данные живут у провайдера.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developer-Owned Backends&lt;/strong&gt; — Strapi, Payload CMS. Open-source, self-hosted, максимальный контроль над инфраструктурой. Strapi — самый популярный headless CMS с открытым исходным кодом по числу GitHub-звёзд и задокументированных enterprise-деплойментов.&lt;/p&gt;

&lt;h2&gt;Что такое Strapi&lt;/h2&gt;

&lt;p&gt;Strapi — headless CMS на Node.js с MIT-лицензией. Self-hosted Community Edition полностью бесплатен.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;img alt="What is Strapi? Why Should You Use It?" src="https://www.zealousys.com/wp-content/uploads/2024/01/how-does-strapi-work.webp" /&gt;&lt;/p&gt;

&lt;p&gt;Ключевые параметры платформы:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;API&lt;/strong&gt;: REST и GraphQL генерируются автоматически для каждого content type. OpenAPI v3 spec с v5.20&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;База данных&lt;/strong&gt;: PostgreSQL (рекомендован для production), MySQL/MariaDB, SQLite. Только SQL — намеренный выбор под реляционную enterprise-инфраструктуру&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;TypeScript&lt;/strong&gt;: 100% кодовая база с Strapi 5, сборка через Vite&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;i18n, Draft/Publish, версионирование контента&lt;/strong&gt; — из коробки&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Архитектура: схема как код&lt;/h2&gt;

&lt;p&gt;Главное архитектурное решение Strapi — &lt;strong&gt;content type как файл в репозитории&lt;/strong&gt;. Каждый тип — это &lt;code&gt;schema.json&lt;/code&gt;, который версионируется в git, открыт для диффа в PR и читаем любым инструментом.&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;// src/api/article/content-types/article/schema.json
{
  "kind": "collectionType",
  "options": { "draftAndPublish": true },
  "attributes": {
    "title":   { "type": "string", "required": true },
    "slug":    { "type": "uid", "targetField": "title" },
    "content": { "type": "richtext" },
    "author":  { "type": "relation", "relation": "manyToOne", "target": "plugin::users-permissions.user" }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Из этой схемы Strapi автоматически генерирует полный CRUD-слой. REST-эндпоинт поддерживает фильтрацию, сортировку, пагинацию и populate для связей:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;GET /api/articles?filters[author][username][$eq]=john&amp;amp;populate[author][fields][0]=username&amp;amp;sort=createdAt:desc&amp;amp;pagination[pageSize]=10
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Тот же запрос через GraphQL — через &lt;code&gt;/graphql&lt;/code&gt;, который подключается одним плагином.&lt;/p&gt;

&lt;h3&gt;Кастомная бизнес-логика&lt;/h3&gt;

&lt;p&gt;Lifecycle hooks перехватывают события без написания отдельных эндпоинтов:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;// src/api/article/content-types/article/lifecycles.ts
export default {
  async beforeCreate(event) {
    const { data } = event.params;
    if (!data.slug &amp;amp;&amp;amp; data.title) {
      data.slug = slugify(data.title, { lower: true });
    }
  },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Кастомные роуты добавляются декларативно:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;// src/api/article/routes/custom-article.ts
export default {
  routes: [
    { method: 'GET', path: '/articles/trending', handler: 'article.findTrending',
      config: { policies: ['global::is-authenticated'] } },
  ],
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Официальный &lt;code&gt;@strapi/sdk-js&lt;/code&gt; генерирует типизированные клиентские методы из OpenAPI-спецификации инстанса — IntelliSense и type narrowing без ручных деклараций.&lt;/p&gt;

&lt;h2&gt;Почему dev-first архитектура выигрывает у AI-агентов&lt;/h2&gt;

&lt;p&gt;Это принципиальный момент для современного рабочего процесса.&lt;/p&gt;

&lt;p&gt;AI-агенты (Claude Code, Cursor, Copilot Workspace) работают с файловой системой и документацией. Когда схема контента существует как JSON-файл в репозитории, агент может прочитать её, добавить поле, написать lifecycle hook и сгенерировать seed-скрипт — всё в рамках одного PR без выхода в браузер.&lt;/p&gt;

&lt;p&gt;В CMS с UI-first архитектурой (Contentful и подобных) схема живёт только в базе данных провайдера. Агент вынужден делать аутентифицированные API-вызовы к Management API, не имея статического контекста. Это не техническое ограничение — это архитектурное.&lt;/p&gt;

&lt;table&gt;
	&lt;thead&gt;
		&lt;tr&gt;
			&lt;th&gt;Задача&lt;/th&gt;
			&lt;th&gt;Strapi&lt;/th&gt;
			&lt;th&gt;UI-first SaaS&lt;/th&gt;
		&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
		&lt;tr&gt;
			&lt;td&gt;Прочитать схему&lt;/td&gt;
			&lt;td&gt;JSON из репозитория&lt;/td&gt;
			&lt;td&gt;API-вызов к провайдеру&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Добавить поле&lt;/td&gt;
			&lt;td&gt;Редактирование файла&lt;/td&gt;
			&lt;td&gt;POST к Management API&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Добавить логику&lt;/td&gt;
			&lt;td&gt;Lifecycle hook в TS&lt;/td&gt;
			&lt;td&gt;Отдельная Lambda/Function&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Ревью изменений&lt;/td&gt;
			&lt;td&gt;git diff в PR&lt;/td&gt;
			&lt;td&gt;Только в UI провайдера&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;

&lt;h3&gt;Strapi AI и MCP&lt;/h3&gt;

&lt;p&gt;В 2025 году Strapi выпустил &lt;strong&gt;Strapi AI&lt;/strong&gt; — генерацию content models из текстового промпта или Figma-дизайна. Параллельно разрабатывается нативный MCP-сервер, который позволяет AI-ассистентам управлять схемой через Model Context Protocol. Пока он в разработке, доступен community-плагин &lt;code&gt;@sensinum/strapi-plugin-mcp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Документация публикует специальные файлы: &lt;code&gt;llms.txt&lt;/code&gt;, &lt;code&gt;llms-full.txt&lt;/code&gt;, &lt;code&gt;llms-code.txt&lt;/code&gt; — структурированный, токен-экономный контекст для RAG-систем и IDE-агентов.&lt;/p&gt;

&lt;h2&gt;Сравнение с конкурентами&lt;/h2&gt;

&lt;table&gt;
	&lt;thead&gt;
		&lt;tr&gt;
			&lt;th&gt;&amp;nbsp;&lt;/th&gt;
			&lt;th&gt;Strapi&lt;/th&gt;
			&lt;th&gt;Contentful&lt;/th&gt;
			&lt;th&gt;Sanity&lt;/th&gt;
			&lt;th&gt;Payload&lt;/th&gt;
		&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
		&lt;tr&gt;
			&lt;td&gt;Лицензия&lt;/td&gt;
			&lt;td&gt;MIT&lt;/td&gt;
			&lt;td&gt;Проприетарный&lt;/td&gt;
			&lt;td&gt;Проприетарный&lt;/td&gt;
			&lt;td&gt;MIT&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Self-hosting&lt;/td&gt;
			&lt;td&gt;&amp;nbsp;Да&lt;/td&gt;
			&lt;td&gt;Нет&lt;/td&gt;
			&lt;td&gt;Да&lt;/td&gt;
			&lt;td&gt;Да&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Schema as code&lt;/td&gt;
			&lt;td&gt;JSON в git&lt;/td&gt;
			&lt;td&gt;API-only&lt;/td&gt;
			&lt;td&gt;TypeScript&lt;/td&gt;
			&lt;td&gt;TypeScript&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;MCP-поддержка&lt;/td&gt;
			&lt;td&gt;plugin + roadmap&lt;/td&gt;
			&lt;td&gt;Нет&lt;/td&gt;
			&lt;td&gt;Нативный&lt;/td&gt;
			&lt;td&gt;Да&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;DB freedom&lt;/td&gt;
			&lt;td&gt;SQL (PG/MySQL)&lt;/td&gt;
			&lt;td&gt;Vendor&lt;/td&gt;
			&lt;td&gt;Vendor&lt;/td&gt;
			&lt;td&gt;PG/MongoDB/SQLite&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Цена (managed)&lt;/td&gt;
			&lt;td&gt;Бесплатно / $18+&lt;/td&gt;
			&lt;td&gt;$300+/мес&lt;/td&gt;
			&lt;td&gt;$15+/мес&lt;/td&gt;
			&lt;td&gt;Бесплатно&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Admin UI зрелость&lt;/td&gt;
			&lt;td&gt;Высокая&lt;/td&gt;
			&lt;td&gt;Высокая&lt;/td&gt;
			&lt;td&gt;Высокая (Studio)&lt;/td&gt;
			&lt;td&gt;Базовая&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Payload CMS&lt;/strong&gt; — ближайший конкурент в open-source нише. Устанавливается прямо в Next.js-приложение и работает внутри App Router. Figma приобрела Payload в июне 2025 года, MIT-лицензия сохранена. Если проект Next.js-first и минимальный network overhead важен — Payload стоит рассматривать наравне со Strapi.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contentful&lt;/strong&gt; — правильный выбор для global enterprise с требованиями к SLA, managed CDN и zero-ops. Ценовой порог отражает реальную стоимость этих гарантий.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sanity&lt;/strong&gt; выигрывает на real-time collaboration и кастомизации редактора через Portable Text.&lt;/p&gt;

&lt;h2&gt;Self-hosting: что нужно учесть&lt;/h2&gt;

&lt;p&gt;Strapi в production стандартно деплоится за reverse proxy (Cloudflare, nginx) с frontend на Vercel/Netlify. Для медиа нужен отдельный CDN (S3 + CloudFront или аналог) — Strapi не предоставляет его из коробки.&lt;/p&gt;

&lt;p&gt;Для multi-region деплоймента придётся самостоятельно проектировать топологию репликации и кэширования. Именно это managed-платформы берут на себя за деньги.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Честно про миграции&lt;/strong&gt;: upgrade между major-версиями Strapi исторически требует значительных усилий. Переход v4 → v5 не исключение. Это нужно учитывать при оценке long-term стоимости ownership.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Когда выбирать Strapi&lt;/h2&gt;

&lt;table&gt;
	&lt;thead&gt;
		&lt;tr&gt;
			&lt;th&gt;Сценарий&lt;/th&gt;
			&lt;th&gt;Вывод&lt;/th&gt;
		&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
		&lt;tr&gt;
			&lt;td&gt;Data sovereignty, GDPR/HIPAA compliance, self-hosted&lt;/td&gt;
			&lt;td&gt;Strapi&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Code-first команда, схема в git, CI/CD пайплайн&lt;/td&gt;
			&lt;td&gt;Strapi&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;AI-агенты работают с кодовой базой&lt;/td&gt;
			&lt;td&gt;Strapi&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Ограниченный бюджет, нужен production-ready CMS&lt;/td&gt;
			&lt;td&gt;Strapi (MIT)&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Next.js-monorepo, минимальный инфраструктурный overhead&lt;/td&gt;
			&lt;td&gt;→ Payload&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Global CDN, 99.99% SLA, zero-ops&lt;/td&gt;
			&lt;td&gt;→ Contentful&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Real-time collaboration редакторов&lt;/td&gt;
			&lt;td&gt;→ Sanity&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Dev-first архитектура была преимуществом удобства. В мире, где AI-агенты читают, пишут и изменяют кодовую базу напрямую, она стала архитектурным преимуществом: инструменты работают с кодом, а не с UI провайдера.&lt;/p&gt;</summary>
    <dc:creator>Vadim Mikhu</dc:creator>
    <dc:date>2026-06-10T09:25:00Z</dc:date>
  </entry>
  <entry>
    <title>Именованное деструктурирование в Kotlin</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21266037" />
    <author>
      <name>Maxim Kalabukhov</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21266037</id>
    <updated>2026-06-10T07:30:12Z</updated>
    <published>2026-06-10T07:28:00Z</published>
    <summary type="html">&lt;p&gt;&lt;!-- obsidian --&gt;&lt;/p&gt;

&lt;p data-heading="Именованное деструктурирование в Kotlin: как избавиться от хрупкого кода"&gt;Доброго дня! Сегодня поговорим об одной из экспериментальных фич Kotlin, а именно о деструктурировании.&lt;/p&gt;

&lt;h2 data-heading="Проблема"&gt;Проблема&lt;/h2&gt;

&lt;p&gt;Деструктурирование в Kotlin - удобная вещь. Всё работает через сгенерированные методы &lt;code&gt;componentN()&lt;/code&gt;, и синтаксис получается приятным:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;data class User(val name: String, val age: Int)
 
val user = User("Max", 23)
val (name, age) = user
println("$name is $age years old")
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Но за этим удобством скрывается ловушка. Деструктурирование позиционное - значит, &lt;code&gt;name&lt;/code&gt; получает значение &lt;code&gt;component1()&lt;/code&gt;, &lt;code&gt;age&lt;/code&gt; - &lt;code&gt;component2()&lt;/code&gt;. И если кто-то решит переставить поля местами или добавить новое поле в начало класса:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;data class User(val id: Long, val name: String, val age: Int) 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Компилятор не выдаст ошибку, код соберётся - просто &lt;code&gt;name&lt;/code&gt; теперь будет содержать &lt;code&gt;id&lt;/code&gt;, а &lt;code&gt;age&lt;/code&gt; - &lt;code&gt;name&lt;/code&gt;. Ещё хуже ситуация с интерфейсами: деструктурировать объект через интерфейс нельзя, потому что &lt;code&gt;componentN()&lt;/code&gt; объявляется только в &lt;code&gt;data class&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;В Kotlin 2.3.20 появилась экспериментальная поддержка именованного деструктурирования. Идея простая: вместо позиций используем имена свойств, а синтаксис разделяется на два вида.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Именованное деструктурирование&lt;/strong&gt; - круглые скобки:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;val (val name, val age) = user
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Теперь &lt;code&gt;name&lt;/code&gt; привязывается к свойству &lt;code&gt;name&lt;/code&gt;, а не к позиции. Переставляйте поля&lt;br /&gt;
как угодно - код не сломается.&lt;br /&gt;
Если нужно переименовать переменную на месте:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;val (val years = age, val theName = name) = user
println("$theName is $years years old")
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Позиционное деструктурирование&lt;/strong&gt; - квадратные скобки:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;val [x, y] = point
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Таким образом разработчики чётко разделили намерение: если хочешь по именам, то используй &lt;code&gt;()&lt;/code&gt;, но если хочешь по позициям - то будь добр, используй &lt;code&gt;[]&lt;/code&gt;.&lt;/p&gt;

&lt;h2 data-heading="Деструктурирование через интерфейс"&gt;Деструктурирование через интерфейс&lt;/h2&gt;

&lt;p&gt;Это пожалуй самое интересное. Теперь можно деструктурировать через интерфейс, если свойства в нём объявлены:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;interface Named {
    val name: String
    val age: Int
}
 
data class User(override val name: String, override val age: Int) : Named
 
fun printInfo(entity: Named) {
    val (val name, val age) = entity
    println("$name is $age")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Раньше такой код просто не компилировался. Теперь компилятор ищет свойство по имени и находит его в интерфейсе.&lt;/p&gt;

&lt;p&gt;Поддержка экспериментальная, поэтому включается флагом компилятора:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;-Xname-based-destructuring=only-syntax
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Для Gradle:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;kotlin {
    compilerOptions {
        freeCompilerArgs.add("-Xname-based-destructuring=only-syntax")
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 data-heading="Итог"&gt;Итог&lt;/h2&gt;

&lt;p&gt;Именованное деструктурирование - небольшое, но важное изменение. Оно убирает целый класс тихих ошибок, которые легко допустить при рефакторинге, и открывает деструктурирование для интерфейсов. Синтаксис с &lt;code&gt;()&lt;/code&gt; и &lt;code&gt;[]&lt;/code&gt; хорошо передаёт намерение.&lt;/p&gt;

&lt;p&gt;Если вы активно используете деструктурирование в data-классах - стоит уже сейчас попробовать новый синтаксис и пробежаться по коду.&lt;/p&gt;</summary>
    <dc:creator>Maxim Kalabukhov</dc:creator>
    <dc:date>2026-06-10T07:28:00Z</dc:date>
  </entry>
  <entry>
    <title>Микроанимация в интерфейсах: Как сделать цифровой продукт живым, понятным и комфортным</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21265012" />
    <author>
      <name>Алексей Кондратьев</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21265012</id>
    <updated>2026-06-08T21:09:03Z</updated>
    <published>2026-06-08T20:50:00Z</published>
    <summary type="html">&lt;p&gt;Представьте, что вы нажимаете на кнопку в приложении, и... ничего не происходит. Тишина. Кнопка даже не меняет цвет. Возникло ли ощущение, что вы сделали что-то не так? Или что приложение «зависло»?&lt;/p&gt;

&lt;p&gt;А теперь вспомните, как приятно, когда кнопка слегка «вдавливается» под пальцем, когда переключатель плавно скользит из положения «выкл» в «вкл», когда сердечко лайка пульсирует после нажатия. Это и есть микроанимация — маленькая деталь, которая превращает холодный цифровой интерфейс в теплый, отзывчивый и понятный диалог между пользователем и системой.&lt;/p&gt;

&lt;h2&gt;Часть 1. Что такое микроанимация и зачем она нужна?&lt;/h2&gt;

&lt;p&gt;Микроанимация (или микровзаимодействие) — это небольшие, целенаправленные анимации, которые происходят в ответ на действие пользователя или изменение состояния интерфейса. Они длятся доли секунды (обычно 200–400 мс) и не привлекают к себе излишнего внимания, но именно они делают интерфейс «живым» и интуитивно понятным.&lt;/p&gt;

&lt;p&gt;Важно понимать разницу: микроанимация — это не декоративная заставка и не полноценный видеоролик. Это функциональный инструмент, который помогает пользователю понять, что происходит.&lt;/p&gt;

&lt;p&gt;«Микроанимации — это как специи в еде. Без них — пресно. Слишком много — несъедобно. Правильная дозировка — шедевр».&lt;/p&gt;

&lt;p&gt;Сам термин был введен дизайнером Дэном Саффером, который определил четыре ключевых компонента любого микровзаимодействия:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://www.tune-it.ru/documents/portlet_file_entry/21107385/Screenshot_1.png/ded471cc-e4b5-80aa-bc9a-1f306b564dd2?imagePreview=1" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Почему микроанимации так эффективны?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Наш мозг запрограммирован обращать внимание на движение. С эволюционной точки зрения движение могло означать «еду», «опасность» или «потенциального партнера». Микроанимации обращаются к этой древней части нашего сознания, выполняя сразу несколько важных функций:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Предоставление обратной связи — пользователь видит, что его действие зарегистрировано.&lt;/li&gt;
	&lt;li&gt;Снижение когнитивной нагрузки — плавные переходы помогают не «терять» элементы из виду.&lt;/li&gt;
	&lt;li&gt;Направление внимания — анимация указывает, куда смотреть или что делать дальше.&lt;/li&gt;
	&lt;li&gt;Маскировка задержек — интересная анимация загрузки скрашивает ожидание.&lt;/li&gt;
	&lt;li&gt;Создание эмоциональной связи — приятные мелочи вызывают радость и формируют лояльность.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Исследования подтверждают: 70% пользователей чувствуют себя более вовлеченными при работе с интерфейсами, которые используют продуманные микровзаимодействия. А люди распознают анимированные элементы на 60% быстрее, чем статичные.&lt;/p&gt;

&lt;p&gt;Однако есть и обратная сторона. Те же исследования показывают: 73% пользователей раздражаются от излишних анимаций и ищут способ их отключить. Google, например, выяснил, что каждые 100 мс задержки в интерфейсе снижают конверсию на 1%. Медленные анимации — это не «красиво», это дорого.&lt;/p&gt;

&lt;h2&gt;Часть 2. Типы микроанимаций: что, где и когда уместно?&lt;/h2&gt;

&lt;p&gt;Микроанимации решают разные задачи. Условно их можно разделить на несколько категорий:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Обратная связь (Feedback)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Это самый базовый и важный тип. Пользователь совершил действие — интерфейс подтвердил, что заметил это.&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Где использовать: кнопки, переключатели, чекбоксы, поля ввода.&lt;/li&gt;
	&lt;li&gt;Как выглядит: кнопка слегка «вдавливается» при нажатии (scale: 0.98), чекбокс плавно заполняется галочкой, поле ввода подсвечивается зеленым при правильном заполнении или красным при ошибке.&lt;/li&gt;
	&lt;li&gt;Зачем: устраняет тревогу «а сработало ли?». Исследование Якоба Нильсена показало: 82% пользователей нажимают кнопку повторно, если нет видимой реакции в первые 200 мс.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;2. Статус системы (Status)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Информирует о процессе, который происходит в данный момент.&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Где использовать: загрузка страниц, отправка форм, синхронизация данных.&lt;/li&gt;
	&lt;li&gt;Как выглядит: спиннеры (крутящиеся индикаторы), прогресс-бары, skeleton screens (пульсирующие каркасы страницы).&lt;/li&gt;
	&lt;li&gt;Зачем: показывает, что система «жива» и работает, даже если процесс занимает время. Skeleton screens, в частности, создают иллюзию быстрой загрузки и снижают воспринимаемое время ожидания.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;3. Навигация и переходы (Transition)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Объясняют, как изменилась структура интерфейса и куда «переместился» пользователь.&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Где использовать: переключение между экранами, открытие/закрытие меню, модальные окна, аккордеоны.&lt;/li&gt;
	&lt;li&gt;Как выглядит: новый экран въезжает справа, старый уезжает влево (как в мобильных приложениях); меню выезжает сверху; аккордеон плавно раскрывается, показывая скрытый контент.&lt;/li&gt;
	&lt;li&gt;Зачем: помогает пользователю не потерять контекст. Исследования показывают, что анимированные переходы снижают время поиска элементов на 30–40%.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;4. Направление внимания (Guidance)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Подсказывают пользователю, куда смотреть или что делать дальше.&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Где использовать: онбординг (обучение), сложные формы, важные призывы к действию.&lt;/li&gt;
	&lt;li&gt;Как выглядит: кнопка «Далее» мягко пульсирует; поле ввода подсвечивается; появляется подсказка со стрелкой, указывающей на нужный элемент.&lt;/li&gt;
	&lt;li&gt;Зачем: снижает когнитивную нагрузку в процессе обучения и помогает пользователю не «застревать» на сложных этапах.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;5. Эмоциональная связь (Delight)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Самый «необязательный», но самый запоминающийся тип. Создает вау-эффект и укрепляет бренд.&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Где использовать: лайки, достижения, поздравления, пустые состояния.&lt;/li&gt;
	&lt;li&gt;Как выглядит: сердечко лайка не просто закрашивается, а пульсирует или превращается в стаю бабочек; при завершении задачи вылетает анимированное конфетти; в «пустой корзине» грустная корзинка вздыхает.&lt;/li&gt;
	&lt;li&gt;Зачем: вызывает положительные эмоции, делает продукт «человечным» и запоминающимся. Классический пример — анимированный единорог, пролетающий по экрану в Asana после завершения сложной задачи.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Часть 3. Принципы хорошей микроанимации: как не навредить?&lt;/h2&gt;

&lt;p&gt;Микроанимация — это мощный инструмент, но в неумелых руках она становится источником фрустрации. Вот основные принципы, которые помогут сделать анимацию помощником, а не врагом.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Функциональность прежде всего&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Каждая анимация должна решать конкретную задачу, а не просто «быть красивой». Прежде чем добавить эффект, спросите себя: «Помогает ли эта анимация пользователю понять, что происходит?» Если нет — откажитесь от нее.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Скорость и тайминг&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Микроанимация должна быть быстрой. Пользователь не должен ждать.&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Базовые интеракции (наведение, нажатие): 100–200 мс.&lt;/li&gt;
	&lt;li&gt;Переходы между экранами, раскрытие элементов: 300–400 мс.&lt;/li&gt;
	&lt;li&gt;Сложные, кастомные анимации: максимум 500–600 мс.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Всё, что длится дольше 600 мс, — это уже не «микро», а полноценная анимация, которая начинает раздражать и тормозить работу.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Скорость и «характер движения» (Easing)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Не менее важно, как движется объект. Линейное движение (с постоянной скоростью) выглядит неестественно и роботизированно. Используйте easing-функции, которые имитируют физику реального мира:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;ease-out — для появления элементов (быстро вначале, плавно замедляется в конце). Создает ощущение мягкого прибытия.&lt;/li&gt;
	&lt;li&gt;ease-in-out — для переходов между состояниями (плавно ускоряется и плавно замедляется). Выглядит органично.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;4. Консистентность (единообразие)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Анимации должны быть предсказуемыми и соответствовать друг другу на всем протяжении продукта. Если кнопка «Сохранить» при нажатии слегка увеличивается на одной странице, она должна делать то же самое и на всех остальных. Единый «характер» анимации создает у пользователя ощущение целостности и мастерства продукта.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Ненавязчивость (Subtlety)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Хорошая микроанимация — это фон, а не главный герой. Она не должна отвлекать от основной задачи. Анимация должна быть заметна ровно настолько, чтобы быть полезной, и не более того.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Доступность (Accessibility)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Это критически важный принцип. У некоторых пользователей (например, с вестибулярными расстройствами) анимация может вызывать головокружение и тошноту.&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Всегда используйте CSS-медиа-функцию prefers-reduced-motion.&lt;/li&gt;
	&lt;li&gt;Предусматривайте возможность отключить «тяжелую» (декоративную) анимацию в настройках, оставив только функциональную.&lt;/li&gt;
	&lt;li&gt;Дублируйте визуальную обратную связь тактильной (вибрация) или звуковой, где это уместно, но не делайте ни один из каналов единственным источником информации.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Часть 4. Лучшие примеры микроанимаций&lt;/h2&gt;

&lt;p&gt;Теория хороша, но примеры вдохновляют. Вот несколько ярких кейсов, которые стоит изучить.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Поиск Google&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Анимация не в самом поиске, а в автоподсказках. По мере ввода текста появляются и обновляются варианты запросов. Это не просто удобно, но и создает ощущение, что система «думает вместе с вами» и реагирует на каждое ваше действие.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google Assistant&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Когда вы говорите «Окей, Google», на экране появляются четыре цветные точки, которые начинают двигаться, показывая, что ассистент «слушает». Когда вы замолкаете, анимация меняется, сигнализируя о готовности к ответу. Это идеальный пример того, как анимация делает невидимый процесс (обработку голоса) понятным и прозрачным.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Анимация на сайте Apple&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;При наведении курсора на пункты меню в верхней навигации, подменю появляются не мгновенно, а с легкой, едва заметной задержкой. Этот эффект не просто эстетичен, он функционален: он помогает глазу пользователя проследить путь от родительского пункта к дочернему, не сбиваясь.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Завершение задач в Asana&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;После выполнения некоторых задач на экране появляется пролетающий единорог или другое забавное существо. Это непредсказуемая награда, которая превращает рутинную «галочку» в маленький праздник, повышая лояльность пользователей и их желание завершать задачи.&lt;/p&gt;

&lt;h2&gt;Часть 5. Инструменты и технологии&lt;/h2&gt;

&lt;p&gt;Внедрить микроанимацию можно разными способами — от простых CSS-стилей до сложных библиотек.&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;CSS-анимации — идеальны для простых эффектов при наведении (hover), изменении цвета, размера, прозрачности. Легко реализуются, отлично поддерживаются всеми браузерами.&lt;/li&gt;
	&lt;li&gt;GreenSock Animation Platform (GSAP) — мощнейшая JavaScript-библиотека для создания сложных, высокопроизводительных анимаций с точным контролем тайминга и последовательности. Выбор профессионалов для нестандартных задач.&lt;/li&gt;
	&lt;li&gt;Lottie — библиотека от Airbnb, которая позволяет встраивать сложные векторные анимации (созданные в Adobe After Effects) в веб и мобильные приложения. Файлы Lottie (в формате JSON) легковесны и масштабируются без потери качества. Идеально для иконок, иллюстраций, заставок.&lt;/li&gt;
	&lt;li&gt;Framer Motion, React Spring — для тех, кто работает в экосистеме React. Позволяют декларативно описывать анимации прямо в компонентах.&lt;/li&gt;
	&lt;li&gt;Конструкторы сайтов (Tilda, Webflow, Readymag) — имеют встроенные инструменты для создания микроанимаций (эффекты при наведении, появление при скролле) без единой строки кода.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Часть 6. Заключение&lt;/h2&gt;

&lt;p&gt;Микроанимация — это не просто «приятный бонус», а неотъемлемая часть современного пользовательского опыта. Она — тот самый «секретный ингредиент», который превращает функциональный, но холодный интерфейс в отзывчивого, понятного и даже эмпатичного цифрового собеседника.&lt;/p&gt;

&lt;p&gt;Она решает конкретные задачи:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Убирает неопределенность, давая мгновенную обратную связь.&lt;/li&gt;
	&lt;li&gt;Снижает когнитивную нагрузку, делая навигацию интуитивной.&lt;/li&gt;
	&lt;li&gt;Создает положительные эмоции, формируя лояльность к бренду.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Но, как и любой мощный инструмент, микроанимация требует осознанного подхода. Слишком много, слишком быстро, слишком хаотично — и вместо помощи она становится помехой. Ваша задача — найти ту самую золотую середину, где анимация работает незаметно, но эффективно, где она комфортна и доступна для всех.&lt;/p&gt;

&lt;p&gt;Начните с малого: добавьте плавное изменение цвета на кнопке, анимируйте появление подсказки, сделайте переход между экранами менее резким. Протестируйте это на реальных пользователях. Вы увидите, как маленькие изменения сделают ваш продукт значительно более «живым» и любимым. Ведь дьявол, как известно, кроется в деталях, но именно в этих деталях — и вся магия.&lt;br /&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;</summary>
    <dc:creator>Алексей Кондратьев</dc:creator>
    <dc:date>2026-06-08T20:50:00Z</dc:date>
  </entry>
  <entry>
    <title>Gitlab CI: запуск пайплайна при обновлении upstream-репозитория</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21263024" />
    <author>
      <name>Никита Рогаленко</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21263024</id>
    <updated>2026-06-04T13:22:57Z</updated>
    <published>2026-06-04T13:20:00Z</published>
    <summary type="html">&lt;p style="text-align: justify;"&gt;Сегодня в этой небольшой заметке мы покажем пример файла .gitlab-ci.yml, который описывает пайплайн, осуществляющий какие-либо действия с нашим репозиторием в момент, когда в другом проекте выходит новая версия. Типичный сценарий, при котором подобное может пригодиться – это необходимость вызова скрипта для обновления локальной копии репозитория, представляющего собой форк другого проекта (назовем его upstream), когда в оригинальном репозитории появляются изменения.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;В первую очередь, необходимо решить, каким образом мы будем определять наиболее актуальную версию upstream. Чтобы не скачивать репозиторий целиком, удобнее будет воспользоваться командой &lt;code&gt;git ls-remote&lt;/code&gt;,&amp;nbsp;которая показывает список всех ссылок (веток, тегов и HEAD) в удаленном репозитории вместе с их ID коммитов (SHA-1). Так мы узнаем, появились ли новые коммиты. В нашем случае будем искать по тегам, так как это весьма удобный способ получить список готовых к использованию версий с номерами, чтобы по ним фильтровать и отслеживать, как далеко ушли изменения.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Если запустить команду без дополнительных флагов, то мы получим нечто вроде&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
b9a2c14f7...1a2b3c4d    HEAD
b9a2c14f7...1a2b3c4d    refs/heads/main
a1b2c3d4e...5f6g7h8i    refs/tags/v1.0.0&lt;/pre&gt;

&lt;p&gt;где будет длинный список вообще всех ссылок. Чтобы из этого получить последнюю актуальную версию, придется применить несколько фильтров. В итоге получится подобная команда:&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;code&gt;git ls-remote --tags "$UPSTREAM_URL" | awk -F'/' '{print $3}' | grep -v '\^{}' | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1&lt;/code&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Здесь мы последовательно указываем, что берем лишь теги; очищаем строки от хэшей коммитов и части с refs/..; оставляем только числа и точки, чтобы вычленить версию; сортируем и берем только последний (самый актуальный) тег. В итоге будет лишь строка с версией, которая соответствует тегу.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Чтобы понять, есть ли в нашем репозитории самая актуальная версия upstream, можно проверить, существует ли ветка, содержащая в названии номер версии (хотя это сильно зависит от специфики проекта, но вариант кажется логичным). Для этого также вполне подойдет&lt;code&gt; git ls-remote&lt;/code&gt;, но уже с флагом&amp;nbsp;--heads. Так мы сможем получить ветку нашего репозитория, которая содержит в себе тег (точки заменили на дефис)&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;code&gt;git ls-remote --heads "${YOUR_REPO}" | grep "${LATEST_TAG//./-}"&lt;/code&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Переходя же непосредственно к пайплайну, предположим, что исходным у нас является базовый питоновский докер образ (например&amp;nbsp;python:3.10-slim), в который через Dockerfile добавили произвольный python скрипт, призванный обновить локальный репозиторий правками из upstream. Его логику рассматривать не будем, поскольку она своя для кажого конкретного случая. Но что может понадобиться, так это определить ту ветку в нашем проекте, где лежат самые актуальные изменения (например, чтобы перенести их оттуда в ветку для новой версии). Для этого придется использовать уже&amp;nbsp;&lt;code&gt;git branch -r --sort=-committerdate | grep "origin/.*-main$"&lt;/code&gt;, чтобы отсортировать ветки репозитория по дате последнего коммита.&lt;/p&gt;

&lt;p&gt;В итоге получим вот такой файл .gitlab-ci.yml (с поясняющими комментариями):&lt;/p&gt;

&lt;pre class="brush:as3;"&gt;
image:
  name: dr.example.ru/your-script:latest
  entrypoint: [""]

variables:
  UPSTREAM_URL: "https://github.com/something.git"
  YOUR_APPLICATION_REPO_URL: "${CI_SERVER_HOST}/your-application.git"
  YOUR_APPLICATION_REPO_PATH: "${CI_PROJECT_DIR}/your-application"
  
stages:
  - check-version
  - update-repo


# проверка, есть ли новая версия upstream репозитория
check_new_version:
  stage: check-version
  rules:
    # Запускаем по планировщику, а после коммита - только при ручном действии
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: always
    - if: $CI_PIPELINE_SOURCE == "web"
      when: always
    - if: $CI_PIPELINE_SOURCE == "push"
      when: manual
  script:
    - YOUR_REPO="https://oauth2:${PROJECT_PUSH_TOKEN}@${YOUR_APPLICATION_REPO_URL}"
    # самый актуальный тег версии из upstream, как описывали
    - LATEST_TAG=$(git ls-remote --tags "$UPSTREAM_URL" | awk -F'/' '{print $3}' | grep -v '\^{}' | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1)
    # проверка на наличие ветки с таким тегом в названии уже в нашем репозитории
    - IF_CORRESPONDING_BRANCH_EXISTS=$(git ls-remote --heads "${YOUR_REPO}" | grep "${LATEST_TAG//./-}" || true)
    # если есть века - все обновлено, выставляем флаг, если нет - то нужно какое-то действие
    - |
      if [ -n "$IF_CORRESPONDING_BRANCH_EXISTS" ]; then
        echo "Состояние актуально. Новой версии upstream не обнаружено"
        echo "NEEDS_UPDATE=false" &amp;gt;&amp;gt; check.env
      else 
        echo "Обнаружена новая версия ($LATEST_TAG)"
        echo "NEEDS_UPDATE=true" &amp;gt;&amp;gt; check.env
        echo "NEW_UPSTREAM_VERSION=$LATEST_TAG" &amp;gt;&amp;gt; check.env
      fi
  artifacts:
    # сохраняем переменные окружения для следующего этапа
    reports:
      dotenv: check.env


# полезная работа при обновлении upstream
do_on_update:
  stage: update-repo
  before_script:
    # проверяем переменную, если обновление не нужно, то выходим, не вызывая ошибку 
    - |
      if [ "$NEEDS_UPDATE" != "true" ]; then
        echo "Состояние актуально. Ничего не требуется"
        exit 0
      fi
  script:
    # клонируем наш репозиторий с фильтром blob:none, чтобы он не занимал много места, а хранил лишь саму структуру репозитория (что надо подгрузится лениво) 
    - git clone --filter=blob:none --no-checkout https://oauth2:${PROJECT_PUSH_TOKEN}@${YOUR_APPLICATION_REPO_URL} ${YOUR_APPLICATION_REPO_PATH}
    - cd ${YOUR_APPLICATION_REPO_PATH}
    # получаем по регулярному выражению самую свежую ветку в локальном репозитории (например, забрать оттуда наши правки)
    - REQUIRED_BRANCH=$(git branch -r --sort=-committerdate | grep "origin/.*-main$" | head -n 1 | awk '{$1=$1; print $1}')
    # запустить скрипт, который нужно запустить при новой версии upstream
    - python /app/your_script.py --branch ${REQUIRED_BRANCH}
&lt;/pre&gt;

&lt;p style="text-align: justify;"&gt;Для настройки запуска по планировщику стандартно надо перейти в интерфейс Gitlab, выбрать там Build -&amp;gt; Pipeline schedules и задать нужные параметры.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;В конечном итоге мы получим пайплайн, который запускается в указанный промежуток времени, проверяет upstream. Если там появляется новый тег (в нашем репозитории еще нет ветки для такой версии), то запускается скрипт для обновления, который обрабатывает самую новую ветку из локального репозитория. Если такой тег у нас уже есть (то есть нет обновлений в upstream), то пайплайн просто покажет все стадии успешно выполненными.&lt;/p&gt;</summary>
    <dc:creator>Никита Рогаленко</dc:creator>
    <dc:date>2026-06-04T13:20:00Z</dc:date>
  </entry>
  <entry>
    <title>Эволюция инженера: как перейти в AI Engineering, не бросая всё, что вы умеете</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21262076" />
    <author>
      <name>Romo Fedoroff</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21262076</id>
    <updated>2026-06-01T08:56:46Z</updated>
    <published>2026-06-01T08:12:00Z</published>
    <summary type="html">&lt;style type="text/css"&gt;article p {
font-size:11pt;
font-family:Verdana, sans-serif;
text-align:justify;
color:#6a6a6a;
}

article img {
width: 90%;
}

article li {
 font-size:11pt;   
}

.centered {
text-align:center;
}


article .portlet-msg-info {
color: #232323;
background-color: #f9f9f9;
border-style: dashed;
border-color: #232323;
}
&lt;/style&gt;
&lt;h2&gt;&lt;meta charset="UTF-8" /&gt;Введение: почему этот разговор важен именно сейчас&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Несколько лет назад разработчик с десятилетним опытом в бэкенде мог позволить себе смотреть на машинное обучение как на экзотику - интересную, но далёкую от реальной инженерной работы. Сегодня ситуация принципиально изменилась. Крупные технологические компании переориентируют продуктовые дорожные карты, стартапы строят целые платформы поверх языковых моделей, а в описаниях вакансий для старших инженеров появляются требования, которых три года назад попросту не существовало.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Речь идёт не об очередной волне хайпа, которую можно переждать. Это структурное изменение в том, как строятся программные продукты. И здесь возникает закономерный вопрос: что делать опытному разработчику, который строил надёжные системы на протяжении многих лет, но никогда не обучал нейронные сети и не работал с векторными базами данных?&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Ответ, как это ни парадоксально, гораздо менее пугающий, чем кажется на первый взгляд. AI Engineering -&amp;nbsp;это не новая профессия с нуля. Это расширение классической инженерной практики новым инструментальным слоем. Большая часть того, что вы уже умеете -&amp;nbsp;проектирование API, работа с базами данных, управление состоянием, асинхронная обработка, паттерны проектирования -&amp;nbsp;остаётся не просто релевантной, а критически важной.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Эта статья написана именно для тех, у кого есть крепкая инженерная база и кто хочет понять, как органично встроить AI-инструменты в свой профессиональный арсенал.&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;&lt;meta charset="UTF-8" /&gt;Часть первая: Деконструкция иллюзий&lt;/h2&gt;

&lt;h3&gt;&lt;meta charset="UTF-8" /&gt;Почему опытные разработчики избегают AI-тематики&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Парадокс состоит в следующем: именно те инженеры, которым &lt;strong&gt;проще всего войти&lt;/strong&gt; в AI Engineering, нередко &lt;strong&gt;сопротивляются этому дольше всех&lt;/strong&gt;.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Причин несколько, и они вполне понятны:&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Первая -&amp;nbsp;ощущение, что нужно заново начинать с нуля. Когда в разговоре мелькают слова "трансформеры", "градиентный спуск", "функция потерь", у разработчика, который никогда не занимался машинным обучением, возникает стойкое чувство, что перед ним -&amp;nbsp;закрытый клуб со своим языком и своими многолетними правилами входа. Это ощущение понятно, но оно вводит в заблуждение.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Вторая -&amp;nbsp;профессиональная идентичность. Инженер, который годами гордился умением строить надёжные, предсказуемые системы, сталкивается с инструментами, которые по самой своей природе являются вероятностными. Это создаёт когнитивный дискомфорт: как строить систему, если один из её ключевых компонентов может давать разные ответы на один и тот же вопрос?&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Третья -&amp;nbsp;профессиональный снобизм, который иногда принимает форму скептицизма.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;em&gt;"Это просто автодополнение текста в промышленных масштабах".&lt;/em&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Это отчасти верно с технической точки зрения, но совершенно не отменяет практической ценности инструмента.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Ни одна из этих причин не является достаточным основанием для того, чтобы игнорировать происходящие изменения.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Часть вторая: Технические основы -&amp;nbsp;архитектурный взгляд&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Шаг 1. Понимание механики генеративного ИИ&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Первый шаг -&amp;nbsp;избавиться от ощущения "магии". Большая языковая модель (LLM) -&amp;nbsp;это не разум и не оракул. Это вероятностная математическая функция, которая принимает последовательность токенов на входе и возвращает распределение вероятностей для следующего токена. Из этого простого механизма, повторённого миллиарды раз на огромных данных, возникает то, что мы воспринимаем как "понимание текста".&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Для практикующего бэкенд-инженера взаимодействие с LLM через API -&amp;nbsp;это, по существу, вызов внешнего микросервиса. Разница в одном: этот сервис не детерминирован. На один и тот же запрос он может вернуть разные ответы. Это не баг -&amp;nbsp;это фундаментальное свойство, которым нужно научиться управлять.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Несколько концепций, которые необходимо понять на базовом уровне:&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Токенизация.&lt;/strong&gt;&amp;nbsp;Токен -&amp;nbsp;это не слово и не символ. Это единица текста, которую модель обрабатывает за один шаг. В зависимости от языка и модели один токен приблизительно соответствует четырём символам в английском тексте или двум-трём символам в русском. Это имеет прямые практические следствия: вы платите за токены, контекстное окно измеряется в токенах, и именно токены определяют, сколько информации модель может "удержать в голове" за один вызов.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Эмбеддинги.&lt;/strong&gt;&amp;nbsp;Представьте, что любой текст -&amp;nbsp;слово, предложение, абзац -&amp;nbsp;можно описать точкой в многомерном пространстве так, что семантически близкие тексты окажутся рядом друг с другом. Именно это делают эмбеддинги. Если вы работали с индексами в базах данных или с алгоритмами хеширования, думайте об эмбеддингах как о семантическом индексе смысла. Расстояние между двумя векторами -&amp;nbsp;это мера смысловой близости двух текстов.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Температура.&lt;/strong&gt;&amp;nbsp;Этот параметр управляет тем, насколько предсказуемы ответы модели. При температуре, близкой к нулю, модель будет воспроизводить наиболее статистически вероятный ответ -&amp;nbsp;это полезно для задач, где требуется точность и повторяемость. При высокой температуре модель "рискует" и выбирает менее очевидные токены -&amp;nbsp;это нужно для творческих задач. Выбор температуры -&amp;nbsp;это инженерное решение, которое зависит от конкретной задачи.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Контекстное окно.&lt;/strong&gt;&amp;nbsp;Это максимальный объём информации, который модель может обработать за один вызов. Современные модели имеют контекстные окна от нескольких десятков тысяч до нескольких миллионов токенов. Управление контекстом -&amp;nbsp;одна из ключевых инженерных задач при построении AI-приложений.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Вот базовый пример взаимодействия с языковой моделью через API:&lt;/p&gt;

&lt;pre class="brush:python;"&gt;
import openai
 
client = openai.Client(api_key="your_api_key")
 
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {
            "role": "system",
            "content": (
                "Ты — старший инженер-программист. "
                "Отвечай точно и по существу, без лишних слов."
            )
        },
        {
            "role": "user",
            "content": "Объясни разницу между эмбеддингами и хэш-функциями."
        }
    ],
    temperature=0.0,   # Нулевая температура для точных, воспроизводимых ответов
    max_tokens=500
)
 
print(response.choices[0].message.content)
 
# Не забывайте обрабатывать метаданные вызова:
usage = response.usage
print(f"Использовано токенов: {usage.total_tokens} "
      f"(запрос: {usage.prompt_tokens}, ответ: {usage.completion_tokens})")&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Обратите внимание на параметр &lt;em&gt;temperature=0.0&lt;/em&gt;. Когда вы строите систему, которая должна анализировать логи, парсить документы или генерировать структурированные данные, детерминированность важнее разнообразия. Это инженерное решение, а не "магический" параметр.&lt;/p&gt;

&lt;h3&gt;&lt;meta charset="UTF-8" /&gt;Шаг 2. Структурирование хаоса: от текста к типизированным объектам&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Одна из главных болей при интеграции языковых моделей в классический бэкенд -&amp;nbsp;это работа с неструктурированным выводом. Ваша база данных ожидает конкретные типы, фронтенд -&amp;nbsp;строгий JSON-контракт, а оркестрирующий код - предсказуемые объекты с известными полями. Языковая модель по умолчанию возвращает свободный текст.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Решение этой проблемы -&amp;nbsp;принудительная типизация вывода через валидационные схемы. Концептуально это аналог паттерна DTO (Data Transfer Object) в классической архитектуре, только применённый к вероятностному компоненту системы.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;В экосистеме Python стандартом де-факто стал &lt;em&gt;&lt;strong&gt;Pydantic&lt;/strong&gt;&lt;/em&gt;&amp;nbsp;в связке с соответствующими инструментами &lt;strong&gt;&lt;em&gt;LangChain&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Принцип прост: вы описываете схему ожидаемого ответа, передаёте её инструкции в промпт, и парсер принудительно приводит вывод модели к заданному типу.&lt;/p&gt;

&lt;pre class="brush:python;"&gt;
from pydantic import BaseModel, Field
from typing import Literal
from langchain_openai import ChatOpenAI
from langchain.output_parsers import PydanticOutputParser
from langchain.prompts import PromptTemplate
 
# Описываем схему так же, как описывали бы DTO или схему базы данных
class LogAnalysis(BaseModel):
    severity: Literal["INFO", "WARNING", "ERROR", "FATAL"] = Field(
        description="Уровень критичности события"
    )
    affected_service: str = Field(
        description="Название микросервиса, в котором произошла ошибка"
    )
    root_cause: str = Field(
        description="Краткое описание предполагаемой причины проблемы"
    )
    recommended_action: str = Field(
        description="Рекомендуемое первоочередное действие для устранения проблемы"
    )
    is_production_affecting: bool = Field(
        description="True, если ошибка влияет на продакшен прямо сейчас"
    )
 
parser = PydanticOutputParser(pydantic_object=LogAnalysis)
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
 
prompt = PromptTemplate(
    template=(
        "Ты — старший SRE-инженер. "
        "Проанализируй следующую строку лога и верни структурированный анализ.\n\n"
        "{format_instructions}\n\n"
        "Строка лога:\n{log_entry}\n"
    ),
    input_variables=["log_entry"],
    partial_variables={"format_instructions": parser.get_format_instructions()},
)
 
chain = prompt | llm | parser
 
log_line = "[2024-01-15 03:47:22] FATAL: Connection pool exhausted in payment-gateway-service. Active connections: 512/512. Queue depth: 847."
 
result: LogAnalysis = chain.invoke({"log_entry": log_line})
 
# Теперь result — это строго типизированный объект, а не свободный текст
print(f"Сервис: {result.affected_service}")
print(f"Критичность: {result.severity}")
print(f"Влияет на продакшен: {result.is_production_affecting}")
print(f"Рекомендация: {result.recommended_action}")&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Практическая ценность этого подхода становится очевидна, когда вы встраиваете подобный анализатор в реальный пайплайн: результат можно сразу записывать в базу данных, отправлять в систему управления инцидентами или использовать как условие для маршрутизации алертов.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Важно учитывать, что Pydantic-парсер внутри себя делает дополнительный вызов модели при ошибке формата. Если надёжность важнее скорости, используйте &lt;strong&gt;&lt;em&gt;with_structured_output&lt;/em&gt;&lt;/strong&gt;&amp;nbsp;напрямую через OpenAI -&amp;nbsp;это использует нативную поддержку JSON Schema на уровне API и более устойчиво к ошибкам:&lt;/p&gt;

&lt;pre class="brush:python;"&gt;
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
 
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
structured_llm = llm.with_structured_output(LogAnalysis)
 
prompt = ChatPromptTemplate.from_messages([
    ("system", "Ты — старший SRE-инженер. Проанализируй строку лога."),
    ("user", "{log_entry}")
])
 
chain = prompt | structured_llm
result = chain.invoke({"log_entry": log_line})&lt;/pre&gt;

&lt;h3&gt;&lt;meta charset="UTF-8" /&gt;Шаг 3. От простых вызовов к агентам&lt;/h3&gt;

&lt;p style="text-align: justify;"&gt;На определённом этапе простая схема "передали запрос -&amp;nbsp;получили ответ" перестаёт быть достаточной. Реальные задачи требуют многошаговых рассуждений, обращений к внешним источникам данных и принятия решений о том, какой следующий шаг предпринять.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Именно здесь появляется концепция агента. Агент -&amp;nbsp;это языковая модель, которой дан набор инструментов (Tools) и право самостоятельно решать, в каком порядке и как их использовать для решения поставленной задачи.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;С точки зрения классической архитектуры это напоминает паттерн Strategy: у вас есть интерфейс "инструмент", конкретные реализации (поиск в базе данных, вызов внешнего API, расчёт), и оркестратор, который выбирает нужную стратегию. Только в данном случае оркестратором выступает языковая модель.&lt;/p&gt;

&lt;pre class="brush:python;"&gt;
from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.tools import tool
from langchain_core.prompts import ChatPromptTemplate
import requests
 
# Определяем инструменты как обычные Python-функции
@tool
def get_service_metrics(service_name: str) -&amp;gt; dict:
    """
    Возвращает текущие метрики сервиса: CPU, память, количество запросов в секунду.
    Используй этот инструмент, когда нужно проверить состояние конкретного сервиса.
    """
    # В реальном коде здесь был бы запрос к Prometheus или DataDog
    return {
        "service": service_name,
        "cpu_usage": 87.3,
        "memory_mb": 1842,
        "rps": 1243,
        "error_rate": 0.023,
        "p99_latency_ms": 342
    }
 
@tool
def create_incident(severity: str, title: str, description: str) -&amp;gt; str:
    """
    Создаёт инцидент в системе управления инцидентами (например, PagerDuty или Opsgenie).
    Используй только при severity ERROR или FATAL.
    """
    # В реальном коде здесь был бы вызов API системы инцидентов
    incident_id = f"INC-{hash(title) % 10000:04d}"
    return f"Инцидент создан: {incident_id}"
 
@tool
def get_recent_deployments(service_name: str, hours: int = 24) -&amp;gt; list:
    """
    Возвращает список деплойментов сервиса за последние N часов.
    Полезно для корреляции проблем с недавними изменениями в коде.
    """
    return [
        {"time": "2024-01-15 02:30:00", "version": "v2.4.1", "author": "deploy-bot"},
        {"time": "2024-01-15 00:15:00", "version": "v2.4.0", "author": "deploy-bot"}
    ]
 
tools = [get_service_metrics, create_incident, get_recent_deployments]
 
llm = ChatOpenAI(model="gpt-4o", temperature=0)
 
prompt = ChatPromptTemplate.from_messages([
    ("system", (
        "Ты — автоматизированный SRE-ассистент. "
        "Анализируй проблемы, собирай метрики и при необходимости создавай инциденты. "
        "Всегда проверяй метрики перед созданием инцидента."
    )),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}"),
])
 
agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
 
response = executor.invoke({
    "input": "Получили алерт: payment-gateway-service начал возвращать 503 ошибки. "
             "Проверь метрики, посмотри недавние деплойменты и реши, нужно ли создавать инцидент."
})
 
print(response["output"])&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;В этом примере агент самостоятельно решает, в каком порядке вызывать инструменты: сначала собирает метрики, затем проверяет деплойменты, и только после этого принимает решение о создании инцидента. Вы не пишете эту логику явно -&amp;nbsp;модель выводит её из описаний инструментов и контекста задачи.&lt;/p&gt;

&lt;h3&gt;&lt;meta charset="UTF-8" /&gt;Шаг 4. Управление состоянием сложных агентных систем&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Когда число шагов в агентном пайплайне растёт, а логика ветвления становится нетривиальной, код на базе простого AgentExecutor начинает деградировать в запутанный клубок условных операторов. Это знакомая проблема: достаточно вспомнить любой крупный сервис, где бизнес-логика постепенно превратилась в лабиринт if-else.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Индустрия решает эту проблему с помощью &lt;em&gt;&lt;strong&gt;LangGraph&lt;/strong&gt;&lt;/em&gt; - библиотеки для построения агентных систем на основе ориентированных графов. С архитектурной точки зрения LangGraph реализует конечный автомат (Finite State Machine), где узлы -&amp;nbsp;это функции или сервисы обработки, а рёбра -&amp;nbsp;это правила переходов между ними.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Ключевое отличие от классической FSM заключается в том, что решение о переходе из одного состояния в другое может принимать языковая модель, а не жёстко заданное условие.&lt;/p&gt;

&lt;pre class="brush:python;"&gt;
from typing import TypedDict, Annotated, Optional
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage
import operator
 
# Состояние, которое передаётся между узлами графа
class SupportTicketState(TypedDict):
    ticket_id: str
    user_message: str
    category: Optional[str]           # Категория обращения (billing, technical, general)
    sentiment: Optional[str]          # Тональность (positive, neutral, negative, angry)
    response: Optional[str]           # Сгенерированный ответ
    needs_human: bool                 # Флаг эскалации на живого оператора
    history: Annotated[list, operator.add]  # Лог обработки
 
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
 
# Узел 1: классификация обращения
def classify_ticket(state: SupportTicketState) -&amp;gt; SupportTicketState:
    classification_prompt = f"""
    Классифицируй обращение пользователя. Верни ТОЛЬКО JSON с двумя ключами:
    - "category": одно из ["billing", "technical", "general", "complaint"]
    - "sentiment": одно из ["positive", "neutral", "negative", "angry"]
    
    Обращение: {state['user_message']}
    """
    response = llm.invoke([HumanMessage(content=classification_prompt)])
    
    import json, re
    data = json.loads(re.search(r'\{.*\}', response.content, re.DOTALL).group())
    
    return {
        "category": data["category"],
        "sentiment": data["sentiment"],
        "history": [f"Классифицировано: {data['category']}, тональность: {data['sentiment']}"]
    }
 
# Узел 2: генерация ответа
def generate_response(state: SupportTicketState) -&amp;gt; SupportTicketState:
    system_context = {
        "billing": "Ты — специалист по биллингу. Будь чётким и предоставь конкретные цифры.",
        "technical": "Ты — технический специалист поддержки. Давай пошаговые инструкции.",
        "general": "Ты — специалист общей поддержки. Будь дружелюбным и полезным.",
        "complaint": "Ты — менеджер по работе с клиентами. Проявляй эмпатию и предлагай решения."
    }
    
    context = system_context.get(state["category"], system_context["general"])
    response = llm.invoke([
        HumanMessage(content=f"Системный контекст: {context}\n\nОбращение: {state['user_message']}")
    ])
    
    return {
        "response": response.content,
        "history": ["Ответ сгенерирован"]
    }
 
# Узел 3: эскалация на человека
def escalate_to_human(state: SupportTicketState) -&amp;gt; SupportTicketState:
    return {
        "needs_human": True,
        "response": "Ваше обращение передано старшему специалисту. Ожидайте ответа в течение 2 часов.",
        "history": ["Эскалировано на живого оператора"]
    }
 
# Маршрутизатор: определяет, нужна ли эскалация
def route_after_classification(state: SupportTicketState) -&amp;gt; str:
    # Гневные обращения или жалобы сразу идут к живому оператору
    if state["sentiment"] == "angry" or state["category"] == "complaint":
        return "escalate"
    return "generate_response"
 
# Сборка графа
workflow = StateGraph(SupportTicketState)
 
workflow.add_node("classify", classify_ticket)
workflow.add_node("generate_response", generate_response)
workflow.add_node("escalate", escalate_to_human)
 
workflow.set_entry_point("classify")
 
workflow.add_conditional_edges(
    "classify",
    route_after_classification,
    {
        "escalate": "escalate",
        "generate_response": "generate_response"
    }
)
 
workflow.add_edge("generate_response", END)
workflow.add_edge("escalate", END)
 
app = workflow.compile()
 
# Запуск
result = app.invoke({
    "ticket_id": "TKT-001",
    "user_message": "Вы списали деньги дважды! Это уже второй раз за месяц!",
    "category": None,
    "sentiment": None,
    "response": None,
    "needs_human": False,
    "history": []
})
 
print(f"Нужен оператор: {result['needs_human']}")
print(f"Ответ: {result['response']}")
print(f"Лог обработки: {result['history']}")&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Граф явно описывает все возможные пути обработки. Любой инженер, пришедший в проект после вас, может за несколько минут понять, какие состояния существуют и как осуществляются переходы между ними. Это и есть инженерная культура, применённая к AI-системам.&lt;/p&gt;

&lt;h3&gt;&lt;meta charset="UTF-8" /&gt;Шаг 5. Архитектура RAG: дать модели доступ к вашим данным&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;У любой языковой модели есть фундаментальное ограничение: она знает только то, на чём была обучена. Ваша внутренняя документация, база знаний, архивы тикетов, технические спецификации - всё это для неё terra incognita. Паттерн &lt;em&gt;&lt;strong&gt;RAG (Retrieval-Augmented Generation)&lt;/strong&gt;&lt;/em&gt; решает именно эту проблему.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Для опытного инженера RAG - это хорошо известная архитектурная связка: поисковый индекс плюс кэш контента плюс сервис обработки запросов. Новизна заключается в том, что поиск осуществляется не по ключевым словам, а по семантической близости - с использованием эмбеддингов.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Схема работы следующая: документы разбиваются на фрагменты, каждый фрагмент превращается в вектор (эмбеддинг) и сохраняется в специализированной векторной базе данных. При поступлении пользовательского запроса система находит семантически близкие фрагменты и передаёт их языковой модели вместе с исходным вопросом. Модель отвечает, опираясь на предоставленный контекст.&lt;/p&gt;

&lt;pre class="brush:python;"&gt;
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain.schema import Document
 
# --- Этап 1: Подготовка индекса (выполняется один раз при инициализации) ---
 
# Ваша документация или база знаний
documents = [
    Document(
        page_content="""
        API аутентификации использует JWT-токены с временем жизни 15 минут.
        Refresh-токены хранятся в Redis с TTL 30 дней.
        При истечении access-токена клиент должен вызвать endpoint /auth/refresh.
        Endpoint /auth/refresh принимает только HTTP POST запросы.
        При невалидном refresh-токене возвращается 401 с кодом ошибки TOKEN_EXPIRED.
        """,
        metadata={"source": "auth-service-docs.md", "section": "authentication"}
    ),
    Document(
        page_content="""
        Сервис платежей поддерживает следующие провайдеры: Stripe, PayPal, YooKassa.
        Все транзакции логируются в таблицу payment_transactions с retention 7 лет.
        При сумме транзакции свыше 100 000 рублей требуется дополнительная верификация.
        Верификация осуществляется через SMS-код или подтверждение по email.
        Максимальное число попыток верификации — 3, после чего транзакция блокируется.
        """,
        metadata={"source": "payment-service-docs.md", "section": "payments"}
    ),
    Document(
        page_content="""
        Деплойменты в продакшен осуществляются через GitLab CI/CD.
        Каждый деплоймент проходит 4 стадии: test, build, staging, production.
        Стадия production требует ручного подтверждения от tech lead или CTO.
        Rollback выполняется командой: kubectl rollout undo deployment/&amp;lt;service-name&amp;gt;.
        Среднее время полного деплоймента — 12 минут при отсутствии проблем.
        """,
        metadata={"source": "deployment-runbook.md", "section": "deployments"}
    )
]
 
# Разбиваем на чанки с перекрытием для сохранения контекста
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,        # Символов в одном фрагменте
    chunk_overlap=50,      # Перекрытие между фрагментами — важно для сохранения контекста
    separators=["\n\n", "\n", ". ", " "]
)
 
split_docs = text_splitter.split_documents(documents)
 
# Создаём векторный индекс
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = FAISS.from_documents(split_docs, embeddings)
 
# --- Этап 2: Построение цепочки RAG ---
 
retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 3}  # Возвращаем 3 наиболее релевантных фрагмента
)
 
def format_docs(docs):
    """Форматируем найденные документы для передачи в промпт"""
    return "\n\n---\n\n".join(
        f"Источник: {doc.metadata.get('source', 'неизвестен')}\n{doc.page_content}"
        for doc in docs
    )
 
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
 
prompt = ChatPromptTemplate.from_messages([
    ("system", (
        "Ты — внутренний технический ассистент компании. "
        "Отвечай ТОЛЬКО на основе предоставленной документации. "
        "Если ответ не содержится в документации, прямо скажи об этом. "
        "Всегда указывай источник информации.\n\n"
        "Документация:\n{context}"
    )),
    ("human", "{question}")
])
 
rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)
 
# --- Этап 3: Использование ---
 
questions = [
    "Как долго живёт refresh-токен?",
    "Что происходит при попытке перевести 150 000 рублей?",
    "Сколько длится деплоймент в продакшен?"
]
 
for question in questions:
    print(f"\nВопрос: {question}")
    print(f"Ответ: {rag_chain.invoke(question)}")
    print("-" * 60)&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Здесь важно понять одну вещь: 80% качества RAG-системы определяется не выбором языковой модели, а качеством инженерии вокруг неё. Как вы разбиваете документы на фрагменты? Насколько правильно структурированы метаданные? Как настроены параметры поиска? Это классические инженерные вопросы, а не задачи машинного обучения.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;strong&gt;Ключевые решения при построении RAG:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li style="text-align: justify;"&gt;Размер чанка определяет компромисс между точностью поиска и полнотой контекста. Слишком маленькие чанки - модель не получает достаточного контекста; слишком большие - снижается точность семантического поиска. Хорошая отправная точка для технической документации: 400-600 символов с перекрытием 10-15%.&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;Метаданные критически важны для фильтрации. Добавляйте к каждому фрагменту источник, дату обновления, раздел, тип документа. Это позволяет строить гибридный поиск: сначала фильтрация по метаданным, затем семантический поиск внутри отфильтрованного подмножества.&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;Оценка качества - это инженерная задача. Стройте набор тестовых пар "вопрос - ожидаемый ответ" и измеряйте качество системы автоматически при каждом изменении параметров.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;&lt;meta charset="UTF-8" /&gt;Шаг 6. Потоковая передача и асинхронность&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Вызов языковой модели - это долгая операция. Типичный ответ на сложный запрос занимает от 3 до 30 секунд. Если вы строите API, которое синхронно ждёт полного ответа модели, прежде чем вернуть что-либо клиенту, пользовательский опыт будет неприемлемым.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Решения те же, что и в классическом бэкенде: стриминг и асинхронность.&lt;/p&gt;

&lt;pre class="brush:python;"&gt;
import asyncio
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
 
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.3, streaming=True)
 
prompt = ChatPromptTemplate.from_messages([
    ("system", "Ты — технический писатель. Пиши чётко и структурированно."),
    ("human", "{topic}")
])
 
chain = prompt | llm | StrOutputParser()
 
# Асинхронный стриминг — идеально для API на FastAPI
async def stream_response(topic: str):
    async for chunk in chain.astream({"topic": topic}):
        print(chunk, end="", flush=True)
        # В реальном API здесь был бы yield chunk для SSE или WebSocket
    print()  # Новая строка в конце
 
# Параллельная обработка нескольких запросов
async def process_multiple_queries(queries: list[str]) -&amp;gt; list[str]:
    tasks = [chain.ainvoke({"topic": q}) for q in queries]
    return await asyncio.gather(*tasks)
 
# Запуск
asyncio.run(stream_response(
    "Объясни разницу между RAG и fine-tuning языковых моделей"
))
```
 
Пример интеграции со стримингом в FastAPI:
 
```python
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
import asyncio
 
app = FastAPI()
llm = ChatOpenAI(model="gpt-4o-mini", streaming=True)
 
@app.get("/generate")
async def generate_stream(query: str):
    prompt = ChatPromptTemplate.from_messages([
        ("system", "Ты — полезный технический ассистент."),
        ("human", "{query}")
    ])
    chain = prompt | llm | StrOutputParser()
    
    async def event_generator():
        async for chunk in chain.astream({"query": query}):
            yield f"data: {chunk}\n\n"
        yield "data: [DONE]\n\n"
    
    return StreamingResponse(
        event_generator(),
        media_type="text/event-stream"
    )&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Обратите внимание: &lt;strong&gt;&lt;em&gt;astream&lt;/em&gt;&lt;/strong&gt;&amp;nbsp;не просто ускоряет ответ - он фундаментально меняет пользовательский опыт. Первые токены появляются уже через 200-500 миллисекунд, и пользователь видит, что система работает, даже если полный ответ формируется ещё несколько секунд.&lt;/p&gt;

&lt;h2&gt;&lt;meta charset="UTF-8" /&gt;Часть третья: Инженерный фундамент как конкурентное преимущество&lt;/h2&gt;

&lt;h3&gt;&lt;meta charset="UTF-8" /&gt;Почему опыт классической разработки - это преимущество, а не балласт&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Здесь возникает парадокс, который многие не сразу замечают. Рынок AI-инженеров сегодня переполнен людьми, которые умеют вызывать API языковых моделей и получать ответы. Но построить из этого надёжную, масштабируемую, поддерживаемую систему - совсем другая история.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Разработчик с десятью годами опыта проектирования распределённых систем принесёт в AI Engineering то, чего у энтузиастов-самоучек нет: понимание того, как системы ломаются, как они масштабируются, как ими управляют в продакшене.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Observability.&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Классический бэкенд-инженер знает, что без нормального логирования, трейсинга и метрик система неуправляема. В AI-системах это особенно важно, потому что вероятностный компонент делает отладку значительно сложнее. Трассировка LLM-вызовов с захватом промптов, токенов и времени ответа - это не опциональная функция, это базовая good-practice.&lt;/p&gt;

&lt;pre class="brush:python;"&gt;
import time
import logging
from functools import wraps
from dataclasses import dataclass
from typing import Any
 
logger = logging.getLogger(__name__)
 
@dataclass
class LLMCallMetrics:
    model: str
    prompt_tokens: int
    completion_tokens: int
    latency_ms: float
    success: bool
    error: str | None = None
 
def track_llm_call(func):
    """Декоратор для автоматического трекинга вызовов LLM"""
    @wraps(func)
    async def wrapper(*args, **kwargs):
        start = time.time()
        try:
            result = await func(*args, **kwargs)
            latency = (time.time() - start) * 1000
            
            # В реальной системе здесь — отправка в Prometheus/DataDog
            logger.info(
                "LLM call completed",
                extra={
                    "latency_ms": latency,
                    "function": func.__name__,
                }
            )
            return result
        except Exception as e:
            latency = (time.time() - start) * 1000
            logger.error(
                "LLM call failed",
                extra={
                    "latency_ms": latency,
                    "error": str(e),
                    "function": func.__name__,
                }
            )
            raise
    return wrapper&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Управление стоимостью.&lt;/strong&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Каждый вызов языковой модели стоит денег. Классический инженер немедленно задаётся вопросами кэширования: какие запросы повторяются? Какой TTL у кэша разумен для данного типа запросов? Можно ли батчевать вызовы?&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Обработка ошибок.&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;LLM API возвращает ошибки: rate limits, timeout, временная недоступность сервиса. Стратегия retry с экспоненциальным backoff, circuit breaker, fallback на альтернативную модель - всё это стандартная практика надёжного бэкенда, перенесённая в новый контекст.&lt;/p&gt;

&lt;pre class="brush:python;"&gt;
import asyncio
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
from openai import RateLimitError, APITimeoutError
 
@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=4, max=10),
    retry=retry_if_exception_type((RateLimitError, APITimeoutError))
)
async def resilient_llm_call(messages: list, model: str = "gpt-4o-mini"):
    """Вызов LLM с автоматическим retry при временных ошибках"""
    response = await client.chat.completions.acreate(
        model=model,
        messages=messages,
        timeout=30
    )
    return response&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Тестирование.&lt;/strong&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Как тестировать систему, компонент которой вероятностен? Классический инженер инстинктивно понимает, что нужно изолировать вероятностный компонент через моки и тестировать остальную логику детерминированно. Тесты на интеграцию с реальной моделью - это отдельный, более редкий уровень тестирования, который запускается не при каждом коммите.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2 style="text-align: justify;"&gt;Инструментальный стек AI-инженера в 2026 году&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Несколько слов о выборе инструментов. Экосистема AI-разработки меняется быстрее, чем большинство других областей, и здесь важно понимать, что именно находится под капотом инструментов, которые вы используете.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Оркестрация и цепочки:&lt;/strong&gt;&amp;nbsp;LangChain остаётся наиболее распространённым фреймворком для построения LLM-приложений. LangGraph - его расширение для сложных агентных систем. Для более лаконичного кода существует LlamaIndex, особенно популярный в RAG-сценариях.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Векторные базы данных:&lt;/strong&gt;&amp;nbsp;Chroma подходит для прототипов и небольших объёмов данных; Pinecone - для облачных продакшен-решений; Qdrant и Weaviate - для самостоятельного развёртывания с расширенными возможностями фильтрации; pgvector - если вы уже используете PostgreSQL и не хотите вводить дополнительную инфраструктуру.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Observability:&lt;/strong&gt;&amp;nbsp;LangSmith (от команды LangChain) - специализированный инструмент для трассировки LLM-вызовов; Weights &amp;amp; Biases - для более глубокого мониторинга и экспериментов; Phoenix от Arize - для оценки качества RAG-систем.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Оценка качества:&lt;/strong&gt;&amp;nbsp;RAGAS - фреймворк для автоматической оценки RAG-систем по метрикам faithfulness (верность источнику), answer relevancy (релевантность ответа) и context precision (точность контекста).&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Заключение: правильный взгляд на трансформацию&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Переход в AI Engineering - это не смена профессии. Это расширение профессионального контекста. Если переформулировать это в инженерных терминах: вы не мигрируете на новую платформу, вы добавляете новый слой абстракции поверх существующего стека.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Технические концепции, которые мы рассмотрели в этой статье: типизированный вывод, управление состоянием через конечные автоматы, поиск по векторным индексам, асинхронная обработка, стриминг - это не революционно новые идеи. Это переосмысление хорошо известных инженерных принципов применительно к новому классу компонентов.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Несколько практических рекомендаций для тех, кто готов начать:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Начните с задачи, которую вы хорошо понимаете.&lt;/strong&gt;&amp;nbsp;Возьмите реальную проблему из своей области:&amp;nbsp;анализ логов, автоматизация code review, обработка технической документации, и решите её с помощью языковой модели. Знание предметной области поможет вам объективно оценить качество результата.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Измеряйте всё с самого начала.&lt;/strong&gt;&amp;nbsp;Добавляйте логирование LLM-вызовов до того, как система уйдёт в продакшен. Стоимость, задержка, частота ошибок - эти данные необходимы для принятия архитектурных решений.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Читайте исходный код инструментов, которыми пользуетесь.&lt;/strong&gt;&amp;nbsp;LangChain, LangGraph - это Python-библиотеки с открытым кодом. Понимание того, что происходит под капотом, помогает избежать многих неожиданных проблем в продакшене.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Не переоценивайте роль модели.&lt;/strong&gt;&amp;nbsp;Подавляющее большинство проблем в AI-приложениях - это инженерные проблемы: качество данных, архитектура системы, обработка ошибок, управление состоянием. Смена модели к примеру с GPT-4o на Claude или наоборот редко кардинально меняет ситуацию. Инженерные решения - меняют.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p style="text-align: justify;"&gt;Искусственный интеллект &lt;strong&gt;не заменит&lt;/strong&gt; инженеров-программистов. Но инженеры, которые поняли, как встроить AI в архитектуру систем, как управлять его нестабильностью, масштабировать его вызовы, тестировать его поведение и обеспечивать его надёжность, станут теми, кто будет проектировать следующее поколение программных систем.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;em&gt;У вас уже есть для этого фундамент. Теперь есть и карта.&lt;/em&gt;&lt;/p&gt;</summary>
    <dc:creator>Romo Fedoroff</dc:creator>
    <dc:date>2026-06-01T08:12:00Z</dc:date>
  </entry>
  <entry>
    <title>UX-тексты для новичков: Как писать интерфейсы, которые говорят на языке пользователя</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21252009" />
    <author>
      <name>Алексей Кондратьев</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21252009</id>
    <updated>2026-05-06T17:33:50Z</updated>
    <published>2026-05-06T17:22:00Z</published>
    <summary type="html">&lt;p&gt;Представьте: вы открываете приложение, чтобы удалить давно надоевшую подписку. Вы находите нужную кнопку... а на ней написано: «Деактивировать рекуррентный платёжный мандат». Что вы сделаете? Скорее всего, закроете приложение и подумаете: «Я слишком стар для этого».&lt;/p&gt;

&lt;p&gt;Это не ваша проблема. Это проблема UX-письма (UX Writing).&lt;/p&gt;

&lt;p&gt;UX-письмо — это проектирование слов в интерфейсе. Технически это написание текстов для кнопок, ошибок, подсказок, уведомлений — всего, с чем взаимодействует пользователь. По сути — это создание диалога между продуктом и человеком.&lt;/p&gt;

&lt;p&gt;В этой статье разберём основы, на которые должен обратить внимание новичок, и главное — как не облажаться в первые же дни.&lt;/p&gt;

&lt;h2&gt;Что такое UX-тексты и чем они отличаются от копирайтинга?&lt;br /&gt;
&amp;nbsp;&lt;/h2&gt;

&lt;p&gt;Частая ошибка новичка: думать, что UX-тексты— это просто «покороче и подушевнее».&lt;/p&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-5f5bd2bd-7fff-3134-4fd4-7fe133134366"&gt;&lt;img height="312" src="data:image/jpeg;base64,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fX0tdSsc/wCpa59RTtBPHxDldq9FxqVemYPlm2XPCYMp0nu89IKeR3reTfM8Oa3nu4RztlHPsDZIgO3C5D6VyCWn1g0Ep553VEsQla6Vw4MjhVUoLjx8ZPdQekMps62o7h4tymlD/JQ6mY7XY7dHtBDY64wCIyerxw/o8vMz7clO5x5HIQV634Zxf9xOq+eav2mZsuDYDdKLCbZNyeiVzhUO6mfE4PkgqZSfaGPiB+JXD161rybRb0Yel02H3Ga33jLMesGOxVlO/pmpYpLeZZnscO7XGOB0YcO7TJyOCARyLcboV/kC9GPhGO3Cj8C/XzLqC/XwEcPFVUUlSWxO+0Y4hFER7OphI9q7Brpojkut3oxdL6PDbfPcL1i2PWDIqeip2dU1XHFQGKWONoBLneFO94aO7jGGjkkAhgbQvRtaBZht8x7OtXrFcL9kOZ25l1EwuFRStoYJwHQtibE8BzvD6HFzw7kvI447LnmzOvybanv5yTaa2/1lwxS9T1NPHFUHhokbSGspKno9jZTEBE4tADuscjhreneto3pK9CsG0BsGAawV11s2RYZQNtUcUVvlqm10EPqwmNzGkMeI+Glry0AsJDuCAtG2X23K91W/HI93UuPVVtxW0VFVPFJP3a6V9IaOlpQ/jh8jYSJH9PZvQOeA5vIfVpERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQYVq+xpPzmo/jPWasK1fY0n5zUfxnrNQEREBERAREQYVD9k1/5y3+DGs1YVD9k1/wCct/gxrNQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBBS/W3flZP3yp1BS/W3flZP3yp0BahaNJ9LLBlVVnti00xS25NXvlfVXmks1NDXTuld1SmSoawSPL3d3EuPUe55W3ogwLlbLderfVWe82+lr6CtifT1VLVRtlhnieC17HscC1zSCQWkEEditdwjSTSrTaeqqtO9M8Uxaaua2OqkstmpqF07WklrXmFjS4AkkA88crcUQcxynbPt6ze9vyTLNE8Kut0lf4k1XU2WndLM77cjunmQ/+Plb5YrBY8XtVPY8astBabbSN8OCjoaZkEELftMjYA1o/EAvSRBqNPpVp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oPKxe/P8s/508rF78/yz/nQTooPKxe/P8s/508rF78/yz/nQTooPKxe/P8s/508rF78/yz/nQTooPKxe/P8ALP8AnTysXvz/ACz/AJ0E6KDysXvz/LP+dPKxe/P8s/50E6KDysXvz/LP+dPKxe/P8s/50E6KDysXvz/LP+dPKxe/P8s/50E6KDysXvz/ACz/AJ08rF78/wAs/wCdBOig8rF78/yz/nTysXvz/LP+dBOig8rF78/yz/nTysXvz/LP+dBOig8rF78/yz/nTysXvz/LP+dBOig8rF78/wAs/wCdPKxe/P8ALP8AnQTooPKxe/P8s/508rF78/yz/nQTooPKxe/P8s/508rF78/yz/nQTooPKxe/P8s/508rF78/yz/nQTooPKxe/P8ALP8AnTysXvz/ACz/AJ0E6KDysXvz/LP+dPKxe/P8s/50E6KDysXvz/LP+dPKxe/P8s/50Cl+tu/KyfvlTrCpqaN0ZPVL9ckHaZ4/tn8am8rF78/yz/nQTooPKxe/P8s/508rF78/yz/nQTooPKxe/P8ALP8AnTysXvz/ACz/AJ0E6KDysXvz/LP+dPKxe/P8s/50E6KDysXvz/LP+dPKxe/P8s/50E6KDysXvz/LP+dPKxe/P8s/50E6KDysXvz/ACz/AJ08rF78/wAs/wCdBOig8rF78/yz/nTysXvz/LP+dBOig8rF78/yz/nTysXvz/LP+dBOig8rF78/yz/nTysXvz/LP+dBOig8rF78/wAs/wCdPKxe/P8ALP8AnQTooPKxe/P8s/508rF78/yz/nQTooPKxe/P8s/508rF78/yz/nQTooPKxe/P8s/508rF78/yz/nQTooPKxe/P8ALP8AnTysXvz/ACz/AJ0E6KDysXvz/LP+dPKxe/P8s/50E6KDysXvz/LP+dPKxe/P8s/50E6KDysXvz/LP+dPKxe/P8s/50E6KDysXvz/ACz/AJ08rF78/wAs/wCdBOig8rF78/yz/nTysXvz/LP+dBOig8rF78/yz/nTysXvz/LP+dBOig8rF78/yz/nTysXvz/LP+dBOig8rF78/wAs/wCdPKxe/P8ALP8AnQTooPKxe/P8s/508rF78/yz/nQTooPKxe/P8s/508rF78/yz/nQTooPKxe/P8s/508rF78/yz/nQTooPKxe/P8ALP8AnTysXvz/ACz/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NkcNokkloWTzTR+C6QNDyPCc3nkNb7efYuiIghhhjp4Y4IWdLImhjR9oAcAKZEQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBBS/W3flZP3yp1BS/W3flZP3yp0BERAXJdU9uGD6v6kaeao5LdL5T3XTSukr7TFQzwsp5pHvieRO18b3ObzAzgMcw8E9/Zx1pEBERAREQabp3pJp3pRDeKfTzGYLKy/XGS7XFsUsj/Hq3gB8p63HgkAdhwPxLckRBpeHaTad6fZJlGW4djMFsvGaVTK6/VUcsjnVs7DI5r3Bzi1pBmk+pDR6/s9i3REQEREBERAXM8d0JxPG9b8u18pa+51OR5fb6O1zRTvjNNR01OxjQyBrWBw6yxj3dTncuHbgdl0xEBcz130Xj12wyLCanUDLcQgZXx1k1XjNeKSqnY2ORjoHvLSDG4SclpBBLGH4uF0xEHMtBdvum23HCf5D6bW2eGmlnNVW1lXL41XXVBABlmkAAc7gAANa1oHsaOSumoiAiIgIiINNj0k07j1Ok1kjxiAZnNbvgmS6+LJ4hpAQ7wujq6OOQO/Tz+NbkiINLuukund61Jsurl2xiCozDHqWWhtl0MkgkpoJGyNewNDgwgiaQes0n1/b7FuiIgIiICIiAuZak6EYjqnnunue5JX3NtRptcKi6WyigfGKaoqZGsa187XMLj4ZjDmdDm8Hnnkdl01EBERAREQEREBERAREQEREBERAREQFzTXXQjEtwWNWfEs1r7lBbLTfqO/GKhfG3zb6fr6YJetj+YndfrBvS7sOHBdLRAREQEREEFL9bd+Vk/fKnUFL9bd+Vk/fKnQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBhWr7Gk/Oaj+M9ZqwrV9jSfnNR/Ges1AREQEREBERBhUP2TX/nLf4MazVhUP2TX/AJy3+DGs1AREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREEFL9bd+Vk/fKnUFL9bd+Vk/fKnQERa1mmomAacW9l1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ICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiIIKX6278rJ++VOoKX6278rJ++VOgIiICItQ1P1PwXRzDK/UHUbIYLNY7aAZZ5QXOe8nhkcbGgue8nsGtBJ/1AoNvRUo/9pfTZSTNo3tZ1fzmiPqx1tPZzHDK7/uuiEvq/jPB/ErJaFZ7qBqXp9T5fqRpfVaf3arqZw2yVdR408NO13EbpHFjCHOHcgtaR9pB0VERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQYVq+xpPzmo/jPWasK1fY0n5zUfxnrNQEREBERAREQYVD9k1/5y3+DGs1YVD9k1/5y3+DGs1AREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREEFL9bd+Vk/fKnUFL9bd+Vk/fKnQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBBS/W3flZP3yp1BS/W3flZP3yp0BUt1G3l6051rJfdCtmultoy25YkTFkOQXuoLLdSSh3Q+NgbJFyWv5byXlznMk6WOawuN0lQf0RPhnS3Ul916/5THN5vhXxPq+PLxdHVz358XzHt+Pn8aD3MY3ma96R6qY9pbvT0rsOOUuXzeVsuU49UF1A6XqawCVrpJOGlzgC7qY5gLXOZ0nqGoekQ1KwSk3C6TYLqvR1V2wzHrdWZhWY/TMMkl9r3ufT0FKGexxM0Zbwe3RJLz2Wz+l9Fp/zYLS6s7Vwy+h+Den6rxvL1PV+Pjw+v2fHwtU1lsTnekk21XvPIXmKrxGKnL5W8h1zgbXyNHrf2hNNAft8kfGg2XId3G9/ArM/UTJ9k1PQ4HQxunnp4b6x9wpKRg5L5GsLnMDWdz1QANDSTwPZ2Y6855rdoJZtWNn1qxy+XW51rYqigyiR8LKONrXieKQRSNImY8RgDqLXNPUOWlpXf5Io5Y3Rysa9jwQ4OHIIPtBB+JUN9EuWMw/VumsrpDjEWby/BHP1PHhAO4+LnwxT88fi/Eg3XbXud3DZtuey/bjrxiOE2euxTHBeZX4/5h5Mr30Zjb4kkz2lpiq+SA0HqA79jzcJfM2+aMy64+lA1hxaLUzMsHNHi1uuHn8XuBo6qUNpLUzwXvAPMZ8TqLfeYw/Etzr7hrXsk3D6V4dc9cck1N061VunwC+kyiY1NfbqkyQxMkjmcS7pDqmNwDeGuaHtc0Hoeg7JuG3b5FgOqVk2+aH6auz7Uy9U3n5KSWrFLRW6k4cRJNKfjIaXdPLQG8Eu5c1ruR5rus3xaN55pzYdZdMdKrfbM+yOmssUlslq6ieNr5omyHnzBaHBsvYkEc/FwvzvItGbbXNfKPflhrLLebQ+2w45kdhuNaKWefq4Yw0zyDyS1sZ4a1zmmEuLXNLunje47cHqLrxn+3G45dt8yDTu1jNKCuttZc6zx47kyaelI8MeEwjhvDuT7Q8dggu/u23XWLa/itqkZj1Rk2YZTVGgx2wUzy19XKOkOe8gEiNpfG3hrXOc97Ggdy5vGbxrp6SbTrHJ9TtQdv2nd0xuhi87crRZq6VtzoqVo6pHc+PI1xDeeelr+OOengFeXuN8L/2o237+UvV8CfAMnk+fqPhDquHRxz26vE8pzx39n4lfGcQuhkbUtYYi0iQScdPTx3557cce1BWLVzeRDbtmUu63RqipK/xPJimorzE8tifJWsppopmRPaQ9hLx6ruOQCCWnv3zTbIq3NNOsVzC5RwxVd9stDc544QRHHJPAyRzWAknpBcQOSTx7SVV70ilNh1JsXzWLBoLNDaxW2shtpZE2n8Q3Gn6u0Xq9Xs5+Na7pVifpKKjTHEJcV1S0bp7LJYbe63RVVDVGeOlNOwxNkIpyC8M4B4JHPPdB1vRnchmWo+6TV3Q282ey09l0/ZTvt9VSxyiqn6y3nxnOkLDxz26WtX8003IZnmu8fU/bvcbRZocfwi1U1dQVcEcorJnyMpXOErnPLC0Gofx0taew7+3ngOwum1Cot6W4Cl1VuVpuGWx0lGLrU2ljmUks3W3vE1zWuDenj2tHfleda9XcU0M38bn9UczqfDt1kxShlETXASVUxjt7YoI+fa+R5DR8Q55PABIDse/TfMNqdvsmO4VbrTes3vbvNeTuHiOgo6BpLTNK2N7HdT3jpYOoA9EhP1IDtmzLUDeVf8YwTK9BMF04utFkGNUV1u7r7UVEToa2eMPcyFrZm/zYa4cdXUftkqomt2keVjZXqnuh1qpudStU6qz1Rhkaf/oWzm40xpqGMO7s9QRucD34EbXDqa4n6L6Df9BunX907R/g4kFMNMd2XpAtXMzzzA8Q0r0fku2nFwZbL62easiY2d0k7AI3GpPWOqmk7j8X213LXHXnXDQXaDVayZjjGJs1Etj6WOutsPjTWtrpq9sI6OmUSH+Ze131f1f4uy5hsF/pS7wP7603+Muq3n0of9CzNvzq0/8AMadBYbTbIq3NNOsVzC5RwxVd9stDc544QRHHJPAyRzWAknpBcQOSTx7SVtCoNhGybU2TRjHM10t3g6t2jI6rG6G40FDWXt01qbK6mZIymMII4h5IYOeoNbwel3HB7XsO3BZJuU2/UGb5nFF/KC219RZbnPFGI2VU0TWPEwY0BrS6OWPkN9Xq6uABw0BY5ERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREGFavsaT85qP4z1mrCtX2NJ+c1H8Z6zUBERAREQEREGFQ/ZNf+ct/gxrNWFQ/ZNf+ct/gxrNQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBBS/W3flZP3yp1BS/W3flZP3yp0BERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQQUv1t35WT98qdQUv1t35WT98qdAVKtQtnWuOnes1/wBddmWpNlxysy9xlyLG79CXUFVMXdb5Iy1j+C55L+C1rmufJ0vDXlguqiCj+P7OtwmtGqeO6ob1NScevNuxCfzdmxPHYXCjE3U1wMrnMYOnqaOQQ9zw0NLw3lp7Ju32s2vcziVqho8inxjMMVrfhHG7/TtJfRz+qXMd0kO6HFkZ5aQ5r443Dngtd3xEFD75o56UDUHHptMsw1t02tlhrYn0dzvtsp5BX1VM8dL2ta2nZw4t7Ho8InkjqVotvGg2IbbtLrXpdhplnp6MvqKutnAE1dVv4Mk7wOwJ4DQBz0sYxvJ45PTkQUiz/bDu6tG7fONyegGW6ZUMWWWuktDYcjlrHytgjp6RsnVHFTua1xlpAQQ8+r7eCeB7eDbSNbM21pxrXDdvqrZcmrsJ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OleIY1VOBaZ7PY6WjkIPtBdExp4Px91uaINeyDBMHy252e9ZZhlivNfj1R5uz1dwt8NTNb5+pjvFp3vaXQv6o4z1MIPLGHnkDis+umm+Tap77NEPMYvcpcR0/tNfk9Vc/JyGjbWuk6YYfG6ejxRLT07+jq6unvxx3VuUQEREBERAREQYVq+xpPzmo/jPWasK1fY0n5zUfxnrNQEREBERAREQYVD9k1/5y3+DGs1YVD9k1/5y3+DGs1AREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREEFL9bd+Vk/fKnUFL9bd+Vk/fKnQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBBS/W3flZP3yp1BS/W3flZP3yp0BERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQYVq+xpPzmo/jPWasK1fY0n5zUfxnrNQEREBERAREQYVD9k1/5y3+DGs1YVD9k1/wCct/gxrNQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBBS/W3flZP3yp1BS/W3flZP3yp0BUx1B3j6yZ5rTe9BdnGm1kym6YoXR5FkV+mc220cod0vjYGPYSWv5ZyXEueyQNY5rS83OVBvRE+D/kw1K+Fev+VP8ALab4X8T6vjy8XR1c+tz4vmfb8fP40G34ju4140x1YxnSXeLpXZcfbmkzaGwZRjdQ6S3T1hc1oila97yzlzmAnqaWkglnSepvga17gvSG6J4ZkGpmTaXaPDGLFI0uliqayWcxSTthjPQ2pHLiZGc8ezurk5VSYRUxUf8ALamsc0bKgOpPhVkLmif4jH4vYP49nT3XCfSRf0KdS/ze3f8AMqVBq2ieq2//AFHOD5lkWmmk9LgmTx2+6VNVSVNUK2O2VLWSF7I3TkCURP5DSD37EFehrVuc14/ywVOg21vRinya/WmlbWXi+38yQ2mkDmtcI2OD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kgeXROlggZG8sLgHFpc08EtB49oHsXFNFdt+c6c7qNX9cb5dLHPYtQG07LZTUtRM6rh8Mt6vGY6JrG+zt0verKIgozfvR6XPUHfBdtxOo9zsFbgktTTXGks0Uk0lXU1MFNBFGyoY6IRiISRl5Ae/qADS3hzunu28nRXKdwu37ItJ8Lr7VRXe7TUMkM90kkjpmiGqimf1ujY945awgcNPfjngd13BEFetWdKtfq/a9Z9FdGshxe0ZMbJQ2C63avrqmGOCnjpmxTmldFA95e8t6Q5zWFrHFw4dxx6mnO2bH9H9tNw0EwF1OKquslbS1NwnBZ525VNO5j6mUtBcAXEAABxaxjWjnpC7iiCpGnuE5tsu2CZJZMjvVqkybEbJfa+mrbVJJLTipldNJTFjpo2OJD3xg8s45+2F0DZJc9Sci20Ybl+rWSVl8yTI6aS7y1NU1jXCnmkc6maA1oHT4Phu9nteVvetmktk1z0vv2lWSXW6W22ZBFFDU1NsfGypaxkzJeGOkY9g5LOk8tPqk8cHgjacdsVuxbHrZjFmg8G32ijhoKSMf2IYmBjG/wC5rQEHpoiICIiAiIgIiICIiAiIgIiICIiAiIgIiIMK1fY0n5zUfxnrNWFavsaT85qP4z1moCIiAiIgIiIMKh+ya/8AOW/wY1mrCofsmv8Azlv8GNZqAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiIIKX6278rJ++VOoKX6278rJ++VOgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiCCl+tu/KyfvlTqCl+tu/KyfvlToCIiAiIgIiICIseapp6cxioqIovFeI4+t4b1uPsaOfaT9oIMhERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBhWr7Gk/Oaj+M9ZqwrV9jSfnNR/Ges1AREQEREBERBhUP2TX/nLf4MazVhUP2TX/nLf4MazUBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQ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LbaLTTspaOkgBEcELBw1jQeewC9dAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREGFavsaT85qP4z1mrCtX2NJ+c1H8Z6zUBERAREQEREGFQ/ZNf+ct/gxrNWFQ/ZNf+ct/gxrNQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBBS/W3flZP3yp1BS/W3flZP3yp0BERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQQUv1t35WT98qdQUv1t35WT98qdAXzW2mar4rsS1J1H2wa+1kuMWurvr77jF7qoZHUdbBIGxNPU1hDQ6KKI9f1DXMkY4tc0A/SlatnOmOnWptBHa9RsEsOTUkJL4orrboqoROPtczxGnpP428FBQPetrjiu8mrw3aZttuhyyvu1/huN8u1DFIaKhpoWvYep7mgPYPF8Vz2ktaI2tBc53A2ffFi1hqN0O0vDblaqW42b4WqKCWirIWTQzQCahb0SRuBa5paOCCOD9pXPwLSbTHS2mmo9NtPcexiKo48cWq2w0xm49he5jQXkf94lZt6wXCMmvNqyPJcNsd2u1glM1pr663wz1FvkJaS6CR7S6JxLWklhB5aPtBBznO9uW3ulwfIaql0I07hlhtVXJHJHi1C1zXCFxDmkRcgg9wQuB+jZxakznYZXYVcHuZS5BU321zOHtEc7TE4/7g4q7dVS09ZTy0tXTxzwzsdHJHIwOZIxw4c1wPYgjsQfavLxPC8QwOztx7B8Rs2OWpkjpWUNpoIqOnD3d3OEcTQ0En2njk/Ggobsf3NYPtvxC4bUdyV6Zg2UYJdquGklubZG0lbTTzPm6o5enpaOt73AvIa9kkbmk8kN8nXjU3H99+5TSjR7Q2Spv2K4RdhkWUX6KGRlIyMPjLmtL2j2RxvYHn1XvnDW8gEm9+faMaS6qmF+pOm2NZK+maWQS3S2Q1EsLT3IY97S5oPxgEL0sL07wLTe1myafYVZMaoHO8R1NaqCKljc73nNjaA534zyUFGddrzU7Q9/lDucyq21z9O9SbLHYLzdKaF0jbfUMjhj/AJxrWkngUtPIG/VOb4nQHOYWrdd0G/8A0BborkGOaU5xDmWX5ha5rNZrdZ45ZJWy1THQiV56OGFnV1CM+u53DQ3uSLiXyw2TJrVUWPI7LQ3a21bPDno66mZPBM37T43gtcPxELS8O28aEafXgZFg+jmG2O6tJLK2hstPFPHz7QyQN6mA/aaQEFbcW0dvehvowcpwXKYHU98/kNfrjc4D7YJ6mKaXwncf2mMcxh9vrNPB4Wjej43cab6c6BY9pPrffosJrrbDUV1irbw4x0t4tk1VM8SwzcdHLJvFiLCefUHHPrBtvN0Nnu+Q7cdT7HYbXWXK5XDErrTUlFSQumnqJn0z2sjYxoLnuJIAaAST2C5ftQ0NxzIdn2m+Da56S0VZV2qkqvEteT2ZpnopHVcx58OdnVE4tIPIAJBHxIOC5dn1s3x759LbbpH5i64PozU/D10v7I3NpX1Alim6WdTRyDJTQRNJ7uPiOaOlvUfzuX3C6K6lb09FrH/lLslNjOllZWXy+3WebopYq5r2Ojpg8j15Q+ljBDeQPEPfkOAv9hmA4NpxaBYMAw6zY5besyGltVDFSxF59ri2NoBcfjJ7lVV2pbLbPjEOo1VuE0Ywi9XG+ZnW3Sz1F0ttDdJfg+QNLAHua8xgu6z0cjguJ47oPC3z7qdueoO1PP8AEML1jxm83q5UtIykoaSsD5Zi2tge4Nbx34a1xP4gszHtT9Ps69Gnf8cw/Lrdd7nimkEVFe6Wll65LfObU5gjkH9l3VDIOPtsKsb/AJrO2P8A7OWl/wDwhb//AEVxraztfu2lupu4VuX4Bj9JgeoN2pvgG1xMppaOe3MdWh8TqVnLI4+ieMeG5oBBI47FBWv0f+CZZudotPrnn9q8vpfoVHJDZqBxLor1f5JnzGokBABbC2SP1e4BDACQ+QLsWbf1uWAf7PJv3bgrnYximMYXZ6fG8Mxu12G0UvUaegtlHHS00XU4ud0RRtDW8uJceB3JJPdY9RgmD1OXU+oFThljlyikgNJBe5LdC6vhgPVzEyoLfEaw9b/VDuPXPbuUFI9WcVxfNPStYLj+Y43a77a59PpHS0Nzo46qnkc0V7ml0cjS0kEAjkdj3C6fvF0F0Mxza7qXfMf0XwW13KisFRLTVtFjtHBPA8ccOZI2MOa4fbBBVjajA8Hqcup9QKjDLHLlFJAaSC9SW6F1fDAermJlQW+I1h63+qHceue3crPvdismT2irx/JLNRXa118RhqqKupmT088Z9rJI3gte0/GCCEHzu1Y/qcbF/wCVWT/mcSvRoN/0G6df3TtH+DiXpVemmnVbh0enVdp/jdTikTGRssUtqgfbmtY4OY0UxaYwA8BwHT2I5Hde7QUFFaqGmtlroYaOjo4mU9PTU8YjihiYAGMY1oDWtDQAABwAOAgzEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQYVq+xpPzmo/jPWasK1fY0n5zUfxnrNQEREBERAREQYVD9k1/5y3+DGs1YVD9k1/5y3+DGs1AREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREEFL9bd+Vk/fKnUFL9bd+Vk/fKnQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBBS/W3flZP3yp1BS/W3flZP3yp0BERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQYVq+xpPzmo/jPWasK1fY0n5zUfxnrNQEREBERAREQebSwslq7gXOkB8y0dpHN/wDgx/ECFl+Vi9+f5Z/zqGh+ya/85b/BjWagg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/wAs/wCdPKxe/P8ALP8AnU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8ALP8AnTysXvz/ACz/AJ1OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/ACz/AJ08rF78/wAs/wCdTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/wAs/wCdPKxe/P8ALP8AnU6IIPKxe/P8s/50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ERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBBS/W3flZP3yp1BS/W3flZP3yp0BERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQQUv1t35WT98qdQUv1t35WT98qdAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREGFavsaT85qP4z1mrCtX2NJ+c1H8Z6zUBERAREQEREHm0sLJau4FzpAfMtHaRzf/AIMfxAhZflYvfn+Wf86hofsmv/OW/wAGNZqCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/ACz/AJ08rF78/wAs/wCdTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/wAs/wCdPKxe/P8ALP8AnU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8ALP8AnTysXvz/ACz/AJ1OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/ACz/AJ08rF78/wAs/wCdTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/wAs/wCdPKxe/P8ALP8AnU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8ALP8AnTysXvz/ACz/AJ1OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/ACz/AJ08rF78/wAs/wCdTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogwqamjdGT1S/XJB2meP7Z/GpvKxe/P8s/50pfrbvysn75U6CDysXvz/ACz/AJ08rF78/wAs/wCdTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/wAs/wCdPKxe/P8ALP8AnU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8ALP8AnTysXvz/ACz/AJ1OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/ACz/AJ08rF78/wAs/wCdTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/wAs/wCdPKxe/P8ALP8AnU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8ALP8AnTysXvz/ACz/AJ1OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/ACz/AJ08rF78/wAs/wCdTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/wAs/wCdPKxe/P8ALP8AnU6IMKmpo3Rk9Uv1yQdpnj+2fxqbysXvz/LP+dKX6278rJ++VOgg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/wAs/wCdPKxe/P8ALP8AnU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8ALP8AnTysXvz/ACz/AJ1OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/ACz/AJ08rF78/wAs/wCdTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/wAs/wCdPKxe/P8ALP8AnU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8s/508rF78/yz/nU6IIPKxe/P8ALP8AnTysXvz/ACz/AJ1OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/LP+dPKxe/P8s/51OiCDysXvz/ACz/AJ08rF78/wAs/wCdTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/yz/nTysXvz/LP+dTogg8rF78/wAs/wCdPKxe/P8ALP8AnU6IIPKxe/P8s/508rF78/yz/nU6IMC0gNpHD4hU1HtPP/xn/GVnrCtX2NJ+c1H8Z6zUBERAREQEREGFQ/ZNf+ct/gxrNWFQ/ZNf+ct/gxrNQERV9083p6W6la/ZBtvsNjymHJ8bmr4aupq6SnZQudSSeHL0PbO6Qgu+p5jHI9vCCwSLnmuOuGn23rT+t1I1IuUlNbaUtiihga19TWTu56IIGOcA+Q8E8EgAAucQ0EjzNvWv9g3IYW7ULEcOyyyWR87qekqL/SwU5runs98LYppC6Nrh0lx6QXcgc8O4DqyIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiIIKX6278rJ++VOoKX6278rJ++VOgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiLXM+rcvtuD5BcMAt1HcMmpLZU1Foo6vnwamsZG50UT+HNIa94DSeocdXPKDY0VL7V6SXTGHQuqyPLKynterVvpZ6Opwg0VSypN7YXMZA2I8v8J0nQSeolrXEOIcCFZbRm+6i5RpZjWRasWCjsWWXOibVXO2Usb2MpHvcXMi6Xve5rmsLA4FxIdz7PYA3pERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBBS/W3flZP3yp1BS/W3flZP3yp0BERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQYVq+xpPzmo/jPWasK1fY0n5zUfxnrNQEREBERA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EQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQQUv1t35WT98qdQUv1t35WT98qdAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERARQTTRUsT5ppWsjjBc97jw1rR3JJPYABedjmT41mFqivuJ3+23q2TFzYq221cdTA8tJa4NkjJaSCCDwex7IPYReLjuWYtmFHLcMRya1Xulp6h9LNUW2sjqY452AF8bnRuIDwCOWk8jkcjuvaQEREBERAREQEREBERAREQYVq+xpPzmo/jPWasK1fY0n5zUfxnrNQEREBERAREQYVD9k1/wCct/gxrNWFQ/ZNf+ct/gxrNQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBBS/W3flZP3yp1BS/W3flZP3yp0BapT6oab1VPe6yl1CxmanxmQxXuVl2p3MtjwSC2pcH8QuBa8EP6TyD9ora18rdqO32z6/7m9f6PUeoqq7Asazqsr58dEjoqa53OSsrW08kzmEOe2GNspDOeCZBz26g4Po7hOsukuplVUUOnWp2KZPU0o65obTeKerkjbzx1OZG8uDefY7jg/EVuhPHcr51b69rWC7fcFt26TbhbBgWUYDc6SWcWovbT1VPNMyEdcZcWgh72A8Dh7HyNcHAjj1N/e5O63DbtpFZscyH+SkWujaSpudzDy3yVqfBTyTtLgQ4N5q4uvg942SNPZxQW7/zi9AP5RfyR/wAt+B/DPi+D5H+UVJ4/i88eH0dfPXz26PqvxLbMny/E8KtLr7meT2mw2xr2xmtuldFSwB7uzWmSRwbyfiHPdfPx+l/okjpycDGe4o2t8p4IyH4YnNy8x0dPmevq6erq9fw+nw+e3Rx2W2+jly+m1829ZvoNqjUw5paMTuL7FFPVcvbWWiZpMA5cS/1XRyFjuQWt8INILAUF4rbdLbdrdT3i1XGlraCshbU01VTTNkhmicOpsjHtJa5pB5DgeCO4WDi2Z4hndrN7wjKrRkNuEroXVlproquDxGgFzPEicW9QBHI55HIVItPMzvPo+tQH7ftYb9PVaNZL5mpwPKat3V8E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Q/TWaiDC87Vfger/AFofpp52q/A9X+tD9NZqIMLztV+B6v8AWh+mnnar8D1f60P01mog82Cpq42FjrPWclz3dnw/G4n3/wAal87Vfger/Wh+ms1EGF52q/A9X+tD9NPO1X4Hq/1ofprNRBhedqvwPV/rQ/TTztV+B6v9aH6azUQYXnar8D1f60P0087Vfger/Wh+ms1EGF52q/A9X+tD9NPO1X4Hq/1ofprNRBhedqvwPV/rQ/TTztV+B6v9aH6azUQYXnar8D1f60P0087Vfger/Wh+ms1EGF52q/A9X+tD9NPO1X4Hq/1ofprNRBhedqvwPV/rQ/TTztV+B6v9aH6azUQYXnar8D1f60P0087Vfger/Wh+ms1EGF52q/A9X+tD9NPO1X4Hq/1ofprNRBhedqvwPV/rQ/TTztV+B6v9aH6azUQYXnar8D1f60P0087Vfger/Wh+ms1EGF52q/A9X+tD9NPO1X4Hq/1ofprNRBhedqvwPV/rQ/TTztV+B6v9aH6azUQYXnar8D1f60P0087Vfger/Wh+ms1EGF52q/A9X+tD9NPO1X4Hq/1ofprNRBhedqvwPV/rQ/TTztV+B6v9aH6azUQYXnar8D1f60P0087Vfger/Wh+ms1EGF52q/A9X+tD9NPO1X4Hq/1ofprNRBhedqvwPV/rQ/TTztV+B6v9aH6azUQYXnar8D1f60P0087Vfger/Wh+ms1EGF52q/A9X+tD9NPO1X4Hq/1ofprNRBhedqvwPV/rQ/TTztV+B6v9aH6azUQYXnar8D1f60P0087Vfger/Wh+ms1EGF52q/A9X+tD9NPO1X4Hq/1ofprNRBhedqvwPV/rQ/TTztV+B6v9aH6azUQYXnar8D1f60P0087Vfger/Wh+ms1EGF52q/A9X+tD9NPO1Q9lpqv974vprNRBheauD+0dt6fxyzNA/wD4eUio5HTCorJRLI36loHDI+ftD4z+MrNRAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQf//Z" width="602" /&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Золотое правило UX-текста:&lt;/p&gt;

&lt;p&gt;Пользователь не должен думать о словах. Он должен смотреть на интерфейс и уже знать, что делать.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Пример:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Плохо (копирайтинг в интерфейсе): «Нажмите на эту волшебную кнопку, чтобы отправиться в захватывающее путешествие по миру скидок!»&lt;/li&gt;
	&lt;li&gt;Хорошо (UX-письмо): «Получить скидку»&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;На что обратить внимание новичку&lt;br /&gt;
&amp;nbsp;&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Ясность превыше всего (Clarity &amp;gt; Cleverness)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Самый частый грех новичков — пытаться быть остроумным. Запомните: пользователь не ищет в вашем интерфейсе юмор. Он ищет способ закончить дело и уйти.&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;❌Остроумно, но непонятно: «Ой, что-то пошло не так с нашим магическим шаром...» (ошибка 500)&lt;/li&gt;
	&lt;li&gt;✅Понятно и полезно: «Не удалось загрузить данные. Проверьте соединение и попробуйте снова.»&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Как проверить себя:&lt;br /&gt;
Прочитайте текст вслух. Если кто-то за стеной не поймёт, о чём речь, — переписывайте.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Действие в кнопке — глагол&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Кнопка — это самый важный микротекст в интерфейсе. Пользователь должен мгновенно понимать, что случится после нажатия.&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;❌ Окей, но расплывчато: «Подтвердить», «Отправить», «Далее»&lt;/li&gt;
	&lt;li&gt;✅ Конкретно и честно: «Оплатить 590 ₽», «Удалить профиль», «Перейти к загрузке»&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Правило «Да/Нет — это зло»: &lt;/strong&gt;Если вы спрашиваете «Вы уверены?», не давайте ответы «Да» и «Нет». Дайте ответы, которые повторяют действие:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;❌ «Вы уверены?» [Да] [Нет]&lt;/li&gt;
	&lt;li&gt;✅ «Удалить навсегда?» [Удалить] [Отменить]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Ошибки — не конец света, а подсказка&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Пользователь и так расстроен, что у него что-то не получилось. Ваша задача — не добить его, а помочь.&lt;/p&gt;

&lt;p&gt;Что должна содержать хорошая ошибка:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Информацию о том, что произошло&lt;/li&gt;
	&lt;li&gt;Объяснение почему это произошло&lt;/li&gt;
	&lt;li&gt;Ответ на вопрос «Что делать?»&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
	&lt;li&gt;❌ Бесполезная ошибка: «Ошибка валидации формы. Код: 0x000A12»&lt;/li&gt;
	&lt;li&gt;✅ Полезная ошибка: «Пароль слишком короткий. Используйте минимум 8 символов.»&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Пустые состояния (Empty States) — это не мусорка&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Пустое состояние — это когда в списке нет задач, корзина пуста, поиск не дал результатов. Новички часто оставляют там просто «Нет данных».&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Пустое состояние должно:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Объяснить почему здесь пусто («У вас пока нет сохранённых адресов»).&lt;/li&gt;
	&lt;li&gt;Предложить действие («Добавить адрес»).&lt;/li&gt;
	&lt;li&gt;(Опционально) Показать пример или успокоить.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
	&lt;li&gt;❌ Плохо: «Список наблюдения пуст»&lt;/li&gt;
	&lt;li&gt;✅ Хорошо: «Вы ещё не добавили ни одного товара в избранное. Самое время найти что-то особенное! [Перейти в каталог]»&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. Последовательность (их консистенция)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ваши тексты должны быть предсказуемыми. Если на одной странице кнопка называется «Купить», а на следующей «Оформить заказ» — это разные действия в голове пользователя.&lt;/p&gt;

&lt;p&gt;Создайте глоссарий для себя:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;«Войти» — всегда «Войти», а не «Логин» или «Sign in».&lt;/li&gt;
	&lt;li&gt;«Товар» — всегда «Товар», а не «Продукт» или «Позиция».&lt;/li&gt;
	&lt;li&gt;Обращение на «ты» или «вы» — выберите одно и придерживайтесь везде. (Для массовых B2C-сервисов чаще «ты», для B2B и госуслуг — «вы»).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Как не облажаться: Типичные ошибки новичков и как их избежать&lt;br /&gt;
&amp;nbsp;&lt;/h2&gt;

&lt;h4&gt;&lt;strong&gt;Ошибка №1: «Сейчас я им объясню...»&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;Вы пишете длинный, детальный текст, чувствуя себя профессором. Пользователь его не читает. Вообще. Люди сканируют интерфейсы, а не читают.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Как избежать: Напишите текст. Затем сократите его вдвое. Затем ещё раз вдвое. Если осталось 2-3 слова — идеально.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Плохо: «Для того чтобы завершить регистрацию, пожалуйста, нажмите на ссылку, которую мы отправили на ваш электронный почтовый ящик...»&lt;br /&gt;
Хорошо: «Проверьте почту. Мы отправили ссылку для подтверждения.»&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;Ошибка №2: Копирование «крутых» фраз из чужих интерфейсов&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;Увидели в Telegram при регистрации «Ваш код — как секретная подушка для объятий: никому не показывайте». Скопировали текст к себе в банковское приложение — получился абсурд.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Как избежать: Голос продукта должен соответствовать его контексту. Банк — строго, лаконично, надёжно. Игровое приложение — игриво. Медицинский сервис — заботливо и спокойно.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;Ошибка №3: Смешение «я» и «ты» (мы/вы/я)&lt;/h4&gt;

&lt;p&gt;В одном сообщении писать «Мы не смогли обработать вашу карту», а в следующем — «Я удалю этот платёж» (от лица робота). Это сбивает с толку.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Лучшая практика:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;От лица системы = мы. «Мы обновили политику конфиденциальности.»&lt;/strong&gt;&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;От лица пользователя = вы/твой. «Вы сохранили файл.», «Ваша подписка активна.»&lt;/strong&gt;&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Смешивать без нужды — не надо.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Ошибка №4: Игнорирование негативных сценариев&lt;/h4&gt;

&lt;p&gt;Вы продумали идеальный путь «вход &amp;gt; оплата &amp;gt; спасибо». Но забыли про «забыл пароль», «карта отклонена», «соединение потеряно». В результате, когда случается проблема, пользователь выпадает в осадок.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Как избежать: Составьте карту всех возможных ошибок в вашем интерфейсе и напишите для каждой короткий, полезный текст с инструкцией. Сначала плохие сценарии, потом — хорошие.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;Чек-лист для проверки: 15 вопросов перед публикацией&lt;br /&gt;
&amp;nbsp;&lt;/h2&gt;

&lt;p&gt;Перед тем как отдать текст разработчикам или выкатить в прод, пройдитесь по списку:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Ясность: Поймёт ли мой текст человек, который видит интерфейс впервые?&lt;/li&gt;
	&lt;li&gt;Лаконичность: Можно ли удалить из этого текста хотя бы одно слово без потери смысла?&lt;/li&gt;
	&lt;li&gt;Действие: Понятно ли, что произойдёт после нажатия на кнопку?&lt;/li&gt;
	&lt;li&gt;Ошибка: Помогает ли она решить проблему, а не просто констатирует факт?&lt;/li&gt;
	&lt;li&gt;Единообразие: Так же ли я называю эту кнопку/объект в других местах?&lt;/li&gt;
	&lt;li&gt;Тон: Соответствует ли стиль текста задачам продукта (банк, игра, доставка еды)?&lt;/li&gt;
	&lt;li&gt;Призыв: Есть ли у пользователя понятное следующее действие после прочтения текста?&lt;/li&gt;
	&lt;li&gt;Пустые состояния: Не оставлены ли они без внимания?&lt;/li&gt;
	&lt;li&gt;Тревога: Не пугаю ли я пользователя без нужды («Вы уверены?» там, где достаточно «Отменить»)?&lt;/li&gt;
	&lt;li&gt;Орфография: Есть ли опечатки? (Это убивает доверие мгновенно).&lt;/li&gt;
	&lt;li&gt;Капитализация: Не пишу ли я целыми предложениями ЗАГЛАВНЫМИ БУКВАМИ? (Не кричите на пользователя).&lt;/li&gt;
	&lt;li&gt;Обращение: Везде ли выбрано единое «ты» или «вы»?&lt;/li&gt;
	&lt;li&gt;Негативные сценарии: Написал ли я текст для случая, когда пошло не так?&lt;/li&gt;
	&lt;li&gt;Адаптив: Помещается ли текст в кнопку на мобильном телефоне? (Проверьте!)&lt;/li&gt;
	&lt;li&gt;Тест: Показал ли я эти тексты хотя бы одному коллеге/другу, который не в теме?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;UX-текст — это уважение&lt;br /&gt;
&amp;nbsp;&lt;/h2&gt;

&lt;p&gt;Писать хорошие интерфейсные тексты сложнее, чем кажется. Потому что это требует не столько литературного таланта, сколько эмпатии и самоограничения.&lt;/p&gt;

&lt;p&gt;Ваша задача как UX-писателя — убрать себя из интерфейса. Убрать остроты, сложные конструкции, гордость за удачную фразу. Оставить только то, что нужно пользователю здесь и сейчас, чтобы он сделал своё дело и почувствовал себя умным и успешным.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Помните:&lt;br /&gt;
Пользователь не пришёл к вам восхищаться вашим слогом. Он пришёл удалить подписку, заказать пиццу или перевести деньги. Помогите ему сделать это быстро и без головной боли. И тогда ваш продукт полюбят. А хороший UX-текст останется незамеченным — это и есть высшая оценка.&lt;/em&gt;&lt;/p&gt;</summary>
    <dc:creator>Алексей Кондратьев</dc:creator>
    <dc:date>2026-05-06T17:22:00Z</dc:date>
  </entry>
  <entry>
    <title>Неоднозначные отношения Kotlin с Hibernate</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21251941" />
    <author>
      <name>Maxim Kalabukhov</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21251941</id>
    <updated>2026-05-06T13:34:09Z</updated>
    <published>2026-05-06T13:19:00Z</published>
    <summary type="html">&lt;p dir="auto"&gt;Kotlin позиционируется как язык, который призван сделать жизнь Java разработчика счастливее. Код становится лаконичнее, Null-safety спасает от NPE, а стандартная библиотека - удовольствие. Но когда мы подключаем к этому котлу JPA-провайдер (например&amp;nbsp;Hibernate), начинаются интересные сюрпризы.&lt;/p&gt;

&lt;p dir="auto"&gt;Хотя Kotlin и Java отлично совместимы, их парадигмы иногда конфликтуют. Hibernate изначально проектировался под Java-бины, а Kotlin привносит свои концепции: immutable data classes, свойства вместо геттеров/сеттеров и строгую типизацию.&lt;/p&gt;

&lt;h2 dir="auto"&gt;Ловушка &lt;code&gt;data class&lt;/code&gt; и &lt;code&gt;equals&lt;/code&gt;/&lt;code&gt;hashCode&lt;/code&gt;&lt;/h2&gt;

&lt;p dir="auto"&gt;Это, пожалуй, самая популярная ошибка. Все мы любим &lt;code&gt;data class&lt;/code&gt;, но сущности помеченные @Entity - это не просто DTO.&lt;/p&gt;

&lt;pre class="brush:as3;"&gt;
@Entity

data class User(
 @Id 
 @GeneratedValue
 val id: Long? = null,
 val username: String
)
&lt;/pre&gt;

&lt;p dir="auto"&gt;Так в&amp;nbsp;чем же проблема? Первое - это&amp;nbsp;&lt;strong&gt;Lazy Loading:&lt;/strong&gt; Hibernate создает прокси-объекты, наследующие сущность. Если в &lt;code&gt;equals&lt;/code&gt; используется &lt;code&gt;==&lt;/code&gt; или &lt;code&gt;===&lt;/code&gt;, вы можете получить некорректные сравнения. Второе это -&amp;nbsp;&lt;strong&gt;изменение ID:&lt;/strong&gt; Когда вы сохраняете новую сущность, Hibernate присваивает ей ID. Если &lt;code&gt;equals&lt;/code&gt;/&lt;code&gt;hashCode&lt;/code&gt; опираются на ID (как генерирует &lt;code&gt;data class&lt;/code&gt;), хеш-код объекта изменяется прямо в момент сохранения. Если этот объект лежал в &lt;code&gt;HashSet&lt;/code&gt;, он «потеряется», так как хеш изменился после добавления.&lt;/p&gt;

&lt;p dir="auto"&gt;Не используйте &lt;code&gt;data class&lt;/code&gt; для сущностей, либо отключите генерацию методов и напишите их руками, используя бизнес-ключ (например, уникальный username), а не ID.&lt;/p&gt;

&lt;h2 dir="auto"&gt;Проблема &lt;code&gt;final&lt;/code&gt; и отсутствие &lt;code&gt;open&lt;/code&gt;&lt;/h2&gt;

&lt;p dir="auto"&gt;В Kotlin все классы и методы по умолчанию &lt;code&gt;final&lt;/code&gt;. Hibernate же требует наследоваться от класса сущности для создания прокси (например, для Lazy Loading). Без дополнительных настроек вы получите ошибку при попытке подгрузить данные лениво.&lt;/p&gt;

&lt;p dir="auto"&gt;Самый простой способ - использовать магию плагинов в &lt;code&gt;build.gradle&lt;/code&gt;. Плагин &lt;code&gt;kotlin-spring&lt;/code&gt; (или &lt;code&gt;all-open&lt;/code&gt;) делает все классы, помеченные аннотациями (в т.ч. &lt;code&gt;@Entity&lt;/code&gt;), открытыми, а плагин &lt;code&gt;kotlin-jpa&lt;/code&gt; еще и &lt;code&gt;open&lt;/code&gt;-ит методы, имеющие аннотации &lt;code&gt;@Entity&lt;/code&gt;&amp;nbsp;и т.д.&lt;/p&gt;

&lt;h2 dir="auto"&gt;Конструкторы без аргументов&lt;/h2&gt;

&lt;p dir="auto"&gt;JPA-провайдеру нужен конструктор по умолчанию (без аргументов), чтобы создать экземпляр класса через рефлексию, а затем заполнить его поля данными из ResultSet. В Kotlin, если вы напишете primary конструктор с параметрами, конструктора по умолчанию не будет.&lt;/p&gt;

&lt;p dir="auto"&gt;Здесь на помощь приходит тот же плагин &lt;code&gt;kotlin-jpa&lt;/code&gt;. Он сгенерирует для вас невидимый конструктор без аргументов, если вы пометите класс аннотацией &lt;code&gt;@Entity&lt;/code&gt;.&lt;/p&gt;

&lt;h2 dir="auto"&gt;Проблема Default values&lt;/h2&gt;

&lt;p dir="auto"&gt;Допустим, у нас есть такое поле:&lt;/p&gt;

&lt;pre class="brush:csharp;"&gt;
@Entity

class Task(

   val status: String = "NEW"

)
&lt;/pre&gt;

&lt;p dir="auto"&gt;Разработчик ожидает, что если он сохранит объект, не задавая статус, то в БД будет "NEW". Но Hibernate при построении SQL-запроса (&lt;code&gt;INSERT&lt;/code&gt;) смотрит на значение поля. Если мы создали объект через &lt;code&gt;new Task()&lt;/code&gt;, в памяти статус "NEW". Но если мы мапим результат из базы, Hibernate использует конструктор без аргументов (о котором говорили выше) и сеттеры.&lt;/p&gt;

&lt;p dir="auto"&gt;Если в БД колонка не имеет &lt;code&gt;DEFAULT&lt;/code&gt;, а вы передаете &lt;code&gt;null&lt;/code&gt; (или Hibrenate решит не вставлять это поле), возникнет ошибка. И наоборот, значение по умолчанию в Kotlin не синхронизируется со схемой БД.&lt;/p&gt;

&lt;p dir="auto"&gt;Всегда дублируйте дефолтные значения на уровне бд&amp;nbsp;и инициализируйте поле в классе. Либо, что более надежно в Enterprise-разработке, используйте &lt;code&gt;@PrePersist&lt;/code&gt;.&lt;/p&gt;

&lt;p dir="auto"&gt;&amp;nbsp;&lt;/p&gt;

&lt;p dir="auto"&gt;В итоге получается, что Kotlin и Hibernate - отличная связка, но она требует понимания того, что происходит «под капотом». Плагины &lt;code&gt;kotlin-jpa&lt;/code&gt; и &lt;code&gt;kotlin-allopen&lt;/code&gt; решают 90% проблем с магией байт-кода, а остальные 10% решаются внимательным отношением к &lt;code&gt;equals&lt;/code&gt;, &lt;code&gt;hashCode&lt;/code&gt; и контрактам JPA.&lt;/p&gt;</summary>
    <dc:creator>Maxim Kalabukhov</dc:creator>
    <dc:date>2026-05-06T13:19:00Z</dc:date>
  </entry>
</feed>

