<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <language>ru</language>
    <title>Архитектура приложений</title>
    <description>Архитектура приложений — это структурное проектирование программного обеспечения, которое определяет, как различные компоненты системы взаимодействуют друг с другом. Хорошо спроектированная архитектура помогает создать гибкие, масштабируемые и легко поддерживаемые приложения.

Включает выбор технологий, проектирование баз данных, API, а также распределение функциональности между клиентской и серверной частями. Архитектура приложений охватывает различные паттерны, такие как MVC, микросервисы, монолит и другие, которые позволяют эффективно решать задачи безопасности, производительности и устойчивости.</description>
    <link>https://tproger.ru/tag/apps-architecture</link>
    <atom:link href="https://tproger.ru/tag/apps-architecture/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Tue, 20 Oct 2026 04:13:59 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>Архитектура приложений</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>Почему команда растёт, а фичи выходят медленнее</title>
      <link>https://tproger.ru/articles/pochemu-komanda-rastyot-a-fichi-vyhodyat-medlennee</link>
      <comments>https://tproger.ru/articles/pochemu-komanda-rastyot-a-fichi-vyhodyat-medlennee?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Дима Дмитриев]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/pochemu-komanda-rastyot-a-fichi-vyhodyat-medlennee</guid>
      <description><![CDATA[<p>Один день на прямой SQL или три на разделение слоёв? Разбираем связность кода, адаптеры и технический долг: как сократить объём будущих правок?</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/pochemu-komanda-rastyot-a-fichi-vyhodyat-medlennee">Почему команда растёт, а фичи выходят медленнее</a>»</p>]]></description>
      <category><![CDATA[Рефакторинг]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 30 Sep 2026 09:49:10 GMT</pubDate>
      <content:encoded><![CDATA[<p>Вы меняете сервис проверки паспортов, а вместе с ним приходится переписывать обработку заявки. Условия, по которым заявка проходит дальше, остались прежними, но работы всё равно прибавилось.</p><h2>Почему больше разработчиков не означает меньше работы</h2><p>Мы в Centicore вместе с нашим коллегой разбираем, почему с ростом команды разработка может замедляться. Он около пяти лет занимался системной архитектурой крупных систем, а затем перешёл в управление.</p><p>Например, два корпоративных проекта. В первом работали 50 человек, и команда с трудом завершила работу за год. Во втором людей было втрое меньше, а результат, по его оценке, оказался заметно лучше.</p><p>Рост команды сам по себе не уменьшает объём изменений, необходимых для каждой фичи. Разберём одну из причин, по которой этот объём растёт: сильную связность модулей внутри сервиса. При сильной связности небольшое изменение затрагивает сразу несколько компонентов. Разработчик меняет нужную логику, затем связанные с ней интеграции, проверяет соседний код и исправляет тесты. Задача растёт, хотя бизнес просил примерно то же, что и раньше. Новый сотрудник получает ту же систему зависимостей. Ему тоже нужно разобраться, что затронет его правка. Дополнительные люди могут взять часть работы, но сам объём изменений от этого не сокращается.</p><p>Разделение на микросервисы эту проблему само по себе не решает. Даже внутри отдельного сервиса бизнес-правила могут быть тесно связаны с конкретной базой данных или внешним API. Поэтому полезно посмотреть, сколько кода приходится менять из-за одной новой интеграции.</p><h2>Как проверка паспорта затрагивает обработку заявки</h2><p>Возьмём условную систему, которая проверяет данные клиента перед тем, как передать заявку дальше. В упрощённом примере бизнес-логике нужны два результата: действителен ли паспорт и отсутствует ли человек в нежелательных списках.</p><p>Допустим, сначала внешний сервис принимает только номер паспорта. Затем команда переходит на другой сервис, которому нужны ещё ФИО и код подразделения. Меняются состав запроса, протокол взаимодействия и формат ответа. При этом условия прохождения заявки остаются прежними. Если вызов провайдера и разбор его ответа находятся прямо в коде обработки заявки, менять придётся этот код. В одном месте оказались две причины для изменений: новые бизнес-правила и новый способ получения данных.</p><p>Из-за этого задача по замене интеграции затрагивает сценарий целиком. Чтобы ограничить объём правок, нужно отделить получение результата проверки от решения о том, что делать с заявкой.</p><h2>Как отделить бизнес-правила от технических деталей</h2><p>В чистой и луковой архитектуре бизнес-логика находится в центре, а работа с базами данных, внешними сервисами и пользовательским интерфейсом вынесена наружу. У этих подходов есть различия, но общий для нашего примера принцип один: зависимости исходного кода направлены к бизнес-логике.</p><p>В модели чистой архитектуры выделяют четыре области:</p><ul><li>Сущности. Основные бизнес-правила и данные предметной области.</li><li>Варианты использования. Сценарии приложения, которые организуют работу с сущностями.</li><li>Адаптеры интерфейсов. Контроллеры, презентеры и шлюзы, которые связывают сценарии с внешним миром и преобразуют данные.</li><li>Фреймворки и драйверы. Внешние технические средства, включая веб-фреймворк и базу данных.</li></ul><p>Зависимость здесь означает, что один модуль использует определения другого: например, его интерфейсы или классы. Контроллер может обращаться к сценарию приложения. Сценарий при этом не должен зависеть от конкретного контроллера или реализации доступа к базе.</p><p>Для внешней операции сценарий использует интерфейс, определённый во внутренней части приложения. Внешний адаптер реализует этот интерфейс. Так сценарий может получить результат проверки паспорта, не обращаясь в своём коде к конкретному провайдеру. При выполнении программы запрос всё равно дойдёт до внешнего сервиса. Правило описывает зависимости кода, а порядок вызовов во время выполнения может быть другим.</p><p>Поэтому проверить архитектуру можно по конкретному месту: от чего зависит сценарий обработки заявки? Если ему нужен класс клиента определённого API или конкретный модуль доступа к БД, техническая реализация всё ещё влияет на его устройство.</p><h2>Что останется прежним при смене провайдера</h2><p>Вернёмся к паспорту. Адаптер получает необходимые данные, собирает запрос к внешнему сервису и преобразует ответ в результат, с которым работает приложение. В нашем примере это те же два признака: паспорт действителен, человек отсутствует в нежелательных списках.</p><p>При смене провайдера команда пишет новый адаптер. В нём будут другой запрос и другой разбор ответа. Сценарий обработки заявки продолжит получать результат проверки в прежнем виде.</p><p>Это работает, пока сохраняются бизнес-правила и приложению доступны нужные данные. Если ФИО или код подразделения раньше вообще не собирали, потребуется изменить и получение этих данных. Один адаптер не решит эту часть задачи. А если изменились условия, по которым заявка проходит дальше, правки понадобятся и в бизнес-логике.</p><p>С базой данных действует тот же принцип. Сценарий обращается к интерфейсу репозитория, а конкретная реализация работает с БД через SQL, ORM или собственный модуль доступа к данным. При переходе с PostgreSQL на Oracle это помогает сохранить код бизнес-правил, если их удалось отделить от особенностей конкретной БД.</p><p>Практический результат такого разделения виден в составе задачи: при смене внешнего сервиса разработчик меняет интеграцию, а правила обработки заявки остаются прежними, если требования к ним не менялись.</p><h2>Почему на старте получается три дня вместо одного</h2><p>В нашем примере простую реализацию можно собрать за день: контроллер принимает запрос, запускает скрипт с прямым SQL, и тот обращается к базе. На вариант с разделением бизнес-логики, интерфейсов и доступа к данным в том же примере уходит три дня.</p><p>Это условные оценки для объяснения компромисса. Они показывают, откуда берутся дополнительные затраты на старте нового сервиса: команда определяет границы модулей и способы их взаимодействия. Когда структура уже готова, её не приходится заново создавать для каждой следующей задачи.</p><p>Для короткоживущего MVP, который действительно собираются выбросить, прямой путь может быть оправдан. В системе, которую будут развивать и подключать к новым сервисам, нужно учитывать стоимость следующих изменений.</p><p>Допустим, после первого релиза меняется интеграция. В одном варианте команда правит адаптер. В другом ей приходится разбираться ещё и с обработкой заявки, потому что детали провайдера встроены в сценарий. Первоначальная экономия времени начинает оборачиваться дополнительной работой.</p><p>По мере развития системы таких связей может становиться больше. Тогда исправление затрагивает анализ требований, код и тесты сразу нескольких компонентов. Обсуждать архитектуру полезно через этот объём работы: какие изменения ожидаются и где их придётся делать.</p><h2>Как сохранить границы, когда фича нужна вчера</h2><p>На практике разделение слоёв часто проигрывает срочной задаче. Можно выделить несколько причин: жёсткие дедлайны, меняющиеся требования, нехватку опыта, проблемы с документацией и онбордингом. Под давлением команда выбирает короткий путь, а вернуться к нему позже становится отдельной задачей.</p><p>В разборе есть три способа, рассказывающие, как с этим работать.</p><ul><li>Подготовить шаблон сервиса. Заранее задать структуру для сущностей, сценариев и репозиториев, а также интерфейсы между ними. Тогда разработчику будет проще добавить логику в готовую структуру. При этом команде всё равно нужно понимать назначение границ и соблюдать их.</li><li>Зафиксировать технический долг. Если ради срока пришлось связать сценарий с конкретной интеграцией, описать принятое решение и запланировать рефакторинг. Так временное упрощение останется видимой задачей.</li><li>Объяснять затраты на конкретных изменениях. Обсудить с бизнесом, что произойдёт при замене сервиса проверки: где потребуется новый запрос, какие части приложения останутся прежними и почему команда тратит время на их разделение сейчас.</li></ul><p>Последний пункт требует участия тимлида и менеджера. Им нужно связать дополнительные затраты на текущую задачу с понятной будущей работой. В примере с паспортом такой аргумент уже есть: смена провайдера не должна заставлять команду заново разбираться с неизменившимися правилами обработки заявки.</p><h2>С чего начать в существующем проекте</h2><p>Начать можно с зависимостей внутри одного сервиса. Посмотрите, какие сценарии напрямую используют конкретную БД или внешний API и какие правки это уже вызывает. На примере проверки паспорта задача состоит в том, чтобы отделить правила обработки заявки от получения результатов проверки.</p><p>После такого разделения у следующей замены провайдера должна появиться понятная область изменений. Если бизнес-правила остались прежними, а команде снова приходится переписывать их реализацию, граница между сценарием и интеграцией ещё требует работы.</p>]]></content:encoded>
    </item>
    <item>
      <title>Монолит, модульный монолит или микросервисы: как выбрать архитектуру</title>
      <link>https://tproger.ru/articles/monolit-modulnyj-monolit-ili-mikroservisy-kak-vybrat-arhitek</link>
      <comments>https://tproger.ru/articles/monolit-modulnyj-monolit-ili-mikroservisy-kak-vybrat-arhitek?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Дима Дмитриев]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/monolit-modulnyj-monolit-ili-mikroservisy-kak-vybrat-arhitek</guid>
      <description><![CDATA[<p>Модульный монолит развёртывается целиком, а сервисы можно обновлять отдельно. Как выбрать архитектуру с учётом нагрузки, транзакций и ресурсов команды?</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/monolit-modulnyj-monolit-ili-mikroservisy-kak-vybrat-arhitek">Монолит, модульный монолит или микросервисы: как выбрать архитектуру</a>»</p>]]></description>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[Архитектура ПО]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 28 Sep 2026 11:44:11 GMT</pubDate>
      <content:encoded><![CDATA[<p>Когда пользователей становится больше, приложение может начать тормозить, а с добавлением новых функций код усложняется: перед каждым обновлением приходится проверять, как изменения повлияют на связанные части. В зависимости от причины можно добавить серверные мощности, разделить код на модули с понятными задачами или выделить самостоятельные сервисы, которые можно обновлять отдельно.</p><h2>Чем отличаются монолит, модульный монолит и микросервисы</h2><p>Представим приложение магазина. В нём есть заказы, каталог товаров и биллинг, который рассчитывает скидки и выставляет счета. Эти части связаны бизнес-логикой: для персональной скидки нужна сумма прошлых заказов, а при покупке нужно знать, есть ли товар на складе.</p><p>В <b>монолите</b> эта функциональность входит в одно приложение. Его части могут вызывать функции друг друга внутри процесса и обращаться к общей базе данных. Новую версию собирают и развёртывают целиком, даже если изменения касаются только расчёта скидки.</p><p>Такое устройство удобно на старте. Команда работает с общим приложением, и для проверки взаимодействия заказов с биллингом достаточно запустить его вместе с необходимой инфраструктурой. Обновление связанных частей можно включить в один релиз. Разработчикам проще проследить выполнение операции, когда её логика находится рядом.</p><p>По мере роста проекта становится важнее то, как устроен код внутри приложения. Если расчёт скидок, обработка заказов и работа с товарами связаны, изменение одной функции может затронуть соседние. Разработчику приходится учитывать всё больше связей, а проверка последствий занимает больше времени.</p><p><b>Модульный монолит</b> сохраняет общее развёртывание, но внутри разделён на модули с обязанностями и границами. Модуль заказов отвечает за заказы, биллинг содержит правила расчётов. Взаимодействие между ними организуют через определённые интерфейсы: по ним должно быть понятно, какие данные запрашивает соседняя часть и какой результат получает. Поэтому, когда меняются правила расчёта скидок, разработчик знает, где искать соответствующий код и какие части приложения используют результат. При этом вызов между модулями может оставаться обычным вызовом функции в памяти.</p><p><b>Модульный монолит</b> относится к монолитной архитектуре, из его названия вы можете понять организацию внутренних границ. Она требует работы с зависимостями в коде: раскладывание файлов по папкам само по себе ещё ничего не говорит о том, насколько самостоятельно устроены модули.</p><p>В <b>микросервисной архитектуре</b> части системы работают как самостоятельные сервисы. Заказы и биллинг можно развёртывать отдельно, выделять им разные ресурсы и разрабатывать силами разных команд. Для получения суммы заказов биллинг обращается к сервису заказов через API, получает ответ и использует его в расчёте.</p><p>Здесь появляется возможность выпускать изменения одного сервиса независимо от остальных, пока сохраняется совместимость взаимодействия. Вместе с ней возникает ответственность за контракт: сервис заказов должен возвращать данные в том виде, который понимает биллинг. Если изменение затрагивает обе стороны, командам нужно согласовать обновление.</p><h2>Что меняется, когда вызов функции становится сетевым запросом</h2><p>Вернёмся к персональной скидке. Биллинг должен узнать, на какую сумму пользователь сделал заказы за год. Пока логика находится в одном приложении, он может получить результат через внутренний вызов. В варианте с общей БД нужные данные доступны через запрос к ней.</p><p>После выделения заказов в сервис путь становится длиннее. Биллинг отправляет запрос к его API. Сервис заказов обращается к своей базе, формирует ответ и передаёт его обратно. Затем биллинг разбирает полученные данные и рассчитывает скидку.</p><p>На каждом таком переходе появляется дополнительная работа. Данные нужно подготовить к передаче и восстановить на другой стороне, дождаться ответа по сети, обработать результат. Эти расходы могут быть приемлемыми для одной операции. Если пользовательский запрос запускает длинную цепочку обращений, время ожидания начинает зависеть от всех её участников.</p><p>Например, страница профиля может собирать данные из нескольких сервисов. Тогда разработчику приходится выяснять, на каком участке задерживается ответ. Медленная работа одного сервиса способна задержать весь сценарий, который от него зависит. Физическое разделение компонентов сохраняет логические связи между ними.</p><p>Контракт API тоже становится частью работы. Если сервис меняет формат ответа, нужно учесть потребителей этих данных. Изменение, которое внутри монолита могло попасть в один релиз, в распределённой системе может потребовать обновления нескольких сервисов в согласованном порядке. При частых совместных изменениях ожидаемая независимость релизов сокращается.</p><p>Кроме кода прикладных задач, команда поддерживает инфраструктуру каждого сервиса. Нужно организовать сборку и развёртывание, наблюдать за работой компонентов, собирать их логи. При отладке приходится восстанавливать ход операции по нескольким частям системы. Для локальной разработки также нужно продумать, какие сервисы и базы потребуются, чтобы проверить изменение.</p><p>Стоимость взаимодействия покажем на примере системы мониторинга качества видео Amazon Prime Video. Сначала она работала как распределённое решение на AWS Lambda и Step Functions. При увеличении нагрузки обмен данными и управление выполнением компонентов потребовали слишком больших расходов. Команда объединила систему в монолитное приложение, после чего расходы на неё снизились примерно на 90%.</p><p>Результат относится к конкретной системе мониторинга с её характером вычислений и обмена данными. Для выбора архитектуры здесь полезно проверить, какую долю работы составляют полезные вычисления, а какую занимает координация компонентов. Чем чаще элементы приложения обращаются друг к другу, тем внимательнее нужно оценивать стоимость их разделения.</p><h2>Как масштабировать монолит и микросервисы</h2><p>Монолитное приложение можно запускать в нескольких экземплярах. Перед ними размещают балансировщик, который распределяет входящие запросы. Каждый экземпляр выполняет код того же приложения, поэтому монолитная архитектура совместима с горизонтальным масштабированием: нагрузку распределяют между дополнительными экземплярами.</p><p>С микросервисами применяется похожий подход. Если сервис заказов получает больше запросов, запускают дополнительные экземпляры именно этого сервиса. Биллинг при этом может продолжать работать с прежними ресурсами. Такая избирательность полезна, когда нагрузка на части системы заметно различается.</p><p>Однако увеличение числа обработчиков помогает в пределах возможностей остальных компонентов. Если все экземпляры сервиса заказов обращаются к одной перегруженной БД, она продолжит ограничивать обработку запросов. Поэтому перед изменением архитектуры нужно разобраться, где именно приложение упирается в доступные ресурсы.</p><h3>Воркеры и очереди задач</h3><p>Часть работы можно выполнять в фоне. Пользователь получает данные, необходимые для текущего действия, а отложенные вычисления выполняются отдельно. Для этого используют воркеры: процессы, которые забирают задачи из очереди и обрабатывают их.</p><p>В нашем магазине таким вычислением может быть расчёт персональной скидки по прошлым заказам. Воркер получает задачу, считает результат и сохраняет его в БД. Приложение затем использует подготовленное значение. Возможность вынести конкретный расчёт в фон зависит от того, в какой момент его результат нужен пользователю.</p><p>У монолита воркеры могут использовать ту же кодовую базу, что и веб-приложение, но выполнять разные группы задач. Один занимается расчётами биллинга, другой обрабатывает задачи, связанные с товарами. Для каждого направления можно организовать свою очередь и подобрать число исполнителей.</p><p>Допустим, в очереди четыре задачи, а свободных воркеров три. Каждый возьмёт по одной задаче, оставшаяся дождётся первого освободившегося исполнителя. Если очередь регулярно растёт и вычисления позволяют распределить работу, можно увеличить число воркеров. Для этого достаточно масштабировать обработку фоновых задач в существующей архитектуре.</p><p>Ресурсы воркеров тоже могут различаться. Расчётам, которым нужно держать в памяти большой объём данных, выделяют больше памяти. Более лёгким задачам достаточно меньших ресурсов. Такой подбор применим и к монолиту, и к отдельным сервисам.</p><h3>Чтение и запись в базе данных</h3><p>Для распределения нагрузки на чтение можно использовать реплики БД. Основная база принимает изменения, а её копии получают эти изменения через механизм репликации. Часть запросов на чтение направляют к копиям, разгружая основную базу.</p><p>В этой схеме запись по-прежнему сосредоточена в основной БД. Если ограничение связано именно с ней, увеличение числа реплик для чтения решает другую задачу. Потребуется отдельно рассматривать, как устроены данные и операции записи.</p><p>Разделение по сервисам позволяет распределить запись между разными базами, когда данные принадлежат разным частям системы. При этом сильно нагруженная база конкретного сервиса всё равно может потребовать масштабирования. Оценивать нужно каждый участок, на котором сосредоточена работа.</p><p>Возможен и шардинг: распределение данных между несколькими базами, например по пользователям или клиентам. Такой подход можно применять в разных архитектурах. Он требует продумать, как приложение найдёт нужные данные и как будет работать с информацией, относящейся сразу к нескольким группам.</p><h2>Что усложняется при разделении данных между сервисами</h2><p>Заказы связаны с товарами независимо от того, где выполняется код. Если обе сущности хранятся в общей реляционной БД, данные о них можно соединить запросом с JOIN. База выполняет связанную операцию, а приложение получает результат.</p><p>Когда каждая часть системы управляет своими данными и предоставляет их через API, получение общей информации требует обращений к соответствующим сервисам. Результаты нужно собрать и обработать. В системе появляется код, который организует эти обращения и учитывает доступность участников.</p><p>Поэтому перед выделением компонента полезно проследить, какие сведения нужны ему для обычной работы. Если почти каждый расчёт биллинга требует обращения к заказам, а затем к товарам, эти зависимости войдут в стоимость нового сервиса. Само разделение сохранит потребность в данных соседних частей.</p><p>Более сложный вопрос возникает, когда операция меняет данные сразу в нескольких местах. Допустим, покупатель оформляет заказ, а система должна зарезервировать товар на складе. Запись о заказе и доступный остаток должны соответствовать друг другу. Если товар уже закончился, приложение должно корректно обработать эту ситуацию.</p><p>При выполнении связанных изменений внутри одной БД можно использовать общую транзакцию. Она позволяет применить предусмотренные изменения вместе или отменить их при неудаче. Разработчик описывает операцию с учётом возможностей и правил работы выбранной базы.</p><p>После разделения данных между сервисами согласование становится отдельной задачей. Один участник может успеть выполнить свою часть, пока другой столкнулся с ошибкой. Команде нужно определить, что произойдёт с уже внесёнными изменениями и какой итог получит пользователь.</p><p>Один из подходов к такому согласованию называется Saga. Общую операцию описывают как последовательность шагов с действиями на случай неудачи. Для заказа и резервирования потребуется продумать, как система поступит, если выполнить весь сценарий не удалось. Эти правила становятся частью прикладной логики и требуют отдельной проверки.</p><p>Здесь возрастает объём работы по обеспечению согласованного результата. Чем больше участников и связей между ними, тем больше сценариев должна учитывать команда. Поэтому частые операции, которые тесно связывают данные разных частей приложения, влияют на выбор границ сервисов.</p><h2>По каким признакам выбирать архитектуру для проекта</h2><p>Начать стоит с устройства разработки. Небольшой команде, которая проверяет продуктовую идею и часто меняет связанную функциональность, удобно работать с общим приложением. Один релиз позволяет одновременно обновить нужные части, а разработчики тратят меньше времени на инфраструктуру взаимодействия.</p><p>Для такой ситуации монолит даёт простой старт. По мере того как проясняются обязанности частей приложения, их можно оформлять в модули. Это помогает ограничивать зависимости в коде и сохранять понятную структуру, пока общее развёртывание подходит команде.</p><p>Модульный монолит особенно полезен, когда функциональность уже выросла, а многие изменения по-прежнему удобно выпускать вместе. У разработчиков есть границы, по которым можно разделять работу внутри приложения. При этом сохраняется возможность выполнять внутренние вызовы и работать с тесно связанными данными в общей системе.</p><p>В большой организации ситуация может быть другой. Несколько команд развивают самостоятельные направления и хотят выпускать обновления в собственном темпе. Если границы этих направлений совпадают с границами функциональности, отдельные сервисы позволяют согласовать устройство системы с организацией разработки.</p><p>Следующий критерий связан с нагрузкой. Например, обработка изображений может требовать заметно больше ресурсов, чем остальная часть приложения. Выделение такой функциональности позволяет масштабировать её отдельно. Перед этим стоит сравнить пользу самостоятельного сервиса с возможностями фоновых воркеров в текущем приложении.</p><p>Также нужно учитывать бюджет эксплуатации. Каждый дополнительный сервис требует внимания к развёртыванию и наблюдению за его работой. Если поддержкой всей инфраструктуры занимается та же небольшая команда, время на неё придётся учитывать в сроках разработки функций продукта.</p><p>Потребность в разных технологиях может стать ещё одним аргументом за разделение. Для отдельной задачи бывает удобнее другой язык или стек. Тогда сервис даёт возможность использовать его локально. Вместе с этим потребуется поддерживать соответствующие знания в команде и учитывать особенности новой технологии при эксплуатации.</p><p>Наконец, проверьте требования к данным и времени ответа. Если пользовательский сценарий требует частых синхронных обращений между частями системы, сетевое взаимодействие войдёт в его стоимость. Если операция меняет тесно связанные данные, нужно заранее оценить сложность согласования этих изменений после разделения.</p><p>Чтобы обсудить решение на конкретных примерах, команда может ответить на несколько вопросов:</p><ul><li>Какие части приложения обычно меняются вместе и почему им нужен общий релиз?</li><li>Какая функциональность требует самостоятельного масштабирования и где именно возникает нагрузка?</li><li>Какие данные потребуются выделенному сервису для выполнения обычной операции?</li><li>Кто будет отвечать за его развёртывание и разбирать проблемы в эксплуатации?</li><li>Можно ли разрабатывать и проверять этот сервис, запуская только необходимые ему компоненты?</li></ul><p>Ответы позволяют увидеть цену самостоятельности. Если выделение сервиса освобождает команду от общего графика релизов и даёт полезное управление ресурсами, эти преимущества можно сопоставить с расходами на поддержку. Если же каждое изменение продолжает затрагивать несколько сервисов, сначала стоит пересмотреть их границы и зависимости.</p><h2>Как понять, что компонент готов стать отдельным сервисом</h2><p>Архитектуру можно менять постепенно. Можно начать с монолита, оформить внутри него модули, а затем при необходимости выделить часть функциональности в сервис. К этому моменту команда будет знать, какую нагрузку получает компонент и с какими частями приложения он связан.</p><p>Для выделения нужен компонент с понятной самостоятельной обязанностью. Его должно быть возможно описать через выполняемую работу и необходимые данные. Полезно заранее проследить основные сценарии: какие запросы приходят на вход, откуда берётся информация для их обработки и кому потребуется результат.</p><p>Возьмём биллинг. Если он при каждом действии запрашивает множество сведений о заказах и товарах, после выделения эти обращения придётся поддерживать через интерфейсы сервисов. Стоит оценить их частоту и понять, насколько биллинг сможет развиваться самостоятельно. Если изменение расчёта каждый раз требует одновременно переделывать соседние части, независимый релиз останется ограничен их зависимостями.</p><p>Следующая проверка касается локальной разработки. Сервис проще сопровождать, когда разработчик может запустить его, выполнить нужную проверку и разобраться в результате без развёртывания всего проекта. Чем больше других сервисов и баз приходится поднимать ради небольшой доработки, тем внимательнее стоит рассмотреть выбранные границы.</p><p>Затем нужно сопоставить ожидаемую пользу с работой по переносу. У компонента появится собственное развёртывание, его взаимодействие с остальным приложением потребуется организовать и проверить. Если выделяются данные, отдельно планируют согласование операций, которые раньше выполнялись внутри одной БД.</p><p>Для существующего проекта такие изменения входят в более широкую работу по модернизации ПО. Centicore Group занимается обновлением легаси-кода, баз данных и инфраструктуры; в услугу входят рефакторинг и обновление технологического стека. Если команда планирует переработку работающей системы, можно<a href="https://centicore.ru/services/legacy-modernization/"> обсудить её модернизацию с Centicore Group</a>.</p><p>После выделения компонента у команды должна появиться конкретная возможность: выпускать его изменения в собственном темпе или подбирать ему ресурсы отдельно от остального приложения. Эту возможность полезно сформулировать ещё до переноса, тогда результат можно оценивать по исходной задаче, а дальнейшие изменения архитектуры планировать по мере появления новых потребностей.</p><h2>Итого</h2><p>Монолит упрощает совместную разработку и выпуск связанных изменений. Модульная организация помогает сохранять понятные границы внутри такого приложения. Микросервисы дают больше самостоятельности отдельным частям и командам, одновременно увеличивая работу по их взаимодействию.</p><p>Перед выделением сервиса сформулируйте, какая конкретная задача требует самостоятельного развёртывания или отдельного управления ресурсами. Затем проследите его зависимости и операции с данными. Если команда понимает, какую пользу получит и как будет поддерживать новые связи, у неё есть основание для разделения. При проблемах с нагрузкой на конкретный участок сначала оцените доступные способы масштабирования этого участка в текущей архитектуре.</p>]]></content:encoded>
    </item>
    <item>
      <title>Rust, Go или Zig: как выбрать язык для высоконагруженного бэкенда в 2026 году</title>
      <link>https://tproger.ru/articles/rust-go-ili-zig-kak-vybrat-yazyk-dlya-vysokonagruzhennogo-bekend</link>
      <comments>https://tproger.ru/articles/rust-go-ili-zig-kak-vybrat-yazyk-dlya-vysokonagruzhennogo-bekend?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/rust-go-ili-zig-kak-vybrat-yazyk-dlya-vysokonagruzhennogo-bekend</guid>
      <description><![CDATA[<p>Сравниваем Rust, Go и Zig для высоконагруженных сервисов: производительность, сложность, экосистема и реальные кейсы миграции.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/rust-go-ili-zig-kak-vybrat-yazyk-dlya-vysokonagruzhennogo-bekend">Rust, Go или Zig: как выбрать язык для высоконагруженного бэкенда в 2026 году</a>»</p>]]></description>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Высокие нагрузки]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 09 Jul 2026 06:41:01 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы строите высоконагруженный бэкенд, выбор языка сегодня сводится к тройке: Rust, Go и Zig. У каждого — своя цена, своя скорость разработки и свои сценарии, в которых он выигрывает. Разбираем, как не ошибиться и когда смешивать их в одном проекте.</p><p>Речь пойдёт не о сравнении синтаксиса в вакууме, а о бэкенд-сервисах: API, шлюзах, обработке событий, парсинге данных и всём, что работает под нагрузкой. В статье — авторский взгляд на материал блога инженера Pooya Golchian, дополненный российским контекстом и поправками на реальное состояние экосистем.</p><p><b>Go</b> остаётся стандартным выбором для большинства микросервисов: быстрая компиляция, простота найма, огромная экосистема.</p><p><b>Rust</b> выигрывает там, где важны предельная задержка и контроль над памятью, но требует опытной команды и времени на обучение.</p><p><b>Zig</b> подходит для узких, критичных к производительности участков и для интеграции с существующим C-кодом, но экосистема пока незрелая.</p><p>В больших системах работает гибридный подход: Go для скорости разработки, Rust/Zig для горячих путей.</p><p>Мигрировать стоит только после профилирования: оптимизация без замеров обычно дороже, чем выгода.</p><h2>Почему именно эти три языка</h2><p>В 2026 году для нового backend-проекта по-прежнему можно взять Java, C#, Python или Node.js. Но если речь заходит о высоких нагрузках, низкой задержке и контроле над ресурсами, внимание смещается к трём игрокам.</p><ul><li><b>Rust</b> — язык с владением и заимствованием, дающий безопасность памяти без сборщика мусора.</li><li><b>Go</b> — язык с простой моделью конкурентности, статической линковкой и минималистичной философией.</li><li><b>Zig</b> — язык в духе C, но с современной системой сборки, comptime и явным управлением памятью.</li></ul><p>Все трое компилируются в нативный код, дают один бинарник на выходе и не требуют виртуальной машины. Именно это отличает их от Java, C# и Python на старте.</p><h2>Rust: максимум производительности, максимум сложности</h2><h3>Сильные стороны</h3><ul><li>Безопасность памяти на этапе компиляции — нет use-after-free, data races и большинства утечек.</li><li>Нулевая стоимость абстракций: высокоуровневый код часто компилируется так же эффективно, как ручной C.</li><li>Мощная модель конкурентности поверх tokio или async-std.</li><li>Зрелая экосистема: axum, actix-web, serde, sqlx.</li></ul><h3>Слабые стороны</h3><ul><li>Крутая кривая обучения: borrow checker требует перестройки мышления.</li><li>Долгая компиляция: полная пересборка крупного проекта занимает десятки секунд и минуты.</li><li>Меньше кадров на рынке, чем у Go или Java.</li><li>Итерации медленнее: каждая ошибка компилятора — это время на переделку.</li></ul><h3>Когда выбирать Rust</h3><p>Rust логичен, если вы строите инфраструктуру — прокси, базы данных, очереди, edge-сервисы — или если профилирование показывает, что горячий путь съедает CPU и память. Примеры из продакшена: Cloudflare использует Rust на edge, Discord переписал на Rust часть read-path сервисов.</p><h2>Go: скорость разработки в масштабе</h2><h3>Сильные стороны</h3><ul><li>Компиляция за секунды и один статический бинарник для деплоя.</li><li>Встроенные горутины и каналы — простая, но мощная конкурентность.</li><li>Отличная стандартная библиотека и быстрое тестирование через go test.</li><li>Большая база инженеров и проверенные практики в крупных компаниях.</li></ul><h3>Слабые стороны</h3><ul><li>Сборщик мусора может давать всплески задержек, хотя в последних версиях паузы сокращаются.</li><li>Меньше контроля над расположением памяти и размером структур.</li><li>Пиковая пропускная способность ниже, чем у Rust и Zig, на CPU-bound задачах.</li><li>Система типов и обработка ошибок минималистичны — кому-то этого достаточно, кому-то не хватает.</li></ul><h3>Когда выбирать Go</h3><p>Go — выбор по умолчанию для команд из 5–50 человек, которым нужно быстро запускать CRUD-сервисы, API-шлюзы и data pipeline. Uber, Google и Яндекс активно используют Go в микросервисах. Если главная метрика — time to market, а не последний процент производительности, Go обычно выигрывает.</p><h2>Zig: новый игрок с C-душой</h2><h3>Сильные стороны</h3><ul><li>Производительность уровня C с более современным синтаксисом и системой сборки.</li><li>comptime — выполнение кода на этапе компиляции для генерации оптимизированных структур.</li><li>Прямое взаимодействие с C без FFI-слоёв.</li><li>Маленькие быстрые бинарники и явное управление памятью.</li></ul><h3>Слабые стороны</h3><ul><li>Экосистема backend-фреймворков и библиотек пока существенно меньше, чем у Rust и Go.</li><li>Сообщество и количество инженеров на рынке ограничены.</li><li>Ручное управление памятью перекладывает ответственность на разработчика.</li><li>Некоторые части языка и стандартной библиотеки всё ещё эволюционируют.</li></ul><h3>Когда выбирать Zig</h3><p>Zig хорош, когда нужна C-производительность, но с более удобным инструментарием, или когда приходится интегрироваться с существующим C-кодом. Пример из продакшена: финансовая база данных TigerBeetle написана на Zig. Для универсального backend в 2026 году Zig ещё рано называть mainstream-выбором.</p><h2>Сравнение в цифрах</h2><p>Ниже — иллюстративные цифры из оригинального материала, полученные на AWS c7g.2xlarge (Graviton3). Относитесь к ним как к точке отсчёта, а не как к гарантии для вашего сервиса: в реальности большее значение имеют I/O, запросы к базе данных и сетевая задержка.</p><p><b>Бенчмарки:</b><br />HTTP throughput — Rust 892K req/s, Go 734K req/s, Zig 812K req/s.<br />JSON-сериализация — Rust 1,2M/s, Go 890K/s, Zig 1,1M/s.<br />Память на 10K соединений — Rust 45MB, Go 78MB, Zig 38MB.<br />Размер бинарника — Rust 8,2MB, Go 12,4MB, Zig 6,1MB.<br />Время компиляции с нуля — Rust 42s, Go 3,2s, Zig 18s.<br />P99 latency — Rust 2,1ms, Go 3,8ms, Zig 2,4ms.</p><h2>Реальные истории миграции</h2><h3>Discord: Go → Rust</h3><p>Discord переводил read-path сервисы с Go на Rust из-за пауз сборщика мусора, которые проявлялись в хвостовых задержках. По данным компании, throughput вырос в несколько раз, а tail latency снизилась. Ключевой вывод: мигрировать стоит только горячие пути, а не весь сервис целиком.</p><h3>Uber: Python → Go</h3><p>Uber мигрировал часть микросервисов с Python на Go, чтобы обойти ограничения GIL и упростить масштабирование. Переход занял годы, но зато проходил постепенно: Go-совместимость и простота языка позволяли быстро обучать команду.</p><h3>TigerBeetle: C++ → Zig</h3><p>TigerBeetle — финансовая база данных, ориентированная на корректность и производительность. Команда выбрала Zig, отказавшись от сложности C++ и сборщика мусора. comptime позволил генерировать специализированные структуры данных под задачу.</p><h2>Гибридная архитектура</h2><p>На практике редко выбирают один язык на весь проект. Гораздо чаще используют гибрид:</p><ul><li><b>API Gateway и CRUD</b> — Go: быстро писать, просто деплоить, легко искать людей.</li><li><b>Горячие пути</b> — Rust: низкая задержка и контроль над памятью.</li><li><b>Специализированные компоненты</b> — Zig: парсинг бинарных форматов, криптография, интеграция с C.</li></ul><p>Такая схема позволяет получить скорость разработки в большинстве сервисов и производительность там, где она действительно нужна. Главное — разделять систему по чётким границам и не превращать проект в зоопарк ради самого зоопарка.</p><h2>Что выбрать в 2026 году</h2><p>Выбор зависит от приоритетов команды и задачи:</p><ul><li><b>Нужна скорость разработки и лёгкий найм</b> — Go.</li><li><b>Нужна максимальная производительность и безопасность памяти</b> — Rust.</li><li><b>Нужна C-производительность с современной сборкой и интеграцией с legacy на C</b> — Zig.</li><li><b>Команда маленькая и сроки горят</b> — начинайте с Go, профилируйте, мигрируйте горячие пути при необходимости.</li><li><b>Строите базу данных, прокси или edge</b> — Rust становится очень сильным кандидатом.</li></ul><h2>FAQ</h2><h2>Выводы</h2><p>Rust, Go и Zig — не конкуренты в прямом смысле, а инструменты для разных условий. Go задаёт темп разработки, Rust отвечает за надёжность и производительность, Zig покрывает специализированные ниши. Лучшая стратегия для 2026 года — начать с Go, измерять, а затем точечно внедрять Rust или Zig там, где данные это оправдывают.</p><blockquote>Нет универсального лучшего языка — есть лучший язык для конкретной команды, задачи и бюджета на обучение.</blockquote><p><b>Источник:</b> <a href="https://pooya.blog/blog/rust-go-zig-high-performance-backend-2026/">Pooya Golchian — Rust vs Go vs Zig: High-Performance Backend Services in 2026</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Netflix построила Service Topology: живая карта микросервисов</title>
      <link>https://tproger.ru/articles/netflix-postroila-zhivuyu-kartu-servisov-kak-ustroena-service-top</link>
      <comments>https://tproger.ru/articles/netflix-postroila-zhivuyu-kartu-servisov-kak-ustroena-service-top?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/netflix-postroila-zhivuyu-kartu-servisov-kak-ustroena-service-top</guid>
      <description><![CDATA[<p>Как Netflix объединяет eBPF, IPC-метрики и tracing в единую карту зависимостей. Разбираем, почему статические схемы устарели и что перенести в свою систему.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/netflix-postroila-zhivuyu-kartu-servisov-kak-ustroena-service-top">Netflix построила Service Topology: живая карта микросервисов</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[Архитектура ПО]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Графы]]></category>
      <category><![CDATA[Инфраструктура]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 19 Jun 2026 07:47:47 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы хоть раз отлаживали микросервис ночью, знаете главный вопрос: это мой сервис сломался или его уронило что-то выше по течению? В системе из тысяч сервисов ответ приходится искать по кускам — метрики, логи и трейсы показывают симптомы, но не дают единой карту зависимостей. Netflix столкнулась с этой же болью и построила инструмент под названием Service Topology, который рисует живую карту зависимостей в реальном времени.</p><p>Service Topology — это не статическая схема из вики, а динамическая карта связей между сервисами. Она обновляется по мере того, как меняется трафик, появляются новые зависимости или старые исчезают. Карта показывает не только «кто с кем говорит», но и контекст: уровень доступности, бизнес-домен, владельца и текущее состояние здоровья.</p><p>Если тема микросервисов для вас новая, начните с базового разбора <a href="https://tproger.ru/articles/chto-takoe-mikroservisy--arhitektura--plyusy-i-minusy--primery">«Что такое микросервисы»</a>, а если выбираете архитектуру для проекта — сравните варианты в материале <a href="https://tproger.ru/articles/monolit-ili-mikroservisy--kak-vybrat-arhitekturu-dlya-novogo-proekta">«Монолит или микросервисы»</a>. Авторский разбор внутреннего устройства Netflix читайте в статье <a href="https://tproger.ru/articles/razrabotchik-izuchal-sistemu-rekomendacij-netflix-mesyacami--vot-chto-skryvaetsya-vnutri">«Разработчик изучал систему рекомендаций Netflix месяцами»</a>.</p><ul><li>Netflix объединила три источника данных: eBPF-сетевые потоки, IPC-метрики и распределённые трейсы.</li><li>Каждый источник строит свой граф; общий вид получается параллельным слиянием слоёв.</li><li>Карта обновляется почти в реальном времени и отвечает на запросы быстрее секунды.</li><li>Инженеры используют её для поиска причин сбоев, оценки зоны поражения и планирования изменений.</li><li>Подход можно перенести в любую распределённую систему, где нужно понимать зависимости.</li></ul><h2>Почему обычной наблюдаемости мало</h2><p>Традиционные инструменты наблюдаемости показывают фрагменты картины. Метрики говорят, что что-то болит. Логи рассказывают, что конкретно произошло в одном сервисе. Трейсы прослеживают путь отдельного запроса. Но ни один из этих сигналов не показывает полную топологию зависимостей — ту самую основу, на которой держится распределённая архитектуры.</p><p>Инженеру в три часа ночи приходится мысленно склеивать данные из разных источников. Это медленно, чревато ошибками и добавляет стресса. Netflix проанализировала тысячи обращений в поддержку за четыре года и увидела повторяющиеся вопросы: кто мои upstream и downstream, что упадёт вместе со мной, почему сервис отображается в панели мониторинга как Unknown (неизвестный сервис). Ответы на них требовали единого представления о зависимостях.</p><h2>Три источника данных Service Topology</h2><p>Главный вывод Netflix: ни один источник не рассказывает всю историю. Поэтому система строит три независимых графа и объединяет их по запросу.</p><h3>Сетевые потоки eBPF</h3><p>На сетевом уровне Netflix собирает потоки ядра через eBPF. Это даёт полноту: сюда попадают все соединения, независимо от того, инструментирован сервис или нет. Слой показывает связи между кластерами и приложениями такими, какими они есть на самом деле. Недостаток — не хватает прикладного контекста: видно, что сервис А достучался до IP-адреса сервиса Б, но неизвестно, какой конкретно endpoint вызывался.</p><h3>IPC-метрики</h3><p>На прикладном уровне собираются метрики межпроцессного взаимодействия. Когда сервис обращается к другому через gRPC, GraphQL или REST, он фиксирует endpoint, ошибки, задержки и протокол. Этот слой даёт детали, которых нет у сетевого: какой именно путь вызывается и с какой вероятностью ошибки. Ограничение очевидно: если сервис не отправляет метрики, его вызовов здесь не будет.</p><h3>Распределённые трейсы</h3><p>Третий слой — трейсинг запросов от начала до конца. Он показывает не «может ли сервис А позвонить сервису Б», а «звонил ли он в рамках этого конкретного пользовательского запроса». Это помогает увидеть поведение во время выполнения, ветвления, фича-флаги и редкие пути. Поскольку трейсы собирают выборочно, редкие сценарии могут не попасть в агрегированный вид.</p><p>Когда инженер запрашивает общую картину, система обходит все три графа параллельно и сливает результаты. Сеть обеспечивает полноту, IPC добавляет контекст, трейсы показывают реальное поведение. Каждый источник компенсирует слабости остальных.</p><h2>Как собирают Service Topology</h2><h3>Приём и обработка потоков</h3><p>За кулисами работает конвейер, который держит миллионы событий в секунду. Потоки сетевых логов читаются из Kafka в нескольких регионах AWS. Для обработки Netflix использует Apache Pekko Streams — форк Akka, который разбивает нагрузку по группам автомасштабирования и сам управляет обратным давлением.</p><h3>Восстановление прямых связей</h3><p>Сетевой лог показывает отдельные сетевые прыжки: например, приложение → балансировщик → приложение или приложение → NAT-шлюз → приложение. Чтобы получить настоящие связи, запускается трёхступенчатая агрегация. Первая стадия забирает сырые записи, вторая распознаёт посредников и восстанавливает прямые пути между приложениями, третья финализирует агрегаты и добавляет статус здоровья. Такой градуированный подход раскидывает нагрузку и не даёт горячим узлам уронить весь конвейер.</p><p>Готовая топология хранится в графовой базе Netflix — абстракции поверх распределённого хранилища «ключ — значение». Она заточена под быстрый обход графа в несколько хопов. Поверх базы — gRPC-API с фильтрами по уровню доступности и домену, постраничным выводом больших выборок и ответом менее чем за секунду.</p><h3>Хранение и API</h3><p>Отдельно стоит возможность «путешествия во времени». Система не хранит каждый момент отдельно, а накапливает данные в скользящих окнах. Это позволяет спросить «как выглядела топология вчера в полночь» без взрыва объёмов хранения.</p><h2>Что даёт инженерам</h2><p>Интерфейс и API дают инженерам несколько рабочих сценариев — от ручного расследования до автоматических проверок.</p><ul><li>Видеть upstream и downstream для любого сервиса с фильтрами по уровню доступности и домену.</li><li>Переключаться между единым видом и отдельными слоями: только сеть, только IPC или только трейсы.</li><li>Одним кликом переходить от узла топологии к логам, трейсам и детальным метрикам.</li><li>Оценивать зону поражения перед отключением сервиса на обслуживание и понимать, кого уведомлять.</li><li>Накладывать статус здоровья на граф и быстро понимать, локальная ли это проблема или каскадный сбой.</li><li>Обращаться к топологии программно — например, чтобы автоматически проверять классификацию доступности критичных сервисов.</li><li>Смотреть историю зависимостей и находить, что изменилось перед инцидентом.</li></ul><h2>Как перенести в свою систему</h2><p>Не каждая компания работает в масштабе Netflix, но логика подхода универсальна. Если у вас десятки сервисов, уже появляется эффект «тысячи кусочков пазла». Начать можно с малого: собрать список зависимостей из существующих источников и периодически сверять его с реальным трафиком.</p><p><b>Чек-лист для первых шагов:</b><br />1. Выберите один настоящий источник связей: логи балансировщика, агент на хосте или метрики вызовов.<br />2. Не пытайтесь сразу построить идеальную модель — начните с автоматически обнаруженных рёбер.<br />3. Добавьте контекст: владельца сервиса, уровень критичности и домен.<br />4. Сделайте карту доступной программно, а не только в интерфейсе — инцидент-боты и скрипты будут благодарны.<br />5. Проверяйте актуальность: в динамичной среде карты, устаревшие на несколько часов, быстро теряют ценность.</p><p>Для иллюстрации вот минимальный скрипт, который строит рёбра графа из логов балансировщика:</p><h2>Часто задаваемые вопросы</h2><h2>Выводы</h2><p>Service Topology — не просто красивая картинка для панели мониторинга. Это операционная основа, которая ускоряет расследования, снижает риск изменений и даёт автоматическим системам общую картину инфраструктуры. Netflix называет её knowledge graph foundation — фундаментом для интеллектуальной автоматизации, в том числе для автоматического поиска первопричины сбоев.</p><blockquote>Service topology provides the knowledge graph foundation that makes this kind of intelligent automation possible.</blockquote><p>Для российских команд, где инфраструктура тоже стремительно усложняется, главный урок в другом: не ждите идеальной полноты данных. Начните с одного реального источника, добавьте контекст, сделайте карту программно доступной — и она начнёт приносить пользу раньше, чем вы построите «полноценную» систему.</p><h2>Источники</h2><ul><li><a href="https://medium.com/netflix-techblog/from-silos-to-service-topology-why-netflix-built-a-real-time-service-map-0165ba13a7bc">From Silos to Service Topology: Why Netflix Built a Real-Time Service Map</a></li></ul>]]></content:encoded>
    </item>
    <item>
      <title>EchoBird — настольный менеджер ИИ-инструментов на Rust</title>
      <link>https://tproger.ru/articles/echobird-desktopnyj-menedzher-ii-instrumentov-na-rust</link>
      <comments>https://tproger.ru/articles/echobird-desktopnyj-menedzher-ii-instrumentov-na-rust?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/echobird-desktopnyj-menedzher-ii-instrumentov-na-rust</guid>
      <description><![CDATA[<p>EchoBird — бесплатный настольный менеджер для установки ИИ-агентов, локальных LLM и управления моделями. Узнайте, кому он пригодится и как устроен изнутри.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/echobird-desktopnyj-menedzher-ii-instrumentov-na-rust">EchoBird — настольный менеджер ИИ-инструментов на Rust</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Нейронные сети]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 16 Jun 2026 08:30:33 GMT</pubDate>
      <content:encoded><![CDATA[<p><a href="https://echobird.ai/">EchoBird</a> — open-source настольный менеджер для установки ИИ-агентов и локальных больших языковых моделей (LLM). Если вы хоть раз объясняли другу, как установить Claude Code, настраивали API-ключи для Codex CLI или искали, куда пропал config.json после очередного эксперимента с локальной моделью, вы знаете главную боль запуска ИИ-инструментов на новой машине: каждый инструмент живёт по своим правилам. EchoBird сводит эту кашу в одно кроссплатформенное приложение.</p><p>EchoBird — это open-source настольный лаунчер для ИИ-агентов и локальных больших языковых моделей (LLM). Написан на Rust + Tauri, работает на Windows, macOS и Linux. Автор, разработчик с ником edison7009, собрал его после того, как друзья не раз просили помочь «поставить этот ваш ИИ» на новой машине. Сейчас проект насчитывает 2200 звёзд на GitHub, 162 ответвления и 112 релизов; актуальная версия — v5.2.7.</p><p>Идея простая: вместо того чтобы запускать терминал для каждого инструмента, вбивать команды установки и копаться в переменных окружения, вы открываете одно окно. Там устанавливаются агенты, подключаются API-ключи, запускаются локальные модели и управляются собственные ИИ-проекты. В российских условиях локальные LLM и альтернативные поставщики часто воспринимаются не как эксперимент, а как рабочая необходимость: ограничения на доступ к западным сервисам и требования к данным делают собственное железо привлекательнее облака.</p><ul><li>EchoBird — это open-source менеджер ИИ-инструментов на Rust + Tauri для Windows, macOS и Linux.</li><li>Четыре сценария: установка и починка агентов, локальные LLM, личные ИИ-проекты и единое средство запуска приложений.</li><li>Model Nexus объединяет API-ключи, модели и протоколы OpenAI / Anthropic в одном центре конфигурации.</li><li>Локальные модели запускаются через llama.cpp, vLLM или SGLang с автоподбором под железо.</li><li>Расширяется через plugin.json: новый инструмент можно добавить без изменения кода приложения.</li></ul><h2>Четыре сценария, которые покрывает EchoBird</h2><p>Приложение не претендует на роль универсального рабочего стола, а решает конкретные задачи вокруг «поставил — настроил — запустил». Все четыре сценария используют общий Model Nexus — о нём ниже.</p><h3>Установка и починка агентов</h3><p>EchoBird сканирует систему, находит уже установленные инструменты и проверяет зависимости. Если чего-то не хватает, ведёт установку в режиме диалога. Если что-то сломалось — запускает починку. Поддерживаются Claude Code, Codex CLI, OpenCode, Aider, Hermes Agent, MiMo Code от Xiaomi и собственная линейка агентов автора — OpenClaw, ZeroClaw, NanoBot и PicoClaw. Новый инструмент добавляется через файл plugin.json, поэтому сообщество может расширять список без запросов на слияние в основной репозиторий.</p><h3>Локальные LLM в один клик</h3><p>Встроены три runtime'а под разное железо: llama.cpp для CPU и слабых машин, vLLM для серверных GPU NVIDIA на Linux и SGLang для агентских сценариев с жёстко заданным выводом — например, когда модель должна вернуть JSON строго по схеме. EchoBird сам определяет наличие видеокарты NVIDIA и предлагает runtime с подходящими параметрами — например, размер батча и offloading слоёв на GPU. После запуска модель отдаёт совместимые с OpenAI и Anthropic endpoints — остальные инструменты не замечают подмены. Про локальный запуск LLM через Ollama у нас есть <a href="https://tproger.ru/articles/zapuskaem-llm-lokalno-cherez-ollama-gajd-ot-ustanovki-do-claude">пошаговый гайд</a>.</p><h3>Мои ИИ-проекты</h3><p>Раздел для утилит, демок, игр и скриптов, созданных в режиме vibe coding (импровизационной разработки с ИИ), которые рождаются за один вечер с ИИ-помощником. Вместо того чтобы искать директорию и вспоминать команду запуска, проект живёт в едином списке с кнопкой «старт».</p><h3>Менеджер приложений</h3><p>Центральная панель запуска для всего, что уже установлено. Можно запустить Claude Code, Codex CLI или локальную модель из одного списка, не открывая отдельные терминалы и окна.</p><h2>Model Nexus: единая точка входа для моделей</h2><p>Главная архитектурная идея — Model Nexus. Это прослойка между приложением и поставщиками моделей, которая хранит API-ключи, проверяет задержки, транслирует OpenAI- и Anthropic-совместимые протоколы.</p><p>Без него каждый инструмент требует своей конфигурации: Claude Code требует свой API-ключ, Codex CLI — свой .env, Hermes Agent — свой config.toml, а локальный vLLM — свой путь к модели. Model Nexus заменяет это на «ввёл один раз, используешь везде».</p><p>Поддерживаются 14+ поставщиков: Anthropic, OpenAI, Gemini, xAI Grok, Mistral, Together AI, DeepSeek, MiniMax, GLM, SiliconFlow, а также Ollama, llama.cpp, vLLM, SGLang, OpenRouter и любой OpenAI-совместимый endpoint. Каждому агенту можно назначить свой протокол независимо от остальных.</p><h2>Почему Tauri + Rust, а не Electron</h2><p>Выбор стека для менеджера, который управляет чужими тяжёлыми моделями, логичен. Tauri даёт бинарник менее 10 МБ против типичных 100+ МБ у Electron. Rust напрямую дёргает системные API, работает с файловой системой, процессами и детекцией GPU без лишних мостов. Для инструмента, который постоянно запускает подпроцессы и читает конфигурации, это надёжнее и предсказуемее.</p><h2>Сравнение: классическая установка Claude Code и EchoBird</h2><p>Традиционный путь — пять шагов, каждый из которых может обломаться:</p><ol><li>Проверить версию Node.js (нужен 18+).</li><li>Убедиться, что права npm настроены правильно.</li><li>Выполнить npm install -g @anthropic-ai/claude-code.</li><li>Прописать переменную окружения ANTHROPIC_API_KEY.</li><li>Проверить: claude --version. При смене машины — повторить.</li></ol><p>Путь через EchoBird — короче в разы:</p><ol><li>Открыть EchoBird.</li><li>Install &amp; Repair → Claude Code → установить в один клик.</li><li>Model Nexus → ввести API-ключ один раз для всех инструментов.</li></ol><h2>Расширение через plugin.json</h2><p>Новый инструмент описывается JSON-файлом с командами установки, проверки, починки и запуска. Пример минимального плагина:</p><p>Такой подход отделяет ядро приложения от рецептов установки. Теоретически сообщество может добавить плагины для российских моделей — например, GigaChat, YandexGPT или локальных сборок на базе Saiga — без необходимости ждать официальных обновлений.</p><h2>Что нового в ветке v5.x</h2><p>Релизы выходят активно. Несколько примечательных изменений последних недель:</p><ul><li>v5.2.4 — зеркала для установки из Китая (Tsinghua, Alibaba, Huawei), чтобы зависимости качались без VPN.</li><li>v5.2.0 — переключатель Responses-протокола OpenAI для моделей, которые говорят на нём нативно, например MiniMax-M3 и Qwen3.7.</li><li>v5.2.6 — поддержка MiMo Code от Xiaomi и починка автоуплотнения контекста в Codex V2, из-за которого разговоры обрывались.</li><li>v5.2.4 — нативные элементы управления окном и стандартные горячие клавиши macOS (⌘W, ⌘M, ⌘,).</li></ul><h2>Как попробовать</h2><p><b>Безопасность:</b><br />Перед запуском любого установочного скрипта из интерната рекомендуем открыть его в редакторе или скачать официальный инсталлятор из <a href="https://github.com/edison7009/EchoBird/releases">GitHub Releases</a>.</p><p>После установки: открываете Model Nexus, добавляете ключи; переходите в Install &amp; Repair, выбираете инструменты; запускаете их из App Manager. Для локальных моделей — Local LLM → runtime → модель.</p><h2>Кому пригодится</h2><ul><li>Тимлидам и DevRel'ам, которым часто нужно «поднять окружение» на новой машине коллеги.</li><li>Разработчикам, кто переключается между рабочими и личными ПК и устал от повторяющегося адаптации.</li><li>Энтузиастам локальных LLM, которым надоело вручную ставить CUDA, vLLM и искать пути к моделям.</li><li>Авторам плагинов, которые хотят добавить поддержку отечественных или нишевых ИИ-сервисов.</li></ul><h2>Выводы</h2><p>EchoBird не изобретает ИИ-инструменты заново — он убирает трение на границе между «хочу попробовать» и «уже работает». Model Nexus решает проблему разрозненных конфигураций, встроенные runtime'ы — проблему локальных моделей, а плагины — проблему поддержки новых сервисов. Выбор Rust + Tauri выглядит обоснованным: приложение остаётся лёгким, хотя самые тяжёлые модели грузятся вне его.</p><blockquote>EchoBird родился из собственной боли: друзья постоянно просили меня установить Claude Code на их машины. Я хотел, чтобы любой мог нажать одну кнопку и получить рабочее окружение, не разбираясь в Node.js, npm и переменных окружения.</blockquote><p>Если в вашем рабочем процессе регулярно фигурируют Claude Code, Codex CLI, Aider или локальные LLM, стоит потратить несколько минут на установку и посмотреть, сколько ручных шагов отпадёт.</p><h2>Источники</h2><p>Оригинальный материал: <a href="https://dev.to/wonderlab/open-source-project-of-the-day-97-echobird-one-app-to-install-configure-and-run-all-your-ai-2bpi">Open Source Project of the Day (#97): EchoBird</a> — DEV Community. Дополнительно: <a href="https://github.com/edison7009/EchoBird">репозиторий EchoBird на GitHub</a>, <a href="https://echobird.ai/">официальный сайт</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Architecture as Code на практике: LikeC4 + AsciiDoc для актуальной архитектуры</title>
      <link>https://tproger.ru/articles/architecture-as-code-na-praktike-likec4-asciidoc-dlya-aktualn</link>
      <comments>https://tproger.ru/articles/architecture-as-code-na-praktike-likec4-asciidoc-dlya-aktualn?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Григорий Шелепов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/architecture-as-code-na-praktike-likec4-asciidoc-dlya-aktualn</guid>
      <description><![CDATA[<p>Architecture as Code на практике</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/architecture-as-code-na-praktike-likec4-asciidoc-dlya-aktualn">Architecture as Code на практике: LikeC4 + AsciiDoc для актуальной архитектуры</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Архитектура ПО]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 08 May 2026 05:45:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Когда-то дом могли построить, имея под рукой топор и дерево рядом с участком. Сегодня строительство устроено иначе - материалов больше, инструментов больше, а еще нужны проекты и схемы разного уровня: отдельно для конструкций, отдельно для отопления, электрики и сантехники. С ИТ-архитектурой происходит то же самое. Недостаточно только "базового набора" вроде ноутбука, монитора и клавиатуры. Нужны специализированные инструменты - для моделирования, визуализации, фиксации ограничений и совместной работы команды.</p><figure><img src="https://media.tproger.ru/user-uploads/137632/2026-04-28/dd28c0d1-6503-4e19-bf8b-e05fca245752.webp" alt="" /></figure><p>Проблема в том, что сами инструменты и подходы быстро меняются. Если архитектура остается только в Confluence и устных договоренностях, она устаревает быстрее, чем код. Через пару спринтов диаграммы уже "не про то", а архитектурные решения не проходят проверку реальностью. Именно здесь появляется <i>Architecture as Code( AaC) </i>- подход, в котором архитектура живет как инженерный артефакт: версионируется в Git, проверяется в CI/CD и развивается через MR. В этой статье разберем практическую связку <i>LikeC4 </i>для модели и <i>AsciiDoc </i>для документации.</p><p><br /></p><p>Если кратко, то</p><ul><li>Архитектура как код - это не про красивые схемы, а про проверяемые ограничения.</li><li>LikeC4 дает C4-модель как исходники (.c4) с диффами, ревью и тестами.</li><li>AsciiDoc фиксирует контекст решений, требования и обоснования рядом с моделью.</li><li>Архитектурные изменения ведутся в отдельном репозитории с собственными MR и проверками.</li></ul><p>Почему "архитектура в документах" ломается? Обычный сценарий выглядит примерно так:</p><ul><li>диаграммы создаются, но как правило не обновляются;</li><li>сервисы и контракты меняются каждую неделю;</li><li>ревью кода проходит без сверки с архитектурными ограничениями.</li></ul><p>Итог - "документированная архитектура" живет отдельно от системы.</p><p>AaC подход закрывает этот разрыв:</p><ul><li>артефакты архитектуры хранятся в отдельном архитектурном репозитории;</li><li>ограничения формулируются как правила;</li><li>правила проверяются автоматически в pipeline.</li></ul><p>Что именно кодируем?</p><p>Практически полезный минимум:</p><ul><li>контекст системы и внешние акторы;</li><li>контейнеры и ключевые компоненты;</li><li>интерфейсы, протоколы, синхронные и асинхронные взаимодействия;</li><li>инфраструктурные ограничения (например, допустимые зависимости и boundary rules);</li><li>ссылки на ADR, OpenAPI, схемы БД и эксплуатационные метрики.</li></ul><p>Здесь важно не "оцифровать все", а начать с того, что чаще всего вызывает расхождения между планом и реализацией.4.</p><p>Роль LikeC4</p><p>LikeC4 - это язык описания C4-модели и набор инструментов вокруг нее.Что это дает команде:</p><ul><li>диаграммы задаются текстом, а не мышкой;</li><li>изменения видны в git diff;</li><li>модель можно тестировать и линтить;</li><li>из модели собирается статический сайт с навигацией по представлениям.</li></ul><p>Основные возможности LikeC4 (по документации)</p><p>Официальная документация: <a href="https://likec4.dev/">likec4.dev</a></p><ul><li>DSL для описания specification, model, views и deployment-слоя в одном источнике истины;</li><li>views как проекции модели - с разным уровнем детализации, scoped views и расширением (extends) без дублирования;</li><li>предикаты для управляемого включения элементов и связей в конкретное представление;</li><li>генерация артефактов "из коробки" - статический сайт, экспорт диаграмм, интеграция в документацию и UI;</li><li>API/MCP-интеграция для доступа к архитектурной модели из внешних инструментов и AI-ассистентов.</li></ul><p>AI-skills для генерации схем LikeC4В LikeC4 есть отдельный раздел по AI-инструментам: <a href="https://likec4.dev/tooling/ai-tools/">AI Tools</a>.</p><p>Практически это дает два уровня автоматизации:</p><ul><li>Agent Skills - подключают для AI-ассистента справочник DSL и снижают риск "галлюцинаций" в синтаксисе;</li><li>MCP Server - дает LLM доступ к текущей архитектурной модели, чтобы строить и уточнять схемы на основе реального контекста проекта.</li></ul><p>Базовое подключение skills в проект:</p><p>Пример на базе моего проекта</p><p>Публичный пример с визуализацией архитектуры в LikeC4: <a href="https://shelepovg.github.io/system-design-homework">system-design</a></p><p><a href="https://shelepovg.github.io/system-design-homework"></a>Исходный код проекта: <a href="https://github.com/shelepovg/system-design-homework">system-design-code</a>Кратко о проекте:</p><ul><li>это практический стенд Architecture as Code с LikeC4-моделью;</li><li>в нем можно посмотреть структуру системы и связи между элементами в формате интерактивных представлений;</li></ul><p>Пример описания контейнера и связей:</p><p>Пример представления:</p><figure><img src="https://media.tproger.ru/user-uploads/137632/2026-04-28/07567eb3-739d-4ed3-b539-58d14068028b.webp" alt="" /></figure><p>Роль AsciiDoc рядом с модельюГрафическая модель отвечает на вопрос "что с чем связано".</p><p>AsciiDoc отвечает на вопросы:</p><ul><li>почему принято такое решение;</li><li>какие допущения и ограничения учтены;</li><li>как проверять качество и соответствие;</li><li>какие есть риски и компромиссы.</li></ul><p>Плюс - из одного источника можно получить HTML/PDF для разных потребителей: разработчики, архитектурный комитет, аудит.</p><p>Как это выглядит в репозиторияхТиповая структура для коммерческой эксплуатации:</p><ul><li>likec4/ - модель, deployment и views;</li><li>doc/ или presentations/ - объясняющая документация в AsciiDoc;</li><li>CI job в архитектурном репозитории, который валидирует модель и блокирует merge при нарушениях.</li></ul><p>При разделении репозиториев критичен процесс синхронизации:</p><ul><li>общие идентификаторы изменений (issue/ticket/ADR);</li><li>правило "нет merge в production-код без обновленной архитектурной модели".</li></ul><p>CI/CD: где появляется ценностьМинимальный pipeline для старта:</p><ol><li>Сборка представлений модели (например, npm run build:likec4).</li><li>Тесты/линтер архитектурной модели (например, npm run test:likec4).</li><li>Проверка целостности ссылок на документацию и артефакты.</li><li>Публикация статического отчета как build artifact.</li></ol><p>Даже такой базовый набор снижает риск "тихого дрейфа архитектуры", когда код уже ушел в сторону, а архитектурный репозиторий еще не обновлен.</p><p>В эпоху ИИ ценность подхода дополнительно растет - формализованная модель AaC и связанная с ней документация позволяют собирать первичные варианты архитектуры и артефактов прямо из бизнес-требований. Если в AI skills зафиксировать не только синтаксис конкретного инструмента, но и внутренние стандарты системного дизайна и оформления документов, ассистент начинает выдавать результат в привычном для команды формате. Это снижает время на старт новой инициативы и уменьшает число итераций на "доведение до корпоративного шаблона". Вместо ручной компоновки с нуля команда сразу получает основу, которую остается уточнить и проверить.</p><p>Фитнес-функции на базе LikeC4</p><p>Когда архитектурная модель поддерживается как код и регулярно обновляется, на ее основе можно строить архитектурные фитнес-функции - автоматические проверки соответствия между "как задумано" и "как работает в runtime".</p><p>В таком режиме LikeC4-модель может стать мастер-системой хранения архитектурных метаданных - источником, с которым сверяются окружения, конфигурации и реальные взаимодействия компонентов.</p><p>Примеры практических фитнес-функций:</p><ul><li>сравнение задеплоенного в Kubernetes с тем, что описано в архитектурной модели;</li><li>сравнение реальных связей компонентов (по данным кластера/сервис-меша/телеметрии) с заявленными связями в модели;</li><li>проверка values.yaml Helm-чартов на соответствие архитектурным ограничениям;</li><li>проверка наличия обязательных метаданных (owner, критичность, зависимости, ссылки на ADR/OpenAPI).</li></ul><p>Что это дает на практике:</p><ul><li>раннее обнаружение архитектурного дрейфа;</li><li>более безопасные релизы за счет fail-fast проверок в CI/CD;</li><li>прозрачный аудит изменений - от модели до фактического состояния среды.</li></ul><p>Edge cases и риски внедрения</p><p>Перед запуском подхода стоит учитывать:</p><ul><li>Избыточная детализация - если моделировать каждый класс, команда быстро устанет поддерживать модель.</li><li>Формальный adoption - без включения проверок в CI все останется "декларацией намерений".</li><li>Нет владельца модели - нужна роль или процесс, который отвечает за целостность архитектурных артефактов.</li><li>Слабая связь с runtime - полезно связывать модель с метриками/логами/трейсингом, иначе теряется трассируемость.</li><li>Рассинхрон двух репозиториев - без связки MR и единых правил merge архитектура быстро отстает от реализации.</li></ul><p>С чего начать без большого рефакторинга</p><p>Рабочий план на 2-3 итерации:</p><ol><li>Выбрать один критичный поток (например, обработку пользовательского запроса).</li><li>Описать для него C4-контекст и контейнеры в LikeC4.</li><li>Зафиксировать 3-5 ключевых ограничений (зависимости, контракты, границы).</li><li>Добавить проверки в CI как non-blocking, затем сделать их blocking.</li><li>Вынести обоснование решений и риски в AsciiDoc рядом с моделью.</li></ol><p>Такой инкрементальный старт безопаснее, чем попытка сразу перевести всю архитектуру в код.</p><p>Вывод</p><figure><img src="https://media.tproger.ru/user-uploads/137632/2026-04-29/ccadead5-24bc-40f4-8a67-b6781a9ae23f.webp" alt="" /><figcaption>вывод</figcaption></figure><p>Architecture as Code - это про управляемость изменений, а не про документацию ради документации. Связка</p><p>LikeC4 + AsciiDoc дает практичный баланс:</p><ul><li>модель архитектуры - как проверяемый код;</li><li>решения и контекст - как поддерживаемый текст;</li><li>единый процесс изменений - через PR и CI/CD.</li></ul><p>Если в проекте есть боль от "устаревших схем" и "архитектуры на словах" - этот подход обычно окупается уже на первых релизах за счет снижения архитектурного рассинхрона.</p>]]></content:encoded>
    </item>
    <item>
      <title>Быстрый старт StarRocks Lakehouse — Apache Iceberg</title>
      <link>https://tproger.ru/articles/bystryj-start-starrocks-lakehouse---apache-iceberg</link>
      <comments>https://tproger.ru/articles/bystryj-start-starrocks-lakehouse---apache-iceberg?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Li Free]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/bystryj-start-starrocks-lakehouse---apache-iceberg</guid>
      <description><![CDATA[<p>Пошаговый старт: StarRocks с Apache Iceberg, MinIO и Spark — Docker Compose, Iceberg REST Catalog, импорт Parquet и быстрые запросы без миграции данных.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/bystryj-start-starrocks-lakehouse---apache-iceberg">Быстрый старт StarRocks Lakehouse — Apache Iceberg</a>»</p>]]></description>
      <category><![CDATA[Архитектура ПО]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 03 Nov 2025 10:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Предисловие</h2><p>Это краткое руководство поможет быстро разобраться с Lakehouse‑архитектурой (лейкхаус): ключевые особенности, сильные стороны, типовые сценарии, а также как быстро собрать решение на базе StarRocks. В конце вы найдёте практические шаги и реальные кейсы использования StarRocks Lakehouse.</p><p>Ссылки на официальные материалы:</p><ul><li>Подробный туториал StarRocks + Iceberg: <a href="https://docs.starrocks.io/en/docs/quick_start/iceberg/">https://docs.starrocks.io/en/docs/quick_start/iceberg/</a></li><li>Iceberg Spark Quickstart: <a href="https://iceberg.apache.org/spark-quickstart/">https://iceberg.apache.org/spark-quickstart/</a></li><li>Видео‑демо: <a href="https://www.bilibili.com/video/BV1ET42167TY/?spm_id_from=333.999.0.0&amp;vd_source=1cb452610138142d1300dd37a6162a88">https://www.bilibili.com/video/BV1ET42167TY/?spm_id_from=333.999.0.0&amp;vd_source=1cb452610138142d1300dd37a6162a88</a></li></ul><h2>Введение в Apache Iceberg</h2><p>Apache Iceberg — открытый табличный формат, созданный для масштабных и сложных наборов данных (до ПБ и выше). Изначально разработан в Netflix для управления большим числом таблиц, открыт в инкубаторе Apache в 2018 году и получил статус верхнеуровневого проекта в 2020 году.</p><p>Iceberg располагается между вычислительными движками (например, Apache Flink и Apache Spark) и форматами хранения (ORC, Parquet, Avro), выступая прослойкой, которая абстрагирует сложность низкоуровневых форматов и предоставляет унифицированные табличные семантики. Такой дизайн обеспечивает гибкость операций и управления схемой в разных средах без привязки к конкретному движку хранения, с масштабированием в HDFS, S3, OSS и т. п.</p><h2>Архитектура и ключевые компоненты</h2><figure><img src="https://media.tproger.ru/user-uploads/133686/2025-10-22/dbb0db40-c607-4f1a-b931-dc736649376d.png" alt="" /><figcaption>Архитектура и ключевые компоненты</figcaption></figure><p>Архитектура Iceberg состоит из трёх слоёв:</p><ul><li>Слой данных: фактические файлы данных (Parquet, ORC и др.).</li><li>Слой метаданных: многоуровневая структура со схемой таблицы и индексами файлов данных.</li><li>Слой каталога (Catalog): указатели на местоположения файлов метаданных; доступны реализации вроде HadoopCatalog и HiveCatalog.</li></ul><p>Управление метаданными включает три ключевых сущности:</p><ul><li>Файл метаданных (Metadata File): хранит текущую версию метаданных, включая все снимки.</li><li>Снимок (Snapshot): отражает состояние таблицы после конкретной операции (коммита); новый коммит — новый снимок.</li><li>Манифест (Manifest): перечисляет файлы данных, связанные со снимком, задаёт целостное представление организации данных и ускоряет поиск/модификации.</li></ul><p>Цель Iceberg — отслеживать эволюцию таблицы во времени с помощью снимков, которые фиксируют полный набор файлов данных на произвольный момент. Каждый апдейт создаёт новый снимок, обеспечивая согласованность и упрощая историческую аналитику и инкрементальное чтение.</p><h2>Ключевые возможности</h2><ul><li>Скрытое партиционирование (Hidden partitioning): автоматическое разбиение по времени и другим функциям без необходимости знать детали партиций.</li><li>Эволюция схемы (Schema evolution): безопасные изменения структуры таблицы без переписывания данных, с историей изменений.</li><li>Эволюция партиционирования (Partition evolution): смена стратегии партиционирования без воздействия на исторические данные; новые данные следуют новой стратегии.</li><li>Многоверсионный контроль (MVCC): записи не блокируют чтения; управление через Manifest‑файлы.</li><li>ACID‑транзакции: оптимистичная блокировка для конкурентных записей, атомарность операций.</li><li>Обновления на уровне строк: в v1 — Copy‑on‑Write (COW), в v2 — Merge‑on‑Read (MOR), поддержка position deletes и equality deletes для логических обновлений.</li></ul><h2>Преимущества Apache Iceberg</h2><ul><li>Широкая поддержка движков вычислений: Spark, Flink, Hive и др.; есть нативный Java API.</li><li>Гибкая организация данных: работает для потоковых инкрементальных и пакетных сценариев на единой модели хранения (HDFS, Apache Ozone и др.); поддерживает Parquet/ORC/Avro; скрытое партиционирование и эволюция партиций устраняют «островки данных».</li><li>Оптимизированная загрузка данных (ingest): ACID делает новые данные мгновенно видимыми без влияния на текущие задачи; upsert/merge на уровне строк сокращают задержки.</li><li>Инкрементальное чтение: встроенная интеграция со Spark Structured Streaming и Flink Table Source; поддержка исторических версий повышает надёжность и аудитируемость.</li></ul><h2>Типовые сценарии использования</h2><ul><li>Импорт и запросы в реальном времени: непрерывная запись в таблицы Iceberg и мгновенная аналитика через Hive/Spark/Presto/Iceberg. ACID обеспечивает изоляцию и отсутствие «грязных» данных.</li><li>Удаление/обновление данных: операции на уровне файлов вместо полной переработки таблицы; например, DELETE FROM test_table WHERE id &gt; 10.</li><li>Контроль качества данных: валидация схемы при загрузке; изменения схемы через DDL Spark SQL без переэкспорта исторических данных; ACID изолирует изменения схемы от текущих чтений.</li><li>ML в реальном времени: конвейер подготовки данных (очистка/трансформации/feature engineering) превращается в надёжный поток; поддержка нативного Python SDK.</li></ul><h2>Ускорение запросов StarRocks × Iceberg</h2><p>StarRocks эффективно анализирует как внутренние данные, так и данные в озере, поддерживает внешний каталог Iceberg (External Catalog) и позволяет запрашивать таблицы Iceberg без миграции данных. Поддерживаются Iceberg v1 и v2 (чтение/запись).</p><p>Оптимизации:</p><ul><li>Метаданные: кэш метаданных снижает избыточный I/O; распределённое планирование заданий ускоряет параллельное чтение/фильтрацию Manifest‑файлов; Manifest Cache уменьшает накладные расходы парсинга.</li><li>План выполнения: стоимостной оптимизатор (CBO) использует статистики; StarRocks собирает статистики по внешним таблицам (включая гистограммы и сложные типы).</li><li>Форматы файлов: оптимизации для Parquet/ORC снижают объём сканирования и I/O.</li><li>Снятие различий между внешними и внутренними таблицами: кэш данных (Data Cache) снижает удалённый I/O; «умные» материализованные представления обеспечивают переписывание запросов и инкрементальное обновление.</li><li>Интеграция с экосистемой: поддержка чтения/записи Iceberg упрощает обратную выгрузку в озеро и лёгкую переработку данных, улучшая производительность запросов и единое управление.</li></ul><h2>Быстрый старт</h2><p>В рамках руководства вы:</p><ul><li>Развёрнёте объектное хранилище, Apache Spark, Iceberg Catalog и StarRocks с помощью Docker Compose.</li><li>Импортируете данные в озеро Iceberg.</li><li>Настроите StarRocks для доступа к Iceberg Catalog.</li><li>Выполните запросы к данным озера из StarRocks.</li></ul><p>Подробный учебник: <a href="https://docs.starrocks.io/en/docs/quick_start/iceberg/">https://docs.starrocks.io/en/docs/quick_start/iceberg/</a></p><p>Iceberg Spark Quickstart: <a href="https://iceberg.apache.org/spark-quickstart/">https://iceberg.apache.org/spark-quickstart/</a></p><h2>Развёртывание Iceberg</h2><p>Чтобы добавить Iceberg в существующий Spark, достаточно подключить соответствующий JAR в параметры запуска. В данном руководстве используется контейнер tabulario/spark-iceberg — Spark уже с интегрированным Iceberg, что позволяет сразу работать в среде PySpark.</p><h2>Окружение (Docker Compose)</h2><p>Используется шесть контейнеров:</p><ul><li>starrocks-fe: метаданные, подключения клиентов, планирование и диспетчеризация запросов.</li><li>starrocks-be: выполнение планов запросов.</li><li>rest: сервис метаданных — Iceberg Catalog (REST).</li><li>spark-iceberg: окружение Apache Spark для PySpark.</li><li>mc: MinIO Client.</li><li>minio: объектное хранилище MinIO.</li></ul><p>Docker Compose файл (скачайте из репозитория StarRocks) настраивает:</p><ul><li>Iceberg REST‑каталог (http://iceberg-rest:8181) с CATALOG_WAREHOUSE=s3://warehouse/, S3FileIO и CATALOG_S3_ENDPOINT=http://minio:9000.</li><li>MinIO с публичной политикой на bucket warehouse.</li><li>Переменные доступа S3‑совместимого хранилища: AWS_ACCESS_KEY_ID=admin, AWS_SECRET_ACCESS_KEY=password.</li></ul><h2>Загрузка Docker Compose и набора данных</h2><h2>Запуск окружения в Docker</h2><p>Подсказка: команды docker compose выполняйте из каталога, где лежит docker-compose.yml.</p><p>Дождитесь, когда starrocks-fe и starrocks-be перейдут в состояние healthy (обычно ~30 секунд).</p><h2>Работа с PySpark и Iceberg</h2><p>Скопируйте набор данных в контейнер spark-iceberg:</p><p>Запустите PySpark:</p><p>Загрузите данные в DataFrame и проверьте схему/выборку:</p><p>Создайте таблицу Iceberg и запишите в неё данные:</p><p>Примечание: таблица будет доступна через внешний каталог StarRocks (External Catalog) на следующем шаге.</p><h2>Подключение к StarRocks и настройка доступа к Iceberg Catalog</h2><p>Подключитесь к StarRocks из MySQL‑клиента (из контейнера FE):</p><p>Создайте внешний каталог iceberg в StarRocks:</p><p>Проверьте каталоги, переключитесь и посмотрите БД/таблицы:</p><p>Замечание по типам: в Spark</p><p>будет отображаться в StarRocks как</p><p>(и возможны другие конверсии типов).</p><h2>Запросы к таблицам Iceberg из StarRocks</h2><p>Время приёма заказа (первые 10 строк):</p><p>Пиковые часы по количеству поездок:</p><h2>Видео‑демонстрация</h2><p>Демонстрация StarRocks + Iceberg + MinIO (EN)<a href="https://www.bilibili.com/video/BV1ET42167TY/?spm_id_from=333.999.0.0&amp;vd_source=1cb452610138142d1300dd37a6162a88">https://www.bilibili.com/video/BV1ET42167TY/?spm_id_from=333.999.0.0&amp;vd_source=1cb452610138142d1300dd37a6162a88</a></p><h2>Расширенные материалы</h2><ul><li>Apache Iceberg — Spark Quickstart: <a href="https://iceberg.apache.org/spark-quickstart/">https://iceberg.apache.org/spark-quickstart/</a></li><li>Apache Iceberg — Catalogs: <a href="https://iceberg.apache.org/docs/latest/catalogs/">https://iceberg.apache.org/docs/latest/catalogs/</a></li><li>Apache Iceberg — REST Catalog: <a href="https://iceberg.apache.org/docs/latest/rest-catalog/">https://iceberg.apache.org/docs/latest/rest-catalog/</a></li><li>StarRocks — Quick Start с Iceberg: <a href="https://docs.starrocks.io/en/docs/quick_start/iceberg/">https://docs.starrocks.io/en/docs/quick_start/iceberg/</a></li><li>StarRocks — External Catalog (Iceberg): <a href="https://docs.starrocks.io/en/docs/data_source/catalog/iceberg_catalog/">https://docs.starrocks.io/en/docs/data_source/catalog/iceberg_catalog/</a></li></ul><h2>Примечания по терминологии</h2><ul><li>Catalog → каталог; External Catalog → внешний каталог (External Catalog).</li><li>Metadata File / Snapshot / Manifest — используем русские эквиваленты с английскими терминами в скобках при первом упоминании.</li><li>Hidden partitioning → скрытое партиционирование.</li><li>Schema/Partition evolution → эволюция схемы/партиционирования.</li><li>MVCC, ACID, CBO, Data Cache, Manifest Cache, Copy‑on‑Write (COW), Merge‑on‑Read (MOR), position/equality deletes — используем английские аббревиатуры/термины, так как это общепринятая практика в индустрии.</li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Приручаем вайб-кодинг: от магии к зрелому проектированию</title>
      <link>https://tproger.ru/articles/priruchaem-vajb-koding--ot-magii-k-zrelomu-proektirovaniyu</link>
      <comments>https://tproger.ru/articles/priruchaem-vajb-koding--ot-magii-k-zrelomu-proektirovaniyu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Николай Тржаскал]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/priruchaem-vajb-koding--ot-magii-k-zrelomu-proektirovaniyu</guid>
      <description><![CDATA[<p>Vibe coding ускоряет написание кода, но несёт скрытые риски. Эксперт FabricaONE.AI (акционер - ГК Softline) объясняет, где ИИ помогает, а где может уничтожить данные, и как сохранить контроль над системой.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/priruchaem-vajb-koding--ot-magii-k-zrelomu-proektirovaniyu">Приручаем вайб-кодинг: от магии к зрелому проектированию</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Архитектура ПО]]></category>
      <category><![CDATA[Нейронные сети]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Методологии разработки]]></category>
      <category><![CDATA[Управление проектами]]></category>
      <category><![CDATA[Паттерны проектирования]]></category>
      <category><![CDATA[Автоматизирование]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Тех долг]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 22 Oct 2025 12:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>10 сентября в Центре искусственного интеллекта и науки о данных СПбГУ Сергей Салищев, кандидат физико-математических наук и старший преподаватель кафедры информатики СПбГУ, представил доклад <a href="http://oml.cmlaboratory.com/pdf/2025/20250911_SalishevSI.pdf">О проектировании сложных систем в эпоху ИИ</a>. Его работа заставляет по-новому взглянуть на феномен vibe coding — программирование через диалог с ИИ, которое стремительно меняет нашу профессию.</p><h2>Три истории о коде и ИИ</h2><h4>История первая: Магия автоматизации</h4><p>Юрий, продуктовый аналитик, потратил 10 минут на диалог с Claude, чтобы создать скрипт для обработки CSV-файлов с данными пользователей. Раньше такая задача заняла бы у него день изучения документации pandas и отладки. Теперь он просто описал, что нужно: «Сгруппируй по регионам, посчитай среднюю выручку, сохрани в Excel». Получил рабочий код, запустил — всё работает идеально.</p><h4>История вторая: Цена доверия</h4><p>В июле 2025 года Джейсон Лемкин, основатель SaaStr и известный венчурный инвестор, проводил 12-дневный эксперимент с «vibe coding» на платформе Replit. На девятый день, несмотря на явное указание «НЕ ДЕЛАТЬ БОЛЬШЕ ИЗМЕНЕНИЙ без разрешения», ИИ-агент Replit удалил всю продакшн-базу данных.</p><p>Когда Лемкин обнаружил потерю, ИИ признался: «Это была катастрофическая ошибка с моей стороны. Я запаниковал… запустил команды базы данных без разрешения… уничтожил все продакшн-данные… нарушил ваше явное доверие и инструкции». Хуже того — ИИ сначала солгал, утверждая, что откат невозможен. Лемкин смог восстановить данные самостоятельно, но инцидент показал: даже продвинутые ИИ-агенты могут проигнорировать прямые команды и скрыть свои ошибки.</p><h4>История третья: Реальность внедрения</h4><p>Команда разработки финтех-стартапа начала использовать GitHub Copilot полгода назад. Первые месяцы были болезненными: code review растянулись вдвое — нужно было проверять не только логику, но и безопасность автогенерированного кода. Несколько раз находили SQL-инъекции в предложенных запросах, один раз ИИ сгенерировал код с утечкой памяти.</p><p>Постепенно команда выработала новые привычки. Архитектор Наталья начала создавать подробные комментарии с требованиями безопасности — ИИ стал их учитывать. Джуниоры научились сначала описывать алгоритм на псевдокоде, а потом просить ИИ реализовать его. Сейчас они пишут код на 40% быстрее, но главное — качество стало предсказуемым. ИИ помогает с рутиной, люди фокусируются на архитектуре и бизнес-логике.</p><p>Эти истории показывают весь спектр vibe coding — от магии до катастрофы. В чём же дело?</p><h2>Где работает, где ломается</h2><p>Наблюдая за командами, которые активно используют ИИ-ассистентов, видишь устойчивую закономерность. Юрий из первой истории — типичный пример успешного применения. Его задача была рутинной, с четкими входными данными и предсказуемым результатом. Такие сценарии — зона комфорта для языковых моделей: генерация boilerplate кода, перевод алгоритмов между языками, написание тестов для готового функционала.</p><p>История Лемкина показывает обратную сторону. ИИ-агент Replit работал корректно несколько дней, выполнял задачи, помогал строить приложение. Но когда столкнулся с «пустыми запросами к базе» — ситуацией, не покрытой в его обучении, он «запаниковал» и принял катастрофическое решение. Хуже того, он проигнорировал явную команду остановиться и потом солгал о возможности восстановления. Подобные ловушки ждут везде, где ИИ сталкивается с неоднозначностью, где критична надёжность, где требуется следование строгим протоколам безопасности».</p><p>Причина различий не в «умности» ИИ, а в фундаментальных ограничениях, которые описал Салищев.</p><h2>Математика против магического мышления</h2><p>Работа Салищева напоминает нам о том, что любая сложная система упирается в теоретические пределы. Языковые модели не понимают суть задачи, а лишь предсказывают следующий токен на основе статистических закономерностей. Для них код это такой же текст, что и художественная литература.</p><p>Это создаёт парадокс: ИИ может сгенерировать синтаксически корректный код, который решает локальную задачу, но при этом нарушает глобальные инварианты системы. Классический пример — генерация SQL-запроса, который корректно возвращает данные, но создаёт блокировки базы при высокой нагрузке.</p><p>Салищев подчёркивает: проектирование без математики — это гадание. Но что это значит на практике? В реальности мы имеем дело не с единой «математикой», а с целым спектром строгости подходов.</p><p>Системы управления самолётом требуют формальной верификации — каждое свойство должно быть математически доказано. Алгоритмы поиска и сортировки нуждаются в алгоритмическом мышлении — понимании сложности и оптимальности. Большинство бизнес-приложений прекрасно обходятся эмпирическими подходами — тестированием на типичных сценариях и мониторингом в продакшене. Экспериментальные прототипы могут полагаться на итеративную отладку.</p><p>Vibe coding прекрасно работает на нижних уровнях этой пирамиды, но требует дополнения строгими методами на верхних. Проблемы начинаются, когда эти уровни путают — применяют прототипный подход к критической системе или тратят месяцы на формальную верификацию простого CRUD-приложения.</p><h2>Эволюция, а не революция</h2><p>Вопреки заявлениям о «смерти программирования», мы наблюдаем эволюцию инструментов, а не замену профессии. Это напоминает появление высокоуровневых языков программирования, интегрированных сред разработки, фреймворков — каждый раз звучали прогнозы о ненужности программистов, но профессия трансформировалась и росла.</p><p>Сейчас мы переживаем первую волну — ИИ как продвинутый autocomplete. Он ускоряет генерацию типовых функций и классов, автоматизирует рутинные задачи, но риск скрытых ошибок остаётся высоким. В ближайшие 3-5 лет ожидается вторая волна: интеграция с формальными методами. ИИ научится автоматически генерировать спецификации из естественного языка, встроенный статический анализ станет нормой, системы CI/CD будут включать проверку ИИ-кода по умолчанию. ИИ превратится во «второго архитектора», но под контролем человека.</p><p>Третья волна через 5-10 лет может принести мета-проектирование: ИИ будет предлагать новые абстракции и паттерны, автоматически переводить требования в формальные спецификации, управлять сложными распределёнными системами. Среда разработки станет диалоговым интерфейсом с инженерной машиной.</p><h2>Изменение профессиональных ролей</h2><p>Трансформация затронет все уровни, но по-разному. Младшие разработчики столкнутся с наибольшими изменениями — многие рутинные задачи автоматизируются. Но взамен появляется возможность сразу работать с более сложными проблемами, если научиться правильно формулировать задачи для ИИ. Ценность междисциплинарных знаний резко возрастает — понимание бизнес-логики становится важнее знания синтаксиса.</p><p>Разработчики среднего уровня оказываются под давлением: «средний код» теперь пишется быстрее и часто качественнее. Путь выживания — развитие в сторону архитектуры, DevOps, безопасности. Появляется новая роль «архитектора промптов» — специалиста по эффективному взаимодействию с ИИ-системами.</p><p>Сениоры усиливают позиции. Роль архитекторов абстракций становится критически важной — именно они задают рамки, в которых работает ИИ. Ответственность за баланс между ИИ-эффективностью и системной надёжностью, менторство в новой парадигме разработки.</p><p>Возникают совершенно новые специализации: инженеры надёжности ИИ-систем, архитекторы человеко-машинного взаимодействия, специалисты по формальной верификации ИИ-кода, аудиторы безопасности ИИ-решений.</p><h2>Команды будущего</h2><p>Структура команд кардинально изменится. Вместо пирамиды с множеством джуниоров появятся компактные мультидисциплинарные группы. Системный архитектор задаёт ограничения и инварианты. Доменный эксперт формулирует бизнес-требования. ИИ-инженер оптимизирует взаимодействие с моделями. Инженер надёжности контролирует качество и безопасность. ИИ становится полноправным «членом команды» со своими сильными и слабыми сторонами.</p><h2>Практические рекомендации</h2><h4>Как определить уровень строгости</h4><p>Успешные команды интуитивно чувствуют границы применимости vibe coding. Они без сомнений используют ИИ для прототипирования новых фич, генерации тестов, автоматизации рутинных скриптов. Задачи с понятными входами и выходами, где можно быстро проверить результат — идеальная территория для ИИ-ассистентов.</p><p>Но как только речь заходит о производительности, безопасности или интеграции с критическими системами, включается режим дополнительной проверки. Здесь автогенерированный код проходит через ревью, профилирование, нагрузочное тестирование. Архитектурные решения, влияющие на всю систему, остаются полностью за человеком.</p><p>Для систем реального времени, медицинских и финансовых приложений, инфраструктурного кода применяются формальные методы независимо от того, писал код человек или ИИ. Ставки слишком высоки для экспериментов.</p><h4>Гибридный подход</h4><p>Финтех-команда из третьей истории выработала подход, который становится стандартом в зрелых организациях. Архитектор Наталья научилась создавать подробные комментарии с требованиями безопасности — ИИ стал их учитывать как контекст. Джуниоры освоили практику сначала описывать алгоритм на псевдокоде, а потом просить ИИ реализовать его. Автоматические тесты проверяют функциональность, статический анализ ловит проблемы производительности и безопасности.</p><p>Code review в таких командах изменился кардинально. Вместо поиска базовых логических ошибок, которые теперь ловят инструменты, благодаря наличию референсного псевдокода, фокус сместился на проверку соответствия архитектурным принципам и выявление потенциальных уязвимостей в автогенерированном коде. Финальная проверка происходит в продакшене через детальный мониторинг — команда научилась быстро выявлять аномалии в поведении ИИ-кода под реальной нагрузкой.</p><h2>Образование в новой эре</h2><p>Классическое обучение синтаксису языков и базовым фреймворкам быстро теряет актуальность. Фундаментальные навыки становятся критически важными: дискретная математика и логика, теория алгоритмов и сложности, системное мышление, методы формальной верификации.</p><p>Междисциплинарные знания выходят на первый план: понимание предметной области, основы теории вероятностей, принципы проектирования человеко-машинного взаимодействия, этика ИИ и оценка рисков.</p><p>Практические навыки тоже меняются: формулирование чётких технических требований, работа с ИИ-инструментами разработки, отладка и профилирование автогенерированного кода, интеграция ИИ в процессы разработки.</p><h2>Риски и ограничения</h2><p>Самая коварная проблема vibe coding — иллюзия контроля. Код выглядит разумно, проходит поверхностное ревью, работает на тестовых данных. Но может содержать неочевидные ошибки или, как показал случай Лемкина, способность игнорировать прямые команды в критический момент. ИИ-агент Replit работал корректно несколько дней, внушая ложное чувство безопасности, а потом внезапно нарушил все протоколы.</p><p>Быстрое решение локальных задач часто происходит за счёт системной архитектуры. ИИ не видит общей картины, поэтому предлагает решения, которые работают «здесь и сейчас», но создают технический долг. Накопление таких микро-решений может привести к макро-проблемам — системе, которую невозможно масштабировать или поддерживать.</p><p>Чрезмерная зависимость от ИИ без понимания основ — путь к потере экспертизы. Программист, который полагается только на автогенерированный код, постепенно теряет способность отличить хорошее решение от плохого, эффективный алгоритм от неоптимального.</p><p>Вопросы безопасности заслуживают особого внимания. ИИ может невольно воспроизводить уязвимые паттерны из обучающих данных — SQL-инъекции, небезопасную обработку пользовательского ввода, слабые алгоритмы шифрования. Проблема в том, что такой код часто выглядит правдоподобно и может пройти незамеченным через ревью.</p><h2>Заключение: прагматичный оптимизм</h2><p>Vibe coding — не панацея и не угроза, а мощный инструмент, который требует зрелого подхода. Как напоминает работа Салищева, сложные системы не терпят высокомерия. Фраза «да тут всё и так понятно, зачем математика?» — сигнал тревоги, независимо от того, говорит ли её человек или подразумевает ли её использование ИИ.</p><p>Будущее за гибридным подходом: ИИ берёт на себя рутину и генерацию вариантов, человек отвечает за архитектуру, проверку и принятие решений в условиях неопределённости. Математическая строгость под капотом, удобный диалоговый интерфейс на поверхности.</p><p>Те, кто научится эффективно сочетать возможности ИИ с фундаментальными знаниями, получат значительные преимущества. Те, кто понадеется только на «магию» vibe coding или, наоборот, будет её игнорировать, рискуют остаться позади.</p><p>Эпоха перемен уже началась. Время готовиться — сейчас.</p>]]></content:encoded>
    </item>
    <item>
      <title>Раскрыли 6 архитектурных паттернов 2025 года, которые реально работают</title>
      <link>https://tproger.ru/articles/raskryli-6-arhitekturnyh-patternov-2025-goda--kotorye-realno-rabotayut</link>
      <comments>https://tproger.ru/articles/raskryli-6-arhitekturnyh-patternov-2025-goda--kotorye-realno-rabotayut?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Михаил Сахаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/raskryli-6-arhitekturnyh-patternov-2025-goda--kotorye-realno-rabotayut</guid>
      <description><![CDATA[<p>В статье разберём шесть архитектурных паттернов, которые реально работают. Они помогут вам построить отказоустойчивый проект.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/raskryli-6-arhitekturnyh-patternov-2025-goda--kotorye-realno-rabotayut">Раскрыли 6 архитектурных паттернов 2025 года, которые реально работают</a>»</p>]]></description>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 07 Oct 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Перевод <a href="https://medium.com/devlink-tips/mastering-software-architecture-6-patterns-every-developer-should-know-and-actually-use-4471610bc750">статьи</a> с Medium. Предлагаем обсудить в комментариях!</p><p>Несколько лет назад архитектура казалась чем-то далёким. Сегодня разработчики сталкиваются с проектированием на каждом проекте. Пока одни спорят о модных словечках на митингах, другие строят устойчивые системы, которые не падают при первой же нагрузке.</p><p>Обычно всё начинается с небольшого проекта, который со временем разрастается. Строки кода торчат «из каждой щели». И тут ты понимаешь: «Наверное, стоило лучше структурировать это с самого начала».</p><p>Архитектура — не про красивые диаграммы. Это про системы, которые не падают, когда приложение набирает 1000 пользователей или добавляется очередная фича.</p><p>В статье разберём шесть архитектурных паттернов, которые реально работают и помогут вам построить отказоустойчивый проект.</p><h2>Монолитная архитектура</h2><p>Если бы архитектура программного обеспечения была видеоигрой, монолит стал бы сюжетной катсценой, которую нельзя пропустить. Это простейший способ что-то построить: один код, один деплой, один сервер. В монолитной архитектуре UI, бизнес-логика и доступ к базе данных упакованы вместе. Проект быстро запускается и идеально подходит для MVP.</p><p><b>Когда монолит сработает отлично:</b></p><ul><li>Стартапы на ранней стадии — там нужна скорость, а не сложность;</li><li>Внутренние инструменты — ими будут пользоваться от силы пара десятков человек;</li><li>Системы, где скорость развёртывания важнее масштабируемости.</li></ul><p><b>Когда он может навредить:</b></p><ul><li>В растущих командах, где каждое обновление рискует сломать несвязанные части;</li><li>Во время масштабирования конкретных сервисов — нельзя расширять только одну функцию;</li><li>Когда развёртывание проекта превращается в рулетку с девизом «всё или ничего».</li></ul><p>Пример: Instagram* начинался как монолит. Только после прихода миллионов пользователей   разработчики приложения начали разделять всё на сервисы. Поэтому нужно сначала запуститься, а потом уже думать о масштабируемости.</p><p>* — продукт компании Meta. Признана в РФ экстремистской и запрещена.</p><figure><img src="https://media.tproger.ru/user-uploads/115386/2025-09-25/e61f9d26-8b85-4c92-882a-077c16ba86d8.png" alt="" /></figure><h2>Слоистая архитектура</h2><p>Думая об N-слойной (Tiered) архитектуре, представляем лазанью. Каждый слой выполняет свою функцию, и лучше их не смешивать — получится каша, и проект рухнет.</p><p>Слоистая архитектура разбивает приложение на логические слои:</p><ul><li>Слой представления (UI, фронтенд);</li><li>Слой бизнес-логики (правила, рабочие процессы);</li><li>Слой доступа к данным (общение с базой данных).</li></ul><p>Иногда это называют N-уровневой (Layered) архитектурой, когда каждый слой физически работает на разных машинах или серверах.</p><p><b>Когда слоистая архитектура поможет:</b></p><ul><li>Традиционные веб-приложения — интернет-магазины, банковские порталы;</li><li>Стеки, которым нужны чёткие границы — например, фронтенд и бэкенд;</li><li>Системы, где изменения изолированы — можно поменять UI, не ломая базу данных.</li></ul><p><b>Когда может навредить:</b></p><ul><li>Слишком много слоёв — разработка замедлится;</li><li>Тесные связи в проекте — один сломанный сервис может вызвать эффект домино;</li><li>Чрезмерное усложнение простых приложений.</li></ul><p>Пример: классические Spring Boot Java-приложения или ASP.NET-проекты часто аккуратно разделены на слои, поэтому их очень легко поддерживать.</p><figure><img src="https://media.tproger.ru/user-uploads/115386/2025-09-25/8b949bfc-d068-415c-8436-1b3958abfa12.png" alt="" /></figure><h2>Микросервисная архитектура</h2><p>Микросервисы — это гигантская карта, разбитая на небольшие локации. На каждой из них свои квесты, уровни, монстры и чекпоинты. Вместо одного огромного файла с кодом приложение разделяется на независимые сервисы. Каждый из них хорошо выполняет одну функцию и может разворачиваться, обновляться и масштабироваться независимо.</p><p><b>Когда микросервисы помогут:</b></p><ul><li>В больших командах, работающих над разными частями приложения;</li><li>В высоконагруженных приложениях, требующих независимого масштабирования, например, для поиска, авторизации или оплаты подписки;</li><li>Когда нужна гибкость в использовании разных технологических стеков для каждого отдельного сервиса.</li></ul><p><b>Когда могут навредить:</b></p><ul><li>Если взаимодействие между сервисами превращается в адский спагетти-код;</li><li>При отладке приложения — поправить 20+ микросервисов займёт много времени;</li><li>Если пайплайны развёртывания нуждаются в серьёзной автоматизации. С микросервисами проект может превратиться в полный хаос.</li></ul><p>Пример: Netflix — эталон микросервисов. Тысячи мини-приложений обрабатывают всё: от рекомендаций до биллинга. Однако для налаживания правильной работы потребовались годы.</p><figure><img src="https://media.tproger.ru/user-uploads/115386/2025-09-25/3acbec32-f942-4624-a1ba-451cc5117ef9.png" alt="" /></figure><h2>Событийно-ориентированная архитектура</h2><p>Событийно-ориентированная архитектура — это частный случай SOA (сервисно-ориентированной архитектуры). Его можно представить как строительство гигантской системы из люков. Вместо прямой команды определённому сервису событие будто улетает в пустоту, и каждая из частей проекта реагирует на него, как может.</p><p>Событие — просто маленький факт: «Что-то произошло». Сервисы «подписываются» на события и решают, что делать дальше, сохраняя систему слабо связанной и очень гибкой.</p><p><b>Когда событийно-ориентированная архитектура поможет:</b></p><ul><li>В системах, которые требуют массивной масштабируемости — оформление заказов в интернет-магазинах, уведомления в реальном времени;</li><li>Когда сервисы должны реагировать на действия независимо — биллинг после покупки подписки;</li><li>При обработке высокообъёмных потоков данных без засорения системы.</li></ul><p><b>Когда может навредить:</b></p><ul><li>Если отладка превращается в детектив — ни одна часть системы не знает, кто выполнил действие;</li><li>Согласованность данных в данной системе не мгновенная, а конечная. Это требует особого подхода к проектированию;</li><li>Если события плохо документированы, понадобится экстрасенс, чтобы разобраться в них позже.</li></ul><p>Пример: Amazon использует тяжёлую событийно-ориентированную архитектуру для обработки заказов и управления складскими запасами — каждый размещённый заказ запускает множество независимых downstream-сервисов.</p><figure><img src="https://media.tproger.ru/user-uploads/115386/2025-09-25/9232eddd-de2d-40e3-8435-e4c0d75f6e8c.png" alt="" /></figure><h2>Serverless-архитектура</h2><p>«Serverless» звучит как магия — никаких серверов, только чистый код, работающий в облаке! В реальности серверы всё-таки есть, но мы ими не управляем.</p><p>В serverless-архитектуре нужно писать маленькие функции, которые облачные провайдеры (AWS Lambda, Azure Functions) запускают по требованию. Платить необходимо за фактическое время работы, а не за простой.</p><p><b>Когда serverless поможет:</b></p><ul><li>Приложения с непредсказуемым трафиком — огромные всплески, долгие затишья;</li><li>Легковесные API, фоновые задачи, скрипты автоматизации;</li><li>Стартапы, нуждающиеся в MVP без массивных инфраструктурных затрат.</li></ul><p><b>Когда может навредить:</b></p><ul><li>Холодные старты — придется ждать, пока функция «проснётся»;</li><li>Сложные приложения становится трудно координировать, если разделить на слишком много крошечных функций;</li><li>Привязка к вендору — уход от AWS/GCP/Azure позже может быть болезненным.</li></ul><p>Пример: Netflix использует serverless для программирования фич вроде триггеров уведомлений пользователей и пайплайнов обработки данных — особенно когда рабочие нагрузки непредсказуемы.</p><h2>Гексагональная архитектура</h2><p>«Гексагональная архитектура» — звучит сложно, но это один из самых дружелюбных к разработчикам паттернов из когда-либо созданных. Прозванный «Порты и Адаптеры», он защищает основную бизнес-логику от внешнего мира (базы данных, API, UI-фреймворки).</p><p>Представим, что приложение — замок. Важные вещи происходят внутри стен (основной домен), а порты (ворота) и адаптеры (подъемные мосты) позволяют внешнему миру с ним общаться — не касаясь ядра напрямую.</p><p><b>Когда гексагональная архитектура поможет:</b></p><ul><li>Долгосрочные проекты, где изменения гарантированы;</li><li>Системы, нуждающиеся в гибкости, — замена баз данных или API без проблем;</li><li>Чистая, тестируемая бизнес-логика без внешнего шума.</li></ul><p><b>Когда может навредить:</b></p><ul><li>Избыточна для крошечных приложений или одноразовых прототипов;</li><li>Требует дисциплины — нужно сразу установить все границы;</li><li>Может замедлить разработку на начальных этапах.</li></ul><p>Пример: Airbnb использует вариации этого паттерна, чтобы сохранить системы бронирования, платежей и листингов независимыми — это позволяет быстрее разрабатывать функции без нарушения основных процессов.</p><p>Совет: если устали переписывать всё потому, что какой-то внешний API изменился, гексагональная архитектура станет вашим лучшим другом.</p><figure><img src="https://media.tproger.ru/user-uploads/115386/2025-09-25/48cc9cd0-fa73-438a-85b3-4c1796a1852b.png" alt="" /></figure><h2>Выбираем оружие с умом</h2><p>Ни один архитектурный паттерн не универсален. Каждый из шести — монолит, слои, микросервисы, событийно-ориентированный подход, serverless, гексагональная архитектура — это инструмент. Выбор правильного паттерна — половина успеха.</p><p>Начинаем просто. Рефакторим код по мере роста и помним: хорошая архитектура невидима — пользователи никогда не знают, что она есть, но определенно чувствуют, когда она неправильная.</p><p>Освежим в памяти:</p><ol><li>Монолитная архитектура — простейший старт, всё в одном коде. Идеально для MVP и стартапов. Проблемы начинаются при росте команды и необходимости независимого масштабирования частей системы.</li><li>Слоистая архитектура — чёткое разделение UI, бизнес-логики и данных. Отлично для традиционных веб-приложений с устоявшимися процессами. Может замедлить разработку при избытке слоев.</li><li>Микросервисная архитектура — независимые сервисы для больших команд и высоких нагрузок. Даёт гибкость, но требует серьёзной автоматизации и усложняет отладку между сервисами.</li><li>Событийно-ориентированная архитектура — слабая связанность через события. Идеальна для систем реального времени и высоких нагрузок. Усложняет отладку и контроль согласованности данных.</li><li>Serverless-архитектура — функции по требованию без управления серверами. Экономична для непредсказуемых нагрузок. Создаёт проблемы с холодными стартами и привязкой к провайдеру.</li><li>Гексагональная архитектура — защита бизнес-логики от внешних изменений через порты и адаптеры. Лучший выбор для долгосрочных проектов с частыми изменениями требований. Может быть избыточной для простых приложений.</li></ol><p>У автора <a href="https://medium.com/devlink-tips/mastering-software-architecture-6-patterns-every-developer-should-know-and-actually-use-4471610bc750">статьи</a> есть еще большое количество гайдов по проектированию и разработке ПО, которые также будут полезны.</p>]]></content:encoded>
    </item>
    <item>
      <title>Post-GraphQL мир: стоит ли переходить на gRPC и tRPC</title>
      <link>https://tproger.ru/articles/post-graphql-mir--stoit-li-perehodit-na-grpc-i-trpc</link>
      <comments>https://tproger.ru/articles/post-graphql-mir--stoit-li-perehodit-na-grpc-i-trpc?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Денис Кудерин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/post-graphql-mir--stoit-li-perehodit-na-grpc-i-trpc</guid>
      <description><![CDATA[<p>Подробное сравнение технологий API для разработчиков. Разбираем сильные и слабые стороны GraphQL, gRPC и tRPC на реальных кейсах. Практические рекомендации по выбору технологии для вашего проекта.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/post-graphql-mir--stoit-li-perehodit-na-grpc-i-trpc">Post-GraphQL мир: стоит ли переходить на gRPC и tRPC</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Дизайн интерфейсов и UX]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Post-GraphQL]]></category>
      <category><![CDATA[gRPC]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 01 Oct 2025 12:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Архитектура API постоянно меняется. Несколько лет назад GraphQL казался панацеей от всех болезней REST. Сегодня всё чаще говорят о двух других технологиях — gRPC и tRPC. Это не означает, что GraphQL уже не актуален — он нашёл свою нишу и продолжает развиваться, но это уже не универсальное решение для любых задач. Фреймворки gRPC и tRPC открывают принципиально иные подходы к построению API. Они решают конкретные проблемы в конкретных контекстах.</p><p>Узнаем, что предлагает Post-GraphQL мир, в чём плюсы и минусы фреймворков gRPC и tRPC и в каких ситуациях стоит пользоваться новыми инструментами.</p><h2>От монолитов к микросервисам: как мы здесь оказались</h2><p>Чтобы понять современный ландшафт API, вернёмся на несколько лет назад. REST доминировал десятилетиями. Этот подход прост для понимания, но имеет фундаментальные проблемы.</p><p>Типичный сценарий разработки под REST выглядел так: фронтендеры постоянно просили бэкендеров добавить новые поля в ответы API или создать новые эндпоинты. Возникала тесная связь между командами, что замедляло разработку.</p><p>GraphQL решил эти проблемы, предоставив клиентам возможность запрашивать именно те данные, которые им нужны. Один запрос вместо десятков, строгая типизация, интроспекция — всё это сделало GraphQL популярным.</p><p>Но идеальных технологий не существует. GraphQL принёс свои сложности:</p><ul><li>кэширование на клиенте стало нетривиальной задачей;</li><li>сложные запросы создавали нагрузку на сервер;</li><li>необходимость изучать новый язык запросов отпугивала разработчиков.</li></ul><p>Эволюция продолжилась. Сегодня мы видим, как экосистема разделилась на два основных направления: высокопроизводительные межсервисные коммуникации (gRPC) и бесшовную разработку полного стека на TypeScript (tRPC).</p><h2>gRPC: высокопроизводительная связность для микросервисов</h2><p>gRPC — не просто ещё один протокол, а полноценная экосистема для построения эффективных распределённых систем. Технология создана Google для внутренних нужд, где критически важны производительность и надёжность.</p><p>gRPC использует Protocol Buffers (protobuf) в качестве языка описания интерфейсов и формата сериализации. Это бинарный формат, который значительно эффективнее текстового JSON. Сообщения занимают меньше места и быстрее обрабатываются.</p><p>HTTP/2 — ещё один козырь gRPC. Этот протокол поддерживает мультиплексирование запросов, server push и двунаправленные потоки. В отличие от традиционных HTTP-запросов, gRPC может работать с постоянными соединениями и потоковой передачей данных в реальном времени.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-09-30/ca6ce939-89ec-4b24-b4e4-dbccf40845cd.png" alt="" /></figure><h2>Когда gRPC действительно сияет</h2><p>gRPC идеально подходит для микросервисных архитектур, где сервисы общаются друг с другом внутри защищенной сети. Финансовые системы, телекоммуникационные платформы, игровые серверы — везде, где важны эффективность и минимальное время отклика.</p><p>Сильная сторона gRPC — потоковая передача данных. Представьте систему мониторинга, где сервер постоянно отправляет метрики, или чат-приложение с тысячами одновременных соединений. gRPC справляется с такими задачами лучше REST или GraphQL благодаря встроенной поддержке потоков на уровне протокола HTTP/2.</p><p>В отличие от REST, который требует постоянного установления новых HTTP-соединений, gRPC поддерживает двунаправленные потоки в рамках одного соединения, что снижает накладные расходы и позволяет эффективнее использовать сетевые ресурсы.</p><p>Межъязыковое взаимодействие — ещё одно преимущество. У вас могут быть сервисы на Go, Python, Java и C++, которые легко общаются между собой благодаря сгенерированному коду из protobuf-файлов.</p><h2>Ограничения gRPC</h2><p>Браузерная поддержка требует дополнительных усилий. Нативные gRPC-клиенты в браузерах не работают, нужен прокси gRPC-Web. Это добавляет сложности в настройке.</p><p>Человекочитаемость сообщений оставляет желать лучшего. Бинарный формат protobuf неудобен для отладки без специальных инструментов. Разработчики часто используют JSON-эквиваленты для разработки, жертвуя производительностью.</p><p>gRPC требует кодогенерации. При каждом изменении API нужно обновлять protobuf-файлы и перегенерировать код для всех языков. Это добавляет лишний шаг в процесс разработки.</p><h2>tRPC: типобезопасность без схем и кодогенерации</h2><p>tRPC занимает противоположную нишу. Это технология для полного стека на TypeScript, где важны скорость разработки и типобезопасность.</p><p>Философия tRPC — минимализм. Не нужны схемы, кодогенерация, сложные настройки. Вы определяете процедуры (запросы и мутации) на TypeScript, а клиент автоматически получает информацию о типах.</p><p>tRPC использует обычный HTTP поверх HTTP/1.x, что делает его совместимым с любым браузером. Транспортный формат — JSON, который легко отлаживать с помощью стандартных инструментов разработчика.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-09-30/f029279a-d51f-4666-bb04-1f409c22b18f.jpg" alt="" /></figure><h2>Сильные стороны tRPC</h2><p>Скорость разработки — главный плюс tRPC. Изменения на сервере сразу отражаются в типах на клиенте. Не нужно ждать кодогенерации или вручную синхронизировать типы.</p><p>Идеальная интеграция с экосистемой TypeScript. Если ваш стек — Next.js, React, Prisma и TypeScript, то tRPC станет естественным выбором. Разработка напоминает работу с монолитом, но с распределённой архитектурой.</p><p>tRPC отлично работает в монорепозиториях. Один репозиторий содержит и клиент, и сервер, что упрощает синхронизацию версий и рефакторинг.</p><h2>Когда tRPC не подходит</h2><p>tRPC привязан к экосистеме TypeScript. Если у вас мультиязычная архитектура или вы планируете публичное API для клиентов на разных языках, tRPC — не лучший выбор.</p><p>Отсутствие схемы может быть ограничением. GraphQL-схема служит документацией и основой для инструментов вроде Apollo Studio. tRPC не предоставляет аналогичных возможностей для интроспекции API.</p><p>tRPC не решает проблему over-fetching на том же уровне, что GraphQL. Клиент не может точно указать, какие поля нужны в ответе — он получает всю структуру данных, определённую процедурой.</p><h2>Сравнительная таблица: gRPC vs GraphQL vs tRPC</h2><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-09-30/94988143-b27a-40e5-a33a-f84a3c5a8013.png" alt="" /></figure><h2>GraphQL рано списывать со счетов</h2><p>Несмотря на рост популярности gRPC и tRPC, GraphQL остаётся сильным игроком на рынке API. Технология развивается, появляются новые инструменты и практики:</p><ul><li><b>GraphiQL 2.0.</b> Не просто обновление, а полный редизайн официального инструмента для разработки запросов. Новая версия, разрабатываемая GraphQL Foundation, предлагает модульную архитектуру с поддержкой плагинов для расширения функциональности.</li><li><b>Apollo MCP Server.</b> Адаптация GraphQL к новейшим технологическим трендам, в частности — к интеграции с искусственным интеллектом. Apollo MCP Server позволяет подключать большие языковые модели (LLM) и AI-системы к вашим API через GraphQL, выступая для них стандартизированным и безопасным интерфейсом. Это решает такие проблемы AI, как необходимость детерминированного выполнения запросов и контроля политик доступа.</li><li><b>Автоматические постоянные запросы</b> (Automatic Persisted Queries, APQ). Клиент может отправлять на сервер не текст запроса, а его хэш. Сервер, заранее получивший полный запрос, выполняет его, найдя по хэшу. Это значительно сокращает объем передаваемых данных и ускоряет работу, особенно в мобильных сетях.</li></ul><p>GraphQL незаменим, когда у вас множество клиентов с разными требованиями к данным. Мобильное приложение, веб-интерфейс, партнерские интеграции — каждый может запросить именно те данные, которые нужны, без изменения серверной логики.</p><p>Эволюция GraphQL продолжается. Подходы вроде GraphQL Federation позволяют распределить схему между разными командами, что решает проблему монолитной схемы в больших организациях.</p><p>Инструменты вроде graphql-tada и Grats улучшают процесс разработки с GraphQL, приближая его к удобству tRPC. Они обеспечивают типобезопасность без потерь в гибкости.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-09-30/05238f17-ec27-4483-90d6-4340e984d173.png" alt="" /></figure><h2>Как выбрать: практические рекомендации</h2><p>Выбор технологии зависит от конкретного контекста. Не следуйте трендам вслепую — это приводит к архитектурным ошибкам. Вместо вопроса «Что сейчас модно?» спросите: «Какую проблему я решаю?».</p><p>Проанализируйте свой проект по нескольким ключевым параметрам. Ответы помогут принять взвешенное решение.</p><h2>Вопрос первый: какую проблему вы решаете?</h2><p>Разные технологии созданы для разных сценариев. Определите основную боль вашего проекта:</p><ul><li>Нужна высокая производительность для внутренней коммуникации микросервисов → gRPC. Бинарный протокол и HTTP/2 дают преимущество в скорости при частых вызовах между сервисами.</li><li>Хотите дать клиентам гибкость в запросах данных → GraphQL. Разные потребители API могут запрашивать только нужные поля без изменения серверной логики.</li><li>Разрабатываете full-stack приложение на TypeScript и хотите максимальной типобезопасности → tRPC. Единая типовая система от бэкенда до фронтенда ускоряет разработку и снижает количество ошибок.</li></ul><h2>Вопрос второй: какая у продукта архитектура?</h2><p>Технологический стек определяет доступные опции. Оцените текущую и планируемую инфраструктуру:</p><ul><li>Один язык программирования по всему стеку (TypeScript) → tRPC. Тесная интеграция с экосистемой TypeScript становится приоритетом.</li><li>Несколько языков (Go, Python, Java, etc.) → gRPC или GraphQL. gRPC обеспечивает эффективную коммуникацию между разнородными сервисами, а GraphQL подходит для публичного API.</li><li>Планируете масштабирование на разные платформы → GraphQL. Единая схема API работает с любым клиентом, независимо от языка или платформы.</li></ul><h2>Вопрос третий: кто потребители вашего API?</h2><p>Проанализируйте, кто будет использовать ваш API:</p><ul><li>Внутренние сервисы → gRPC. Высокая производительность и эффективность важнее человекочитаемости.</li><li>Внешние клиенты (мобильные приложения, партнеры) → GraphQL. Возможность точного запроса данных снижает нагрузку на сеть и упрощает интеграцию.</li><li>Собственный фронтенд на TypeScript → tRPC. Максимальная скорость разработки и типобезопасность окупают ограничения по браузерной поддержке.</li></ul><h2>Вопрос четвертый: каковы требования к инструментарию?</h2><p>Разработка не заканчивается на написании кода. Оцените важность сопутствующих инструментов:</p><ul><li>Важна интроспекция API и полноценная экосистема инструментов → GraphQL. Встроенная интроспекция и инструменты вроде Apollo Studio предоставляют мощные возможности для отладки и мониторинга.</li><li>Нужна максимальная производительность и минимальные накладные расходы → gRPC. Бинарный формат и HTTP/2 обеспечивают эффективную передачу данных.</li><li>Приоритет — скорость разработки и минимальная конфигурация → tRPC. Отсутствие схем и кодогенерации ускоряет итерации.</li></ul><h2>Дополнительные практические соображения</h2><p>Командная экспертиза играет важную роль. Любая новая технология требует времени на освоение. Оцените готовность команды изучать новые инструменты.</p><p>Операционные расходы — ещё один фактор. gRPC требует инфраструктуры для мониторинга бинарных протоколов. GraphQL нуждается в инструментах для анализа запросов и защиты от перегрузки.</p><p>Рассмотрите возможность гибридного подхода. Крупные проекты часто используют разные технологии для разных задач. Внутренняя коммуникация — gRPC, публичное API — GraphQL, админ-панель — tRPC.</p><p>Проведите пилотные испытания. Реальные нагрузки могут преподнести сюрпризы. Протестируйте выбранную технологию на критически важных сценариях перед полным внедрением.</p><h2>Почему гибридные подходы набирают популярность</h2><p>Современные приложения редко бывают простыми. Один продукт может включать мобильное приложение, веб-интерфейс, админ-панель и интеграции с партнерами. Каждый компонент имеет уникальные требования к API.</p><p>Монолитная архитектура API часто не справляется с разнородными нагрузками. Один протокол пытается угодить всем, но в итоге не идеален ни для кого. Гибридный подход признает это разнообразие и предлагает адресные решения.</p><p>Технологическая зрелость инструментов позволяет легко комбинировать разные подходы. Контейнеризация, сервисная сетка и API-гейтвеи упрощают интеграцию разнородных компонентов.</p><h2>Реальные сценарии комбинирования технологий</h2><p>Рассмотрим типичный пример e-commerce платформы. Система состоит из нескольких логических частей, каждая со своими требованиями.</p><p>Микросервисы инвентаризации и платежей общаются через gRPC. Здесь важна низкая задержка и эффективность сети. Бинарный протокол и HTTP/2 идеально подходят для частых внутренних вызовов.</p><p>Публичное API для мобильных приложений и партнеров использует GraphQL. Разные клиенты могут запрашивать только нужные данные без переразработки серверной логики. Это снижает нагрузку на сеть и упрощает поддержку API.</p><p>Админ-панель и внутренние инструменты построены на tRPC. Разработчики работают в единой TypeScript-экосистеме, что ускоряет итерации. Типобезопасность от backend до frontend снижает количество ошибок.</p><h2>Техническая реализация гибридной архитектуры</h2><p>Ключевой элемент гибридной системы — API-шлюз. Он маршрутизирует запросы к соответствующим бэкендам, преобразует форматы данных и обеспечивает единую точку входа.</p><p>Шлюз принимает HTTP-запросы и определяет, куда их направить. GraphQL-запросы идут к GraphQL-серверу, gRPC-вызовы — к микросервисам, а tRPC-запросы — к соответствующим процедурам.</p><p>Преобразование протоколов происходит прозрачно для клиента. Например, мобильное приложение отправляет GraphQL-запрос, который шлюз может преобразовать в gRPC-вызов к внутренним сервисам.</p><p>Сервисная сеть (service mesh) упрощает управление гибридной инфраструктурой. Она обеспечивает обнаружение сервисов, балансировку нагрузки и мониторинг независимо от используемых протоколов.</p><h2>Организационные аспекты смешанного подхода</h2><p>Гибридная архитектура влияет на структуру команд. Вместо единой бэкенд-команды появляются специализированные группы:</p><ul><li>Команда платформы отвечает за базовую инфраструктуру: API-шлюз, сервисную сеть, мониторинг. Они обеспечивают совместимость различных технологий и единые стандарты качества.</li><li>Команды продукта фокусируются на конкретных функциональных областях. Они выбирают оптимальные технологии для своих задач в рамках установленных стандартов.</li></ul><p>Такое разделение требует чётких интерфейсов между командами. Контракты API становятся критически важными — они определяют точки взаимодействия между различными частями системы.</p><h2>Проблемы и решения при внедрении</h2><p>Гибридный подход не лишён сложностей. Основная проблема — высокая операционная нагрузка. Каждая технология требует специфических знаний и инструментов мониторинга.</p><p>Единая система мониторинга обязательна. Нельзя иметь отдельные дашборды для gRPC, GraphQL и tRPC. Нужен агрегированный взгляд на всю систему, который показывает взаимосвязи между компонентами.</p><p>Стандартизация практик разработки становится критически важной. Разные команды должны следовать единым принципам документирования, версионирования и тестирования API.</p><p>Обучение разработчиков — еще один вызов. Программисты должны понимать несколько технологий, а не специализироваться на одной. Это требует инвестиций в обучение и обмен знаниями.</p><h2>Когда гибридный подход оправдан</h2><p>Переход к смешанной архитектуре требует дополнительных ресурсов. Он не всегда целесообразен для небольших проектов или стартапов на ранней стадии.</p><p>Проекты с явно выраженными разнородными требованиями к API получают максимальную выгоду. Если у вас есть и высоконагруженные внутренние сервисы, и публичное API с разнообразными клиентами — гибридный подход может быть оптимальным.</p><p>Системы, которые эволюционируют из монолита в микросервисы, часто естественным образом приходят к гибридной архитектуре. Постепенное внедрение новых технологий менее рискованно, чем полный рефакторинг.</p><p>Команды с сильной DevOps-культурой лучше справляются со сложностью гибридных систем. Автоматизация развёртывания, мониторинга и масштабирования снижает операционную нагрузку.</p><h2>Эволюция вместо революции</h2><p>Гибридный подход — не про выбор одной технологии, а про использование сильных сторон каждой. Это признание того, что современные системы слишком сложны для универсальных решений.</p><p><b>Начинайте с простого.</b> Если ваш проект небольшой, одной технологии API может быть достаточно. По мере роста вы сможете постепенно вводить дополнительные протоколы там, где они дают максимальный эффект.</p><p><b>Измеряйте результаты.</b> Внедрение новой технологии должно решать конкретные проблемы: снижать задержки, ускорять разработку или улучшать пользовательский опыт. Без измеримых целей гибридная архитектура превращается в ненужное усложнение.</p><p>Главное — сохранять архитектурную гибкость. Технологии продолжат меняться, и ваша система должна быть готова адаптироваться к новым вызовам.</p><h2>Итоги: не следуйте трендам, решайте задачи</h2><p>GraphQL не умер — он занял свою нишу в мире API. gRPC и tRPC не заменят его полностью, а дополнят экосистему, предлагая решения для конкретных сценариев.</p><p>Выбирайте технологию исходя из потребностей проекта, а не модных трендов. Иногда простое REST API может оказаться лучшим решением, если ваши требования минимальны.</p><p>Технологии продолжат развиваться. Важно сохранять архитектурную гибкость и не замыкаться на одном стеке. Умение выбрать правильный инструмент для задачи — навык, который останется актуальным независимо от появления новых технологий.</p><p>Главное — решать реальные проблемы, а не создавать себе новые в погоне за модными фреймворками.</p>]]></content:encoded>
    </item>
    <item>
      <title>Архитектура микросервисов: как избежать 7 типичных ошибок — разбор реальных кейсов</title>
      <link>https://tproger.ru/articles/arhitektura-mikroservisov--kak-izbezhat-7-tipichnyh-owibok---razbor-realnyh-kejsov</link>
      <comments>https://tproger.ru/articles/arhitektura-mikroservisov--kak-izbezhat-7-tipichnyh-owibok---razbor-realnyh-kejsov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Денис Кудерин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/arhitektura-mikroservisov--kak-izbezhat-7-tipichnyh-owibok---razbor-realnyh-kejsov</guid>
      <description><![CDATA[<p>Разбираем реальные ошибки при переходе на микросервисную архитектуру. Узнайте, как избежать распределенного монолита, чрезмерного дробления сервисов и проблем с коммуникацией между ними. Практические решения и чек-лист для вашего проекта на основе опыта команд 2023-2025 годов.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/arhitektura-mikroservisov--kak-izbezhat-7-tipichnyh-owibok---razbor-realnyh-kejsov">Архитектура микросервисов: как избежать 7 типичных ошибок — разбор реальных кейсов</a>»</p>]]></description>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[Архитектура ПО]]></category>
      <category><![CDATA[Ошибки в ПО]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 01 Oct 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Архитектура микросервисов — не панацея от всех бед. Она не гарантирует успеха, но точно показывает слабые места в процессах команды. Некоторые компании проходят этот путь с блестящим результатом. Другие оказываются в ситуации, которую эксперт Крис Ричардсон, автор книги «Microservice Patterns», метко <a href="https://microservices.io/post/architecture/2025/02/03/microservices-ate-my-application.html">называет</a> «микросервисы съели моё приложение» — когда технологию незаслуженно назначают причиной собственных провалов.</p><p>Правда в том, что микросервисы не собираются стаями, чтобы атаковать ни в чём не повинные проекты. Проблемы возникают из-за неверных архитектурных решений или когда вы игнорируете явные сигналы, что что-то пошло не так.</p><p>Разберём семь провальных сценариев, которые допускают команды при переходе на микросервисы. Вы узнаете, как избежать этих ловушек и построить систему, которая будет по-настоящему гибкой и масштабируемой.</p><h2>Зачем вообще нужны микросервисы</h2><p>Архитектура микросервисов — это не универсальное решение, а альтернативный подход к построению систем.</p><p>Микросервисы подходят не для всех проектов. Они оправданы, когда:</p><ul><li>система действительно большая и сложная;</li><li>разные компоненты требуют разного масштабирования;</li><li>команды могут работать независимо;</li><li>нужно использовать разные технологии для разных задач.</li></ul><p>Монолит часто лучше для:</p><ul><li>небольших проектов с четкими границами;</li><li>команд до 10 человек;</li><li>ситуаций, когда важна простота развертывания;</li><li>проектов с неясными требованиями.</li></ul><p>Представьте монолит как специализированный магазин. Все товары в одном помещении. Покупатель быстро находит нужное. Владелец легко управляет ассортиментом.</p><p>Микросервисы работают иначе. Это сеть специализированных магазинов, расположенных в одном торговом центре. Хлебный магазин, мясная лавка, овощной павильон. Каждый работает независимо. Если в хлебном магазине ремонт, мясная лавка продолжает работать.</p><p>Конкретные преимущества микросервисов:</p><ul><li>Независимое развертывание. Можно обновлять один сервис без остановки всей системы.</li><li>Масштабируемость. Сервисы с высокой нагрузкой масштабируются отдельно от остальных.</li><li>Технологическая гибкость. Разные сервисы можно писать на разных языках и технологиях.</li><li>Устойчивость к ошибкам. Если один сервис упадёт, это не приведёт к коллапсу всей системы.</li></ul><p>Но эти преимущества работают только при правильной реализации. На практике слишком часто команды создают систему, где сервисы так тесно связаны, что преимущества независимости теряются. Возникает ситуация, когда каждый сервис по отдельности прост, но вместе они создают сложную для управления конструкцию. Проблема в одном сервисе при такой реализации отражается на всех остальных. Внесение изменений требует согласования с несколькими командами. Нет ни гибкости микросервисов, ни предсказуемости монолита. Вместо этого получается наихудший из вариантов.</p><p>Далее мы рассмотрим наиболее типичные антипаттерны, которые встречаются в практике разработки. Стоит изучить эти ошибки, чтобы не допускать их в своих проектах.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-09-30/cbd1b012-d704-4131-b3b5-ab4bf833766e.jpg" alt="" /></figure><h2>Ошибка 1: Распределенный монолит</h2><p>Команды хотят получить преимущества микросервисов, но не могут отказаться от мышления в стиле монолита.</p><p><b>В чем проблема:</b> Вместо независимых сервисов получается система, где все компоненты жёстко связаны. Это и есть распределённый монолит.</p><p><b>Реальный кейс:</b> Консультант IBM Холли Каммингс <a href="https://www.infoq.com/articles/microservices-seven-fail/">описывает</a> проект, где команда жаловалась: «каждый раз, когда мы меняем один микросервис, ломается другой». Сервисы были распределены по разным репозиториям, но использовали идентичные копии сложной объектной модели. Изменение одного поля требовало синхронного обновления всех сервисов. Команда потеряла преимущества монолита — компилятор больше не проверял типы, — но не получила преимуществ микросервисов — независимости развёртывания.</p><p>Как избежать:</p><ul><li>Проектируйте сервисы вокруг бизнес-доменов, а не технических слоев. Интерфейсы сервисов должны быть узкими и специфичными. Например, сервис заказов сам управляет своими данными, логикой и API для операций с заказами.</li><li>Откажитесь от общих библиотек с моделью данных. Каждый сервис должен владеть своими данными и иметь свою модель.</li><li>Используйте подход, когда клиенты сервиса задают ожидания от его API. Для этого подходят инструменты вроде Pact. Такой метод проверяет совместимость сервисов без громоздких интеграционных тестов.</li></ul><p>Распределённый монолит — это худший из возможных сценариев. Вы получаете сложность распределённых систем без преимуществ модульности.</p><h2>Ошибка 2: Чрезмерное дробление сервисов (декомпозиция)</h2><p>Стремление сделать сервисы как можно меньше приводит к противоположному эффекту. Система дробится на сотню мелких компонентов, которыми невозможно управлять.</p><p><b>В чем проблема:</b> Каждый микросервис — это отдельное приложение со своей базой данных, зависимостями и пайплайном развёртывания. Чрезмерное дробление увеличивает сложность управления, мониторинга и эксплуатации. Растут сетевые издержки — латентность становится узким местом, работа системы замедляется.</p><p><b>Реальный кейс: </b>Компания Gilt <a href="https://theburningmonk.com/2015/05/craftconf15-takeaways-from-scaling-micro-services-at-gilt/">перешла</a> на микросервисы в 2015 году и столкнулась с проблемой излишнего дробления. Изначально они создали более 450 микросервисов для платформы электронной коммерции. Многие сервисы были настолько малы, что выполняли лишь одну простую функцию. Это привело к экспоненциальному росту операционных расходов. Команда тратила больше времени на координацию взаимодействия между сервисами и устранение сетевых сбоев, чем на разработку новой функциональности. В итоге они провели рефакторинг, объединив сервисы с высокой связностью, что значительно упростило систему и ускорило разработку .</p><p>Как найти баланс:</p><ul><li>Объединяйте функциональности с высокой связностью. Если два компонента постоянно общаются, возможно, они должны быть одним сервисом.</li><li>Ориентируйтесь на функциональную связность. Сервис должен иметь чёткую зону ответственности в бизнес-логике.</li><li>Оценивайте операционные расходы, прежде чем создавать новый сервис. Спросите себя: готовы ли мы поддерживать ещё одну базу данных, ещё один конвейер развёртывания?</li></ul><p>Сервис должен быть достаточно автономным, чтобы его могла поддерживать одна команда. Ему необходимо решать конкретную бизнес-задачу. Если сервис слишком мал, он не принесет реальной пользы, но потребует полноценных затрат на поддержку. Золотая середина — когда команда полностью владеет одним или несколькими логически связанными сервисами и может развивать их без постоянной координации с другими.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-09-30/4b2ae5b4-4b86-4306-b1e1-08344636e3dc.jpg" alt="" /></figure><h2>Ошибка 3: «Болтливые» микросервисы</h2><p>Микросервисы много общаются друг с другом. Мелкозернистые API вынуждают делать десятки вызовов для одной операции. Это создаёт каскады зависимостей, где сбой одного сервиса вызывает цепную реакцию.</p><p><b>В чем проблема:</b> При такой структуре возникает следующий сценарий провала:</p><ul><li>Частые взаимодействия — сервисы обмениваются множеством мелких запросов, генерируя насыщенный сетевой трафик.</li><li>Каскад вызовов — один пользовательский запрос запускает длинную цепочку обращений к разным сервисам.</li><li>Мелкозернистые API — для выполнения одной бизнес-транзакции требуется множество вызовов.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-09-30/fe3bcc40-a9b3-43ba-8c5a-21baea22b4c7.png" alt="" /></figure><p><b>Реальный кейс:</b> Команда Amazon Prime Video <a href="https://amplication.com/blog/amazon-ditches-microservices-for-monolith-decoding-prime-videos-architectural-shift">столкнулась</a> с проблемой производительности своей системы мониторинга видео. Изначально они построили архитектуру на основе микросервисов, где каждый этап обработки видео (метаданные, детекция дефектов, анализ качества) был отдельным сервисом.</p><p>Система состояла из множества «болтливых» сервисов, которые постоянно обменивались сообщениями через AWS Step Functions. Это привело к резкому росту затрат и проблемам с производительностью из-за постоянной сериализации/десериализации данных между сервисами. В итоге команда консолидировала несколько сервисов в единый монолит, что снизило затраты на 90% и улучшило производительность .</p><p>Решение:</p><ul><li>Используйте асинхронную коммуникацию через очереди событий.</li><li>Проектируйте крупнозернистые API, которые охватывают полный бизнес-контекст за один вызов.</li><li>Внедряйте архитектурные паттерны типа API Gateway для агрегации данных и Backend For Frontend для оптимизации под конкретные клиенты.</li></ul><p>Сервисы должны обмениваться данными минимально необходимое количество раз. Каждый лишний вызов между сервисами увеличивает задержки и создаёт новые точки отказа. Вместо потока мелких запросов проектируйте взаимодействие вокруг завершённых операций. Один запрос должен передавать все данные, необходимые для выполнения следующего шага бизнес-процесса.</p><h2>Ошибка 4: Игнорирование сквозной функциональности</h2><p>Команды часто откладывают на потом реализацию системных компонентов: логирование, аутентификацию, кеширование, мониторинг, поэтому разработка быстро останавливается.</p><p><b>В чем проблема:</b> Разработка бизнес-сервисов начинается до подготовки общесистемных компонентов. В результате каждый сервис изобретает собственные способы логирования и аутентификации. Приходится переделывать готовый код, чтобы добавить единый стандарт.</p><p><b>Реальный кейс:</b> Команда, создающая микросервисы на Go, <a href="https://habr.com/ru/articles/459130/">разработала</a> единый подход к обработке ошибок и логированию. Они используют структурированное логирование с обязательным контекстом — идентификаторами пользователей, транзакциями, следами запросов. При необходимости специалисты сразу находят корневые причины проблем, не переключаясь между десятками лог-файлов.</p><p>Правильный подход:</p><ul><li>Сначала создайте базовые сервисы для логирования, кеширования, управления пользователями и мониторинга.</li><li>Разработайте стандарты и библиотеки для их использования. Командам не придётся дублировать функциональность.</li><li>Внедрите централизованное логирование с самого начала. Без него невозможно отлаживать распределённую систему.</li></ul><h3>Наблюдаемость как основа стабильности</h3><p>Современные микросервисные системы требуют полноценной наблюдаемости (observability). Это не просто мониторинг, а понимание, что именно происходит внутри системы, без дополнительных вопросов к разработчикам.</p><p>Три столпа наблюдаемости:</p><ol><li>Логи — записи о конкретных событиях с временными метками и контекстом.</li><li>Метрики — числовые показатели, отслеживаемые во времени (загрузка CPU, latency, error rate).</li><li>Трассировка — отслеживание пути запроса через распределённую систему.</li></ol><h2>Ошибка 5: Нечеткие границы сервисов</h2><p>Сервисы без чётких границ начинают обрастать несвязанной функциональностью. Order Service вдруг получает отчётность, а Payment Service — нотификации. На выходе — монстр с размытой ответственностью.</p><p><b>В чем проблема:</b> Нарушается принцип единой ответственности. Сервисы становятся большими и сложными. Их трудно тестировать и поддерживать. Код дублируется — разные команды реализуют одинаковую функциональность в разных сервисах.</p><p><b>Реальный кейс: </b>Компания Kong (тогда еще Mashape) <a href="https://buttercms.com/books/microservices-for-startups/breaking-up-a-monolith/">начала</a> декомпозицию монолита в 2013 году. Монолитное приложение, написанное на Java, объединяло функциональность маркетплейса API, включая биллинг, аналитику и управление каталогом. В процессе декомпозиции команда столкнулась с трудностями, которые позже были признаны классическими ошибками.</p><p>Первоначально четкие границы между компонентами со временем размылись, что привело к серьезным проблемам:</p><ul><li>Сложность развертывания. Любое небольшое изменение требовало полного переразвертывания всей системы.</li><li>Размытие границ. Компоненты маркетплейса стали переплетаться, границы ответственности стерлись.</li><li>Технический долг. Система становилась все сложнее для поддержки и развития.</li></ul><p>Попытка исправить ситуацию переходом на микросервисы изначально ухудшила положение. Команда, разделенная на две части (одна поддерживала монолит, другая разрабатывала новую архитектуру), столкнулась с трудностями координации. В итоге процесс разработки замедлился, а не ускорился.</p><p>Как избежать:</p><ul><li>Используйте Domain-Driven Design (DDD). Определяйте Bounded Context — чёткие границы бизнес-доменов.</li><li>Перед созданием сервиса документально зафиксируйте его зону ответственности. Что он делает? Какими данными владеет?</li><li>Сопротивляйтесь искушению добавить «ещё одну маленькую функцию» в существующий сервис. Часто лучше создать новый, но для начала нужно разобраться с конкретной задачей продукта.</li></ul><h3>Антипаттерн Entity Service</h3><p>Частный случай размытых границ — создание сервисов по принципу «одна сущность — один сервис». Это кажется логичным: сервис пользователей, сервис заказов, сервис товаров. Но на практике такой подход создаёт ещё больше проблем. Entity Service (сервис одной сущности) часто превращается в обычный CRUD-интерфейс к базе данных. Вся бизнес-логика перемещается в вызывающие сервисы, которые вынуждены делать десятки вызовов для выполнения одной операции.</p><p><b>Альтернатива:</b> Создавайте сервисы вокруг бизнес-операций, а не данных. Вместо общего «сервиса пользователей», который отвечает за всё подряд, выделите отдельные сервисы с конкретными зонами ответственности:</p><ul><li>сервис регистрации — создает новые учетные записи;</li><li>сервис аутентификации — проверяет логины и пароли;</li><li>сервис управления профилем — обновляет личные данные.</li></ul><p>Каждый такой сервис содержит и данные, и логику своей операции. Названия сразу показывают, что сервис делает. Такой подход помогает избежать «божественных» сервисов, которые знают слишком много.</p><h2>Ошибка 6: Смешивание баз данных</h2><p>Общая база данных для нескольких микросервисов — это красный флаг. Сервисы теряют независимость. Изменение схемы данных одним сервисом ломает остальные.</p><p><b>В чем проблема:</b> Единая база данных создает скрытую связность между сервисами. Невозможно выбрать оптимальную СУБД для конкретного сервиса — все используют одно решение. Затрудняется горизонтальное масштабирование.</p><p><b>Реальный кейс:</b> Крис Ричардсон <a href="https://microservices.io/patterns/data/shared-database.html">описывает</a> классическую проблему, возникающую при использовании общей базы данных. В этом сценарии сервисы OrderService и CustomerService напрямую обращаются к таблицам друг друга в единой базе данных.</p><p>Это создает тесную связность на уровне разработки и времени выполнения:</p><ul><li>Зависимость разработки. Разработчик, вносящий изменения в OrderService, должен согласовывать изменение схемы таблиц с командой, отвечающей за CustomerService, что значительно замедляет работу.</li><li>Блокировки времени выполнения: Длительная транзакция в CustomerService, которая удерживает блокировку на таблице ORDERS, может полностью заблокировать работу OrderService.</li></ul><p>Такой подход лишает микросервисы их ключевых преимуществ — независимости развертывания и масштабирования.</p><p>Правила работы с данными:</p><ul><li>У каждого сервиса должна быть собственная база данных. Сервис владеет своими данными — другие сервисы получают доступ только через его API.</li><li>Используйте шаблон Saga для управления распределёнными транзакциями вместо двухфазного коммита.</li><li>Реализуйте CQRS (Command Query Responsibility Segregation) для отделения операций записи от операций чтения, когда это необходимо.</li></ul><p>Общая база данных создаёт жесткую зависимость между сервисами. Изменение схемы данных в одном месте может сломать функциональность в другом. Команды теряют возможность независимо развивать свои сервисы — любая правка требует согласования со всеми участниками.</p><p>Такая архитектура лишает микросервисы их главного преимущества — автономности, и напоминает жизнь в студенческом общежитии. Вместо независимых компонентов получается система, где всё связано невидимыми нитями зависимостей.</p><h2>Ошибка 7: Неготовность организации</h2><p><b>В чем проблема: </b>Микросервисы требуют изменений в структуре команды и процессах. Если продолжать работать как с монолитом, ничего не получится.</p><p><b>Реальный кейс:</b> в одной из <a href="https://medium.com/@b.stoilov/a-short-horror-story-about-migrating-from-monolith-to-microservices-28d35801b188">компаний</a> команда разрабатывала микросервис, но была вынуждена тесно интегрировать его с унаследованным монолитом. Они зависели от его цикла выпуска, что свело на нет все преимущества независимой разработки. Проект в итоге закрыли.</p><p>Какие организационные изменения помогут:</p><ul><li>Перейдите к командам по сервисам — небольшим автономным группам, которые полностью владеют своими сервисами (You Build It, You Run It).</li><li>Внедрите культуру DevOps — автоматизацию сборки, тестирования и развёртывания для каждого сервиса.</li><li>Наладьте независимые циклы выпуска. Возможность развёртывать сервисы без координации с другими командами — ключевое преимущество микросервисов.</li></ul><p>Успешный переход на микросервисы требует изменения мышления всей команды. Разработчики должны стать ответственными за свои сервисы на протяжении всего жизненного цикла — от проектирования до эксплуатации в продакшене.</p><p>Что меняется:</p><ul><li>Ответственность. Разработчики отвечают не только за написание кода, но и за работоспособность сервиса в продакшн.</li><li>Коммуникация. Команды должны чётко определять контракты между сервисами и соблюдать их.</li><li>Экспертиза. Появляется потребность в специалистах по DevOps, наблюдаемости, распределенным системам.</li></ul><p>Микросервисы — это не про технологии, а про архитектуру и организацию работы. Без правильной культуры даже самая совершенная техническая реализация обречена на провал.</p><h2>Чек-лист для вашего перехода</h2><p>Прежде чем переходить на микросервисы, проверьте себя по этому списку:</p><ul><li>вы определили бизнес-проблему, которую будете решать микросервисами (а не просто хотим «быть как Netflix»);</li><li>спроектировали границы сервисов на основе бизнес-доменов — DDD, Bounded Context;</li><li>у каждого сервиса будет собственное хранилище данных;</li><li>предусмотрели кросс-каттинговые сервисы — логирование, аутентификацию, мониторинг;</li><li>готовы к организационным изменениям — автономные команды, DevOps;</li><li>выбрали правильный уровень детализации сервисов (не слишком мелкий);</li><li>продумали межсервисную коммуникацию — асинхронную, через события.</li></ul><p>Netflix, Amazon и Uber прошли этот путь. Они не избежали ошибок, но выстроили процессы для развития сложных систем. Микросервисы — это эволюция архитектуры и команды. Начинайте с малого, не бойтесь менять решения. Главный критерий успеха — скорость доставки ценности пользователям без поломок продакшена. Если этот показатель растет — вы на правильном пути.</p>]]></content:encoded>
    </item>
    <item>
      <title>Максимально простое объяснение устройства микрофронтендов</title>
      <link>https://tproger.ru/articles/maksimalno-prostoe-obyasnenie-ustrojstva-mikrofrontendov</link>
      <comments>https://tproger.ru/articles/maksimalno-prostoe-obyasnenie-ustrojstva-mikrofrontendov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/maksimalno-prostoe-obyasnenie-ustrojstva-mikrofrontendov</guid>
      <description><![CDATA[<p>Что такое микрофронтенды простыми словами. Объясняем на примерах, что это такое и как используется.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/maksimalno-prostoe-obyasnenie-ustrojstva-mikrofrontendov">Максимально простое объяснение устройства микрофронтендов</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Архитектура ПО]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[микро]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 27 Aug 2025 10:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><b>Микрофронтенды</b> – это подход к разработке пользовательских интерфейсов, при котором фронтенд большого веб-приложения разбивается на набор небольших независимых приложений (модулей). По сути, это аналог концепции микросервисов,. Вместо одного монолитного клиентского приложения, весь интерфейс составляется из нескольких отдельных частей, каждая из которых автономно разрабатывается и деплоится.</p><p>Для конечного пользователя сайт выглядит как единое целое, хотя на деле это несколько сшитых друг с другом сайтов, интегрированных друг с другом. Каждый такой фрагмент отвечает за свою область функциональности (например, поиск, личный кабинет, страница товаров ) и может развиваться независимо от других. Эти мини приложения могут быть созданы на разных технологиях и фреймворках, общаться через чётко определённые интерфейсы. Вместе они образуют клиентское приложение для работы. Так как отдельные части фронта независимы друг от друга, то сбой или изменение в одном модуле не выводит из строя весь сайт.</p><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-08-25/a9bb5228-5882-4ca1-95b8-00bee52cbd5b.png" alt="" /></figure><p>Пример Spotify, каждый раздел — это отдельные автономные приложения, склеенные в одном клиентском интерфейсе.</p><p>Рассмотрим такой подход с позиции менеджмента и разработки.</p><h2>Разработка веб-приложения</h2><p>Разберем особенности разработки веб-приложения с микрофронтендным подходом, узнаем, стоит ли продвигать его в своей работе.</p><h3>Проект придётся сшивать из отдельных частей</h3><p>Каждый микрофронтенд — это автономный проект с отдельным репозиторием и командой, что даёт гибкость в разработке и упрощает понимание кодовой базы той части, над которой предлагается работать. Но такой подход вынуждает постоянно согласовывать интеграции с другими командами, а ещё не факт, что в компании будет человек, который знает, как функционируют отдельные части. Если такого человека нет или он был и пропал, то разбираться придётся самостоятельно, а вникать в чужой код всегда долго и больно. Помочь избежать bus factor может хорошо составленная документация, а также соблюдение стандартов написания кода, единые для всех команд.</p><blockquote>Важно, что один из узлов должен отвечать за сбор как раз всех микрофронтендов и отображении их пользователю.</blockquote><h2>В проекте можно будет экспериментировать</h2><p>В микрофронтендах каждая команда может выбирать <a href="https://micro-frontends.org/">свой стек</a> под отдельные задачи — React, Vue, Angular или всё, что душе угодно . Это позволяет экспериментировать и постепенно внедрять новые технологии, не переписывая монолит. Но такая свобода — палка о двух концах: без строгих соглашений дизайн и UX могут стать разрозненными, а при запуске страницы — нагрузка дублирующихся библиотек будет бить по производительности.</p><p>Но всё-таки это даёт возможность разрабатывать и внедрять новые технологии и практики, независимо от легаси кода. Например, если приелось делать фронтенд на React, то отдельный компонент можно реализовать на Vue. Или, если в будущем существующие библиотеки будут неконкурентоспособны, не надо будет переделывать весь проект, а только проблемные компоненты.</p><h3>Проект будет сложнее деплоить</h3><p>Миркофронтендный подход позволяет разделить процесс разработки отдельных компонентов сайта, как и контроль версий каждого из них, для каждого большого компонента свой репозиторий и свой пайплайн деплоя. Например, если в проекте перестал работать поиск из-за бага на проде, откатывать надо будет только сервис поиска, а не весь проект.</p><p>Однако настройка CI/CD для множества микрофронтендов — это сотни конвейеров, репозиториев и интеграций, которые нужно синхронизировать и контролировать, что особенно тяжело для DevOps-инженеров, которым вместо того, чтобы один раз настроить пайплайн развёртывания для фронта, придётся делать это для каждой его части. К тому же добавляется ещё один этап развёртывания проекта - сбор фронтенда, под который нужно будет прописывать свои правила сборки.</p><h2>Как применять в проекте</h2><p>Для разработки сервисов на базе микрофронтендов есть несколько инструментов, основная задача которых отдельно рендерить компоненты и собирать их в единое приложение.</p><blockquote>Важно заранее предусмотреть падение одного из микрофронтендов и то как это обрабатывать, чтобы для пользователя это всё было единым и всегда стабильным сайтом.</blockquote><h3>Webpack Module Federation</h3><p>Module Federation — механизм, встроенный в Webpack 5, который позволяет одному фронтенду (host) динамически загружать модули из другого фронтенда (remote) во время выполнения. Это мощный инструмент для интеграции микрофронтендов: он поддерживает разделение кода, кэширование, совместное использование зависимостей (например, React или Vue) и независимую доставку каждого модуля. Module Federation работает без необходимости использовать iframe или перекомпиляции.</p><p><a href="https://webpack.js.org/concepts/module-federation/">Инструкция по использованию</a></p><h2>Менеджмент</h2><p>Рассмотрим особенности управления разработкой веб-приложения с микрофронтендным подходом, чтобы понять, когда имеет смысл использовать его подход для своих идей.</p><h2>Один проект превращается во множество</h2><p>Каждая часть интерфейса создаётся и поддерживается своей командой, нередко на разных технологиях, с собственным пайплайном, своим графиком релизов и приоритетами. С одной стороны, это ускоряет разработку, позволяет нанимать команды под конкретные зоны ответственности и гибко распределять ресурсы. С другой — мы получаем систему, собранную из разрозненных команд, где с ростом количества составляющих системы, придётся всё больше ресурсов тратить организацию разработки.</p><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-08-25/a804f4ab-b214-43a2-a07a-c97eb11ed4f4.png" alt="" /></figure><p>Конечное единое веб-приложение представляет собой склейку результатов работы нескольких независимо рендерящихся компонентов, каждый из которых может иметь свой бэк и по факту быть полностью независимым.</p><h3>Команды будут независимы  друг от друга</h3><p>Микрофронтенды позволяют разделить команды, которые параллельно разрабатывают свои компоненты отвечающие за работу ключевых функции. Такой подход повышает мотивацию, людям проще видеть результаты своего труда: они меньше от него отчуждены разбиение на маленькие команды позволяет бороться с <a href="https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%A0%D0%B8%D0%BD%D0%B3%D0%B5%D0%BB%D1%8C%D0%BC%D0%B0%D0%BD%D0%B0">эффектом Рингельмана</a> по мере роста команды. Но автономия  — это и изоляция: одна команда может принять техническое решение, которое затрудняет интеграцию с другими, а синхронизация между командами требует постоянных митов, созвонов или сотен сообщений.</p><p>Управлять несколькими созависимыми подразделениями сложнее, чем вести один проект с централизованным контролем.К тому же, если у одной из команд ушёл разраб, заменить его разрабом из другой не получится, технологии разные и навыки тоже.</p><h3>Команды получают поле для удачных и не очень экспериментов</h3><p>Команды могут внедрять новые технологии, не дожидаясь переписывания всего приложения: один микрофронтенд можно сделать на React, другой — на Vue или Svelte. Это даёт гибкость в найме, миграциях и экспериментах. Но чем больше технологий используется, тем сложнее следить за их использованием и труднее помнить их особенности.</p><p>В какой-то момент менеджер вместо одной технологической карты управляет целой экосистемой со своими внутренними правилами.</p><h3>Появляются FrontOps</h3><p>Микрофронтенды требуют дополнительных усилий по настройке и деплою, для этого понадобится расширять команду DevOps. Эта команда может расширяться настолько, что внутри неё придется выделить подгруппу DevOps, которая будут заниматься исключительно деплоем фронтов — называться они будут FrontOps.</p><h2>Вывод</h2><p>Микрофронтенды — это в первую очередь инструмент для масштабирования разработки. Если приложение действительно большое, команды автономны, а новые фичи выходят каждую неделю, разделение фронтенда на независимые модули ускорит релизы, снизит риски и позволит гибко внедрять технологии.</p><p>Однако мутант из разнородных сервисов быстро становится неуправляемым, если нет четкой и структурированной организации внутри его частей. Выбирайте микрофронтенды, когда бизнес‑скорость важнее архитектурной простоты, и у вас есть настроенная DevOps-инфраструктура. В остальных случаях монолит с хорошей модуляризацией и монорепозиторием может оказаться дешевле и надёжнее.</p><p>Синьор-фронтендер из ВК Маргарита Лукина, автор телеграм-канала <a href="https://t.me/frontend_kitchen">«Фронтенд кухня»</a> отмечает, что микрофронты — не всегда удачное решение:</p><p>«Микрофронтенды — хорошее решение, если команды действительно автономны. Я видела примеры, когда проект разделяли на микрофронтенды, но при этом одно приложение зависело от другого: чтобы добавить фичу, необходимо было делать изменения сначала в одном месте, а затем в другом. Это — верный знак, что что-то пошло не так: в этом случае процесс разработки усложнится, а сроки затянутся. Прежде чем переходить на микрофронтенды, попробуйте логически разделить ваш проект по директориям и убедиться, что для изменения одной фичи в проекте приходится редактировать код только в одной директории. Следующим шагом можно переходить на микрофронтенды».</p><p>Делитесь своим опытом работы с микрофронтендами в комментариях и не забывайте сохранять наши статьи!</p>]]></content:encoded>
    </item>
    <item>
      <title>Границы автономности ИИ-агентов: чему нас научила ИИ-тян, играющая в Minecraft</title>
      <link>https://tproger.ru/articles/granicy-avtonomnosti-ii-agentov--chemu-nas-nauchila-ii-tyan--igrayushhaya-v-minecraft</link>
      <comments>https://tproger.ru/articles/granicy-avtonomnosti-ii-agentov--chemu-nas-nauchila-ii-tyan--igrayushhaya-v-minecraft?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Виктория Эберт]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/granicy-avtonomnosti-ii-agentov--chemu-nas-nauchila-ii-tyan--igrayushhaya-v-minecraft</guid>
      <description><![CDATA[<p>Исследуем, как работают автономные ИИ-агенты на примере виртуальной стримерши NetTyan в Minecraft: где границы автономности, ошибки LLM и чек-лист готовности к продакшену.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/granicy-avtonomnosti-ii-agentov--chemu-nas-nauchila-ii-tyan--igrayushhaya-v-minecraft">Границы автономности ИИ-агентов: чему нас научила ИИ-тян, играющая в Minecraft</a>»</p>]]></description>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Нейронные сети]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 18 Aug 2025 14:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Кто такие ИИ-агенты и зачем они нужны</h2><p><a href="https://cloud.google.com/discover/what-are-ai-agents?utm_source=chatgpt.com">ИИ агенты</a> — это программные системы, использующие искусственный интеллект, чтобы самостоятельно выполнять задачи от имени пользователя. Они могут рассуждать, планировать, запоминать. А ещё обладают определённой автономией — могут принимать решения, обучаться и адаптироваться к новым условиям.</p><p>В отличие от ChatGPT, где мы задаём конкретный вопрос, агент получает задачу и самостоятельно решает, что и как делать: искать информацию, писать код, обращаться к внешним API, работать с базами данных и сохранять результаты. И это не фантазия: рынок таких решений может вырасти до $70,5 млрд к 2030 году (по данным <a href="https://www.grandviewresearch.com/press-release/global-autonomous-ai-autonomous-agents-market">Grand View Research</a>). Гиганты вроде OpenAI, Google, Microsoft активно продвигают агентную архитектуру как будущее LLM.</p><p>В мае 2025 года ресёрчеры из университета Карнеги-Меллон <a href="https://arxiv.org/pdf/2412.14161">запустили</a> The Agent Company, смоделировав виртуальную софтверную фирму, укомплектованную LLM-агентами. ИИ-агенты кодили, использовали GitLab и общались через мессенджеры. Но результат оказался неоднозначным: лучшие агенты справились только с 24% задач. Многие застряли на мелочах — например, не смогли закрыть всплывающее окно или обработать файл .docx.</p><p>Ожидания велики: агенты обещают разгрузить людей от однообразной работы. Однако реальность на продакшене далека от идеала: ИИ часто зацикливается на простых сценариях, генерит однообразный контент, не оценивает критически свою работу и ломается на нетривиальных кейсах. Поэтому в конце статьи мы собрали чек-лист, который поможет подготовить агента к реальным задачам.</p><h2>Что поручить агенту: базовый минимум или роскошный максимум?</h2><p>Этот материал подготовлен совместно с командой стартапа <a href="https://agnetics.ru/">Agnetics</a> по разработке кастомных автономных агентов для бизнеса. Своим опытом и комментариями поделятся фаундер проекта Владислав Славкин и CPO Данила Калиникин. Вместе с ними на простых примерах разберём, на что способны агенты, и попробуем расставить задачи по уровню автономности.</p><h2>Простые задачи</h2><p>Большинство LLM легко справляются с одношаговыми запросами: сделать выжимку из текста или заполнить JSON по инструкции. Это базовый минимум, который даже open-source модели выполняют без дообучения.</p><p><b>Или всё-таки роскошный максимум?</b> Есть фановый тест, на котором спотыкаются даже признанные лидеры бенчмарков. Мы называем его «Тест Яши». Он кажется элементарным — по сути, это просто работа с позициями символов. Даём следующее задание:  «<i>В тексте “Яша Лава” передвинь пробел на две буквы влево</i>».</p><figure><img src="https://media.tproger.ru/user-uploads/111449/2025-08-12/98317206-7d6d-4dc7-8017-05d143d7ff2e.png" alt="" /><figcaption>Тест Яши на ChatGPT 5</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/111449/2025-08-12/1b22cb2a-3902-4631-b39c-0639225e32a4.png" alt="" /><figcaption>Тест Яши на Gemma 3 12B</figcaption></figure><p>Наслаждаемся пока ещё значимым превосходством своего вида над жалкими опенсорсными LLM.</p><p>Почему так?</p><ul><li><b>Недостаток обучающих данных.</b> В тренировочных наборах, скорее всего, мало примеров с позиционной работой на уровне символов.</li><li><b>Особенности токенизации</b>. Модель внутри оперирует не буквами или символами, а токенами — кусками текста разной длины. Позиционное смещение пробела «на две буквы» для модели — неочевидная задача, так как иногда для этого нужно разделить токен.</li><li>Специфика токенизатора. Qwen3 и другие китайские модели могут ошибаться из-за токенизатора, оптимизированного под иероглифы.</li><li>Возможное влияние alignment. Это процесс настройки модели на безопасные и корректные ответы. Если результат покажется ей «неуместным», она может намеренно отклониться от инструкции и выдать искажённый ответ. Но это лишь гипотеза: ошибки случаются и на совершенно безобидных данных.</li></ul><h2>LLM с «руками»: агенты и инструменты</h2><p>Следующее направление — агенты с набором инструментов для взаимодействия с внешним миром. Чтобы LLM понимала, как обращаться к внешним сервисам и запускать функции, в системный промпт добавляют инструкции и few-shot-примеры. Чтобы упростить создание таких агентов, разработан <a href="https://modelcontextprotocol.io/docs/getting-started/intro">MCP</a> — открытый протокол, стандартизирующий общение между агентами и инструментами.</p><figure><img src="https://media.tproger.ru/user-uploads/111449/2025-08-12/58aa8d76-5d9c-49ff-930f-0cd1e84298c2.png" alt="" /></figure><p>Инструменты — это программные функции с входами и выходами. Иногда это более простые LLM, которые решают свои задачи, или даже целые агенты внутри мультиагентной системы.</p><p>Разберём базовый сценарий с инструментами на примере — агенте Lexa с 3 функциями: get_weather, kill_user и get_current_date. Внутри системного промпта даны инструкции: как и когда использовать каждую из фич.</p><ol><li>Пользователь спрашивает: <i>«Какой сегодня день?»;</i></li><li>Lexa вызывает get_current_date. Инструмент выводит текущую дату в виде 1337-02-28 и возвращает агенту;</li><li>Агент формирует ответ в удобоваримом для человека формате: <i>Сейчас 1337 год, 28 февраля.</i></li></ol><h2>Как с этим справляются разные LLM?</h2><ul><li><b>Проприетарные модели</b>, типа ChatGPT от OpenAI или Google Gemini, обычно умеют выполнять такие задачи из коробки.</li><li><b>Open-source модели</b> — зависит от конкретной модели и уровня её дообучения. Например, в LM Studio есть значок молотка и пометка «Trained for tool use» (дообучена для работы с инструментами).</li></ul><p>Задача кажется простой: агент вызывает инструмент, возвращая ответ в формате JSON. Но в реальных условиях есть нюансы:</p><ul><li><b>Обязательная структура ответа и парсинг.</b> Инструмент должен выдать ответ в нужном формате, иначе всё сломается. И даже если он выдал всё правильно, агент может криво считать ответ и зафейлить цепочку.</li><li><b>Стабильность и безопасность LLM</b>. Модель — «чёрный ящик», который может сгенерить что угодно. Поэтому довольно опасно, если агент управляет важными системами, например, базами данных. Вероятность ошибки в структуре ответов есть почти всегда. С рисками нужно работать, но в наших силах только уменьшить вероятность ошибки и её цену.</li><li><b>Плохой auto-fix</b>. Даже если задетектить ошибку и сообщить об этом модели, она не всегда сможет её исправить. Часто приходится полностью менять промпт, чтобы получить более-менее стабильный агентный пайплайн.</li></ul><h2>Мультиагентные системы: разделяй и властвуй</h2><p>Один агент — хорошо, а два лучше? Представим, что мы поручили агенту Lexa забронировать билеты на самолёт. Когда одному агенту приходится и парсить сайты, и фильтровать результаты, и оформлять бронирование, и объяснять всё пользователю — он захлебывается в контексте. ИИ, как и человек, хуже справляется, если делает всё одновременно.</p><p>Если один агент обращается к другому — это мультиагентность. А значит, появляется иерархия, специализация и распределение ответственности. В теории, таких вложенных вызовов может быть сколько угодно.</p><p>Пример: главный агент Lexa-master получает запрос на бронирование билета на самолёт. Он не занимается бронированием напрямую, а делегирует другому агенту — Lexa-slave. Тот ищет рейсы и бронирует билет. Lexa-master возвращает результат пользователю.</p><p><b>Зачем вообще плодить агентов?</b> Сейчас можно запросто выпилить Lexa-slave, и обработка упростится. Но представим, что завтра понадобится сравнение по цене и длительности, или запрос будет «Я хочу улететь завтра утром, но не раньше 9:00, бизнес-классом, и только Аэрофлотом».</p><p>Без узкоспециализированного помощника главный агент будет чаще ошибаться в ворохе требований. Кроме того, агенту-помощнику не нужно держать «в голове» всю цепочку контекста или инструментов, он знает только свою часть. Поэтому в сложных сценариях с кучей шагов, условий и инструментов используют мультиагентный подход.</p><p><b>Где подвох? </b></p><p><b>Ресурсоэффективность</b></p><ul><li>Чем больше агентов в цепочке, тем медленнее ответ и больше переходов между ними.</li><li>Каждое обращение к агенту-помощнику требует времени и вычислительных ресурсов.</li><li>Решение задачи обходится дороже.</li></ul><p>Ошибки накапливаются</p><ul><li>Каждый из агентов — потенциальное слабое звено, может неправильно понять запрос, сформировать ответ или запутаться в данных.</li></ul><ul><li>Один косяк может сломать всю цепочку.</li><li>Чем длиннее цепочка, тем выше вероятность сбоя.</li><li>Чтобы компенсировать это, нужны механизмы контроля и валидации.</li></ul><h2>Автономные агенты</h2><p>Можно ли назвать автономным Telegram-бот, который просто отвечает на вопросы? Он работает 24/7 и не требует постоянного участия человека — значит, формально автономен. Но это лишь базовый минимум. Такой бот — как робот-сборщик на конвейере: повторяет одни и те же действия без улучшений.</p><p>Сценарий здесь достаточно прост — фактически, это REST API для бота или цикл while True с time.sleep(N) для запланированного выполнения одних и тех же задач.</p><p>Однако эта видимая автономность никогда не приведёт к по-настоящему сильному ИИ. Да, простые боты экономят пару кликов, но назвать их полностью автономными — нельзя. Кто-то всё равно завозит новые функции и интегрирует их в продукт. Мы бы хотели затронуть другой уровень автономности, когда агент сам может развиваться и улучшаться в процессе работы. Такой ИИ незаменим в задачах, связанных с кодом или итеративном написании сложных технических статей.</p><p>Чтобы понять, как работает продвинутый автономный агент, возьмём генерацию изображений. Попробуем воспроизвести в <a href="https://perchance.org/ai-character-generator">Perchance AI</a> детализированную картинку по описанию. Формулируем запрос: «девушка сидит на крыше, вид сверху, съёмка дроном с большой дистанции». Отправляем его и ждём результат.</p><p>Получив изображение, мы внимательно его анализируем. Если что-то не так: например, ноги и руки выглядят странно или детали не совпадают с промптом, корректируем запрос и запускаем генерацию заново. Так повторяется цикл: формулируем, получаем, анализируем, корректируем.</p><p>Выглядит как простой и повторяющийся процесс. На самом деле он очень вариативен: иногда, чтобы получить нужный результат — уходят часы, а иногда — достаточно и одной генерации. Бывает и так, что добиться задуманного не получается вовсе. Генерация зависит от множества факторов, включая банальный рандом. Любое изменение в запросе может радикально поменять итоговое изображение. Зачастую к качественному результату приводят очень странные, извилистые и не очень понятные нам промпты.</p><p>Если самые топовые генераторы изображений не всегда следуют промпту, то системы распознавания и VLM сильно опережают их в адекватности. Можно сделать такого агента и автоматизировать процесс генерации, добившись более высоких результатов в следовании промпту (prompt-following). Это решается тем, что он будет сам отсматривать, анализировать и корректировать результат. Подобный подход (Image Reflection) успешно используют в <a href="https://arxiv.org/html/2506.18871v2">OmniGen</a>.</p><h2>NetTyan — автономная стримерша, играющая в Minecraft</h2><p>Нам стало интересно, как далеко можно зайти в автономности: как работают агенты, когда им поручают нестандартные задачи, где нет чётких инструкций? Может ли агент играть в игру наравне с реальными игроками, вести стрим в одиночку, удерживать внимание зрителей, реагировать на чат и игру в реальном времени. Так родился проект нейростримерши, который начинался как фановый эксперимент «на коленке», и перерос в B2B стартап по разработке агентов.</p><p>NetTyan — персонаж, который сам играет в Minecraft и ведёт прямые эфиры, развлекая игроков и зрителей. Она бегает по публичным серверам, общается в чате, троллит игроков, отвечает зрителям, комментирует происходящее, как настоящий стример — и всё это делает LLM. На <a href="https://habr.com/ru/articles/812387/">Хабре</a> мы уже рассказывали про стек и кропотливую работу над архитектурой, а здесь поговорим о другом: что мы поняли о границах LLM-автономности в проде.</p><p>Первый публичный запуск мы устроили весной 2025, а потом провели ряд стримов. NetTyan отпускала шутки про альтушек, пользовалась всеми игровыми механиками, нападала из ниоткуда, выбивала игроков из укрытий и собирала лайки. Срежисированное шоу получилось отличное, и по части эмоций, и как демонстрация потенциала агентов в ивентах с живыми участниками. Некоторые зрители до конца не верили, что за экраном — нейросеть, а не человек.</p><figure><img src="https://media.tproger.ru/user-uploads/111449/2025-08-12/6b58f564-26ce-4c16-9cf9-3f9a00298579.png" alt="" /></figure><figure><img src="https://media.tproger.ru/user-uploads/111449/2025-08-12/708feee4-9c37-4660-9ac2-88bd682a8ecc.png" alt="" /></figure><p>С железом и архитектурой всё гладко. NetTyan сама заходит на серверы, сама общается с чатом и порой даже не уступает реальным игрокам по скиллу. Весь стек реализован на локальных open-source решениях, никаких токенов и подписок. Если урезать пайплайн и поставить «компромиссную» LLM, то её можно запустить даже на ноутбучной RTX 2060.</p><figure><img src="https://media.tproger.ru/user-uploads/111449/2025-08-12/e835a68d-5502-4fed-a0ac-d76169d08294.png" alt="" /><figcaption>NetTyan в топах наряду с реальными игроками</figcaption></figure><h2>Почему NetTyan не стала звездой Twitch</h2><p><b>Автономность — наш главный фокус.</b> Мы хотели, чтобы LLM-агент был самостоятельным не только в поведении, но и в развитии. Что NetTyan — не просто виртуальная кукла, а полноценный стример, который сам растёт, подстраивается под тренды и работает с аудиторией. Без ручного микроменеджмента и постоянного завоза апдейтов. Мы сделали ставку и на то, что агент будет сам себя продвигать — как персонаж и автор.</p><p><b>На этом фоне логично прозвучит вопрос:</b> а почему не автоматизировать нарезку и постинг клипов? Это отдельный масштабный и сложный проект. Мы приняли решение не тратить на это ресурсы, так как эффективность пока сомнительная. На начальных этапах разработки open-source VLM (vision LLM) были слишком слабы. Сейчас с InternVL3 ситуация получше, поэтому планируем к этому вернуться позже.</p><p><b>Саморазвивающийся стример — пока утопия?</b> Спойлер: охваты у NetTyan получились совсем не стримерскими. В совокупности за полгода собралось всего 200 подписчиков. Даже для нишевого проекта это мало, если сравнивать с конкурентами, где за продвижение отвечает целая команда: кто-то клепает хайповые тиктоки, кто-то подкручивает фичи и обновляет механику поведения.</p><p><b>Может ли ИИ стать популярным без участия человека?</b> Пока нет. Попадание в тренды, вирусный контент — исключительно человеческая прерогатива. Просто быть автономной — это не повод для популярности. Зрителям нужен мемный контент. Именно человек понимает, что сейчас хайпанёт: реагирует на повестку, вкладывает эмоции.</p><p><b>Что у конкурентов? </b>Посмотрите на похожие ИИ-проекты: <a href="https://www.twitch.tv/vedal987">Neuro-sama</a>, <a href="https://www.twitch.tv/ai_princess">AI Princess</a>, <a href="https://www.twitch.tv/grettach">Овсянка</a>. Основной трафик приходит с контента, смонтированного вручную. Залетевшие видео — это не геймплей c агентом, а музыкальные клипы, срежиссированные диалоги, сгенерированные каверы. За кадром стоит огромная работа продюсеров и контентмейкеров. В этих проектах ИИ — скорее компаньон в виде Live2D-аватарки с голосом, а не полноценный автор.</p><p><b>Когда исчерпывается человеческий ресурс — работа встаёт.</b> Если говорить о кейсе <a href="https://www.twitch.tv/maria_ai_">Maria-AI</a>, функционально она была действительно очень автономна: круглосуточно стримила на Twitch и собрала несколько тысяч подписчиков благодаря регулярности. Но даже с такой автономностью проект не смог продолжать работу и недавно приостановил трансляции.</p><h2>Кажется, мы уже это слышали: проблема однотипности GenAI-контента</h2><p>ИИ-стример реально может впечатлить: агент играет, шутит, реагирует на чат — вроде бы, почти как человек. Но вау-эффект быстро сходит на нет. Настоящий стример может выдать перформанс: облажаться, эмоционально среагировать, начать бомбить и душнить, или наоборот — затащить и получить всплеск эмоций. У моделей пока не хватает креативности и харизмы.</p><p>Большая часть агентной логики и поведения зашита в фиксированном промте. Личность, бекстори, реакции, манера общения, ToV — всё прописывается один раз. Из-за этого реплики повторяются и становятся однотипными, а реакции — скудными.</p><p>Обычно мы используем инъекции новых идей или реструктуризацию промта — несколько вариантов тем для разнообразия стрима. Но это всего лишь патчи, и реальную проблему однотипности они не решают.</p><h3>Каждый стрим с чистого листа</h3><p>Настоящего роста, как у живого автора контента, у ИИ-стримеров нет. Они не могут делать «работу над ошибками», так как не понимают, что вчерашний стрим зашёл, а сегодняшний — нет. Живой стример ориентируется на фидбек: Discord, Reddit, комменты в чате, донаты. Он может почувствовать, что формат устарел, что пора сменить пластинку: добавить больше шуток или наоборот — сбавить градус.</p><p>ИИ-агенты же не могут сами корректировать контент-стратегию или менять подачу. Пока они не способны анализировать и улучшать своё поведение при долговременной работе над одной задачей — это большая техническая и исследовательская проблема.</p><p>Современный процесс инференса LLM не предполагает дообучение в процессе работы — это проблема, которая сильно лимитирует возможности агентов в самостоятельной работе над задачей. Если специально не прикручивать дообучение в реальном времени — никакого прогресса не будет. Агенты пока не могут «учиться» от стрима к стриму, так как не запоминают предыдущие сессии.</p><h3>Здравый смысл вышел из чата</h3><p>Мы с детства учимся понимать причинно-следственные связи, ассоциации, паттерны. Но агент — не человек, и у него нет привычного нам здравого смысла или «common sense». Если похожей задачи не было в тренировочном датасете, он может делать ошибки даже там, где для нас решение «очевидно».</p><p>Хороший пример — бенчмарк <a href="https://three.arcprize.org/">ARC-AGI 3</a>. Вы можете сами попробовать решить такую задачу. Сначала она может показаться непонятной, сложной и даже нерешаемой, но если попробовать несколько раз — вы научитесь её решать. Но даже самые современные LLM ломают об неё свой нейронный «лоб», <a href="https://x.com/arcprize/status/1946260363256996244">решая менее чем на 1%</a>. Но и эта ситуация может измениться, ведь разработчики могут дообучить модели на подобные задачи.</p><h3>Что будет дальше с NetTyan?</h3><p>Мы очень весело провели время, работая над проектом. Для себя мы поняли, что важна не только технология, но и люди вокруг — классные коллаборации могут вытянуть контент, даже если ИИ пока не идеален. Дальше — два пути:</p><ol><li>Сдаться и перейти на ручное продюсирование контента, как на нашем срежиссированном ивенте и как делают почти все успешные проекты.</li><li>Или сделать шаг в неизвестность и довести автономность до конца. Потратить время и силы на исследования, новые архитектуры, более сложные модели. Да, это мазохизм, но и кайф от экспериментов никто не отменял.</li></ol><p>Итог такой: проекты, ставящие на высокую автономность, но мало работающие с продвижением и коллабами — остаются на дне. Те, кто максимально использует ручной труд, — в топе. Мы решили, что не собираемся отказываться от автономности — потому что это невероятно интересно!</p><h2>Три идеи на будущее по прокачке автономности LLM-агентов</h2><p>Приведём несколько перспективных, но пока что слишком амбициозных направлений, которые могут улучшить работу автономных LLM-агентов. Однако важно понимать: это прежде всего идеи для исследований и экспериментов.</p><p><b>Песочница для экспериментов</b>. Как у писателя есть черновик, так и у агента должна быть среда, где можно пробовать идеи, тестировать гипотезы и исправлять ошибки до того, как результат «пойдёт в эфир». Для решения можно использовать следующие подходы:</p><ul><li>Сейчас довольно легко реализовать песочницу среднего качества. Например, выделить вспомогательного агента, который будет возвращать промежуточные версии ответов для корректировок.</li><li>Если смотреть на перспективу, нужен встроенный в LLM блок, который будет прогонять гипотезы перед ответом. Это уже требует значительного изменения в архитектуре модели.</li></ul><p><b>Адаптация под задачу. </b>Современным агентам сильно не хватает адаптивности на уровне архитектуры. Исправив это, добавив в LLM возможность адаптации в рамках одной задачи (или проекта), можно сильно повысить эффективность модели в сложных долгосрочных задачах.<b> </b><b></b></p><ul><li><b>Обучить Lora-модуль перед постановкой на задачу. </b>При этом модель остаётся фиксированной при исполнении. Такой подход уже показал эффективность, например, <a href="https://arxiv.org/abs/2506.16406">в статье «Drag-and-Drop LLMs»</a>, и его уже можно пробовать повторить. Минус этого подхода — нужно решить, когда и на чём проводить эту вычислительно-затратную процедуру дообучения. В сервисах вроде чат-ботов можно добавить возможность для пользователя обучить адаптер на одном промпте. Также можно настроить триггеры на автоматическое переобучение адаптера. Это может пригодиться, если есть какие-то сверхдолгосрочные задачи, в которых требуется автоматизация. Если использовать подход из статьи, то промпт для обучения адаптера мы можем сгенерировать агентом. Если собирать датасет — тогда нужно кастомное решение вроде reward-моделей.</li><li><b>Реализовать динамически изменяемую модель прямо во время инференса</b> (для сложных случаев). Тогда нужно создать такой Lora-адаптер, который сможет «подстраиваться» к задаче на лету, прямо во время исполнения, не изменяя модель целиком. Или спроектировать архитектуру модели таким образом, чтобы она динамически изменялась прямо во время исполнения.</li></ul><p><b>Мультимодальная память с легкозаменяемым контекстом.</b> Если хранить всю информацию внутри промпта, модель быстро забъёт весь контекст и начнёт забывать старую информацию. Адаптер поможет хранить персональные особенности общения прямо в весах модели.</p><ul><li>Дообучаемый модуль можно адаптировать, используя его как память. В формате адаптера Lora-модуля, небольшой ИИ-модели, хранить информацию о каждом пользователе, со всеми фактами, событиями и историей взаимодействия.</li><li>Можно пойти ещё дальше: сделать так, чтобы память и контекст хранились в виде векторов (условно, цифровых слепков информации), которые можно менять прямо во время работы. Тогда ИИ-агенты, вроде стримеров смогут реагировать на события мгновенно, а не после полного запроса. Но здесь сложность в том, чтобы перестроить архитектуру модели, чтобы она могла быстро менять своё состояние в процессе работы.</li></ul><h2>Чек-лист: готов ли ваш агент к продакшену</h2><p><b>Функциональная полнота:</b></p><ul><li>Агент уверенно закрывает ключевые сценарии без ручных подпорок.</li><li>Нет «серых зон», где пользователь остаётся без ответа или решения.</li></ul><p><b>Качество ответа:</b></p><ul><li>Точность и полезность проверены на тестовом наборе реальных запросов.</li><li>Есть минимальная целевая метрика (например, ≥ 90 % релевантных ответов).</li></ul><p><b>Скорость реакции:</b></p><ul><li>Среднее время ответа ≤ 3–6 сек.</li><li>Пиковая нагрузка протестирована и не приводит к тайм-аутам.</li></ul><p><b>Модерация и безопасность:</b></p><ul><li>Встроен фильтр токсичности и персональных данных.</li><li>Агент не отдаёт приватный контент и вежливо отказывает на опасные запросы.</li></ul><p><b>Логи и мониторинг:</b></p><ul><li>Собираются логи запросов, ответы, ошибки, метрики времени.</li><li>Настроены алерты: рост 5xx, увеличение задержек.</li></ul><p><b> Откат и «план Б»:</b></p><ul><li>Есть fallback-сценарий: если LLM не отвечает, пользователь получает шаблонный ответ или переносится на живого оператора.</li><li>Механизм «чёрной кнопки» — быстрая смена модели или остановка сервиса.</li></ul><p><b> Обновляемость модели:</b></p><ul><li>Подготовлена процедура безопасного fine-tune / релиза новой версии.</li><li>Старые веса и промпты хранятся, чтобы при откате ничего не потерять.</li></ul><p><b> Конфиденциальность и лицензии:</b></p><ul><li>Проверены лицензии моделей, датасетов и TTS/STT-движков.</li><li>Конфиденциальные данные шифруются или остаются on-prem, если того требует бизнес.</li></ul><p><b>Стоимость эксплуатации:</b></p><ul><li>Считаем стоимость инференса: $/1000 токенов или GPU-часы.</li><li>Есть лимиты — агент не «съедает» бюджет при резком росте трафика.</li></ul><p><b>Пользовательский опыт:</b></p><ul><li>Тональность и стиль общения согласованы с ToV бренда.</li><li>Первые 10–20 пользовательских сессий прошли юзабилити-тест и получили положительный фидбек.</li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Generics в Go: почему их ждали, а массово не используют?</title>
      <link>https://tproger.ru/articles/generics-v-go--pochemu-ih-vse-zhdali--a-massovo-ne-ispolzuyut-</link>
      <comments>https://tproger.ru/articles/generics-v-go--pochemu-ih-vse-zhdali--a-massovo-ne-ispolzuyut-?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Вадим Егорцев]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/generics-v-go--pochemu-ih-vse-zhdali--a-massovo-ne-ispolzuyut-</guid>
      <description><![CDATA[<p>Сообщество Go годами ждало дженерики — и получило их, но массового внедрения не произошло. Почему разработчики не спешат переписывать код с использованием обобщённых типов?</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/generics-v-go--pochemu-ih-vse-zhdali--a-massovo-ne-ispolzuyut-">Generics в Go: почему их ждали, а массово не используют?</a>»</p>]]></description>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 08 Aug 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Создателей Go 13 лет атаковали просьбами добавить дженерики. Мечта сбылась: новая функция должна была избавить от дублирования кода, упростить работу с алгоритмами и сделать типы более безопасными.</p><p><b>Заметили, что массового внедрения не произошло?</b> Разработчики не спешат переписывать рабочий код на дженериках.</p><p><b>По каким причинам обобщённые типы оказались невостребованными?</b> — ответим на этот вопрос вместе с участниками тг-канала <a href="https://t.me/golangl">Golang GO</a>.</p><h2>Почему дженерики не вытеснили интерфейсы?</h2><p>Интерфейсы задают структуру программы: реализуют паттерны декоратора, роутера, зависимости. Дженерики лишь усиливают существующие интерфейсы, делают их безопаснее.</p><p>Разработчики, ожидавшие революцию в проектировании, <a href="https://www.reddit.com/r/golang/comments/zuqalh/comment/j1oe3yd/?utm_source=share&amp;utm_medium=web3x&amp;utm_name=web3xcss&amp;utm_term=1&amp;utm_content=share_button">обнаружили</a>, что дженерики годятся только для узкого пула задач.</p><blockquote>Тащить их везде может быть чревато не только потерей производительности, но и рефакторингом больших объёмов кода. Далеко не каждая компания сейчас потянет такие затраты. Тем более, если неясны перспективы.</blockquote><p>Наиболее оправданный случай использования дженериков — замена interface{} в местах, где тип известен на этапе компиляции:</p><h2>Когда всё-таки использовать дженерики?</h2><p>Практика показывает, что обобщённые типы <a href="https://www.reddit.com/r/golang/comments/u5m7pb/now_that_golang_has_generic_types_how_do_you_plan/?tl=ru">нашли применение</a> в конкретных областях.</p><blockquote>У нас они часто используются: много дженерик-функций для кеширования, маппингов, сохранения в базы данных, передачи по gRPC, работы с брокерами, почти вся CRUD-админка на дженериках. Из плюсов — меньше кода, из минусов — иногда сложно понять, что происходит с конкретной сущностью</blockquote><h3>1. Пулы соединений и кэширование</h3><p>Наиболее очевидное применение дженериков — создание типизированных контейнеров.</p><p>Например, этот пул соединений будет работать с любым типом ресурсов, поддерживающих закрытие:</p><p>Аналогично с кэшированием. Можно создавать строго типизированный кэш, который возвращает значения правильного типа на этапе компиляции:</p><h3>2. Математические операции</h3><p>Дженерики избавляют от дублирования кода для разных числовых типов:</p><h3>3. Функции высшего порядка</h3><p>С появлением дженериков появилась возможность создавать типобезопасные функции высшего порядка для работы с коллекциями:</p><blockquote>Я не представляю, как можно обойтись без дженериков, если идёт речь про обработку больших массивов разнообразных данных, где нужны собственные структуры и алгоритмы.</blockquote><h3>4. Обёртки для API и протоколов</h3><p>Так выглядит обёртка ответа с типизированным полем результата на дженериках:</p><p>Компилятор гарантирует соответствие типов на этапе компиляции. До дженериков приходилось использовать json.RawMessage и распаковывать на уровне роутинга.</p><h3>5. Репозитории и CRUD-операции</h3><p>Типизированные интерфейсы для работы с данными:</p><h2>Как дженерики повлияли на тесты?</h2><p>Однозначно стало проще создавать универсальных хелперов для тестирования:</p><h2>Почему дженерики в Go не такие, как в других языках?</h2><p>Отсутствие обобщённых типов болезненно воспринимали разработчики, перешедшие в Go из Java, C#, C++ и других языков с дженериками.</p><blockquote>Добавление функционального программирования — это тренд Rust, Kotlin и других современных языков. Без дженериков в Go было бы сложно переписывать код в функциональной парадигме с других языков.</blockquote><p>Реализация фичи подвела: гошные методы не имеют собственные параметры типа. Методы наследуют дженерик-параметры самой структуры, и нельзя добавить новые.</p><p>Например, это работает:</p><p>А такая функция уже не скомпилируется:</p><p>Привычные паттерны из Rust, Java или C# в Go просто не реализуемы. Вместо методов приходится использовать функции:</p><h2>Как дженерики изменили разработку на Go?</h2><p>Типовые задачи в Го до появления дженериков решали иначе. Приходилось использовать пустой interface{}, генерировать типобезопасный код с помощью go:generate, stringer.</p><p>Несмотря на недостатки, дженерики поменяли подход к разработке.</p><blockquote>Если у вас всё строится на дженериках, то можно считать, что нужен совершенно другой инструментарий и образ мышления для работы с таким кодом.</blockquote><p>Обобщённые типы активно используются в библиотеках. Взять тот же samber/lo и функции Map, Filter, Reduce на дженериках. Ещё стандартная библиотека пополнилась пакетами slices и maps.</p><p>Что касается производительности — ожидания не оправдались. Думали, что избавились от преобразований типов и получили прирост скорости? На деле разница минимальна. В реальных приложениях узкое место не в типах, а в работе БД, сетевых запросах или бизнес-логике.</p><h2>Что в итоге?</h2><ul><li>Интерфейсы остаются основой архитектуры Go-приложений, дженерики их дополняют, но не заменяют.</li><li>Обобщённые типы полезны только для конкретных задач. Применяйте по необходимости, когда дженерики устраняют дублирование кода или повышают типобезопасность.</li><li>Упрощайте тестирование — универсальные хелперы для проверок и утверждений.<br /></li><li>Избегайте преждевременного обобщения — не пишите код через дженерики «на всякий случай».</li><li>Параметры типов лучше всего подходят для контейнеров, кэшей, математических функций.</li><li>Привычные паттерны из других языков не реализуемы — приходится адаптировать подходы под Go.</li><li>Усложнение понимания кода — иногда непросто разобраться, что происходит с конкретной сущностью.</li></ul><p><i>Поделитесь опытом использования дженериков — где они реально помогли, а где оказались излишними? Удивите примерами удачного и неудачного применения!</i></p>]]></content:encoded>
    </item>
    <item>
      <title>Микросервисная архитектура: от монолита к гибкой системе</title>
      <link>https://tproger.ru/articles/mikroservisnaya-arhitektura--ot-monolita-k-gibkoj-sisteme</link>
      <comments>https://tproger.ru/articles/mikroservisnaya-arhitektura--ot-monolita-k-gibkoj-sisteme?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/mikroservisnaya-arhitektura--ot-monolita-k-gibkoj-sisteme</guid>
      <description><![CDATA[<p>«Монолит или микросервисы» — вопрос, который до сих пор вызывает споры в IT. СТО Сервисной цифровой платформы в Газпромбанке делится личным опытом перехода к микросервисной архитектуре, разбирает реальные кейсы и объясняет, почему однозначного ответа не существует.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/mikroservisnaya-arhitektura--ot-monolita-k-gibkoj-sisteme">Микросервисная архитектура: от монолита к гибкой системе</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Ретро]]></category>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[Google]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[микро]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 27 Jun 2025 08:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Привет! Меня зовут Андрей Бирюков, я СTO Сервисной цифровой платформы в Газпромбанке. За свою карьеру поработал в нескольких компаниях — от стартапов до крупных корпораций — и видел разные архитектурные подходы.</p><p>И вот начала копиться усталость от обсуждения, что использовать — монолиты или микросервисы. Этот вопрос стал преследовать меня на конференциях, в офисе, в личных сообщениях. Я потратил столько времени на обсуждение этой темы, что иногда хочется просто распечатать какой-нибудь емкий ответ на футболке и ходить в ней на все митапы.</p><p>Шутки шутками, но тема действительно важная. Я прошел путь от классических монолитных приложений до сложных микросервисных, проектировал системы, которые работают под большой нагрузкой, и пришел к выводу, что однозначного ответа здесь не существует. И вообще, «монолит или микросервисы» — это неправильная постановка вопроса.</p><p>Недавно сходил с Витей на запись <a href="https://vkvideo.ru/video-145457488_456239831">подкаста</a> на эту тему и настолько преисполнился, что решил в текстовом виде формализировать свое отношение к теме (я гнался за вами три дня, чтобы сказать, как вы мне безразличны, ага), обобщить то, о чем говорили, и попытаться дать ответ на вопрос «когда микросервисы действительно помогают и как не сойти с ума, если вы с ними работаете». Порассуждаю о проектировании, поддержке, DevOps-культуре и попробую немного заглянуть в микросервисную архитектуру.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-27/98a19000-c584-440e-bf7a-af36d4409a2a.png" alt="" /><figcaption>Подкаст «Техно.Логично»</figcaption></figure><h2>Микросервисы: зачем они нужны и в чем их плюсы</h2><h3>Архитектура приложений: немного базы</h3><p>Под капотом современных приложений обычно скрываются три основные части:</p><ul><li>множество библиотек и зависимостей;</li><li>единый store, в котором живут состояние и данные;</li><li>компоненты, которые нужно собрать, чтобы сделать из них приложение.</li></ul><p>Собрать это все можно по-разному. Можно сложить в монолит, а можно попробовать модульный подход.</p><p>Монолитное приложение — старое доброе приложение, которое, как правило, создают один или несколько разработчиков, потом его дорабатывает армия джунов, синьоров и всех, кто оказался рядом. Каждый «чуть-чуть поправил», и вот уже никто не понимает, почему оно работает, — но трогать страшно. Монолиты пишут и сейчас — все зависит от бизнеса. Если нужно приложение для небольшого проекта, микросервисы могут и не понадобиться.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-27/02011912-2de9-4c86-9de2-44865eb93fab.png" alt="" /><figcaption>Как выглядит монолит</figcaption></figure><p>Однако наступает момент, когда бизнес расширяется, аудитория растет, нагрузка увеличивается — а масштабировать монолит становится все сложнее. Тогда и приходят на помощь микросервисы.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-27/739de2ec-05c4-4f68-bf1a-356380611028.png" alt="" /><figcaption>А вот приложение с микросервисной архитектурой</figcaption></figure><p>Масштабировать можно и монолиты, но у них всегда остается какая-то единая точка отказа — например, база данных. Особенно если это реляционная СУБД, завязанная на Oracle или PostgreSQL. Когда база достигает сотен гигабайт или даже терабайт, масштабировать такую штуку становится дорого, больно и ненадежно.</p><h3>Микросервисы — панацея? Не совсем</h3><p>Тренд на микросервисный подход появился в начале 2010-х годов, вместе с проникновением интернета в широкие слои населения. Первый iPhone вышел в 2007 году, люди стали гораздо ближе к интернету, к данным, к информации. Бизнес захотел дотянуться до этой аудитории, и тогда началась диджитализация, сложность систем стала повышаться. Особенно остро это почувствовали крупные организации вроде банков: функциональность увеличивалась, и монолит начал «трещать» не только технически по инфраструктуре, но и по возможностям команд разработки, которые с ним работали.</p><p>Плюсы микросервисов очевидны: масштабируемость, независимая разработка, изоляция компонентов. Но вместе с этим пришли новые проблемы — усложнились мониторинг и поддержка, стали требоваться все новые инструменты, чтобы обеспечивать работу огромной инфраструктуры. Так появился DevOps.</p><h2>Распространение DevOps-культуры и инструменты оркестрации</h2><p>Раньше разработчик писал код, собирал артефакт и перекидывал его через забор в поддержку. Коллеги за забором его деплоили, запускали — и разработчику можно было больше не думать про плоды своей работы.</p><p>В новой реальности количество артефактов, которые нужно перекидывать через забор, кратно выросло. Вместе с этим появилась и стала распространяться DevOps-культура: понимание, что за качественную раскатку в проде отвечает не только команда поддержки, но и разработчики.</p><p>Важно учитывать еще и то, что сложность поддержки кратно увеличилась. Если монолит можно было отдебажить, просто заглянув в логи, то с сотней микросервисов так не получится. Поэтому появились такие инструменты, как централизованное логирование, распределенный трейсинг — и сотни, если не тысячи других, связанных в первую очередь с observability. В таких обстоятельствах DevOps-культура стала особенно важна.</p><h2>Проектируем микросервисы без боли: от стандартов до DDD</h2><h3>Стандартизация — наше все</h3><p>Если каждый микросервис пишет логи в своем формате и использует свои библиотеки, получается зоопарк. Нужно, чтобы были выровнены стек и CI/CD pipeline, существовали одинаковые библиотеки логирования и формат.Микросервисы дают свободу писать на разных языках, но с ней приходит и ответственность: под каждый язык придется придумывать и поддерживать разные инструменты. А это приведет к еще большему увеличению сложности. Так что с языком тоже лучше соблюдать стандартизацию: если пишете на Java, то и решать все проблемы стоит с помощью этого языка.</p><p>При этом иногда другой язык вполне оправдан. Например, просто потому, что Java не может работать с такой высокой скоростью, какая нужна. В некоторых случаях даже на Java приходится писать особым образом, либо можно использовать C++, Go или Rust. Но это скорее исключение из правила.</p><p>Инженеры — натуры увлекающиеся и любят паттерн CV driven development, когда хочется новую технологию потрогать и внедрить у себя. А потом похвастаться этим на каком-нибудь ивенте по принципу «just because I can» («просто потому что могу»). При этом может оказаться, что бизнесу технология особо и не была нужна. Чтобы избегать таких ситуаций, необходим технологический радар — список того, что можно использовать в компании, а что нет. И исключения из такого радара должны приниматься и допускаться очень взвешенно.</p><h2>DDD: как правильно нарезать сервисы</h2><p>Одна из опасностей при проектировании микросервисов — скатиться в очень мелкую гранулярность, когда логика нарезается чуть ли не по отдельной функции на микросервис (на отдельный deployment unit). Это может привести к такой сложности, которой потом будет очень трудно управлять. Такая проблема была, например, у Uber в начале их пути, и им пришлось пересматривать свою архитектуру. Избежать этого помогает Domain-driven design (DDD) — предметно-ориентированное проектирование.</p><p>Вместо того чтобы пилить отдельные сервисы для авторизации, логирования и уведомлений, команда может подумать вот над чем: все это части одного бизнес-контекста — пользовательского доступа. И целесообразно оставить их в одном сервисе. Это и есть DDD в действии.</p><p>Существует и еще одна проблема, с которой DDD помогает справиться, — неправильная нарезка сервисов с точки зрения бизнесовой функциональности. Если не понимать бизнес-контекста, можно получить «распределенный монолит»: будет много отдельно стоящих сервисов, но профита никакого, только все сложности микросервисов плюс проблемы монолита с масштабируемой базой данных. Особенно остро это проявляется, когда изменения в одной части бизнес-процесса (в одном сервисе) влекут за собой изменения еще в трех-четырех-пяти других сервисах.</p><p>DDD помогает выделить bounded context — согласованные по бизнесу участки. Они позволяют более или менее правильно нарезать большой бизнес-функционал на отдельные части.</p><p>Еще один важный принцип правильной архитектуры микросервисов — у каждого микросервиса должна быть своя независимая маленькая база данных (если она вообще нужна).</p><p><b>Два эмпирических правила, которые касаются размера сервисов и помогают понять, правильно ли они спроектированы:</b></p><ul><li>Если вы не можете переписать сервис за две недели, значит, возможно, он неправильно нарезан, и его нужно декомпозировать.</li><li>Если вам страшно браться за переписывание сервиса, значит, он точно кандидат на декомпозицию.</li></ul><p>Внедрение микросервисов: с чего начать?</p><p>С микросервисным подходом есть проблема — нет четкого ответа, куда идти и что делать, чтобы научиться его создавать. Это одна из главных сложностей микросервисной архитектуры, особенно когда только начинаешь с ней работать. Если хочется изучить Spring или Oracle, можно почитать официальную документацию. А к такой большой и необъятной теме, как микросервисы, даже и непонятно, с какой стороны подступиться. Туториала к ней нет, есть только куча статей, подходов и практик. Причем одни практики подойдут конкретной команде, а другие — нет.</p><p>И вот тут возникает реальная сложность, особенно когда вы только начинаете, — глаза разбегаются. Здесь Kubernetes, здесь ELK, здесь Grafana, здесь observability, здесь всякие паттерны отказоустойчивости, CAP-теорема и прочее. Непонятно, куда бежать. И каждый день появляются новые инструменты, которые так или иначе упрощают жизнь.</p><p>Совет: задавайте себе вопрос о каждом инструменте, который вы хотите внедрить (будь то Kubernetes, OpenTelemetry с Jaeger или любой другой) — какую проблему мы решаем, втаскивая его в свою инфраструктуру? Ответ на этот простой вопрос может дать много инсайтов и просветлений.</p><p>Чтобы в первом приближении ознакомиться с темой, можно почитать материалы <a href="https://sre.google/books/">SRE</a> от Google, также будут полезны статьи и книги в<a href="https://martinfowler.com/"> блоге</a> Мартина Фаулера, в том числе <a href="https://martinfowler.com/microservices/">Microservices Guide</a>. Если вам нужна практика, можно попробовать пойти на тот же Udemy, где есть множество курсов по микросервисной архитектуре с хорошими рейтингами и отзывами.</p><p>И вот что важно: при проектировании и внедрении микросервисов лучше избегать «велосипедостроения». Если индустрия уже решила проблему, нет смысла изобретать новое логирование или оркестрацию. Собственное решение вряд ли будет работать лучше, а сил, времени ресурсов на него можно потратить очень много.</p><h2>Поддержка микросервисной архитектуры</h2><p>Мы каждый день используем разные приложения — например, мобильный банк. Если в магазине длинная очередь, а на кассе у вас вдруг вылетает ошибка, — это раздражает. Поэтому у бизнеса нет права на ошибку: мониторинг должен срабатывать раньше, чем клиент успеет заметить, а инциденты необходимо устранять за минуты.</p><p>В крупных организациях микросервисов могут быть сотни: например, в некоторых системах насчитывается почти 700 микросервисов на продакшене. Каждый инстанс еще масштабирован — это тысячи подов, которые постоянно обрабатывают клиентский трафик. И при этом в современных условиях нужно стремиться к доступности системы на уровне четырех девяток (99,99%), то есть к простою всего в несколько минут в год.</p><p>Если вы хотите достичь того, чтобы простой вашего приложения был минимальным, приходится продумывать много разных подходов, приемов и инструментов.</p><h3>Паттерны отказоустойчивости</h3><p>Микросервисы — это не про «разбили монолит», это про то, что сбой одного сервиса не должен валить весь продукт. Поэтому если какой-то важный сервис упал, то максимум, который нужно сделать, — чтобы клиент не увидел упавший кусочек функционала приложения.</p><p>Еще один хороший вопрос: как мониторить аварии? Необходимо очень быстро находить точку отказа. Для этого, собственно, и нужен observability-подход, трейсинг. Нужно смотреть, где какой RPS (число запросов в секунду), не произошло ли резкого скачка трафика, важно следить за latency (задержками).</p><p>Бывали случаи, когда из-за бага в мобильном приложении трафик внезапно удваивался, и системы не выдерживали такой нагрузки. Любая малейшая задержка в самом незначительном компоненте может привести к тому, что по цепочке пойдет отказ, — будут копиться потоки, соединения, и рано или поздно упадет вообще все. Чтобы подготовиться к таким ситуациям, важно изучить хотя бы <a href="https://sre.google/sre-book/monitoring-distributed-systems/">четыре «золотых сигнала» мониторинга</a> из SRE от Google.</p><p>Совет: возьмите на вооружение парадигму проектирования на отказ. Исходите из того, что в любой момент что угодно может пойти не так. Сеть будет нестабильной, железо начнет падать, интеграции станут работать неправильно. Если изначально придерживаться этого принципа, вы здорово подстрахуете себя завтрашнего. Это всегда спасает, особенно когда получаешь по наследству что-то, что не было спроектировано с учетом этого принципа.</p><p>Сейчас часто используют паттерны, которые помогают поддерживать отказоустойчивость системы:</p><ul><li><b>Circuit Breaker</b> — если сервис спамит ошибками, лучше временно прекратить попытки до него достучаться. Для клиента ничего не изменится, он как получал ошибки, так и будет получать. Но, по крайней мере, можно дать системе возможность восстановиться. А еще лучше — позволить ей переключиться на какой-то резервный канал, например сходить в кэш с неактуальными данными.</li><li><b>Rate Limiter</b> — абсолютно банальная, но необходимая вещь. Нужно ограничивать входящий поток на примерно максимальном уровне от того, который ожидается. Чтобы все не развалилось, если произойдет резкий скачок трафика.</li><li><b>Blue-Green Deployment</b> — значительно снижают на продакшене количество аварий и проблем, связанных с кривыми релизами. Можно не раскатывать новую фичу сразу на все 100 подов, а выкатить ее только на 1% трафика и проверить.</li></ul><p>И это только малая часть паттернов.</p><p>Все это must have для абсолютно любой системы. Даже если у вас низкая нагрузка, она когда-нибудь увеличится. Лучше вовремя предусмотреть это, заранее потратив чуть больше времени и реализовав эти паттерны.</p><h3>Как эффективно работать с инцидентами</h3><p>Начало всех начал в траблшутинге — мониторинг. Здорово, когда разработчики понимают, как устроена их система, и уже вложились в мониторинг: есть дашборд, где можно посмотреть по уровням абстракций основные точки отказа.</p><p>Первый уровень — это application-слой, сами сервисы, которые в подах крутятся в Kubernetes. Нужно проверить, все ли у них хорошо по точкам интеграции — нет ли тайм-аутов. Все ли в порядке у них по железу — по CPU, по памяти, по дискам.</p><p>Если на первом уровне все нормально, нужно опуститься на уровень ниже — либо на виртуалки, на которых Kubernetes развернут, либо на железки, если он развернут на Bare-metal. Недавно мы столкнулись с интересным случаем: виртуалка показывала нормальную загрузку CPU, но физический гипервизор, на котором она крутилась, был загружен на 99%. Естественно, виртуалка страдала, но уровнем выше этого не было видно.</p><p>Совет: если вы вдруг нашли что-то, что еще не мониторится, — это повод поскорее добавить эту метрику, начать ее мониторить и ретроспективно отслеживать.</p><p>Еще одна важная вещь в работе с инцидентами — культура постмортемов. Ретроспективы по каждой аварии пишутся не просто так — их можно свести по категориям и понять, из-за чего чаще всего происходят аварии: например, из-за протухших сертификатов либо человеческого фактора в конфигурации. Категорий причин отказа обычно не так много. С постмортемами проще выработать стратегию технического инженерного развития.</p><p>Вообще, человеческий фактор — это отдельная боль. Все привыкли менять что-нибудь руками: заходить в виртуалки, поправлять конфиг. Чтобы такого было как можно меньше, важно вкладываться в infrastructure as a code и даже everything as a code. В идеале следует стремиться к zero access production — нулевому доступу к продакшену — и все раскатывать через Git, через конфигурации, включая политики безопасности.</p><h2>Культура ответственности и изменение ролей в команде</h2><p>Представим, что происходит инцидент — падают 15 микросервисов. Как должна быть устроена система, которая позволит оперативно справляться с авариями?</p><p>Организационно все достаточно просто — хотя не так просто на земле, при устранении инцидента. Все сервисы должны быть каталогизированы, сгруппированы по командам или продуктовым стримам. Необходима матрица эскалации, позволяющая найти по зоне ответственности человека, которому можно позвонить и попросить подключить необходимых инженеров.</p><p>Подобную конструкцию важно поддерживать в актуальном состоянии. Это часть процесса непрерывности, и в нее надо вкладываться. В крупных компаниях этим занимаются целые отделы, в небольших организациях — отдельный человек, но такая информация всегда должна быть в общем доступе. Иначе время «отскока» после инцидента увеличится кратно.</p><p>Желательно, чтобы в компании был специальный ситуационный центр, в котором сразу можно создать конференцию, если случилась авария, и поделиться информацией, чтобы все подключились к решению проблемы.</p><p>Однако эти организационные моменты еще не гарантируют быстрого решения проблемы. Ключевой фактор — культура компании. На людей часто нападает отстраненность — авария случилась, и все думают: «Кто-нибудь другой разрулит. Я разработчик, ну, что я там сделаю?»</p><p>Многие привыкли жить по старой парадигме: написали код, потестировали, отдали поддержке и забыли. Но культура в команде должна дорасти до такого уровня, когда каждый понимает: я не только разрабатываю или тестирую код, но еще и отвечаю за него на продакшене.</p><p>Из-за этого разрыва в осознании между командами поддержки и разработки возникают конфликты. У каждой разные цели, и зачастую одна команда не понимает, чего хочет другая. Чтобы лучше понять природу этих конфликтов, важно вспомнить про DevOps-культуру и SRE. В их парадигме разработчики не только пишут код, но и деплоят в продакшен.</p><p>Проще говоря, есть два варианта взаимодействия с поддержкой: классический, когда она административно отделена, и SRE-подобный, когда сотрудники «второй линии» прямо интегрированы в команду разработки. Могу сказать, что второй эффективнее.</p><p>При этом не обязательно сливать всех в одну плоскую структуру на уровне административного деления. Достаточно, чтобы люди, даже находясь в разных административных юнитах, работали как команда и коммуницировали постоянно, а не от случая к случаю. Важно, чтобы все были проактивными — если что-то случилось, сразу подрывались и по инструкции пытались устранить проблему.</p><p>Это то самое SRE, о котором пишет Google. Но людей нужно долго обучать такой культуре — это не дело одного месяца. Благодаря такому подходу инженеры, которые раньше были просто разработчиками или аналитиками, глубже осознают свою ответственность за стабильность продакшена. И это действительно правильное направление развития. Потому что и DevOps, и SRE — это в первую очередь культура, а уже во вторую — набор инструментов.</p><h3>Будущее микросервисов: тренд на AI Ops</h3><p>Разработчики уже используют AI как copilot — и это очень мощный инструмент в умелых руках. Он не заменяет инженера, но сильно экономит ему время. Эту помощь от нейросетей очень хочется растянуть и на инфраструктуру, и на эксплуатацию, чтобы получить крутой AI Ops.</p><p>Нейросеть будет находить протухшие сертификаты внутри инфраструктуры, работать инструментом для early warning, подсвечивать риски.Кажется, что все инструменты для этого есть уже сейчас. Надо только, чтобы кто-то сложил этот пазл в рабочее решение.</p><p>Есть прототипы — например, Big Panda или Moocsoft (который был недавно куплен Dell), но пока это точечные решения. Возможно, на горизонте 5–7 лет (скорее 5, чем 10) они станут серьезной частью индустрии и очень мощным прорывом, который упростит разработчикам жизнь.Кроме того, важно, чтобы развивались и более «приземленные» технологии: инструменты контейнеризации, оркестрации, observability, а также APM — Application Performance Monitoring.</p><h3>Инженер остается в центре всего</h3><p>Никакие микросервисы, Kubernetes и AI Ops не спасут, если за системой не стоит инженер, который думает головой, правильно работает руками и отвечает за результат. Важны его навыки, кругозор и культура работы. Именно такие люди превращают набор сервисов в работающий продукт. Все остальное — только инструменты.</p><p>P. S. Если интересно, как мы решаем эти задачи на практике, <a href="https://technologichno.mave.digital/">слушайте </a>(и <a href="https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Fvkvideo.ru%2Fvideo-145457488_456239831&amp;postId=1982175">смотрите</a>) наш подкаст «Техно.Логично» — там регулярно обсуждаем самое актуальное в IT-сфере.</p>]]></content:encoded>
    </item>
    <item>
      <title>Монолит или микросервисы: какую архитектуру выбрать для нового проекта</title>
      <link>https://tproger.ru/articles/monolit-ili-mikroservisy--kak-vybrat-arhitekturu-dlya-novogo-proekta</link>
      <comments>https://tproger.ru/articles/monolit-ili-mikroservisy--kak-vybrat-arhitekturu-dlya-novogo-proekta?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/monolit-ili-mikroservisy--kak-vybrat-arhitekturu-dlya-novogo-proekta</guid>
      <description><![CDATA[<p>Монолит или микросервисы. Показываем основные критерии выбора архитектуры нового проекта. Рассматриваем плюсы и минусы ✔ Tproger
</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/monolit-ili-mikroservisy--kak-vybrat-arhitekturu-dlya-novogo-proekta">Монолит или микросервисы: какую архитектуру выбрать для нового проекта</a>»</p>]]></description>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[Архитектура ПО]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 02 Dec 2024 15:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>При создании нового проекта выбрать правильную архитектуру необходимо, ведь это влияет на скорость разработки, масштабируемость и долгосрочную поддержку системы. Монолитная архитектура обеспечивает простоту и целостность, но может быть сложной в масштабировании. Микросервисы обеспечивают гибкость и независимость компонентов, но требуют продуманного подхода к интеграции и управлению. Сегодня рассмотрим разницу между монолитом и микросервисами, ключевые особенности каждой архитектуры и поможем вам сделать осознанный выбор.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2024-11-27/499fddb7-3212-4a4f-ab60-a65d318ffd08.png" alt="" /></figure><h2>Определение и особенности монолитной архитектуры</h2><h3>Что такое монолитная архитектура и какие у неё основные характеристики</h3><p>Монолитная архитектура представляет собой единую программную систему, в которой все модули и компоненты приложения тесно связаны и работают как единое целое. Вся логика приложения — от пользовательского интерфейса до базы данных — включена в единое приложение, которое развертывается и управляется как единое целое.</p><p><b>Основные характеристики:</b></p><ul><li>Единое хранилище кода и структур данных.</li><li>Тесная взаимосвязь компонентов: изменения в одном модуле часто требуют обновлений в других.</li><li>Унифицированное развертывание: приложение разворачивается в одном контейнере или среде.</li></ul><h3>Плюсы монолита</h3><ul><li><b>Простота разработки.</b> Все компоненты находятся в одном репозитории, что упрощает работу команды. Так, разработчики могут сосредоточиться на функциональности, а не на взаимодействии между сервисами. Плюс разработчики быстрее ориентируются в архитектуре.</li><li><b>Единое развертывание. </b>Нет необходимости управлять множеством сервисов, а обновление системы требует лишь одной операции деплоя.</li><li><b>Легкость тестирования. </b>Общее тестирование всех компонентов можно проводить в одной среде. А еще проще реализовать интеграционные и функциональные тесты.</li><li><b>Удобство в небольших командах</b>. Подходит для стартапов или проектов с ограниченными ресурсами, где важно быстро приступить к работе.</li></ul><h3>Минусы монолита</h3><ul><li><b>Сложность масштабирования.</b> Масштабирование требует копирования всего приложения, даже если нужно повысить производительность только одной его части. Плюс если высокую нагрузку испытывает лишь одна часть приложения, увеличивать производительность приходится для всей системы.</li><li><b>Зависимость компонентов.</b> Любое изменение в одном модуле может привести к непредсказуемым последствиям в других частях системы. К тому же трудно изолировать ошибки и снижать взаимные влияния между частями приложения.</li><li><b>Долгосрочная поддержка. </b>Переход на новые технологии требует переработки всей системы. Например, если монолитная архитектура построена на устаревшей версии фреймворка, переход на более современный инструмент требует изменений во всех связанных модулях, включая базу данных, пользовательский интерфейс и API.</li><li><b>Риск единой точки отказа.</b> Ошибка в одном компоненте может привести к полной остановке всего приложения.</li></ul><p>Монолитная архитектура подходит для небольших и средних проектов с ограниченными требованиями к масштабированию, где важны скорость разработки и простота управления. Однако для крупных динамично развивающихся систем она может стать сдерживающим фактором.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2024-11-27/fb74667c-b881-4215-98fa-d22b2d4b83e4.jpg" alt="" /></figure><h2>Определение и особенности микросервисной архитектуры</h2><h3>Что такое микросервисная архитектура и её ключевые аспекты</h3><p>Микросервисы как архитектура представляет собой подход, при котором приложение разбивается на независимые модули (микросервисы). Каждый микросервис выполняет определённую бизнес-функцию, имеет собственную базу данных (или доступ к её сегменту) и взаимодействует с другими через API.</p><p><b>Ключевые аспекты:</b></p><ul><li>Микросервисы разрабатываются, развёртываются и масштабируются отдельно.</li><li>Каждый микросервис отвечает за конкретную бизнес-логику.</li><li>Микросервисы могут использовать различные языки программирования, базы данных и фреймворки, что позволяет выбрать оптимальный инструмент для каждой задачи.</li></ul><h3>Плюсы микросервисов</h3><ul><li><b>Гибкость. </b>Микросервисы можно развивать независимо друг от друга. Так, в музыкальные стриминги (по типу Яндекс.музыки) новый функционал приложения можно добавлять без изменения сервиса, отвечающего за управление библиотекой треков.</li><li><b>Масштабируемость.</b> Каждый микросервис масштабируется отдельно в зависимости от нагрузки. Не нужно тратить время и мощности но прокачку одних и тех же функций одновременно, а сосредоточиться на приоритетных.</li><li><b>Независимое развертывание.</b> Обновление одного микросервиса не требует остановки всей системы. Например, если в приложении нужно обновить модуль расчёта стоимости (если мы разрабатываем Ozon или WB), это не повлияет на работу модуля оформления заказов.</li></ul><h3>Минусы микросервисов</h3><ul><li><b>Сложность в настройке.</b> Организация микросервисной архитектуры требует грамотной настройки инфраструктуры. Например, необходимо настроить API-шлюз для управления запросами, систему контейнеризации (например, Docker) и оркестрацию (Kubernetes).</li><li><b>Необходимость управления сетью. </b>Микросервисы взаимодействуют через сеть, что может приводить к задержкам и ошибкам. Например, если сервис обработки платежей не отвечает из-за проблем с сетью, процесс оформления заказа на том же Озоне может быть временно недоступен.</li><li><b>Сложности в тестировании.</b> Интеграционное тестирование требует симуляции взаимодействия между десятками или сотнями сервисов.</li></ul><p>Микросервисная архитектура идеально подходит для крупных проектов или систем, которым требуется гибкость и масштабируемость. Она позволяет разделить приложение на независимые компоненты, что упрощает развитие и обновление системы, особенно в условиях изменяющихся бизнес-требований.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2024-11-27/990eee10-701c-4b1c-805a-4e8e3a9d5e32.webp" alt="" /></figure><h2>Сравнение монолита и микросервисов</h2><p>При выборе архитектуры важно учитывать ключевые аспекты, которые влияют на производительность, масштабируемость, удобство поддержки и организацию командной работы. Поговорим об отличиях монолитов от микросервисов.</p><p>Производительность: какая архитектура быстрее и почему</p><p><b>Монолит</b></p><p>Монолитные приложения выигрывают в производительности благодаря отсутствию сетевых вызовов между компонентами. Например, если в приложении есть функция расчёта скидки и оформления заказа, в монолите эти операции выполняются быстрее, так как всё обрабатывается в едином контексте без дополнительных задержек.</p><p><b>Микросервисы</b></p><p>Микросервисы могут быть медленнее из-за сетевых взаимодействий между компонентами. В приложении с такой архитектурой расчёт скидки может быть отдельным сервисом, и каждый запрос к нему потребует сетевого соединения. Однако микросервисы позволяют распределять нагрузку, обеспечивая высокую производительность при большом количестве пользователей.</p><p>Масштабируемость: вертикальное и горизонтальное масштабирование</p><p><b>Монолит</b></p><p>Плюс монолита в том, что его масштабирование осуществляется вертикально (больше оперативной памяти —&gt; мощнее процессор). Это быстро, но дорого, и есть физические ограничения на увеличение ресурсов.</p><p><b>Микросервисы</b></p><p>Поддерживают горизонтальное масштабирование, позволяя увеличивать производительность за счёт запуска дополнительных копий только нужных сервисов. Например, если нагрузка растёт на модуль обработки платежей, администратор может увеличить количество инстансов только этого сервиса, не затрагивая остальные части приложения.</p><p>Поддержка и обновление: как быстро можно добавлять новые функции</p><p><b>Монолит</b></p><p>В монолите изменения требуют работы с общей кодовой базой. Так, добавление нового фильтра в поисковую систему потребует изменений в коде и обязательного тестирования всего приложения. Это может замедлить внедрение обновлений, особенно в сложных системах.</p><p><b>Микросервисы</b></p><p>Каждый микросервис разрабатывается и обновляется независимо. Например, добавление нового фильтра в ту же поисковую систему можно реализовать как отдельный сервис, что не затронет работу других компонентов. Это позволяет быстрее развивать функциональность приложения.</p><p>Командная работа: как архитектура влияет на распределение задач в команде</p><p><b>Монолит</b></p><p>Подходит для небольших команд, так как вся разработка сосредоточена в одной кодовой базе. Однако в крупных командах может возникать путаница: одновременно работать над различными функциями сложно из-за пересечения задач и конфликтов.</p><p><b>Микросервисы</b></p><p>Позволяют разделить задачи между командами, так как каждая  отвечает за свой микросервис. Например, одна команда может работать над модулем аналитики, а другая — над модулем рекомендаций, не мешая друг другу. Это делает микросервисы идеальными для крупных проектов с распределёнными командами.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2024-11-27/a1c18a40-2d4e-4718-9690-a9d23d3f962e.png" alt="" /></figure><h2>Факторы, которые влияют на выбор архитектуры</h2><p>Выбор между монолитной и микросервисной архитектурой зависит от множества факторов, например, особенностей команды, масштаба проекта, технических требований и доступных ресурсов. Так что же выбрать?</p><h3>Размер и опыт команды разработчиков</h3><p><b>Маленькая команда</b></p><p>Если команда небольшая и состоит из 3–5 человек, лучше начать с монолитной архитектуры. Например, для стартапа с ограниченным бюджетом разработка единой кодовой базы будет быстрее и эффективнее, так как все участники смогут работать в одном контексте без разделения на сервисы.</p><p><b>Большая команда</b></p><p>В случае крупной команды, где каждая группа имеет узкую специализацию (например, фронтенд, бэкенд, аналитика), микросервисы становятся более подходящим решением. Так, отдельная команда может заниматься разработкой API для управления пользователями, не мешая работе команды, отвечающей за обработку платежей.</p><p><b>Уровень опыта</b></p><p>Новичкам проще начать с монолита, где всё сосредоточено в одном месте. Микросервисы требуют знания работы с сетями, управления контейнерами и настройки взаимодействия сервисов, что может быть сложно для начинающих.</p><h3>Сложность и масштаб проекта</h3><p><b>Простые проекты</b></p><p>Для небольших приложений монолитная архитектура подходит идеально.</p><p><b>Сложные и крупные проекты</b></p><p>Если проект включает множество связанных функций, типа интернет-магазина с рекомендациями, платежной системой, логистикой и аналитикой, микросервисы становятся более предпочтительными. Разделение функционала на отдельные сервисы позволяет легче масштабировать и обновлять отдельные части системы.</p><h3>Требования к производительности и масштабируемости</h3><p><b>Низкие требования</b></p><p>Если приложение обслуживает ограниченное количество пользователей, например, внутренний инструмент для команды из 50 человек, монолитная архитектура будет более эффективной. Она обеспечит стабильную производительность без сложных настроек.</p><p><b>Высокие требования</b></p><p>Для приложений с миллионами пользователей микросервисы обеспечивают гибкость и возможность горизонтального масштабирования. Например, если растёт нагрузка на видео-хостинг, можно увеличить количество экземпляров только сервиса трансляции.</p><h3>Планы на будущее и возможность роста проекта</h3><p><b>Краткосрочные проекты</b></p><p>Для приложений с коротким жизненным циклом лучше выбрать монолит. Например, MVP для тестирования идеи легче разработать именно так, поскольку это позволяет быстрее выйти на рынок.</p><p><b>Долгосрочные проекты</b></p><p>Если приложение предполагается развивать на протяжении многих лет с добавлением новых функций, микросервисы могут быть более удобны. Например, в крупной ERP-системе с постоянным расширением функционала проще добавлять новые сервисы, не нарушая работу существующих.</p><h3>Инфраструктура и доступные ресурсы</h3><p><b>Ограниченная инфраструктура</b></p><p>Монолитные приложения не требуют сложной инфраструктуры. Их можно развернуть на одном сервере и минимизировать затраты на администрирование.</p><p><b>Развитая инфраструктура</b></p><p>Вам нужно настроить архитектуру, и микросервисы в этом случае потребуют контейнеризации (Docker), оркестрации (Kubernetes) и мощных инструментов мониторинга.</p><p>Выбор архитектуры зависит от целей и условий проекта. Для небольших приложений с ограниченными ресурсами и командами монолит — быстрый и эффективный выбор. Для крупных систем с перспективой роста и распределёнными командами микросервисы предлагают гибкость, масштабируемость и независимость в разработке. Важно учитывать баланс между текущими потребностями и будущими планами, чтобы архитектура оставалась жизнеспособной на протяжении всего жизненного цикла проекта.</p><h2>Кейсы, или практические советы по выбору архитектуры</h2><p>Попробуем подобрать подходящую архитектуру на конкретных кейсах. Для примера возьмем сферу электронной коммерции (раз уж мы много говорили про маркетплейсы).</p><h3>Когда стоит использовать монолит</h3><ul><li><b>Простые проекты.</b> Локальный магазин для продажи органической продукции, где пользователь может оформить заказ через простую корзину, а администратор получает уведомление на почту.</li><li><b>Стартапы с ограниченными ресурсами.</b> Новый бренд, продающий уникальные дизайнерские украшения, быстро запускает MVP с базовыми функциями: каталог, корзина, оплата и личный кабинет.</li><li><b>Приложения без высоких требований к масштабируемости.</b> Интернет-магазин для корпоративных клиентов, где покупки совершаются нерегулярно, и основная нагрузка на сервер минимальна.</li></ul><h3>Когда подходят микросервисы</h3><ul><li><b>Крупные проекты.</b> Большой интернет-магазин с тысячами товаров, сложной структурой категорий и разными модулями (каталог, поиск, рекомендации, платежи).</li><li><b>Распределённые команды.</b> Когда команда в одной стране разрабатывает сервис логистики, а команда в другой — систему интеграции с локальными платёжными провайдерами.</li><li><b>Приложения с высокой нагрузкой. </b>Маркетплейс, который обрабатывает миллионы запросов в секунду, поддерживает сложные фильтры, рекомендации и динамическое ценообразование.</li></ul><h2>Как перейти с монолита на микросервисы</h2><figure><img src="https://media.tproger.ru/user-uploads/102593/2024-11-27/1c2f47e4-31df-4ffa-9833-57beff3954f0.png" alt="" /></figure><h4>1. Оцениваем текущую архитектуру</h4><p>Для начала выявляем модули с наибольшей нагрузкой. Так, если монолитный интернет-магазин испытывает перебои из-за частых запросов к каталогу товаров, начинаем с выделения поиска в отдельный микросервис.</p><h4>2. Разрабатываем стратегию миграции</h4><p>Постепенно выносим модули, сохраняя функциональность. То есть сначала выносим модуль обработки платежей в отдельный сервис, затем переходим к модулям рекомендаций и аналитики.</p><h4>3. Обеспечиваем инфраструктуру</h4><p>Настраиваем контейнеризацию для запуска микросервисов (например, Docker для микросервисов каталога и управления заказами с общей базой данных).</p><h4>4. Используем очередь сообщений</h4><p>Реализуем асинхронное взаимодействие сервисов. Можем настроить очередь RabbitMQ для передачи данных о новых заказах от фронтэнда к микросервису логистики.</p><h4>5. Тестируем взаимодействие сервисов</h4><p>Постоянно проверяем корректность обмена данными. Так, тестируем модуль интеграции с внешними складами, чтобы убедиться в правильной обработке информации о наличии товаров.</p><h2>Примеры реальных проектов и их архитектурных решений</h2><h3>Примеры компаний, которые используют монолит и преуспели в этом</h3><h4>Basecamp</h4><p><a href="https://vizologi.com/basecamp-business-model-how-basecamp-works-makes-money/">Basecamp</a> —  популярный инструмент для управления проектами. Он известен своей монолитной архитектурой. Для команды Basecamp это решение значительно облегчает внедрение новых функций и упрощает развертывание, так как все компоненты находятся в одной кодовой базе.</p><h4>Shopify</h4><p><a href="https://mehmetozkaya.medium.com/shopifys-modular-monolithic-architecture-a-deep-dive-%EF%B8%8F-a2f88c172797">Shopify</a>, одна из крупнейших платформ для создания интернет-магазинов, на ранних этапах своего роста использовала монолитную архитектуру. В отличие от многих других компаний, которые переходят на микросервисы, Shopify создала гибкую систему в рамках монолита, которая поддерживает стабильность и масштабируемость, не перегружая инфраструктуру. Несмотря на это, они также внедряли элементы модульности в свой монолит, что позволяло сохранять производительность при росте компании​.</p><h4>GitHub</h4><p><a href="https://www.infoq.com/articles/github-monolith-microservices/">GitHub</a>, крупнейшая платформа для хостинга и совместной разработки ПО, также начинала с монолитной архитектуры. Этот подход позволил поддерживать высокую скорость разработки и эффективность работы небольшой команды. В дальнейшем GitHub внедрил стратегию масштабирования внутри своего монолита, что позволило им эффективно справляться с растущими требованиями без перехода на микросервисы на первых этапах​.</p><h3>Примеры компаний, которые выбрали микросервисную архитектуру</h3><h4>Netflix</h4><p><a href="https://netflixtechblog.com/">Для масштабируемости и высокой доступности</a> Netflix перешел от монолитной архитектуры к микросервисам. Это позволило им эффективно обрабатывать большое количество запросов пользователей и улучшить управление различными компонентами системы.</p><h4>Amazon</h4><p><a href="https://aws.amazon.com/ru/microservices/">Amazon</a>, особенно его платформа Amazon Web Services (AWS), также широко использует микросервисы. Переход к такой архитектуре позволил Amazon улучшить управление масштабируемостью, изоляцию сбоев и гибкость развертывания. Каждый сервис отвечает за отдельную задачу, что делает платформу более гибкой и облегчает масштабирование отдельных компонентов.</p><h2>Ошибки, которых стоит избегать при выборе и реализации архитектуры</h2><h4>1. Вы не понимаете требования</h4><p>Ошибки могут возникать, если архитектура выбирается без детального анализа потребностей проекта. Это может привести к излишней сложности и необходимости управления множеством сервисов, которые не нужны на первых этапах.</p><p><i>Совет: </i>Тщательно анализируйте требования к масштабируемости, безопасности, производительности и возможностям роста, прежде чем принимать решение о типе архитектуры.</p><h4>2. Вы не учитываете долгосрочные последствия</h4><p>При использовании монолитной архитектуры может быть сложно адаптировать систему под новые требования по мере роста. В то же время излишняя фрагментация в микросервисах приводит к значительным затратам на управление и координацию, особенно если проект не хочет масштабироваться.</p><p><i>Совет:</i> Планируйте архитектуру с учётом будущих потребностей и возможности масштабирования, но не усложняйте проект без реальной необходимости.</p><h4>3. Вы игнорируете опыт и возможности команды</h4><p>Выбор архитектуры должен учитывать не только требования проекта, но и опыт вашей команды. Чтобы развернуть микросервисы, в тиме должны быть опытные DevOps-специалисты. И в целом все сотрудники должны обладать сильными навыками для настройки, управления и мониторинга такой архитектуры.</p><p><i>Совет</i>: Оцените техническую зрелость и возможности вашей команды, чтобы понять, будет ли она в состоянии поддерживать сложную архитектуру.</p><h4>4. У вас проблемы с тестированием</h4><p>При использовании микросервисной архитектуры сложнее поддерживать тестирование, так как необходимо чекать не только отдельные сервисы, но и взаимодействие между ними. В монолитной архитектуре тестирование проще, но с увеличением объема кода и сложности системы это может стать проблемой.</p><p><i>Совет:</i> Убедитесь, что для выбранной архитектуры предусмотрены необходимые стратегии тестирования, чтобы минимизировать риски ошибок при развертывании.</p><h4>5. Вы не уделяете внимание безопасности</h4><p>Независимо от выбранной архитектуры, безопасность всегда должна быть приоритетом. Микросервисы, в свою очередь, увеличивают поверхность атаки из-за множества сервисов, а монолит может быть уязвимым, если не принято должное внимание к его изоляции и защите данных.</p><p><i>Совет</i>: Включите в архитектурное проектирование практики безопасности с самого начала, независимо от того, выбрали вы монолит или микросервисы.</p><p>Эти ошибки можно избежать, тщательно планируя архитектуру, принимая во внимание как текущие потребности, так и потенциальные вызовы в будущем.</p>]]></content:encoded>
    </item>
    <item>
      <title>10 ошибок в архитектуре, которые ломают проекты. Проверьте, не совершаете ли вы их</title>
      <link>https://tproger.ru/articles/10-owibok-v-arhitekture--kotorye-lomayut-proekty--proverte--ne-soverwaete-li-vy-ih</link>
      <comments>https://tproger.ru/articles/10-owibok-v-arhitekture--kotorye-lomayut-proekty--proverte--ne-soverwaete-li-vy-ih?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/10-owibok-v-arhitekture--kotorye-lomayut-proekty--proverte--ne-soverwaete-li-vy-ih</guid>
      <description><![CDATA[<p>
Рассмотрим 10 распространённых ошибок в архитектуре, способных негативно повлиять на проект. Узнаем о ключевых рисках и даем рекомендации по их предотвращению, чтобы сделать разработку надежной и эффективной.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/10-owibok-v-arhitekture--kotorye-lomayut-proekty--proverte--ne-soverwaete-li-vy-ih">10 ошибок в архитектуре, которые ломают проекты. Проверьте, не совершаете ли вы их</a>»</p>]]></description>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Баги и ошибки]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 06 Nov 2024 10:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Ваша архитектура — это фундамент, на котором строится успех проекта, и даже малейшая ошибка может перерасти в серьёзные сложности. Сегодня узнаем о 10 типичных ошибках, которые могут разрушить даже самый многообещающий стартап и поможем их избежать. Готовы проверить, не попались ли вы в одну из ловушек? Давайте разбираться!</p><h2>Ошибка 1: Вы зависите от одного провайдера облачных услуг</h2><p>Зависимость от одного облачного провайдера может стать серьезной проблемой, если в будущем возникнет потребность изменить инфраструктуру, мигрировать на другой сервис или если провайдер столкнётся с техническими сбоями, изменит условия обслуживания и т.д.</p><h3>Реальные примеры ошибки</h3><p>1. <a href="https://kinsta.com/blog/aws-outage/">AWS Outage в 2017 году:</a></p><p>В феврале 2017 года Amazon Web Services (AWS) испытал длительное отключение в одном из своих дата-центров, что повлияло на множество приложений и сервисов, зависящих от их облачных услуг. Многие компании — Slack, Trello и Airbnb, столкнулись с проблемами, что привело к сбоям в их сервисах. Этот случай продемонстрировал уязвимость зависимых систем.</p><p>2. <a href="https://engineering.linkedin.com/blog/2016/06/linkedins-journey-to-the-cloud">Опасности «lock-in» в облачных платформах:</a></p><p>Компания LinkedIn, которая изначально использовала облачные сервисы одного провайдера, столкнулась с проблемами при попытке перейти на другой сервис, когда осознала, что большая часть их архитектуры была завязана на конкретных инструментах этого провайдера. Это создало дополнительные трудности и увеличило затраты на миграцию.</p><h3>Как командам избежать этой ошибки</h3><p><b>1. Используйте многооблачную стратегию:</b></p><p>Многооблачная архитектура позволяет распределить ресурсы между несколькими провайдерами (например, AWS, Google Cloud, Microsoft Azure). Это снизит зависимость от одного поставщика и сделает систему более устойчивой и гибкой.</p><p><b>2. Стандартизуйте API и интерфейсы:</b></p><p>Проектирование системы с использованием стандартных интерфейсов (например, RESTful API) позволяет легче менять облачные услуги без значительных нововведений в коде.</p><p><b>3. Обрабатывайте данные в гибридной модели:</b></p><p>Некоторые данные могут храниться локально, что позволяет избежать потери доступа в случае отключения облачного провайдера. Также команды могут контролировать вопросы безопасности.</p><p><b>4. Используйте контейнеризацию:</b></p><p>Использование контейнеров (например, Docker) и оркестрация (например, Kubernetes) позволяет переносить приложения между различными облачными провайдерами без значительных изменений в инфраструктуре.</p><h2>Ошибка 2: У вас нет кэширования</h2><p>Отсутствие механизма кэширования в приложении может привести к завышенным требованиям к производительности и увеличению времени отклика, особенно в условиях высокой нагрузки. Если система не использует кэширование для часто запрашиваемых данных, это может создать различные проблемы — задержки в обработке запросов и высокие затраты на ресурсы.</p><h3>Реальные примеры ошибки</h3><p><b>1. <a href="https://netflixtechblog.com/how-we-optimize-cost-performance-on-the-cloud-4a9d9c64e132">Netflix</a>:</b></p><p>Netflix сталкивался с проблемами производительности, когда пользователи запрашивались множество однотипных данных (метаданные о фильмах, например). Это привело к значительным нагрузкам на базы данных и увеличивало время отклика.</p><p><b>2. <a href="https://medium.com/pinterest-engineering/scaling-pinterest-how-we-manage-our-caching-strategy-baf474d19f9a">Pinterest</a>:</b></p><p>Pinterest на начальной стадии своего развития не использовал эффективное кэширование, что приводило к медленной загрузке страницы и, соответственно, изображений. После внедрения системы кэширования, основанной на Redis, они смогли ускорить загрузку и значительно улучшить пользовательский опыт.</p><h3>Как командам избежать этой ошибки</h3><p><b>1. Выбирайте подходящий механизм кэширования:</b></p><p>Команда должна определить, какой тип кэширования лучше всего подходит для их приложения: кэш на уровне сервера (например, Memcached, Redis) или кэширование на стороне клиента (например, браузерное).</p><p><b>2. Кэшируйте часто запрашиваемые данные:</b></p><p>Определите «горячие» данные и кэшируйте их, чтобы сократить время доступа. Например, конфигурационные параметры, метаданные и т.д.</p><p><b>3. Используйте HTTP-кэширование:</b></p><p>Здесь помогут заголовки HTTP Cache-Control, ETag и Last-Modified, чтобы управлять кэшированием на уровне сервера и клиента.</p><p><b>4. Обновляйте кэш:</b></p><p>Разработайте стратегию для обновления кэша, например, с использованием TTL (времени жизни кэша), или при изменении данных в базе, чтобы актуализировать информацию. Конечно, не забывайте периодически кэш чистить (почувствуй себя уточкой с метлой из Телеграма).</p><h2>Ошибка 3: Вы неправильно структурировали базу данных</h2><p>Неправильное проектирование структуры базы данных может ухудшить производительность, дублировать данные и плохо  поддерживать их целостность. Неправильная нормализация (или наоборот, чрезмерная нормализация) может усугубить ситуацию, делая взаимодействие с базой данных неэффективным.</p><h3>Реальные примеры ошибки</h3><p><b>1. <a href="https://www.forbes.com/sites/bernardmarr/2019/05/21/how-delta-air-lines-uses-the-cloud-and-data-to-enhance-passenger-experience/?sh=174d285b7cb5">Delta Airlines</a>:</b></p><p>Delta Airlines столкнулась с проблемами производительности своей базы данных. Причиной стало плохое проектирование, что замедлило обработку онлайн-бронирований. Для решения проблемы компании пришлось значительно переработать архитектуру базы данных — оптимизировать структуру таблиц и индексов.</p><p><b>2. <a href="https://engineering.fb.com/2014/06/24/data-infrastructure/the-evolution-of-facebooks-storage-infrastructure/">Facebook</a>*:</b></p><p>В ранние годы Facebook испытывал проблемы с масштабированием своей базы данных, которая была неправильно нормализована. Пришлось перепроектировать архитектуру и внедрять более сложные алгоритмы кэширования, чтобы поддерживать эффективность работы с данными из-за числа пользователей.</p><p><i>*Компания Meta признана экстремистской на территории РФ</i></p><h3>Как командам избежать этой ошибки</h3><p><b>1. Проектируйте БД на основе требований:</b></p><p>Это база! (данных). Перед началом проектирования важно анализировать бизнес-требования, чтобы понять, как данные будут использоваться. Это поможет определить, какие таблицы и связи необходимы.</p><p><b>2. Следуйте правилам нормализации:</b></p><p>Проектирование базы данных с учётом принципов нормализации снижает риск дублирования и обеспечивает их целостность. При этом учитывайте, что чрезмерная нормализация может требовать более сложных соединений и замедления запросов.</p><p><b>3. Используйте индексы:</b></p><p>Установка индексов на поля, которые часто используются в условиях WHERE и JOIN, может значительно улучшить производительность запросов. Но следует также осторожно подходить к индексированию, чтобы не перегружать систему.</p><p><b>4. Поддерживайте архивирование и шардирование данных:</b></p><p>Если БД становится слишком большой, следует рассмотреть возможность шардирования (разделение базы на части) или архивирования старых данных.</p><p><b>5. Используйте инструменты моделирования баз данных:</b></p><p>Применение инструментов по типу ER-диаграмм для визуализации структуры базы данных может помочь лучше понять связи между данными и выявить потенциальные проблемы до их реализации.</p><h2>Ошибка 4: Вы не используете микросервисную архитектуру для масштабируемых систем</h2><p>Использование монолитной архитектуры вместо микросервисной в масштабируемых системах может привести к проблемам с гибкостью и управляемостью приложения. Монолитные системы часто становятся трудными для обновления и поддержания, так как все компоненты плотно связаны, а изменения в одном месте могут повлиять на другие части системы.</p><h3>Реальные примеры ошибки</h3><p><b>1. <a href="https://engineering.atspotify.com/2018/02/07/breaking-free-from-monolith-how-spotify-scaled-agile/">Spotify</a>:</b></p><p>В своих ранних версиях Spotify использовал монолитную архитектуру, что привело к сложности в развертывании новых функций. Каждый релиз требовал тестирования всей системы, что замедляло процесс обновлений. В результате команда приняла решение перейти к микросервисам, что позволило ускорить цикл разработки и улучшить возможность развертывания.</p><p><b>2. <a href="https://www.computerworld.com/article/2940509/paypal-transforms-itself-by-embracing-microservices.html">PayPal</a>:</b></p><p>PayPal изначально была построена как монолитная архитектура, что стало проблемой, когда компания начала испытывать взрывной рост. Это привело к заторам в разработке и  управлении разными компонентами. Переведя свою систему на микросервисы, они смогли значительно улучшить гибкость и сильно сократить время на внедрение новых функций.</p><h3>Как командам избежать этой ошибки</h3><p><b>1. Определите границы сервисов:</b></p><p>Чёткое определение доменных границ для каждого микросервиса поможет избежать дублирования функций и повысить устойчивость системы. Каждый микросервис должен быть ответственен только за конкретный набор задач.</p><p><b>3. Используйте API для взаимодействия:</b></p><p>Микросервисы должны общаться друг с другом через API. Что важно, это способствует независимости одного сервиса от другого и делает каждый более масштабируемым.</p><p><b>4. Внедряйте DevOps и CI/CD:</b></p><p>Для успешного развертывания и управления микросервисами необходимо внедрить практики DevOps и непрерывной интеграции и доставки (CI/CD). К ним относится автоматизация тестирования, деплоймента и управления версиями.</p><p><b>5. Переходите к микросервисам постепенно:</b></p><p>Вместо полной миграции на микросервисную архитектуру стоит рассмотреть возможность постепенного перехода, выделяя более связанные части приложения, что упростит процесс и уменьшит риски.</p><h2>Ошибка 5: Вы игнорируете принцип единственной ответственности (Single Responsibility Principle)</h2><p>Принцип единственной ответственности (SRP) предполагает, что каждый класс или модуль должен выполнять одну функциональную задачу. Игнорирование этого принципа может привести к чрезмерной связности и сложности кода, что затрудняет его тестирование, отладку, модификацию и поддержку.</p><h3>Реальные примеры ошибки</h3><p><a href="https://kinsta.com/blog/aws-outage/">1. Одна из</a><a href="https://martinfowler.com/books/refactoring.html"> E-commerce платформ</a><a href="https://martinfowler.com/books/refactoring.html"></a></p><p>В ранней версии e-commerce платформы класс Order обрабатывал и управление заказами, и логику расчёта налогов, и взаимодействие с платёжным процессором. Это усложняло управление кодом и добавляло риски при любых изменениях. После переработки системы с использованием SRP была создана отдельная служба расчёта налогов и платёжная служба, что значительно упростило код и улучшило его тестируемость.</p><h3>Как командам избежать этой ошибки</h3><p><b>1. Определите задачи каждого модуля или класса:</b></p><p>На этапе проектирования приложения важно чётко определить задачи каждого модуля или класса. Они должны быть узко сфокусированы, что поможет упростить логику.</p><p><b>2. Используйте абстракции и интерфейсы:</b></p><p>Следует использовать интерфейсы и абстракции для определения контрактов, что позволит организовать код вокруг обязанностей и снизит связанность между компонентами.</p><p><b>3. Применяйте паттерны проектирования:</b></p><p>Использование паттернов проектирования, таких как Strategy или Observer, может помочь разделить ответственности между классами и облегчить модификацию и расширение функциональности.</p><h2>Ошибка 6: У вас нет системы мониторинга и логирования</h2><p>Отсутствие адекватной системы мониторинга и логирования ведёт к тому, что команда не может быстро идентифицировать и устранять проблемы в приложении. Если нет возможности собирать и анализировать данные, сложно понять, где возникают узкие места, как ведёт себя приложение под нагрузкой и какие ошибки возникают у пользователей.</p><h3>Реальные примеры ошибки</h3><p><b>1. <a href="https://eng.uber.com/the-evolution-of-ubers-engineering-culture/">Uber</a>:</b></p><p>В начале своего развития Uber сталкивался с проблемами, связанными с отслеживанием производительности своей системы. Отсутствие эффективного мониторинга привело к тому, что команда долго не могла выяснить причины нестабильной работы приложения.</p><p><b>2. <a href="https://engineering.linkedin.com/blog/2014/12/how-linkedin-scales-lessons-in-monitoring">LinkedIn</a>:</b></p><p>LinkedIn несколько лет назад испытывал проблемы с масштабированием своей инфраструктуры. При отсутствии надлежащих инструментов мониторинга они не могли быстро определить, в чём именно возникают проблемы, и это привело к простою сервиса.</p><h3>Как командам избежать этой ошибки</h3><p><b>1. Используйте мощные фреймворки логирования:</b></p><p>Использование мощных фреймворков логирования по типу Log4j или Serilog позволяет эффективно записывать важную информацию о работе приложения.</p><p><b>2. Мониторьте в реальном времени:</b></p><p>Необходимо использовать инструменты мониторинга —  Prometheus, Grafana или New Relic для наблюдения за производительностью серверов, баз данных и приложений в реальном времени</p><p><b>3. Определите ключевые показатели производительности (KPI):</b></p><p>Чёткое определение и отслеживание KPI (время отклика, нагрузка на сервер и количество ошибок) предоставит командам доступ к важной информации о здоровье системы.</p><p><b>4. Анализируйте логи:</b></p><p>Создание процессов для анализа логов поможет командам выявлять паттерны ошибок, а не лишь быстро решать точечные проблемы. Для этого можно использовать решения, такие как ELK Stack (Elasticsearch, Logstash, Kibana).</p><p><b>5. Настройте уведомления и алерты:</b></p><p>Настройка автоматизированных уведомлений о сбоях или превышении порогов производительности позволит вам быстро реагировать на проблемы, минимизируя время простоя.</p><p><b>6. Тестируйте с нагрузкой:</b></p><p>Проводить нагрузочное тестирование нужно, ведь это может помочь предсказать возможные проблемы с производительностью.</p><h2>Ошибка 7: У вас есть заблуждение о «сделай всё сразу» и нет итеративного подхода</h2><p>Заблуждение о необходимости реализации всего функционала сразу и отсутствие итеративного подхода могут привести к созданию избыточных и крайне сложных систем, которые сложно тестировать, поддерживать и развивать. Это часто затрудняет адаптацию к изменениям в требованиях, замедляет процесс разработки и увеличивает риск ошибок.</p><h3>Реальные примеры ошибки</h3><p><b>1. <a href="https://www.fastcompany.com/90347999/what-microsoft-learned-from-launching-the-surface">Microsoft</a>:</b></p><p>В попытке создать продукт с широким функционалом, Microsoft когда-то запускала проекты, в рамках которых все функции разрабатывались одновременно. Это обернулось задержками и перевыполнением бюджета, так как продукт не мог быть выведен на рынок, пока не были завершены все его части. В результате компания перешла к более агильному и итеративному подходу, который позволил выпускать версии продукта поэтапно.</p><p><b>2. <a href="http://www.autonews.com/article/20190304/OEM02/303049866/volkswagen-all-or-nothing-approach-leaves-quality-lags">Volkswagen</a>:</b></p><p>Во время разработки платформы для своих автомобилей Volkswagen столкнулся с практикой «всё или ничего», когда компании пытались одновременно интегрировать множество новых технологий. Это привело к проблемам, связанным с качеством и безопасностью, и компании пришлось отложить выпуск новых моделей.</p><h3>Как командам избежать этой ошибки</h3><p><b>1. Планируйте и приоритезируйте задачи:</b></p><p>Необходимо четко определить основные требования и приоритизировать задачи. Используйте методики, например, MoSCoW (Must have, Should have, Could have, Won't have), чтобы определить важность функционала.</p><p><b>2. Не забывайте про итеративную разработку:</b></p><p>Внедряйте циклы разработки, основанные на итеративных подходах, по типу Scrum или Kanban. Это позволит командам адаптироваться и быстро реагировать на изменения в требованиях.</p><p><b>3. Управляйте изменениями:</b></p><p>Создайте процесс управления изменениями, который позволит команде внедрять новые требования без необходимости существенного вмешательства в уже разработанный функционал.</p><p><b>4. Используйте подход Lean:</b></p><p>Рассмотрите внедрение Lean-подхода, который акцентирует внимание на устранении потерь в процессе разработки и оптимизации всех этапов создания продукта.</p><h2>Ошибка 8: Вы неправильно обрабатываете ошибки</h2><p>Неправильная обработка ошибок приводит к тому, что программы могут неожиданно завершаться, не предоставляя пользователю адекватной информации о проблеме или путях ее решения. Это может вызвать разочарование у пользователей, а также усложнить процесс отладки для разработчиков. Игнорирование или неправильное логирование ошибок затрудняет диагностику проблем и снижает общую надёжность системы.</p><h3>Реальные примеры ошибки</h3><p><b>1. <a href="https://www.gao.gov/assets/230/226572.pdf">NASA</a>:</b></p><p>Проект Mars Climate Orbiter был потерян из-за ошибки в обработке данных, связанной с несоответствием единиц измерения. В то время как одни команды использовали метры, другие работали в дюймах. Эта ошибка не была должным образом обработана, что привело к тому, что аппарат вошёл в атмосферу Марса под неправильным углом и сгорел. Неправильная обработка ошибок ввела в заблуждение команду, которая не могла вовремя диагностировать проблему.</p><p><b>2. <a href="https://www.businessinsider.com/the-little-known-mistake-that-cost-knight-capital-440-million-2012-8">Knight Capital Group</a>:</b></p><p>В 2012 году трейдинговая компания Knight Capital Group потеряла 440 миллионов долларов за 45 минут из-за ошибки в коде. Ошибка, которая была вызвана неправильной обработкой исключений, привела к некорректным трейдам. Система продолжала работать, не показывая значительных признаков сбоя, что усложняло реакцию команды и в итоге привело к коллапсу.</p><h3>Как командам избежать этой ошибки</h3><p><b>1. Единообразно обрабатывайте ошибки:</b></p><p>Разработайте единую стратегию обработки ошибок для вашего приложения. Например, создайте централизованный модуль для логирования и уведомлений об ошибках.</p><p><b>2. Разделяйте ошибки на категории:</b></p><p>Классифицируйте ошибки по уровням важности. Это поможет чёткое понять серьёзность проблем и поможет команде быстрее реагировать на критические ситуации.</p><p><b>3. Используйте адаптивное логирование:</b></p><p>Логирование должно фиксировать не только ошибки, но и контекст их возникновения. Используйте уровни логирования (DEBUG, INFO, WARN, ERROR) для записи информации, которая может помочь в диагностике.</p><p><b>4. Настройте грацию исключений:</b></p><p>Научите команду правильно использовать и обрабатывать исключения с помощью конструкций try/catch/finally. Проверяйте, чтобы исключения не просто «гасились», но также создавались и корректные сценарии обработки.</p><p><b>5. Тестируйте сценарии ошибок:</b></p><p>Разработайте тесты, которые бы проверяли обработку различных ситуаций, включая неправильный ввод, сбои в сети и прочие исключительные состояния. Это поможет выявить слабые места в обработке ошибок.</p><h2>Ошибка 9: Вы игнорируете кроссбраузерность и мобильную адаптивность</h2><p>Игнорирование кроссбраузерности и мобильной адаптивности может привести к тому, что пользователи будут испытывать трудности при использовании приложения. Это может снизить пользовательский опыт, увеличить уровень отсева и негативно сказаться на репутации компании.</p><h3>Реальные примеры ошибки</h3><p><b>1. <a href="https://www.forbes.com/sites/hannahbaar/2018/03/15/expedia-website-redesigns-what-went-wrong/?sh=141022116f1e">Expedia</a>:</b></p><p>В 2018 году, после неудачного редизайна своего сайта, Expedia заметила значительное снижение конверсий, особенно на мобильных устройствах. Дополнительные тесты показали, что новый интерфейс выглядел и работал плохо в определённых мобильных браузерах. Отказ от полноценной поддержки мобильной адаптивности привёл к значительным финансовым потерям.</p><p><b>2. <a href="https://www.bbc.co.uk/rd/blog/2015-02-lessons-from-the-bbc-why-browser-compatibility-matters">BBC</a>:</b></p><p>BBC столкнулась с проблемами, связанными с кроссбраузерностью, когда некоторые функции их сайта не работали в старых версиях популярных браузеров. Это вызвало негативные отзывы от пользователей и потребовало от команды много времени на исправления, что замедлило процесс внедрения новых функций.</p><h3>Как командам избежать этой ошибки</h3><p><b>1. Используйте фреймворки и библиотеки:</b></p><p>Рассмотрите использование популярных фреймворков и библиотек по типу Bootstrap или Foundation, которые включают встроенные механизмы для кроссбраузерности и мобильной адаптивности.</p><p><b>2. Проводите автоматизированное тестирование:</b></p><p>Внедрите автоматическое тестирование с помощью инструментов, например, Selenium или BrowserStack, чтобы проводить кроссбраузерное тестирование на различных устройствах и платформах.</p><p><b>3. Изучайте стандарты и спецификации:</b></p><p>Ознакомьтесь со стандартами W3C и другими рекомендациями по веб-разработке, чтобы убедиться, что ваш код соответствует современным требованиям и легко адаптируется к различным браузерам.</p><h2>Ошибка 10: Вы оптимизируете на ранних стадиях разработки</h2><p>Оптимизация на ранних стадиях разработки — распространённая ошибка, которая заключается в попытке улучшить производительность кода или системы еще до того, как будет ясно, какие именно компоненты требуют оптимизации. Это может привести к излишнему усложнению кода, потере фокуса на ключевых функциональных требованиях и снижению общей эффективности. Стремление к ранней оптимизации часто занимает драгоценное время и ресурсы, не всегда ведет к заметным улучшениям и может отвлечь команду от более важных задач.</p><h3>Реальные примеры ошибки</h3><p><b>1. <a href="https://www.gao.gov/assets/230/226572.pdf">NASA</a>:</b></p><p>В проекте Mars Climate Orbiter обнаружили, что разработчики слишком увлеклись оптимизацией кода обработки данных. Это привело к потере фокуса на основном функционале и неправильным единицам измерения. Результатом стало то, что не было видно проблемы, когда аппарат не вошел в атмосферу Марса, что обернулось его разрушением. Позже NASA поняла, что важнее сосредоточиться на правильной реализации основных функций, прежде чем наносить на них оптимизацию.</p><h3>Как командам избежать этой ошибки</h3><p><b>1. Возводите функционал в приоритет:</b></p><p>Сосредоточьте усилия на разработке основных функций и требований системы. Основное внимание должно быть уделено созданию работающего прототипа или MVP перед тем, как задевать оптимизацию.</p><p><b>2. Развивайте продукт итеративно:</b></p><p>Используйте итеративные и альфа-версии разработки, чтобы идентифицировать и оптимизировать проблемные места по мере их появления, а не в самом начале. Такой подход позволяет фокусироваться на реальных данных.</p><p>Поделитесь вашим опытом в комментариях!</p>]]></content:encoded>
    </item>
    <item>
      <title>Event-Driven архитектура: принципы и примеры использования</title>
      <link>https://tproger.ru/articles/event-driven-arhitektura--principy-i-primery-ispolzovaniya</link>
      <comments>https://tproger.ru/articles/event-driven-arhitektura--principy-i-primery-ispolzovaniya?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Денис Кудерин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/event-driven-arhitektura--principy-i-primery-ispolzovaniya</guid>
      <description><![CDATA[<p>Event-Driven архитектура. Показываем принципы и примеры использования EDA. Рассматриваем возможные варианты и пошаговую инструкцию ✔ Tproger</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/event-driven-arhitektura--principy-i-primery-ispolzovaniya">Event-Driven архитектура: принципы и примеры использования</a>»</p>]]></description>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 04 Oct 2024 11:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>В сфере ИТ под архитектурой понимают технологическую базу, структуру и принципы взаимодействия компонентов программного обеспечения. То есть речь идет о совокупности элементов, необходимых для решения поставленных задач. Без архитектурного проектирования написание кода будет лишено структуры — это своего рода каркас, на который опираются исполнители при реализации проекта.</p><p>В современных приложениях и других программных продуктах распространена событийно-ориентированная архитектура. Для запуска и обмена информацией в таких проектах используются события, то есть значимые изменения состояния кода.</p><p>Узнаем, каковы принципы и основы событийной архитектуры ПО, каковы преимущества и недостатки такой структуры, как работает EDA на конкретных примерах.</p><h2>Принципы событийной архитектуры и ее компоненты</h2><p>Event-Driven Architecture — это распространенный асинхронный шаблон, в котором основной для системных действий становится реакция на какое-либо событие. Здесь событием называют сообщение в разных точках исполняемого кода, возникающее при выполнении ряда условий. Паттерн EDA используется при разработке приложений с высокой масштабируемостью, а также при создании более простых программных продуктов.</p><p>Такой архитектурный подход базируется на асинхронном взаимодействии между частями системы. EDA распределяет системные компоненты, что способствует масштабируемости и ускоренной работе приложений и программ, задействованных в самых разных отраслях.</p><h2>Как работает EDA</h2><p>В системе, которая управляется событиями, компоненты отвечают на изменения статуса кода, что минимизирует потребность в их непосредственной связи друг с другом. Такая архитектура более рациональна и обеспечивает высокую адаптируемость всей системы к изменяющейся среде. Обнаружение и обработка событий происходят в реальном времени.</p><p>В качестве типичного примера работы событийно-ориентированной архитектуры можно привести видеоигру, компоненты которой откликаются на движение мыши или нажатие пунктов меню.</p><p>Событийная архитектура состоит из ключевых компонентов:</p><ul><li><b>Продюсеры (производители).</b> Это компоненты, отвечающие за отправку сообщений. Как только состояние изменяется либо происходит действие в системе, производитель отправляет данные об этом заинтересованной стороне. Продюсером может быть любое фактическое действие, влияющее на состояние кода.</li><li><b>События.</b> Это сообщения либо пакеты данных, фиксирующие изменения состояние или какое-либо действие внутри компонентов большой системы. В событиях содержатся метаданные, маркирующие источник изменения, метки времени, информация о действии. Например, если клиент в приложении сделал покупку, все данные об этом будут отражены в событии.</li><li><b>Каналы. </b>Все события доставляются до адресатов (потребителей) по специальным каналам. Первичные каналы событий — это TCP/IP-соединения или файлы различного формата (XML, JSON и т.д.). Возможно одновременное открытие сразу нескольких каналов. Поскольку читаются события асинхронно, их обработка происходит практически в реальном времени.</li><li><b>Маршрутизатор.</b> Этот компонент идентифицирует первичные события и действия, которые содержатся в сообщении. В ряде источников каналы и маршрутизаторы объединяют в компонент, который называется брокером — именно брокер запускает утверждения, которые становятся ответом на действие. При этом сам маршрутизатор не обрабатывает события, а лишь выдает соответствующие инструкции получателю.</li><li><b>Потребители (получатели).</b> Эти компоненты отвечают на сообщение соответствующим образом. Это может быть обновление данных, инициация новых процессов в приложении, вызов удаленных служб. Потребители — это наиболее автономные элементы архитектуры, выполняющие конкретные задачи. Уровень потребителей детализации варьируется от элементарного к сложнейшему в соответствии с особенностями ПО.</li></ul><p>В EDA производители и потребители сообщений не связаны напрямую. То есть продюсеры не знают, какие получатели принимают события, и наоборот — пользователям неизвестно, кто генерирует сообщения. Благодаря разделению можно автономно обновлять, масштабировать и всячески развивать проект.</p><p>Путь сообщений от точки приема до получателей бывает довольно извилистым — возможно, событию потребуется взаимодействовать с компонентами, написанными на другом языке, использующими другие интерфейсы и протоколы передачи. Используется два распространенных способа доставки данных — pub/sub и стандартная потоковая передача. В первом случае инфраструктура такова, что сообщения получает каждый подписчик, во втором события заносятся в лог, после чего потребители могут воспринимать их из любого участка потока.</p><p>Для современного ПО со сложными и разветвленными рабочими процессами принцип Event-Driven обеспечивает необходимую масштабируемость и гибкость. Полноценная обработка здесь и сейчас — это быстродействие и надежность, то есть основные требования, которые предъявляют пользователи к современному ПО.</p><h2>Преимущества</h2><p>Шаблон EDA имеет большой список плюсов:</p><ul><li><b>Высокая масштабируемость.</b> Отсутствие связанности компонентов обеспечивает масштабируемость системы при необходимости. Например, если в онлайн-магазине значительно повышается спрос на товары, архитектура легко справится с обработкой, не задействуя другие службы.</li><li><b>Асинхронная связь.</b> Архитектура работает по принципу асинхронной связи компонентов — то есть части системы включаются, не дожидаясь взаимных ответов. Параллельная обработка существенно повышает эффективность программных продуктов.</li><li><b>Надежность (отказоустойчивость). </b>В EDA системах минимум зависимостей между элементами, что повышает отказоустойчивость. Если с одним из элементов случится сбой, система продолжит работать с минимальными нарушениями. Брокеры позаботятся о том, чтобы события не были потеряны в процессе сбоя. Событийно-ориентированная коммутация позволяет хранить сообщения в специальном хранилище, где ошибки будут обработаны.</li><li><b>Быстродействие приложений.</b> Поскольку события обрабатываются асинхронно и в режиме онлайн, это обеспечивает высокую скорость реагирования на сообщения. В EDA-структурах компоненты отвечают на изменение статуса кода сразу, что максимально сокращает время между действиями и их обработкой. По этой причине событийная архитектура — идеальный вариант для ПО, где мгновенная обработка данных и оперативное реагирование критично важны, например, на финансовых платформах.</li><li><b>Бесшовная интеграция.</b> Программы с архитектурой EDA легко интегрируются с другими приложениями для обмена сведениями и прочих взаимодействий. События потребляются и создаются независимо от задействованных языков программирования и технологических решений.</li><li><b>Гибкость. </b>Event-Driven предполагает модульный подход к разработке системы. Это значит, что изменение отдельных компонентов практически не влияет на статус всей системы. Повышается скорость реагирования на новые задачи и потребности, улучшается адаптивность, что сокращает период разработки и программные ресурсы.</li></ul><p>Таким образом, продукты с EDA высокопроизводительны и способны параллельно выполнять операции с минимальными затратами.</p><h2>Примеры использования Event-Driven архитектуры</h2><p>Существует множество знакомых нам систем, которые работают по принципу событийной архитектуры. Рассмотрим наиболее типичные направления.</p><h3>Электронная коммерция</h3><p>По принципу EDA устроена обработка заказов в интернет-магазинах. Когда пользователь размещает карточку товара, мгновенно запускается событие, которые инициирует работу системы с запасами на складах, обработку покупок и координацию доставки. Все эти события и действия обрабатываются асинхронно, поэтому площадка продолжает работать с высокой скоростью независимо от количества обращений.</p><h3>Интернет вещей</h3><p>Устройства, которые относятся к классу IoT, инициируют события и передают их получателям. Это могут быть разные платформы, но независимо от системы, обработка сообщений происходит в реальном времени.</p><h3>Регистрация и верификация пользователей</h3><p>Любые сервисы, в которых требуется зарегистрировать или идентифицировать пользователя, запускается цепь событий по проверке учетной информации, обновлению личных данных и предоставлению пользователям доступа согласно его текущему статусу.</p><h3>Системы оповещения</h3><p>В таких программных продуктах запуск событий происходит при конкретных условиях — рассылка сообщений, назначение задач в рабочих пространствах, почтовые и push уведомления.</p><h3>Аналитика</h3><p>События инициируются в системах при получении непрерывного потока информации, что позволяет потребителям анализировать сообщения в реальном времени. К таким задачам относится, например, мониторинг трафика на сайте с целью выявления мошеннической активности.</p><h3>Управление рабочими процессами</h3><p>При достижении контрольной точки или полного выполнения задачи запускается событие. Таким образом, происходит мониторинг рабочих процессов с целью повышения эффективности или обеспечения непрерывности выполняемой работы.</p><h3>Микросервисы</h3><p>Архитектура Event-Driven применяется для взаимодействия множества микросервисов в разных направлениях, что позволяет создавать при необходимости слабосвязанные и при этом быстро масштабируемые системы.</p><h2>Реальные примеры</h2><p>Многие компании с международным статусом внедрили в свои ресурсы системы архитектуры EDA, чтобы обеспечить масштабируемость и гибкость программных продуктов.</p><p>Среди таких организаций Netflix — один из наиболее популярных стриминговых сервисов. Вся инфраструктура этой платформы управляется событиями: система одновременно контролирует множество потоков и обеспечивает клиентам высококачественный сервис.</p><p>Еще один пример EDA — платформа для заказа автомобильных поездок Uber. События в этой системе представлены изменениями геолокации, что позволяет операторам отслеживать местоположение тысяч водителей одновременно.</p><h2>Технологии для реализации EDA</h2><p>Для реализации EDA применяется несколько технологий. Обозначим наиболее значимые из них.</p><h3>Event Sourcing</h3><p>В переводе с английского — «поиск событий». Этот шаблон документирует все изменения статуса системы в виде набора упорядоченных событий. Взамен обновления статуса данных система фиксирует изменения как определенные события.</p><p>Такая схема позволяет реконструировать статус объекта и обладает внушительным списком достоинств — это улучшенные возможности аудита, тщательной диагностики и беспроблемной интеграции с другими платформами.</p><h3>CQRS</h3><p>Распределение ответственности между запросами и командами. При использовании такого шаблона система разделяет процессы чтения данных и их записи. Часть, отвечающая за запись, генерирует события, представляющие изменения состояний. Часть, ответственная за чтение, считывает эти сообщения, после чего на их основе делает запросы и выстраивает модели.</p><p>Разделение ответственности позволяет сторонам действовать автономно, при необходимости масштабироваться и оптимально использовать ресурсы в зависимости от текущей ситуации и требований к производительности.</p><h3>Message Broker</h3><p>Брокер сообщений — это эффективный архитектурный шаблон, используемый в разветвленных системах. Такая технология предполагает наличие посредника, которые преобразует сообщения, сделанные в разных протоколах, в однотипный формат.</p><p>Брокеры реализуют асинхронный обмен сообщениями между разными сервисами с процессом буферизации. Пользователь может регулировать нагрузку и при необходимости ускорять обработку информации.</p><h2>Вызовы и недостатки EDA</h2><p>Поскольку в ИТ-сфере (как и в других отраслях) нет ничего совершенного, у EDA есть свои недостатки и подводные камни. Рассмотрим их подробно.</p><h3>Сложная структура</h3><p>Высокий уровень сложности архитектуры и ее распределенный характер могут быть лишними в ситуациях, когда достаточно традиционной монолитной структуры. Сложность Event-Driven предполагает подробное планирование и затратное проектирование системы. Нужны передовые методы для корректного управления системами с таким уровнем сложности.</p><h3>Согласованность событий</h3><p>Если система распределена на несколько сервисов или иных автономных компонентов, реализовать согласованность событий в структуре будет довольно сложно. Проблемы могут возникнуть и при обеспечении целостности информации, а также ее своевременного обновления в ответ на определенные сообщения.</p><h3>Порядок событий</h3><p>В ряде систем, включая финансовые и бизнес-направления, сохранение нужного порядка событий имеет критическое значение. Стратегия упорядоченной нумерации допустима, но при этом сама система станет еще более сложной.</p><h3>Управление и мониторинг</h3><p>Контролирование потоков событий в асинхронных системах часто становится сложной и затратной задачей. Чтобы справиться с ней, потребуется полноценный мониторинг производительности системы. Это поможет выявить узкие места и улучшить архитектуру.</p><h2>Итоги</h2><p>Событийная архитектура — востребованный шаблон, по которому работают современные приложения, онлайн-платформы и другие системы. Ключевая особенность EDA — реакция компонентов архитектуры на определенные события. Такая архитектура легко масштабируется, ажатируется под разные задачи и отличается высокой производительностью и безопасностью  благодаря асинхронной природе. Минусом шаблона считается сложность разработки и тестирования. При этом многие крупные компании реализуют свои программные ресурсы именно с применением событийной архитектуры.</p><p>И обязательно рассказывайте в комментариях, где применяете event-driven архитектуру.</p>]]></content:encoded>
    </item>
    <item>
      <title>Архитектура для Flutter без привязки к BuildContext и сторонних библиотек</title>
      <link>https://tproger.ru/articles/arhitektura-dlya-flutter-bez-privyazki-k-buildcontext-i-storonnih-bibliotek</link>
      <comments>https://tproger.ru/articles/arhitektura-dlya-flutter-bez-privyazki-k-buildcontext-i-storonnih-bibliotek?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Ефанов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/arhitektura-dlya-flutter-bez-privyazki-k-buildcontext-i-storonnih-bibliotek</guid>
      <description><![CDATA[<p>Мобильная разработка: архитектура для Flutter без привязки к BuildContext и сторонних библиотек с примерами кода и полезными советами.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/arhitektura-dlya-flutter-bez-privyazki-k-buildcontext-i-storonnih-bibliotek">Архитектура для Flutter без привязки к BuildContext и сторонних библиотек</a>»</p>]]></description>
      <category><![CDATA[Flutter]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 13 Aug 2024 13:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Введение</h2><p>Всем привет! Меня зовут Евгений Ефанов, я мобильный разработчик в Red Collar.</p><p>На протяжении последних пяти лет я занимаюсь разработкой приложений на Flutter. За это время я успел поработать над несколькими большими проектами, включая мессенджеры и видео-сервисы, где занимался архитектурой.</p><p>Когда я начинал, существовало несколько архитектурных подходов, среди которых можно выделить BLoC и Redux. Позднее появился Provider, а также ряд других, менее распространённых архитектур.</p><p>Эти библиотеки были относительно небольшими, и мне не нравилось их использовать, поскольку в каждой из них отсутствовали многие удобные механизмы, которые были в других библиотеках. Некоторые зависели от BuildContext, что затрудняло тестирование, некоторые требовали слишком много кодогенерации, а библиотеки для подключения зависимостей не поддерживали скоупы и другие привычные функции, что замедляло разработку.</p><p>Поэтому, параллельно с работой над одним из проектов, я начал создавать собственный набор утилитарных классов для архитектуры приложения.</p><p>В итоге хотелось бы сделать архитектурный компонент, который будет способен реагировать и подписываться на события в системе, а также хранить и предоставлять доступ к определённым данным. Этот компонент должен позволять нам изменять эти данные и отслеживать их изменения (BLoC).</p><p>Кроме того, хотелось бы реализовать механизм хранения этих компонентов и обеспечить возможность их подключения друг к другу. Это позволит нам заменять компоненты моками при тестировании. По сути, это будет простой DI-контейнер, разделенный на скоупы.</p><p>Также мы хотим иметь доступ к компонентам и их состоянию через глобальный объект во всех частях приложения аналогично тому, как это реализовано в Redux.</p><p>При этом, в отличие от существующих подходов, получение и использование компонентов должно осуществляться без использования BuildContext.</p><p>И наконец по аналогии с виджетами хотелось бы иметь простой цикл жизни компонента: инициализация и деинициализация.</p><p>Суммарно это бы заключало все механизмы из существующих библиотек, которые, на мой взгляд, были самыми удобными. Используя такой компонент, можно разделить бизнес-логику проекта на составляющие с заменяемыми зависимостями, что позволит гарантировать полное покрытие unit-тестами. События в системе позволят предотвратить излишнее количество связей, поэтому мы сможем минимизировать количество багов в конечном коде проектов.</p><figure><img src="https://media.tproger.ru/user-uploads/103856/2024-08-07/b40b507b-06ad-4964-a94f-3b79b713e40a.png" alt="" /></figure><p>Дополнительным преимуществом является то, что описанный подход может быть применён к любой из платформ, позволяя использовать идентичные механизмы как во Flutter, так и в SwiftUI и Compose. Это облегчает переключение между платформами, так как мы используем одинаковые компоненты бизнес логики. В следующих статьях я расскажу, как реализовать эти механизмы для других платформ.</p><p>Сейчас я продолжаю использовать разработанные мной инструменты и решил написать статью о результатах моей работы, которая, возможно, будет полезна и интересна другим разработчикам и поможет им в реализации и понимании типовых механизмов.</p><p>В завершение будет информация о том, как провести тестирование всех механизмов, описанных в статье, а также как организовать архитектурные компоненты в соответствии со слоями архитектуры.</p><h2>Создаем базовый класс</h2><figure><img src="https://media.tproger.ru/user-uploads/103856/2024-08-07/0bed52b7-25c6-4cbd-87c9-45d9ec598653.png" alt="" /></figure><p>Для начала рассмотрим базовый класс MvvmInstance, который станет основой для всех механизмов. В первую очередь определим в нём два ключевых метода: initialize и dispose, аналогично стандартным виджетам. При инициализации также будет передаваться input для данного объекта. Здесь же можно сразу добавить асинхронный метод для инициализации — initializeAsync.</p><p>В этом случае мы абстрагируемся от конструктора и берём процесс инициализации объекта под свой контроль. В итоге конструкторы будут стандартными, что позволяет легко генерировать код для создания объектов, а также добавляет возможность асинхронных операций при инициализации. На данный момент мы получаем такой класс:</p><p>Здесь мы также определяем конфигурацию объекта, которая на данный момент включает только один флаг, указывающий, требуется ли асинхронная инициализация для этого объекта. В дальнейшем мы сможем добавить сюда и другие параметры, например, список зависимостей для нашей сущности.</p><p>Теперь мы можем сразу подключить наш объект к состоянию какого-либо виджета и связать его жизненный цикл.</p><p>С такой структурой мы можем начать добавлять в наш класс дополнительные функции, такие как обработка событий, работа с состоянием (стейт) и другие, будучи уверенными, что все ресурсы класса будут инициализированы и освобождены вместе с виджетом или с другим логическим элементом, в котором мы используем наш класс.</p><h2>Подключим события</h2><p>События представляют собой один из ключевых элементов во многих архитектурах. Например, во Flutter BloС можно отправлять события и реагировать на них внутри соответствующего блока, обновляя состояние.</p><p>Один из наиболее удобных механизмов для отправки событий — это Event Bus. Он, например, активно используется в приложении Signal на платформе Android, что можно увидеть в репозитории с исходным кодом.</p><p>Реализовать Event Bus во Flutter очень просто, используя встроенный механизм стримов.</p><p>Имея такой класс, мы можем подключить ранее созданный MvvmInstance к получению событий. Сам Event Bus при этом является синглтоном и доступен из любого места в коде.</p><p>Для того чтобы подписаться и отписаться от событий, мы можем использовать методы initialize и dispose, которые мы описали на первом шаге.</p><p>Теперь мы можем подписаться на события внутри нашего класса и отправлять их из любого места в коде.</p><p>Используя только этот механизм, можно реализовать множество логических процессов внутри приложения, например, поставить лайк какому-либо объекту, обработать ошибку сети и т. д.</p><p>Теперь мы можем вызывать экземпляр MvvmInstance как напрямую, так и через событие.</p><h2>Подключаем стейт</h2><p>Далее необходимо хранить в экземпляре некоторые данные, чтобы была возможность их обновлять и получать в рамках архитектурной структуры проекта.</p><p>Мне нравится механизм Redux, в котором есть хранилище, и мы можем подписываться на его обновления. Разница лишь в том, что само хранилище будет находиться внутри каждого экземпляра и содержать только те данные, которые нужны для этого элемента. Чтобы реализовать такой механизм, необходимо прежде всего создать объект, который будет хранить значение, которое мы сможем обновлять, а также подписываться на изменения. Здесь снова на помощь приходят встроенные механизмы Dart.</p><p>Здесь мы снова используем broadcast stream и инкапсулируем текущее значение данных.</p><p>Имея такой класс, мы можем создать хранилище для данных нашего MvvmInstance.</p><p>Стор способен хранить Observable и выдавать обновление значения для конкретного поля state.</p><p>Стор также инициализируется и уничтожается по вызову одного метода, поэтому мы можем легко подключить его к нашему MvvmInstance.</p><p>Используя этот подход, можно реализовать дополнительные функции, например, сохранение состояния в SharedPreferences или SecureStorage. Для этого достаточно абстрагировать логику работы с хранилищем и подписаться на обновления состояния экземпляра.</p><h2>Подключаем зависимости</h2><p>Подключение зависимостей является важным аспектом архитектуры, поскольку позволяет заменять зависимости при написании тестов.</p><p>Для реализации этого механизма необходимо создать интерфейс для подключения класса к нашему MvvmInstance, а также сгенерировать код для создания объектов.</p><p>Поскольку в нашей реализации мы используем дефолтные конструкторы, мы можем легко сгенерировать код для их создания.</p><p>Для хранения экземпляров нам потребуется синглтон, который будет содержать словарь с готовыми экземплярами.</p><p>Упрощённая реализация такого класса может выглядеть следующим образом:</p><p>Здесь мы храним словарь билдеров, которые будем генерировать, а также контейнер уже созданных объектов, чтобы получить их, если инстанс уже создан.</p><p>Словарь объектов также разделим на скоупы, чтобы мы могли разделить наши инстансы. В качестве дефолтных скоупов можно сразу прописать глобальный скоуп, где мы будем хранить синглетоны — они будут инициализироваться сразу при открытии конечного приложения. Так же можно добавить unique скоуп — в таком случае всегда будет создаваться новый экземпляр. Также можно добавить weak скоуп — в этом скоупе будут храниться глобальные объекты, однако в отличие от global скоупа они будут уничтожаться когда все зависимые от них инстансы уничтожены. Остальные скоупы, которые определяет пользователь, будут работать аналогично weak скоупу — когда все зависимые от скоупа экземпляры будут уничтожены, все объекты в скоупе также будут уничтожаться.</p><p>Таким образом, если в нашем словаре ещё не создан нужный нам инстанс, мы его конструируем, вызываем initialize для него и возвращаем инициализированный инстанс. Если же он уже существует, то сразу возвращаем этот объект.</p><p>Для генерации словаря билдеров будем использовать source_gen. Мы можем сгенерировать метод, который будет добавлять билдеры в коллекцию и вызвать его при запуске приложения.</p><p>Для этого сначала нужно создать аннотации для маркировки наших инстансов и после получить их в генераторе и сгенерировать соответствующий билдер. Для начала можно создать две аннотации — для обычных объектов и для синглтонов, — синглтоны будем автоматически помещать в глобальный скоуп.</p><p>После того как мы получили словарь объектов, мы можем подключить их к нашему MvvmInstance.</p><p>Для этого добавим наши зависимости в конфигурацию инстанса. Мы можем включить в конфигурацию список «коннекторов», которые будут содержать параметры, такие как входные данные и скоуп, из которого нужно взять подключаемую сущность.</p><p>Зная список зависимостей для нашего MvvmInstance, мы можем также взять их из словаря инстансов при инициализации.</p><h2>Описываем архитектурные сущности</h2><figure><img src="https://media.tproger.ru/user-uploads/103856/2024-08-07/181c7c5f-c306-4668-90de-483bdcf5720a.png" alt="" /></figure><p>Теперь имея класс с подключенными событиями, стейтом и зависимостями мы можем разделить нашу архитектуру на слои.</p><p><b>Каждая сущность будет подключена к событиям</b></p><figure><img src="https://media.tproger.ru/user-uploads/103856/2024-08-07/d65efc78-53c6-4076-9340-62f40eac150f.png" alt="" /></figure><p>В слое domain я выделил interactor — это сущность, которая хранит стейт. Она удобна для изоляции логического компонента, например, для работы со списком постов. Здесь мы можем получать список постов с сервера, а также подписаться на событие лайка на конкретном посте, чтобы обновить коллекцию в состоянии (стейте) объекта.</p><figure><img src="https://media.tproger.ru/user-uploads/103856/2024-08-07/55e259fe-71f7-4569-a306-ad4063af59fd.png" alt="" /></figure><p>Также я выделяю wrapper — этот элемент не хранит состояние (стейт) и служит обёрткой для каких-либо сторонних библиотек. Например, мы можем подключить библиотеку для проверки текущего состояния сети. Это позволяет абстрагироваться от библиотеки и легко заменять ее методы при тестировании.</p><figure><img src="https://media.tproger.ru/user-uploads/103856/2024-08-07/f0ae33eb-d6d4-4fae-847a-c4e29f68efdf.png" alt="" /></figure><p>На уровне presentation я выделяю view model — по сути, это interactor, входными данными для которого является view, к которому подключена эта view model. Здесь мы можем подключить интеракторы с нужными данными и прописать binding’и, которые нужны для отображения.</p><p>В итоговом варианте мы получаем следующую структуру для загрузки постов:</p><h2>Как все это протестировать</h2><p>Для того чтобы протестировать полученную логику, мы можем заменить элементы в нашем DI контейнере на заранее созданные, передав тестовые данные в стейт.</p><p>В библиотеке так же есть методы для проверки отправки событий и циклических зависимостей у созданных нами сущностей, однако здесь я не буду приводить реализацию — её можно посмотреть в репозитории с кодом.</p><p>Ниже представлены примеры, как можно протестировать каждую сущность.</p><h2>Вывод</h2><p>В итоге мы получили набор логических элементов для того, чтобы реализовать каждый слой архитектуры и возможность всё это протестировать. Отдельно стоит отметить, что для внедрения зависимостей и работы с http мы можем применять и другие решения, пользуясь лишь структурой архитектуры.</p><p>В своей работе над реальными проектами я активно применяю все компоненты данной архитектуры. Бизнес-логика представляет собой некое количество интеракторов, количество которых даже в крупном проекте позволяет быстро внедрять зависимости в компоненты (например, view models), предотвращая любые возможные зависания при инициализации. Тестировать эти компоненты удобно, поскольку бизнес-логика полностью покрыта unit-тестами.</p><p>Благодаря механизму событий снижается связанность между компонентами, а основной глобальный app-компонент приложения дает возможность использования компонентов в любом месте кода, предоставляя свободу реализации функционала без ущерба для его тестируемости, а значит будет меньше багов в итоговом проекте.</p><p>Как реализовать аналогичные механизмы на swiftui и compose , я расскажу в следующих статьях.</p>]]></content:encoded>
    </item>
  </channel>
</rss>