компонуемые .net-блоки для микросервисов
Koto
Koto — набор небольших, сфокусированных NuGet-пакетов, которые связывают Wolverine, Marten, FastEndpoints и EF Core общими конвенциями для DDD, CQRS и Event Sourcing. Берите что нужно — остальное не мешает.
dotnet add package Koto.Domainсмотреть пакеты →как это выглядит ↓
зачем
DDD в .NET — это обычно либо боилерплейт, либо лицензионная ловушка
Либо вы с нуля пишете always-valid доменные объекты, обработку ошибок через Result и доставку событий через outbox в каждом сервисе — либо берёте готовый фреймворк и потом узнаёте, что он стал коммерческим (MediatR v13+, MassTransit v9+, FluentAssertions v8+).
Koto — тонкая прослойка со своими конвенциями над свободными лучшими в своём классе .NET-библиотеками: Wolverine для messaging, Marten для event sourcing, FastEndpoints для HTTP, EF Core для персистентности. Конвенции есть, а боилерплейта и лицензионных ловушек — нет.
как это выглядит
Доменная модель, которую нельзя создать в невалидном состоянии
Валидация живёт в фабричном методе, а не разбросана по кодовой базе. Неудача — это значение, Result<T>, а не исключение.
объект-значение
public sealed class Email : ValueObject
{
public string Value { get; }
private Email(string value) => Value = value;
public static Result<Email> Create(string value) =>
string.IsNullOrWhiteSpace(value) ? Errors.General.ValueIsRequired() :
value.Length > 150 ? Errors.General.InvalidLength(1, 150) :
new Email(value);
}корень агрегата
public class Order : AggregateRoot<OrderId>
{
public static Result<Order> Place(Customer customer, IReadOnlyList<OrderItem> items)
{
if (items.Count == 0)
return OrderErrors.NoItems();
var order = new Order(OrderId.New(), customer.Id);
order.AddDomainEvent(new OrderPlacedDomainEvent(order.Id, customer.Id));
return order;
}
public Result<Unit> Cancel(string reason)
{
if (Status == OrderStatus.Cancelled)
return OrderErrors.AlreadyCancelled();
Status = OrderStatus.Cancelled;
AddDomainEvent(new OrderCancelledDomainEvent(Id, reason));
return Unit.Value;
}
}как это собирается вместе
Четыре принципа вместо фреймворка
01
Всегда валидный домен
Доменные объекты нельзя создать в невалидном состоянии. Валидация живёт в фабричных методах, а не в валидаторах.
02
Явные ошибки от начала до конца
Никаких исключений для ожидаемых неудач. Result<T> идёт от домена до самого HTTP-ответа.
03
События сами долетают до Kafka
Доменное событие попадает в outbox в той же транзакции, что и сохранение агрегата. Wolverine доставляет его in-process хендлеру, тот публикует интеграционное событие, а Kafka разносит его по остальным сервисам.
04
Без магии
Никакой рефлексии в горячих путях. Никаких скрытых конвенций, которые удивят вас в два часа ночи. Код, который вы пишете — код, который выполняется.
доменное событие → Kafka, автоматически
Order.Cancel()
→ AddDomainEvent(OrderCancelledDomainEvent)
→ DbContext.SaveChangesAsync() // outbox, same transaction
→ Wolverine delivers to in-process handler
→ handler publishes OrderCancelledIntegrationEvent
→ Kafka → other servicesпакеты
Двенадцать пакетов. Берите что нужно — остальное не мешает.
Koto.Domain
DDD-примитивы для .NET-микросервисов. Без внешних зависимостей.
Koto.Application
CQRS-диспетчер, pipeline-поведения и абстракции межсервисной интеграции.
Koto.Validation
Расширения FluentValidation и CQRS pipeline-поведение.
Koto.Infrastructure.EFCore
Интеграция EF Core 10: generic-репозиторий, строготипизированные ID, specifications, Wolverine outbox.
Koto.Infrastructure.Http
Anti-Corruption Layer для синхронных HTTP-вызовов между сервисами.
Koto.EventSourcing.Marten
Event Sourcing на PostgreSQL через Marten.
Koto.Messaging.Wolverine
Реализация messaging-абстракций Koto на Wolverine + Kafka.
Koto.Api.AspNetCore
Транспорт-независимая интеграция ASP.NET Core — Minimal API, MVC или любой хост.
Koto.Api.FastEndpoints
Интеграция FastEndpoints для DDD-примитивов Koto.
Koto.Observability
Настройка observability одной строкой: Serilog + OpenTelemetry.
Koto.Scheduling
Плановые джобы и batch-обработка на Quartz.NET.
Koto.Testing
DDD-специфичные тестовые хелперы: Given/When/Then для агрегатов.
начало работы
Добавьте нужные пакеты
dotnet add package Koto.Domain
dotnet add package Koto.Application
dotnet add package Koto.Infrastructure.EFCoreлицензия mit · опубликовано на nuget
Создано для реальной продакшен-системы, открыто для всех остальных
Koto вырос из работы над реальным .NET-микросервисным бэкендом и был вынесен в отдельный репозиторий, когда абстракции доказали свою пользу.