Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
Message Types: Commands, Events, and Queries; Event Notification and Event-Carried State Transfer
A command is imperative and goes to one receiver, an event is a past-tense fact that doesn't know its receivers, and a query expects an answer; that distinction decides a message's name, its contract owner, and its channel. An envelope with message, correlation, and causation ids, Fowler's event notification versus event-carried state transfer, and domain versus integration events, with real output.
When Are CQRS and Event Sourcing Unnecessary? Anti-Patterns and a Decision Guide
CQRS and event sourcing are unnecessary for plain CRUD, MVPs, static reference data, real-time consistent views, and inexperienced teams; the decision is made separately for each bounded context. Bookstore's context map, a decision flow for CQRS levels 1/2/3 and event sourcing, and four anti-patterns: CQRS ceremony on a single database, event sourcing everywhere, state-change events, and using internal events as an integration contract.
The Hard Parts of Event Sourcing: GDPR, Unique Constraints, and Dynamic Consistency Boundaries
Keep personal data out of events and encrypt it with crypto-shredding when it must stay; protect cross-stream uniqueness with a natural-key stream id or an Inline projection with a unique index, and rules spanning two aggregates with a Dynamic Consistency Boundary. AES-GCM crypto-shredding with Marten 9, a race between two concurrent registrations, a campaign quota with DcbConcurrencyException, and not calling external services on replay.
Event Versioning and Snapshots: Changing Event Schemas Without Breaking History
Written events are not changed; new code reads old shapes through tolerant deserialization, fixed JSON names, and upcasters, while snapshots are turned on based on measurement and together with a rebuild. A property rename that silently turns into zero, RespectRequiredConstructorParameters, a Marten upcaster, a Turkish-culture alias breaking on a namespace move, the cost of in-place migration, a snapshot serialization trap, and closing the books.
Projections: Building Read Models with Inline, Async, and Live Projections
A projection is a function that turns events into a read model shaped by a specific question; Inline runs in the same transaction as the events, Async runs in the background with the daemon, and Live is never stored. A stock badge, a monthly stock movement report, and reservations waiting to ship from the Bookstore stock ledger; checkpoints, changing a projection and rebuilding it, dead letters, and a failed rebuild emptying a read model.
Working with an Event Store: Append, Optimistic Concurrency, and Streams with Marten and PostgreSQL
An event store's core contract is appending to a stream only while it is at the expected version; Marten provides this on PostgreSQL with a unique index on (stream_id, version) and FetchForWriting. Setting up Marten 9, StartStream/Append, wiring a decider to FetchForWriting, a race between two writers, stream id strategies, KurrentDB versus your own table, and event names that break under a Turkish culture.
Event-Sourced Aggregates with the Decider Pattern: decide, evolve, and Given-When-Then Tests
The decider pattern splits an event-sourced model's decision logic into two pure functions: Decide produces new events from a command and a state, Evolve produces a new state from a state and an event. A decider for the stock ledger with C# 14 switch expressions, moving time into the command with TimeProvider, database-free Given-When-Then tests and a comparison with the OOP aggregate style, with real test output.
What Is Event Sourcing? Storing What Happened Instead of State
Event Sourcing stores what happened in an append-only event stream instead of the latest state, and derives state by folding those events. Using Bookstore's stock ledger: rehydration, audit, temporal queries, optimistic concurrency with an expected version, why an event store is not a message broker, why it goes together with CQRS, and its real costs.
A Separate Read Model: Materialized Views, Synchronization, and Living with Eventual Consistency
A separate read model stores the screen's row precomputed from domain events; updated in the same transaction it stays immediately consistent, updated asynchronously in a separate database you have to live with eventual consistency. Inline projections, PostgreSQL materialized views, an asynchronous projector with a checkpoint, waiting on a position for read-your-own-writes, idempotent updates and a full rebuild, with real output.
CQRS in a Single Database: Aggregates on the Write Side, Projections on the Read Side
CQRS in a single database means saving the aggregate through EF Core's change tracker on the write side and projecting from the same tables on the read side without ever touching the aggregate. What PlaceOrder and CancelOrder should return, a separate flat read DbContext, Dapper over a SQL view, and having PostgreSQL enforce that queries don't change state with read-only transactions, with real SQL and the 25006 error.
What Is CQRS? From CQS to Command Query Responsibility Segregation
CQRS splits one model into two, one for writing (commands) and one for reading (queries); Greg Young took Meyer's method-level CQS principle up to the model level. We show with a real compiler error and a load count why an aggregate does not fit a list screen, then cover the three levels of CQRS, how it differs from Event Sourcing and MediatR, and Fowler's 'only where it pays off' warning.
Command Pattern: Turning Requests into Objects, Undo/Redo and Queuing
Command packages a request as an object, so an invoker can run it, undo it, queue it and log it without knowing what it does. An undo/redo stack and a MacroCommand in Bookstore's catalog editor, System.Windows.Input.ICommand in the BCL, serializing commands with System.Text.Json and running them in the background through a Channel, how a GoF command differs from a CQRS command, MediatR 13's license and a library-free dispatcher.