Microservices vs Monolith: спектр архитектур
Зачем знать: “Microservices vs monolith” — главный архитектурный холивар 2010-2020. К 2026 году рынок остыл: ясно, что между монолитом и микросервисами есть весь спектр (modular monolith, distributed monolith — anti-pattern, miniservices, microservices, nanoservices). Middle Go-разработчик должен уметь оценить: моноолит правильное решение для стартапа из 10 человек, или нужно дробить уже? Когда modular monolith лучше? Что такое distributed monolith и почему он хуже обоих?
Содержание
Заголовок раздела «Содержание»- Концепция: спектр архитектур
- Глубже: modular monolith, Strangler Fig, anti-patterns
- Gotchas
- Real cases
- Вопросы (20)
- Practice
- Источники
1. Концепция
Заголовок раздела «1. Концепция»1.1 Спектр архитектур
Заголовок раздела «1.1 Спектр архитектур»Архитектура — это не binary choice “монолит или микросервисы”. Это спектр:
Monolith → Modular Monolith → Miniservices → Microservices → Nanoservices ↓ ↓ ↓ ↓single deploy single deploy несколько серв. много серв. too small ↑ anti-pattern Distributed Monolith (anti-pattern): много сервисов, но deploy together1.2 Monolith
Заголовок раздела «1.2 Monolith»Один процесс, одна codebase, один deploy.
[Single binary / process] ├── handlers/ ├── services/ ├── repositories/ └── domain modelsPros:
- Простота: один git repo, один CI/CD pipeline, один runtime.
- Atomicity: транзакции через БД, нет distributed problems.
- Refactoring: легко двигать код между модулями.
- Debugging: один процесс, один stack trace.
- Performance: in-process calls вместо network.
Cons:
- Scaling: масштабируется только вертикально, либо весь монолит горизонтально (даже если узкое место — один module).
- Tech stack: один язык, одна runtime.
- Deploy: каждое изменение требует deploy всего.
- Team coordination: 50+ инженеров на одной codebase — merge conflicts, longer reviews.
- Blast radius: bug в одном модуле — падает всё.
Когда монолит ок:
- Стартап, MVP, прототип.
- Команда < 10 человек.
- Domain ещё не понят (microservices boundaries неясны).
- Performance critical (low-latency in-process calls).
Антипример мнения: “Микросервисы — best practice.” Нет. DHH (Basecamp, Hey.com) ушёл от микросервисов обратно к монолиту в 2022. Shopify публично использует “majestic monolith”. Stack Overflow обслуживает 6B запросов в месяц на small fleet of monolithic servers.
1.3 Modular Monolith
Заголовок раздела «1.3 Modular Monolith»Один процесс, но строгие модули с явными границами.
[Single binary] ├── modules/ │ ├── payment/ │ │ ├── api/ (public interface) │ │ ├── internal/ (private logic) │ │ └── models/ │ ├── order/ │ └── customer/ └── main.goМежду модулями — internal API (Go interfaces), не direct access к internals.
Pros монолита, плюс:
- Чёткие boundaries — легче понять, поменять.
- Independent development по модулям.
- Migration path к microservices: модуль уже изолирован, его можно вытащить.
- Single deploy (простота).
- Atomic refactoring across modules.
Cons:
- Требует дисциплины (Go-linter проверяет imports между модулями).
- Один runtime, один tech stack.
- Скорость deploy зависит от общего CI/CD.
Реализация в Go:
- Use internal package (
payment/internal/) — Go enforces visibility. - One main, multiple sub-packages.
- Tools:
go-cleanarch,arch-goдля проверки правил.
1.4 Microservices
Заголовок раздела «1.4 Microservices»Несколько процессов, каждый — независимый сервис.
[Order Service] ←→ [Payment Service] ←→ [Notification Service] Go, Go, Python Postgres Postgres+Redis RabbitMQPros:
- Independent scaling.
- Independent deploy.
- Tech stack per service.
- Team ownership (Conway’s law).
- Fault isolation (один сервис не валит другие, при правильных resilience patterns).
Cons:
- Distributed complexity: network failures, latency, consistency.
- Operations: K8s, service mesh, observability stack.
- Debugging: trace через 5 hops через 5 сервисов.
- Eventual consistency.
- Schema evolution через несколько сервисов.
1.5 Conway’s Law
Заголовок раздела «1.5 Conway’s Law»“Any organization that designs a system… will produce a design whose structure is a copy of the organization’s communication structure.” — Melvin Conway, 1967.
Применение: структура сервисов отражает структуру команд. Если команды раздроблены — микросервисы естественны. Если команда одна — монолит.
Inverse Conway Maneuver: организуй команды так, как хочешь, чтобы выглядела архитектура.
1.6 Когда microservices оправданы
Заголовок раздела «1.6 Когда microservices оправданы»- Multiple teams (>3 команды по 5-10 человек).
- Different scaling needs: search service нужен 100 instances, payment — 5.
- Different tech stacks: ML на Python, real-time на Go, batch на Spark.
- Independent release cycles: разные команды деплоят разное.
- Different SLAs: payment 99.99%, analytics 99%.
- Compliance isolation: PCI-DSS только для billing service.
1.7 Costs of microservices
Заголовок раздела «1.7 Costs of microservices»Hidden costs:
- Network latency: in-process call ~ns, gRPC ~1ms. 10 hops = 10ms minimum.
- Network reliability: TCP не идеален, ретраи нужны везде.
- Distributed transactions: Saga, outbox, eventual consistency. Сложно.
- Service discovery: Consul, etcd, Kubernetes Service.
- Observability: distributed tracing (Jaeger, Tempo), aggregated logs (Loki, ELK), metrics (Prometheus).
- DevOps cost: K8s expertise, CI/CD per service, service mesh.
- Data consistency: eventual, conflicts, reconciliation.
- Schema evolution: versioning, backwards compat между сервисами.
- Testing: unit + integration + contract + E2E.
Estimated cost: 30-50% engineering overhead для same business functionality.
1.8 Strangler Fig pattern (Martin Fowler)
Заголовок раздела «1.8 Strangler Fig pattern (Martin Fowler)»Migration legacy → new (часто monolith → microservices).
Идея от banyan tree: новое растение обрастает старое, постепенно его душит. В коде:
[Old Monolith] ↑[Proxy/Facade] ←─── route some endpoints to new ↑[New Microservice]Шаги:
- Поставить proxy перед monolith.
- Извлечь endpoint X в новый микросервис.
- Proxy роутит X → new, остальное → monolith.
- Повторить для других endpoints.
- Monolith постепенно усыхает.
Преимущества:
- Incremental, не big bang rewrite.
- Old + new работают параллельно.
- Можно откатить, если new фейлится.
Pitfalls:
- Долго (годы).
- Двойная поддержка во время.
- Shared database — proxy не помогает.
1.9 Anti-pattern: Distributed Monolith
Заголовок раздела «1.9 Anti-pattern: Distributed Monolith»Симптомы:
- Много сервисов, но deploy together (нельзя один без других).
- Tight coupling: A синхронно вызывает B вызывает C → если C упал, A падает.
- Shared database между сервисами.
- Changes требуют координации между командами на каждый release.
Это хуже монолита: сложность распределённой системы без её преимуществ.
Признаки:
- “Сегодня выкатываем feature X — нужно координировать 5 команд.”
- “Не можем запустить локально без всех 12 сервисов.”
- “Изменение API в одном сервисе ломает 5 других.”
Решение:
- Async messaging вместо sync calls (где возможно).
- Database per service.
- Versioned APIs.
- Service contracts (Pact, consumer-driven contracts).
1.10 Anti-pattern: Nanoservices
Заголовок раздела «1.10 Anti-pattern: Nanoservices»Микросервисы слишком мелкие. “Каждая функция — отдельный сервис.”
Признаки:
- Сервис делает одно простое CRUD на одну таблицу.
- Больше сервисов чем разработчиков.
- Inter-service calls для каждой бизнес-операции.
Проблемы:
- Network overhead доминирует над работой.
- Координация для любого изменения.
- Observability ад: тысячи нод в трейсе.
Правило большого пальца (Kelsey Hightower): “Microservice should be small enough that 2 engineers can own it, but not so small that it’s a function.”
1.11 Размер сервиса
Заголовок раздела «1.11 Размер сервиса»Эмпирические правила:
- “Two-pizza team”: команда, которая помещается за двумя пиццами (~6-10 человек). Каждая команда владеет одним сервисом (Amazon).
- “Two-week rewrite”: сервис достаточно мал, что можно переписать за 2 недели.
- “Bounded context” (DDD): один сервис = один bounded context.
1.12 Communication patterns
Заголовок раздела «1.12 Communication patterns»Sync (request-reply):
- HTTP REST, gRPC.
- Простой, но caller блокируется.
- Используй для: query (read), critical commands где нужен ответ.
Async (events):
- Kafka, RabbitMQ, NATS.
- Слабая связь, fault-tolerant.
- Используй для: notifications, eventual workflows, fan-out.
Правило: sync для query, async для command (events).
Bad: [Order Service] --sync POST→ [Inventory] --sync POST→ [Shipping]Good: [Order Service] → publishes OrderCreated event [Inventory] subscribes, reserves [Shipping] subscribes, schedulesВ sync chain если один упал — все падают. В async chain каждый работает независимо.
2. Глубже
Заголовок раздела «2. Глубже»2.1 Modular Monolith в Go: структура
Заголовок раздела «2.1 Modular Monolith в Go: структура»project/├── cmd/│ └── app/│ └── main.go├── internal/│ ├── modules/│ │ ├── payment/│ │ │ ├── api/ # public interface (interfaces, DTOs)│ │ │ │ └── api.go│ │ │ ├── internal/ # private (Go enforces visibility)│ │ │ │ ├── service.go│ │ │ │ └── repository.go│ │ │ └── module.go # wire dependencies│ │ ├── order/│ │ └── customer/│ ├── platform/ # shared infrastructure│ │ ├── db/│ │ ├── logger/│ │ └── auth/│ └── app/ # composition root│ └── app.go└── pkg/ # public для external use (rare)Правила:
- Module A может импортировать только
modules/B/api/, неmodules/B/internal/. - Go enforce’ит через
internal/package. internal/modules/payment/internal/доступно только изinternal/modules/payment/....
API между модулями:
package paymentapi
type Service interface { Charge(ctx context.Context, userID string, amount int64) (TransactionID, error) GetTransaction(ctx context.Context, txID TransactionID) (*Transaction, error)}
// internal/modules/order/internal/service.gopackage order
import paymentapi "myapp/internal/modules/payment/api"
type OrderService struct { payment paymentapi.Service}
func (s *OrderService) PlaceOrder(...) { s.payment.Charge(ctx, userID, amount)}При миграции к microservices: реализация paymentapi.Service меняется с in-process на gRPC client. Контракт остаётся.
2.2 Microservices в Go: типичная структура
Заголовок раздела «2.2 Microservices в Go: типичная структура»payment-service/├── cmd/│ └── server/│ └── main.go├── internal/│ ├── domain/ # сущности, value objects│ ├── application/ # use cases│ ├── infrastructure/│ │ ├── repository/ # PostgreSQL impl│ │ ├── messaging/ # Kafka producer/consumer│ │ └── client/ # gRPC clients для других сервисов│ ├── api/│ │ ├── grpc/│ │ └── http/│ └── config/├── proto/ # gRPC contracts├── migrations/ # SQL migrations├── Dockerfile├── go.mod└── deploy/ └── kubernetes/2.3 Database per service
Заголовок раздела «2.3 Database per service»Принцип: каждый микросервис владеет своей БД. Никакие другие сервисы не имеют direct DB access.
Pros:
- Schema evolution без координации.
- Right tool for the job (Order — Postgres, Search — Elastic, Cache — Redis).
- Failure isolation.
Cons:
- Joins через сервисы (через API/events).
- Distributed transactions сложны.
- Data duplication (одни данные хранятся в нескольких сервисах).
Anti-pattern: “Shared DB между сервисами.” Это создаёт coupling сильнее, чем у monolith — изменение схемы ломает несколько сервисов.
2.4 Inter-service communication
Заголовок раздела «2.4 Inter-service communication»Sync через gRPC:
service PaymentService { rpc Charge(ChargeRequest) returns (ChargeResponse); rpc GetTransaction(GetTransactionRequest) returns (GetTransactionResponse);}conn, _ := grpc.Dial("payment-service:9090", grpc.WithTransportCredentials(insecure.NewCredentials()))client := pb.NewPaymentServiceClient(conn)resp, err := client.Charge(ctx, &pb.ChargeRequest{UserId: "u1", Amount: 100})Async через Kafka:
// Producer (Order Service)producer.Send(ctx, &kafka.Message{ Topic: "order-events", Key: []byte(orderID), Value: encode(OrderCreatedEvent{...}),})
// Consumer (Inventory Service)for msg := range consumer.Messages() { event := decode(msg.Value) handleOrderCreated(event) consumer.MarkMessage(msg, "")}2.5 Saga pattern для distributed transactions
Заголовок раздела «2.5 Saga pattern для distributed transactions»См. отдельную тему. Кратко: chain of compensating actions.
2.6 Service granularity decision
Заголовок раздела «2.6 Service granularity decision»Когда выделить новый сервис?
- Different scaling needs: один компонент требует разной capacity.
- Different team ownership: два team фокусируются на разном.
- Different SLA: один критичен, другой нет.
- Different tech stack: ML нужен Python, real-time нужен Go.
- Different change frequency: один меняется каждый день, другой — раз в квартал.
- Different compliance: PCI/HIPAA для одного, нет для другого.
Если ни одного из этих — не дроби. Cohesive features вместе.
2.7 Inverse Conway Maneuver
Заголовок раздела «2.7 Inverse Conway Maneuver»Шаги:
- Спроектируй желаемую архитектуру.
- Реструктурируй команды так, чтобы они владели сервисами 1:1.
- Архитектура естественно эволюционирует в нужное.
Пример:
- Хотим payment, order, inventory как отдельные сервисы.
- Создаём 3 команды: Payment Team, Order Team, Inventory Team.
- Каждая команда деплоит свой сервис, владеет API.
- Конвэйс заработал на тебя.
2.8 Migration patterns
Заголовок раздела «2.8 Migration patterns»Pattern 1: Strangler Fig (см. выше).
Pattern 2: Branch by Abstraction:
- Внутри monolith создай abstraction layer над данными.
- Реализация может быть локальной или удалённой.
- Переключай feature flag для миграции.
Pattern 3: Parallel Run:
- Запусти новый сервис параллельно со старым.
- Дублируй запросы в оба.
- Сравнивай ответы.
- Когда уверен — переключи.
Pattern 4: Database Migration:
- Изначально shared DB.
- Сервис читает/пишет в shared DB.
- Параллельно создаём private DB и реплицируем.
- Переключаем чтение на private DB.
- Прекращаем запись в shared DB.
2.9 Polyglot persistence
Заголовок раздела «2.9 Polyglot persistence»В микросервисной архитектуре нормально иметь:
- Order service — PostgreSQL.
- Cart service — Redis (TTL автоматически).
- Search — Elasticsearch.
- Analytics — ClickHouse.
- Files — S3.
Каждый сервис выбирает оптимальное хранилище.
В monolith это сложнее: один процесс должен работать с несколькими БД, scaling сложен.
2.10 Service mesh для микросервисов
Заголовок раздела «2.10 Service mesh для микросервисов»См. файл 23 (API Gateway / Service Mesh). Кратко: Istio/Linkerd добавляют mTLS, observability, traffic management без изменения кода сервисов.
3. Gotchas
Заголовок раздела «3. Gotchas»⚠️ “Микросервисы — best practice.” Нет. Контекст важен. Большинство стартапов должно начинать с монолита.
⚠️ Преждевременное дробление. Если boundaries не понятны, дробление создаёт frozen boundaries — менять их потом дорого.
⚠️ Distributed monolith. Микросервисы без autonomy = хуже монолита. Симптомы: shared DB, sync chains, deploy together.
⚠️ Nanoservices. Сервис на 100 строк кода — overhead network/observability больше пользы.
⚠️ Shared library hell. Одна shared lib импортируется всеми сервисами → её bump требует деплой всех. Альтернатива: contract testing.
⚠️ Versioning API. /v1/users vs /v2/users. Если не делать — breaking changes сломают консьюмеров. Если делать — больше maintenance.
⚠️ Distributed tracing забыли. В микросервисах без tracing дебаг — мука. Внедряй OpenTelemetry с первого дня.
⚠️ Local dev pain. Если для запуска “hello world” нужны 12 сервисов + Kafka + Redis + Postgres + Elastic — productivity tanks. Используй docker-compose, или mocks, или devcontainers.
⚠️ Cascading failures. Если A sync calls B calls C calls D, и D медленный — все цепочки висят. Circuit breakers + async patterns.
⚠️ Cost of microservices. RAM ×N, CPU ×N, network egress, observability. Иногда дешевле big monolith на больших box.
⚠️ Team velocity при микросервисах. Часто измеряется через “сколько фич в спринт”. Микросервисы могут замедлить начальные спринты, но ускорить долгосрочные.
⚠️ Premature optimization для scale. “Через 5 лет у нас будет 100M users, давайте microservices сразу.” Нет. Дойди до 10K users на монолите, потом рефактори.
⚠️ Refactoring через сервисы дорого. Внутри monolith — move file. Через сервисы — координация APIs, миграция данных, синхронизация deploy.
⚠️ Modular monolith требует дисциплины. Без enforcement (linters, code review) границы размываются → “ball of mud”.
⚠️ Microservices без CI/CD = катастрофа. Каждый сервис должен иметь свой автоматический pipeline, иначе deploy 50 сервисов вручную невозможен.
⚠️ Schema versioning в events. Если producer изменил схему, consumer ломается. Используй schema registry (Confluent, Karapace) + backwards compat правила.
4. Real cases
Заголовок раздела «4. Real cases»Monzo Bank — microservices. 1500+ микросервисов. Внутренняя платформа на Go. Cassandra, Kafka. Сильная investment в platform team. Это не для всех.
Shopify — modular monolith (“Majestic Monolith”). Большая часть Shopify — modular monolith на Rails. После 12+ лет роста — всё ещё monolith. Извлекли несколько critical services (Inventory, Payments).
Netflix — microservices. Pioneer. Тысячи сервисов. Open sourced Hystrix, Eureka, Zuul. Эстафету подхватили service mesh (Istio).
DHH / 37signals / Basecamp — back to monolith. В 2022 объявили “leaving the cloud.” Сервисы стали обратно одним монолитом. Простота и cost.
Uber — миграция в разные стороны. 2008: Python monolith. 2014-2018: ~2000 микросервисов. 2020+: “Domain-Oriented Microservice Architecture (DOMA)” — группировка микросервисов в домены, упрощение.
Amazon — “two-pizza teams”. Каждая команда владеет своим сервисом. AWS — extreme microservices. Внутренние сервисы — тысячи.
Google — миксы. Borg/Kubernetes — internal microservices. Но некоторые продукты (Search Frontend) — гигантские монолиты.
Facebook (Meta) — monolith for years. PHP/Hack monolith долго. Извлекли некоторые сервисы (News Feed ranking).
Stack Overflow — monolith. Один большой ASP.NET monolith. 6B запросов в месяц. Несколько hand-tuned серверов. Жан-вертикальное масштабирование.
Spotify — squad model + microservices. Squads (small teams) владеют сервисами. ~1000 сервисов. Сильная investment в Backstage (developer portal).
Mercedes Benz — modular monolith → microservices. Платформа постепенно перешла. Сначала boundaries through modules, затем вытащили в сервисы.
Tinkoff Bank — microservices. Сильное технологическое подразделение. Микросервисы на Go (большая часть), Kafka, K8s.
Yandex.Taxi — microservices. ~1500 сервисов. Полностью C++ (исторически), часть Python. Облако Y.Cloud — внутренний deploy.
WhatsApp до Facebook — monolith. 50 человек обслуживали 900M пользователей. Erlang monolith. Это extreme case “majestic monolith”.
Etsy — monolith and beyond. Большой PHP monolith много лет. Migration на JVM/microservices для специфичных областей. Не всё дробили.
Twitter — initial monolith → microservices. Ruby on Rails monolith (“fail whale” era 2008-2010). Перешли на JVM + microservices (Scala). Сейчас X (Twitter) ещё больше микросервисов.
Khan Academy — Python monolith. Сильно одна codebase. Извлекли единичные сервисы. Простота вторична — образовательные продукты vs scale.
Yandex.Practikum — modular monolith. Modular monolith с микросервисами для специфичных областей (ML, video processing). Не extreme microservices.
Capital One — domain-oriented services. Не строго микросервисы, а сервисы по domain boundaries. Migration с mainframe legacy через Strangler Fig.
ING Bank — microservices. Squads и микросервисы. Один of pioneers banking microservices. Heavy investment в platform.
Etsy backend для frontend (BFF). Pattern adoption: BFF для mobile разный от web. Aggregation для mobile.
HEY.com email — back to monolith. DHH-led проект. Single monolith, deployed simply. Демонстрация anti-microservices мысли.
HashiCorp — Go microservices. HashiCorp products (Terraform, Vault, Consul, Nomad) — каждый microservice, но architecturally они тоже monoliths внутри. Composition external.
Дополнительные considerations
Заголовок раздела «Дополнительные considerations»Modular monolith → microservices migration checklist:
- Идентифицировать bounded context (DDD).
- Удостовериться module имеет clear API.
- Дать ему свою БД (separate schema внутри monolith).
- Извлечь в отдельный процесс.
- Replace in-process call на gRPC/HTTP.
- Database migration (если общая).
Сосуществование monolith + microservices. Realistic: большинство компаний имеют hybrid. Core monolith + микросервисы вокруг для новых features или критичных по scale частей.
Cost of “doing microservices wrong”. Распространённый case: компания нанимает много инженеров, дробит на сервисы, но не строит platform (CI/CD, observability, service mesh). Результат: chaos, slow delivery, on-call hell.
5. Вопросы
Заголовок раздела «5. Вопросы»Q1: Что такое монолит? A: Один процесс, одна codebase, один deploy. Все компоненты приложения работают вместе в одном runtime. Простота, но scaling/deploy ограничения.
Q2: Когда монолит — правильный выбор? A: Стартап, MVP, маленькая команда (<10), domain ещё не понят, performance-critical workload. WhatsApp обслуживал 900M users с 50 инженерами на monolith.
Q3: Что такое modular monolith? A: Монолит с строгими модулями и явными API между ними. Преимущества monolith (simplicity) + микросервисов (clear boundaries). Migration path.
Q4: Чем microservices отличаются от просто разделения на сервисы? A: Microservices — independent deploy, independent data store, loose coupling, owned by separate teams. Просто разделение без этих свойств — distributed monolith.
Q5: Что такое distributed monolith и почему он плох? A: Много сервисов, но deploy together, sync chains, shared DB. Сложность distributed + отсутствие преимуществ microservices. Хуже монолита.
Q6: Что такое nanoservices? A: Микросервисы слишком мелкие (каждая функция — сервис). Overhead network/observability больше пользы. Anti-pattern.
Q7: Объясните Conway’s Law. A: Архитектура системы отражает структуру коммуникации команд. Раздробленные команды → микросервисы естественны. Одна команда → монолит. Inverse maneuver: структурируй команды под желаемую архитектуру.
Q8: Когда оправданы микросервисы? A: Multiple teams (>3 команды), independent scaling, different tech stacks, different SLAs/compliance, independent release cycles. Минимум одно из этих должно быть.
Q9: Каковы скрытые costs микросервисов? A: Network latency, distributed transactions, observability, DevOps cost, schema evolution. Эстимат: 30-50% engineering overhead.
Q10: Что такое Strangler Fig pattern? A: Migration legacy → new. Поставить proxy. Постепенно переносить endpoints в новый сервис. Old + new в parallel. Eventually old retired.
Q11: Какие коммуникации между сервисами? A: Sync (HTTP/gRPC) для query, critical commands с нужным ответом. Async (Kafka/NATS/RabbitMQ) для events, notifications, eventual workflows. Правило: sync для query, async для command.
Q12: Что такое “database per service”? A: Каждый микросервис владеет своей БД. Никто другой не имеет direct DB access. Schema evolution без координации. Joins через API/events.
Q13: Можно ли иметь shared DB между микросервисами? A: Технически да, на практике это distributed monolith. Schema change ломает несколько сервисов. Sharing through service API only.
Q14: Какой размер сервиса оптимален? A: “Two-pizza team owns it” (6-10 человек). “Two-week rewrite”. Один bounded context (DDD). Не функция, не монолит — между.
Q15: Polyglot persistence — что это? A: В микросервисной архитектуре разные сервисы используют разные БД (Postgres, Redis, Elastic, ClickHouse). Right tool for the job. В монолите сложнее.
Q16: Что такое Inverse Conway Maneuver? A: Реструктурировать команды под желаемую архитектуру. Если хочешь 3 микросервиса — создай 3 команды по 1 сервису. Архитектура естественно эволюционирует.
Q17: Сколько сервисов это много? A: Уравнение: сервисов > людей → проблемы maintenance. Уравнение: сервисов > 3× команд → дробление избыточное. Monzo (1500) — extreme case с большим platform investment.
Q18: Что такое branch by abstraction? A: Migration pattern: внутри monolith создать abstraction layer. Реализация может переключаться (in-process или remote). Feature flag для миграции.
Q19: Зачем contract testing между сервисами? A: Гарантия совместимости API между producer и consumer. Без E2E запуска. Pact, Spring Cloud Contract. Защита от breaking changes.
Q20: Когда перейти с монолита на микросервисы? A: Симптомы: команда >20, deploy задерживается из-за координации, разные scaling needs очевидны, разные tech stacks нужны. Не делать преждевременно.
Q21: Modular monolith vs microservices — когда что? A: Modular monolith — simplicity деплоя + clear boundaries. Microservices — independent scaling/deploy + tech stack diversity, но цена. Modular monolith — отличная отправная точка.
Q22: Что делать если у вас “distributed monolith”? A: Шаг 1: identify cause — shared DB, sync chains, deploy coupling. Шаг 2: database per service. Шаг 3: async messaging. Шаг 4: versioned APIs. Постепенно decouple.
Q23: Как Conway’s Law влияет на архитектуру? A: Структура коммуникации команд определяет архитектуру системы. Раздробленные команды → микросервисы. Одна команда → monolith. Use Inverse Conway Maneuver для контроля.
Q24: Polyglot persistence — pros & cons? A: Pros: right tool per service (Redis for cache, ES for search, Postgres for transactions). Cons: больше БД для maintenance, dev complexity.
Q25: Когда использовать nanoservices можно? A: Почти никогда в business apps. FaaS (Lambda) для очень специфичных задач (image resize, webhook handler). Не для general microservices.
6. Practice
Заголовок раздела «6. Practice»-
Реализуй modular monolith на Go. 3 модуля (Order, Payment, Customer), каждый со своей
internal/. API через interfaces. Используй linter для проверки imports. -
Strangler Fig симуляция. Создай “legacy” monolith с 3 endpoints. Добавь proxy (chi). Извлеки один endpoint в новый сервис. Покажи, что proxy роутит на новый.
-
Извлечение модуля в сервис. Из modular monolith вытащи Payment module в отдельный сервис. Замени in-process call на gRPC. Сравни latency.
-
Сервис с polyglot persistence. Order service: PostgreSQL для orders, Redis для cart, Elasticsearch для search. Покажи sync data между ними.
-
Distributed monolith detection. Запусти 3 сервиса с sync chain (A → B → C). Покажи каскадный fail. Затем переделай через events. Сравни.
-
Contract test с Pact. Producer-consumer contracts. Schema change в producer должен ломать contract test.
-
Database per service migration. Изначально shared DB. Реализуй replication в private DB. Переключи чтение/запись.
-
Сравни operational complexity. Поставь monitoring (Prometheus + Grafana + Jaeger) на monolith и на 5-service microservices. Время на запуск, размер дашбордов.
-
Inverse Conway Maneuver симуляция. Опиши команды и сервисы. Покажи, как структура команд диктует API контракты.
-
Cost analysis. Эстимируй cost (cloud bill, dev time) для same feature на monolith vs 3-service microservices vs 10-service.
-
Команда + архитектура. Опиши hypothetical компанию (50 инженеров, 8 продуктов). Какая структура команд и сервисов?
-
Latency analysis. Запусти monolith и распределённый equivalent. Замерь p50, p95, p99 latency. Network hops cost.
-
Deploy frequency simulator. Симулируй 10 разработчиков deploy’я в monolith vs в 5 microservices. Conflict rate, rollback rate, deploy time.
-
Database extraction. Возьми shared DB в monolith. Извлеки одну таблицу в private DB для отдельного сервиса. Покажи migration steps.
-
Conway’s Law check. Возьми свой проект. Сравни структуру команд и сервисов. Совпадает?
7. Источники
Заголовок раздела «7. Источники»- Martin Fowler. “Microservices.” 2014. https://martinfowler.com/articles/microservices.html
- Sam Newman. “Building Microservices.” 2nd ed., O’Reilly, 2021.
- Sam Newman. “Monolith to Microservices.” O’Reilly, 2019.
- Chris Richardson. “Microservices Patterns.” Manning, 2018.
- Martin Fowler. “MonolithFirst.” 2015. https://martinfowler.com/bliki/MonolithFirst.html
- Martin Fowler. “Strangler Fig Application.” https://martinfowler.com/bliki/StranglerFigApplication.html
- Shopify. “Deconstructing the Monolith.” https://shopify.engineering/deconstructing-monolith-designing-software-maximizes-developer-productivity
- Monzo. “The Modern Engineering Organization.” https://monzo.com/blog/
- DHH. “We’re leaving the cloud.” 2022. https://world.hey.com/dhh/we-re-leaving-the-cloud-654b47e0
- Uber Engineering. “Introducing Domain-Oriented Microservice Architecture.” 2020. https://www.uber.com/blog/microservice-architecture/
- Conway, M. “How Do Committees Invent?” Datamation, 1968.
- Microservices.io patterns. https://microservices.io/patterns/