Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
The Always-Valid Domain Model: Protecting Invariants with Constructors, Factories, and Guards
An always-valid domain model doesn't check invariants before saving, it makes violating them impossible: a private constructor, a static factory and guard clauses close every path to an invalid state. With Bookstore's Order we work through the at-least-one-item, 10-copies-per-book, single-currency and one-coupon rules, the limits of required/init and C# 14's field, the domain exception vs Result split, and the difference between input validation and invariants, with real output.
Entities and Value Objects: Identity, Equality, and Immutable Models with C# Records
An entity is defined by an identity that lasts through time, a value object only by its value: two Money values are the same if amount and currency match, two Orders only if their Ids do. We write Money, Isbn and strongly typed ids with C# records and readonly record structs, map them with the complex types EF Core 10 recommends over owned types, and show the collection-in-record, struct default and with pitfalls with real output.
Discovering the Domain with EventStorming: From Big Picture to Aggregates
EventStorming is a workshop format that brings domain experts and developers to a shared language by placing what happens in the domain on a timeline as orange, past-tense stickies. We take Bookstore's order flow through the Big Picture, Process Modeling and Software Design levels and turn the hot spots, pivotal events, policies and aggregate candidates from the wall into code.
Context Mapping: Anti-Corruption Layer, Open Host Service, and Relationships Between Bounded Contexts
A context map names the relationships between bounded contexts on both the technical and the organizational level: upstream/downstream, Partnership, Shared Kernel, Customer/Supplier, Conformist, Anti-Corruption Layer, Open Host Service, Published Language, Separate Ways, and Big Ball of Mud. Bookstore's context map, a tested ACL that translates the legacy carrier's SOAP/XML model into Shipping's, a versioned Published Language, and the trap of a Shared Kernel turning into Common.dll.
Bounded Context: Same Word, Different Meanings, and Model Boundaries
A bounded context is an explicitly drawn boundary within which a model and its language apply; because a "book" is a work on sale in Catalog, physical copies in Inventory, a purchased line in Ordering, and a box in Shipping, you need four models instead of one giant Book class. Evans's definition, CS0104 with .NET's Timers, how a bounded context differs from a subdomain and a microservice, sizing, a Bounded Context Canvas for Ordering, and one schema per context with EF Core.
Ubiquitous Language: Code That Speaks the Domain Expert's Language
Ubiquitous language is the one precise language that domain experts and developers speak inside a bounded context and that maps directly to class and method names: order.Cancel(reason) and RequestReturn instead of Status = 4. Separating ambiguous words (product, status, return versus refund), a glossary with a translation column for a team that speaks Turkish and writes English code, a reflection-based glossary check, and how HttpStatusCode followed RFC 9110's renaming.
What Is Domain-Driven Design? When It Pays Off and When It Doesn't
DDD accepts that complexity lives in the business rules rather than the technology and brings the model into code together with domain experts; it pays off in a core domain whose rules change often and is unnecessary for CRUD screens and short-lived MVPs. A campaign discount bug that shows the difference between a CRUD model and a domain model, strategic versus tactical design, eShop's Ordering.Domain, and the series roadmap.
When to Use Vertical Slices: Combining Them with Clean Architecture and Modular Monoliths
Vertical slices work well for APIs that gain features often and whose use cases vary in complexity; they aren't enough on their own for teams without refactoring discipline or for rich, shared domains, and they work best together with a Clean domain core and modular monolith boundaries. We split Bookstore into modules and protect the boundary with internal and ArchUnitNET, evaluate REPR with FastEndpoints, and lay out a plan for moving a layered project to slices gradually.
Testing Vertical Slices: Integration Tests per Slice and Unit Tests Where They Matter
A slice's natural test unit is the path from the HTTP request to the real database, while domain rules are tested cheaply with pure unit tests. We build per-slice tests with WebApplicationFactory, a real SQL Server via Testcontainers, and Respawn, and show with real output how tests break each other without a reset and how the InMemory provider both passes and fails wrongly on the same search query.
Sharing Across Slices: Duplication or Abstraction, and Where Does Domain Logic Go?
Across slices you share the domain model, cross-cutting concerns, and infrastructure; you don't share request/response types, queries, or workflows, and invariants move into the entity without waiting for a second copy. With real output we see a rule placed on a request allow a 7-copy order and a slice calling another slice save an order whose payment was declined, then prevent that with an ArchUnitNET slice test.
Slices with a Mediator: Comparing MediatR, Source-Generated Mediator, and Wolverine
The real gain of a mediator in slices is a pipeline that is independent of the entry point; as of November 2026 MediatR 14.3 is RPL 1.5 or commercially licensed, while Mediator 3.0.2 and Wolverine 6.62 are MIT. We write the same PlaceOrder slice with all three tools and with a mediator-free endpoint filter, and compare dispatch cost, first-request time, Native AOT behaviour, and each tool's real setup pitfalls.
Your First Slice Without MediatR: Minimal API, a Handler Class, and Endpoint Registration
A slice without MediatR is built from request and response records, a handler class that uses DbContext directly, and an IEndpoint that maps its own route, with an assembly scan doing the registration. We write Bookstore's PlaceOrder and GetOrderDetails slices with .NET 10 AddValidation, TypedResults, and EF Core projections, and show how a naming convention can take down every endpoint and how to catch that at startup.