<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Denis Toropov</title>
    <description>The latest articles on DEV Community by Denis Toropov (@dtoropov).</description>
    <link>https://dev.to/dtoropov</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4105889%2F1df1ad8b-0a40-4f89-a2b0-747597fdadcf.png</url>
      <title>DEV Community: Denis Toropov</title>
      <link>https://dev.to/dtoropov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dtoropov"/>
    <language>en</language>
    <item>
      <title>Технический долг: причины появления и как с ним работать системно</title>
      <dc:creator>Denis Toropov</dc:creator>
      <pubDate>Sun, 20 Sep 2026 18:26:45 +0000</pubDate>
      <link>https://dev.to/dtoropov/tiekhnichieskii-dolgh-prichiny-poiavlieniia-i-kak-s-nim-rabotat-sistiemno-1k27</link>
      <guid>https://dev.to/dtoropov/tiekhnichieskii-dolgh-prichiny-poiavlieniia-i-kak-s-nim-rabotat-sistiemno-1k27</guid>
      <description>&lt;p&gt;О техническом долге обычно вспоминают в двух случаях: когда релизы становятся болезненными или когда любое изменение в системе начинает стоить непропорционально дорого. До этого момента он часто воспринимается как фоновая проблема: что-то устарело, что-то не покрыто тестами, где-то есть баги, документация не в лучшем состоянии — но «в целом жить можно».&lt;/p&gt;

&lt;p&gt;В этом и проблема. Технический долг редко приходит как одно крупное событие. Он накапливается из небольших решений, каждое из которых в моменте кажется рациональным. Не обновили библиотеку, потому что сейчас важнее фича. Отложили оптимизацию, потому что SLA пока не горит. Не написали тесты, потому что нужно быстрее выйти в релиз. Документацию решили оформить позже. В итоге через какое-то время команда уже не ускоряется за счёт компромиссов, а расплачивается за них в каждом спринте.&lt;/p&gt;

&lt;p&gt;Главная ошибка — считать технический долг чем-то абстрактным. Пока он не зафиксирован в задачах, не оценён и не попал в планирование, его как будто не существует. А значит, он будет расти.&lt;/p&gt;

&lt;h2&gt;
  
  
  Что такое технический долг в реальной разработке
&lt;/h2&gt;

&lt;p&gt;Если убрать красивые определения, технический долг — это всё, что делает изменения в системе дороже и рискованнее, чем они могли бы быть.&lt;/p&gt;

&lt;p&gt;Не обязательно речь идёт только о коде. Долг может быть в архитектуре, в тестовом контуре, в зависимостях, в документации, в пользовательских сценариях и даже в операционных процессах вокруг системы. Его главный признак — не то, что «сделано некрасиво», а то, что команда регулярно платит за это временем, дефектами, ручной работой или повышенным риском.&lt;/p&gt;

&lt;p&gt;Хороший маркер техдолга — фразы, которые в команде начинают звучать слишком часто:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;«этот модуль лучше не трогать»;&lt;/li&gt;
&lt;li&gt;«релизим аккуратно, там нет тестов»;&lt;/li&gt;
&lt;li&gt;«да, библиотека старая, но обновлять страшно»;&lt;/li&gt;
&lt;li&gt;«это известный баг, просто обходите его так»;&lt;/li&gt;
&lt;li&gt;«если что, спросите у Сергея, только он знает, как это работает».&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Если такие вещи стали нормой, долг уже влияет не только на кодовую базу, но и на скорость команды.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Устаревшие версии библиотек
&lt;/h2&gt;

&lt;p&gt;Один из самых частых источников технического долга — старые зависимости и framework-версии, которые годами никто не трогает, потому что «и так работает».&lt;/p&gt;

&lt;p&gt;Проблема в том, что такая стабильность обычно мнимая. Пока библиотека не мешает прямо сегодня, её обновление откладывают. Но потом выясняется, что проект сидит на версии без поддержки, security fixes уже не приходят, новые компоненты экосистемы не совместимы, а переход на актуальный стек превращается в отдельную программу работ.&lt;/p&gt;

&lt;p&gt;Чем дольше откладывается обновление, тем выше цена. Разница между «подняться на один минор» и «перепрыгнуть через несколько крупных версий» — это разница между обычной инженерной задачей и рискованной миграцией с регрессией, совместимостью API, изменением конфигурации и непредсказуемыми побочными эффектами.&lt;/p&gt;

&lt;p&gt;Отдельный риск — накопление скрытых ограничений. Команда уже не может взять новый observability-агент, новый JDBC driver, новую версию Kafka client или security patch без цепочки зависимых обновлений. Формально причина одна — старая библиотека. Фактически это уже блокер для развития системы.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Плохая производительность
&lt;/h2&gt;

&lt;p&gt;Технический долг — это не только про поддержку кода. Деградация производительности тоже очень быстро становится долгом, особенно если к ней привыкают и начинают считать нормой.&lt;/p&gt;

&lt;p&gt;Чаще всего всё начинается не с катастрофы, а с мелких уступок. Один тяжёлый запрос. Один лишний синхронный вызов между сервисами. Один участок, где решили не ставить кэш. Один batch, который выполняется дольше, чем ожидалось. Пока нагрузка умеренная, система держится. Потом приходит рост объёма данных, больше пользователей, новые интеграции — и выясняется, что запас прочности давно закончился.&lt;/p&gt;

&lt;p&gt;На этом этапе производительность перестаёт быть локальной технической темой. Она начинает влиять на бизнес: пользователи ждут дольше, batch-процессы не укладываются в окна, инфраструктура дорожает, команда боится добавлять новые сценарии, потому что система и так работает на пределе.&lt;/p&gt;

&lt;p&gt;Самое неприятное — когда нет базовых метрик и истории деградации. Если команда не знает свои узкие места, не понимает профиль нагрузки, то любые разговоры про производительность превращаются в гадание. А это уже классический техдолг: проблема есть, но она не описана как инженерный объект.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Отсутствие тестов
&lt;/h2&gt;

&lt;p&gt;Отсутствие тестов — это один из самых дорогих долгов, потому что он бьёт по каждому изменению, а не по одному конкретному месту в системе.&lt;/p&gt;

&lt;p&gt;Когда тестов нет, скорость какое-то время действительно может быть выше. Но это короткий выигрыш. Дальше каждая новая задача начинает требовать всё больше ручной проверки, больше согласований и больше осторожности. Любой рефакторинг превращается в риск. Любой релиз — в напряжение. Любой багфикс может породить новый баг в соседнем сценарии.&lt;/p&gt;

&lt;p&gt;Причём проблема не сводится к отсутствию unit-тестов как таковых. Плохой тестовый контур тоже создаёт долг. Например:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ситуация&lt;/th&gt;
&lt;th&gt;Во что превращается проблема&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Тестов почти нет&lt;/td&gt;
&lt;td&gt;регрессии ловятся уже после релиза&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Есть только интеграционные тесты&lt;/td&gt;
&lt;td&gt;проверки слишком медленные, команда запускает их нерегулярно&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Тесты хрупкие&lt;/td&gt;
&lt;td&gt;их перестают воспринимать как источник уверенности&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Тесты завязаны на реализацию, а не на поведение&lt;/td&gt;
&lt;td&gt;любой рефакторинг ломает половину набора&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Нет покрытия критических бизнес-сценариев&lt;/td&gt;
&lt;td&gt;самое важное продолжает проверяться вручную&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;В итоге без тестов команда не просто «хуже контролирует качество». Она теряет возможность безопасно менять систему. А это уже прямое влияние на delivery.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Ошибки и известные дефекты
&lt;/h2&gt;

&lt;p&gt;Не каждый баг — техдолг. Но баг, который известен всем, давно не исправляется и уже оброс обходными путями, почти всегда становится частью долга.&lt;/p&gt;

&lt;p&gt;Такой дефект редко живёт только в коде. Вокруг него обычно возникает инфраструктура компенсаций: ручные проверки, инструкции для поддержки, дополнительные шаги у бизнеса, повторные операции, исключения в регламентах. Снаружи может казаться, что проблема под контролем. На деле команда платит за неё постоянно.&lt;/p&gt;

&lt;p&gt;Особенно опасны дефекты, к которым «все привыкли». Их перестают воспринимать как приоритет, потому что они не выглядят как авария. Но именно такие ошибки съедают время годами: support обрабатывает однотипные кейсы, аналитики учитывают ограничения в новых процессах, разработчики помнят, что «в этом месте надо быть осторожнее».&lt;/p&gt;

&lt;p&gt;Если у бага появился устный workaround, это уже повод занести его в бэклог техдолга, а не просто в список известных проблем.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Документация
&lt;/h2&gt;

&lt;p&gt;Недостаток документации редко ощущается в маленькой команде, где все давно в контексте. Но как только система растёт, появляются новые люди, интеграции, аудит, инциденты или параллельные команды, отсутствие документации начинает тормозить не хуже плохого кода.&lt;/p&gt;

&lt;p&gt;Проблема не в том, что «нечего почитать». Проблема в зависимости от памяти конкретных людей. Архитектурные ограничения, исторические решения, особенности интеграций, неочевидные контракты, эксплуатационные нюансы — всё это существует только в головах нескольких инженеров. Пока они рядом, система как будто управляемая. Как только кто-то уходит в отпуск, меняет проект или просто недоступен в нужный момент, выясняется реальная стоимость такого подхода.&lt;/p&gt;

&lt;p&gt;При этом документационный долг не означает, что нужно описывать вообще всё. Обычно достаточно держать в актуальном состоянии несколько критически важных слоёв:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;архитектурную схему и границы сервисов;&lt;/li&gt;
&lt;li&gt;основные интеграции и контракты;&lt;/li&gt;
&lt;li&gt;decision log по важным техническим решениям;&lt;/li&gt;
&lt;li&gt;инструкции по запуску, поддержке и разбору инцидентов;&lt;/li&gt;
&lt;li&gt;ограничения, о которых нельзя забывать при изменениях.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Это не «бумажная работа». Это инструмент передачи контекста и снижения bus factor.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Руководство пользователя
&lt;/h2&gt;

&lt;p&gt;Эту часть часто вообще не относят к техническому долгу, особенно если речь идёт о внутренней корпоративной системе. Но на практике отсутствие пользовательского руководства создаёт вполне измеримые потери.&lt;/p&gt;

&lt;p&gt;Когда пользователю непонятно, как работать с системой, нагрузка уходит в поддержку, в аналитиков и в разработку. Начинаются объяснения в чатах, созвоны «на пять минут», демонстрации экранов, пересылка устаревших инструкций, ручное сопровождение новых сценариев. Если продукт сложный — CRM, MDM, внутренняя платформа, операционный интерфейс — объём таких потерь становится заметным очень быстро.&lt;/p&gt;

&lt;p&gt;Есть и второй эффект: изменения в продукте становятся дороже. Любая правка в интерфейсе или процессе требует дополнительной коммуникации, потому что у пользователей нет устойчивой точки опоры в виде актуального руководства.&lt;/p&gt;

&lt;p&gt;Руководство пользователя — это не косметика. Для зрелого продукта это часть общей эксплуатационной модели. Если его нет, система начинает требовать «живого посредника» между функциональностью и пользователем. И это уже вполне нормальный кандидат в бэклог техдолга.&lt;/p&gt;

&lt;h2&gt;
  
  
  Почему технический долг нужно оцифровывать
&lt;/h2&gt;

&lt;p&gt;Пока технический долг живёт в формулировках вроде «тут всё старое», «это узкое место» или «там опасный код», он почти всегда проигрывает фичам в приоритизации.&lt;/p&gt;

&lt;p&gt;Не потому, что фичи важнее. А потому, что фича обычно описана лучше: у неё есть цель, эффект, срок и ожидаемый результат. У техдолга часто есть только раздражение команды.&lt;/p&gt;

&lt;p&gt;Чтобы долг начал управляться, его нужно переводить в конкретные сущности. Минимальный набор обычно такой:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Поле&lt;/th&gt;
&lt;th&gt;Что фиксировать&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Область&lt;/td&gt;
&lt;td&gt;зависимости, производительность, тесты, баги, документация, user guide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Проблема&lt;/td&gt;
&lt;td&gt;что именно не так&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Последствие&lt;/td&gt;
&lt;td&gt;на что это влияет: релизы, SLA, support, скорость команды, риски&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Риск&lt;/td&gt;
&lt;td&gt;низкий / средний / высокий&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Оценка&lt;/td&gt;
&lt;td&gt;часы, дни, story points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Метрика результата&lt;/td&gt;
&lt;td&gt;как понять, что стало лучше&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Например, запись «надо обновить стек» бесполезна. Запись «Spring Boot 2.x больше не поддерживается, часть security patches недоступна, новые версии библиотек не поднимаются; оценка — 8 рабочих дней; результат — переход на поддерживаемый baseline и снятие ограничений по обновлению зависимостей» — уже пригодна для планирования.&lt;/p&gt;

&lt;p&gt;Оцифровка нужна не ради отчётности. Она нужна, чтобы долг можно было сравнивать между собой и с продуктовыми задачами на одном языке.&lt;/p&gt;

&lt;h2&gt;
  
  
  Отдельный бэклог технического долга
&lt;/h2&gt;

&lt;p&gt;Если техдолг не выделен в отдельный список, он почти неизбежно растворяется в общей очереди задач. В таком виде его неудобно обсуждать, сложно ранжировать и легко игнорировать.&lt;/p&gt;

&lt;p&gt;Поэтому на практике лучше работает отдельный backlog технического долга. Не изолированный от общего planning-процесса, а встроенный в него.&lt;/p&gt;

&lt;p&gt;У каждой задачи в этом бэклоге должны быть хотя бы три вещи: описание проблемы, оценка и причина приоритета. Для приоритизации удобно смотреть на несколько простых критериев:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Критерий&lt;/th&gt;
&lt;th&gt;Вопрос&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Business impact&lt;/td&gt;
&lt;td&gt;влияет ли это на клиента, операционные процессы, SLA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delivery impact&lt;/td&gt;
&lt;td&gt;мешает ли это выпускать изменения быстрее и безопаснее&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Risk&lt;/td&gt;
&lt;td&gt;может ли это привести к инциденту, дефектам, уязвимостям, потере данных&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost of delay&lt;/td&gt;
&lt;td&gt;насколько дороже будет исправлять через квартал&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effort&lt;/td&gt;
&lt;td&gt;сколько реально стоит исправление&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Такой подход полезен ещё и тем, что убирает эмоциональность из обсуждения. Вместо «нам всем неприятно на это смотреть» появляется разговор в терминах риска, стоимости и эффекта.&lt;/p&gt;

&lt;h2&gt;
  
  
  Пример бэклога технического долга
&lt;/h2&gt;

&lt;p&gt;Ниже — пример того, как это может выглядеть в рабочем виде.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Задача&lt;/th&gt;
&lt;th&gt;Причина&lt;/th&gt;
&lt;th&gt;Приоритет&lt;/th&gt;
&lt;th&gt;Оценка&lt;/th&gt;
&lt;th&gt;Ожидаемый эффект&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Обновить критические библиотеки и framework&lt;/td&gt;
&lt;td&gt;накопились security и compatibility риски&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;8 дней&lt;/td&gt;
&lt;td&gt;снижение числа уязвимостей, упрощение поддержки&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Оптимизировать 5 самых медленных SQL-запросов&lt;/td&gt;
&lt;td&gt;p95 выше целевого SLA&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;5 дней&lt;/td&gt;
&lt;td&gt;ускорение ключевых операций, снижение нагрузки на БД&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Добавить интеграционные тесты на критический бизнес-поток&lt;/td&gt;
&lt;td&gt;регрессии всплывают в релизе&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;6 дней&lt;/td&gt;
&lt;td&gt;выше предсказуемость релизов&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Исправить известные дефекты с ручными обходами&lt;/td&gt;
&lt;td&gt;support и бизнес компенсируют проблему процессом&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;4 дня&lt;/td&gt;
&lt;td&gt;снижение ручных операций и количества обращений&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Описать ключевые архитектурные решения и интеграции&lt;/td&gt;
&lt;td&gt;высокая зависимость от нескольких инженеров&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;3 дня&lt;/td&gt;
&lt;td&gt;быстрее онбординг и проще разбирать инциденты&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Подготовить руководство пользователя по top-5 сценариям&lt;/td&gt;
&lt;td&gt;высокая нагрузка на поддержку&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;3 дня&lt;/td&gt;
&lt;td&gt;меньше однотипных вопросов и ошибок в работе пользователей&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Важно, что это уже не «список всего плохого». Это набор задач, у которых есть смысл, цена и ожидаемый результат.&lt;/p&gt;

&lt;h2&gt;
  
  
  Почему имеет смысл брать техдолг в каждый спринт по 20%
&lt;/h2&gt;

&lt;p&gt;Попытка «сначала быстро закрыть весь техдолг, а потом вернуться к продукту» почти никогда не работает. Бизнес не готов надолго остановить развитие, а команда без чётких рамок быстро уходит в бесконечные внутренние улучшения без видимого эффекта.&lt;/p&gt;

&lt;p&gt;Поэтому резервировать часть спринта под техдолг — рабочая практика. Значение 20% обычно выглядит разумным стартом: не слишком мало, чтобы ничего не менять, и не слишком много, чтобы остановить поставку продукта.&lt;/p&gt;

&lt;p&gt;У такого подхода есть несколько плюсов.&lt;/p&gt;

&lt;p&gt;Во-первых, он делает работу предсказуемой. Не нужно каждый спринт заново доказывать, почему техдолг вообще достоин времени команды.&lt;/p&gt;

&lt;p&gt;Во-вторых, он снижает риск накопления. Мелкие регулярные улучшения почти всегда дешевле, чем редкие крупные кампании по расчистке legacy.&lt;/p&gt;

&lt;p&gt;В-третьих, через несколько месяцев можно показать эффект в цифрах: меньше инцидентов, меньше регрессий, быстрее релизы, меньше ручной работы, короче онбординг, стабильнее производительность.&lt;/p&gt;

&lt;p&gt;Конечно, 20% — не универсальная магическая цифра. Для одной команды может быть достаточно 10–15%, для другой в период тяжёлой миграции понадобится 25–30%. Но сама идея постоянной квоты работает лучше, чем модель «исправим потом, когда будет окно».&lt;/p&gt;

&lt;h2&gt;
  
  
  Как это внедрить на практике
&lt;/h2&gt;

&lt;p&gt;Схема достаточно простая.&lt;/p&gt;

&lt;p&gt;Сначала нужно собрать известные долги в единый список. Не пытаться сразу всё чинить, а просто зафиксировать. Потом — для каждой записи указать последствия, риск и оценку. После этого задачи ранжируются по приоритету, и в спринт попадает объём примерно на 20% ёмкости команды.&lt;/p&gt;

&lt;p&gt;Дальше важно не потерять измеримость. Если команда взяла в работу блок задач по производительности, нужно заранее понимать, какие метрики должны измениться. Если речь про тесты — где именно снизится регрессионный риск. Если про документацию — какой участок зависимости от конкретных людей будет снят.&lt;/p&gt;

&lt;p&gt;И ещё один важный момент: бэклог техдолга нужно пересматривать регулярно. Часть задач со временем теряет актуальность. Часть, наоборот, становится критичнее. Иногда после изменения архитектуры старый долг вообще перестаёт существовать, а иногда появляется новый, который раньше был не виден.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>refactoring</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Когда одни и те же справочники живут в трёх сервисах: зачем мы вынесли их в отдельный сервис</title>
      <dc:creator>Denis Toropov</dc:creator>
      <pubDate>Tue, 15 Sep 2026 06:08:04 +0000</pubDate>
      <link>https://dev.to/dtoropov/koghda-odni-i-tie-zhie-spravochniki-zhivut-v-triokh-siervisakh-zachiem-my-vyniesli-ikh-v-otdielnyi-siervis-4acg</link>
      <guid>https://dev.to/dtoropov/koghda-odni-i-tie-zhie-spravochniki-zhivut-v-triokh-siervisakh-zachiem-my-vyniesli-ikh-v-otdielnyi-siervis-4acg</guid>
      <description>&lt;p&gt;&lt;em&gt;Как снизить коллизии в данных, когда три сервиса работают с разными БД, но используют одну и ту же бизнес-семантику.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;В распределённых системах проблемы редко начинаются с чего-то громкого. Обычно всё выглядит вполне рационально: отдельные сервисы, отдельные базы, понятные границы ответственности. Но в какой-то момент оказывается, что система начинает спорить сама с собой.&lt;/p&gt;

&lt;p&gt;У нас был кейс, где остатки пришлось разносить по трём разным базам данных.&lt;/p&gt;

&lt;p&gt;Первая база использовалась сервисом отображения счетов. Вторая — сервисом отображения остатков по клиентам. Третья — сервисом текущих остатков по счетам. С каждой базой работал отдельный сервис, потому что у каждого контура были свои сценарии чтения, свои требования к производительности и свой формат представления данных.&lt;/p&gt;

&lt;p&gt;На старте такое разделение казалось правильным. Проблема была в другом: всем трём сервисам нужны были одни и те же справочники.&lt;/p&gt;

&lt;h2&gt;
  
  
  Где именно сломалась логика
&lt;/h2&gt;

&lt;p&gt;Когда одинаковые справочники живут в нескольких сервисах, система почти неизбежно начинает производить разные версии правды.&lt;/p&gt;

&lt;p&gt;В одном месте уже обновился статус. В другом ещё осталась старая категория. &lt;/p&gt;

&lt;p&gt;Для пользователя это выглядит как простая несогласованность интерфейсов:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;в одном экране счёт попадает в одну категорию;&lt;/li&gt;
&lt;li&gt;в другом агрегируется по другому признаку;&lt;/li&gt;
&lt;li&gt;в третьем отображается с ещё одной трактовкой.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Для команды это уже не косметическая проблема. Это инциденты, ручные сверки, долгие расследования и потеря доверия к данным.&lt;/p&gt;

&lt;h2&gt;
  
  
  Исходная схема
&lt;/h2&gt;

&lt;p&gt;На архитектурном уровне всё выглядело примерно так:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;сервис счетов работает со своей БД;&lt;/li&gt;
&lt;li&gt;сервис клиентских остатков работает со своей БД;&lt;/li&gt;
&lt;li&gt;сервис текущих остатков по счетам работает со своей БД;&lt;/li&gt;
&lt;li&gt;каждый сервис использует одинаковые справочники: типы счетов, статусы, продуктовые признаки, классификаторы и другие reference-данные.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;На бумаге это стандартная картина для enterprise-ландшафта. Но как только появляются несколько владельцев одной и той же семантики, начинаются вопросы, на которые уже трудно отвечать однозначно.&lt;/p&gt;

&lt;p&gt;Кто является источником истины по справочнику? Когда обновление считается применённым? Что делать, если одна система уже живёт на новой версии, а другая ещё нет? Кто отвечает за расследование, если одно и то же поле в разных контурах интерпретируется по-разному?&lt;/p&gt;

&lt;p&gt;Если отвечать честно, в тот момент у нас не было одного хорошего ответа на эти вопросы.&lt;/p&gt;

&lt;h2&gt;
  
  
  Почему справочники — это не «вторичные данные»
&lt;/h2&gt;

&lt;p&gt;Это частая ловушка в проектировании. Справочники воспринимаются как нечто вспомогательное: не деньги, не транзакции, не основной поток операций. Значит, можно просто держать копию рядом с каждым сервисом и синхронизировать «как-нибудь потом».&lt;/p&gt;

&lt;p&gt;Но на практике именно справочники определяют, как система понимает основные данные.&lt;/p&gt;

&lt;p&gt;Остаток сам по себе — это просто число. Его смысл появляется только вместе с контекстом: тип продукта, статус счёта, принадлежность к сегменту, набор признаков для агрегации. Если этот контекст в разных сервисах отличается, то даже одинаковое значение остатка перестаёт быть одинаковым с точки зрения бизнеса.&lt;/p&gt;

&lt;p&gt;Это уже не техническое расхождение. Это расхождение в интерпретации данных.&lt;/p&gt;

&lt;h2&gt;
  
  
  Какие проблемы начали проявляться
&lt;/h2&gt;

&lt;p&gt;Проблемы были не в одном большом падении, а в постоянном накоплении серой зоны.&lt;/p&gt;

&lt;p&gt;Во-первых, версии справочников расходились асинхронно. Один сервис уже применил изменения, другой ещё нет, третий обновился по отдельному процессу. В результате одна и та же сущность начинала выглядеть по-разному в разных пользовательских сценариях.&lt;/p&gt;

&lt;p&gt;Во-вторых, заметно усложнилась диагностика. Любой инцидент в стиле «почему здесь одно, а там другое» требовал разбирать три базы, три сервиса, три истории обновления и часто ещё несколько команд. Самое неприятное — такие инциденты редко выглядят как полноценная авария. Они живут как хроническая операционная боль.&lt;/p&gt;

&lt;h2&gt;
  
  
  Какие варианты у нас были
&lt;/h2&gt;

&lt;p&gt;Когда стало понятно, что локальное дублирование справочников начинает стоить слишком дорого, мы рассмотрели несколько вариантов.&lt;/p&gt;

&lt;h3&gt;
  
  
  Вариант 1. Оставить локальные копии и улучшить синхронизацию
&lt;/h3&gt;

&lt;p&gt;Самый очевидный путь — ничего принципиально не менять, а просто жёстче выстроить доставку обновлений.&lt;/p&gt;

&lt;p&gt;Плюс подхода в том, что он почти не меняет текущую архитектуру. У сервисов остаются локальные данные, быстрые чтения и привычный способ работы.&lt;/p&gt;

&lt;p&gt;Минус в том, что проблема владения никуда не исчезает. Даже если лучше организовать синхронизацию, в системе по-прежнему остаются несколько мест, где один и тот же справочник может интерпретироваться и изменяться по-разному.&lt;/p&gt;

&lt;h3&gt;
  
  
  Вариант 2. Сделать общую БД для справочников
&lt;/h3&gt;

&lt;p&gt;Это лучше, чем держать копии в трёх местах. Формально появляется единое хранилище.&lt;/p&gt;

&lt;p&gt;Но такой вариант часто приводит к другой проблеме: сервисы начинают ходить в одну и ту же схему напрямую, правила начинают расползаться по коду потребителей, а контракт эволюционирует без явного владельца. В итоге единая база есть, а единое управление справочниками — нет.&lt;/p&gt;

&lt;h3&gt;
  
  
  Вариант 3. Выделить единый сервис справочников
&lt;/h3&gt;

&lt;p&gt;Это был вариант, который мы в итоге выбрали.&lt;/p&gt;

&lt;p&gt;Идея простая: справочники перестают быть «чем-то общим для всех», а становятся отдельным доменом с явным владельцем. Один сервис отвечает за хранение, версионирование, валидацию и публикацию изменений. Остальные сервисы больше не решают самостоятельно, какая версия справочника правильная.&lt;/p&gt;

&lt;h2&gt;
  
  
  Почему мы выбрали единый сервис справочников
&lt;/h2&gt;

&lt;p&gt;Ключевая мысль была такой: у нас проблема не доставки данных как таковой, а множественного владения одной и той же бизнес-семантикой.&lt;/p&gt;

&lt;p&gt;Пока справочник живёт в нескольких сервисах, система почти гарантированно будет порождать локальные трактовки:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;где-то появится дополнительный статус;&lt;/li&gt;
&lt;li&gt;где-то — локальный маппинг;&lt;/li&gt;
&lt;li&gt;где-то — особое правило фильтрации;&lt;/li&gt;
&lt;li&gt;где-то — временная логика, которая неожиданно станет постоянной.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Единый сервис справочников не делает систему магически простой. Но он убирает главный источник коллизий: несколько центров принятия решений по одним и тем же reference-данным.&lt;/p&gt;

&lt;p&gt;Проще говоря, мы перестали синхронизировать три почти одинаковые правды и начали работать с одной.&lt;/p&gt;

&lt;h2&gt;
  
  
  Что изменилось в архитектуре
&lt;/h2&gt;

&lt;p&gt;После выделения сервиса схема стала концептуально проще:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;сервис справочников стал владельцем canonical-модели;&lt;/li&gt;
&lt;li&gt;сервис счетов, сервис клиентских остатков и сервис текущих остатков перестали самостоятельно владеть справочниками;&lt;/li&gt;
&lt;li&gt;правила валидации, версионирования и обновления были централизованы;&lt;/li&gt;
&lt;li&gt;все коллизии начали разбираться относительно одного источника истины, а не трёх локальных копий.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Что должен уметь полноценный сервис справочников
&lt;/h2&gt;

&lt;p&gt;Если делать такой сервис всерьёз, а не как тонкую CRUD-обёртку поверх таблицы, у него есть несколько обязательных обязанностей.&lt;/p&gt;

&lt;p&gt;Во-первых, он должен быть владельцем модели. Не просто хранить данные, а определять поля, статусы, связи, ограничения и правила жизненного цикла.&lt;/p&gt;

&lt;p&gt;Во-вторых, он должен поддерживать версионирование. Потребитель должен в любой момент уметь ответить на вопрос, какую версию справочника он использует.&lt;/p&gt;

&lt;p&gt;В-третьих, он должен предсказуемо публиковать изменения. Это может быть API, события, снапшоты или гибридный подход — главное, чтобы схема доставки была единой и контролируемой.&lt;/p&gt;

&lt;p&gt;В-четвёртых, он должен обеспечивать контроль качества данных: валидации, аудит, дедупликацию, проверку обязательных полей и прозрачный процесс изменений.&lt;/p&gt;

&lt;p&gt;В-пятых, он должен быть наблюдаемым. Если от справочников зависит корректная интерпретация остатков, то нужны метрики свежести, версий, ошибок обновления и отставания потребителей.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Подход&lt;/th&gt;
&lt;th&gt;Плюсы&lt;/th&gt;
&lt;th&gt;Минусы&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Локальные копии справочников в каждом сервисе&lt;/td&gt;
&lt;td&gt;Быстрые локальные чтения, минимальная зависимость на сетевые вызовы, автономность сервисов&lt;/td&gt;
&lt;td&gt;Дрейф данных, сложное расследование, несколько источников истины&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Общая БД справочников&lt;/td&gt;
&lt;td&gt;Формально единое хранилище, относительно простой старт&lt;/td&gt;
&lt;td&gt;Сильная связность по схеме, риск обхода правил, нет явного владельца контракта&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Единый сервис справочников&lt;/td&gt;
&lt;td&gt;Централизованное владение, прозрачные правила, меньше коллизий, проще аудит и контроль версий&lt;/td&gt;
&lt;td&gt;Новый критичный компонент, выше требования к SLA, нужно отдельно проектировать модель распространения изменений&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Мы выбрали третий вариант, потому что в нашем случае главной стоимостью была не задержка чтения, а цена несогласованности данных между контурами.&lt;/p&gt;

&lt;h2&gt;
  
  
  Где легко ошибиться
&lt;/h2&gt;

&lt;p&gt;Самая частая ошибка — назвать сервисом справочников обычную БД с REST-обёрткой.&lt;/p&gt;

&lt;p&gt;Если у такого сервиса нет владения моделью, нет версий, нет контроля изменений и нет прозрачной схемы распространения данных, то он не решает исходную проблему. Он просто переносит её в другое место.&lt;/p&gt;

&lt;p&gt;Вторая ошибка — заставить все сервисы читать справочники только синхронно и только в онлайне. Это быстро превращает инфраструктурный сервис в точку каскадной деградации.&lt;/p&gt;

&lt;p&gt;На практике почти всегда нужен гибридный подход:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;единый сервис владеет reference-данными;&lt;/li&gt;
&lt;li&gt;изменения публикуются централизованно;&lt;/li&gt;
&lt;li&gt;потребители могут держать локальные read-optimized представления там, где это оправдано по нагрузке и latency;&lt;/li&gt;
&lt;li&gt;право менять и интерпретировать справочник остаётся в одном месте.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Decision log
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Контекст.&lt;/strong&gt; Три сервиса работают с тремя разными БД, но используют одни и те же справочники для интерпретации остатков.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Проблема.&lt;/strong&gt; Возникают коллизии, расхождения версий и сложные инциденты, где разные контуры показывают разные значения или категории для одной и той же сущности.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Варианты.&lt;/strong&gt; Оставить локальные копии и усилить синхронизацию; сделать общую БД; выделить единый сервис справочников.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Выбор.&lt;/strong&gt; Выделить отдельный сервис справочников как единого владельца reference-данных.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Почему.&lt;/strong&gt; Проблема была не только в доставке данных, а в множественном владении одной и той же бизнес-семантикой.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Последствия.&lt;/strong&gt; Меньше коллизий, проще расследование, более прозрачная эволюция справочников. Цена — появление нового критичного сервиса, который нужно проектировать как часть core-архитектуры.&lt;/p&gt;

&lt;h2&gt;
  
  
  Что я бы отдельно заложил в такую систему
&lt;/h2&gt;

&lt;p&gt;Если проектировать подобную схему сразу под production, я бы обязательно закладывал следующие вещи:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;один writer для справочников;&lt;/li&gt;
&lt;li&gt;явные версии и timestamp публикации;&lt;/li&gt;
&lt;li&gt;контроль freshness у потребителей;&lt;/li&gt;
&lt;li&gt;аудит изменений и понятный ownership;&lt;/li&gt;
&lt;li&gt;backward compatibility для изменений в контракте;&lt;/li&gt;
&lt;li&gt;наблюдаемость не только по доступности сервиса, но и по актуальности данных у потребителей.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Вывод
&lt;/h2&gt;

&lt;p&gt;Когда несколько сервисов используют одни и те же справочники, вопрос довольно быстро перестаёт быть вопросом хранения таблиц. Это становится вопросом владения смыслом данных.&lt;/p&gt;

&lt;p&gt;В нашем случае было три базы, три сервиса и одна общая проблема: одинаковые справочники жили в нескольких местах и со временем начинали расходиться. Выделение единого сервиса справочников не убрало всю сложность системы, но убрало самый токсичный её вид — конкурирующие версии правды.&lt;/p&gt;

&lt;p&gt;Если коротко, то вывод такой: в распределённой системе можно жить с разными БД, разными сервисами и разными read-моделями. Но если справочники определяют, как бизнес понимает данные, у них должен быть один хозяин.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>database</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Пять пороков команд</title>
      <dc:creator>Denis Toropov</dc:creator>
      <pubDate>Sat, 05 Sep 2026 18:02:42 +0000</pubDate>
      <link>https://dev.to/dtoropov/piat-porokov-komand-16nl</link>
      <guid>https://dev.to/dtoropov/piat-porokov-komand-16nl</guid>
      <description>&lt;p&gt;Прочитал книгу &lt;strong&gt;«Пять пороков команды»&lt;/strong&gt; Патрика Ленсиони. Книга понравилась.&lt;/p&gt;

&lt;p&gt;Она написана в форме романа, поэтому читается легко — это большой плюс для подобной литературы. При этом ситуации в книге, конечно, сильно упрощены. В реальной жизни команды устроены гораздо сложнее. Но для начинающего руководителя книга всё равно будет полезной: она хорошо показывает базовые механизмы того, почему команда может буксовать.&lt;/p&gt;

&lt;p&gt;Главная идея для меня — &lt;strong&gt;доверие&lt;/strong&gt;. Всё начинается именно с него. Без доверия не работают ни открытые обсуждения, ни здоровые конфликты, ни ответственность, ни общий результат.&lt;/p&gt;

&lt;p&gt;Наверное, поэтому книга мне откликнулась особенно сильно. Выстраивание доверия в команде — это как раз то, чем я занимаюсь последние годы. И практика только подтверждает: процессы важны, но без доверия они быстро становятся формальностью.&lt;/p&gt;

&lt;p&gt;Хорошая книга для тех, кто только начинает управлять людьми и хочет лучше понять, на чём вообще держится сильная команда.&lt;/p&gt;

</description>
      <category>career</category>
      <category>leadership</category>
      <category>management</category>
    </item>
    <item>
      <title>Иллюзия микросервисов и ловушка Shared Database</title>
      <dc:creator>Denis Toropov</dc:creator>
      <pubDate>Wed, 02 Sep 2026 09:52:16 +0000</pubDate>
      <link>https://dev.to/dtoropov/illiuziia-mikrosiervisov-i-lovushka-shared-database-m9o</link>
      <guid>https://dev.to/dtoropov/illiuziia-mikrosiervisov-i-lovushka-shared-database-m9o</guid>
      <description>&lt;p&gt;Во многих компаниях микросервисы начинаются с небольшой уступки здравому смыслу. Новый сервис нужен быстро, а нужные данные уже лежат в общей базе. Значит, можно пока не делать API, не тащить события и не договариваться о контракте. Просто сходить &lt;code&gt;SELECT&lt;/code&gt;-ом в чужую таблицу.&lt;/p&gt;

&lt;p&gt;На короткой дистанции это и правда удобно. На длинной — это почти гарантированный способ собрать распределенный монолит.&lt;/p&gt;

&lt;p&gt;Особенно хорошо это видно в банке. У вас есть общие сущности вроде клиентов, счетов, договоров. С ними одновременно живут несколько команд. Пока все читают одну и ту же схему, любая безобидная правка в базе перестает быть локальной. Кто-то меняет колонку, тип, ограничение или трактовку статуса — и это внезапно становится проблемой не одной команды, а сразу нескольких.&lt;/p&gt;

&lt;p&gt;В какой-то момент независимые релизы заканчиваются. Вместо них начинается синхронизация. Перед каждым изменением нужно выяснять, кто еще сидит на этой таблице, кого надо предупредить, кто не успеет адаптироваться, кто попросит подождать до следующего окна. Архитектурно сервисы вроде бы разнесены. По факту все по-прежнему сидят на одной общей точке зависимости.&lt;/p&gt;

&lt;p&gt;Именно поэтому правило &lt;code&gt;Database per Service&lt;/code&gt; обычно формулируют без смягчений: данные сервиса — это его внутреннее состояние. Если другому сервису что-то нужно, он получает это через публичный контракт, а не через прямой доступ к таблицам.&lt;/p&gt;

&lt;p&gt;На бумаге идея простая. На практике переход почти всегда оказывается неприятнее, чем выглядит в презентации.&lt;/p&gt;

&lt;h3&gt;
  
  
  Как мы вытаскивали счета из общей базы
&lt;/h3&gt;

&lt;p&gt;На одном банковском проекте у нас была большая таблица &lt;code&gt;accounts&lt;/code&gt; в монолитной postgresql-базе. В нее напрямую ходили примерно 10 команд. Пока все было относительно стабильно, это считалось нормой. Проблема стала очевидной в момент, когда мы захотели сделать партиционирование таблицы счетов и вынести её на отдельную базу.&lt;/p&gt;

&lt;p&gt;Тогда выяснилось, что даже локальное изменение в модели счетов может зацепить слишком много потребителей. Стало понятно, что дальше так жить нельзя: управление счетами нужно выносить в отдельный Account Service и закрывать прямой доступ к базе.&lt;/p&gt;

&lt;p&gt;Самое неприятное началось после этого решения. Выделить сервис — не значит просто перенести таблицу и отдать пару REST-методов. Раньше потребители решали свои задачи SQL-запросами, а теперь эти сценарии нужно было превратить в нормальный внешний контракт.&lt;/p&gt;

&lt;p&gt;Сначала сделали базовый &lt;code&gt;GET /accounts/{id}&lt;/code&gt; для точечного получения баланса и статуса. Это была самая простая часть.&lt;/p&gt;

&lt;p&gt;Потом пришлось разбираться со списками. Консьюмеры привыкли к логике вида &lt;code&gt;SELECT ... WHERE ... ORDER BY ... LIMIT&lt;/code&gt;, поэтому одного метода на чтение счета было мало. Нужен был полноценный &lt;code&gt;GET /accounts&lt;/code&gt; с пагинацией, фильтрами, сортировкой и внятным набором параметров. То, что раньше жило в произвольных SQL разных команд, пришлось собирать в осмысленный API.&lt;/p&gt;

&lt;p&gt;Но настоящая сложность была в &lt;code&gt;JOIN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Многие команды строили свои выборки через &lt;code&gt;JOIN accounts&lt;/code&gt; с &lt;code&gt;clients&lt;/code&gt;, чтобы фильтровать счета по атрибутам клиента. Типичный сценарий — подсчитать количество счетов в конткретном отделении или выбрать счета клиентов из нужного сегмента. Пока все данные лежали в одной базе, это был обычный рабочий SQL. После разделения баз такой путь исчез.&lt;/p&gt;

&lt;p&gt;Чтобы не собирать эти выборки через каскад синхронных вызовов между сервисами, мы пошли в денормализацию. Account Service начал асинхронно получать события из Client Service через Kafka и хранить у себя минимальный набор клиентских атрибутов, нужных для поиска: идентификатор клиента, сегмент, регион и другие признаки, без которых потребительские сценарии просто не работали.&lt;/p&gt;

&lt;p&gt;И здесь всплыл еще один кейс, который обычно недооценивают в момент проектирования. Понадобились методы получения не только списков счетов, но и количества счетов в географическом разрезе — по регионам, городам и другим клиентским атрибутам. Раньше это решалось обычными SQL-агрегациями поверх общего контура данных. После разделения сервисов такой запрос уже нельзя было честно собрать без локальной копии клиентских признаков.&lt;/p&gt;

&lt;p&gt;В итоге нам пришлось дополнительно подтянуть в Account Service именно те клиентские атрибуты, которые были нужны для географических срезов и агрегатов. Иначе любой такой метод превращался либо в дорогую склейку нескольких сервисов на лету, либо в медленную и хрупкую конструкцию, которую трудно сопровождать.&lt;/p&gt;

&lt;p&gt;Это, кстати, хороший отрезвляющий момент. Как только сервис должен отдавать не только CRUD, но и прикладные выборки, агрегаты и срезы, одной красивой границы по домену уже недостаточно. Почти всегда приходится строить локальные read-модели или держать денормализованные проекции под реальные сценарии чтения.&lt;/p&gt;

&lt;h3&gt;
  
  
  Что на самом деле меняется
&lt;/h3&gt;

&lt;p&gt;Отказ от Shared Database не убирает сложность. Он просто переставляет ее.&lt;/p&gt;

&lt;p&gt;Пока все сидят в одной базе, часть проблем решает сама СУБД. Там же живут транзакции, &lt;code&gt;JOIN&lt;/code&gt;, строгая консистентность и ощущение, что система под контролем. После перехода к &lt;code&gt;Database per Service&lt;/code&gt; эти удобства заканчиваются. Вместо них появляются другие обязательства: нужно жить с eventual consistency, думать про доставку событий, обрабатывать дубли, следить за порядком обновлений и уметь разбирать сквозные сбои.&lt;/p&gt;

&lt;p&gt;То есть вопрос не в том, есть ли цена у изоляции данных. Цена есть, и она заметная. Вопрос в другом: где вы хотите держать связанность — в общей базе, на которую молча завязаны все, или в явных контрактах и интеграционных механизмах, которыми кто-то действительно владеет.&lt;/p&gt;

&lt;p&gt;Для меня в этом и есть главная развилка. Shared Database кажется быстрым решением, пока система еще терпит. Потом оказывается, что вы сэкономили несколько недель в начале и годами расплачиваетесь за это скоростью изменений. &lt;code&gt;Database per Service&lt;/code&gt; сложнее и дороже в реализации, зато делает границы честными. А в больших системах это обычно важнее, чем локальное удобство на старте.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>database</category>
      <category>microservices</category>
      <category>systemdesign</category>
    </item>
  </channel>
</rss>
