<?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-06-12T07:26:17Z</updated>
  <dc:date>2026-06-12T07:26:17Z</dc:date>
  <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/EAvSRBqNPpVpjSZnJqPS6b4tDlkpcZL9HZ6dtxeXM6HE1IZ4p5Z6h9bu3t7OyzsuwfC9QLULDnuI2XJLYJWztobxb4qyDxWghr/Dla5vUATweORyVsCINVrtMdNrnh0Gn1y09xqrxWnbG2GxVFpp5LfE1h5YG07mmMBp7jhvY9wvRxjFcYwmy0+NYZjdrsFopes09Ba6OOlpoupxc7ojjAa3lxc48DuSSe5Xsog1KDSrTCmzR+pEGm+LxZbL1GS/R2enbcXEx+GeakM8U8x+ofW7t7ezsqD7ntLdT7/6SzSzO7BptlFxxq3z48au80lnqJqGnEdY90hknawxs6WkE9Th0jueF9JUQc5ve3jQXJcmOZ5DovhNyvr5PGkuFVYaaWeSQccPe9zCXuHA4c7kj4iugRRxwRtiiYGMYA1oaOAAOwAA+IKZEHO71t80HyTJDmOQaM4Tcb4ZTM64VVgpZZ5JOeet73MJc4HuHO5IPcFetNpTpbUZjDqHPpvi8uVU/T4V8fZ6c3CPpZ4bempLPEHDPUHDuze3sW3Ig0+96SaVZNk9JnGSaY4pdMjoXRGlvFdZqaetgMTuqIxzvYXt6Hes3hw6T3HBXv3my2bJLTV2HIbTSXS2XCJ0FXR1tOyeCeJw4cySN4LXtI7EEEFeiiDXsPwXCdPrU6xYBh1jxm2vmdUvorNb4aKAyuADpDHE1rS4hoBdxyQB9oLCzTSnTDUiejn1D03xbKZLeHikferPT1zqYP4LxGZmOLOS1vPTxz0jn2BbciAtOxzSTSrD8irMvxLTPFLJfbiJBV3O3WWmpquoEjw+QSSxsD39TwHHqceXAE91uKINazPTvANR6CC16h4Rj2T0VLL48NNebXBWxRy9Jb1sZM1wa7pJHIHPBIWPkWlWl+YWK3Ytlum+LXuy2cMbb7dcrPT1NLRhjOhgiikYWR8M9UdIHDew7LbUQYNvt9DZ6GmtNpoaeioqKFlNTU1NG2OKCJjQ1kbGNAa1oaAA0AAAcBeBi2lWl+C3WtvuEab4tj1yuYLa6stVnp6SeqBd1ESSRMDn8u9Y9RPfv7VtqINRp9KtMaTM5NR6XTfFocslLjJfo7PTtuLy5nQ4mpDPFPLPUPrd29vZ2W3IiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiCCl+tu/KyfvlTqCl+tu/KyfvlToC8PK8OxLO7NLjma4xar/ap+8lDc6OOpgeR7CWPBbyOex45HxL3EQcTsuzLarj90be7XoJhzauJ4kjdLbmzsa4ewtjk5YCPi4b2Pcd12Q01OaXyhgYYCzw/C6B0dHHHT0+zjjtwshEGn4ZpHpTpvUVNXp3pjiWLVFaxsVRLZbLTUL5mNPLWvdExpcAe4B5AK2SvoKK6UVRbLnRw1lJWRPgqKeeMSRSxPBD2PYQQ5pBIII4I7FZiINQwrSjS3TeSrm0400xXFZK8MbVOstmpqEzhnJYJDCxvWB1Hjnnjk8e1beiIPDyrEMSzqzS47m+LWjIbXM5j5aC7UUVXTvcw9TS6OVpaSCOQSOx7hS45jWO4fZKXG8Rx+22S00QcymoLbSR01NAHOLnBkUYDWguJceAOSSfaV66INRtmlOl1ky6qz6zabYvQZPXGQ1V6pbPTxV85kPLzJUNYJHdRHflx5+NfmPSTSuDMzqPFpnijMtc4yG/NstMLiXlnhl3mQzxeTH6hPV9T29nZbgiDw8pxDFM6ssuOZvi9oyG0zvY+WgutDFV00jmODmF0UjS0kOAIJHYjkKXHMbxzDrJTY3iOP22x2miDm01BbaSOmpoAXFzgyOMBrQXOLjwByST7SvXRBzzONv8AodqTdG3zP9IsRv8Acm9I85X2mCWcgexrpHN6nNH2iSPxLacYxHE8ItTLFhmMWqwW1ji5lFbaKOlgDjwCRHGA0E8DvwvaRBzvIdvmg2W3qqyPK9EMAvV2r3iSqr7hjVFU1E7gA0F8r4y5xAAHJJ7ABezh2l2menhl/wAn+nWM4yZm9MvwPaKei62888O8JreRz34K2tEGp5dpdpnn1dQXPOtOsXyOstfPkqi72inrJabkhx8J0rSWcloPqkdwD8S2Ooo6StYI6ykina09QbKwOAP2+Dz3WSiDXswwXCdQbU2xZ/h1jya2smbUsorzb4a2AStBDZBHK1zQ4BxAdxyAT9sr0bRZ7Vj1rpLHYbbSW23W+FlNSUdJC2GCnhYA1kccbQGsYAAA1oAA7BegiDmOU7Z9vWb3t+SZZonhV1ukr/Emq6my07pZnfbkd08yH/x8rfLFYLHi9qp7HjVloLTbaRvhwUdDTMgghb9pkbAGtH4gF6SICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgwrV9jSfnNR/Ges1YVq+xpPzmo/jPWagIiICIiAiIgwqH7Jr/wA5b/BjWavNpYWS1dwLnSA+ZaO0jm//AAY/iBCy/Kxe/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/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/50Cl+tu/KyfvlTrCpqaN0ZPVL9ckHaZ4/tn8am8rF78/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/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/AJ0E6KDysXvz/LP+dPKxe/P8s/50E6KDysXvz/LP+dPKxe/P8s/50E6KDysXvz/LP+dPKxe/P8s/50ENq+xpPzmo/jPWasC0gNpHD4hU1HtPP/xn/GVnoCIiAiIgIiIMKh+ya/8AOW/wY1mrCofsmv8Azlv8GNZqAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiIIKX6278rJ++VOoKX6278rJ++VOgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiCCl+tu/KyfvlTqCl+tu/KyfvlToCIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgwrV9jSfnNR/Ges1YVq+xpPzmo/jPWagIiICIiAiIgwqH7Jr/AM5b/BjWasKh+ya/85b/AAY1moCr7p5vT0t1K1+yDbfYbHlMOT43NXw1dTV0lOyhc6kk8OXoe2d0hBd9TzGOR7eFYJfKnaX/AFrmq3/mGVf4wIPqsq/aTb09K9ZNcMn0BxiyZVTZFinwgKyor6WnZRyeUqW08vhvZO955e4FvUxvLe54PZWBXyp2Hf1mGtP/AIsq/wCcwoPqsiqJvU3xz7drxZdK9MsSZlmpWSMY+loZA98NIyR5jiL44yHyySPBDImuaSB1Fw9UO4hkm8D0iG3aG3Z7uN0Px6owqtqY4ajyXhNlpi89meJBUS+C8gdvFaQSennq9gfSpFouH6sYvqJpHR6xYbV+astytL7rTukbw5gaxxfHIAez2Pa9jgD2cwjn4189tGt63pI9wNor79pDo5p9f6C2VIpKqYRimEcxaHBvE9ewn1SDyAQg+oaKiGxzefr1r5rtl+kOsOPYra3YtZ6uomZaqWVksdbBWQU743PdPIxzR4kgPT7SAQ7j2+zi+8bVW8+kEuW1mrtuONxGjlqmx1EdJMK8iO3eYbzIZSz652PqfU9vb3QXWREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBBS/W3flZP3yp1BS/W3flZP3yp0BEVCsP3V74NY9Q9S8X0X020qrrbp9klTY5JbrLVwTPY2eZkTjxUAOcWwkkgAc+wBBfVFQXPt1e+fRTLMAtWsmmuk9HbM3yKmssctrkrJ5QHyxteR/pBDSGv5BII5+JdK3k7xrttW1C0ttslpttTi+VzVrr/UTU001XBTwPpwfLBkjW+IRM/jra4c8ewcoLYIqQ5Lrj6SEWOXVXHduWC0mLRwG4NxysrJai/eS6esl/RMxvi9Hfw2s6wfVLHOHSu97YNyeIbntKafUvHoXWyWCV9HeLbPIHvt9Wxoc9hfwA5ha4Pa/gctcOQ0hzQHY0VFW7zNy+4XMr9ZdlekmOXPEsbqzQ1WV5RUObBVS9yDCxssfDSByAPEd0OY5zY+oBbNopvH1Qi1ppdt+7XTKgwfNbvB5ix19rqOu23IHqLWN5kk6XEMcGuEjgXgsLWO4BC4iKte9fcVqHt5xvCX6XWOxXfIMxyeGww095ZK6HiSN3BHhSMId4nhjkkgAnt7OOSasbgvSO6L6fXjUzNtKdGIrJY445Kt9NU1ksgD5WRN6WCpBPrPH+5Be9Fy/A9X/AIT2549rnmdKyB1ZiFLk1yp7bE94Dn0jZ5I4Iy4vcSSWsaXFxPA5JVbMc3DekL1moX59pDt7wew4hJNIbbTZZVTNuNdExxb7BNF0EkEguY1v2nOHcheNFX3aVugq9xFryex5dhkuJZ5gVxFryazl/XHDM50jWPjdyT0kxSAg88Fh4c4cOPGNa9wXpDdE8MyDUzJtLtHhjFikaXSxVNZLOYpJ2wxnobUjlxMjOePZ3QXpRVA0T1W3/wCo5wfMsi000npcEyeO33SpqqSpqhWx2ypayQvZG6cgSiJ/IaQe/YgrbtNNyGZ5rvH1P273G0WaHH8ItVNXUFXBHKKyZ8jKVzhK5zywtBqH8dLWnsO/t5CyKIiAiKtO67crnG27NNLa4WSx1OnuW3xtkyKvqo5vNW57nNLJI3tkDODGZX8OY76w7v3HAWWWLVVNPQ081bWVMVPBTxulllleGMYxo5c5zjwAABySewCwssyW1YZi14y++z+DbbHQVFyrJfucEMbpHn/c1pXzr1f3Tasatej3uOoOd0djxL/KTlMWK2qS3MnY2O1GQ+PLK6R7y7qFPUxHpDQWAnjv2DsV+9JrpVNeqvHtG9MdRNUqqilMb58es5dSHjsS15JkI+0fD6SO4PHHPTtumvmrOtl4vUma7ccj0ysdBTROoam/SPbUV0znHqaInxRuYGtHPPDh39o9ir1pvrxuDtun1ut2zLZrFV6U2SIw2u53m5R0lTeY2OLX1UcDnxvLpHAvLvXLjySeTwO9bUd3lg3KU18x+vxisw/O8Sl8vfscrn9UkBDiwyRuLWucwPBa4FrXMdw1w4LXOCwyKpm4Ld9n9h1dg237YdN6XOtSvKiuub6+bw7daIS0OAmIezl3Q5jjzIxrfEjAL3P6BpsO8TcvoDm+PWPeppRjVqxPKKwUFJlmMTPdT0c54+vtdLJ6o55PPhu6A9zRJ0kILyouea+aiV+keiua6nWimpamuxyy1NwpIqoOdDLMxhMbXhrg4tLuAeHA8ewhVf091t9JTqfg9k1CxbSXRh1oyCjjr6M1FVWRyGF45aXMNT2JHxILxoq1bFNyed7ndMcgzLUGyWO2XGz5NPY2xWeOZkJjjp6eTqPiyPcXdUzxyCBwB29pUm1LchmWvGbax41lVps1DTad5S+x22S3xytfPCJqhgdMXveC/iBndoaOSe3s4CyKKj+8z0hdZoBqlj+kGmNnsd8vskkUmQyXISvioWSloihYInsPilp8Q9RIa0x9iXHp6rrJkO+a255VU2heAaY3bEWwwmnqr9V1EdY6UsHiBzWTMbwH8ger7EFi0Xz10I3ZekC3G4tcMz010r0fmttsustmnNZNWQPFTHHFI4BpqTy3pnZwft8/aXZt2u5bVTbdpHp3lkGP41U5Nkd7t9mvlNUsmkpIJJaWSSfwOiRru0rOGlzner7eT3QWkREQERaFrlnN00v0azfUex01NU3DGbBXXWlhqg50MksMLntbIGuDi0kd+HA8ewhBvqKh+l+4L0j+runto1RwzSHR+tsl5hfUUjH1lVBPK1kjmEdL6rhri5hA6jx8a7ftB3SHc1iN7nvWIvxfLMRuZtF/tXjGVkU4B4exxAIa4tkb0u7tcwjlw4cQsCipbqNvL1pzrWS+6FbNdLbRltyxImLIcgvdQWW6klDuh8bA2SLktfy3kvLnOZJ0sc1hccXGN5mvekeqmPaW709K7DjlLl83lbLlOPVBdQOl6msAla6SThpc4Au6mOYC1zmdJ6gF3EVUN4u5nWnRbUfSvTbRnGcUu901HqKuiY2/CfobOx9O2INfFKwNaTOeS4H2DjjvzoeoW6ze/t0tVLqDuB0IwKswhtbDSXCoxe5SippfEPS13Eksg7nsOW9JPDS5pcCgvWi8m0ZFab5jVFlttqfFtlwoY7lBLxx1QPjEjHcfFy0gqieh+6X0hO4bCBqLptpRo/LZXVk1Ex1ZNWQSGSPjq9U1Ps9Yd/8AWg+gSKq+yzcvqzr1fNU8W1cx3GbTdtObxDZnMsbJxG+brqWTdTpZX9QD6fsW8dufb241rUbeJrZnGsV90L2b6YWbLLliL/CyPIr5OWW2jmDi18TA2SPlzXgt5Li5zmSBrHNYXkLmoqZ6Z7wNa8O1nsegu8fTC0YpdsuPh43frFM59urZi7pZC4Okk4c5/DQQ8Oa98YcxrXhy3yDcjmT98M+2T4Hs38m4sWF8Fd4cvnvG6Wnp6uvo6O/s6OfxoLIIuDb0tecq23aE3DVPDLVabhc6Ovo6VsFzZI+Atlk6XEiN7Hcgez1lh7ktwmXaNbUJdesctNoqr5HR2ipFLXRyupOqrlgY8dLHtfwBMePW9oHPKCwqLV9Nsirc006xXMLlHDFV32y0NznjhBEcck8DJHNYCSekFxA5JPHtJW0ICIiAiIggpfrbvysn75U6gpfrbvysn75U6AiKhWH7q98GseoepeL6L6baVV1t0+ySpsckt1lq4JnsbPMyJx4qAHOLYSSQAOfYAgvqioLn26vfPoplmAWrWTTXSejtmb5FTWWOW1yVk8oD5Y2vI/0ghpDX8gkEc/Eu97tt11l2wYxanQ49U5RmOVVRoMcsFM8tfVygtDnuLQXBgL428NaXOe9jWjuXNDv6Kh1+1/8ASX6bY9Nqln+3bT6uxehidW3S1WuseLjR0rBy55c2plHIb3Ja2TpAJLWgHjuse6ax5rtMyDcxpbDFUG2Y9cLnFQXFpPgVtNE5z6aoaxwPZ7eD0uHU0hzTwQUHfEVUtg+8mv3Z4lkP8r7ZaLVleN1rBUUlsbIyCWilbzFMxsr3v562yscOogdLD26gF1TdBrpbtu2iWSaqVccM9Xb4BDa6SYnpq6+U9EEZDSHFvUep3SQehjyD2QdZRVy2O7jct3MaJVOp2dWqy2uup71VW50dsZLHTiKKOJ4cfFe88/zh5PVxwB2XIm7zNy+4XMr9ZdlekmOXPEsbqzQ1WV5RUObBVS9yDCxssfDSByAPEd0OY5zY+oBBepFTvRTePqhFrTS7b92umVBg+a3eDzFjr7XUddtuQPUWsbzJJ0uIY4NcJHAvBYWsdwDukG5HMn74Z9snwPZv5NxYsL4K7w5fPeN0tPT1dfR0d/Z0c/jQWQRcG3pa85Vtu0JuGqeGWq03C50dfR0rYLmyR8BbLJ0uJEb2O5A9nrLD3JbhMu0a2oS69Y5abRVXyOjtFSKWujldSdVXLAx46WPa/gCY8et7QOeUFhUWr6bZFW5pp1iuYXKOGKrvtlobnPHCCI45J4GSOawEk9ILiBySePaStoQEWha5ZzdNL9Gs31HsdNTVNwxmwV11pYaoOdDJLDC57WyBrg4tJHfhwPHsIVTNL9wXpH9XdPbRqjhmkOj9bZLzC+opGPrKqCeVrJHMI6X1XDXFzCB1Hj40F8EVftoO6Q7msRvc96xF+L5ZiNzNov8AavGMrIpwDw9jiAQ1xbI3pd3a5hHLhw4+ftS3IZlrxm2seNZVabNQ02neUvsdtkt8crXzwiaoYHTF73gv4gZ3aGjknt7OAsiiKt22Pcjmmter+umn2TWeyUdBpfkbLPapqCOVs1RCaitjLpy+RzS/ppYzyxrByXdvYAFkUVCsP3V74NY9Q9S8X0X020qrrbp9klTY5JbrLVwTPY2eZkTjxUAOcWwkkgAc+wBRZ9ur3z6KZZgFq1k010no7Zm+RU1ljltclZPKA+WNryP9IIaQ1/IJBHPxIL9IuAbtt11l2wYxanQ49U5RmOVVRoMcsFM8tfVygtDnuLQXBgL428NaXOe9jWjuXN4bftf/AEl+m2PTapZ/t20+rsXoYnVt0tVrrHi40dKwcueXNqZRyG9yWtk6QCS1oB4C+KLnWg+tmIbhdMbRqnhMkooLm1zJaabgTUdQw9MkEgBI6mu+MdnNIcOxCrbmm53dnkG6DUDQPb5gWnd3pMHpqGqkqb8+pilLZqaB7+Xtna0kSzOaAGj1W9+TyUF10VKNNt0W6qm3YYttr18wXT20nIrPU3ky2B1TLIyFkNS6PiR87mgmSmIILT2/18ro2mm5DM813j6n7d7jaLNDj+EWqmrqCrgjlFZM+RlK5wlc55YWg1D+OlrT2Hf28hZFFwXenrxlm27Qq4apYZa7TcLnSV9HSsgubJHwFssnS4kRvY7kD2essTcnuEy7RnajLrzjlotFVfIqS0Tilro5XUnVVywMeOlj2v4AmPHre0DnlBYVFpOJ6hUlXpBZdVM0qqK1U1RjdLf7pNyWU9K19M2aVw6iSGN5PHJJ4HtJVVNrW/HUDdLqnqViOLYjj9HaLFZKu54qahkzamplbMyOnFW7xCwNd1AuDGtLeeA48ckLwovntrxux9IFtvwynzzU3SvR6C01Nwitkb6Oasnf4745HtBaKkdumJ/f/Uu9aQZHvtumeUFHrhp/pfasQfHMa2qsVXUPrGvETjEGNfO9vBk6AeWn1eUFj0VbtNNyGZ5rvH1P273G0WaHH8ItVNXUFXBHKKyZ8jKVzhK5zywtBqH8dLWnsO/t5sigIiICIiAiIgIiICIiAiIgIiICIiAiIgIiIMK1fY0n5zUfxnrNWFavsaT85qP4z1moCIiAiIgIiIMKh+ya/wDOW/wY1mrCofsmv/OW/wAGNZqAvlTtL/rXNVv/ADDKv8YF9Vl8ycz9HhvBp9w2ca36O6tYVi8uS3q5VtJOy610NWylqZ3SCN/TRuaHcEchrnDkdiUH02Xyp2Hf1mGtP/iyr/nMK3X/ADTfSp/9rrH/APiG4/8A+Cqpa6aG7qNi+R0GrN41btseQ5zUV8Mlzxy5VT6qZxdHNOZ3TQRch73Md26uXDk8cBB0ncNbNWrt6Vist2m+RWixZdPU0H8nbheoy+hh4s0Zby0xy888SNHDHDxD8R5I75qbtp9Jzq9g1105zrXTSS4WK9RsjrYBTPiMjWSNkbw9luDmkPYw8gg9l0nd3scG5mPGtUMEy0YpqVYKSAU1xk6xDVtYfEjEr4/XjkjkJcyVgcRyQWu9Ut4/fdofpHtbrVFpxrjuRxyDCjKxtcKL+cnqGNPUCWQ00LqjggHpllaOQD7QCg7NpHpLmm0/Ytm2GakXyz1tbYLNkNwimtdRLJTshfTySsY10scburrL+3Txy7sSStH9DrZ30W2zIrrLH0uuOZVXhn3446OkaD+t4gWRuE2K6uX3SvAdAduGodFjeBWakqKbI6e6XCeJ90lfKyUTythhcJiX+K4tJa3lwAAaB02d26aI2PbtpBj+k1hqzWstET3VVa9nQ6rqpXl8spbyekF7jw3k9LQ1vJ45QUC9HV/WCa6/m+Qf87gXONQ9HIdevSiZjphPlVzxxlzrJ5Dcbfx48XhWtsvDeSPb0dJ7+wq3+1TZlqjoXuj1J1syu+4tV2PMYrpHQU9uqqiSriNTcYqmPxWSQMYOGMIPS93DuAOR3XOtWtiO7Su3WZNuQ0N1MwXGqm5VRlt01ZU1JqoY30rYJA+M0csfJAeOxd2PPIPsDjmudh1r9GbqVg2U4TrnfMuxnI31DpbRdJXtjmbTPhM8EsRe9hDmTs6ZmBr2knjjgF31wo6qGupIK2Dq8OojbKzqHB6XDkcg+w8H2L58WX0c2u2rmptmz3ebrnbswo7IWmO12vxZGTsa8OMHU6KBkMbiPXLIy5w7cg8OH0RQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBBS/W3flZP3yp1BS/W3flZP3yp0BUY9HF/0s7o/9oUv+JrledVr2nbcM50IzfWXJcvudjrKXUTKX3y1st080kkMBmqXhs4kiYGv4nZ2YXjkHv7OQ5X6TH/3o25/7Qqf+JTrx/SINsrt0m1FuQ8fBxyiTx+rjp6fPW7jq5/s88c/93lds3f7cc51/vWlNxwy6WOjjwXKYr5chc55o3SwNfE4th8OJ4c/hh7OLR7O64T6SPCLNqVuI206f5CKhtsyG6XG3VTqaXw5WxyzUTS5ju/DhzyDwe/xFB9Cl8xtrJuDLNvubgvjfBbZbt8AeHzx43Rdujw+n4+nwPZ3+pXW8k0g9Ja2wyaVY/rxp9W43JAbfHlNVTT0188n09HMgbE9om6O3W1znk+t1hx6h3fa5toxPbDpPDptZKl11qamV9beblNEGur6t7Q17ujk9MYa0Mazk8NHclxcSHLvRaiyjZtivwZx5g3C6m4ez7I85Jxzx/wDZeD7VoHpKvDGsG2B9n8T+U38tj5DwvqujzNB1c8d/rnhcf71lQ7Pd0O2/Mb9dNmGp2MwYdkdWa+oxPKInmKkm7gCF7Y38tAPSHB0biwMa7xOgOWzaK7PNV7hrXSbkN3Go9tzDMbNB4NitdphLbdbeOrpeOWMBc3qJDQwcPPWXPdwQHlb93Nvuv+1fBaf+dlqs8F0miHtEFPPSF7j/APKZOP8AUV0v0jH9C/U38zov8fTKoen9l3kbqdfb7uKwjK9NmVumF5uGH2emyKKpZFSMHVzJHFDDI1zyyY8yOd1c/Fw1vHXdW9CPSUa1ad3nTDNdQdCjZb7HHHVikFxil4ZKyVvS/wAqePWYOe3sQdbwDV/H9BthOC6s5RBPUW/H9P7FK6ngc0STyvpoIoomlxABdI9jeT7OeeDxwtAxHMvSSa4YxbNQMToNHNPLBfKaOvt1LdPOVVe6llAdFJIWtezksII7MPB7tB7DSdsdmzvcNpdrRsk11udn8jpnT2bEbfXWKmP8y+AztZMHSAGXpfRQOHU1hPBHA57bNg2h/pJcJx+g0ht2uem0WJW2CK30WQPoJZ7pR0LG9DGRROhDHSNYBwHuPHA/nOyDUfR4R5rTbr9x9HqLfrZeMlhqqaO61tsZ0Us1S2ona/w29LeAD6vBbyCCDyeSe+eki/oU6l/m9u/5lSrwNomzvLttWrup2XXLKKK9WHLhTC2TSVs1Rc5XMe98s1YXxNZ4j3PLiWufySfYup7tNIcl1429ZfpPh9ZbaS73+KkZTTXKWSOmaYquGZ3W6Nj3jlsZA4ae/HsHdB6G1f8Aox6Q/wBw7B/y+FUaZolLrl6SLXLH4dUs1wY2+1UFZ53FrkaOon/0ehb4UjgD1M9bq4+2AV9AdGcNumnOj2CafXuelnuOMY1bLNVy0r3PgfNTUscT3Mc5rXFhcwkFzWkjjkA9lVTLNsO8LGt1OoO4LQPLtL6KmzSmpqMQ5BLWyTNgjhp2u6mR07mNcZIOQQ53q/j7APGju2tWy7c1pjprftasi1N071aqpLVBFksxqLhbatj4ow5sxJd0h9RAexaxzTICwFrXq/SqFpxtH1kyfWyx6/bstVLRlV5xGNzccsmP0r4bbQyn2ylzmsc4h3rAFvJcGkvLWhi/uc6maq330iOF6K4bmFbQYbZ8TOQZPQQMjLZ3B84YHlzS4AudRtPBHZ5QW8XC962jf+XPbXmeE0lL492iozdbQA3l/nab+djYz8cga+L/AFSFd0RB83tWtx131b9Hnp1jeNVPms41Zq6DApIg/wDnX1MMojq3u/FJ4UYP/dqgvW9JdpXR6fbFsGwXGoXm14NfrRTyOYzjmJlFVU5lf+N0krST8bn/AI1pm1jRC3Xr0guoEVhuklx060hvlzvNspweaSku9wDIzDG32AxmKQcj46KMr6GasaX4prRp1ftMM1pnzWfIKU00/hkCSJwIdHLGSCBJHI1j2kggOYOQR2QethsFkpsQsdPjLWttEVupm28NADRTCJoi4A7cdHHsVIcebBTel5yNuMdbRPhTXX8Rt4b1Gmpy3q4+3xSHv/aP2+FNjGgvpI9FcfZpdpLrVp7fcRoGmlstdfqZ7a2304JLWlpheOB7A1zpWtbwGgAADsG0raNPoBV5JqJn2YPzPUzNZTLe725hbG1hf1mGEO9bpL+HOcQ3q6GANaGgIKiaK2rdBeN5e5STQzKsHs17hyKZtd/KynqJXS0JrKgU/geGx/DQxsfPPHYx8cj2dQ122wekG3DYKdO9QtSdFprRJWQ1hFLBXQStki56S1/lzx7TyOByO3K6NuA2f6k3LWJm5Xa3qRRYVqHNSiiu1NcYi+3XeINDQZOGP4d0NY0hzHtcWRuHQ5vUdXqds29TX+52m3boNacbsmEWyqjq6my4QJoqm5PZ26ZJSxhY1w57hzwOeQwO4cA3DenJcdPvR95LZcmuMNRdqbHLTZaqeJ7nMqKp01NDI5hcA4gnrcCQDx3IC7NtoskuN7ddL7FPF4c1Fh1nhmZ9qUUcXX//ABcqle861a57j9yNNs305vWK27GrJZaPLhR3dssMFQ6I9HhyyQske5g6xxGGtb7STyG8dbixb0pcEbYYc82+sjYA1rWwXEAAdgABTdgEGt+iK/6Dc+/2hV/+Do1x7QncBb9usm67LmUvwlkdx1HfasatDGl8lxuctTXNijDG+s5oPru479I4HrOaD7m0y07hNn25jE9qOcXnDLhYtR33TLat1nbPO8SNopmgCWaOIs9eiYekNcOOfW79uj6A+jzumDbp8w3E6p3XH7rTzXq4XjFbfQSzSmCapqZHtnqRLExrZI43ANawvHWerqBY0kOBbptv9w0S2y6f3nO6o3PUnOtTKK+5jdJCHySVklNVOFOHDt0RdRaOPVLzI5vAcAPrGq2b4tuGc7lsIxHGcEutjoaqw5TTXypfdp5oo3QRwzMc1hiikJeTKOAQBxz3Vk0FGPRBf0ecz/2hXD/A0CxvS60wrNG9PaMTyw+PntJF4sR4fHzSVI6mn4iOeQftrrmxLbhnO2DSrIMGz252Wvr7rlNVfIZLPPNLC2CWmpomtcZYoyHh0DyQGkcEdyeQIN9+3DUTcxp3jGMaaXbHrfdLDksN7dJeqiaKAsZBMwBphilcXdUjDwWgcc9+eAQ5PrBtX1n0D02yHWDSDeJqrV3XDqCa+S23Jbr5+hrIKdhklY6N/qdXQ15HW14JHTwOeoWg2zauVOu2hGGar11BHR1l/oC6rhi58NtTFI+GUs57hhkjeQDzwCByfaa6Zjt99ILrhYKjTvV7XPTTH8Ru3EN3OK0FTLWVNNzy+L+eij4a7jggPbyOzuRy0y7xLlle2Lb3pXovtpvlZYLxc8mt+L2uZvRJPLCYpesuL2kFz5nRFxAHd5449iC7K5Du9/os6tf3Nu3+FkXUbZSSUNtpKKorJayWnhjikqZeOuZzWgF7uO3USOTx8a03XXBrvqfovm+nePT0kFyyawV1qpJax7mQRyzQuY10jmtc4MBd3LWuPHsBQUV2o2n0htVtjw9+jOT6RUeKPoZ/ght0jqjco2eYl6uv+ZdF1eJ1kckjjjldR9HHccbx92pek99sV3turtpvZuOdTXGsiqvhKplLgKiCSJrWiLq6yGcEt8QHqf1cjyNJtC/SS6O6fWTS3EdRtDqeyWSJ8FLJOy4T1DWPkc9xJdSgOIc88cgD2Bdl2p7XLxobccx1D1Ezp2Y6h6g1bKq93RsAgp42sc9zIoWcAgEvJJ4aOBG1rGhvcOI+iJ8M6W6kvuvX/KY5vN8K+J9Xx5eLo6ue/Pi+Y9vx8/jXqel9Fp/zYLS6s7Vwy+h+Den6rxvL1PV+Pjw+v2fHws/ULZ1rjp3rNf8AXXZlqTZccrMvcZcixu/Ql1BVTF3W+SMtY/gueS/gta5rnydLw15YMTH9nW4TWjVPHdUN6mpOPXm3YhP5uzYnjsLhRibqa4GVzmMHT1NHIIe54aGl4by0hom/Rmo82t21CPD57bDnD55xRyXfrNK24F9BwZ+kF/R1+3gE/iWDutxTfLV6ZyXHcrUYZkWlNoqoLhlFqwGrdR189NHIC0mSqpyehr+h5DO/bntx1N7vvJ2163ay6k6VamaJ37D7bc9N6mrrQcjmqWsfO99O+LpZDBJ1tBgPUCW+0cc9+NSzXb56QLXLHarTfWLW3S+x4ldjHHdf5L26plq6inDw50YM0UYAPA9jhz7D6pIIWCGoGF3Pa3ValYCfLYwcIqLlbGPZ0GnpY6JzmRubyeksDekjk8Fp7n2rlfovrQ62bMcNqXR9LrlWXWrP2yPPTRg/7xEP9y/u4DbPrbkOkuIbdNu+e2HFNP6azOsORy3VjpK6ppWNibGIyyI9ReBL4nDo+ov454JC79pHprZNHdNMa0wxx75KDHLfFQRyyNAfM5o9eVwHYOe8ueQO3LjwgqT6O/8A6dd2P+0KT/GXJcA9H/ZN413xLPazRHNNObS85TKy/wAOUU1TJWurREwl/Mcbh4Z5eACeeoScj7d09q23DOdDdSdb8xyy52OrotSspdfLVHbqiaSWGA1FXJ0ziSJjWv6ahg4YXjkHv7Cef6g7PNddOtY8g1v2Zal2XHKjMJPMZFjN+jc631U5cXPkjLWPAJeS4Ata5pfJ0vDXdADTdYdp2/fXq44hPqNqVo+6PD7s27UMltZXU00coLSeHeXPP1A7cju0Fb1ug0Y1zxPcXi+7zbxjFHltyttqdYr/AI1NUtp5KymJeBJG9xAJLZODwepro4yGvaXAfvEdse6LVLUzHNRt22r1mltWJ1IrrXiWICWKjmqAQ4OqXuawuaHNHLT4nUPV6mguDrkoPldvs1u3T6qbfLjSZxtfdpphtPcKJ9fXXO9Nq6qabxOIo4YwyJwBf3JLHDge0chd835f1b9T/wCV4z/iaRdZ3q6EZfuR0GuOluD3G1UN1rK+jqo5rrNLFThkUgc4F0Ucj+SPZ6vt9pCw9yu3zNNZdp02g+MXOyUt/fRWimFTXzSso+qllgfIetkb38EQnp9TueOeO/AcOwjZNqbJoxjma6W7wdW7RkdVjdDcaChrL26a1NldTMkZTGEEcQ8kMHPUGt4PS7jg9r2Hbgsk3KbfqDN8zii/lBba+ostznijEbKqaJrHiYMaA1pdHLHyG+r1dXAA4aOVUeh3pJqvA6TSms1q0lxzHoLXDZTW2WlrJrhHSMjEXDDLAwdZjHHUHMdz3DmnuM/WvHodg+we72HSDIqqlvdBLSxU95exonqK+prIhPP0u5a0mISBre4a1jRySOohdRFo2itFmNBpHh9NqHd6m55R8C0kl5qqkNEj6x8YdKCGgDs9xaOAOwC3lAREQQUv1t35WT98qdQUv1t35WT98qdAVGPRxf8ASzuj/wBoUv8Aia5XnVa9p23DOdCM31lyXL7nY6yl1Eyl98tbLdPNJJDAZql4bOJImBr+J2dmF45B7+zkOV+kx/8Aejbn/tCp/wCJTrA3F9DvSj7f25F4nwKLBKaTn6jz/Nw6eOe3PieU547+z8S7Hu/245zr/etKbjhl0sdHHguUxXy5C5zzRulga+JxbD4cTw5/DD2cWj2d16W7najatzeOWeSgyOfFs1xOqNfjt+p2kuppSWl0bw0h3QXMjcHNIcx7GOHPrNcHfJhCYnifoMRafE6uOnp47889uOPavlptF5/9n9ufbazKceEt++C+vnjp+DWdXHxc9Hhc8Lr+QaI+k51Jx2fS3O9ctObZjlwidRXW9Wumf5+spXjpe0NbTsHJHYhpi5BILiCV3KLavZsH2kZDto0rmgilueO3C2xV9yeWCprqmJzXVFQ5jXOAL3Dnpa7pYA0AhoCCjuijP82jGNt+7W3s8vjGU0M+D56WDhgilrJzTVcnHu9IJd9qnjaO71YnWZrN0G8Gx6OREVeC6J0Jy3JwPWhqrzKz/QqZ/ta7oaQ/g+1pqGn2LoOH7TaibZLTbVdSa21z14s9RRyV1AXzU8NWaiSennjMjGOd4chjcQWt56SPYeV6G0Xa3Ltr0xvONXbJI8iyvJKyauvF56X/AM+4t6IWdTyXlrGd/W79Ukh9hCCtWw03QejV1VNj8T4SDMp8p4fPV4/wZH4fTx356uOOF2X0Woso2bYr8GceYNwupuHs+yPOScc8f/ZeD7VtOxjblmO2nRCp0x1BuFhuVwnvVXcHPtU0s1MYZY4mhpMsUbur1DyOnjgjuVyGHZ7uh235jfrpsw1OxmDDsjqzX1GJ5RE8xUk3cAQvbG/loB6Q4OjcWBjXeJ0ByDF9JV4Y1g2wPs/ifym/lsfIeF9V0eZoOrnjv9c8Lj/etr3QaMa54nuLxfd5t4xijy25W21OsV/xqapbTyVlMS8CSN7iASWycHg9TXRxkNe0uAl0V2ear3DWuk3IbuNR7bmGY2aDwbFa7TCW2628dXS8csYC5vUSGhg4eesue7gi46D5Xb7Nbt0+qm3y40mcbX3aaYbT3CifX11zvTauqmm8TiKOGMMicAX9ySxw4HtHIXfN+X9W/U/+V4z/AImkXWd6uhGX7kdBrjpbg9xtVDdayvo6qOa6zSxU4ZFIHOBdFHI/kj2er7faQsPcrt8zTWXadNoPjFzslLf30VophU180rKPqpZYHyHrZG9/BEJ6fU7njnjvwHDsI2TamyaMY5mulu8HVu0ZHVY3Q3Ggoay9umtTZXUzJGUxhBHEPJDBz1BreD0u44Pa9h24LJNym36gzfM4ov5QW2vqLLc54oxGyqmiax4mDGgNaXRyx8hvq9XVwAOGjlVHod6SarwOk0prNatJccx6C1w2U1tlpaya4R0jIxFwwywMHWYxx1BzHc9w5p7iyW3TQbFdt+lVq0sxSeerhojJPV104DZKyqkPMkzmgkN57ANBPS1oHJIJIYW73+izq1/c27f4WRU02o2n0htVtjw9+jOT6RUeKPoZ/ght0jqjco2eYl6uv+ZdF1eJ1kckjjjlXq11wa76n6L5vp3j09JBcsmsFdaqSWse5kEcs0LmNdI5rXODAXdy1rjx7AVU/SbQv0kujun1k0txHUbQ6nslkifBSyTsuE9Q1j5HPcSXUoDiHPPHIA9gQev6OK443j79TNJ77YrxbdXLTfDcc6muNZFVfCVTKXAVEEkTWtEXV1kM6SW+ID1v6uRwjbFtyqdddZdxNbT62ai4IbPntXH4eKXY0bKoyVdWQ6UAHqLent9oOKuLtT2uXjQ245jqHqJnTsx1D1Bq2VV7ujYBBTxtY57mRQs4BAJeSTw0cCNrWNDe/EML2ub69GdRNTcm0YzfR6mteoWSVV6cy8Pr5p443TzPiBDaXpa4NnPIDnDn2Ejug9fRLN9Z9Ad4MO0bUzU+46kY5lVhkv2OXa7+tcaQsEziyWQlzngimnaQ5xHaNzejlzFD6P8A/pObv/79Rf426roe3/aZnmL6v3PcfuI1Lp831GraI2yiFBTGC32qlPYthaQ0uJby0eqwAPkJDnOLl6O2DbfnOiusWu2oOU3Wx1Vt1QyRl4s8VvnmfPBCKitkLahr4mNa/pqoxwxzxyHd+wJDlno4v+lndH/tCl/xNcv56TH/AN6Nuf8AtCp/4lOuqbTtuGc6EZvrLkuX3Ox1lLqJlL75a2W6eaSSGAzVLw2cSRMDX8Ts7MLxyD39nLd/txznX+9aU3HDLpY6OPBcpivlyFznmjdLA18Ti2Hw4nhz+GHs4tHs7oOObi+h3pR9v7ci8T4FFglNJz9R5/m4dPHPbnxPKc8d/Z+JXxmEJieJ+gxFp8Tq46enjvzz2449q4Hu52o2rc3jlnkoMjnxbNcTqjX47fqdpLqaUlpdG8NId0FzI3BzSHMexjhz6zXcPyDRH0nOpOOz6W53rlpzbMcuETqK63q10z/P1lK8dL2hradg5I7ENMXIJBcQSg/Hoif+iTUVtsMpx4ZvUfBfic8dPloerj4uejwueF7GzwtyDerurytnrtorvbrOJP8AvMdURuaD+I0wBXW6PQHMtC9s7NINqN5tVryih8N1Ndr+zqjnnfM11VUTBsbwXuZ19I6HBvDG/Uhf3Z7tnr9tuEXqnyvKY8lzLL7vLfMhusbHNZNO/wCpYwu4c5o5e4ucAS6R54A4ADjGo/8AW56Wf7PKj926rmDLZuHunpItcotueSYlZb0y1UD6+XJIZZIJKXy9COmMRseQ/r6D3AHHPdWkyzbfnN+3zYXuapLrY2YvjmLS2OqpJaiYV753NrQHRsERjLP9Kj5JkB7O7dhz/NMduGc4XvL1S3D3S6WOXHM3tNNQ2+lp6iZ1dFJGyla4ysdEGNaTTv46ZHHuO3t4CpW/LHd8tu273Op131A0xu2JC40InprDSVEdWZjL/Nlrnwsb0h3t9b2Luu/H+rhqP/LMa/xNIur719CMv3IaC3DS7B7laaG61lfR1Uc12mlipwyKTqcC6KOR3JHs9X/WQsTctt9zPWTafNoPjFzslLf30dopxU180rKPqpZYHyHrZG9/BELun1O545478BXy/wB7u26am0r2XYHcJoMZtWK2K9aoXalfx4NI2lhdDbWvHYSyHpJHfguYe4ZI1ertnsloxr0leumO2C3wUFstmK2yko6WBnTHBDHBbmsY0fEA0ABd82b7X7RtY0kpsNEtLXZJcpBXZFc4ASypqyOAyNzgHGKNvqM5A59Z5a1z3BeLpjtxzjCt5WqW4e53Sxy45m9ppqK30sE8zq6KSNlK1xlY6IMa0mnfx0vce47e3gOWemF/ot2b++tD/hK1XmHsVa9+O2/ON0OjNv070/udjt9ypMhprs+W8TzRQGGOCojc0Ohikd1kzM4HTxwD39gNlAOBwg+ZLNEpdcvSRa5Y/DqlmuDG32qgrPO4tcjR1E/+j0LfCkcAepnrdXH2wCt9ju2tWy7c1pjprftasi1N071aqpLVBFksxqLhbatj4ow5sxJd0h9RAexaxzTICwFrXr2cs2w7wsa3U6g7gtA8u0voqbNKamoxDkEtbJM2COGna7qZHTuY1xkg5BDner+PsNk042j6yZPrZY9ft2Wqloyq84jG5uOWTH6V8NtoZT7ZS5zWOcQ71gC3kuDSXlrQxBb1ERAREQEREBERAREQEREBERAREQEREBERBhWr7Gk/Oaj+M9ZqwrV9jSfnNR/Ges1AREQEREBERBhUP2TX/nLf4MazVhUP2TX/AJy3+DGs1AREQFzvVzQPSHXemt1Hq1hNNkcNokkloWTzTR+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>
  <entry>
    <title>Немного о porcelain и plumbing командах, а также о типах объектов в git</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21251808" />
    <author>
      <name>Никита Рогаленко</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21251808</id>
    <updated>2026-05-06T13:06:31Z</updated>
    <published>2026-05-06T13:05:00Z</published>
    <summary type="html">&lt;p style="text-align: justify;"&gt;Каждому разработчику практически ежедневно приходится сталкиваться с системой контроля версий git, выполняя набор привычных операций вроде &lt;code&gt;git add&lt;/code&gt;, &lt;code&gt;git fetch&lt;/code&gt;, &lt;code&gt;git commit&lt;/code&gt;, &lt;code&gt;git log&lt;/code&gt; и им подобных. Обычно для работы над прикладным проектом знания базового набора команд git оказывается вполне достаточно, однако важно понимать, что большинство всем известных команд представляют собой высокоуровневый инструментарий git (т.н. "porcelain" команды), которым возможности git не исчерпываются.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Porcelain - это команды, которые предназначены в первую очередь для удобства конечного пользователя (программиста), у них обычно довольно подробный вывод информации в консоль, который представлен в виде, удобном для чтения. Кроме того, вывод таких команд не регламентирован и теоретически может незначительно меняться от версии к версии. Подобные команды делают работу с git быстрее и доступнее, освобождая программиста от лишней работы, осуществляя множество операций "под капотом". У такого подхода есть очевидный недостаток - отсутствие гибкости и возможности контролировать каждый отдельный этап процесса выполнения команд. Впрочем, для большинства повседневных задач это и не нужно. Однако проблемы могут возникнуть, например, при необходимости автоматизировать какой-либо процесс, связанный с git. Если мы пишем скрипт, который полагается на вывод porcelain команд, то с выходом новой версии git код может сломаться (не говоря уже о необходимости в принципе парсить текстовый вывод). Примерами porcelain команд можно обозначить&amp;nbsp;&lt;code&gt;add&lt;/code&gt;, &lt;code&gt;commit&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;push&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt;, &lt;code&gt;fetch&lt;/code&gt;, &lt;code&gt;branch&lt;/code&gt;, &lt;code&gt;checkout&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;rebase&lt;/code&gt;, &lt;code&gt;log&lt;/code&gt;, &lt;code&gt;diff&lt;/code&gt;, &lt;code&gt;stash&lt;/code&gt;, &lt;code&gt;show&lt;/code&gt;, &lt;code&gt;reset&lt;/code&gt; и др.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Другой категорией команд выступает низкроуровневый инструментарий - plumbing команды. В повседневной работе они редко нужны, однако позволяют работать с внутренностями git напрямую, обеспечивая максимальную гибкость. Иногда такие команды экономят время в повседневной разработке, заменяя длинные цепочки визуальных действий или помогая «вылечить» репозиторий, когда обычные команды выдают ошибки. Также они могут оказаться крайне полезны для использования в скриптах, поскольку они стабильны, их вывод не меняется и содержит минимум необходимых данных в хорошо структурированном формате, упрощая автоматическую обработку. По сути каждая&amp;nbsp;porcelain команда, написанная программистом, самостоятельно исполняет набор более мелких низкоуровневых plumbing команд, манипулирующих различными объектами git.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Для общего понимания ситуации отметим, что в файловой системе git в принципе есть 4 типа объектов, о которых мы часто не задумываемся, но к работе с которыми сводится процесс исполнения любой команды:&lt;/p&gt;

&lt;ul&gt;
	&lt;li style="text-align: justify;"&gt;
	&lt;p&gt;&lt;code&gt;blob&lt;/code&gt; - просто голое содержимое файла; в нем нет имени файла или даты, только сами данные (код, текст, картинка); если создать несколько файлов с идентичным содержанием, то все они будут ссылаться на один и тот же объект;&lt;/p&gt;
	&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;
	&lt;p&gt;&lt;code&gt;tree&lt;/code&gt; - своего рода директория, объект-дерево, содержащее список имен файлов (блобов) и других директорий (деревьев), а также права доступа к ним;&lt;/p&gt;
	&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;
	&lt;p&gt;&lt;code&gt;commit&lt;/code&gt; -&amp;nbsp;это "снимок" проекта, который ссылается на конкретное дерево (корень проекта в этот момент) и содержит метаданные: автора, дату, сообщение и ссылку на предыдущий коммит (родителя);&lt;/p&gt;
	&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;
	&lt;p&gt;&lt;code&gt;tag&lt;/code&gt; -&amp;nbsp;ссылка на конкретный коммит, содержащая имя тега, автора и сообщение.&lt;/p&gt;
	&lt;/li&gt;
&lt;/ul&gt;

&lt;p style="text-align: justify;"&gt;Именно с ними работают plumbing команды как "атомарные" операции. В качестве примера приблизительно покажем, какие plumbing команды нужно вызвать, чтобы добиться результата аналогичного работе высокоуровневой обертке &lt;code&gt;git commit&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
	&lt;li style="text-align: justify;"&gt;&lt;code&gt;git hash-object -w file.txt&lt;/code&gt; - взять содержимое файла и превратить его в объект blob, высчитать хеш и сохранить в директорию .git/objects&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;&lt;code&gt;git update-index --add file.txt&lt;/code&gt; -&amp;nbsp;привязать имя к хешу в индексе,&amp;nbsp; связать содержимое (блоб) с именем файла&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;&lt;code&gt;git write-tree&lt;/code&gt; - создать из текущего состояния индекса новый объект типа tree, вернуть хеш этого дерева&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;&lt;code&gt;echo "commit message" | git commit-tree &amp;lt;хеш_дерева&amp;gt; -p &amp;lt;хеш_предыдущего_коммита&amp;gt;&lt;/code&gt; - создать объект commit из созданного ранее дерева; идет указание на tree как на внутреннее состояние репозитория и на parent как на прошлый коммит (нужно, чтобы связать в историю все коммиты); на выходе получаем хеш самого коммита&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;&lt;code&gt;git update-ref refs/heads/main &amp;lt;хеш_коммита&amp;gt;&lt;/code&gt; - передвинуть указатель ветки на новый хеш, чтобы HEAD теперь указывал на новый созданный нами коммит&lt;/li&gt;
&lt;/ol&gt;

&lt;p style="text-align: justify;"&gt;На примере выше мы показали, как plumbing команды позволяют лучше понимать внутреннее устройство git и при необходимости гибко им управлять, в том числе и внутри скриптов. Сам список таких команд весьма обширен и может быть найден в документации. Сейчас же, в дополнение к plumbling командам уже указанным выше, отдельно выделим еще несколько, заслуживающих внимание:&lt;/p&gt;

&lt;ul&gt;
	&lt;li style="text-align: justify;"&gt;&lt;code&gt;git rev-parse&lt;/code&gt; - одна из самых полезных команд в принципе, которая принимает строку (название ветки, тег, ссылка в стиле HEAD~4) и отдает хеш соответсвтующего коммита (либо последнего на указанной ветке); оказывается весьма нужно в скриптах;&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;&lt;code&gt;git cat-file &amp;lt;хеш&amp;gt;&lt;/code&gt; - показывает сырое содержимое объекта по его хешу, позволяя узнать тип, размер любого из типов объектов;&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;&lt;code&gt;git ls-tree&lt;/code&gt; - вывод содержимого дерева, показывается как список файлов и папок внутри конкретного коммита;&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;&lt;code&gt;git ls-files&lt;/code&gt; - вывод информации о содержимом индекса.&lt;/li&gt;
&lt;/ul&gt;

&lt;p style="text-align: justify;"&gt;Итак, подводя итог, еще раз отметим, что даже если использовать большинство из plumbing команд оказывается избыточно в случае повседневной разработки, все равно знать об их существовании достаточно важно. В этом небольшом обзоре, который не является исчерпывающим, я постарался сформулировать азы, которые позволят понимать git чуть глубже и расширить свой арсенал команд.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&amp;nbsp;&lt;/p&gt;</summary>
    <dc:creator>Никита Рогаленко</dc:creator>
    <dc:date>2026-05-06T13:05:00Z</dc:date>
  </entry>
  <entry>
    <title>Astro.js: современный фреймворк для контент-ориентированных сайтов</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21251834" />
    <author>
      <name>Vadim Mikhu</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21251834</id>
    <updated>2026-05-06T09:50:23Z</updated>
    <published>2026-05-06T09:23:00Z</published>
    <summary type="html">&lt;h1&gt;Astro.js: современный фреймворк для контент-ориентированных сайтов&lt;/h1&gt;

&lt;h2&gt;Что такое Astro и зачем он нужен&lt;/h2&gt;

&lt;p data-end="451" data-start="57"&gt;Astro — это фреймворк для сайтов и веб-приложений, который по умолчанию рендерит большую часть страницы в статический HTML на сервере, а JavaScript подключает только там, где он действительно нужен. Такой подход называется islands architecture: основная часть страницы остается «легкой», а интерактивность добавляется небольшими изолированными фрагментами.&lt;/p&gt;

&lt;p data-end="752" data-start="453"&gt;Astro поддерживает несколько UI-фреймворков одновременно: React, Preact, Vue, Svelte, Solid и веб-компоненты. Это делает его удобным, когда нужно сочетать контентные страницы, маркетинговые лендинги, документацию и отдельные интерактивные блоки в одном проекте.&lt;/p&gt;

&lt;h2&gt;Ключевые преимущества&lt;/h2&gt;

&lt;h3&gt;Производительность «из коробки»&lt;/h3&gt;

&lt;p&gt;Astro проектировался как server-first решение, поэтому большинство страниц может отдаваться без необходимости тащить на клиент целый фреймворк runtime. В документации прямо отмечено, что это снижает сложность по сравнению с другими UI-фреймворками, потому что на сервере нет необходимости управлять реактивностью, хуками, stale closures и похожими механизмами.&lt;/p&gt;

&lt;h3&gt;UI-агностичность&lt;/h3&gt;

&lt;p&gt;Astro имеет систему интеграций и renderer-ов, через которую подключаются UI-фреймворки, адаптеры для серверного рендеринга и дополнительные возможности вроде MDX или sitemap. Для обычного проекта подключение официальной интеграции делается в несколько строк.&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;React&lt;/strong&gt; — для компонентов с богатым состоянием,&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Preact&lt;/strong&gt; — там, где нужен React-подобный синтаксис с минимальным весом,&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Svelte&lt;/strong&gt; — для компактных и производительных виджетов,&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Vue&lt;/strong&gt; — если команда привыкла к его экосистеме,&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Lit&lt;/strong&gt; — для веб-компонентов.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;На практике это особенно ценно при миграции старых проектов: вы можете постепенно переписывать компоненты, не ломая всё сразу.&lt;/p&gt;

&lt;h3&gt;Гибкая модель интерактивности&lt;/h3&gt;

&lt;p&gt;Astro использует компонентный подход, но интерактивность включается точечно через hydration directives: &lt;code data-end="1403" data-start="1390"&gt;client:load&lt;/code&gt;, &lt;code data-end="1418" data-start="1405"&gt;client:idle&lt;/code&gt;, &lt;code data-end="1436" data-start="1420"&gt;client:visible&lt;/code&gt;, &lt;code data-end="1452" data-start="1438"&gt;client:media&lt;/code&gt; и &lt;code data-end="1468" data-start="1455"&gt;client:only&lt;/code&gt;. Это позволяет запускать JavaScript только для конкретных элементов интерфейса и выбирать момент загрузки в зависимости от приоритета UI.&lt;/p&gt;

&lt;h3&gt;Content Collections&lt;/h3&gt;

&lt;p&gt;Начиная с версии 2.0, Astro предлагает типизированные коллекции контента — встроенную систему для работы с Markdown, MDX и другими форматами с полной поддержкой TypeScript.&lt;/p&gt;

&lt;h2&gt;Технические основы: как это работает&lt;/h2&gt;

&lt;h3&gt;Этапы сборки&lt;/h3&gt;

&lt;p&gt;Когда вы запускаете &lt;code&gt;astro build&lt;/code&gt;, происходит следующее:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;&lt;strong&gt;Парсинг компонентов&lt;/strong&gt; — Astro читает все &lt;code&gt;.astro&lt;/code&gt;-файлы и компоненты UI-фреймворков.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Статическая генерация&lt;/strong&gt; — выполняется JavaScript в &lt;code&gt;frontmatter&lt;/code&gt; (часть между &lt;code&gt;---&lt;/code&gt;), которая может делать запросы к API, читать файлы и т.д.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Рендеринг в HTML&lt;/strong&gt; — вся разметка превращается в чистый HTML.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Выделение «островов»&lt;/strong&gt; — компоненты с клиентскими директивами (&lt;code&gt;client:load&lt;/code&gt;, &lt;code&gt;client:idle&lt;/code&gt; и т.д.) упаковываются отдельно.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Гидратация&lt;/strong&gt; — при загрузке страницы браузер загружает только нужные острова, причём строго по заданной стратегии.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;Клиентские директивы&lt;/h3&gt;

&lt;p&gt;Директивы определяют, &lt;strong&gt;когда&lt;/strong&gt; браузер должен&amp;nbsp;оживить&amp;nbsp;компонент:&lt;/p&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;&lt;code&gt;client:load&lt;/code&gt;&lt;/td&gt;
			&lt;td&gt;Немедленно при загрузке страницы&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;&lt;code&gt;client:idle&lt;/code&gt;&lt;/td&gt;
			&lt;td&gt;Когда браузер освободился (через &lt;code&gt;requestIdleCallback&lt;/code&gt;)&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;&lt;code&gt;client:visible&lt;/code&gt;&lt;/td&gt;
			&lt;td&gt;Когда компонент попадает в область видимости (Intersection Observer)&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;&lt;code&gt;client:media="(max-width: 768px)"&lt;/code&gt;&lt;/td&gt;
			&lt;td&gt;При совпадении медиазапроса&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;&lt;code&gt;client:only="preact"&lt;/code&gt;&lt;/td&gt;
			&lt;td&gt;Только на клиенте, без серверного рендеринга&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;Синтаксис &lt;code&gt;.astro&lt;/code&gt;-файлов&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;.astro&lt;/code&gt;-файл делится на две части: &lt;strong&gt;frontmatter&lt;/strong&gt; (серверный JavaScript) и &lt;strong&gt;шаблон&lt;/strong&gt; (HTML-подобная разметка).&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;---
// Всё здесь выполняется ТОЛЬКО на сервере/в момент сборки.
// Этот код никогда не попадёт в браузер.

import Header from '../components/Header.astro';
import ProductCard from '../components/ProductCard.jsx'; // React-компонент
import { getCollection } from 'astro:content';

const products = await fetch('https://api.example.com/products')
  .then(res =&amp;gt; res.json());

const { title = 'Каталог товаров' } = Astro.props;
---

&amp;lt;html lang="ru"&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8" /&amp;gt;
    &amp;lt;title&amp;gt;{title}&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;!-- Статический Astro-компонент --&amp;gt;
    &amp;lt;Header /&amp;gt;

    &amp;lt;main&amp;gt;
      &amp;lt;h1&amp;gt;{title}&amp;lt;/h1&amp;gt;

      &amp;lt;ul class="product-grid"&amp;gt;
        {products.map(product =&amp;gt; (
          &amp;lt;!-- ProductCard — React-компонент --&amp;gt;
          &amp;lt;ProductCard client:visible name={product.name}/&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/main&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&amp;lt;style&amp;gt;...&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Astro автоматически изолирует CSS-стили — каждый &lt;code&gt;.astro&lt;/code&gt;-файл получает уникальный хэш-атрибут.&lt;/p&gt;

&lt;h3&gt;Layouts — переиспользуемые макеты&lt;/h3&gt;

&lt;p&gt;В Astro макеты — это просто компоненты со слотом &lt;code&gt;&amp;lt;slot /&amp;gt;&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;---
// src/layouts/BaseLayout.astro
interface Props {
  title: string;
  description?: string;
}

const { title, description = 'Мой Astro-сайт' } = Astro.props;
---

&amp;lt;!doctype html&amp;gt;
&amp;lt;html lang="ru"&amp;gt;
  &amp;lt;head&amp;gt;
    ...
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;nav class="site-nav"&amp;gt; ... &amp;lt;/nav&amp;gt;

    &amp;lt;!-- Содержимое страницы подставляется сюда --&amp;gt;
    &amp;lt;slot /&amp;gt;

    &amp;lt;footer&amp;gt;© 2024 Мой сайт&amp;lt;/footer&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Маршрутизация и работа с данными&lt;/h2&gt;

&lt;h3&gt;Файловая маршрутизация&lt;/h3&gt;

&lt;p&gt;Astro использует файловую систему для маршрутизации — принцип, знакомый по Next.js:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;src/pages/
├── index.astro          → /
├── about.astro          → /about
├── blog/
│   ├── index.astro      → /blog
│   └── [slug].astro     → /blog/любой-slug
└── api/
    └── products.ts      → /api/products  (API-эндпоинт)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Динамические маршруты и &lt;code&gt;getStaticPaths&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Для генерации динамических страниц используется функция &lt;code&gt;getStaticPaths&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;---
// src/pages/blog/[slug].astro
import { getCollection } from 'astro:content';
import BlogLayout from '../../layouts/BlogLayout.astro';

// Эта функция говорит Astro: "вот все возможные URL, которые нужно сгенерировать"
export async function getStaticPaths() {
  const posts = await getCollection('blog'); // читаем коллекцию из src/content/blog/

  return posts.map(post =&amp;gt; ({
    params: { slug: post.slug },
    props: { post },              // передаём данные в компонент
  }));
}

const { post } = Astro.props;
const { Content } = await post.render(); // превращаем Markdown в компонент
---

&amp;lt;BlogLayout title={post.data.title} description={post.data.description}&amp;gt;
  &amp;lt;article&amp;gt;
    &amp;lt;h1&amp;gt;{post.data.title}&amp;lt;/h1&amp;gt;
    &amp;lt;time&amp;gt;{post.data.publishedAt.toLocaleDateString('ru-RU')}&amp;lt;/time&amp;gt;
    &amp;lt;!-- Content — это готовый к рендерингу HTML из Markdown-файла --&amp;gt;
    &amp;lt;Content /&amp;gt;
  &amp;lt;/article&amp;gt;
&amp;lt;/BlogLayout&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Content Collections с типизацией&lt;/h3&gt;

&lt;p&gt;Система коллекций позволяет описать схему frontmatter и получить полную автодополнение в редакторе:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;// src/content/config.ts
import { defineCollection, z } from 'astro:content';

const blogCollection = defineCollection({
  type: 'content', // 'content' для Markdown, 'data' для JSON/YAML
  schema: z.object({
    title: z.string(),
    description: z.string(),
    publishedAt: z.date(),
    tags: z.array(z.string()).default([]),
    draft: z.boolean().default(false),
    // Если поля нет — TypeScript немедленно об этом сообщит
    coverImage: z.string().optional(),
  }),
});

export const collections = {
  blog: blogCollection,
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;После этого &lt;code&gt;getCollection('blog')&lt;/code&gt; вернёт типизированный массив, и вы не сможете случайно обратиться к несуществующему полю.&lt;/p&gt;

&lt;h3&gt;API-эндпоинты&lt;/h3&gt;

&lt;p&gt;Astro позволяет создавать серверные API прямо внутри проекта:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;// src/pages/api/newsletter.ts
import type { APIRoute } from 'astro';

export const POST: APIRoute = async ({ request }) =&amp;gt; {
  const body = await request.json();
  const { email } = body;

  if (!email || !email.includes('@')) {
    return new Response(
      JSON.stringify({ error: 'Некорректный email' }),
      { status: 400, headers: { 'Content-Type': 'application/json' } }
    );
  }

  // Здесь можно вызвать любой сервис: Mailchimp, Resend, собственную БД...
  await subscribeToNewsletter(email);

  return new Response(
    JSON.stringify({ success: true }),
    { status: 200, headers: { 'Content-Type': 'application/json' } }
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Сравнение с другими фреймворками&lt;/h2&gt;

&lt;p&gt;Понять место Astro в экосистеме проще всего через сравнение с конкурентами. Но важно понимать: это не «Astro против Next.js», а «разные инструменты для разных задач».&lt;/p&gt;

&lt;h3&gt;Сводная таблица&lt;/h3&gt;

&lt;table&gt;
	&lt;thead&gt;
		&lt;tr&gt;
			&lt;th&gt;Критерий&lt;/th&gt;
			&lt;th&gt;Astro&lt;/th&gt;
			&lt;th&gt;Next.js&lt;/th&gt;
			&lt;th&gt;SvelteKit&lt;/th&gt;
			&lt;th&gt;Nuxt&lt;/th&gt;
		&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
		&lt;tr&gt;
			&lt;td&gt;JS по умолчанию&lt;/td&gt;
			&lt;td&gt;✅ Нет&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;Смешение фреймворков&lt;/td&gt;
			&lt;td&gt;✅ Да&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;SSR&lt;/td&gt;
			&lt;td&gt;✅ Да&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;Встроенный роутер&lt;/td&gt;
			&lt;td&gt;✅ Файловый&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;Лучший случай&lt;/td&gt;
			&lt;td&gt;Контент-сайты&lt;/td&gt;
			&lt;td&gt;Rich SPA&lt;/td&gt;
			&lt;td&gt;Svelte-приложения&lt;/td&gt;
			&lt;td&gt;Vue-приложения&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Порог входа&lt;/td&gt;
			&lt;td&gt;Низкий&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;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h2&gt;Интеграция с UI-фреймворками на практике: Preact&lt;/h2&gt;

&lt;p data-end="5380" data-start="4963"&gt;Preact — это компактная библиотека компонентов, совместимая с React-экосистемой через &lt;code data-end="5064" data-start="5049"&gt;preact/compat&lt;/code&gt;. В официальных материалах Preact подчеркивается, что compatibility layer позволяет использовать React-компоненты как drop-in replacement в ряде случаев, а сам Preact отличается более близким к DOM поведением и меньшим runtime-overhead, в том числе без synthetic event system.&lt;/p&gt;

&lt;p data-end="5664" data-start="5382"&gt;В Astro интеграция с Preact подключается официальным пакетом &lt;code data-end="5460" data-start="5443"&gt;@astrojs/preact&lt;/code&gt;. Для обычного использования достаточно команды &lt;code data-end="5526" data-start="5508"&gt;astro add preact&lt;/code&gt;; после этого Astro умеет рендерить Preact-компоненты и гидрировать их через &lt;code data-end="5613" data-start="5603"&gt;client:*&lt;/code&gt; директивы.&lt;/p&gt;

&lt;h3&gt;Установка и конфигурация&lt;/h3&gt;

&lt;pre&gt;
&lt;code&gt;# Добавляем интеграцию одной командой
npx astro add preact

# Или вручную через npm
npm install @astrojs/preact preact
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;После этого обновляем конфиг:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;// astro.config.mjs
import { defineConfig } from 'astro/config';
import preact from '@astrojs/preact';

export default defineConfig({
  integrations: [
    preact({
      // compat: true — включает слой совместимости с React,
      // что позволяет использовать некоторые React-библиотеки с Preact
      compat: true,
    }),
  ],
});&lt;/code&gt;
&lt;/pre&gt;

&lt;h3&gt;Особенности и тонкости при работе с Preact в Astro&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Атрибуты &lt;code&gt;class&lt;/code&gt; vs &lt;code&gt;className&lt;/code&gt;.&lt;/strong&gt; В Astro-компонентах (&lt;code&gt;.astro&lt;/code&gt;) всегда используется &lt;code&gt;class&lt;/code&gt;. В Preact-компонентах (&lt;code&gt;.jsx&lt;/code&gt;) тоже рекомендуется &lt;code&gt;class&lt;/code&gt;, а не &lt;code&gt;className&lt;/code&gt; — это одно из отличий Preact от React.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Серверный рендеринг Preact-компонентов.&lt;/strong&gt; Даже без клиентской директивы Preact-компоненты рендерятся на сервере в HTML. Директива лишь добавляет гидратацию. Это значит, что поисковик увидит контент компонента, даже если JavaScript в браузере отключён.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;client:only="preact"&lt;/code&gt;&lt;/strong&gt; нужен в редких случаях — когда компонент использует браузерные API (localStorage, window) и не может быть отрендерен на сервере. В таком случае Astro пропускает серверный рендеринг полностью.&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;// Компонент, который читает из localStorage — не может работать на сервере
export default function ThemeToggle() {
  const [theme, setTheme] = useState(
    // localStorage доступен только в браузере
    () =&amp;gt; localStorage.getItem('theme') ?? 'light'
  );

  // ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;
&lt;code&gt;&amp;lt;!-- Правильно: client:only пропускает SSR --&amp;gt;
&amp;lt;ThemeToggle client:only="preact" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Итог&lt;/h2&gt;

&lt;p&gt;Astro полезен там, где важны скорость первой отрисовки, небольшой клиентский бандл и гибкая интеграция с несколькими UI-фреймворками. Preact в этой экосистеме хорошо подходит для компактных интерактивных компонентов и для проектов, где нужна совместимость с частью React-экосистемы, но без полного веса React runtime.&lt;/p&gt;</summary>
    <dc:creator>Vadim Mikhu</dc:creator>
    <dc:date>2026-05-06T09:23:00Z</dc:date>
  </entry>
  <entry>
    <title>Введение в архитектуру ПО. Часть 1: Истинная ценность структуры и цена спешки</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21249903" />
    <author>
      <name>Romo Fedoroff</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21249903</id>
    <updated>2026-05-01T13:23:55Z</updated>
    <published>2026-05-01T12:54: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 style="text-align: justify;"&gt;Введение&lt;/h2&gt;

&lt;p style="text-align: justify;"&gt;Вы когда-нибудь сталкивались с ситуацией, когда добавление «одной небольшой кнопки» на сайт превращается в задачу на несколько дней? Или когда каждый новый запрос от бизнеса оказывается сложнее предыдущего, хотя на первый взгляд всё выглядит просто? Как правило, причина кроется не в уровне команды и не в сложности самих задач -&amp;nbsp;а в том, на каком фундаменте выполнен проект.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Давайте разберёмся: зачем нужна архитектура, почему спешка в начале выходит боком впоследствии, и как выстраивать конструктивный диалог с руководством о качестве кода.&lt;/p&gt;

&lt;h2 style="text-align: justify;"&gt;Что на самом деле означает хорошая архитектура&lt;/h2&gt;

&lt;p style="text-align: justify;"&gt;Распространённое заблуждение -&amp;nbsp;считать, что хорошая архитектура обязательно предполагает сложные паттерны, многоуровневые абстракции или модные технологические решения. На практике всё значительно проще.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p style="text-align: justify;"&gt;Хорошая архитектура -&amp;nbsp;это когда разработчики тратят минимум усилий на создание нового функционала и поддержку существующего.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Именно это и является единственным значимым критерием.&lt;/strong&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;&lt;strong&gt;Для тех, кто только начинает путь в разработке:&lt;/strong&gt;&amp;nbsp;представьте конструктор. Если детали рассортированы по типам и размерам, собирать новые уровни легко. Если всё свалено в одну кучу, а нижние уровни собраны кое-как -&amp;nbsp;каждый новый этаж будет даваться труднее предыдущего, потому что прежде всего придётся укреплять то, что уже есть.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Для специалистов с опытом:&amp;nbsp;&lt;/strong&gt;в терминологии бизнеса это совокупная стоимость владения продуктом. Слабая архитектура делает кривую стоимости изменений экспоненциальной. Когда вы обосновываете необходимость рефакторинга перед заинтересованными сторонами - говорите именно об этом, а не об абстрактном «качестве кода».&lt;/p&gt;

&lt;h2 style="text-align: justify;"&gt;Синдром быстрого старта и иллюзия «разберёмся потом»&lt;/h2&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;/p&gt;

&lt;blockquote&gt;
&lt;p style="text-align: justify;"&gt;Команды работают в условиях постоянного давления: сроки поджимают, рынок не ждёт. В такой обстановке легко поддаться соблазну сделать «как-нибудь сейчас, а разберёмся потом». Это, пожалуй, одно из самых распространённых и дорогостоящих заблуждений в индустрии.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Проблема в том, что это «потом» почти никогда не наступает. После первой задачи приходит вторая, за ней третья -&amp;nbsp;давление не ослабевает, а технический долг неуклонно накапливается. До тех пор, пока рутинная задача вдруг не начинает занимать неделю вместо дня.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p style="text-align: justify;"&gt;Именно тогда возникает идея: «Давайте перепишем всё с нуля». Но если подход к проектированию не меняется по существу, новая система через несколько лет придёт ровно к тому же результату -&amp;nbsp;как если бы та же бригада построила рядом новый дом, но снова без нормального фундамента.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Здесь работает простая закономерность: поддерживать порядок в коде с самого начала - быстрее и дешевле, чем разгребать последствия накопленного беспорядка. На любой дистанции и при любом масштабе проекта.&lt;/p&gt;

&lt;h2 style="text-align: justify;"&gt;Технический долг: когда метафора становится реальностью&lt;/h2&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;blockquote&gt;
&lt;p style="text-align: justify;"&gt;Важно понимать: технический долг сам по себе не всегда является ошибкой. Иногда это осознанное и обоснованное решение. Например, стартап на ранней стадии может намеренно выбрать более простое техническое решение, чтобы быстро проверить гипотезу на рынке. Это разумно -&amp;nbsp;при условии, что долг фиксируется явно и план по его погашению существует.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p style="text-align: justify;"&gt;Проблема возникает тогда, когда технический долг накапливается неосознанно -&amp;nbsp;когда команда не отдаёт себе отчёта в том, что именно она делает и какие последствия это повлечёт. В таком случае «проценты» начинают начисляться сами собой, и в какой-то момент их обслуживание поглощает большую часть производительности команды.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Признаки того, что технический долг вышел из-под контроля, как правило, очевидны:&lt;/p&gt;

&lt;ul&gt;
	&lt;li style="text-align: justify;"&gt;Разработчики боятся вносить изменения в определённые части системы, потому что не понимают, что именно может сломаться.&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;Исправление одной ошибки порождает две новые в других местах.&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;p style="text-align: justify;"&gt;Если хотя бы два из этих признаков присутствуют в вашем проекте -&amp;nbsp;технический долг уже влияет на производительность команды, даже если это ещё не очевидно в цифрах.&lt;/p&gt;

&lt;h2 style="text-align: justify;"&gt;Две составляющие любого программного продукта&lt;/h2&gt;

&lt;p style="text-align: justify;"&gt;У каждой программной системы есть два измерения. Трудности начинаются тогда, когда о каком-то из них забывают.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Поведение&amp;nbsp;&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;- это то, насколько легко систему можно изменить.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Само английское слово &lt;em&gt;&lt;strong&gt;software&lt;/strong&gt;&lt;/em&gt;&amp;nbsp;содержит в себе это значение: &lt;em&gt;&lt;strong&gt;soft&lt;/strong&gt;&lt;/em&gt;&amp;nbsp;-&amp;nbsp;мягкий, податливый. Программное обеспечение изначально задумано как то, что легко поддаётся изменениям. Сложность добавления новой возможности должна определяться только масштабом самой этой возможности -&amp;nbsp;но никак не состоянием кодовой базы.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Наглядный пример: &lt;/strong&gt;система формирует отчёты в формате PDF. Бизнес просит добавить выгрузку в Excel. Если архитектура продумана -&amp;nbsp;это задача на несколько дней. Если логика формирования отчёта жёстко связана с логикой генерации PDF -&amp;nbsp;команда переписывает модуль несколько недель.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Что важнее - поведение или структура? Ответ неочевиден, но принципиален.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p style="text-align: justify;"&gt;Система, которая работает безупречно, но которую невозможно изменить, потеряет актуальность при первом же серьёзном изменении требований. Система, которая работает с некоторыми недочётами, но легко поддаётся изменениям, может развиваться и приносить пользу годами. Первую не спасёт даже идеальный функционал -&amp;nbsp;вторую вытянет сама гибкость.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 style="text-align: justify;"&gt;Связанность и согласованность: два понятия, которые стоит знать&lt;/h2&gt;

&lt;p style="text-align: justify;"&gt;Если говорить о структуре системы чуть более конкретно, то в основе большинства архитектурных решений лежат два фундаментальных понятия: связанность и согласованность. Понимание этих концепций помогает оценивать качество архитектуры не интуитивно, а осознанно.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Связанность&lt;/strong&gt;&amp;nbsp;-&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;strong&gt;Согласованность&amp;nbsp;&lt;/strong&gt;-&amp;nbsp;это степень того, насколько элементы одного модуля относятся к одной задаче. Высокая согласованность означает, что каждый модуль делает что-то одно, но делает это хорошо. Низкая согласованность - признак того, что в одном месте собрано слишком много разнородной логики, которую со временем становится всё труднее понимать и поддерживать.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p style="text-align: justify;"&gt;Идеальное сочетание для здоровой архитектуры -&amp;nbsp;низкая связанность и высокая согласованность. Именно к этому балансу стремятся большинство архитектурных принципов и паттернов, о которых мы будем говорить в следующих материалах.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 style="text-align: justify;"&gt;Матрица Эйзенхауэра: почему архитектура всегда проигрывает в приоритетах&lt;/h2&gt;

&lt;p style="text-align: justify;"&gt;Президент Дуайт Эйзенхауэр сформулировал это так: «У меня есть два вида дел -&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;/p&gt;

&lt;p style="text-align: justify;"&gt;Проектирование, рефакторинг, работа над структурой системы -&amp;nbsp;это важно. Критически важно. Однако никто не приходит к разработчику с задачей «срочно улучши архитектуру». Поэтому она откладывается снова и снова -&amp;nbsp;и это не лень, а системная ошибка в расстановке приоритетов, которую необходимо осознанно исправлять.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p style="text-align: justify;"&gt;Вывод здесь прост: если команда никогда не выделяет время на важное, потому что всегда находится что-то срочное -&amp;nbsp;рано или поздно срочным становится всё.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p style="text-align: justify;"&gt;Система деградирует до состояния, в котором каждое изменение требует экстренного вмешательства, а разработка превращается в постоянную борьбу с последствиями прошлых решений. Именно поэтому работа над архитектурой должна планироваться намеренно и регулярно -&amp;nbsp;не в ущерб срочным задачам, но и не в вечном ожидании подходящего момента, который так и не наступит.&lt;/p&gt;

&lt;h2 style="text-align: justify;"&gt;Как архитектура влияет на команду: человеческое измерение&lt;/h2&gt;

&lt;p style="text-align: justify;"&gt;Разговор об архитектуре нередко сводится к техническим и экономическим аргументам. Однако есть ещё одно измерение, которое упускают из виду -&amp;nbsp;человеческое.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Работа в условиях плохо спроектированной системы изматывает. Разработчик, который каждый день вынужден продираться сквозь запутанный код, тратит значительную часть своих когнитивных ресурсов не на решение задачи, а на то, чтобы просто понять, что вообще происходит. Это явление называется когнитивной нагрузкой, и оно напрямую влияет на производительность и качество принимаемых решений.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Помимо этого, плохая архитектура негативно сказывается на моральном состоянии команды. Трудно сохранять профессиональную мотивацию, когда понимаешь, что твоя работа -&amp;nbsp;это не создание чего-то нового, а бесконечное латание прорех. Опытные специалисты в таких условиях нередко принимают решение сменить место работы, унося с собой накопленные знания о системе. Это создаёт дополнительные риски для проекта, которые крайне сложно измерить, но очень болезненно ощутить.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p style="text-align: justify;"&gt;Хорошая архитектура, напротив, создаёт среду, в которой разработчики могут сосредоточиться на содержательной работе.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p style="text-align: justify;"&gt;Когда система организована логично, новый член команды способен разобраться в ней значительно быстрее. Когда модули изолированы и независимы, над разными частями продукта можно работать параллельно, не мешая друг другу. Всё это -&amp;nbsp;не абстрактные преимущества, а вполне конкретные факторы, влияющие на скорость и качество разработки.&lt;/p&gt;

&lt;h2 style="text-align: justify;"&gt;Как обосновывать важность архитектуры в диалоге с руководством&lt;/h2&gt;

&lt;p style="text-align: justify;"&gt;Разработчик -&amp;nbsp;это не просто исполнитель, реализующий поставленные задачи. Это профессионал со своей зоной ответственности. И защита качества системы -&amp;nbsp;неотъемлемая часть этой ответственности.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Менеджеры, маркетологи, отдел продаж будут закономерно требовать скорости -&amp;nbsp;это их работа. Задача разработчика -&amp;nbsp;не противостоять этому давлению молчанием или раздражением, а уметь выстраивать аргументированный диалог.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Несколько практических принципов:&lt;/p&gt;

&lt;ul&gt;
	&lt;li style="text-align: justify;"&gt;&lt;strong&gt;Избегайте субъективных формулировок&lt;/strong&gt;: «код стал некрасивым» или «это технически неправильно» не убеждают никого, кто не занимается разработкой.&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;&lt;strong&gt;Говорите на языке конкретных последствий&lt;/strong&gt;: «Если мы выделим три дня на оптимизацию этого модуля сейчас, следующий этап займёт неделю, а не месяц».&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;&lt;strong&gt;Фиксируйте технический долг явно.&lt;/strong&gt; Если ваша команда принимает осознанное решение сделать что-то упрощённо ради скорости -&amp;nbsp;запишите это. Создайте задачу, опишите, что именно было сделано не так, как следовало бы, и почему. Это переводит технический долг из категории неосознанного накопления в категорию управляемого инструмента. Руководство видит, что команда отдаёт себе отчёт в принятых решениях, а не просто пишет «как получается».&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;&lt;strong&gt;Внедрите принцип постепенного улучшения&lt;/strong&gt;: каждый раз, работая с определённым участком кода, оставляйте его в немного лучшем состоянии, чем он был до вашего вмешательства. Это не требует отдельного времени -&amp;nbsp;это профессиональная привычка, которая со временем существенно меняет общее состояние системы.&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;&lt;strong&gt;Предлагайте компромиссы, а не ультиматумы. &lt;/strong&gt;Вместо «нам нужна неделя на рефакторинг, иначе ничего не выйдет» попробуйте «давайте заложим в план двадцать процентов времени на улучшение структуры параллельно с основной работой». Это звучит управляемо и вызывает значительно меньше сопротивления.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 style="text-align: justify;"&gt;Заключение&lt;/h2&gt;

&lt;p style="text-align: justify;"&gt;Если сформулировать главное из этого материала, получится следующее.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
	&lt;li style="text-align: justify;"&gt;Качество архитектуры измеряется не технической изощрённостью решений, а тем, насколько легко и предсказуемо в систему вносятся изменения спустя месяцы и годы после запуска.&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;Поддерживать порядок в коде с самого начала выгоднее, чем устранять последствия накопленного беспорядка -&amp;nbsp;это не вопрос эстетики, а вопрос экономики разработки.&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;Технический долг -&amp;nbsp;управляемый инструмент, когда он осознан и зафиксирован. Неуправляемая угроза -&amp;nbsp;когда накапливается незаметно и без плана по погашению.&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;Гибкость системы в долгосрочной перспективе важнее идеального функционала в моменте. Рынок меняется, требования меняются -&amp;nbsp;продукт, который не способен меняться вместе с ними, неизбежно теряет ценность.&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;Архитектура влияет не только на код, но и на людей. Среда, в которой разработчики могут работать уверенно и без лишних препятствий -&amp;nbsp;это конкурентное преимущество, которое сложно измерить, но легко потерять.&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;И наконец: умение объяснить всё это руководству на понятном бизнесу языке -&amp;nbsp;такой же профессиональный навык, как и умение проектировать надёжные системы.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p style="text-align: justify;"&gt;&lt;em&gt;&lt;strong&gt;Спасибо, что прочитали материал до конца.&lt;/strong&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;em&gt;&lt;strong&gt;Следите за продолжением.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;</summary>
    <dc:creator>Romo Fedoroff</dc:creator>
    <dc:date>2026-05-01T12:54:00Z</dc:date>
  </entry>
  <entry>
    <title>Анатомия письма: почему email-дизайн — это машина времени в 1999 год</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21239713" />
    <author>
      <name>Алексей Кондратьев</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21239713</id>
    <updated>2026-04-08T17:34:56Z</updated>
    <published>2026-04-08T16:59:00Z</published>
    <summary type="html">&lt;p&gt;Вы когда-нибудь пробовали применить display: flex или grid в коде письма? Если да, то вы знаете чувство глубокого разочарования, когда Gmail, Outlook или Yahoo решают, что ваш современный красивый макет должен выглядеть как стена текста, набранная на печатной машинке.&lt;/p&gt;

&lt;p&gt;Добро пожаловать в мир email-дизайна — уникальной дисциплины, где правила веб-разработки не работают, а стандарты де-факто застыли в эпохе Netscape Navigator. Здесь дизайнер и верстальщик вынуждены использовать табличную вёрстку, писать инлайновые стили и воевать с условными комментариями для Outlook. И тем не менее, именно здесь рождаются письма, которые читают, по которым кликают и которые приносят миллионы.&lt;/p&gt;

&lt;p&gt;Эта статья — глубокое погружение в специфику создания адаптивных писем. Мы разберем, почему таблицы до сих пор правят бал, как сделать письмо красивым на iPhone и при этом не сломать его на древней версии Microsoft Outlook.&lt;br /&gt;
&lt;br /&gt;
&lt;b id="docs-internal-guid-849f4ac7-7fff-726e-277c-e88d7b336db7"&gt;Часть 1. Великий парадокс: Почему email живет в прошлом?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;В отличие от сайтов, которые вы открываете в одном-двух браузерах (Chrome, Safari), email-клиентов — сотни. Каждый из них использует свой движок для рендеринга HTML:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Gmail (веб и приложение) использует свой собственный, сильно урезанный HTML-парсер.&lt;/li&gt;
	&lt;li&gt;Outlook (десктоп) печально известен тем, что использует движок Microsoft Word (!) для отображения HTML.&lt;/li&gt;
	&lt;li&gt;Apple Mail — один из самых «продвинутых», поддерживает современные CSS.&lt;/li&gt;
	&lt;li&gt;Яндекс.Почта, Mail.ru — имеют свои особенности.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Чтобы письмо выглядело одинаково (или хотя бы читаемо) во всех этих средах, разработчики вынуждены опираться на наименьший общий знаменатель — технологии, которые были стандартом 20 лет назад.&lt;/p&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-8c2f7877-7fff-2589-2a3e-92bf3248c5fe"&gt;Часть 2. Табличная вёрстка: Скелет вашего письма&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Забудьте про &amp;lt;div&amp;gt; с display: flex. В мире email главный строительный блок — это &amp;lt;table&amp;gt;.&lt;/p&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-b64a5411-7fff-7c83-f27f-6dd3592ce2ce"&gt;2.1. Почему таблицы?&lt;/b&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Предсказуемость: Таблицы были созданы для отображения структурированных данных. Их алгоритм рендеринга (как ячейки растягиваются и выравниваются) одинаков во всех клиентах.&lt;/li&gt;
	&lt;li&gt;Надёжность: Они устойчивы к «съеданию» тегов и стилей. Если какой-то CSS не сработает, таблица всё равно останется таблицей.&lt;/li&gt;
	&lt;li&gt;Вложенность: Вся вёрстка письма — это матрёшка из вложенных друг в друга таблиц.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-aa6e7488-7fff-1746-1494-0ba87bfbe014"&gt;2.2. Базовая структура «резинового» письма&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Современное адаптивное письмо строится по следующему шаблону:&lt;/p&gt;

&lt;pre class="brush:xml;"&gt;
&amp;lt;center&amp;gt;
    &amp;lt;table role="presentation" width="100%" border="0" cellpadding="0" cellspacing="0"&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;td align="center"&amp;gt;
                &amp;lt;!-- Основной контейнер письма (ширина 600px) --&amp;gt;
                &amp;lt;table role="presentation" width="600" border="0" cellpadding="0" cellspacing="0"&amp;gt;
                    &amp;lt;!-- ШАПКА --&amp;gt;
                    &amp;lt;tr&amp;gt;
                        &amp;lt;td&amp;gt; ... &amp;lt;/td&amp;gt;
                    &amp;lt;/tr&amp;gt;
                    &amp;lt;!-- ГЕРОЙ (Баннер) --&amp;gt;
                    &amp;lt;tr&amp;gt;
                        &amp;lt;td&amp;gt; ... &amp;lt;/td&amp;gt;
                    &amp;lt;/tr&amp;gt;
                    &amp;lt;!-- ТЕЛО С КОЛОНКАМИ --&amp;gt;
                    &amp;lt;tr&amp;gt;
                        &amp;lt;td&amp;gt;
                            &amp;lt;table role="presentation" width="100%" border="0" cellpadding="0" cellspacing="0"&amp;gt;
                                &amp;lt;tr&amp;gt;
                                    &amp;lt;td class="stack" width="280"&amp;gt; Левая колонка &amp;lt;/td&amp;gt;
                                    &amp;lt;td class="stack" width="20"&amp;gt; Отступ &amp;lt;/td&amp;gt;
                                    &amp;lt;td class="stack" width="280"&amp;gt; Правая колонка &amp;lt;/td&amp;gt;
                                &amp;lt;/tr&amp;gt;
                            &amp;lt;/table&amp;gt;
                        &amp;lt;/td&amp;gt;
                    &amp;lt;/tr&amp;gt;
                    &amp;lt;!-- ФУТЕР --&amp;gt;
                    &amp;lt;tr&amp;gt;
                        &amp;lt;td&amp;gt; ... &amp;lt;/td&amp;gt;
                    &amp;lt;/tr&amp;gt;
                &amp;lt;/table&amp;gt;
            &amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
    &amp;lt;/table&amp;gt;
&amp;lt;/center&amp;gt;&lt;/pre&gt;

&lt;p&gt;Ключевые моменты:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;role="presentation" — говорит скрин-ридерам, что это таблица для вёрстки, а не для данных.&lt;/li&gt;
	&lt;li&gt;width="100%" — делает внешнюю таблицу «резиновой».&lt;/li&gt;
	&lt;li&gt;align="center" — центрирует всё письмо.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-aedc18bc-7fff-8923-d233-76ceb55a2c1b"&gt;Часть 3. Адаптивность: Как превратить две колонки в одну&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;На десктопе мы видим две колонки текста. На мобильном телефоне они должны встать друг под друга. Это достигается с помощью медиа-запросов и трюка с display: block !important.&lt;/p&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-b3c933fd-7fff-ac7d-9e78-25391708c8eb"&gt;3.1. Медиа-запросы&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Мы задаём правило: если ширина экрана меньше 600px, то заставляем наши колонки (с классом .stack) стать блочными и растянуться на 100%.&lt;/p&gt;

&lt;pre class="brush:xml;"&gt;
@media only screen and (max-width: 600px) {
    .stack {
        display: block !important;
        width: 100% !important;
    }
}&lt;/pre&gt;

&lt;p&gt;В нашем примере выше, у колонок ширина 280px и отступа 20px. На мобильном они получат width: 100% и выстроятся вертикально, а отступ превратится в пустую строку.&lt;/p&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-cceb5875-7fff-3d3c-4796-15b1d299b2d0"&gt;3.2. Проблема кнопок&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Кнопки в письмах — это главная головная боль. &amp;lt;button&amp;gt; работает плохо. Ссылка &amp;lt;a&amp;gt; с padding тоже часто ломается в Outlook.&lt;br /&gt;
Надёжный способ (Bulletproof Button):&lt;br /&gt;
Сделать кнопку через границы ячейки таблицы.&lt;/p&gt;

&lt;pre class="brush:xml;"&gt;
&amp;lt;table role="presentation" border="0" cellpadding="0" cellspacing="0"&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td align="center" bgcolor="#007bff" style="border-radius: 4px;"&amp;gt;
            &amp;lt;a href="https://example.com" style="display: inline-block; padding: 12px 24px; color: #fff; text-decoration: none; font-weight: bold;"&amp;gt;Купить сейчас&amp;lt;/a&amp;gt;
        &amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;&lt;/pre&gt;

&lt;p&gt;Почему это работает? Фон задаётся ячейке (td), а ссылка внутри просто растягивается. Outlook не любит фон у ссылок, но любит фон у ячеек.&lt;/p&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-3472f228-7fff-cbf0-2b26-414df624830e"&gt;Часть 4. Тонкая настройка: Инлайновые стили и условные комментарии&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-aab3cb20-7fff-e212-56af-67df1a394009"&gt;4.1. Инлайн — король&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Никогда не полагайтесь на то, что стили, прописанные в &amp;lt;head&amp;gt; или внешнем CSS, сработают. Gmail, например, вырезает &amp;lt;style&amp;gt; при определённых условиях. Правило: все стили, касающиеся отступов, цветов, границ, шрифтов, должны быть прописаны в атрибуте style каждого тега.&lt;/p&gt;

&lt;pre class="brush:xml;"&gt;
&amp;lt;td style="padding: 20px; font-family: Arial, sans-serif; color: #333;"&amp;gt;
&lt;/pre&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-6271f925-7fff-5c98-5d53-9a59c8930c7c"&gt;4.2. Условные комментарии для Microsoft Outlook&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Outlook (особенно 2007, 2010, 2013) — это темная лошадка. Чтобы задать стили только для Outlook, используют условные комментарии, которые никто, кроме Outlook, не видит.&lt;/p&gt;

&lt;pre class="brush:xml;"&gt;
&amp;lt;!--[if mso]&amp;gt;
    &amp;lt;style type="text/css"&amp;gt;
        /* Стили, которые увидит только Outlook */
        .outlook-button { background: #000; }
    &amp;lt;/style&amp;gt;
&amp;lt;![endif]--&amp;gt;
&lt;/pre&gt;

&lt;p&gt;А для обратной ситуации (спрятать что-то от Outlook):&lt;/p&gt;

&lt;pre class="brush:xml;"&gt;
&amp;lt;!--[if !mso]&amp;gt;&amp;lt;!--&amp;gt;
    &amp;lt;div style="display: none;"&amp;gt;Это увидят все, кроме Outlook&amp;lt;/div&amp;gt;
&amp;lt;!--&amp;lt;![endif]--&amp;gt;
&lt;/pre&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-e8cd7281-7fff-49e5-a3d0-c7ece27c491c"&gt;Часть 5. Изображения: Смертельный номер&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;В email-дизайне изображения — это источник проблем. Многие почтовые клиенты по умолчанию блокируют загрузку картинок (пользователь должен нажать «Показать изображения»). Если ваше письмо — одна большая картинка, пользователь увидит пустоту.&lt;/p&gt;

&lt;p&gt;Правила работы с изображениями:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Не кладите текст на картинки. Если картинка не загрузится, текст не увидят.&lt;/li&gt;
	&lt;li&gt;Всегда прописывайте ALT-текст. И делайте его полезным: не «логотип», а «Купите iPhone со скидкой 20%».&lt;/li&gt;
	&lt;li&gt;Используйте атрибуты ширины и высоты. Без них Outlook может отобразить картинку размером 1x1 пиксель.&lt;/li&gt;
	&lt;li&gt;
	&lt;pre class="brush:xml;"&gt;
&amp;lt;img src="..." alt="Описание" width="600" height="200" style="display: block; width: 100%; height: auto;"&amp;gt;&lt;/pre&gt;
	&lt;/li&gt;
	&lt;li&gt;Спрайты и адаптивность: Чтобы картинка сжималась на мобильном, дайте ей style="width: 100%; height: auto;".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-cf785bc7-7fff-9604-c2d8-aea609b58089"&gt;Часть 6. Инструменты и тестирование&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Спроектировать письмо «на глаз» невозможно. Вы обязательно что-то сломаете в Outlook или Gmail.&lt;/p&gt;

&lt;p&gt;Современный подход к созданию писем:&lt;/p&gt;

&lt;p&gt;Дизайн в Figma: Рисуйте макет, помня, что ширина письма редко превышает 600px (оптимально для чтения).&lt;/p&gt;

&lt;p&gt;Фреймворк MJML: Это спасение. Вы пишете простой, понятный код на MJML, а компилятор превращает его в идеально работающую табличную вёрстку. Это стандарт индустрии.&lt;/p&gt;

&lt;p&gt;Тестирование (важно!):&amp;nbsp;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Litmus / Email on Acid: Платные сервисы, которые прогоняют ваше письмо через 90+ клиентов и показывают скриншоты.&lt;/li&gt;
	&lt;li&gt;PutsMail: Бесплатный инструмент для отправки тестовых писем.&lt;/li&gt;
	&lt;li&gt;Реальная отправка: Заведите себе аккаунты в Gmail, Яндекс.Почте, Outlook.com, Mail.ru и отправляйте письма себе.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-6b8e47b0-7fff-248e-3230-749e3dda26f3"&gt;Заключение: Это не баг, это фича&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Дизайн для email-рассылок раздражает веб-разработчиков своей архаичностью. Но это осознанный выбор, продиктованный средой. Умение создать надёжное, красивое и конвертирующее письмо, которое работает даже в Outlook 2007, — это признак высокой квалификации.&lt;/p&gt;

&lt;p&gt;В следующий раз, когда вы откроете красивую рассылку от Apple или Amazon, знайте: внутри неё — десятки вложенных таблиц, условные комментарии и надежда, что пользователь включил отображение картинок. Это и есть магия email-дизайна.&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;&lt;br /&gt;
&amp;nbsp;&lt;/p&gt;</summary>
    <dc:creator>Алексей Кондратьев</dc:creator>
    <dc:date>2026-04-08T16:59:00Z</dc:date>
  </entry>
  <entry>
    <title>Нативная поддержка gRPC в Spring</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21239144" />
    <author>
      <name>Maxim Kalabukhov</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21239144</id>
    <updated>2026-04-07T16:08:06Z</updated>
    <published>2026-04-07T15:04:00Z</published>
    <summary type="html">&lt;p&gt;Не так давно в релиз был выкачена первая мажорная версия библиотеки&amp;nbsp;Spring gRPC -&amp;nbsp;для встроенной поддержки gRPC-сервисов в приложении Spring Boot.&amp;nbsp;Она развивается внутри экосистемы Spring, а значит версионирование и интеграция с Boot - это теперь не вызывает проблем. У меня появился интерес протестить это in action.&lt;br /&gt;
&lt;br /&gt;
​​​​Начнем с того, что подключим необходимые зависимости в &lt;code&gt;build.gradle.kts&lt;/code&gt;:&lt;/p&gt;

&lt;div class="portlet-msg-info"&gt;implementation("org.springframework.grpc:spring-grpc-spring-boot-starter")&lt;br /&gt;
implementation("com.google.protobuf:protobuf-java")&lt;/div&gt;

&lt;p class="font-claude-response-body break-words whitespace-normal leading-[1.7]"&gt;Допустим, у нас есть такой proto-файл:&lt;br /&gt;
​​​​​&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}&lt;/pre&gt;

&lt;p&gt;Реализация сервиса на kotlin будет выглядить следующим образом:&lt;br type="_moz" /&gt;
&amp;nbsp;&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
@GrpcService 
class GreeterService : GreeterGrpc.GreeterImplBase() {

    override fun sayHello(
        request: HelloRequest,
        responseObserver: StreamObserver&amp;lt;HelloReply&amp;gt;
    ) {
        val reply = HelloReply.newBuilder()
            .setMessage("Hello, ${request.name}!")
            .build()

        responseObserver.onNext(reply)
        responseObserver.onCompleted()
    }
}
&lt;cite&gt;​​​​​​​// можно использовать и аннотацию &lt;code&gt;@Service&lt;/code&gt;, но на личный вкус &lt;code&gt;@GrpcService&lt;/code&gt; выглядит нагляднее&lt;/cite&gt;&lt;/pre&gt;

&lt;p&gt;Spring gRPC автоматически обнаружит все бины, которые реализуют &lt;code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]"&gt;BindableService&lt;/code&gt; (это интерфейс, от которого наследует &lt;code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]"&gt;ImplBase&lt;/code&gt;), и зарегистрирует их на gRPC-сервере.&lt;br /&gt;
​​​​&lt;/p&gt;

&lt;p&gt;Дело за малым - осталось всё собрать и протестировать. Делать я это буду с помощью cli тулзы grpcurl, которая как раз предназначена для протыкивания grpc сервисов.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img src="https://www.tune-it.ru/documents/portlet_file_entry/21214588/grpc+run.png/9e7b3773-5c0e-5a92-93e9-35f18c03c74e?imagePreview=1" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://www.tune-it.ru/documents/portlet_file_entry/21214588/grpcresult.png/d3be2251-399d-8fb6-6b93-18d848a58612?imagePreview=1" /&gt;&lt;/p&gt;

&lt;p class="svelte-121hp7c" dir="auto"&gt;Подводя итог, можно сказать, что Spring gRPC успешно решает главную задачу - делает интеграцию gRPC в Spring Boot максимально бесшовной и нативной. Как показал тест, весь процесс настройки сводится к подключению стартера и созданию класса с аннотацией &lt;code class="cursor-pointer codespan"&gt;@Service&lt;/code&gt;.&amp;nbsp;Автоматическое обнаружение сервисов и привычная работа через DI позволяют сосредоточиться на бизнес-логике, не отвлекаясь на инфраструктурные сложности.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;​​​​​​​​​​​​​​&lt;/p&gt;</summary>
    <dc:creator>Maxim Kalabukhov</dc:creator>
    <dc:date>2026-04-07T15:04:00Z</dc:date>
  </entry>
  <entry>
    <title>Кэширование пользовательских ролей из стороннего сервиса при Stateless-аутентификации (Spring)</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21238639" />
    <author>
      <name>Никита Рогаленко</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21238639</id>
    <updated>2026-04-06T13:47:44Z</updated>
    <published>2026-04-06T13:45:00Z</published>
    <summary type="html">&lt;p style="text-align: justify;"&gt;Представим не столь редкую ситуацию, когда у нас есть некоторый сервис на базе Spring, к которому шлет запросы клиентское приложение. Фронтэнд взаимодействует с Keycloak (или другим сервером аутентификации, не столь важно), определяет пользователя, делающего запросы, и при обращении к нашему сервису подкладывает в заголовок "Authorization" Bearer-токен в виде JWT, на основании которого в сервисе должны происходить идентификация пользователя и определение прав доступа.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Схема обычная и соответствует стандарту авторизации OAuth 2.0, однако проблемы возникают, если нам необходимо непосредственно в процессе авторизации выдать те или иные права, основываясь на данных из другого сервиса, либо в целом приходится использовать какие-либо данные извне. Несмотря на все преимущества stateless-аутентификации, среди которых масштабируемость и производительность, в данном случае она будет проблемой, потому что при данном подходе сервер не использует сессии и не хранит никакой информации о клиенте между запросами. Таким образом, информация из стороннего сервиса будет запрашиваться заново при каждом запросе, что может сильно ударить по производительности системы. Конечно подобные проблемы лучше решать еще на этапе проектирования архитектуры всей системы, но если ситуация уже возникла, то решение есть.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Чтобы не запрашивать данные из стороннего сервиса каждый раз, можно прибегнуть к кэшированию данных, сохраняя их по идентификатору пользователя. Для этого есть несколько решений, но мы рассмотрим вариант, оптимальный&amp;nbsp; по сложности реализации и скорости выполнения. Это будет стандартная поддержка кэширования Spring и библиотека&amp;nbsp;Caffeine, которая де-факто уже также стала частью стандарта кэширования в Spring. Это будет быстрее, чем читать и обновлять значения из Redis, поднимать который имеет смысл лишь в случае множества распределенных сервисов, поскольку в данном случае кэш будет храниться прямо в памяти приложения.&amp;nbsp;В дополнение к этому мы также напишем конвертер для аутентификации, который при входе будет объединять роли из Keycloak и роли, приходящие из стороннего сервиса, чтобы в нашем сервисе можно было единообразно их использовать.&amp;nbsp;&amp;nbsp;&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Шаг 1. Зависимости и конфигурация приложения&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li style="text-align: justify;"&gt;Добавить зависимости:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="brush:as3;"&gt;
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
    implementation 'org.springframework.boot:spring-boot-starter-cache'
    implementation 'com.github.ben-manes.caffeine:caffeine'
}&lt;/pre&gt;

&lt;ul&gt;
	&lt;li style="text-align: justify;"&gt;В главный класс надо добавить аннотацию&amp;nbsp;@EnableCaching, которая включит кэширвание в Spring&lt;/li&gt;
	&lt;li style="text-align: justify;"&gt;Добавить в application.yml нужные настройки:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="brush:as3;"&gt;
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://your-keycloak.com/realms/test
  cache:
    cache-names: infoFromOtherService
    caffeine:
      spec: expireAfterWrite=60s,maximumSize=1000&lt;/pre&gt;

&lt;p style="text-align: justify;"&gt;Здесь под issuer-uri мы указываем адрес Keycloak для проверки валидности токена, который пришел с клиентского приложения. В разделе cache указываем название для кэша, где мы будем хранить информацию о пользователе, приходящую из стороннего сервиса. В spec мы указываем настройки caffeine, которые помогут не очищать кэш самостоятельно, а задать ему срок жизни (в данном случае 60 секунд), после которого данные будут запрашиваться снова. В maximumSize пишется максимальный размер кэша, чтобы он не мог занять слишком много места.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Шаг 2. Сервис, который запрашивает данные о пользователе из стороннего сервиса&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="brush:java;"&gt;

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

​​​​​​​@Service
public class ExternalSourceService {

    // sync = true защищает от повторной отправки застрявших в очереди запросов при истечении кэша
    @Cacheable(value = "infoFromOtherService", key = "#username", sync = true)
    public List&amp;lt;String&amp;gt; getInfoFromExternalSource(String username) {
        // Вызов API
        return externalSourceClient.findExternalInfoByUsername(username); 
    }
}&lt;/pre&gt;

&lt;p style="text-align: justify;"&gt;Это самый обычный сервис, который делает необходимый запрос по указанному API. Не будем приводить его реализацию, поскольку это сильно зависит от конкретного случая, отметим только необходимость добавить аннотацию&amp;nbsp;Cacheable, value которой совпадает с названием кэша из настроек. С помощью этой аннотации мы отмечаем, что результаты именно этого метода необходимо кэшировать.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Шаг 3. Конвертер, преобразующий JWT-токен&lt;/strong&gt;​​​​​​​&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
​​​​​​​
@Component
@RequiredArgsConstructor
public class AuthenticationConverter implements Converter&amp;lt;Jwt, AbstractAuthenticationToken&amp;gt; {

    @Autowired
    private final ExternalSourceService externalSourceService;

    @Override
    public AbstractAuthenticationToken convert(Jwt jwt) {
        UUID userId = UUID.fromString(jwt.getSubject()); // UUID пользователя
        String username = jwt.getClaimAsString("preferred_username"); // имя пользователя
        Collection&amp;lt;GrantedAuthority&amp;gt; roles = extractKeycloakRoles(jwt); // получаем роли из Keycloak
&amp;nbsp;       // получаем информацию о пользователе из стороннего источника (что кэшируется)
        String externalSourceUserInfo = externalSourceService.getInfoFromExternalSource(username);
&amp;nbsp;       try {
            // пытаемся добавить роли пользователя из стороннего источника
            Collection&amp;lt;GrantedAuthority&amp;gt; rolesFromExternalSource = extractExternalRoles(externalSourceUserInfo);
            roles.addAll(rolesFromExternalSource);
        } catch (JsonProcessingException e) {
            log.error("Cannot parse user info ", e);
        }
        return new JwtAuthenticationToken(jwt, roles, username);
    }

    private Collection&amp;lt;GrantedAuthority&amp;gt; extractKeycloakRoles(Jwt jwt) {
        Map&amp;lt;String, Object&amp;gt; realmAccess = jwt.getClaim("realm_access");
        if (realmAccess == null || realmAccess.isEmpty()) return Collections.emptyList();
        Collection&amp;lt;String&amp;gt; roles = (Collection&amp;lt;String&amp;gt;) realmAccess.get("roles");
        return roles.stream()
                .map(role -&amp;gt; new SimpleGrantedAuthority("ROLE_" + role))
                .collect(Collectors.toList());
    }

    private Collection&amp;lt;GrantedAuthority&amp;gt; extractExternalRoles(String externalSourceUserInfo) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = objectMapper.readTree(externalSourceUserInfo);
​​​​​​​        // достаем нужный кусок JSON, но парсинг ответа от стороннего сервиса зависит от особенностей конкретной системы
        JsonNode globalRoles = rootNode.get("roles");
        return objectMapper.convertValue(globalRoles, new TypeReference&amp;lt;List&amp;lt;String&amp;gt;&amp;gt;() {
                }).stream().map(role -&amp;gt; new SimpleGrantedAuthority("ROLE_" + role))
                .collect(Collectors.toList());
    }&lt;/pre&gt;

&lt;p style="text-align: justify;"&gt;&lt;strong&gt;Шаг 4. Конфигурация Spring Security&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AuthenticationConverter authenticationConverter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().authorizeRequests()
                    .antMatchers("/api/v1/example/**").authenticated()
                    .anyRequest().hasAnyRole("EXTERNAL_SOURCE_ADMIN")
                .and().oauth2ResourceServer().jwt().jwtAuthenticationConverter(authenticationConverter);

    }
}&lt;/pre&gt;

&lt;p style="text-align: justify;"&gt;Здесь мы уже можем в правилах проверки прав использовать те роли, которые мы получили из стороннего сервиса (вместе с кейклоковскими). И главное, что получение этих ролей не будет отрабатывать при каждом запросе к нашему сервису, а будет происходить лишь по истечении кэша, настройки которого, с использованием Caffeine, можно регулировать в application.yml.&amp;nbsp;&lt;/p&gt;</summary>
    <dc:creator>Никита Рогаленко</dc:creator>
    <dc:date>2026-04-06T13:45:00Z</dc:date>
  </entry>
  <entry>
    <title>REST API: 5 паттернов формирования ответов, которые используют опытные разработчики</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21236519" />
    <author>
      <name>Romo Fedoroff</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21236519</id>
    <updated>2026-04-01T10:44:07Z</updated>
    <published>2026-04-01T09:28: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;Представьте: вы только что запустили новый сервис. Первые эндпоинты работают, данные приходят, фронтенд доволен. Но спустя полгода приходит задача — переименовать колонку в базе данных. Вы меняете одно поле, и внезапно ломаются три мобильных клиента, два фронтенд-приложения и интеграция с партнёром. Почему? Потому что ваш API с самого начала возвращал сырые сущности напрямую из базы данных.&lt;/p&gt;

&lt;p&gt;Это не гипотетический сценарий. Это ежедневная реальность команд, которые не уделили должного внимания слою формирования ответов.&lt;/p&gt;

&lt;p&gt;Возвращать необработанные JPA-сущности из REST-контроллеров — это один из тех паттернов, который кажется безобидным в начале, но&amp;nbsp;затем превращается в системную проблему в production. Он не просто нарушает принцип разделения ответственности — он создаёт&amp;nbsp;три взаимосвязанных риска одновременно: утечку чувствительных данных, жёсткую связанность API со схемой БД и потерю контроля над публичным контрактом.&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;Прежде чем переходить к решениям, важно понять, в чем именно состоит&amp;nbsp;проблема.&lt;/p&gt;

&lt;p&gt;Рассмотрим типичную JPA-сущность:&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String firstName;
    private String lastName;
    private String email;

    // Никогда не должно покидать сервер
    private String passwordHash;

    // Внутренние поля, не нужные клиентам
    private String internalNotes;
    private String resetToken;
    private LocalDateTime resetTokenExpiry;

    // Технические поля аудита
    @CreatedDate
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime updatedAt;

    @Version
    private Long version;
}&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:java;"&gt;
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
    return userRepository.findById(id).orElseThrow();
    // В ответе окажется: passwordHash, internalNotes,
    // resetToken, resetTokenExpiry, version...
}&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;p&gt;&lt;strong&gt;Проблема 1: Утечка чувствительных данных.&lt;/strong&gt;&amp;nbsp;Поле `passwordHash` попадёт в JSON-ответ. Даже если там не открытый пароль, а хеш — это уже вектор для атак. Поле `resetToken` тоже не должно быть видно никому, кроме системы сброса пароля. Можно добавить `@JsonIgnore` на отдельные поля, но это ненадёжно: забудете об одном поле при добавлении — и утечка неизбежна.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проблема 2: Жёсткая связанность с базой данных.&lt;/strong&gt;&amp;nbsp;Ваш API-контракт теперь является точным отражением вашей схемы БД. Переименовали `firstName` в `first_name` для соответствия coding style? Поздравляем — вы сломали всех клиентов. Разделили таблицу `users` на `users` и `user_profiles`? Теперь нужно менять не только схему, но и весь публичный API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проблема 3: Отсутствие контроля над контрактом.&lt;/strong&gt;&amp;nbsp;API должен выражать бизнес-понятия, а не структуру хранилища. Клиент хочет получить `fullName` вместо `firstName` + `lastName`? С сырыми сущностями это невозможно без изменения схемы БД.&lt;/p&gt;

&lt;p&gt;Для решения этих проблем, на помощь приходят проверенные паттерны. Рассмотрим их по порядку.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Паттерн 1: Record-классы для формирования ответа&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;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Традиционные DTO-классы на Java требуют написания конструкторов, геттеров, сеттеров, `equals`, `hashCode` и `toString`. Это десятки строк шаблонного кода на каждую форму ответа. Даже с Lombok это всё равно дополнительные аннотации и косвенность.&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;Java Records (доступны с Java 16) дают вам неизменяемый объект передачи данных в несколько строк — без Lombok, без шаблонного кода, без сюрпризов.&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
public record UserResponse(
    Long id,
    String firstName,
    String lastName,
    String email
) {}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Вот и всё. Java автоматически генерирует конструктор, геттеры, `equals`, `hashCode` и `toString`. Объект неизменяем по умолчанию — никаких сеттеров, никаких случайных мутаций.&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;pre class="brush:java;"&gt;
// Сервисный слой
@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;

    public User findById(Long id) {
        return userRepository.findById(id)
            .orElseThrow(() -&amp;gt; new EntityNotFoundException("User not found: " + id));
    }
}

// Контроллер
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    @GetMapping("/{id}")
    public UserResponse getUser(@PathVariable Long id) {
        User user = userService.findById(id);
        return new UserResponse(
            user.getId(),
            user.getFirstName(),
            user.getLastName(),
            user.getEmail()
        );
    }
}&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&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Вложенные Record-классы&amp;nbsp;хорошо работают для составных ответов:&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
public record AddressResponse(
    String street,
    String city,
    String country
) {}

public record UserDetailResponse(
    Long id,
    String firstName,
    String lastName,
    String email,
    AddressResponse address,        // вложенный record
    List&amp;lt;String&amp;gt; roles              // коллекции тоже поддерживаются
) {}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Кастомная сериализация&amp;nbsp;настраивается через стандартные Jackson-аннотации:&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
public record UserResponse(
    Long id,
    String firstName,
    String lastName,
    String email,

    @JsonFormat(pattern = "dd.MM.yyyy")
    LocalDate birthDate,

    @JsonProperty("isVerified")
    boolean verified
) {}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Почему опытные разработчики это ценят: &lt;/strong&gt;Record-классы самодокументируемы — любой член команды, открыв файл, немедленно видит полный контракт эндпоинта. Не нужно читать маппер, искать аннотации `@JsonIgnore` или гадать, какие поля попадут в ответ.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Паттерн 2: MapStruct для конвертации без шаблонного кода&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;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Ручное маппирование — серьёзная проблема при масштабировании. Когда у вас десять сущностей, каждая с двадцатью полями, написание маппинга вручную превращается в рутину, которая к тому же молча ломается. Добавили новое обязательное поле в `UserResponse`, но забыли обновить маппер? Компилятор промолчит, тесты не поймают — и вы получите `null` в production.&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;MapStruct генерирует код конвертации на этапе компиляции через annotation processing. Вы объявляете только интерфейс — всё остальное делает библиотека.&lt;/p&gt;

&lt;pre class="brush:xml;"&gt;
&amp;lt;!-- pom.xml --&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.mapstruct&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;mapstruct&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.5.5.Final&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.mapstruct&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;mapstruct-processor&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.5.5.Final&amp;lt;/version&amp;gt;
    &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;&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;pre class="brush:java;"&gt;
// Базовый маппер
@Mapper(componentModel = "spring")
public interface UserMapper {

    // Простое маппирование: поля с одинаковыми именами — автоматически
    UserResponse toResponse(User user);

    // Маппирование коллекций — бесплатно
    List&amp;lt;UserResponse&amp;gt; toResponseList(List&amp;lt;User&amp;gt; users);

    // Кастомное маппирование полей с разными именами
    @Mapping(source = "passwordHash", target = "hasPassword",
             qualifiedByName = "passwordToBoolean")
    UserAdminResponse toAdminResponse(User user);

    @Named("passwordToBoolean")
    default boolean mapPassword(String passwordHash) {
        return passwordHash != null &amp;amp;&amp;amp; !passwordHash.isEmpty();
    }

    // Игнорирование поля в целевом объекте
    @Mapping(target = "sensitiveData", ignore = true)
    UserPublicResponse toPublicResponse(User user);

    // Вычисляемые поля
    @Mapping(target = "fullName",
             expression = "java(user.getFirstName() + \" \" + user.getLastName())")
    UserSummaryResponse toSummaryResponse(User user);
}&lt;/pre&gt;

&lt;pre class="brush:java;"&gt;
// Использование в контроллере
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;
    private final UserMapper userMapper;

    @GetMapping("/{id}")
    public UserResponse getUser(@PathVariable Long id) {
        return userMapper.toResponse(userService.findById(id));
    }

    @GetMapping
    public List&amp;lt;UserResponse&amp;gt; getAllUsers() {
        return userMapper.toResponseList(userService.findAll());
    }
}&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&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Что происходит при несовпадении полей:&amp;nbsp;MapStruct по умолчанию выдаёт предупреждение компилятора, если у целевого объекта есть поле, которое не замаппировано. Это можно настроить:&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
// Превратить предупреждение в ошибку компиляции — рекомендуется для production
@Mapper(
    componentModel = "spring",
    unmappedTargetPolicy = ReportingPolicy.ERROR  // жёсткий режим
)
public interface UserMapper { ... }&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Маппинг между вложенными объектами&amp;nbsp;работает автоматически, если зарегистрировать вспомогательные маппинги:&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
@Mapper(componentModel = "spring", uses = {AddressMapper.class})
public interface UserMapper {
    // Address внутри User будет смаппирован через AddressMapper автоматически
    UserDetailResponse toDetailResponse(User user);
}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Почему опытные разработчики это ценят:&amp;nbsp;&lt;/strong&gt;&amp;nbsp;MapStruct — это отраслевой стандарт в крупных компаниях. Один интерфейс заменяет десятки строк ручного маппинга, при этом ошибки обнаруживаются на этапе компиляции, а не в production в три часа ночи.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Паттерн 3: Проекции Spring Data для эндпоинтов чтения&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;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Типичный сценарий: страница со списком пользователей отображает только имя и email. Но ваш репозиторий загружает из базы данных всю сущность — включая `bio`, `avatarUrl`, `preferences`, `notificationSettings` и ещё пятнадцать полей, которые на этой странице просто не нужны. Это избыточный SELECT, лишний трафик и бесполезная нагрузка на сериализатор.&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;Spring Data поддерживает проекции — интерфейсы, которые указывают репозиторию: «загрузи только эти поля». На уровне SQL это выражается в `SELECT id, first_name, email FROM users` вместо `SELECT * FROM users`.&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;pre class="brush:java;"&gt;
// Объявление проекции — просто интерфейс
public interface UserSummary {
    Long getId();
    String getFirstName();
    String getEmail();
}

// Проекция для вложенных объектов
public interface UserWithAddress {
    Long getId();
    String getEmail();
    AddressSummary getAddress();  // вложенная проекция

    interface AddressSummary {
        String getCity();
        String getCountry();
    }
}&lt;/pre&gt;

&lt;pre class="brush:java;"&gt;
// Репозиторий
public interface UserRepository extends JpaRepository&amp;lt;User, Long&amp;gt; {

    // Возвращает только нужные поля
    List&amp;lt;UserSummary&amp;gt; findAllBy();

    // С фильтрацией
    List&amp;lt;UserSummary&amp;gt; findByActiveTrue();

    // Динамическая проекция — тип выбирается вызывающим кодом
    &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt; findByDepartmentId(Long departmentId, Class&amp;lt;T&amp;gt; type);
}&lt;/pre&gt;

&lt;pre class="brush:java;"&gt;
// Контроллер
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {

    private final UserRepository userRepository;

    @GetMapping
    public List&amp;lt;UserSummary&amp;gt; getUsers() {
        return userRepository.findAllBy();
        // SQL: SELECT u.id, u.first_name, u.email FROM users u
    }

    @GetMapping("/list")
    public List&amp;lt;UserListItem&amp;gt; getUserList() {
        // Динамическая проекция
        return userRepository.findByDepartmentId(1L, UserListItem.class);
    }
}&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&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Существуют два типа проекций, и важно понимать разницу:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Closed projection&lt;/strong&gt;&amp;nbsp;— интерфейс, где геттеры точно соответствуют полям сущности. Hibernate оптимизирует SQL: `SELECT id, first_name, email FROM users`. Это обеспечивает максимальную производительность.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open projection&lt;/strong&gt;&amp;nbsp;— интерфейс с аннотацией `@Value` и SpEL-выражениями. Hibernate вынужден загружать всю сущность в память, а потом вычислять поле. Производительность хуже, но гибкость выше.&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
// Closed — оптимальный SQL
public interface UserSummary {
    Long getId();
    String getEmail(); // точное соответствие полям сущности
}

// Open — полная загрузка сущности, потом вычисление

// Расширенная проекция с вычисляемым полем через SpEL
public interface UserSummaryOpen {
    Long getId();
    String getEmail();
    String getFirstName();
    String getLastName();

    // Вычисляемое поле — склеивается на уровне Java, не SQL
    @Value("#{target.firstName + ' ' + target.lastName}")
    String getFullName(); // Hibernate загружает ВСЕ поля
}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Почему опытные разработчики это ценят:&lt;/strong&gt;&amp;nbsp;Проекции — это одновременно паттерн безопасности и инструмент оптимизации. Одно объявление интерфейса устраняет и DTO-класс, и лишний трафик к базе данных.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Паттерн 4: Конвертные ответы для единообразных контрактов API&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;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Клиент вашего API делает десять запросов к десяти разным эндпоинтам. У каждого своя структура: один возвращает объект напрямую, другой оборачивает в `{ "data": ... }`, третий при ошибке отдаёт строку, четвёртый — объект с полем `error`. Frontend-разработчики пишут десять разных обработчиков. Новые члены команды не знают, что ожидать. Интеграция с партнёрами превращается в квест по документации.&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;Единый конверт ответа (Envelope Pattern) — универсальная обёртка, которая делает каждый эндпоинт предсказуемым.&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
//  Универсальный конверт ответа
public record ApiResponse&amp;lt;T&amp;gt;(
    boolean success,
    String message,
    T data,
    List&amp;lt;String&amp;gt; errors,
    Map&amp;lt;String, Object&amp;gt; meta
) {
    // Успешный ответ с данными
    public static &amp;lt;T&amp;gt; ApiResponse&amp;lt;T&amp;gt; ok(T data) {
        return new ApiResponse&amp;lt;&amp;gt;(true, "OK", data, null, null);
    }

    // Успешный ответ с данными и пагинацией
    public static &amp;lt;T&amp;gt; ApiResponse&amp;lt;T&amp;gt; ok(T data, Map&amp;lt;String, Object&amp;gt; meta) {
        return new ApiResponse&amp;lt;&amp;gt;(true, "OK", data, null, meta);
    }

    // Ответ об ошибке
    public static &amp;lt;T&amp;gt; ApiResponse&amp;lt;T&amp;gt; error(String message) {
        return new ApiResponse&amp;lt;&amp;gt;(false, message, null, null, null);
    }

    // Ответ с несколькими ошибками (например, ошибки валидации)
    public static &amp;lt;T&amp;gt; ApiResponse&amp;lt;T&amp;gt; validationError(List&amp;lt;String&amp;gt; errors) {
        return new ApiResponse&amp;lt;&amp;gt;(false, "Validation failed", null, errors, null);
    }
}&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;pre class="brush:java;"&gt;
// Контроллер
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;
    private final UserMapper userMapper;

    // Обычный запрос
    @GetMapping("/{id}")
    public ResponseEntity&amp;lt;ApiResponse&amp;lt;UserResponse&amp;gt;&amp;gt; getUser(@PathVariable Long id) {
        UserResponse user = userMapper.toResponse(userService.findById(id));
        return ResponseEntity.ok(ApiResponse.ok(user));
    }

    // Запрос с пагинацией — мета-информация передаётся в конверте
    @GetMapping
    public ResponseEntity&amp;lt;ApiResponse&amp;lt;List&amp;lt;UserResponse&amp;gt;&amp;gt;&amp;gt; getUsers(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size) {

        Page&amp;lt;User&amp;gt; usersPage = userService.findAll(PageRequest.of(page, size));

        Map&amp;lt;String, Object&amp;gt; meta = Map.of(
            "page", usersPage.getNumber(),
            "size", usersPage.getSize(),
            "totalElements", usersPage.getTotalElements(),
            "totalPages", usersPage.getTotalPages(),
            "last", usersPage.isLast()
        );

        return ResponseEntity.ok(
            ApiResponse.ok(userMapper.toResponseList(usersPage.getContent()), meta)
        );
    }
}&lt;/pre&gt;

&lt;pre class="brush:java;"&gt;
// Глобальный обработчик ошибок — ключевая часть паттерна
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(EntityNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ApiResponse&amp;lt;Void&amp;gt; handleNotFound(EntityNotFoundException ex) {
        return ApiResponse.error(ex.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse&amp;lt;Void&amp;gt; handleValidation(MethodArgumentNotValidException ex) {
        List&amp;lt;String&amp;gt; errors = ex.getBindingResult()
            .getFieldErrors()
            .stream()
            .map(fe -&amp;gt; fe.getField() + ": " + fe.getDefaultMessage())
            .collect(Collectors.toList());
        return ApiResponse.validationError(errors);
    }

    @ExceptionHandler(AccessDeniedException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public ApiResponse&amp;lt;Void&amp;gt; handleAccessDenied(AccessDeniedException ex) {
        return ApiResponse.error("Access denied");
    }
}&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;
// Успех
{
  "success": true,
  "message": "OK",
  "data": { "id": 1, "firstName": "Иван", "email": "ivan@example.com" },
  "errors": null,
  "meta": null
}

// Ошибка валидации
{
  "success": false,
  "message": "Validation failed",
  "data": null,
  "errors": ["email: must be a valid email", "firstName: must not be blank"],
  "meta": null
}

// Пагинация
{
  "success": true,
  "message": "OK",
  "data": [...],
  "errors": null,
  "meta": { "page": 0, "size": 20, "totalElements": 150, "totalPages": 8 }
}&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&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Некоторые команды выбирают более лёгкий вариант без `success`/`errors` и просто полагаются на HTTP-статусы. Это тоже валидный подход. Главное — &lt;strong&gt;единообразие&lt;/strong&gt;: выбранный формат должен применяться ко всем эндпоинтам без исключений.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Почему опытные разработчики это ценят:&lt;/strong&gt;&amp;nbsp;Единообразие API — признак зрелой кодовой базы. Это разница между API, с которым внешние команды работают с удовольствием, и тем, интеграции с которым боятся.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Паттерн 5: @JsonView для ролевого формирования ответов&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;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Бизнес-требование: публичные пользователи должны видеть имя и email; менеджеры - также дату рождения и телефон; администраторы должны видеть&amp;nbsp;всё, включая внутренние заметки и историю входов. Самое простое&amp;nbsp;решение — создать три отдельных DTO: `UserPublicResponse`, `UserManagerResponse`, `UserAdminResponse`. Однако, при десяти ролях и двадцати сущностях это превращается в сотни DTO-классов, которые нужно синхронизировать при каждом изменении.&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;Jackson `@JsonView` позволяет управлять видимостью полей на уровне сериализации: одна сущность, несколько представлений, ноль дублирующихся классов.&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;pre class="brush:java;"&gt;
// Определение иерархии представлений
public class UserViews {
    // Иерархия через наследование:
    // Admin видит всё, что видит Manager,
    // Manager видит всё, что видит Public
    public interface Public {}
    public interface Manager extends Public {}
    public interface Admin extends Manager {}
}&lt;/pre&gt;

&lt;pre class="brush:java;"&gt;
// Сущность с разметкой полей
@Entity
@Table(name = "users")
public class User {

    @Id
    @JsonView(UserViews.Public.class)
    private Long id;

    @JsonView(UserViews.Public.class)
    private String firstName;

    @JsonView(UserViews.Public.class)
    private String lastName;

    @JsonView(UserViews.Public.class)
    private String email;

    // Видно менеджерам и выше
    @JsonView(UserViews.Manager.class)
    private String phone;

    @JsonView(UserViews.Manager.class)
    private LocalDate birthDate;

    @JsonView(UserViews.Manager.class)
    private String department;

    // Только для администраторов
    @JsonView(UserViews.Admin.class)
    private String internalNotes;

    @JsonView(UserViews.Admin.class)
    private LocalDateTime lastLoginAt;

    @JsonView(UserViews.Admin.class)
    private String lastLoginIp;

    @JsonView(UserViews.Admin.class)
    private boolean accountLocked;

    // Поля без @JsonView не попадают ни в один ответ
    private String passwordHash;
    private String resetToken;
}&lt;/pre&gt;

&lt;pre class="brush:java;"&gt;
// Контроллер с тремя представлениями
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    // Публичный профиль — для всех
    @GetMapping("/{id}/profile")
    @JsonView(UserViews.Public.class)
    public User getPublicProfile(@PathVariable Long id) {
        return userService.findById(id);
        // Ответ: id, firstName, lastName, email
    }

    // Расширенный профиль — для менеджеров
    @GetMapping("/{id}/details")
    @JsonView(UserViews.Manager.class)
    @PreAuthorize("hasAnyRole('MANAGER', 'ADMIN')")
    public User getUserDetails(@PathVariable Long id) {
        return userService.findById(id);
        // Ответ: id, firstName, lastName, email, phone, birthDate, department
    }

    // Полный профиль — только для администраторов
    @GetMapping("/admin/{id}")
    @JsonView(UserViews.Admin.class)
    @PreAuthorize("hasRole('ADMIN')")
    public User getAdminProfile(@PathVariable Long id) {
        return userService.findById(id);
        // Ответ: все поля, размеченные @JsonView(Admin.class) и выше
    }
}&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&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Тестирование ролевой видимости&lt;/strong&gt;&amp;nbsp;— важная часть работы с `@JsonView`:&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
@Test
void publicProfileShouldNotExposePhone() throws Exception {
    mockMvc.perform(get("/api/v1/users/1/profile"))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.phone").doesNotExist())
        .andExpect(jsonPath("$.internalNotes").doesNotExist())
        .andExpect(jsonPath("$.email").exists());
}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Программное переключение представления&lt;/strong&gt;&amp;nbsp;— когда роль определяется динамически:&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
@GetMapping("/{id}")
public ResponseEntity&amp;lt;String&amp;gt; getUser(@PathVariable Long id) throws JsonProcessingException {
    User user = userService.findById(id);

    Class&amp;lt;?&amp;gt; view = SecurityUtils.isAdmin()
        ? UserViews.Admin.class
        : UserViews.Public.class;

    ObjectWriter writer = objectMapper.writerWithView(view);
    return ResponseEntity.ok(writer.writeValueAsString(user));
}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ограничение паттерна:&amp;nbsp;&lt;/strong&gt;`@JsonView` применяется только к сериализации. Если вы возвращаете саму сущность, вы всё равно загружаете из базы все поля. Для оптимизации запросов к БД этот паттерн нужно комбинировать с проекциями (паттерн 3).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Почему опытные разработчики это ценят:&lt;/strong&gt;&amp;nbsp;Ролевое управление видимостью полей — требование безопасности в большинстве production-систем. `@JsonView` реализует его на уровне сериализации — самом надёжном месте, где невозможно случайно «забыть» применить фильтрацию.&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;blockquote&gt;
&lt;p&gt;| Паттерн | Лучше всего для | Компромисс |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Record-классы&amp;nbsp;&lt;/strong&gt;| Любые DTO, быстрый старт | Ручное маппирование при простых случаях |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;MapStruct&lt;/strong&gt;&amp;nbsp;| Большие проекты, много сущностей | Требует настройки зависимости |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Проекции&lt;/strong&gt;&amp;nbsp;| Эндпоинты списков и чтения | Ограниченная гибкость при сложных вычислениях |&lt;/p&gt;

&lt;p&gt;|&lt;strong&gt; Envelope&lt;/strong&gt;&amp;nbsp;| Публичные API, интеграции с партнёрами | Небольшой оверхед структуры ответа |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;@JsonView&lt;/strong&gt;&amp;nbsp;| Ролевой доступ к полям | Не оптимизирует запрос к БД |&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;На практике паттерны комбинируются. Зрелый проект обычно использует их все одновременно:&lt;/p&gt;

&lt;pre class="brush:java;"&gt;
// Все паттерны вместе
@GetMapping("/{id}")
@JsonView(UserViews.Public.class)           // Паттерн 5: ролевая фильтрация
public ApiResponse&amp;lt;UserResponse&amp;gt; getUser(@PathVariable Long id) {
    return ApiResponse.ok(                  // Паттерн 4: конверт ответа
        userMapper.toResponse(              // Паттерн 2: MapStruct
            userService.findById(id)
        )
    );
    // UserResponse — это Record (Паттерн 1)
}&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;h2&gt;Заключение&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Возврат сырых сущностей из REST API — это не просто технический долг. Это ошибка проектирования с реальными последствиями: утечки данных в production, сломанные клиенты после рефакторинга схемы, бесконечные вопросы от frontend-команды «а что именно возвращает этот эндпоинт?».&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Каждый из пяти паттернов решает конкретную задачу:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Record-классы&amp;nbsp;— явный, самодокументируемый контракт ответа без шаблонного кода.&lt;/li&gt;
	&lt;li&gt;&amp;nbsp;MapStruct&amp;nbsp;— безопасное маппирование на этапе компиляции вместо молчаливых ошибок в runtime.&lt;/li&gt;
	&lt;li&gt;Проекции&amp;nbsp;— производительность и безопасность на уровне SQL-запроса.&lt;/li&gt;
	&lt;li&gt;Envelope-обёртки&amp;nbsp;— единообразие, которое внешние команды перестают замечать, потому что «оно просто работает».&lt;/li&gt;
	&lt;li&gt;@JsonView&amp;nbsp;— ролевое управление видимостью без взрыва DTO-классов.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Начать можно с малого. Если сегодня ваши контроллеры возвращают сырые сущности — введите Record-классы. Это займёт немного времени&amp;nbsp;и сразу закроет риск утечки полей. Затем добавьте MapStruct. Envelope-паттерн введите перед первой внешней интеграцией. Проекции — когда появятся жалобы на производительность списков. `@JsonView` — как только появятся разные роли пользователей.&lt;/p&gt;</summary>
    <dc:creator>Romo Fedoroff</dc:creator>
    <dc:date>2026-04-01T09:28:00Z</dc:date>
  </entry>
  <entry>
    <title>Поломалась оснастка порты управляемых сетей в zVirt</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21235647" />
    <author>
      <name>Andrei Maksimov</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21235647</id>
    <updated>2026-03-30T11:39:55Z</updated>
    <published>2026-03-30T10:48:00Z</published>
    <summary type="html">&lt;p&gt;В какой то момент в zVirt поломалась возможность импортировать виртуальные машины из образов в формате OVA размещённых на дисках хоста с гипервизором. Но о том как это чинить, как-нибудь в другой раз, а может и в очередном обновлении починится.&lt;br /&gt;
Дело в том, неудачные попытки импорта имеют неприятные последствия. В интерфейсе настройки Управляемых сетей на вкладке Порты нас встречает сообщение вида.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;«Порт с идентификатором c7808f18-b5ab-4045-a230-c4ce59a86139 не найден»&lt;br /&gt;
​​​​​​​&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;И это все, что&amp;nbsp; мы можем наблюдать на этой вкладке, соответственно&amp;nbsp; управлять портами из веб-интерфейса становиться не возможно.&amp;nbsp;&lt;br /&gt;
Как показало небольшое исследование, данная проблема возникает&amp;nbsp; вследствие неудачного импорта. Во время импорта создаётся новая ВМ , для неё создаётся порт в&amp;nbsp; соответствующей логической сети SDN. Но после краха процедуры импорта, виртуальная машина из конфигурации zvirt удаляется, а вот в базе данных программно определяемых сетей zvirt остаётся, что и вызывает вышеуказанное сообщение.&lt;br /&gt;
Чтобы исправить ситуацию сначала нужно найти какому порту соответствует указанный в ошибке идентификатор. Все парамеры портов хранятся в базе данных OVN , которую можно посмотреть на менеджере виртуализации.&lt;br /&gt;
Искомый идентификатор задаётся в параметре&amp;nbsp; &amp;nbsp;ovirt_device_id в поле external_ids в свойствах порта. Для поиска нужного порта можно использовать команду&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ovn-nbctl find logical_switch_port external_ids:ovirt_device_id=&amp;lt;ИД из ошибки&amp;gt;&lt;/em&gt;&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
ovn-nbctl find logical_switch_port external_ids:ovirt_device_id=&lt;strong&gt;c7808f18-b5ab-4045-a230-c4ce59a86139&lt;/strong&gt; 
_uuid               : e7ff4956-2151-4190-aee4-4d5681691050
 addresses           : ["56:6f:7e:2b:00:a2"]
 dhcpv4_options      : []
 dhcpv6_options      : []
 dynamic_addresses   : []
 enabled             : true external_ids        : {ovirt_device_id="c7808f18-b5ab-4045-a230-c4ce59a86139", ovirt_device_owner=oVirt, ovirt_nic_name=nic1, ovirt_security_groups="", zvirt_mode=dynamic, zvirt_namespace=common}
 ha_chassis_group    : []
 mirror_rules        : []
 &lt;strong&gt;name&lt;/strong&gt;                : "&lt;strong&gt;c9afb0db-de90-4a42-a26c-88e69eb4c183&lt;/strong&gt;"
 options             : {}
 parent_name         : []
 port_security       : []
 tag                 : [] 
tag_request         : [] 
type                : ""
 up                  : false&lt;/pre&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;В поле&amp;nbsp; name&amp;nbsp; указано имя порта.&lt;br /&gt;
На всякий случай можно проверить в базе данных менеджера нет ли ВМ использующей этот порт, по имени порта или MAC адресу.&amp;nbsp; Я просто поискал в дампе базы данных извлечённой из резервной копии (о том как делать резервные копии мы подробно рассказываем &lt;a id="backup" name="backup"&gt;&lt;/a&gt;&lt;a href="https://www.tune-it.ru/education/catalogue/-/catalogue/vendors/%D0%9E%D1%80%D0%B8%D0%BE%D0%BD/zVirt/zvirt-base" target="_blank"&gt;тут&lt;/a&gt;) и увидел такую запись&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
grep  05ef7f198d82   out_engine 21703    00000000-0000-0000-0000-000000000000    SYSTEM    \N        \N        \N        2026-03-25 11:24:02.987+03    SDN_PORT_CREATE_SUCCESS    16301    0    Port nic1 (9223a5aa-8394-4caf-9a33-05ef7f198d82) for VM DC602-location1 created successfully    f    \N        \N        \N        \N    \N    \N        \N        oVirt    \N    \N    \N    f    \N    \N    \N    \N&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
Что усилило мои подозрения.&lt;br /&gt;
Теперь фантомный порт необходимо удалить из базы данных OVN. Перед удаление настоятельно рекомендуется выполнить&amp;nbsp; &lt;a href="http://www.tune-it.ru/education/catalogue/-/catalogue/vendors/%D0%9E%D1%80%D0%B8%D0%BE%D0%BD/zVirt/zvirt-base" target="_blank"&gt;резервное копирование&lt;/a&gt; конфигурации менеджера.&lt;br /&gt;
Удаление выполняется с помощью команды &lt;em&gt;ovn-nbctl lsp-del &amp;lt;имя порта &amp;gt;&lt;/em&gt;&lt;br /&gt;
​​​​​​​&lt;/p&gt;

&lt;pre class="brush:bash;"&gt;
ovn-nbctl lsp-del c9afb0db-de90-4a42-a26c-88e69eb4c183&lt;/pre&gt;

&lt;p&gt;Возможно&amp;nbsp; создалось несколько фантомных портов , эту процедуру нужно повторить для каждого.&amp;nbsp;&lt;/p&gt;</summary>
    <dc:creator>Andrei Maksimov</dc:creator>
    <dc:date>2026-03-30T10:48:00Z</dc:date>
  </entry>
  <entry>
    <title>Невидимые пользователи: Проектируем цифровую среду, доступную каждому</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21227823" />
    <author>
      <name>Алексей Кондратьев</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21227823</id>
    <updated>2026-03-09T16:28:05Z</updated>
    <published>2026-03-09T14:51:00Z</published>
    <summary type="html">&lt;p&gt;Вы когда-нибудь пробовали пользоваться любимым сайтом с закрытыми глазами? Или только одной рукой? А может быть с громко играющей музыкой в наушниках, которая мешает сосредоточиться на интерфейсе? В такие моменты каждый из нас хотя бы отчасти приближается к пониманию того, что испытывают люди с инвалидностью ежедневно.&lt;br /&gt;
&lt;br /&gt;
Доступность (Accessibility, часто сокращаемая как A11y — где 11 означает количество букв между 'A' и 'y') — это не просто моральный долг или соответствие юридическим нормам. Это фундаментальное качество продукта, определяющее, сможет ли им воспользоваться каждый пятый житель планеты.&lt;br /&gt;
&lt;br /&gt;
В данной статье мы рассмотрим международный стандарт WCAG 2.2, научимся проектировать для разных групп пользователей и разберем практические инструменты тестирования, включая работу со скрин-ридерами.&lt;/p&gt;

&lt;h3 dir="ltr"&gt;&lt;b id="docs-internal-guid-34be1f07-7fff-d9e6-ed8c-a5fcde1c8547"&gt;Часть 1: WCAG 2.2 — Навигационная карта доступности&lt;/b&gt;&lt;/h3&gt;

&lt;p dir="ltr"&gt;Web Content Accessibility Guidelines (WCAG) — это «золотой стандарт» доступности, разработанный Консорциумом Всемирной паутины (W3C). В октябре 2023 года была утверждена новая редакция — WCAG 2.2, которая пришла на смену версии 2.1.&lt;/p&gt;

&lt;p dir="ltr"&gt;&lt;strong&gt;1.1. Четыре принципа POUR&lt;/strong&gt;&lt;/p&gt;

&lt;p dir="ltr"&gt;В основе WCAG лежат четыре фундаментальных принципа, известных по аббревиатуре POUR. Контент должен быть:&lt;/p&gt;

&lt;ol dir="ltr"&gt;
	&lt;li&gt;Воспринимаемым (Perceivable): Пользователи должны иметь возможность воспринимать информацию, даже если у них есть сенсорные ограничения. Информация не может быть невидимой для всех органов чувств сразу .&lt;/li&gt;
	&lt;li&gt;Управляемым (Operable): Интерфейс должен работать с разными устройствами ввода. Пользователь должен иметь возможность управлять интерфейсом (например, нажимать кнопки), даже если не может использовать мышь .&lt;/li&gt;
	&lt;li&gt;Понятным (Understandable): И информация, и управление интерфейсом должны быть ясными. Пользователь должен понимать, где он находится и что происходит на странице.&lt;/li&gt;
	&lt;li&gt;Надёжным (Robust): Контент должен быть совместим с различными пользовательскими агентами, включая ассистивные технологии (скрин-ридеры, брайлевские дисплеи) .&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-3a068bcf-7fff-023c-d976-56f4caa94f04"&gt;1.2. Что нового в WCAG 2.2?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Главное изменение в версии 2.2 — фокус на пользователей с ограниченной моторикой и когнитивными нарушениями . Добавлено 9 новых критериев, а один устаревший исключен . Вот ключевые нововведения, на которые стоит обратить внимание:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Фокус не должен исчезать (Focus Appearance — уровень AA): Визуальный индикатор фокуса клавиатуры (обычно контур вокруг элемента) должен иметь достаточный контраст и размер, чтобы его было легко заметить.&lt;/li&gt;
	&lt;li&gt;Перетаскивание (Dragging — уровень AA): Действия, требующие перетаскивания объектов (drag &amp;amp; drop), должны иметь альтернативный простой способ выполнения (например, нажатие кнопок), так как многие пользователи с моторными нарушениями не могут удерживать кнопку мыши при перемещении.&lt;/li&gt;
	&lt;li&gt;Целевой размер (Target Size — уровень AA): Для интерактивных элементов (кнопок, ссылок) рекомендуется минимальный размер 24x24 пикселя, чтобы по ним было легко попасть людям с тремором рук или при использовании мобильных устройств. Исключения делается для ссылок внутри текстового абзаца.&lt;/li&gt;
	&lt;li&gt;Аутентификация (Accessible Authentication — уровень AA): Процессы входа в систему не должны требовать решения задач, основанных на запоминании пароля или распознавании объектов (капча), если для этого нет альтернативы. Это критически важно для людей с когнитивными нарушениями.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Понимание WCAG 2.2 становится обязательным не только для госсектора. С 28 июня 2025 года Европейский акт о доступности (EAA) распространяет требования уровня AA на частный бизнес в ЕС: интернет-магазины, банки, телеком-операторов и многих других .&lt;/p&gt;

&lt;h3 dir="ltr"&gt;&lt;b id="docs-internal-guid-c33297bd-7fff-0449-86ed-e663fe5dbb7c"&gt;Часть 2: Дизайн для всех — учет особенностей пользователей&lt;/b&gt;&lt;/h3&gt;

&lt;p dir="ltr"&gt;Универсальный дизайн начинается с эмпатии. Рассмотрим, как потребности разных групп пользователей влияют на наши решения.&lt;/p&gt;

&lt;h4 dir="ltr"&gt;&lt;b id="docs-internal-guid-79ce8847-7fff-5059-b2dd-9c449290f8dc"&gt;2.1. Нарушения зрения (от слепоты до дальтонизма)&lt;/b&gt;&lt;/h4&gt;

&lt;p dir="ltr"&gt;Это самая очевидная аудитория для применения стандартов доступности. По данным ВОЗ, более 2,2 млрд человек имеют те или иные нарушения зрения.&lt;/p&gt;

&lt;p dir="ltr"&gt;Практические советы:&lt;/p&gt;

&lt;ul dir="ltr"&gt;
	&lt;li&gt;Контрастность: Обеспечьте достаточный контраст между текстом и фоном. Для обычного текста на уровне AA требуется контраст 4.5:1, для крупного текста — 3:1 . Используйте инструменты проверки контраста (Color Contrast Analyser, WebAIM).&lt;/li&gt;
	&lt;li&gt;Визуальные сигналы: Не используйте цвет как единственный сигнал, дающий информацию о состоянии объекта. Статус системы должен быть визуально понятным даже в черно-белом исполнении. Простыми словами, дублируйте сигнал иконками, текстом или подчеркиванием .&lt;/li&gt;
	&lt;li&gt;Текстовые альтернативы: Все значимые изображения должны иметь атрибут alt с описанием содержания. Декоративные изображения должны быть скрыты от скрин-ридеров (пустой alt="") , .&lt;/li&gt;
	&lt;li&gt;Масштабируемость: Интерфейс должен корректно отображаться при увеличении экрана до 400% без потери функциональности.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-5bbc3894-7fff-2c36-bd3b-0e4fc709102c"&gt;2.2. Нарушения моторики&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Сюда входят люди с параличом, тремором рук, артритом, а также те, у кого временно сломана рука. Они часто используют клавиатуру, трекбол или специальные устройства (стикеры для рта).&lt;/p&gt;

&lt;p&gt;Что делать дизайнеру:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Управление с клавиатуры: Все функции, доступные мышью, должны быть доступны с клавиатуры. Это означает логичный порядок фокуса (обычно совпадающий с визуальным порядком на странице) и видимый индикатор фокуса .&lt;/li&gt;
	&lt;li&gt;Крупные кликабельные области: Как требует WCAG 2.2, кнопки и ссылки должны быть большими, чтобы в них было легко попасть .&lt;/li&gt;
	&lt;li&gt;Достаточно времени: Избегайте таймеров или давайте возможность их продлить/отключить. Людям с моторными нарушениями может потребоваться больше времени на заполнение формы.&lt;/li&gt;
	&lt;li&gt;Отказ от сложных жестов: Предоставляйте простую альтернативу сложным жестам (смахивание, мультитач).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-ce9e407f-7fff-ce7a-db8f-f0d010d4c8ab"&gt;2.3. Когнитивные особенности&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Это одна из самых сложных и разнообразных групп. Она включает людей с нарушениями обучаемости (дислексия), памяти, внимания, а также пожилых людей.&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;Четкая структура: Используйте заголовки, списки и иконки для визуального разделения информации . Пользователю должно быть легко сканировать страницу взглядом.&lt;/li&gt;
	&lt;li&gt;Упрощенная аутентификация: Дайте возможность войти по биометрии или с помощью ссылки на email вместо запоминания сложного пароля.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 dir="ltr"&gt;&lt;b id="docs-internal-guid-26556fa8-7fff-d258-19a4-58b673590ef3"&gt;Часть 3: Техническая реализация и семантическая верстка&lt;/b&gt;&lt;/h3&gt;

&lt;p dir="ltr"&gt;Красивый дизайн бесполезен, если он не может быть корректно передан ассистивным технологиям. Здесь на сцену выходит семантический HTML.&lt;/p&gt;

&lt;p dir="ltr"&gt;&lt;b id="docs-internal-guid-9bbba552-7fff-89e6-70bf-20c261e47162"&gt;3.1. Почему семантика — это основа?&lt;/b&gt;&lt;/p&gt;

&lt;p dir="ltr"&gt;Семантическая верстка — это использование HTML-элементов строго по их назначению. Это язык, на котором сайт общается с браузером, поисковиками и, что важнее всего, со скрин-ридерами.&lt;/p&gt;

&lt;p dir="ltr"&gt;Например, можно сделать "кнопку" так:&lt;/p&gt;

&lt;pre class="brush:jscript;"&gt;
&lt;code&gt;&amp;lt;div class="btn" role="button" tabindex="0"&amp;gt;Купить&amp;lt;/div&amp;gt;&lt;/code&gt;
&lt;/pre&gt;

&lt;p&gt;Но гораздо правильнее и проще так:&lt;/p&gt;

&lt;pre class="brush:jscript;"&gt;
&lt;code&gt;&amp;lt;button&amp;gt;Купить&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Элемент &amp;lt;button&amp;gt;&amp;nbsp;«из коробки» имеет правильную роль, управление с клавиатуры (Tab, Enter/Пробел) и фокус .&lt;/p&gt;

&lt;p&gt;Ключевые семантические теги:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&amp;lt;header&amp;gt;, &amp;lt;nav&amp;gt;, &amp;lt;main&amp;gt;, &amp;lt;footer&amp;gt;, &amp;lt;aside&amp;gt; — создают навигационные вехи (landmarks), по которым пользователи скрин-ридеров могут быстро перемещаться.&lt;/li&gt;
	&lt;li&gt;&amp;lt;h1&amp;gt; — &amp;lt;h6&amp;gt; — создают иерархию заголовков. Никогда не пропускайте уровни (не перескакивайте с &amp;lt;h2&amp;gt; на &amp;lt;h4&amp;gt;). &amp;lt;h1&amp;gt; должен быть на странице один.&lt;/li&gt;
	&lt;li&gt;&amp;lt;ul&amp;gt;, &amp;lt;ol&amp;gt;, &amp;lt;li&amp;gt; — для списков.&lt;/li&gt;
	&lt;li&gt;&amp;lt;table&amp;gt; с &amp;lt;th&amp;gt; — для таблиц с данными (указывайте заголовки столбцов/строк).&lt;/li&gt;
	&lt;li&gt;&amp;lt;a&amp;gt; — для ссылок. Текст ссылки должен быть понятен вне контекста (никогда не пишите "нажмите здесь") .&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-45ff3bb0-7fff-831c-dd07-51db34868674"&gt;3.2. Доступные формы&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Формы — частый источник проблем. Чтобы сделать их доступными:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Каждый &amp;lt;input&amp;gt;, &amp;lt;select&amp;gt; или &amp;lt;textarea&amp;gt; должен быть связан с подписью через связку id и &amp;lt;label for="id"&amp;gt; или быть вложенным в &amp;lt;label&amp;gt;.&lt;/li&gt;
	&lt;li&gt;Группируйте логически связанные поля (например, адрес) в &amp;lt;fieldset&amp;gt; и давайте группе имя через &amp;lt;legend&amp;gt;.&lt;/li&gt;
	&lt;li&gt;Четко обозначайте обязательные поля и формат ввода данных в подписях, а не только цветом.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-764a96ab-7fff-fecf-5816-e0cbd63bae44"&gt;3.3. Когда HTML не справляется: WAI-ARIA&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Иногда мы создаем сложные интерфейсные компоненты (например, кастомный выпадающий список с автодополнением), для которых нет подходящего HTML-тега. В таких случаях на помощь приходит WAI-ARIA (Accessible Rich Internet Applications).&lt;/p&gt;

&lt;p&gt;ARIA позволяет добавить к элементам атрибуты, которые сообщают скрин-ридеру дополнительную информацию:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Роль (role): Что это за элемент? (role="dialog", role="tablist", role="progressbar").&lt;/li&gt;
	&lt;li&gt;Состояние и свойства: В каком он состоянии? (aria-expanded="true/false", aria-checked="true", aria-hidden="true").&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Важное правило: Не использовать ARIA там, где можно обойтись нативным HTML. ARIA — это как хирургический инструмент для исправления сложных случаев, а не замена простым и понятным тегам.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/ru/docs/Learn_web_development/Core/Accessibility/HTML"&gt;Подробнее о создании доступной среды благодаря HTML&lt;/a&gt;&lt;/p&gt;

&lt;h3 dir="ltr"&gt;&lt;b id="docs-internal-guid-e45b7a04-7fff-229b-e490-840703dd8d06"&gt;Часть 4: Тестирование — Смотрим и слушаем мир чужими глазами&lt;/b&gt;&lt;/h3&gt;

&lt;p dir="ltr"&gt;Автоматические инструменты (Lighthouse, axe) — отличный первый шаг, но они находят лишь около 30% проблем. Настоящее тестирование доступности — это ручной труд и эмпатия.&lt;/p&gt;

&lt;h4 dir="ltr"&gt;&lt;b id="docs-internal-guid-7e1670ac-7fff-75ba-9d71-0f887a88f4ee"&gt;4.1. Тестирование клавиатурой&lt;/b&gt;&lt;/h4&gt;

&lt;p dir="ltr"&gt;Самый простой и эффективный тест. Отключите мышь и попробуйте пользоваться сайтом только с клавиатуры.&lt;/p&gt;

&lt;ol dir="ltr"&gt;
	&lt;li&gt;Используйте клавишу Tab, чтобы перемещаться по интерактивным элементам.&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;&lt;b id="docs-internal-guid-856e49e8-7fff-e70c-1049-1bd9ab4fe5e1"&gt;4.2. Тестирование со скрин-ридерами&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/training/modules/develop-products-with-screen-reader-support/7-test-screen-reader-support"&gt;Скрин-ридеры&lt;/a&gt; (читалки экрана) преобразуют цифровой текст в синтезированную речь или шрифт Брайля. Это основной инструмент для незрячих пользователей. Тестирование с ними — обязательный этап.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Популярные комбинации скрин-ридеров:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Windows: NVDA (бесплатный, лучше всего работает с Firefox). Или JAWS (платный, самый популярный в корпоративном секторе) .&lt;/li&gt;
	&lt;li&gt;macOS: VoiceOver (встроен в систему, лучше всего работает с Safari).&lt;/li&gt;
	&lt;li&gt;Android: TalkBack (встроен).&lt;/li&gt;
	&lt;li&gt;iOS: VoiceOver (встроен).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Что проверять с помощью скрин-ридера:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Чтение содержимого: Пройдитесь по странице стрелками (режим виртуального курсора). Все ли элементы озвучиваются? Правильно ли озвучиваются изображения (через alt)?&lt;/li&gt;
	&lt;li&gt;Навигация по заголовкам (клавиша H): Можете ли вы составить "карту" страницы и перейти к нужному разделу только по заголовкам? Не пропущены ли уровни? .&lt;/li&gt;
	&lt;li&gt;Навигация по ссылкам (клавиша K): Понятно ли, куда ведут ссылки, при прослушивании их вне контекста?&lt;/li&gt;
	&lt;li&gt;Навигация по вехам (landmarks) (клавиша D): Можно ли быстро перейти к основному контенту (&amp;lt;main&amp;gt;), минуя шапку и навигацию?&lt;/li&gt;
	&lt;li&gt;Работа с формами (клавиши F, E, C, R, B): Озвучивается ли подпись поля, когда вы входите в него? Правильно ли читаются сообщения об ошибках?&lt;/li&gt;
	&lt;li&gt;Динамический контент: Оповещает ли скрин-ридер о появлении всплывающих окон или обновлении части страницы?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-f7d1a99a-7fff-fef1-08c7-eea1b4f4372a"&gt;4.3. Инструменты для помощи в тестировании&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Помимо ручного тестирования, полезно использовать:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Accessibility Insights for Web (браузерный плагин): Помогает проходить проверки пошагово.&lt;/li&gt;
	&lt;li&gt;Lighthouse (встроен в Chrome DevTools): Быстрая автоматическая проверка основных метрик.&lt;/li&gt;
	&lt;li&gt;Инструменты разработчика (браузера): Позволяют инспектировать дерево доступности (Accessibility Tree), чтобы увидеть, какую именно информацию браузер передает скрин-ридеру.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b id="docs-internal-guid-369dd0be-7fff-cc0a-6316-1ae9dc35a9a5"&gt;Заключение&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Доступность — это не финальный штрих и не чек-лист для галочки. Это философия проектирования, которая ставит человека в центр вселенной продукта. Интегрируя знания о WCAG 2.2, создавая продуманный дизайн для разных групп пользователей, опираясь на семантическую верстку и проверяя свою работу с реальными инструментами (от клавиатуры до VoiceOver), мы перестаем делить мир на "обычных" и "особенных" пользователей. Мы просто создаем качественный, удобный и честный продукт для всех.&lt;/p&gt;</summary>
    <dc:creator>Алексей Кондратьев</dc:creator>
    <dc:date>2026-03-09T14:51:00Z</dc:date>
  </entry>
  <entry>
    <title>Как я сократил время итерации в 3 раза на проекте с микросервисами</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21224493" />
    <author>
      <name>Maxim Kalabukhov</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21224493</id>
    <updated>2026-03-04T11:28:24Z</updated>
    <published>2026-03-04T09:33:00Z</published>
    <summary type="html">&lt;p&gt;Рано или поздно любая задача по написанию кода сводится к одному и тому же циклу: собрал проект -&amp;gt; запустил -&amp;gt; прогнал тесты -&amp;gt; поймал проблему -&amp;gt; выдвинул гипотезу -&amp;gt; внёс правки -&amp;gt; и снова по кругу, каждый раз надеясь, что в этот раз «точно всё».&lt;/p&gt;

&lt;p&gt;На моём проекте - 10+ микросервисов на kotlin/spring, docker, gradle - один такой круг занимал примерно 3 минуты: секунд 15–30 на сборку всего проекта, около 2 минут на запуск контейнеров и ещё секунд 30 на тестирование. Казалось бы, 3 минуты - мелочь. Но представьте, что за одну задачу вы проходите этот цикл 10 раз (а это вполне реалистично). Получается 30 минут чистого ожидания - просто сидишь и смотришь в монитор. Мне показалось, что с этим стоит что-то сделать.&lt;/p&gt;

&lt;p&gt;Первая мысль была в духе «надо как-то ускорить сборку». Но потом я понял, что проблема не в скорости отдельных шагов, а в том, что на каждой итерации собиралось и запускалось всё. Все 10+ сервисов. Каждый раз. Хотя для проверки моей гипотезы обычно нужны один-два из них.&lt;/p&gt;

&lt;p&gt;Вопрос переформулировался: как сделать так, чтобы на каждую итерацию собиралось и поднималось только то, что действительно нужно?&lt;/p&gt;

&lt;p&gt;До этого я запускал gradle из терминала, это была прям укоренившаяся привычка. Но оказалось, что idea собирает gradle-проект заметно быстрее. Уже одно это дало заметный выигрыш. Но главное в idea сборку можно встроить в единый пайплайн с запуском контейнеров.&lt;/p&gt;

&lt;h3&gt;Всё в одной конфигурации&lt;/h3&gt;

&lt;p&gt;В idea можно создать docker сompose конфигурацию, которая за один запуск делает всё: собирает нужные модули и поднимает контейнеры. Вот как это выглядит:&lt;/p&gt;

&lt;p&gt;&lt;img src="https://www.tune-it.ru/documents/portlet_file_entry/21214588/Pasted+image+20260304123936.png/5df3246d-9290-ba63-d649-395662845c39?imagePreview=1" /&gt;&lt;/p&gt;

&lt;p&gt;Тут указываем путь до docker compose файла, а в &lt;code&gt;Services&lt;/code&gt; вместо указания 10+ сервисов, перечисляем только те, которые нужны для текущей задачи, по желанию указываем флаги для &lt;code&gt;docker compose up&lt;/code&gt;. В &lt;code&gt;Before-launch&lt;/code&gt; добавляем gradle-таски &lt;code&gt;clean assemble&lt;/code&gt;, но только для конкретных модулей - это позволит idea выполнить их перед тем как запустить &lt;code&gt;docker compose up&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Экономим энергию и пару секунд хоткеем &lt;code&gt;Shift+F10&lt;/code&gt; и радуемся результату - idea сначала собрала два нужных модуля, потом подняла два контейнера. Всё. Не нужно помнить порядок команд, не нужно их прописывать вручную.&lt;/p&gt;

&lt;p&gt;Вместо одной «универсальной» конфигурации, которая поднимает всё, я создаю отдельную под каждую задачу. Работаю над gateway и some - конфигурация &lt;code&gt;gateway+some&lt;/code&gt;. Завтра нужен другой набор сервисов - создаю новую.&amp;nbsp;Создание такой конфигурации занимает пару минут. Но эта пара минут окупается уже на второй итерации.&lt;/p&gt;

&lt;p&gt;Давайте глянем на цифры: сборка теперь занимает в среднем 5 секунд, а запуск 15 секунд. Итого мне нужно 50 секунд на проверку гипотезы, вместо 180, а это разница в 3 раза и это ощущается - стало легче сохранять фокус и контекст во время ожидания.&lt;/p&gt;

&lt;p&gt;Если у вас похожий стек - kotlin/spring, gradle, docker, несколько микросервисов - попробуйте. Возможно, самое дорогое время в вашем рабочем дне - это не написание кода, а ожидание, пока он соберётся.&lt;/p&gt;</summary>
    <dc:creator>Maxim Kalabukhov</dc:creator>
    <dc:date>2026-03-04T09:33:00Z</dc:date>
  </entry>
  <entry>
    <title>HashMap в Java: 10 фактов, о которых вы, возможно, не знали</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21224460" />
    <author>
      <name>Polina Napolskaya</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21224460</id>
    <updated>2026-03-04T09:04:06Z</updated>
    <published>2026-03-04T08:14:00Z</published>
    <summary type="html">&lt;p&gt;HashMap – наверное, самая используемая коллекция в Java. Мы кладём в неё элементы, достаём, редко задумываясь, что происходит под капотом. И в целом это нормально: класс работает, документация есть, сообщество стабильно советует переопределять &lt;code&gt;equals&lt;/code&gt; и &lt;code&gt;hashCode&lt;/code&gt;. Но если копнуть чуть глубже, обнаруживается немало деталей, которые могут удивить даже опытного разработчика.&lt;/p&gt;

&lt;p&gt;Я собрала десять таких моментов. Не про то, как устроен HashMap в целом, а про то, что обычно остаётся за скобками.&lt;/p&gt;

&lt;h2&gt;1. Почему порог деревизации – именно 8&lt;/h2&gt;

&lt;p&gt;С Java 8, когда в одной корзине становится больше восьми элементов, связанный список преобразуется в красно-чёрное дерево. Логика понятна: начиная с какого-то размера список работает слишком медленно. Но почему порог установлен именно на восьми?&lt;/p&gt;

&lt;p&gt;Ответ лежит в теории вероятностей. Разработчики Oracle смоделировали ситуацию с хорошей хеш-функцией и стандартным нагрузочным фактором 0.75. Согласно распределению Пуассона, вероятность того, что в одну корзину попадёт восемь элементов, составляет примерно 0.00000006. Это шесть случаев на десять миллионов.&lt;/p&gt;

&lt;p&gt;Восемь здесь – не случайное число, а своеобразная «защита от дурака». Если коллизий так много, значит, либо хеш-функция работает плохо, либо кто-то пытается организовать атаку. В штатной же ситуации дерево просто не нужно. Кстати, обратный переход из дерева в список происходит, когда элементов становится меньше шести – это предотвращает частые преобразования при добавлении и удалении.&lt;/p&gt;

&lt;h2&gt;2. Сдвиг на 16 бит: зачем он нужен&lt;/h2&gt;

&lt;p&gt;В исходном коде HashMap есть такая строчка:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(h = key.hashCode()) ^ (h &amp;gt;&amp;gt;&amp;gt; 16)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;На первый взгляд кажется лишней. Зачем перед вычислением индекса ещё что-то делать с хеш-кодом?&lt;/p&gt;

&lt;p&gt;Дело в том, что размер внутреннего массива всегда является степенью двойки. Индекс корзины вычисляется не через взятие остатка, а через побитовое И: &lt;code&gt;(n - 1) &amp;amp; hash&lt;/code&gt;. Это быстро, но есть ограничение: в вычислении участвуют только младшие биты хеш-кода. Старшие, по сути, игнорируются.&lt;/p&gt;

&lt;p&gt;Сдвиг на 16 бит и XOR решают эту проблему. Они «перемешивают» старшие и младшие биты, и даже если у двух объектов хеш-коды различаются только в старшей части, они всё равно попадут в разные корзины.&lt;/p&gt;

&lt;h2&gt;3. Массив создаётся не сразу&lt;/h2&gt;

&lt;p&gt;Когда вы пишете &lt;code&gt;new HashMap&amp;lt;&amp;gt;()&lt;/code&gt;, внутренний массив ещё не существует. Он создаётся только при первой вставке элемента. До этого объект занимает минимум памяти – фактически только накладные расходы на сам экземпляр.&lt;/p&gt;

&lt;p&gt;Это сделано намеренно: если мапа объявлена, но не используется, память не тратится зря. Мелочь, но в масштабах крупного приложения такие мелочи дают ощутимый выигрыш.&lt;/p&gt;

&lt;h2&gt;4. Начальная ёмкость считается не так, как вы думаете&lt;/h2&gt;

&lt;p&gt;Конструктор &lt;code&gt;new HashMap&amp;lt;&amp;gt;(100)&lt;/code&gt; часто понимают неправильно. Кажется, что если передать 100, то можно положить 100 элементов без расширения. На самом деле 100 – это размер внутреннего массива. Порог срабатывает при превышении &lt;code&gt;ёмкость * loadFactor&lt;/code&gt;, то есть при 75 элементах.&lt;/p&gt;

&lt;p&gt;Чтобы без расширения поместилось ровно 100 элементов, раньше нужно было писать &lt;code&gt;(int) Math.ceil(100 / 0.75)&lt;/code&gt;. Выглядит как заклинание… К счастью, в Java 19 появился метод &lt;code&gt;HashMap.newHashMap(100)&lt;/code&gt;, который делает этот расчёт автоматически.&lt;/p&gt;

&lt;h2&gt;5. Итерация зависит от ёмкости, а не только от размера&lt;/h2&gt;

&lt;p&gt;В документации сказано: время итерации пропорционально ёмкости плюс размер. Это не просто формальность.&lt;/p&gt;

&lt;p&gt;Если вы создали мапу с ёмкостью 10 000, но положили в неё два элемента, итератор всё равно обойдёт все 10 000 корзин, проверяя каждую на наличие данных. Пустые корзины не пропускаются. Поэтому если вы планируете часто перебирать элементы, не стоит завышать начальную ёмкость без необходимости.&lt;/p&gt;

&lt;h2&gt;6. putAll может работать медленнее ручного копирования&lt;/h2&gt;

&lt;p&gt;Неожиданный факт, но в некоторых версиях Java для больших мап метод&amp;nbsp;&lt;code&gt;putAll&lt;/code&gt; (и конструктор копирования) работает медленнее, чем обычный цикл по &lt;code&gt;entrySet() &lt;/code&gt;с ручным добавлением.&lt;/p&gt;

&lt;p&gt;Исследователи OpenJDK связывают это с тем, что JIT-компилятор не всегда может эффективно оптимизировать полиморфные вызовы на границах методов. В простом же цикле оптимизаций больше, и код выполняется быстрее – разница может достигать 20–30%. Ситуация варьируется от версии к версии, но о ней полезно знать, если вы работаете с действительно большими объёмами данных.&lt;/p&gt;

&lt;h2&gt;7. Ключ null всегда попадает в нулевую корзину&lt;/h2&gt;

&lt;p&gt;То, что HashMap допускает один ключ &lt;code&gt;null&lt;/code&gt;, знают все. Но мало кто задумывается, куда именно он попадает.&lt;/p&gt;

&lt;p&gt;В методе &lt;code&gt;hash()&lt;/code&gt; есть явная проверка: для &lt;code&gt;null &lt;/code&gt;возвращается 0. При вычислении индекса &lt;code&gt;(n - 1) &amp;amp; 0 &lt;/code&gt;результат всегда будет 0. То есть все ключи &lt;code&gt;null&lt;/code&gt; хранятся строго в нулевой корзине и всегда располагаются первыми в списке или дереве этой корзины.&lt;/p&gt;

&lt;h2&gt;8. Бесконечный цикл в Java 7 больше не актуален&lt;/h2&gt;

&lt;p&gt;В Java 7 и более ранних версиях в многопоточной среде при одновременном расширении HashMap мог возникнуть бесконечный цикл – программа просто зависала.&lt;/p&gt;

&lt;p&gt;Причина была в способе переноса элементов: использовалась вставка в начало списка, что в конкурентной среде могло замкнуть список само на себя. В Java 8 отказались от этого подхода в пользу вставки в конец. Бесконечные циклы ушли в прошлое. Но это не делает HashMap потокобезопасной – проблемы с потерей данных и состояниями гонки остались.&lt;/p&gt;

&lt;h2&gt;9. computeIfAbsent и merge могут бросить исключение во время выполнения&lt;/h2&gt;

&lt;p&gt;Методы &lt;code&gt;compute, computeIfAbsent&lt;/code&gt; и &lt;code&gt;merge&lt;/code&gt; удобны тем, что позволяют атомарно выполнить сложную логику вставки. Но у них есть особенность: они могут изменять мапу во время работы переданной функции.&lt;/p&gt;

&lt;p&gt;Если внутри этой функции попытаться снова изменить ту же мапу (например, вызвать &lt;code&gt;put&lt;/code&gt;), можно получить &lt;code&gt;ConcurrentModificationException&lt;/code&gt;. Это не баг, а защита от некорректного состояния. Методы стараются отследить такие ситуации и прервать выполнение, чтобы не допустить разрушения структуры данных.&lt;/p&gt;

&lt;h2&gt;10. Даже списки в Java 8 ищут быстрее&lt;/h2&gt;

&lt;p&gt;Даже если в корзине меньше восьми элементов и дерево ещё не создано, поиск работает чуть быстрее обычного последовательного перебора. В коде есть проверка: если ключи реализуют интерфейс &lt;code&gt;Comparable&lt;/code&gt;, алгоритм использует сравнение для более быстрого ветвления.&lt;/p&gt;

&lt;p&gt;Это микрооптимизация, но она хорошо иллюстрирует подход разработчиков: улучшения делаются даже там, где кажется, что они не особо нужны&lt;/p&gt;

&lt;p&gt;&lt;u&gt;​​​​​​&lt;/u&gt;​​​​​​​​​​​​Эти детали редко всплывают в повседневной работе. Но когда сталкиваешься с неожиданным поведением или пытаешься выжать из приложения максимум производительности, знание внутреннего устройства HashMap помогает быстрее понять, что идёт не так и как это исправить.&lt;br /&gt;
Исходный код HashMap открыт, и в нём можно найти ещё много интересного. Иногда полезно просто заглянуть – хотя бы ради любопытства.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;</summary>
    <dc:creator>Polina Napolskaya</dc:creator>
    <dc:date>2026-03-04T08:14:00Z</dc:date>
  </entry>
  <entry>
    <title>Go вместе изучать Go. Часть 6 (Заключительная)</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21222577" />
    <author>
      <name>Romo Fedoroff</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21222577</id>
    <updated>2026-03-01T15:09:42Z</updated>
    <published>2026-03-01T14:54: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;Добро пожаловать в заключительную статью нашей серии о языке программирования Go.&lt;/p&gt;

&lt;p&gt;В ней мы рассмотрим три возможности языка: работу с изображениями через пакет image, обобщения (дженерики) для написания универсального кода и конкурентность — одну из главных «визитных карточек» Go.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Работа с изображениями&lt;/h2&gt;

&lt;p&gt;Go использует интерфейсы для определения поведения. Интерфейс Image демонстрирует, как определить набор методов, которые должна реализовывать структура, чтобы считаться "изображением".&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
package image

type Image interface {
    ColorModel() color.Model
    Bounds() Rectangle
    At(x, y int) color.Color
}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Этот интерфейс описывает три метода: ColorModel() возвращает цветовую модель изображения, Bounds() — его границы в виде прямоугольника, а At(x, y int) — цвет пикселя по заданным координатам.&lt;/p&gt;

&lt;p&gt;Обратите внимание: возвращаемое значение Rectangle метода Bounds на самом деле является типом image.Rectangle, поскольку объявление находится внутри пакета image.&lt;/p&gt;

&lt;p&gt;Типы color.Color и color.Model также являются интерфейсами, но для простоты мы будем использовать готовые реализации color.RGBA и color.RGBAModel из пакета image/color.&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
package main

import (
	"fmt"
	"image"
)

func main() {
	// Создаем 100x100 пикселей типа RGBA
	m := image.NewRGBA(image.Rect(0, 0, 100, 100)) 
	
    // Мы можем вызвать методы, потому что *image.RGBA 
    // неявно реализует интерфейс image.Image.
	fmt.Println(m.Bounds())
	fmt.Println(m.At(0, 0).RGBA())
}
// Вывод:
// (0,0)-(100,100)
// 0 0 0 0&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;В этом примере мы создаём RGBA-изображение размером 100×100 пикселей. Функция Bounds() возвращает прямоугольник от точки (0,0) до точки (100,100). Метод At(0, 0).RGBA() возвращает четыре нуля — это значения красного, зелёного, синего и альфа-каналов для пикселя в левом верхнем углу. Нули означают полностью прозрачный чёрный цвет.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h2&gt;Универсальность кода: Обобщения (Generics)&lt;/h2&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Обобщения, появившиеся в Go 1.18, позволяют писать функции и типы, которые могут работать с любым типом данных, сохраняя при этом типобезопасность.&lt;/p&gt;

&lt;h3&gt;Параметры типов&lt;/h3&gt;

&lt;p&gt;Функции в Go можно писать так, чтобы они работали с несколькими типами, используя параметры типов. Параметры типов указываются в квадратных скобках перед аргументами функции:&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
func Index[T comparable](s []T, x T) int&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Это объявление означает, что s — это срез элементов любого типа T, который удовлетворяет встроенному ограничению comparable. Значение x имеет тот же тип.&lt;/p&gt;

&lt;p&gt;Ограничение comparable позволяет использовать операторы == и != для значений данного типа. В примере ниже мы используем его для сравнения значения со всеми элементами среза до нахождения совпадения:&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
package main

import "fmt"

// Index возвращает индекс x в срезе s или -1, если элемент не найден.
func Index[T comparable](s []T, x T) int {
    for i, v := range s {
        if v == x {
            return i
        }
    }
    return -1
}

func main() {
    // Index работает со срезом целых чисел
    si := []int{10, 20, 15, -10}
    fmt.Println(Index(si, 15))

    // Index также работает со срезом строк
    ss := []string{"foo", "bar", "baz"}
    fmt.Println(Index(ss, "hello"))
}

// Вывод:
// 2
// -1&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;Функция Index универсальна: она работает и с числами, и со строками — с любым типом, поддерживающим сравнение. Компилятор сам определяет конкретный тип T на основе переданных аргументов.&lt;/p&gt;

&lt;h3&gt;Обобщённые типы&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Помимо обобщённых функций, Go поддерживает обобщённые типы. Тип можно параметризовать параметром типа, что особенно полезно для реализации универсальных структур данных.&lt;/p&gt;

&lt;p&gt;Вот пример объявления типа для односвязного списка, хранящего значения любого типа, с добавленной функциональностью:&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
package main

import "fmt"

// List представляет односвязный список, хранящий значения любого типа.
type List[T any] struct {
    next *List[T]
    val  T
}

// Push добавляет новый элемент в начало списка и возвращает новую голову.
func (l *List[T]) Push(val T) *List[T] {
    return &amp;amp;List[T]{next: l, val: val}
}

// Len возвращает длину списка.
func (l *List[T]) Len() int {
    count := 0
    for current := l; current != nil; current = current.next {
        count++
    }
    return count
}

// ToSlice преобразует список в срез.
func (l *List[T]) ToSlice() []T {
    var result []T
    for current := l; current != nil; current = current.next {
        result = append(result, current.val)
    }
    return result
}

// Find ищет элемент в списке (работает только для comparable типов).
func Find[T comparable](l *List[T], val T) bool {
    for current := l; current != nil; current = current.next {
        if current.val == val {
            return true
        }
    }
    return false
}

func main() {
    // Создаём список целых чисел
    var head *List[int]
    head = head.Push(1)
    head = head.Push(2)
    head = head.Push(3)

    fmt.Println("Длина списка:", head.Len())
    fmt.Println("Элементы:", head.ToSlice())
    fmt.Println("Содержит 2?", Find(head, 2))
    fmt.Println("Содержит 5?", Find(head, 5))
}

// Вывод:
// Длина списка: 3
// Элементы: [3 2 1]
// Содержит 2? true
// Содержит 5? false&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Обратите внимание: метод Push возвращает новую голову списка, поскольку мы добавляем элементы в начало. Функция Find объявлена отдельно с ограничением comparable, потому что не все типы поддерживают сравнение через ==.&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;h3&gt;Горутины&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Горутина — это легковесный поток, управляемый средой выполнения Go:&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
go f(x, y, z)&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Эта команда запускает новую горутину, выполняющую f(x, y, z). Вычисление f, x, y и z происходит в текущей горутине, а выполнение f — в новой.&lt;/p&gt;

&lt;p&gt;Горутины работают в одном адресном пространстве, поэтому доступ к общей памяти должен быть синхронизирован. Пакет sync предоставляет полезные примитивы, хотя в Go чаще используются другие механизмы — каналы.&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
package main

import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i &amp;lt; 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go say("world")
    say("hello")
}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;В этом примере две горутины выполняются параллельно: одна печатает «world», другая — «hello». Порядок вывода может варьироваться от запуска к запуску, поскольку горутины работают конкурентно.&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
// Пример вывода (порядок может меняться):
// hello
// hello
// world
// world
// ...
&lt;/pre&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;Каналы — это типизированные каналы связи, через которые можно отправлять и получать значения с помощью оператора &amp;lt;-:&lt;/p&gt;

&lt;p&gt;Каналы (chan) служат для безопасного обмена данными между горутинами.&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
ch &amp;lt;- v    // Отправить v в канал ch.
v := &amp;lt;-ch  // Получить значение из ch и присвоить его v.&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Данные «текут» в направлении стрелки. Как и карты (maps) и срезы, каналы нужно создавать перед использованием:&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
ch := make(chan int)&lt;/pre&gt;

&lt;p&gt;По умолчанию операции отправки и получения блокируются, пока другая сторона не будет готова. Это позволяет горутинам синхронизироваться без явных блокировок.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
package main

import "fmt"

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c &amp;lt;- sum // отправить сумму в канал c
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)
    x, y := &amp;lt;-c, &amp;lt;-c // получить из канала c

    fmt.Println(x, y, x+y)
}

// Вывод: -5 17 12&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;h3&gt;Буферизованные каналы&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Каналы могут быть буферизованными. Размер буфера указывается вторым аргументом make.&lt;/p&gt;

&lt;p&gt;Буферизованные каналы позволяют отправить несколько значений, не блокируя отправителя, пока буфер не заполнится.&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
ch := make(chan int, 100)&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;pre class="brush:cpp;"&gt;
package main

import "fmt"

func main() {
    ch := make(chan int, 2)
    ch &amp;lt;- 1
    ch &amp;lt;- 2
    // ch &amp;lt;- 3 // Эта строка вызовет deadlock!
    
    fmt.Println(&amp;lt;-ch)
    fmt.Println(&amp;lt;-ch)
}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Если раскомментировать строку ch &amp;lt;- 3, программа зависнет (deadlock), потому что буфер размером 2 уже заполнен, и отправка будет ждать, пока кто-то не прочитает из канала. Но читать некому — главная горутина заблокирована на отправке. Результат — взаимная блокировка:&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
fatal error: all goroutines are asleep - deadlock!&lt;/pre&gt;

&lt;p&gt;Это важный урок: размер буфера нужно выбирать с учётом того, сколько значений может быть отправлено до того, как получатель их обработает.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Завершение передачи данных (Range и Close)&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;
v, ok := &amp;lt;-ch&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Значение ok будет false, если канал закрыт и пуст.&lt;/p&gt;

&lt;p&gt;Цикл for i := range c получает значения из канала до его закрытия.&lt;/p&gt;

&lt;p&gt;Важно: закрывать канал должен только отправитель, никогда — получатель. Отправка в закрытый канал вызовет панику. При этом каналы не похожи на файлы — их обычно не нужно закрывать. Закрытие необходимо только когда получателю нужно знать, что значений больше не будет.&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
package main

import "fmt"

func fibonacci(n int, c chan int) {
    x, y := 0, 1
    for i := 0; i &amp;lt; n; i++ {
        c &amp;lt;- x
        x, y = y, x+y
    }
    close(c) // Сигнал об окончании
}

func main() {
    c := make(chan int, 10)
    go fibonacci(cap(c), c)

	// Цикл range автоматически завершится, когда fibonacci вызовет close(c).
    for i := range c {
        fmt.Println(i)
    }
}

// Вывод: 0 1 1 2 3 5 8 13 21 34&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Управляемый выбор: select&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Оператор select позволяет горутине ожидать готовности нескольких каналов связи. Он выбирает первый готовый случай, а если их несколько — выбирает случайным образом.&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
package main

import "fmt"

func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c &amp;lt;- x:
            x, y = y, x+y
        case &amp;lt;-quit:
            fmt.Println("quit")
            return
        }
    }
}

func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() {
        for i := 0; i &amp;lt; 10; i++ {
            fmt.Println(&amp;lt;-c)
        }
        quit &amp;lt;- 0
    }()
    fibonacci(c, quit)
}&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;select блокируется до тех пор, пока один из его case-ов не сможет выполниться. Если готовы несколько — выбирается случайный.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Default в Select&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Ветка default выполняется, если ни один другой case не готов. Это позволяет выполнять неблокирующие операции:&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
select {
case i := &amp;lt;-c:
    // Данные пришли
default:
    //Данные не пришли немедленно, продолжаем работу
}
&lt;/pre&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;h3&gt;Взаимное исключение: sync.Mutex&lt;/h3&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Каналы отлично подходят для коммуникации между горутинами. Но если нам нужно просто гарантировать, что только одна горутина имеет доступ к переменной в данный момент (общение через каналы в данном случае просто напросто избыточно)?&lt;/p&gt;

&lt;p&gt;Для этого существует взаимное исключение (mutex). Стандартная библиотека Go предоставляет sync.Mutex с двумя методами: Lock и Unlock.&lt;/p&gt;

&lt;pre class="brush:cpp;"&gt;
package main

import (
    "fmt"
    "sync"
    "time"
)

// SafeCounter безопасен для конкурентного использования.
type SafeCounter struct {
    mu sync.Mutex
    v  map[string]int
}

// Inc увеличивает счётчик для заданного ключа.
func (c *SafeCounter) Inc(key string) {
    c.mu.Lock()
    c.v[key]++
    c.mu.Unlock()
}

// Value возвращает текущее значение счётчика.
func (c *SafeCounter) Value(key string) int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.v[key]
}

func main() {
    c := SafeCounter{v: make(map[string]int)}
    for i := 0; i &amp;lt; 1000; i++ {
        go c.Inc("somekey")
    }

    time.Sleep(time.Second)
    fmt.Println(c.Value("somekey"))
}

// Вывод: 1000&lt;/pre&gt;

&lt;p&gt;Без мьютекса 1000 горутин, одновременно изменяющих карту, вызвали бы гонку данных (data race) и непредсказуемое поведение. Мьютекс гарантирует, что в каждый момент времени только одна горутина работает с картой.&lt;/p&gt;

&lt;p&gt;&lt;meta charset="UTF-8" /&gt;&lt;/p&gt;

&lt;p&gt;Обратите внимание на использование defer c.mu.Unlock() в методе Value — это гарантирует разблокировку даже при ранних возвратах или панике.&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;Из этой статьи мы научились работать с несколькими важными аспектами Go. Мы узнали, как использовать пакет image для создания и манипулирования изображениями через интерфейс Image. Освоили дженерики — мощный механизм для написания универсального, переиспользуемого кода с параметрами типов и ограничениями вроде comparable и any. Погрузились в мир конкурентности Go: изучили горутины как легковесные потоки, каналы как средство безопасной коммуникации, оператор select для работы с несколькими каналами одновременно и мьютексы для защиты общих данных.&lt;/p&gt;

&lt;p&gt;Эта статья завершает нашу серию материалов о языке Go. Мы прошли путь от основ синтаксиса до продвинутых возможностей языка, и теперь у вас есть некоторая база для написания эффективных, безопасных и элегантных программ на Go.&lt;/p&gt;

&lt;p&gt;Успехов&amp;nbsp;в ваших проектах!&lt;/p&gt;</summary>
    <dc:creator>Romo Fedoroff</dc:creator>
    <dc:date>2026-03-01T14:54:00Z</dc:date>
  </entry>
  <entry>
    <title>iOS разработка: Как обнулить счетчик уведомлений в приложении</title>
    <link rel="alternate" href="https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21221410" />
    <author>
      <name>Никита Рогаленко</name>
    </author>
    <id>https://www.tune-it.ru/ru/c/blogs/find_entry?entryId=21221410</id>
    <updated>2026-02-26T13:16:20Z</updated>
    <published>2026-02-26T13:15:00Z</published>
    <summary type="html">&lt;p style="text-align: justify;"&gt;Хотя мобильная разработка и не является основным профилем нашей компании, порой среди требований к корпоративному порталу оказывается его доступность с мобильных устройств. В связи с этим иногда приходится браться за нетипичные для нас задачи в виде разработки iOS и Android приложений. Однако оставим задачу систематического изложения основ мобильной разработки на другой раз. В этой заметке кратко зафиксируем, как наиболее просто решить проблему с красным значком с количеством уведомлений у иконки iOS-приложения, который не пропадает при переходе в программу. Речь идет о подобном красном кружке:&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;&lt;img alt="Display a badge on the app icon - Progressive web apps | MDN" class="sFlh5c FyHeAf iPVvYb" jsaction="" jsname="kn3ccd" src="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/How_to/Display_badge_on_app_icon/mail-badge-ios.png" style="max-width: 1170px; height: 174px; margin: 10px 0px; width: 574px;" /&gt;​​​​​​​&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Зачастую происходит так, что при открытии приложения счетчик непрочитанных уведомлений не исчезает, а остается неизменным. Особенно часто такое возникает в случае, если переход происходит не по клику на уведомление в "Центре уведомлений", а непосредственно через экранное меню айфона.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Если мы хотим, чтобы все новые уведомления в приложении отмечались как прочитанные при переходе в приложение, то ответ кроется в модификации класса&amp;nbsp;SceneDelegate.&amp;nbsp;SceneDelegate - это класс в Swift, который отвечает за управление жизненным циклом конкретного экземпляра пользовательского интерфейса (сцены). Класс создает объект "контейнер" для элементов UIWindow, управляет состояниями приложения, размещением контента на странице, обработкой касаний разных элементов, переходами между фоновым и активным режимами.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Отличие SceneDelegate&amp;nbsp;от AppDelegate в том, что последний предназначен для глобальной конфигурации всего приложения в целом. Там же происходит и регистрация Push-уведомлений, инициализация Firebase или иных уведомлений. Сейчас же нам нужен&amp;nbsp;SceneDelegate, поскольку именно он обрабатывает событие открытия "сцены" приложения, при переходе в которую мы хотим обнулять счетчик уведомлений.&amp;nbsp;Метод, который нам нужен для обработки события - sceneDidBecomeActive(_:). Он вызывается, когда сцена стала активной и готова к взаимодействию с пользователем.&lt;/p&gt;

&lt;p style="text-align: justify;"&gt;Кусок кода на языке Swift, чтобы достичь поставленной задачи:&lt;/p&gt;

&lt;pre class="brush:as3;"&gt;
import UIKit
import SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let _ = (scene as? UIWindowScene) else {
            return
        }
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
            if #available(iOS 17.0, *) {
                UNUserNotificationCenter.current().setBadgeCount(0) { error in
                    if let error = error { print("sceneDidBecomeActive ERROR: \(error)") }
                }
            } else {
                UIApplication.shared.applicationIconBadgeNumber = 0
            }
            UNUserNotificationCenter.current().removeAllDeliveredNotifications()
        }

}&lt;/pre&gt;

&lt;p style="text-align: justify;"&gt;Для управления уведомлениями в iOS используется класс&amp;nbsp;UNUserNotificationCenter. Во фрагменте кода выше мы используем его методы для сброса счетчика уведомлений на иконке приложения в ноль (метод&amp;nbsp;setBadgeCount), а также для удаления уведомлений, пришедших от нашего приложения, в ленте "Центра уведомлений" (метод&amp;nbsp;removeAllDeliveredNotifications).&amp;nbsp;&lt;span aria-level="2" class="VndcI veK2kb" role="heading"&gt;&lt;span&gt;Метод удаления через UIApplication.shared.&lt;/span&gt;&lt;/span&gt;​​​​​​​applicationIconBadgeNumber является устаревшим (для версий до iOS 17)&lt;/p&gt;</summary>
    <dc:creator>Никита Рогаленко</dc:creator>
    <dc:date>2026-02-26T13:15:00Z</dc:date>
  </entry>
</feed>

