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.

    Aspekt CRUD CQRS
    Złożoność kodu Niska — jeden model Wysoka — dwa modele + synchronizacja
    Wydajność odczytu Ograniczona przez JOINy Bardzo wysoka — pre-computed views
    Skalowalność Razem (write + read) Niezależna dla write i read
    Audit trail Brak (tylko aktualny stan) +ES: pełna historia zdarzeń
    Czas wdrożenia Krótki Długi (2-4x dłużej)
    Eventual consistency Brak problemu Wyzwanie — 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.

    Czytaj dalej

    Powiązane artykuły

    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

    Plac Wolności 16

    61-739 Poznań

    Godziny pracy

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

    Wolisz porozmawiać?

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

    Zadzwoń teraz