Mert Özen Further With Every Line

Blog

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

Series
22 posts found #cozum-desenleri
What Is a Solution Pattern? Real-World Problems Missing from GoF and the Pattern Template
Software Design PART 01

What Is a Solution Pattern? Real-World Problems Missing from GoF and the Pattern Template

A solution pattern is a recurring application decision that, unlike the code-structure patterns of GoF (the Gang of Four), cuts across data, API and UI together (soft delete, sentinel values, a virtual root). This post introduces the series' Pattern Template, its fixed trade-off criteria and the schema of the HR Portal sample application.

7 Nov 2026 15 min 3
The Shadow Record: A Virtual Root That Doesn't Exist in the Database — "Company = 0" Above Departments
Software Design PART 02

The Shadow Record: A Virtual Root That Doesn't Exist in the Database — "Company = 0" Above Departments

A "Company = 0" root that doesn't exist in the database works safely if 0 is turned into a DepartmentScope type (null inside) right at the API boundary; carry 0 as a plain int and you get empty lists on reads and FK violations on writes. The post compares the virtual root, a real root row, a Company entity and an explicit scope contract with their trade-offs.

7 Nov 2026 15 min 8
Sentinel Values: The Hidden Cost of 0, -1, "1900-01-01" and 9999-12-31
Software Design PART 03

Sentinel Values: The Hidden Cost of 0, -1, "1900-01-01" and 9999-12-31

Sentinel values (0 in salary, 9999-12-31 in an end date, 1900-01-01 in a date) silently corrupt aggregates: in the example the average salary comes out as 51,000 instead of 85,000. The fix is usually a nullable column, a separate state field when absence has several meanings and a Special Case type in the domain; a sentinel can be a deliberate standard only when a single producer owns it (temporal tables, a persisted computed column).

7 Nov 2026 15 min 5
Exposing Ids: int Identity, GUID v7 and the Public Id Split
Software Design PART 04

Exposing Ids: int Identity, GUID v7 and the Public Id Split

The most balanced way to expose an id is a bigint identity as the internal clustered key, an immutable unique PublicId outside, and an ownership condition in every query. In our measurement Guid.CreateVersion7 fragmented as badly as v4 in SQL Server (99 percent, 4,987 pages), because SQL Server sorts uniqueidentifier by its last 6 bytes; EF Core's sequential generator stayed close to identity.

7 Nov 2026 13 min 5
Enum or Lookup Table? Keeping Reference Data in Code and in the Database
Software Design PART 05

Enum or Lookup Table? Keeping Reference Data in Code and in the Database

Closed lists that drive code behavior (order status) should stay enums with a database mirror seeded via HasData and linked by an FK, while open lists managed by the business (expense type) should live in a lookup table with IsActive and change without a deploy. The post shows the renumbering and string-enum rename traps with real output.

7 Nov 2026 13 min 7
Doing Soft Delete Right: IsDeleted, DeletedAt, Filtered Unique Indexes and Archive Tables
Software Design PART 06

Doing Soft Delete Right: IsDeleted, DeletedAt, Filtered Unique Indexes and Archive Tables

To do soft delete right, filter unique indexes with WHERE DeletedAt IS NULL, link records deleted in the same operation with a DeletionId, and answer KVKK/GDPR erasure requests with anonymization rather than soft delete. If restore isn't a real requirement, an archive table or hard delete plus audit is the simpler choice.

7 Nov 2026 15 min 8
Audit Trail: Who Changed What, When and Why?
Software Design PART 07

Audit Trail: Who Changed What, When and Why?

For a reliable audit trail, write changes with a SaveChangesInterceptor as per-property old/new values plus user, correlation id and reason, in the same transaction as the business data; mask personal data and make the table append-only. Cover paths that bypass the interceptor, such as ExecuteUpdate, with summary entries and a temporal table safety net.

7 Nov 2026 14 min 7
Temporal Data: Effective-Dated Records, Price History and the Bitemporal Model
Software Design PART 08

Temporal Data: Effective-Dated Records, Price History and the Bitemporal Model

Data with retroactive corrections needs two time axes: valid time (which date the fact is true for) and transaction time (when it was recorded). A SQL Server temporal table only gives transaction time; make a table with half-open [ValidFrom, ValidTo) intervals system-versioned and you can write bitemporal queries with EF Core 10.

7 Nov 2026 12 min 5
When the Status Column Is Updated from Everywhere: Transition Tables, State Machines and Status History
Software Design PART 09

When the Status Column Is Updated from Everywhere: Transition Tables, State Machines and Status History

Stop treating the status column as a field any endpoint can write: let the client send an action instead of a status, keep allowed transitions in one place (a transition table, domain methods or Stateless), write every transition with its reason to a status history in the same transaction, and use a rowversion to stop double approvals.

7 Nov 2026 12 min 7
Hierarchical Data in SQL: Adjacency List, Recursive CTE, Closure Table and hierarchyid
Software Design PART 10

Hierarchical Data in SQL: Adjacency List, Recursive CTE, Closure Table and hierarchyid

When subtree queries on a department tree are frequent and moves are rare, SQL Server's hierarchyid (with LINQ support since EF Core 8) plus a ParentId for FK integrity is a good choice; use a closure table if you need database independence. Walking the tree node by node in the application causes N+1, and cycles should be blocked at move time with IsDescendantOf.

7 Nov 2026 14 min 3
Polymorphic Associations: Attaching Comments and Files to Multiple Tables
Software Design PART 11

Polymorphic Associations: Attaching Comments and Files to Multiple Tables

Linking attachments to several tables with an EntityType/EntityId pair loses FKs, cascade delete and safe authorization; when owner types are few and stable, use an exclusive arc with one nullable FK per owner and a check constraint requiring exactly one. Derive authorization from the owner's policy, not from the attachment itself.

7 Nov 2026 12 min 7
Multilingual Data: Storing Names in Turkish and English — Translation Tables, JSON Columns and Fallback
Software Design PART 12

Multilingual Data: Storing Names in Turkish and English — Translation Tables, JSON Columns and Fallback

For multilingual data managed by users, the most flexible option is a translation table keyed by (EntityId, Culture, Name) plus a fallback chain such as en-GB → en → tr built in one place. The post compares one column per language, translation tables, SQL Server 2025 json columns and a separate translation service, and shows the fallback with EF Core 10 LeftJoin and collation choice for the Turkish I with real output.

7 Nov 2026 14 min 7
Blog Map