Mert Özen Further With Every Line

Blog

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

Series
12 posts found
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 5
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 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 3
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 1
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 3
Interface Segregation Principle: Fat Interfaces and Role Interfaces
Software Design PART 06

Interface Segregation Principle: Fat Interfaces and Role Interfaces

ISP means no client should be forced to depend on methods it doesn't use, and interfaces are cut by client (role interfaces), not by class. One method added to a 14-method IOrderRepository breaking three files, splitting into read/write/report roles and forwarding in DI, IReadOnlyList<T> and IList<T> still separate in .NET 10, single-method interface inflation and the cost of piercing ISP with default interface methods.

7 Nov 2026 12 min 3
Dependency Inversion Principle: DIP vs DI vs IoC and the Composition Root
Software Design PART 07

Dependency Inversion Principle: DIP vs DI vs IoC and the Composition Root

DIP asks for the compile-time dependency to flow from details to abstractions and for the abstraction to be owned by its user; DI is only the technique of supplying dependencies from outside, and IoC is control of the flow moving to a framework. Which project the interface belongs in, using Program.cs as the composition root, and why a service locator defeats DIP.

7 Nov 2026 12 min 5
DRY, KISS and YAGNI: Duplication, Simplicity and "You Aren't Gonna Need It"
Software Design PART 08

DRY, KISS and YAGNI: Duplication, Simplicity and "You Aren't Gonna Need It"

DRY means a single source for knowledge, not for code; merging two rules that change for different reasons just because they look alike is not DRY but a wrong abstraction. Backing out of a wrong abstraction as Metz suggests, the rule of three, measuring KISS with CA1502, and the four costs Fowler lists for YAGNI.

7 Nov 2026 12 min 3
Composition over Inheritance: Fragile Base Class, Delegation and Pluggable Behavior
Software Design PART 09

Composition over Inheritance: Fragile Base Class, Delegation and Pluggable Behavior

Inheritance ties a subclass to its base class's implementation details, so a harmless change in the base class can silently break a subclass, while composition and delegation depend only on the contract. The fragile base class problem shown with real output, the class explosion when behavior grows along two axes, and where inheritance is right: Collection<T> hooks and sealed.

7 Nov 2026 13 min 3
Lesser-Known Principles: Separation of Concerns, Least Astonishment, Fail Fast, CQS and GRASP
Software Design PART 10

Lesser-Known Principles: Separation of Concerns, Least Astonishment, Fail Fast, CQS and GRASP

The principles outside SOLID drive most everyday decisions: Fail Fast catches errors at startup, CQS keeps a question from changing the answer, and GRASP asks which class a responsibility belongs to. Catching a configuration typo with options validation, the Math.Round surprise, side effects in getters, Explicit Dependencies, Persistence Ignorance and deciding when principles collide.

7 Nov 2026 12 min 5
Component Principles: Splitting a .NET Solution into Projects (REP, CCP, CRP, ADP, SDP, SAP)
Software Design PART 11

Component Principles: Splitting a .NET Solution into Projects (REP, CCP, CRP, ADP, SDP, SAP)

When splitting a solution into projects, classes that change together belong in the same project, dependencies must be acyclic and flow toward stability, and stable projects should be abstract. Measuring the cost of a Common project everyone depends on, computing instability and abstractness on a real solution, and reading the main sequence correctly.

7 Nov 2026 12 min 3
Critiquing the Principles: CUPID, Over-Engineering and Where SOLID Really Pays Off
Software Design PART 12

Critiquing the Principles: CUPID, Over-Engineering and Where SOLID Really Pays Off

SOLID's value depends on context: in multi-team, long-lived, frequently changing code it lowers the cost of change, while in scripts, prototypes and small CRUD apps it often just adds layers. The measured cost of adding a push channel to minimal, balanced and excessive designs of the same notification feature, Dan North's CUPID proposal and Ousterhout's deep module warning.

7 Nov 2026 11 min 4
Blog Map