Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
What Are Microservices and What Are They Not? Independent Deployability and Information Hiding
A microservice is a service modeled around a business domain that can be deployed without touching the others; the criterion is not size but independent deployability and information hiding. Lewis and Fowler's nine characteristics, Newman's definition, separating the contract from the internal model in C#, the difference from SOA, and Bookstore's service candidates.
The Cost of Microservices: When Are They Unnecessary and When Are They Inevitable?
Microservices are unnecessary for a single-team system without the prerequisites (automated provisioning, monitoring, fast deployment); they become inevitable once teams waiting on each other and parts that scale differently become measurable. The real cost of a network call, measured, plus the fallacies of distributed computing, Fowler's prerequisites, a correct reading of the Prime Video case and a decision checklist for Bookstore.
Drawing Service Boundaries: Business Capabilities, Bounded Contexts and Types of Coupling
A service boundary is drawn not around tables or entities but around business rules that change together: a service holds at most one bounded context and is owned by a single team. The business capability and subdomain approaches, Microsoft's boundary guide, Newman's domain, pass-through, common and content coupling, the entity service anti-pattern, and Customer as three separate models in three contexts.
Data Ownership and Database per Service: Why Avoid a Shared Database?
A shared database creates coupling that appears in no contract; each service's data should be private to it, and others should reach it through API composition, a local copy replicated through events, or a CQRS read model. Enforcing the boundary with schema-level permissions in SQL Server, a version-checked copy driven by BookRenamed, the snapshot difference, reference data and CDC for reporting.
No Transactions Across Microservices: Embracing Eventual Consistency by Design
Distributed transactions (2PC) are not used across services; a rule that needs immediate consistency stays in one service, and a flow spanning several services is built with sagas and compensating actions, with events going through an outbox. The real error TransactionScope gives on Linux and macOS, a choreographed checkout saga, intermediate states in the domain, and eventual consistency shown to the user with 202 Accepted.
Microservice Communication Styles: Sync Request/Response, Async Events and Temporal Coupling
If the caller must wait for the answer, communication is synchronous however much await the code has, and it binds two services through temporal coupling; if the answer isn't needed now, prefer an event or a local copy. A comparison of REST, gRPC (including deadlines reaching the server) and messages, a checkout simulation while Inventory is being deployed, the command versus event split, and a decision table.
Service Contracts and Versioning: Expand-Contract, Tolerant Reader and Consumer-Driven Contract Tests
Whether a change is breaking can't be decided from the provider's code alone; you need to know what consumers read, so consumers act as tolerant readers, the provider splits breaking changes into expand-contract steps, and consumer-driven contract tests show whom a change would break before it is deployed. Real Pact verification output between a TypeScript consumer and a .NET provider, Deprecation/Sunset headers, and the cost of versioning at the service level.
API Gateway and Backend for Frontend: What Belongs at the Edge and What Doesn't
An API Gateway does the edge work that's the same for every client (routing, TLS termination, token validation, rate limiting); aggregation, response shaping and token handling specific to one user experience belong in a Backend for Frontend owned by that experience's team, and business rules go in neither. A real BFF endpoint that calls three services in parallel for the book detail page and survives an Inventory outage, RFC 10017's BFF recommendation, and the god gateway trap.
Service Discovery: Client-Side, Server-Side, Kubernetes DNS and .NET Service Discovery
Service discovery turns a logical name like "Inventory" into the addresses of the instances that are healthy right now; Kubernetes does it server-side with Services and DNS, and in .NET Microsoft.Extensions.ServiceDiscovery finds addresses from configuration in development and from the platform's DNS in the cluster with the same code. Real round-robin output, a dead instance left in the list failing a third of the requests, and when a service mesh isn't needed.
Microservices in Production: Distributed Tracing, Resilience and Independent Deployment
Running microservices in production takes three things: distributed tracing that follows a request across services (with W3C traceparent), timeouts, retries and circuit breakers thought through at the service level, and independent deployment of every service with its own pipeline, backward compatibility and contract tests. Real trace output with .NET's Activity, retries per layer turning into 64 requests, the trap of tying readiness to downstreams, and where can-i-deploy fits in CI.