Mert Özen Further With Every Line

Blog

Mert Özen's blog posts on software development, backend, frontend, and DevOps.

Series
498 posts found
Liskov Substitution Principle: Behavioral Subtyping and NotSupportedException in .NET
Software Design PART 05

Liskov Substitution Principle: Behavioral Subtyping and NotSupportedException in .NET

LSP requires a subtype to satisfy not just the compiler but the base type's contract: preconditions aren't strengthened, postconditions aren't weakened, invariants and the history constraint are preserved. Three real violations in Bookstore's stock module, the NotSupportedException that T[] and ReadOnlyCollection throw from IList<T>.Add, capability queries with Stream.CanSeek, and verifying the contract against every implementation with an abstract xUnit test class.

7 Nov 2026 15 min 4
Open/Closed Principle: Extending Without Modifying and the Speculative Generality Trap
Software Design PART 04

Open/Closed Principle: Extending Without Modifying and the Speculative Generality Trap

OCP means adding new behavior as a new implementation without opening existing, working code; but any code can only be closed against a particular axis of change. Closing a growing notification switch with INotificationChannel and .NET 8 keyed services, HttpClient's DelegatingHandler chain, lightweight extension points with Func, and the cost of speculative generality.

7 Nov 2026 12 min 2
Single Responsibility Principle: Not "One Thing" but One Actor
Software Design PART 03

Single Responsibility Principle: Not "One Thing" but One Actor

SRP does not mean "a class does one thing"; in Martin's definition a module should be responsible to one actor, the single person or group that requests the same change. An Employee example where an accounting change breaks the HR report, sharing data while separating behavior, a Facade, .NET's Stream/StreamWriter/Encoding split and the fragmentation trap.

7 Nov 2026 13 min 6
Coupling and Cohesion: Two Measures of Good Design, Connascence and the Law of Demeter
Software Design PART 02

Coupling and Cohesion: Two Measures of Good Design, Connascence and the Law of Demeter

Good design means weak links between parts (coupling) and strong unity inside each part (cohesion); connascence grades those links by kind, and the Law of Demeter limits how far objects reach into each other. Kinds of coupling and levels of cohesion, connascence of position in a six-parameter constructor, the TimeSpan(10) trap, and protecting a wallet balance with Tell, Don't Ask.

7 Nov 2026 15 min 5
Why Design Principles Exist: Change, Dependencies and a Short History of SOLID
Software Design PART 01

Why Design Principles Exist: Change, Dependencies and a Short History of SOLID

Design principles exist to name the unplanned dependencies that make change expensive and to draw boundaries around them: rigidity, fragility, immobility and viscosity share dependency as their root. The history from Parnas's information hiding to Feathers's SOLID acronym, and the series' Bookstore order and notification example.

7 Nov 2026 13 min 7
Bulk Import with a Validation Report: Upload Excel/CSV, Staging Table, Row-Level Error File
Software Design PART 22

Bulk Import with a Validation Report: Upload Excel/CSV, Staging Table, Row-Level Error File

The safe way to bring in a large, dirty Excel/CSV file is to load it into a text-column staging table with SqlBulkCopy, apply the rules to every row with set-based SQL, give the user a row-level error file and make the commit a separate, confirmed step. This post walks through a 20,000-row import with real output, including 202 Accepted plus a status endpoint, idempotency via a file hash and escaping against CSV injection.

7 Nov 2026 19 min 9
Pagination Strategies in Depth: Offset, Keyset and Opaque Cursor Tokens
Software Design PART 21

Pagination Strategies in Depth: Offset, Keyset and Opaque Cursor Tokens

On large, changing tables keyset pagination removes offset's depth-dependent cost and page drift: in a 2-million-row test, page 5000 read 375 logical pages with offset and 6 with keyset. This post shows, with real measurements, the tie-breaker keyset condition on SQL Server, an HMAC-signed opaque cursor, the previous page and the nullable sort column trap.

7 Nov 2026 17 min 6
Optimistic Concurrency End to End: From rowversion to ETag, If-Match, 412 and a Conflict UI
Software Design PART 20

Optimistic Concurrency End to End: From rowversion to ETag, If-Match, 412 and a Conflict UI

Building optimistic concurrency end to end on the web means exposing rowversion as an ETag, requiring If-Match on updates (428 otherwise), returning 412 with the current values on a mismatch and doing a field-level three-way merge on the client. As a follow-up to the EF Core Concurrency post, this post shows the HTTP and Angular side with real output.

7 Nov 2026 15 min 8
Idempotency Keys: Not Creating the Same Order Twice on Double Clicks and Retries
Software Design PART 19

Idempotency Keys: Not Creating the Same Order Twice on Double Clicks and Retries

The reliable way to stop the same order from being created twice on double clicks and retries is for the server to store a client-generated Idempotency-Key per user together with a request hash, and to write the work and the 'completed' record in the same transaction. This post covers the current status of the IETF draft (draft-08, not an RFC), the 400/409/422 rules and an ASP.NET Core endpoint filter + SQL Server implementation with real output.

7 Nov 2026 18 min 10
Time and Time Zones: UTC Instants, Local Business Dates, DateOnly and TimeProvider
Software Design PART 18

Time and Time Zones: UTC Instants, Local Business Dates, DateOnly and TimeProvider

Storing time correctly means separating three concepts: event moments are UTC instants (DateTimeOffset), calendar days are DateOnly, and future local events are wall-clock time plus an IANA zone id. This post shows, with real output, how to turn a tenant's day into a UTC range, a testable clock with TimeProvider, the AT TIME ZONE traps in SQL Server and the date shift in Angular.

7 Nov 2026 15 min 9
Money and Rounding: decimal, a Money Value Object, VAT and Distributing Cents
Software Design PART 17

Money and Rounding: decimal, a Money Value Object, VAT and Distributing Cents

Modeling money correctly takes a Money value object that carries the amount with its currency, the same explicit rounding rule in C# and SQL, and Allocate instead of division so no cent is lost. The post shows Math.Round and SQL ROUND disagreeing on 0.125, the 1-cent difference between per-line and total VAT, an effective-dated VAT rate table (20%, 10%, 1% as of November 2026), EF Core complex type mapping and string amounts in JSON, with real output.

7 Nov 2026 14 min 10
Numbering: Invoice and Order Numbers, Gapless Sequences and Yearly Resets
Software Design PART 16

Numbering: Invoice and Order Numbers, Gapless Sequences and Yearly Resets

An invoice number that must be consecutive shouldn't come from an identity, MAX + 1 or a SEQUENCE, but from a locked UPDATE on a counter table keyed by (Series, Year) inside the approval transaction; for order numbers where gaps are acceptable, a SEQUENCE is enough. The post shows GİB's 16-character document number format, gapless numbering under 50 concurrent approvals, the effect of lock duration on throughput and yearly resets by invoice date, with real output.

7 Nov 2026 13 min 9
Blog Map