Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
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.
The Evolution of DDD and Common Mistakes: From the Blue Book to Dynamic Consistency Boundaries
DDD's most common mistake is skipping the strategic design left at the end of the Blue Book and taking only tactical words like entity, repository, and base class. A history from Evans's 2003 book to the DDD Reference, Vernon's aggregate rules, EventStorming, Team Topologies and Khononov, and the Dynamic Consistency Boundary that questions the aggregate; with an in-memory DCB example and a reading route after the series.
End to End: Refactoring Bookstore's Ordering Context from Anemic CRUD to a Rich Model
The safe way to move anemic CRUD code to a rich model is to pin current behavior with characterization tests first, then take the language, value object, aggregate boundary, invariant, and domain event steps as separate commits that each stay green. We transform Bookstore's Ordering in 11 commits and show refactoring toward deeper insight with a buy-3-pay-for-2 campaign, plus before/after metrics, all with real output.
Domain Events: Raise, Collect, and Dispatch on SaveChanges
An aggregate records what happened as a past-tense, immutable domain event in its own list; EF Core 10's SaveChangesInterceptor collects the events during SaveChanges, runs same-transaction handlers before the commit and side effects that leave the database after it. A mediator-free dispatcher, the nested SaveChanges and explicit transaction traps with real output, and how integration events and the outbox differ.
Domain Services, Application Services, and the Anemic Domain Model
Behavior goes first to the entity or value object that owns it; a stateless domain calculation that naturally belongs to none of them becomes a domain service, while loading, saving, and the transaction stay in a thin application service. We move Bookstore's copied shipping rule out of anemic services into Order and a ShippingFeeCalculator, with real output, and cover policies, factories, and the trap of injecting repositories into domain services.
Aggregate Design: Consistency Boundaries, Small Aggregates, and Referencing by Id
An aggregate is a consistency boundary that keeps true invariants consistent within a single transaction; the outside references only the root, and other aggregates are referenced only by id. We apply Vernon's four rules to Bookstore's Order and StockItem aggregates and work through a real EF Core run where a navigation property silently changes the catalog price, eventual consistency for stock, the 'whose job is it?' question and the Aggregate Design Canvas.