Software Architecture

CQRS

Odczyty i zapisy mają różne wymagania — dlaczego używać jednego modelu? CQRS rozdziela je na niezależne strony, które można skalować i optymalizować osobno.

Command Query RS
Pełna nazwa
Event Sourcing
Połączenie
Elasticsearch
Read store
Axon / MediatR
Framework

3 strony architektury CQRS

CQRS dzieli system na trzy wyraźnie rozdzielone warstwy: zapis, odczyt i synchronizację między nimi.

Command Side (Write)

Obsługuje zapisy, egzekwuje reguły biznesowe, gwarantuje spójność

  • →Command — intencja zmiany: CreateOrder, CancelOrder
  • →Command Handler — walidacja i logika biznesowa
  • →Domain Model (Aggregates) — reguły biznesowe
  • →Write Store — PostgreSQL, Event Store

Query Side (Read)

Obsługuje odczyty, zoptymalizowane widoki, eventual consistency

  • →Query — żądanie danych: GetOrderDetails, ListUserOrders
  • →Query Handler — prosta operacja odczytu
  • →Read Models — denormalizowane projekcje
  • →Read Store — Elasticsearch, Redis, MongoDB, PostgreSQL

Synchronizacja (Event Bus)

Propaguje zmiany z write side do read side asynchronicznie

  • →Events — fakty o zmianach stanu
  • →Event Handlers (Projections) — aktualizują read models
  • →Message Broker — Kafka, RabbitMQ, SQS
  • →Dead Letter Queue — obsługa błędów projekcji

CQRS vs. CRUD — porównanie

CQRS nie zawsze jest lepszy — tylko w określonych kontekstach.

AspektCRUDCQRS
Złożoność koduNiska — jeden modelWysoka — dwa modele + synchronizacja
Wydajność odczytuOgraniczona przez JOINyBardzo wysoka — pre-computed views
SkalowalnośćRazem (write + read)Niezależna dla write i read
Audit trailBrak (tylko aktualny stan)+ES: pełna historia zdarzeń
Czas wdrożeniaKrótkiDługi (2-4x dłużej)
Eventual consistencyBrak problemuWyzwanie — read lag

Często zadawane pytania

Co to jest CQRS?

CQRS (Command Query Responsibility Segregation) to wzorzec architektoniczny który rozdziela operacje zapisu (Commands) od operacji odczytu (Queries) na oddzielne modele — i często na oddzielne bazy danych. Tradycyjny CRUD: jeden model i jedna baza do wszystkiego. Problem: odczyty i zapisy mają różne wymagania wydajnościowe i złożoności. CQRS rozdziela: Command side — obsługuje zapisy/modyfikacje. Walidacja, logika biznesowa, zapis do write store (baza relacyjna, event store). Query side — obsługuje odczyty. Zoptymalizowane modele danych (denormalizowane), szybkie odczyty, brak JOINów. Dlaczego CQRS: Skalowalność oddzielnie — skaluj czytelnicy niezależnie od piszących. Optymalizacja — write model normalizowany dla integralności, read model denormalizowany dla szybkości. Event Sourcing naturalnie łączy się z CQRS — komendy generują zdarzenia, zdarzenia budują projekcje (read models). CQRS to nie zawsze konieczność — dla prostych CRUD aplikacji jest over-engineering.

Jak działa Command side w CQRS?

Command side (strona zapisu) w CQRS: Command — intencja zmiany stanu: CreateOrder, CancelOrder, UpdateUserProfile. Command jest walidowany zanim zostanie przetworzony. Command Handler — odbiera komendę, waliduje, wykonuje logikę biznesową, zapisuje do write store lub emituje zdarzenia. Domain Model — agregaty z logiką biznesową (Domain-Driven Design). Aggregate = consistency boundary. Write Store — baza danych dla zapisów. Może być: relacyjna (PostgreSQL), document store (MongoDB) lub Event Store (EventStoreDB, Kafka). Ważne zasady Command side: Idempotentność — ta sama komenda wysłana 2 razy = ten sam wynik (używaj idempotency keys). Validation first — waliduj komendę przed jakimkolwiek zapisem. Thin controller, fat domain — logika w domain model, nie w handler. Command nie zwraca danych — zwraca sukces/błąd, nie obiekt (to byłoby Query). Narzędzia: MediatR (.NET), Axon Framework (Java), command bus pattern.

Jak działają Query side i Read Models?

Query side (strona odczytu) w CQRS: Read Models (projekcje) — denormalizowane widoki danych zoptymalizowane pod konkretne zapytania. Zamiast JOINowania 5 tabel, czytasz gotową, pre-computed projekcję. Jak są budowane: Event handlers słuchają zdarzeń z write side i aktualizują read store. Read Store — może być inny niż write store! Elasticseach dla full-text search, Redis dla cache i liczników, PostgreSQL z denormalizowanymi tabelami, MongoDB dla dokumentowych widoków. Query Handler — prosta operacja: pobierz z read store, zwróć DTO. Zero logiki biznesowej. Eventual consistency — read model jest za write modelem o milisekundy/sekundy. Musisz to zaakceptować lub obsłużyć (np. po zapisie zwróć ostatni stan z write store zamiast query side przez N sekund). Przykład: e-commerce. Write store: znormalizowane tabele orders/items/products. Read model: jeden dokument per zamówienie z wszystkimi danymi — OrderDetailsView. Zapytanie = proste ID lookup.

CQRS vs. tradycyjny CRUD — kiedy co stosować?

CQRS vs. CRUD: CRUD (Create, Read, Update, Delete) — jeden model do wszystkiego. Prostota, szybkość implementacji, łatwość zrozumienia. Sprawdza się dla prostych domenowych problemów gdzie odczyty i zapisy mają podobną złożoność. Kiedy NIE używaj CQRS: Prosta aplikacja CRUD (admin panele, proste API). Mały team bez doświadczenia z CQRS. MVP/startup w early stage — przedwczesna optymalizacja. Kiedy CQRS ma sens: Wymagania na odczyty i zapisy dramatycznie się różnią (np. setki queries/s vs. kilka commands/s). Złożona logika domenowa po stronie zapisu. Potrzebujesz różnych optymalizacji dla różnych widoków tych samych danych. Budujesz z Event Sourcing — CQRS jest naturalny. Systemy wymagające audit trail. Koszty CQRS: Zwiększona złożoność kodu. Eventual consistency — nowe wyzwanie dla developerów. Dwie bazy danych do zarządzania i synchronizacji. Reguła: nie stosuj CQRS na starcie — dodaj gdy outgrowth CRUD staje się bolesny.

CQRS z Event Sourcing — jak połączyć?

CQRS + Event Sourcing (ES) to naturalne połączenie i jeden z najpopularniejszych wzorców w systemach złożonych. Jak to działa razem: Command przychodzi do Command Handler. Handler waliduje i tworzy zdarzenia (OrderCreated, ItemAdded, PaymentProcessed). Zdarzenia są zapisywane do Event Store (append-only). Event Store publikuje zdarzenia do message broker. Event Handlers (projekcje) odbierają zdarzenia i aktualizują Read Models. Queries czytają z Read Models — błyskawiczne odczyty. Zalety połączenia: Event Store = write side (CQRS). Replay zdarzeń = rebuilding read models. Dodajesz nowy Read Model bez migracji danych — replayujesz zdarzenia. Pełen audit trail. Time travel debugging. Wady połączenia: Duża złożoność. Eventual consistency. Schema evolution zdarzeń. Frameworki wspierające CQRS+ES: Axon Framework (Java), EventSauce (PHP), NServiceBus (.NET), custom implementacje z Kafka + PostgreSQL.

Kontakt

Skontaktuj się z nami

Porozmawiajmy o Twoim projekcie. Bezpłatna wycena w ciągu 24 godzin.

Wyślij zapytanie

Bezpłatna wycena w 24h
Bez zobowiązań
Indywidualne podejście
Ekspresowa realizacja

Telefon

+48 790 814 814

Pon-Pt: 9:00 - 18:00

Email

adam@fotz.pl

Odpowiadamy w ciągu 24h

Adres rejestrowy

Poznańska 117/11

62-023 Kamionki · obsługa zdalna

Godziny pracy

Pon - Pt9:00 - 18:00
Sob - NdzZamknięte

Wolisz porozmawiać?

Zadzwoń teraz i porozmawiaj z naszym specjalistą o Twoim projekcie.

Zadzwoń teraz