Публичные API в Модульных Монолитах. Начало
В каждой статье о модульных монолитах говорится, что нужно использовать публичные API между модулями. Но редко говорится, почему эти API существуют или как их правильно проектировать.
Модульный монолит организует приложение в независимые модули с чёткими границами. Границы модулей логичны и группируют связанные бизнес-возможности. Публичные API между ними — это не просто чистый код, это контроль хаоса. Они представляют собой преднамеренные точки связанности. Публичные API не устраняют связанность, они делают её явной и контролируемой.
Когда модулю A что-то нужно от модуля B, у вас есть три варианта:
1) Позволить модулю A читать напрямую из базы данных модуля B,
2) Позволить модулю A получать доступ к внутренним сервисам модуля B,
3) Создать публичный API, который явно определяет, что может делать модуль A.
Первые два варианта приводят к хаосу. Вся система может стать неподдерживаемой, если каждый модуль свободно обращается к данным и сервисам других модулей.
Публичные API служат следующим критически важным целям:
1) Определение контракта: они явно указывают, что могут и не могут делать другие модули,
2) Управление зависимостями: они заставляют вас думать о зависимостях модулей,
3) Управление изменениями: они предоставляют стабильный интерфейс, допуская при этом внутренние изменения.
Вот практический пример. Представьте, что у вас есть модули Orders и Shipping.
Этого мы хотели бы избежать:
public class ShippingService
{
// Прямой доступ к БД
private OrdersDbContext _ordersDb;
public async Task ShipOrder(string id)
{
// Напрямую обращаемся к БД другого модуля
var order = await _ordersDb.Orders
.Include(o => o.Lines)
.FirstOrDefaultAsync(o => o.Id == id);
// Что, если модуль Orders изменит схему данных?
}
}
А вот, чего бы мы хотели добиться вместо этого:
public class ShippingService
{
// Доступ к публичному API
private IOrdersModule _orders;
public async Task ShipOrder(string id)
{
// Используем публичный API
var order = await
_orders.GetShippingOrder(id);
// Модуль Orders может изменять внутреннюю
// структуру, сохраняя внешний контракт
}
}
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/internal-vs-public-apis-in-modular-monoliths