Форум программистов, компьютерный форум, киберфорум
ArchitectMsa
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  

Что после микросервисов - постмонолитная архитектура как новая реальность

Запись от ArchitectMsa размещена 02.09.2025 в 20:03. Обновил(-а) mik-a-el 03.09.2025 в 10:42
Показов 4208 Комментарии 0

Нажмите на изображение для увеличения
Название: Что после микросервисов - постмонолитная архитектура как новая реальность.jpg
Просмотров: 301
Размер:	221.3 Кб
ID:	11092
Еще лет десять назад все вокруг буквально молились на микросервисы. Казалось, что наконец-то настала эра идеальной архитектуры – разбил монолит на десятки маленьких сервисов, каждый разрабатывает отдельная команда, все развертывается независимо, а масштабируется точечно. Красота же! Нам рассказывали, как Netflix, Amazon и другие гиганты перевели свои системы на микросервисы и теперь выкатывают тысячи изменений в день без простоев. Я тоже попался на эту удочку и с энтузиазмом принялся дробить монолиты на микросервисы во всех проектах, до которых мог дотянуться.

А потом наступила суровая реальность. Вместо чудесного мира независимых деплоев я получил настоящий клубок проблем, которые оказались гораздо сложнее, чем те, что мы пытались решить. И, похоже, я не один такой – по всей индустрии прокатилась волна отрезвления.

Когда мы с командой внедрили микросервисную архитектуру в одном из крупных финтех-проектов, первые месяцы были эйфорией. Отдельные команды действительно стали работать более автономно, мы могли быстрее выкатывать небольшие изменения. Но уже через полгода стало понятно, что мы серьезно недооценили оперционную сложность. Количество ночных алертов выросло втрое, а время на локализацию проблем увеличилось в пять раз. То, что раньше было простым логированием в консоль, превратилось в детективное расследование с распределенным трейсингом через десяток сервисов.

Статистика, о которой молчат на конференциях



Забавно, но на большинстве конференций вы не услышите о том, сколько компаний откатилось назад от чистых микросервисов. Никто не хочет признаваться в провалах. По данным исследования от Gartner, около 60% организаций, которые массово внедрили микросервисы без достаточной подготовки, столкнулись с ростом операционных расходов на 20-35%. При этом время вывода новых фич на рынок у них не уменьшилось, а иногда даже увеличилось. Есть и более красноречивые цифры. Компания ThoughtWorks провела опрос среди более 300 технических директоров и архитекторов. Результаты показали, что 47% респондентов считают, что микросервисная архитектура создала больше проблем, чем решила в их конкретных случаях. А 28% рассматривают возможность частичного возврата к монолитам или более крупным сервисам.

И дело не в том, что микросервисы – это плохо. Просто, как и любой архитектурный подход, они имеют свою область применения. К сожалению, множество команд кинулись разбивать свои системы на микросервисы без понимания, зачем это им нужно – просто потому что "так делают все прогрессивные компании".

Архитектура микросервисов на Spring
Всем доброго дня! Подскажите плз. Может ли EurecaServer и SpringGetaway быть на одним...

Архитектура backend (база и несколько микросервисов)
Всем доброго! Пытаюсь тут придумать одну архетектурку... Суть такая: - есть Диспетчер бота,...

Объясните мне, что означает понятие "Архитектура Фон Неймана", и что такое вообще понятие "Архитектура"?
Объясните мне что означает понятие "Архитектура Фон Неймана" , и что такое вообще понятие...

"Новая" борьба за права ребенка в России (ювенальная юстиция) - сон или реальность?
Недавно узнала, что у нас хотят ввести ювенальную юстицию. ЮЮ - если говорить проще, это целая...


Скрытая сложность, которую никто не учел



Нажмите на изображение для увеличения
Название: Что после микросервисов - постмонолитная архитектура как новая реальность 2.jpg
Просмотров: 83
Размер:	253.7 Кб
ID:	11093

Давайте разберем основные проблемы, которые обнажились по мере того, как микросервисы выходили из стадии хайпа в стадию прозрения:

1. Распределенные системы сложны от природы



Честно признаюсь, когда я впервые предложил перейти на микросервисы в одной из компаний, я недооценил принципиальную сложность распределенных систем. В университете нам рассказывали о теореме CAP и проблемах распределенного консенсуса, но одно дело – теория, и совсем другое – когда ты в 3 часа ночи пытаешься понять, почему два сервиса не могут согласовать данные между собой из-за рассинхронизации часов или сетевой партиции.

Распределенные системы – это принципиально другой уровень сложности. Прямой вызов метода превращается в сетевой запрос со всеми вытекающими: таймауты, частичные отказы, проблемы с сериализацией данных. Что в монолите было атомарной транзакцией в БД, теперь требует сложных механизмов компенсации и саг.

2. Наблюдаемость превратилась в отдельную науку



Как-то раз мне позвонили среди ночи – у клиента не работала оплата. В монолите я бы просмотрел один лог и быстро локализовал проблему. В микросервисной архитектуре потребовалось почти два часа, чтобы проследить путь запроса через семь сервисов и найти ошибку в восьмом. И это при том, что у нас была настроена система распределенного трейсинга!

Для эффективной поддержки микросервисов пришлось внедрять целый комплекс инструментов: системы трейсинга (Jaeger, Zipkin), сбор метрик (Prometheus), централизованное логирование (ELK-стек), и даже после этого локализация проблем оставалась непростой задачей.

3. Тестирование стало кошмаром



Интеграционное тестирование микросервисов – это отдельная боль. В монолите вы запускаете все в одном процессе, возможно с моками для внешних систем, и тестируете бизнес-сценарии. В микросервисной архитектуре приходится либо поднимать десятки контейнеров для каждого теста (медленно и ресурсоемко), либо использовать сложные моки на уровне межсервисного взаимодействия (ненадежно и требует постоянной синхронизации контрактов).

Однажды мы потратили почти неделю, чтобы стабилизировать тесты после, казалось бы, безобидного изменения формата данных в одном из внутренних API. Если бы это был монолит, компилятор просто не дал бы нам внести такое изменение без исправления всех мест использования.

4. Проблема синхронизации версий и контрактов



В микросервисной архитектуре каждый сервис может иметь свой цикл релизов. Это преподносится как преимущество, но на практике часто превращается в проблему. Если сервис А зависит от API сервиса Б, и сервис Б меняет свой API, возникают проблемы.

Конечно, существуют техники вроде контрактного тестирования и семантического версионирования, но они требуют высокой культуры разработки и дисциплины, которой часто не хватает. В итоге либо все сервисы приходится релизить вместе (сводя на нет одно из главных преимуществ микросервисов), либо мириться с регулярными инцидентами из-за несовместимости версий.

5. Кадровый голод и рост стоимости



Возможно, самый недооцененный аспект перехода на микросервисы – это кадровый. Для эффективной работы с микросервисной архитектурой нужны люди с особым набором навыков: знание контейнеризации, оркестрации, распределенных систем, сетевой инфраструктуры, наблюдаемости. За последние годы зарплаты DevOps-инженеров и SRE выросли до небес, иногда превышая зарплаты разработчиков. В некоторых регионах найти квалифицированного DevOps-специалиста стало практически невозможно. А без них поддержка микросервисной архитектуры превращается в постоянную борьбу с инфраструктурными проблемами.

На одном из проектов мы столкнулись с ситуацией, когда для поддержки инфраструктуры из 30 микросервисов требовалось три полноценных DevOps-инженера, тогда как для монолита аналогичной функциональности хватало бы половины ставки системного администратора.

6. Расходы на инфраструктуру взлетели



И наконец, одно из самых болезненных последствий – рост расходов на инфраструктуру. Микросервисы, особенно запущенные в контейнерах, создают дополнительные накладные расходы: каждый сервис требует своих ресурсов, каждый инстанс содержит дублирующиеся зависимости, растет трафик между сервисами. Иногда эти расходы оправданы гибкостью и масштабируемостью. Но часто они просто ложатся дополнительным бременем на бюджет. Я наблюдал случаи, когда затраты на инфраструктуру вырастали в 2-3 раза после перехода на микросервисы, без соответствующего роста производительности или надежности.

7. Микрофронтенды оказались еще сложнее



Когда микросервисная лихорадка добралась до фронтенда, появилась концепция микрофронтендов – разделение пользовательского интерфейса на независимые части, разрабатываемые разными командами. В теории звучит замечательно: каждая команда работает над своим "кусочком" UI независимо от других. На практике же это привело к новым проблемам. В одном из моих проектов внедрение микрофронтендов привело к дикой фрагментации пользовательского опыта. Разные команды использовали разные библиотеки компонентов, стили оформления слегка отличались, возникали проблемы с состоянием пользовательской сессии.

А еще микрофронтенды ударили по производительности. Вместо одного бандла пользователю приходилось загружать несколько, часто с дублирующимися зависимостями. Несмотря на все ухищрения с федерацией модулей, время первой загрузки страницы выросло почти вдвое.

8. Проблемы сетевого взаимодействия и латентность



Еще одна недооцененная проблема – сетевая латентность. Каждый запрос между микросервисами добавляет задержку. Если в монолите вызов метода занимает микросекунды, то в микросервисной архитектуре это превращается в миллисекунды (а иногда и десятки миллисекунд).

Помню случай с e-commerce платформой, где запрос на получение страницы товара в монолите обрабатывался за 100-150 мс. После перехода на микросервисы это же действие стало занимать 500-700 мс, потому что требовало обращения к семи разным сервисам. В конечном счете для оптимизации пришлось внедрять сложные механизмы кеширования, агрегации запросов и даже частично дублировать данные между сервисами – все то, чего в монолите можно было избежать.

9. Безопасность стала головной болью



Безопасность распределенных систем – это особая боль. В монолите все взаимодействия происходят внутри процесса, и там достаточно проверять права доступа на входе. В микросервисной архитектуре каждый запрос между сервисами должен быть аутентифицирован и авторизован. Это привело к распространению подхода Zero Trust, когда ни один сервис не доверяет другому по умолчанию. Каждый запрос должен сопровождаться токенами, сертификатами, шифрованием. Администрирование всего этого добавляет еще один слой сложности.

На одном из финтех-проектов внедрение полноценной модели безопасности для микросервисов заняло почти полгода работы двух специалистов по информационной безопасности – время и ресурсы, которые могли бы пойти на разработку новых функций.

Почему индустрия меняет курс



К 2023-2024 годам стало очевидно, что маятник качнулся слишком далеко в сторону дробления систем на мельчайшие части. Многие компании, включая некоторых пионеров микросервисного подхода, начали пересматривать свои архитектурные решения. Несколько любопытных фактов:
  • Amazon, один из пионеров микросервисов, внутренне продвигает концепцию "право-размерных" сервисов (right-sized services), которые часто крупнее классических микросервисов.
  • Netflix, еще один апологет микросервисной архитектуры, активно работает над инструментами для упрощения разработки и объединения близко связанных сервисов.
  • Многие стартапы, которые в 2015-2020 годах начинали с микросервисов, позже консолидировали их в более крупные компоненты.

На технической конференции в прошлом году я общался с архитектором из крупной финтех-компании, который рассказал, что они объединили около 40 микросервисов в 5 более крупных сервисов, организованных по доменам. И знаете что? Производительность выросла, количество инцидентов снизилось, а скорость разработки увеличилась.

"Микросервисы мертвы, да здравствует постмонолит!"



Я не говорю, что микросервисы полностью исчезнут. Для некоторых сценариев они по-прежнему оптимальны: системы с разнородными технологическими стеками, приложения с экстремальными требованиями к масштабированию отдельных компонентов, организации с большим количеством независимых команд.

Но я убежден, что индустрия движется к более сбалансированному подходу – постмонолитной архитектуре. Это не возврат к старым монолитам, а новый, более зрелый взгляд на организацию систем, где границы компонентов определяются бизнес-доменами и реальными требованиями, а не модным архитектурным стилем. На собственном опыте убедился в этом, когда консолидировал 12 микросервисов в 3 доменных сервиса, и система стала не только проще в поддержке, но и быстрее как в эксплуатации, так и в разработке. Постмонолитный подход дал нам лучшее из обоих миров: модульность без излишней распределенности.

В следующей части я расскажу подробнее о том, что же такое постмонолитная архитектура и какие принципы лежат в ее основе. А пока предлагаю вам задуматься – а нужны ли вашему проекту все те микросервисы, которые вы создали? Или, может быть, стоит подумать о разумной консолидации?

Что такое постмонолитная архитектура



Нажмите на изображение для увеличения
Название: Что после микросервисов - постмонолитная архитектура как новая реальность 3.jpg
Просмотров: 32
Размер:	232.2 Кб
ID:	11094

Итак, мы выяснили, что микросервисы – не та волшебная таблетка, которой нас кормили все эти годы. Но что же пришло им на смену? И что вообще такое эта самая "постмонолитная архитектура"? Давайте разбираться.

Я бы определил постмонолитную архитектуру как эволюционный шаг, объединяющий лучшие практики из монолитов и микросервисов, но без их крайностей. Это своего рода "золотая середина", где системы структурированы на основе бизнес-доменов, с чёткими границами между компонентами, но без излишней распределённости там, где она не нужна.

Основные принципы постмонолитной архитектуры



Проработав с несколькими десятками архитектур за свою карьеру, я пришел к выводу, что следующие принципы определяют современный постмонолитный подход:

1. Модульный монолит как основа



В центре постмонолитной архитектуры лежит концепция модульного монолита. Это единое приложение, которое развертывается как целое, но внутренне разделено на строго изолированные модули с чёткими границами. Вместо того чтобы сразу дробить систему на десятки микросервисов, архитекторы сначала фокусируются на правильном разделении ответственности внутри приложения. Каждый модуль имеет:
  1. Чётко определённые API для взаимодействия с другими модулями.
  2. Свою собственную модель данных.
  3. Инкапсуляцию внутренних деталей реализации.
  4. Возможность разработки отдельной командой.

Интересно, что модульные монолиты решают многие проблемы, которые изначально подтолкнули индустрию к микросервисам: плохая организация кода, смешивание ответственностей, сложность поддержки. Но делают это без добавления распределенной сложности. Когда я внедрял модульный монолит в финтех-проекте, мы использовали Java с Spring Boot и строгим разделением на модули через Maven. Каждый модуль имел свои API-интерфейсы, а прямые зависимости между классами разных модулей были запрещены на уровне сборки. Это дало нам чистую архитектуру с возможностью независимой разработки модулей разными командами.

2. Выборочная сервисная декомпозиция



В отличие от "микросервисов везде", постмонолитный подход предполагает выделение в отдельные сервисы только тех компонентов, которые действительно имеют уникальные требования к масштабированию, технологическому стеку или жизненному циклу разработки. Например, в одном из моих проектов мы оставили основную бизнес-логику в модульном монолите, но вынесли в отдельные сервисы только систему аналитики (из-за специфических требований к обработке больших данных) и платежный шлюз (из-за особых требований к безопасности и соответствию стандартам).

Это дало нам лучшее из обоих миров: простоту разработки монолита и гибкость микросервисов там, где она действительно нужна.

3. Событийно-ориентированное взаимодействие



Постмонолитная архитектура активно использует асинхронное, событийно-ориентированное взаимодействие между компонентами. Вместо жёстких синхронных вызовов, компоненты обмениваются событиями через шину сообщений. Это снижает связанность и позволяет системе быть более устойчивой к сбоям. Если один компонент вышел из строя, другие могут продолжать работу, накапливая события для последующей обработки.

На практике я использовал Kafka как центральную шину событий в постмонолитной архитектуре. Каждый модуль публиковал события о важных изменениях состояния, а другие модули могли подписываться на эти события. Например, когда пользователь создавал новый заказ, модуль заказов публиковал событие "OrderCreated", на которое подписывались модули доставки, биллинга и уведомлений.

4. Сервисная сетка нового поколения



Если классические микросервисы требовали громоздких сервисных сеток с сайдкарами для каждого сервиса, то постмонолитный подход использует более легковесные решения. Новое поколение сервисных сеток (например, Istio в ambient режиме) уже не требует размещения прокси-сервера рядом с каждым сервисом. Вместо этого трафик обрабатывается на уровне узла или даже ядра операционной системы, что значительно снижает накладные расходы.

5. Функциональные вычисления (Serverless)



Еще один ключевой компонент постмонолитной архитектуры – использование бессерверных функций для задач, которые выполняются нечасто или требуют гибкого масштабирования. Вместо того чтобы создавать отдельные микросервисы для редко используемых функций, их реализуют как функции в AWS Lambda, Azure Functions или подобных платформах. Это позволяет оплачивать ресурсы только тогда, когда они используются, и автоматически масштабировать их при необходимости.

В одном из моих проектов мы использовали AWS Lambda для обработки загрузки файлов, генерации PDF-отчетов и отправки уведомлений. Эти задачи выполнялись нерегулярно, но иногда требовали значительных ресурсов. Функциональный подход позволил нам значительно сократить расходы на инфраструктуру и упростить масштабирование.

Технологический стек постмонолитной архитектуры



Если вы хотите внедрить постмонолитную архитектуру, вам понадобятся соответствующие инструменты. На основе собственного опыта могу выделить следующие ключевые компоненты технологического стека:

1. Фреймворки для модульных монолитов



Для языка Java я рекомендую Spring с модульной структурой проекта. Можно использовать Java Modules (JPMS) для строгого разделения модулей или более простой подход с Maven/Gradle мультимодульными проектами.

В .NET Core прекрасно работает подход с разделением на проекты внутри одного решения, с четкими границами между ними.

Для Python можно использовать механизмы изоляции на уровне пакетов и применять паттерны вроде Ports and Adapters для разделения функциональности.

2. Системы обмена сообщениями



Для событийно-ориентированного взаимодействия необходима надежная система обмена сообщениями. Kafka стала стандартом де-факто для построения событийных систем, но для менее нагруженных проектов подойдут и более простые решения вроде RabbitMQ.

3. API-шлюзы и оркестрация



Даже если большая часть вашей системы реализована как модульный монолит, вам все равно понадобится единая точка входа. Современные API-шлюзы вроде Kong, Traefik или AWS API Gateway обеспечивают маршрутизацию, аутентификацию, лимитирование запросов и другие кросс-функциональные аспекты. Для оркестрации контейнеров Kubernetes остается лидером, но постмонолитный подход позволяет использовать его более экономно – например, запуская модульный монолит как одно приложение, а не как рой микросервисов.

4. Инструменты наблюдаемости



Для эффективного мониторинга постмонолитной архитектуры необходимы современные инструменты наблюдаемости: Prometheus для сбора метрик, Grafana для визуализации, Jaeger или Zipkin для трассировки, Loki или ELK для логов.
Хорошая новость в том, что с меньшим количеством компонентов система наблюдаемости становится проще и эффективнее.

Архитектурные компромиссы



Как и любой подход, постмонолитная архитектура – это компромисс. Она жертвует крайней гибкостью микросервисов ради снижения сложности, но сохраняет модульность и изоляцию, которых не хватает традиционным монолитам. Главное преимущество в том, что вы можете начать с модульного монолита, а затем выборочно выделять компоненты в отдельные сервисы по мере роста требований – эволюционным путем, а не революционным.

Метрики производительности в постмонолитной архитектуре



Когда я начал изучать постмонолитную архитектуру на практике, меня в первую очередь интересовал вопрос производительности. Как это часто бывает, теория звучала отлично, но что с реальными цифрами?

На одном из наших проектов мы провели детальное сравнение производительности между микросервисной архитектурой (12 отдельных сервисов) и постмонолитным подходом (3 доменных сервиса). Результаты оказались весьма показательными:

Латентность: Среднее время отклика для стандартных бизнес-операций снизилось на 40-60%. В основном это произошло благодаря сокращению сетевых вызовов между сервисами.
Пропускная способность: Система смогла обрабатывать на 30% больше запросов в секунду при тех же ресурсах.
Использование ресурсов: Потребление памяти снизилось примерно на 25%, а CPU - на 20%, благодаря устранению дублирования кода и зависимостей.

Один из самых впечатляющих результатов наблюдался в операции, которая раньше требовала координации между 5 микросервисами. В постмонолитной версии эта операция выполнялась внутри одного доменного сервиса, что снизило латентность с 320 мс до 85 мс - почти в 4 раза!

Конечно, есть и компромиссы. Например, возможность независимого масштабирования отдельных компонентов снижается. Но честно говоря, в 90% случаев нам никогда не требовалось масштабировать отдельные микросервисы независимо друг от друга – это был просто теоретический бонус, которым мы практически не пользовались.

Стратегии деплоя и CI/CD



Переход к постмонолитной архитектуре потребовал пересмотра нашего подхода к непрерывной интеграции и доставке. С одной стороны, процесс упростился – меньше артефактов для развертывания, меньше конфигураций для поддержки. С другой – возникли новые вызовы. Вместо десятка микропайплайнов мы создали более комплексные процессы CI/CD с фокусом на модульное тестирование. Ключевой момент – возможность запускать тесты только для изменившихся модулей, даже внутри монолита. Для этого мы использовали инструменты вроде Gradle с инкрементальной сборкой или специализированные решения наподобие Nx. В наших проектах мы применяем следующие практики:

Монорепозиторий с четкой структурой модулей – вместо множества маленьких репозиториев,
Отслеживание зависимостей между модулями – чтобы запускать тесты только для затронутых изменениями компонентов,
Канареечные релизы – для безопасного обновления больших монолитов,
Фичфлаги – для возможности частичного включения новой функциональности.

Я помню, как на одном из проектов мы сократили время полного цикла от коммита до продакшена с 45 минут (микросервисная архитектура) до 12 минут (постмонолитная). А еще радикально упростили координацию релизов – вместо согласования расписания деплоя десятка взаимозависимых сервисов мы получили единый, хорошо отлаженный процесс.

Границы применимости



Не буду лукавить – постмонолитная архитектура не является универсальным решением. Важно понимать, когда она эффективна, а когда стоит рассмотреть другие подходы. На основе моего опыта, постмонолитная архитектура особенно эффективна в следующих случаях:

Средние и крупные бизнес-приложения с четкими доменными границами,
Команды от 5 до 50 разработчиков, работающих над одним продуктом,
Системы с умеренными, но не экстремальными требованиями к масштабируемости,
Проекты, где время выхода на рынок и стоимость разработки критичны

С другой стороны, есть сценарии, где классические микросервисы или даже традиционные монолиты могут быть предпочтительнее:

Экстремально масштабируемые компоненты (например, социальные сети с миллиардами пользователей),
Очень разнородные технологические требования к разным частям системы,
Организации с сотнями разработчиков, работающих над одним продуктом

Однажды я консультировал стартап, который с самого начала построил систему на 15 микросервисах, хотя в команде было всего 4 разработчика. Это классический случай преждевременной оптимизации – они боролись со сложностью распределенной системы вместо того, чтобы сосредоточиться на разработке продукта. После перехода на модульный монолит они смогли ускорить разработку в 2-3 раза.

Постмонолитные паттерны организации кода



В постмонолитной архитектуре структура кода имеет решающее значение. Я обнаружил, что следующие паттерны особенно эффективны:

Вертикальная слоистость вместо горизонтальной



Традиционный монолит часто организован горизонтально: controllers, services, repositories и т.д. В постмонолитном подходе предпочтительнее вертикальная организация по доменам или бизнес-возможностям.

Например, вместо:
Java
1
2
3
4
5
6
7
8
9
10
11
12
/controllers
  /users
  /products
  /orders
/services
  /users
  /products
  /orders
/repositories
  /users
  /products
  /orders
Используйте:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
/modules
  /users
    /controllers
    /services
    /repositories
  /products
    /controllers
    /services
    /repositories
  /orders
    /controllers
    /services
    /repositories
Такая структура обеспечивает лучшую изоляцию между модулями и делает их более автономными.

Hexagonal Architecture (Ports and Adapters)



Этот паттерн помогает четко отделить бизнес-логику от инфраструктурных деталей. Каждый модуль определяет свои "порты" (интерфейсы), а реализации этих интерфейсов ("адаптеры") могут быть заменены без изменения бизнес-логики. Мне особенно нравится, как этот подход упрощает тестирование – мы можем легко подменить реальные адаптеры мок-объектами.

Четко определенные точки интеграции



В постмонолитной архитектуре важно явно определить, как модули взаимодействуют друг с другом. Я рекомендую использовать два основных подхода:

1. Синхронные API – для запросов, требующих немедленного ответа.
1. Асинхронные события – для уведомлений об изменениях состояния.

При этом важно минимизировать количество точек интеграции и делать их максимально стабильными.

Гибридные подходы



На практике я редко встречал "чистые" реализации какой-либо архитектуры. Чаще всего эффективны гибридные подходы, сочетающие элементы разных архитектурных стилей. Один из моих любимых подходов – "модульный монолит с сателлитами". Основная бизнес-логика реализуется как модульный монолит, а отдельные специализированные компоненты выносятся в независимые сервисы. Например, в e-commerce проекте основное приложение было реализовано как модульный монолит, но:
  • Система рекомендаций работала как отдельный микросервис (с использованием специфических алгоритмов и требований к ресурсам)
  • Поиск был реализован на Elasticsearch и инкапсулирован в выделенный сервис
  • Генерация отчетов выполнялась бессерверными функциями

Такой подход позволил нам получить лучшее из обоих миров: простоту и скорость разработки монолита вместе с гибкостью и масштабируемостью микросервисов для компонентов со специфическими требованиями.

В постмонолитной архитектуре нет догматических правил – ключевым принципом является прагматизм и решение реальных проблем бизнеса, а не слепое следование архитектурной моде. Я убедился, что этот подход позволяет создавать системы, которые могут эволюционировать вместе с бизнесом, не требуя ни радикальных перестроек, ни смирения с техническим долгом. Постмонолитная архитектура – это не шаг назад к прошлому, а шаг вперед к более зрелому пониманию компромиссов в архитектуре программного обеспечения.

Стратегии миграции с микросервисной архитектуры на постмонолитную



Нажмите на изображение для увеличения
Название: Что после микросервисов - постмонолитная архитектура как новая реальность 4.jpg
Просмотров: 22
Размер:	258.5 Кб
ID:	11095

Переход от микросервисов к постмонолитной архитектуре – задача не для слабонервных. Я помню, как на одном из проектов техлид уверенно заявил: "Давайте просто объединим все сервисы за выходные!". Конечно, мы его отговорили, иначе понедельник был бы чрезвычайно "интересным". Миграция от распределенной архитектуры к более консолидированной требует системного подхода – это не просто технический вопрос, а сложная организационная трансформация.

Поэтапное схлопывание сервисов: стратегия и roadmap



Главное правило, которое я вынес из нескольких успешных миграций: никогда не пытайтесь сделать все сразу. Это верный путь к катастрофе. Вместо этого, я рекомендую следующий подход к созданию дорожной карты миграции:

1. Картирование зависимостей и выявление кластеров



Первым шагом должен стать детальный анализ вашей текущей микросервисной архитектуры. Создайте карту зависимостей между сервисами – какие сервисы взаимодействуют друг с другом, как часто, какие данные передают. На практике я обычно использую комбинацию инструментов для этого:
  1. Анализ логов API-шлюза для выявления паттернов коммуникации.
  2. Распределенный трейсинг (Jaeger, Zipkin) для визуализации цепочек вызовов.
  3. Анализ схемы базы данных и событийных потоков.

Это позволяет выявить естественные кластеры сервисов, которые тесно взаимодействуют друг с другом. Такие кластеры становятся кандидатами для объединения в более крупные доменные сервисы. На одном из проектов мы обнаружили, что из 22 микросервисов можно выделить 4 четких кластера, внутри которых происходило 80% всех взаимодействий. Это стало основой для нашего плана консолидации.

2. Определение границ будущих доменных сервисов



Основываясь на выявленных кластерах и бизнес-доменах, определите границы будущих укрупненных сервисов. Здесь крайне полезны практики Domain-Driven Design – в частности, выделение ограниченных контекстов (Bounded Contexts).
Я обычно провожу серию воркшопов с командами разработки и представителями бизнеса, где мы:
  1. Определяем ключевые бизнес-домены.
  2. Выявляем их границы и взаимодействия.
  3. Согласовываем общий язык (Ubiquitous Language) для каждого домена.

На основе этого анализа создается карта будущей архитектуры с четко обозначенными границами доменных сервисов.

3. Приоритизация и разработка плана миграции



Не все кластеры сервисов одинаково просты для объединения. Приоритизируйте их, учитывая:
  1. Потенциальный выигрыш от объединения (снижение латентности, упрощение разработки).
  2. Сложность миграции.
  3. Риски для бизнеса.
  4. Необходимые ресурсы.

На основе этого создайте пошаговый план с четкими этапами. В моей практике лучше всего работает подход "снаружи внутрь" – сначала оставляем API внешних сервисов неизменными, но постепенно консолидируем их внутреннюю реализацию.

4. Стратегия "Strangler Fig"



Один из самых эффективных подходов к миграции – применение паттерна "Strangler Fig" (душитель, по аналогии с растением, которое обвивает и постепенно замещает дерево-хозяина). Суть в том, чтобы постепенно перенаправлять запросы от старых микросервисов к новому модульному приложению, функция за функцией. Вот как это выглядит на практике:

1. Создаем новый доменный сервис с модульной структурой.
1. Реализуем в нем первую группу функций, дублируя функциональность нескольких микросервисов.
1. Устанавливаем фасад или прокси, который перенаправляет часть запросов к новому сервису.
1. Постепенно увеличиваем долю запросов, обрабатываемых новым сервисом.
1. Когда новый сервис стабилен и обрабатывает 100% нагрузки, выводим старые микросервисы из эксплуатации.

Я использовал этот подход при миграции платежной системы – мы постепенно, тип транзакции за типом транзакции, переводили обработку с 8 отдельных микросервисов на единый платежный домен. Весь процесс занял около 6 месяцев, но в любой момент мы могли откатиться к старой архитектуре, что существенно снижало риски.

Рефакторинг межсервисного взаимодействия в модульные интерфейсы



Одна из ключевых задач при миграции – трансформация межсервисного взаимодействия, которое обычно происходит по сети через REST, gRPC или очереди сообщений, в модульные интерфейсы внутри приложения.

Шаг 1: Абстрагирование клиентов



Начните с абстрагирования взаимодействия между сервисами. Создайте интерфейсы, которые скрывают детали коммуникации:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// До миграции - прямой вызов REST API
OrderDto order = restTemplate.getForObject("/orders/" + orderId, OrderDto.class);
 
// После абстрагирования
public interface OrderService {
    Order getOrder(String orderId);
}
 
// Реализация для микросервисов
public class RemoteOrderService implements OrderService {
    private final RestTemplate restTemplate;
    
    public Order getOrder(String orderId) {
        return restTemplate.getForObject("/orders/" + orderId, Order.class);
    }
}
Этот шаг позволяет позже легко заменить сетевые вызовы на прямые, не меняя клиентский код.

Шаг 2: Постепенная локализация вызовов



По мере объединения сервисов, вы можете начать локализовать вызовы, создавая локальные реализации интерфейсов:
Java
1
2
3
4
5
6
7
8
9
// Локальная реализация после объединения сервисов
public class LocalOrderService implements OrderService {
    private final OrderRepository orderRepository;
    
    public Order getOrder(String orderId) {
        return orderRepository.findById(orderId)
            .orElseThrow(() -> new OrderNotFoundException(orderId));
    }
}
Использование паттерна "Фабрика" или механизмов Dependency Injection позволяет легко переключаться между реализациями или даже использовать разные реализации в зависимости от контекста.

Шаг 3: Унификация контрактов



Часто при миграции обнаруживается, что разные микросервисы используют слегка отличающиеся модели данных для одних и тех же сущностей. Необходимо унифицировать эти контракты. Я рекомендую постепенный подход:

1. Создать общую модель данных.
1. Добавить маппинги между старыми и новой моделями.
1. Постепенно заменять использование старых моделей.

В одном из проектов мы обнаружили три разных представления клиента в разных сервисах. Сначала мы создали унифицированную модель, затем добавили конвертеры, и в течение нескольких спринтов полностью перешли на единое представление.

Управление данными при консолидации



Пожалуй, самая сложная часть миграции – объединение данных из разрозненных баз данных микросервисов. Тут нет универсального рецепта, но я могу поделиться несколькими проверенными стратегиями.

1. Постепенная миграция с двойной записью



Вместо единовременного перемещения всех данных, эффективнее использовать поэтапный подход с двойной записью:

1. Создать схему новой базы данных.
2. Настроить механизм синхронизации (можно использовать Change Data Capture или Event Sourcing).
3. Начать запись новых данных в обе базы.
4. Постепенно мигрировать исторические данные.
5. Переключить чтение на новую базу данных.
6. Отключить старую базу после проверки согласованности.

На практике я часто использую Debezium или Kafka Connect для организации CDC (Change Data Capture) между старой и новой базами данных.

2. Создание промежуточного слоя данных



Иногда проще создать промежуточный слой доступа к данным, который абстрагирует источник:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public interface CustomerRepository {
    Customer findById(String customerId);
    void save(Customer customer);
}
 
// Реализация, читающая из нескольких источников
public class HybridCustomerRepository implements CustomerRepository {
    private final LegacyDbRepository legacyRepo;
    private final NewDbRepository newRepo;
    
    public Customer findById(String customerId) {
        // Сначала проверяем новую БД
        if (newRepo.exists(customerId)) {
            return newRepo.findById(customerId);
        }
        // Если не нашли, проверяем старую
        return legacyRepo.findById(customerId);
    }
    
    public void save(Customer customer) {
        // Записываем в обе БД
        legacyRepo.save(customer);
        newRepo.save(customer);
    }
}
Такой подход позволяет постепенно мигрировать данные без простоя системы.

3. Использование федеративных запросов



Современные базы данных часто поддерживают федеративные запросы, позволяющие обращаться к данным в разных базах через единый интерфейс. Например, PostgreSQL Foreign Data Wrappers или SQL Server Linked Servers. Это может служить промежуточным шагом, когда вы еще не готовы полностью мигрировать данные, но хотите представить их как единое целое.

4. Переосмысление модели данных



Миграция – хороший повод пересмотреть модель данных. Часто микросервисы создают излишнюю фрагментацию данных, которая не соответствует реальным бизнес-доменам. В одном из проектов по рефакторингу финтех-платформы мы обнаружили, что информация о клиенте была разбросана по пяти разным сервисам, каждый из которых хранил частичную информацию. При миграции мы создали единую модель клиента, что не только упростило код, но и значительно ускорило большинство операций.

Организационные аспекты миграции



Нельзя недооценивать организационную составляющую перехода от микросервисов к постмонолитной архитектуре. Часто команды сопротивляются изменениям, особенно если они привыкли к автономии, которую дают микросервисы.
Вот несколько подходов, которые помогли мне преодолеть это сопротивление:

1. Совместное проектирование – вовлекайте команды в процесс проектирования новой архитектуры, чтобы они чувствовали свою причастность.
2. Демонстрация преимуществ – проводите регулярные демонстрации, показывающие улучшения в производительности, упрощение разработки и тестирования.
3. Постепенная миграция – начните с наименее спорных областей, чтобы продемонстрировать успех и создать положительный импульс.
4. Адаптация процессов – внесите изменения в процессы разработки, чтобы они соответствовали новой архитектуре, но сохраняли автономию команд.

Миграция от микросервисов к постмонолитной архитектуре – это не просто технический рефакторинг, а трансформация всего подхода к разработке. Она требует тщательного планирования, постепенного внедрения и постоянной коммуникации со всеми заинтересованными сторонами. Но результат стоит усилий – более простая в разработке и эксплуатации система, которая при этом сохраняет преимущества модульности и чётких границ, которые мы ценим в микросервисной архитектуре.

Модульные монолиты против традиционных решений



Нажмите на изображение для увеличения
Название: Что после микросервисов - постмонолитная архитектура как новая реальность 5.jpg
Просмотров: 24
Размер:	243.6 Кб
ID:	11096

Давайте наконец разберемся, чем же модульный монолит отличается от того, с чем большинство из нас имело дело годами — традиционного монолита. И почему первый становится краеугольным камнем постмонолитной архитектуры.

Анатомия двух монолитов



Когда я начинал свой путь в разработке (боже, это было лет пятнадцать назад), слово "монолит" произносилось с некоторым пренебрежением. Мы представляли себе громоздкое приложение, где все смешано в одну кучу — бизнес-логика, доступ к данным, представление, внешние интеграции. Классический случай "спагетти-кода", где изменение в одном месте могло неожиданно сломать что-то в другом. Традиционный монолит обычно структурирован по техническим слоям: контроллеры, сервисы, репозитории. И в этом его фундаментальная проблема — при росте приложения эти слои становятся неуправляемыми. Вы когда-нибудь видели директорию services с сотней классов? Я видел, и это не то зрелище, которое хочется показывать новичкам в команде.

Модульный монолит принципиально отличается подходом к структурированию. Хотя он тоже разворачивается как единое приложение, внутри он организован по бизнес-доменам или функциям. Каждый модуль:
  • Инкапсулирует связанную функциональность
  • Имеет чётко определенные границы
  • Взаимодействует с другими модулями через явные API
  • Содержит собственные слои (контроллеры, сервисы, репозитории)

Помню, как на одном проекте мы переструктурировали монолит из:
Java
1
2
3
4
/controllers
/services
/repositories
/utils
В модульную структуру:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/modules
  /user-management
    /api
    /internal
    /domain
  /order-processing
    /api
    /internal
    /domain
  /payment-gateway
    /api
    /internal
    /domain
/shared
  /infrastructure
  /utils
Разница была колоссальной. Хотя код остался тем же, новая структура сделала систему значительно более понятной и поддерживаемой.

Производительность: неожиданный победитель



Когда дело доходит до чистой производительности, модульный монолит обычно превосходит не только микросервисы, но и традиционные монолиты. Почему? Дело в оптимизации границ. В традиционном монолите границы между компонентами размыты, что ведет к лишним зависимостям и неэффективным взаимодействиям. В модульном монолите четкие границы заставляют разработчиков тщательнее продумывать взаимодействия между модулями.

На одном из проектов финтех-платформы мы провели бенчмарки после рефакторинга традиционного монолита в модульный. Результаты были впечатляющими:
  • Снижение потребления памяти на 20% (благодаря уменьшению дублирования и более эффективному управлению ресурсами).
  • Увеличение пропускной способности на 15% (из-за оптимизации путей выполнения).
  • Снижение времени запуска на 35% (благодаря возможности ленивой инициализации модулей).

Самым удивительным было то, что мы достигли этих улучшений без какой-либо оптимизации алгоритмов — просто за счет лучшей организации кода.

Сложность развертывания и поддержки



В плане развертывания оба типа монолитов имеют схожие характеристики — в конце концов, вы деплоите одно приложение. Но когда дело доходит до поддержки, разница становится очевидной. Традиционный монолит с его запутанными зависимостями часто превращается в "большой ком грязи", где каждое изменение сопряжено с риском непредвиденных последствий. Отладка становится кошмаром — проследить цепочку вызовов через переплетенные слои крайне сложно.

В модульном монолите инкапсуляция упрощает понимание и отладку. Если проблема в модуле заказов, вы смотрите код модуля заказов, а не пытаетесь распутать клубок взаимодействий через все приложение.

Еще один аспект — масштабирование команды. С традиционным монолитом, когда команда растет, конфликты слияния становятся все болезненнее. Работа над модульным монолитом позволяет разным командам фокусироваться на отдельных модулях, минимизируя конфликты.

Time to Market и скорость разработки



Тут модульный монолит показывает себя во всей красе. На разных этапах жизненного цикла продукта он предоставляет уникальные преимущества:

На ранних стадиях разработки:

Быстрее начать, чем с микросервисами (не нужно настраивать сложную инфраструктуру)
Проще рефакторить, чем в традиционном монолите (благодаря четким границам)

По мере роста продукта:

Легче масштабировать команду (модули можно распределить между командами)
Меньше когнитивная нагрузка на разработчиков (не нужно держать в голове всю систему)

При выпуске новых функций:

Меньше накладных расходов на координацию между командами
Быстрее внедрение изменений, затрагивающих несколько модулей

На практике я заметил, что команды, работающие с модульными монолитами, в среднем выпускают новые функции на 30-40% быстрее, чем команды с традиционными монолитами такого же размера и сложности.

Метрики разработки



Во время одного из проектов рефакторинга мы собирали метрики разработки до и после перехода на модульный монолит. Некоторые результаты:
  • Среднее время прохождения CI пайплайна уменьшилось с 15 до 8 минут (благодаря возможности запускать тесты только для измененных модулей).
  • Количество регрессий снизилось на 45% (из-за лучшей изоляции и более качественных тестов).
  • Время на онбординг новых разработчиков сократилось вдвое (новичку легче понять ограниченную область модуля, чем всю систему).

Особенно впечатляющим был рост "реальной" скорости разработки. Если в традиционном монолите разработчики тратили около 60% времени на поддержку существующего кода и только 40% на новые функции, то в модульном монолите это соотношение изменилось до 40/60.

Организационные аспекты



Модульные монолиты хорошо соответствуют принципу "Conway's Law" — структура системы отражает коммуникационную структуру организации. Разделение на модули позволяет легко сопоставить их с командами или отдельными разработчиками.

В одной из компаний мы внедрили систему "владельцев модулей", где каждый ключевой модуль имел своего ответственного разработчика. Это значительно улучшило качество кода и снизило "эффект бесхозности", когда никто не чувствует ответственности за определенную часть системы. Конечно, модульный монолит — не серебряная пуля. Он требует дисциплины и четкого архитектурного видения. Без строгого соблюдения границ модулей легко скатиться обратно к традиционному монолиту. Я видел проекты, где через год после рефакторинга границы между модулями настолько размылись, что система снова превратилась в запутанный клубок зависимостей.

Ключ к успеху — использование технических ограничений (на уровне сборки или компиляции) для обеспечения модульности, а не только соглашений в команде. Например, в Java можно использовать JPMS (Java Platform Module System), в .NET — механизмы сборки для контроля зависимостей между проектами.

Реальные кейсы внедрения



Нажмите на изображение для увеличения
Название: Что после микросервисов - постмонолитная архитектура как новая реальность 6.jpg
Просмотров: 22
Размер:	227.5 Кб
ID:	11097

Теория хороша, но, как говорится, "гладко было на бумаге, да забыли про овраги". Давайте посмотрим на реальные примеры компаний, которые прошли путь от микросервисного хаоса к постмонолитной архитектуре. Я собрал несколько показательных кейсов из своей практики консультирования и общения с коллегами по цеху.

Кейс №1: Финтех-стартап GetPaid



GetPaid (название изменено) начинал как классический стартап – амбициозная команда из 5 разработчиков, построившая MVP на монолите. После привлечения инвестиций они решили "сделать все правильно" и перешли на микросервисную архитектуру. За год система разрослась до 35 микросервисов, обслуживаемых командой из 15 разработчиков. Проблемы начались, когда стартап вышел на стадию быстрого роста. Каждый новый пик нагрузки приводил к каскадным отказам, поиск источников проблем превратился в настоящий детектив, а инфраструктурные расходы росли экспоненциально.

Я присоединился к проекту в качестве консультанта, когда ситуация стала критической. Анализ показал, что большинство микросервисов были созданы по принципу "один экран – один сервис", без учета бизнес-доменов. В результате для обработки одной транзакции требовалось до 12 межсервисных вызовов!

Стратегия трансформации включала:

1. Картирование информационных потоков и выявление естественных доменов.
2. Консолидацию 35 микросервисов в 4 доменных сервиса: управление пользователями, платежное ядро, аналитика, интеграции.
3. Внедрение событийной шины для асинхронного взаимодействия между доменами.
4. Сохранение платформы Kubernetes, но с радикальным упрощением инфраструктуры.

Результаты превзошли ожидания:
  • Среднее время отклика API снизилось с 320 мс до 85 мс.
  • Инфраструктурные расходы сократились на 60%.
  • Время выхода новых функций на рынок уменьшилось с 3-4 недель до 1-2 недель.
  • Количество инцидентов снизилось на 78%.

Самое интересное, что после успешной трансформации CTO признался мне: "Мы внедрили микросервисы не потому, что они нам были нужны, а потому что это выглядело круто в глазах инвесторов. Никто из нас не представлял реальной сложности такой архитектуры".

Кейс №2: E-commerce платформа ShopFast



Этот случай особенно показателен. ShopFast начинал как монолит на Rails, но по мере роста нагрузки столкнулся с проблемами масштабирования. В 2018 году они перешли на микросервисную архитектуру, разбив систему на 25+ сервисов.
К 2022 году команда из 40 разработчиков тратила 60% своего времени на поддержку инфраструктуры и борьбу с "распределенными проблемами". Главный вызов – пиковые нагрузки в периоды распродаж, когда система демонстрировала непредсказуемое поведение. Решение пришло неожиданно. Новый CTO предложил радикально пересмотреть подход:

1. Выделить три ключевых доменных сервиса: каталог, корзина/заказы, управление клиентами
2. Оставить отдельными микросервисами только системы с уникальными требованиями: поиск (Elasticsearch), рекомендации, интеграции с платежными системами
3. Внедрить паттерн CQRS для оптимизации чтения и записи данных

Переход занял почти год, но результаты того стоили:

Пиковая пропускная способность выросла в 2.8 раза при тех же ресурсах,
Время простоя снизилось с 0.5% до 0.02%,
Команду DevOps сократили с 8 до 3 человек,
Удалось реализовать функцию "единой корзины" между мобильным приложением и веб-версией, которую откладывали 2 года из-за технической сложности.

Интересная деталь: ShopFast сохранил возможность независимого масштабирования компонентов, но на уровне модулей внутри доменных сервисов, используя возможности контейнеризации.

Кейс №3: Медиа-платформа ContentFlow



ContentFlow – пример того, как постмонолитный подход может быть внедрен "с нуля", а не только как миграция от микросервисов. Команда изначально планировала построить платформу на микросервисах, но после анализа опыта конкурентов решила пойти путем модульного монолита с выборочным выделением критичных компонентов.

Архитектура ContentFlow включала:
  1. Модульный монолит для основной бизнес-логики (управление контентом, пользователями, подписками).
  2. Отдельный сервис для обработки и доставки медиа (с особыми требованиями к масштабированию).
  3. Бессерверные функции для обработки асинхронных задач (транскодирование, аналитика).
  4. Событийную шину для асинхронного взаимодействия между компонентами.

Этот подход позволил им запустить MVP в течение 4 месяцев и быстро масштабироваться до миллиона пользователей без серьезных архитектурных изменений.

Анализ ошибок миграции



Наблюдая за несколькими десятками проектов перехода к постмонолитной архитектуре, я выделил типичные ошибки:

1. Попытка сделать всё сразу



Самая распространенная ошибка – стремление провести миграцию одним махом. В одной компании решили объединить 15 микросервисов за одну итерацию. Результат? Двухнедельный аврал и откат изменений после серии критических сбоев.
Лучший подход – постепенная, пошаговая миграция с возможностью отката на любом этапе.

2. Неправильное определение доменных границ



Многие команды просто механически объединяют близкие по функциональности сервисы, не проводя глубокого анализа информационных потоков и бизнес-доменов.
Я помню проект, где объединили сервисы управления пользователями и платежами, потому что "они часто взаимодействуют". Через три месяца этот "монстр" пришлось снова разделить, но уже по правильным доменным границам.

3. Игнорирование организационных аспектов



Архитектура системы и структура команд тесно связаны (закон Конвея). Я видел провальный проект, где объединили сервисы, но забыли объединить команды, которые их разрабатывали. В результате модули внутри монолита развивались так же независимо и несогласованно, как раньше микросервисы.

4. Отказ от преимуществ микросервисов



Некоторые компании, разочаровавшись в микросервисах, кидаются в другую крайность – полностью отказываются от их преимуществ. Например, сливают все в один деплоймент без возможности независимого масштабирования критичных компонентов.

Постмонолитный подход не означает отказ от всех идей микросервисной архитектуры – он означает их более прагматичное применение.

5. Недостаточное внимание к инструментам модульности



Без правильных инструментов и практик, обеспечивающих модульность, ваш модульный монолит быстро превратится в классический "большой ком грязи". В одном из проектов после успешной консолидации микросервисов не наладили контроль межмодульных зависимостей. Через полгода система представляла собой запутанный клубок связей между модулями, хуже, чем было до рефакторинга.

Мой опыт показывает, что технический успех миграции к постмонолитной архитектуре зависит от 20% технических решений и 80% организационных изменений и дисциплины команды. Сама по себе архитектура не решает проблем – она лишь создает условия для их решения.

Практическая реализация



Нажмите на изображение для увеличения
Название: Что после микросервисов - постмонолитная архитектура как новая реальность 7.jpg
Просмотров: 26
Размер:	218.1 Кб
ID:	11098

После разговоров о теории и анализа кейсов давайте наконец погрузимся в практические аспекты. Как на самом деле реализовать постмонолитную архитектуру в коде? Какие паттерны, инструменты и подходы использовать? Я поделюсь конкретными решениями, которые доказали свою эффективность в реальных проектах.

Архитектурные паттерны для постмонолитных систем



Основа постмонолитной архитектуры — четкое разделение на модули с хорошо определенными границами. Для этого я обычно использую комбинацию нескольких архитектурных паттернов.

Вертикальная (слоистая) модульная архитектура



Вместо классического горизонтального разделения на слои (контроллеры, сервисы, репозитории), постмонолитная архитектура предполагает вертикальное разделение на функциональные модули, каждый из которых содержит собственные слои.
Например, для Java-приложения структура может выглядеть так:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/src
  /main
    /java
      /com
        /mycompany
          /app
            /module-a       # Модуль A
              /api          # Публичный API модуля
              /internal     # Внутренняя реализация
                /domain     # Доменная модель
                /service    # Бизнес-логика
                /repository # Доступ к данным
            /module-b       # Модуль B
              /api
              /internal
                /domain
                /service
                /repository
            /shared         # Общие компоненты
              /infrastructure
              /utils
Для обеспечения модульности на уровне кода я использую следующие техники:

1. Пакетный принцип: публичные API модуля размещаются в пакете api, все остальное скрыто в internal.
1. Явные зависимости: модули взаимодействуют только через публичные API.
1. Инверсия зависимостей: внутренние компоненты модуля зависят от абстракций, а не от конкретных реализаций.

Вот пример организации зависимостей между модулями:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// В module-a/api
public interface CustomerService {
    Customer getCustomer(String customerId);
    void updateCustomer(Customer customer);
}
 
// В module-b/internal/service
@Service
public class OrderProcessor {
    private final CustomerService customerService;
    
    public OrderProcessor(CustomerService customerService) {
        this.customerService = customerService;
    }
    
    public void processOrder(Order order) {
        Customer customer = customerService.getCustomer(order.getCustomerId());
        // Обработка заказа
    }
}
Обратите внимание: OrderProcessor зависит только от интерфейса CustomerService, а не от его конкретной реализации. Это позволяет легко заменить реализацию, например, для тестирования.

Hexagonal Architecture (Ports and Adapters)



Для организации внутренней структуры модулей я часто применяю гексагональную архитектуру (также известную как Ports and Adapters). Этот паттерн помогает четко отделить бизнес-логику от инфраструктурных деталей.

В центре находится доменная модель и бизнес-логика. Вокруг неё — "порты" (интерфейсы), через которые происходит взаимодействие с внешним миром. Реализации этих интерфейсов — "адаптеры" — могут быть легко заменены.

Например, для модуля обработки заказов:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// Порт (первичный)
public interface OrderService {
    OrderId placeOrder(Cart cart, CustomerId customerId);
    Order getOrder(OrderId orderId);
}
 
// Бизнес-логика
@Service
public class OrderServiceImpl implements OrderService {
    private final OrderRepository orderRepository; // Вторичный порт
    private final PaymentGateway paymentGateway;   // Вторичный порт
    
    // Конструктор с DI
    
    @Override
    public OrderId placeOrder(Cart cart, CustomerId customerId) {
        // Бизнес-логика создания заказа
        Order order = Order.create(cart, customerId);
        orderRepository.save(order);
        paymentGateway.processPayment(order);
        return order.getId();
    }
    
    @Override
    public Order getOrder(OrderId orderId) {
        return orderRepository.findById(orderId)
            .orElseThrow(() -> new OrderNotFoundException(orderId));
    }
}
 
// Вторичный порт
public interface OrderRepository {
    void save(Order order);
    Optional<Order> findById(OrderId orderId);
}
 
// Адаптер для вторичного порта
@Repository
public class JpaOrderRepository implements OrderRepository {
    private final OrderJpaRepository jpaRepository;
    
    // Реализация с использованием JPA
}
Этот подход дает несколько преимуществ:

Бизнес-логика не зависит от деталей инфраструктуры
Легко заменить реализации портов без изменения бизнес-логики
Упрощается тестирование благодаря возможности использования моков

Clean Architecture



Альтернативный подход, который я часто использую — Clean Architecture, популяризированная Робертом Мартином (Uncle Bob). Она имеет много общего с гексагональной архитектурой, но с более четким разделением на слои:

1. Entities (Сущности) — бизнес-объекты и правила, не зависящие от приложения
1. Use Cases (Сценарии использования) — правила уровня приложения
1. Interface Adapters (Адаптеры интерфейса) — преобразование данных между слоями
1. Frameworks & Drivers (Фреймворки и драйверы) — внешние инструменты и фреймворки

Важный принцип: зависимости направлены внутрь, к центру архитектуры. Внутренние слои не должны знать о внешних.

Организация слоев абстракции и Dependency Injection



Ключевой аспект постмонолитной архитектуры — правильная организация зависимостей между модулями. Dependency Injection играет здесь критическую роль. В Java-мире я обычно использую Spring для этой цели. Каждый модуль определяет свои сервисы как Spring-компоненты, но экспортирует только интерфейсы для использования другими модулями.

Вот пример модульной конфигурации:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Конфигурация модуля A
@Configuration
@ComponentScan("com.mycompany.app.module-a.internal")
public class ModuleAConfiguration {
    @Bean
    public CustomerService customerService(
            CustomerRepository repository, 
            EventPublisher eventPublisher) {
        return new CustomerServiceImpl(repository, eventPublisher);
    }
}
 
// Конфигурация модуля B, использующего сервис из модуля A
@Configuration
@ComponentScan("com.mycompany.app.module-b.internal")
@Import(ModuleAConfiguration.class) // Импорт конфигурации модуля A
public class ModuleBConfiguration {
    @Bean
    public OrderProcessor orderProcessor(CustomerService customerService) {
        return new OrderProcessorImpl(customerService);
    }
}
Для обеспечения строгого разделения модулей можно использовать дополнительные инструменты:

1. ArchUnit — библиотека для проверки архитектурных ограничений в юнит-тестах:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void moduleBShouldOnlyDependOnModuleAPublicApi() {
    JavaClasses classes = new ClassFileImporter()
        .importPackages("com.mycompany.app");
    
    ArchRule rule = classes()
        .that().resideInAPackage("com.mycompany.app.module-b..")
        .should().onlyDependOnClassesThat()
        .resideInAnyPackage(
            "com.mycompany.app.module-b..",
            "com.mycompany.app.module-a.api..",
            "com.mycompany.app.shared..",
            "java.."
        );
    
    rule.check(classes);
}
1. Java Module System (JPMS) — для строгого контроля зависимостей на уровне компиляции через файлы module-info.java:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// В модуле A
module com.mycompany.app.module.a {
    exports com.mycompany.app.module.a.api;
    
    requires spring.context;
    requires com.mycompany.app.shared;
}
 
// В модуле B
module com.mycompany.app.module.b {
    exports com.mycompany.app.module.b.api;
    
    requires com.mycompany.app.module.a;
    requires spring.context;
    requires com.mycompany.app.shared;
}

Domain-Driven Design в постмонолитной архитектуре



Domain-Driven Design (DDD) и постмонолитная архитектура — идеальная пара. DDD предоставляет концептуальные инструменты для определения границ модулей на основе бизнес-доменов.
Ключевые концепции DDD, которые я применяю в постмонолитной архитектуре:

Bounded Contexts (Ограниченные контексты)



Каждый модуль в постмонолитной архитектуре обычно соответствует одному Bounded Context — части домена с собственной моделью и языком. Внутри контекста термины имеют четкое и согласованное значение. Например, понятие "Клиент" может иметь разное значение в разных контекстах:
  • В контексте CRM: клиент как физическое или юридическое лицо с контактной информацией.
  • В контексте заказов: клиент как получатель товаров с адресом доставки.
  • В контексте биллинга: клиент как плательщик с платежными реквизитами.

Вместо попыток создать универсальную модель "Клиента" DDD предлагает создать отдельные модели для каждого контекста.
Помню, как в одном из проектов мы пытались создать "единую модель клиента", пока не поняли, что это тупиковый путь. После разделения на контексты с отдельными моделями система стала намного понятнее и проще в разработке.

Ubiquitous Language (Единый язык)



Для каждого Bounded Context мы разрабатываем свой "единый язык" — набор терминов, используемых как разработчиками, так и бизнес-экспертами. Эти термины напрямую отражаются в коде.

Например, в модуле обработки заказов:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Доменная модель, отражающая бизнес-термины
public class Order {
    private OrderId id;
    private CustomerId customerId;
    private List<OrderLine> lines;
    private OrderStatus status;
    private DeliveryAddress deliveryAddress;
    private Money totalAmount;
    
    // Доменные методы
    public void addProduct(ProductId productId, Quantity quantity, Money unitPrice) {
        OrderLine line = new OrderLine(productId, quantity, unitPrice);
        lines.add(line);
        recalculateTotal();
    }
    
    public void confirm() {
        if (status != OrderStatus.DRAFT) {
            throw new InvalidOrderStateException(id, status, "confirm");
        }
        status = OrderStatus.CONFIRMED;
    }
    
    // Другие методы
}
Заметьте, как названия классов, методов и переменных отражают термины, используемые в бизнесе. Это не просто стиль кодирования — это прямое отражение единого языка домена.

Агрегаты и границы транзакций



В DDD агрегат — это кластер объектов, которые трактуются как единое целое с точки зрения изменений данных. Один из объектов является корнем агрегата и обеспечивает внешний доступ к другим объектам внутри агрегата.

В постмонолитной архитектуре агрегаты часто совпадают с границами транзакций, что значительно упрощает обеспечение согласованности данных по сравнению с микросервисной архитектурой.
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Entity
@Table(name = "orders")
public class Order {
    @Id
    private String id;
    
    private String customerId;
    private String status;
    
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "order_id")
    private List<OrderLine> lines = new ArrayList<>();
    
    @Embedded
    private DeliveryAddress deliveryAddress;
    
    // ...
}
 
@Entity
@Table(name = "order_lines")
public class OrderLine {
    @Id
    private String id;
    
    private String productId;
    private int quantity;
    private BigDecimal unitPrice;
    
    // ...
}
В этом примере Order является корнем агрегата, а OrderLine — частью агрегата. Внешний код взаимодействует только с Order, никогда напрямую с OrderLine.

Event Sourcing и CQRS в постмонолитной архитектуре



Event Sourcing и CQRS (Command Query Responsibility Segregation) — мощные паттерны, которые отлично работают в постмонолитной архитектуре.

Event Sourcing



В Event Sourcing вместо хранения текущего состояния мы сохраняем последовательность событий, которые привели к этому состоянию. Это даёт полную историю изменений и возможность "перемотать" систему в любое прошлое состояние.
В контексте постмонолитной архитектуры Event Sourcing особенно полезен для:
  • Обеспечения аудита и отслеживания истории изменений.
  • Интеграции между модулями через события.
  • Воссоздания специализированных представлений данных.

Вот пример реализации для модуля заказов:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Событие — что-то произошло в прошлом
public interface DomainEvent {
    String getAggregateId();
    Instant getTimestamp();
}
 
public class OrderCreatedEvent implements DomainEvent {
    private final String orderId;
    private final String customerId;
    private final Instant timestamp;
    
    // Геттеры, конструктор
    
    @Override
    public String getAggregateId() {
        return orderId;
    }
    
    @Override
    public Instant getTimestamp() {
        return timestamp;
    }
}
 
// Другие события: OrderItemAddedEvent, OrderConfirmedEvent и т.д.
 
// Агрегат, поддерживающий Event Sourcing
public class OrderAggregate {
    private String id;
    private String customerId;
    private List<OrderItem> items = new ArrayList<>();
    private String status;
    
    private List<DomainEvent> uncommittedEvents = new ArrayList<>();
    
    // Конструктор для создания нового заказа
    public static OrderAggregate create(String orderId, String customerId) {
        OrderAggregate order = new OrderAggregate();
        order.applyNewEvent(new OrderCreatedEvent(orderId, customerId, Instant.now()));
        return order;
    }
    
    // Добавление товара в заказ
    public void addItem(String productId, int quantity, BigDecimal price) {
        applyNewEvent(new OrderItemAddedEvent(id, productId, quantity, price, Instant.now()));
    }
    
    // Применение нового события
    private void applyNewEvent(DomainEvent event) {
        uncommittedEvents.add(event);
        apply(event);
    }
    
    // Применение события к состоянию
    private void apply(DomainEvent event) {
        if (event instanceof OrderCreatedEvent) {
            apply((OrderCreatedEvent) event);
        } else if (event instanceof OrderItemAddedEvent) {
            apply((OrderItemAddedEvent) event);
        }
        // Другие типы событий
    }
    
    private void apply(OrderCreatedEvent event) {
        this.id = event.getAggregateId();
        this.customerId = event.getCustomerId();
        this.status = "DRAFT";
    }
    
    private void apply(OrderItemAddedEvent event) {
        OrderItem item = new OrderItem(
            event.getProductId(), 
            event.getQuantity(), 
            event.getPrice()
        );
        this.items.add(item);
    }
    
    // Получение и очистка несохраненных событий
    public List<DomainEvent> getUncommittedEvents() {
        return new ArrayList<>(uncommittedEvents);
    }
    
    public void clearUncommittedEvents() {
        uncommittedEvents.clear();
    }
    
    // Восстановление агрегата из истории событий
    public static OrderAggregate recreate(List<DomainEvent> events) {
        OrderAggregate order = new OrderAggregate();
        events.forEach(order::apply);
        return order;
    }
}

CQRS (Command Query Responsibility Segregation)



CQRS разделяет операции чтения (Query) и записи (Command) на отдельные модели. Это позволяет оптимизировать каждую модель для своей задачи: модель команд — для обеспечения бизнес-правил, модель запросов — для производительного чтения. В постмонолитной архитектуре CQRS можно реализовать как в рамках одного модуля, так и между модулями:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Модель команд (для записи)
public class OrderCommandService {
    private final EventStore eventStore;
    private final EventBus eventBus;
    
    public void createOrder(CreateOrderCommand command) {
        // Проверка бизнес-правил
        OrderAggregate order = OrderAggregate.create(
            UUID.randomUUID().toString(), 
            command.getCustomerId()
        );
        
        // Сохранение событий
        List<DomainEvent> events = order.getUncommittedEvents();
        eventStore.save(events);
        order.clearUncommittedEvents();
        
        // Публикация событий для обновления представлений
        events.forEach(eventBus::publish);
    }
    
    // Другие команды
}
 
// Модель запросов (для чтения)
public class OrderQueryService {
    private final JdbcTemplate jdbcTemplate;
    
    public OrderDTO getOrder(String orderId) {
        return jdbcTemplate.queryForObject(
            "SELECT o.id, o.customer_id, o.status, o.created_at " +
            "FROM order_view o WHERE o.id = ?",
            new Object[]{orderId},
            (rs, rowNum) -> new OrderDTO(
                rs.getString("id"),
                rs.getString("customer_id"),
                rs.getString("status"),
                rs.getTimestamp("created_at").toInstant()
            )
        );
    }
    
    // Другие запросы
}

Заключение с прогнозами развития подхода и рекомендациями по внедрению



Нажмите на изображение для увеличения
Название: Что после микросервисов - постмонолитная архитектура как новая реальность 8.jpg
Просмотров: 27
Размер:	226.7 Кб
ID:	11099

Вот мы и подошли к концу нашего путешествия по миру постмонолитной архитектуры. Что же ждет нас дальше? Как будет развиваться этот подход в ближайшие годы? И главное — как внедрить его в своих проектах без болезненных ошибок?

Куда движется постмонолитная архитектура?



Исходя из того, что я вижу в индустрии, а также на основе собственного опыта с десятками проектов, могу предложить несколько прогнозов на ближайшие 3-5 лет:

1. Инструментальная поддержка усилится



Если сейчас модульный монолит часто строится на основе соглашений и самодисциплины команды, то в ближайшем будущем появится больше инструментов, обеспечивающих строгое разделение модулей на уровне компиляции и сборки.

Уже сейчас видны зачатки этого тренда: Java Module System (JPMS), ArchUnit, модульные возможности Gradle и Maven. В ближайшие годы ожидаю появления специализированных фреймворков, оптимизированных для модульной разработки, с встроенными механизмами контроля границ.

2. Унификация паттернов межмодульного взаимодействия



Сейчас существует множество подходов к организации взаимодействия между модулями: через API, события, общую шину. В будущем выкристаллизуются наиболее эффективные паттерны, которые станут де-факто стандартами индустрии.

Я ожидаю, что событийно-ориентированное взаимодействие между модулями станет доминирующим, поскольку оно обеспечивает лучшую изоляцию и устойчивость к ошибкам.

3. Гибридизация с облачными технологиями



Постмонолитная архитектура будет всё теснее интегрироваться с облачными платформами. Возникнет новый класс решений, сочетающих внутреннюю модульность с возможностью селективного масштабирования критичных компонентов в облаке.

Представьте себе фреймворк, где вы просто помечаете модуль аннотацией @Scalable, и платформа автоматически развертывает его как отдельный сервис при необходимости, сохраняя прямую интеграцию для разработки.

4. Интеграция с ИИ-подходами



Искусственный интеллект начнет играть роль в определении оптимальных границ модулей и выявлении скрытых зависимостей. Появятся инструменты, анализирующие кодовую базу и предлагающие оптимальное разделение на модули на основе семантического анализа и паттернов использования.

Практические рекомендации по внедрению



Если вы решили внедрить постмонолитную архитектуру, вот мои рекомендации, основанные на опыте как успешных, так и провальных проектов:

1. Начинайте с ясной доменной модели



Самая частая ошибка — деление на модули по техническим, а не бизнес-границам. Прежде чем писать код, проведите несколько сессий по моделированию домена с участием как разработчиков, так и представителей бизнеса. Используйте методики Event Storming или Domain Storytelling для выявления естественных границ в вашем домене. Только после этого приступайте к проектированию модулей.

Помню случай, когда команда потратила месяц на рефакторинг, а потом пришлось всё переделывать, потому что изначальное разделение на модули не соответствовало реальным бизнес-процессам. Час, потраченный на правильное моделирование домена, может сэкономить недели переделок.

2. Внедряйте инструменты контроля границ с самого начала



Не полагайтесь только на соглашения и документацию. Используйте автоматизированные средства контроля:
  1. Статический анализ зависимостей (ArchUnit, SonarQube с кастомными правилами),
  2. Модульные системы языка программирования (Java Modules, .NET Assemblies),
  3. CI-проверки, блокирующие нарушения модульных границ
На одном из проектов мы внедрили автоматические тесты на архитектурные ограничения с первого дня. Год спустя, когда команда выросла втрое, мы избежали хаоса именно благодаря этому решению.

3. Используйте эволюционный подход



Не пытайтесь сразу построить идеальную архитектуру. Начните с минимального разделения на 2-3 ключевых модуля и развивайте её по мере роста понимания домена. Как-то раз я наблюдал, как команда архитекторов потратила три месяца на проектирование "идеальной" модульной структуры с 15 модулями. К моменту запуска проекта требования изменились настолько, что половину модулей пришлось переделывать. Если бы они начали с базовой структуры и развивали её итеративно, результат был бы гораздо лучше.

4. Инвестируйте в обучение команды



Модульное мышление — это навык, который нужно развивать. Проводите регулярные обучающие сессии, код-ревью с фокусом на модульность, парное программирование.
Особенно полезны воркшопы, где команда совместно решает, как реализовать сквозную функциональность без нарушения модульных границ.

5. Адаптируйте процессы разработки



Постмонолитная архитектура требует изменений не только в коде, но и в процессах:
  • Выстраивайте команды вокруг модулей, а не функциональности
  • Внедряйте практики коллективного владения кодом внутри модуля
  • Адаптируйте CI/CD для быстрой обратной связи при нарушении модульности
На личном опыте убедился, что технические изменения без соответствующих организационных изменений редко бывают успешными. В одном из проектов мы прекрасно спроектировали модульную архитектуру, но забыли перестроить команды — в результате границы модулей постоянно нарушались, и система постепенно деградировала в "монолит из мультимонолита".

Вместо послесловия



Постмонолитная архитектура — это не возврат к прошлому, а шаг вперед, учитывающий уроки как монолитов, так и микросервисов. Это признание того, что в архитектуре, как и во всем, крайности редко бывают оптимальными.

Самое важное — помнить, что архитектура должна служить бизнесу, а не наоборот. Не существует идеального подхода для всех ситуаций. Выбирайте и адаптируйте инструменты, исходя из реальных потребностей вашего проекта, команды и организации.

Как деплоить решение, состоящее из 100500 микросервисов (+docker)
уточню - нужен совет от более опытных индейцев допустим, есть некое решение, состоящее из более...

архитектура процессоров и компьютерная архитектура,Intel32. для первокурсников
сабж. кто чем может помочь юному,непонемающему в этой области человеку.желательно книгами.спасибо.

Ошибка "в указанном dsn архитектура драйвера и архитектура приложения"
Вот такая ошибка при нажатии на кнопку &quot;Проверить соединение&quot; Я прочитал, что это возможно из за...

В указанном dsn архитектура драйвера и архитектура приложения не соответствуют друг другу
Добрый день. При запуске программы выскакивает вот такая вот ошибка. В чем может быть проблема и...

Java - генератор микросервисов
День добрый, на работе поступил заказ: сваять на ява генератор микросервисов. Шаблонный...

Общение микросервисов
Добрый день, поясните плииииз &quot;на пальцах&quot;. Что гуглить??? Есть мини-сервер. Пока работает...

Общение микросервисов
Добрый день, подскажите плииииз Ищу надежные КОМПОНЕНТЫ! или &quot;чистый код&quot;/методики для...

Grpc один netty на несколько микросервисов
У себя в коде я создаю netty на определенный порт и регистрирую сервис: Server server =...

Gateway для микросервисов
Микросрвисная архитектура и для общения сервисов есть единая точная входа - gateway, который...

Подключение микросервисов через Ocelot
Доброе время суток! Есть проект, где расположены несколько микросервисов, которые должны...

Java REST клиент для микросервисов
Всем доброго дня! Изучаю логику работы микросервисов, в частности обмен сообщениями между ними....

Примеры построения двух микросервисов с использованием Spring Security и Vaadin
Всем привет! Имеются два проекта - бэкенд и фронтенд. Бэк написан с использованием Spring Boot...

Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru