Ответ
CQRS (Command Query Responsibility Segregation) — это архитектурный паттерн, который разделяет модель данных и операции на две отдельные части: Команды (Commands) для изменения состояния и Запросы (Queries) для чтения данных.
Ключевые концепции:
- Команда (Command): Представляет намерение изменить состояние системы (например,
PlaceOrderCommand,UpdateUserEmailCommand). Команда выполняется один раз, не возвращает данных (или возвращает только идентификатор/статус) и обладает побочными эффектами. - Запрос (Query): Представляет запрос на получение данных без изменения состояния системы (например,
GetUserOrdersQuery). Запросы идемпотентны и не имеют побочных эффектов.
Практическая реализация (псевдокод на C#):
// Command и его обработчик (Write Model)
public class CreateProductCommand
{
public string Name { get; set; }
public decimal Price { get; set; }
}
public class CreateProductCommandHandler
{
private readonly WriteDbContext _dbContext;
public async Task Handle(CreateProductCommand command)
{
var product = new Product { Name = command.Name, Price = command.Price };
_dbContext.Products.Add(product);
await _dbContext.SaveChangesAsync();
}
}
// Query и его обработчик (Read Model)
public class GetProductListQuery { }
public class ProductDto { public string Name; public decimal Price; }
public class GetProductListQueryHandler
{
private readonly ReadDbContext _dbContext; // Может быть отдельная, денормализованная БД
public async Task<List<ProductDto>> Handle(GetProductListQuery query)
{
return await _dbContext.ProductViews
.Select(p => new ProductDto { Name = p.Name, Price = p.Price })
.ToListAsync();
}
}
Преимущества CQRS:
- Масштабируемость: Модели чтения и записи можно масштабировать независимо.
- Гибкость: Можно использовать разные типы хранилищ, оптимизированные под конкретные задачи (SQL для команд, NoSQL или материализованные представления для запросов).
- Более чистая модель: Разделение ответственности упрощает код и делает его более понятным.
Сложности и когда использовать: Паттерн добавляет сложность (необходимость синхронизации моделей, две модели данных). Его стоит применять в системах с высокой нагрузкой, сложной бизнес-логикой или там, где требования к чтению и записи кардинально различаются.