Mert Özen Further With Every Line

Blog

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

Series
122 posts found
The Limits of Functional Programming: Performance, Readability and Pragmatic Team Use
Software Design PART 09

The Limits of Functional Programming: Performance, Readability and Pragmatic Team Use

The cost of functional programming in C# is usually not where people expect: measured, LINQ is nanoseconds slower than a loop for a small cart, Option's cost comes from closures more than from being a struct or a class, and carrying expected errors as exceptions is a hundred times more expensive than Result. We show the BenchmarkDotNet results, stack traces in composition, which ideas pay off in a team, F#, and where Bookstore ended up.

15 Nov 2026 14 min 12
C# 15 Union Types and Closed Hierarchies: Real Sum Types and Exhaustive Pattern Matching
Software Design PART 08

C# 15 Union Types and Closed Hierarchies: Real Sum Types and Exhaustive Pattern Matching

C# 15 union types combine independent types into a closed set, and the closed modifier limits the direct subtypes of a class hierarchy to its assembly; in both cases the compiler names the missing case. We turn Bookstore's OrderStatus into a closed hierarchy and Result and its error codes into unions, and show how System.Text.Json serializes each, how they compare with TypeScript, and the binary breaking change risk in a public API, all with real output.

15 Nov 2026 15 min 13
Result and Railway-Oriented Programming: Errors as Values and Accumulating Validation
Software Design PART 07

Result and Railway-Oriented Programming: Errors as Values and Accumulating Validation

Railway-oriented programming connects steps that can fail into a two-track flow with Bind: if a step fails, later steps don't run and the error is carried to the end as a value, while errors from independent form fields are accumulated. We build Bookstore's order flow with Map, Bind, Ensure, Tap and Match, and show Task<Result<T>> chains, mapping to TypedResults and ValidationProblem, the Angular UI state and the line between exceptions and Result, all with real output.

15 Nov 2026 17 min 11
Option and Escaping Null: the Maybe Type, Map, Bind and the Secret of LINQ Query Syntax
Software Design PART 06

Option and Escaping Null: the Maybe Type, Map, Bind and the Secret of LINQ Query Syntax

Option expresses "no value" as a type and makes you answer "what if there isn't one?" before you reach the value; nullable reference types are enough in most places, but Option pays off in chained computations and nested kinds of absence. We build Bookstore's coupon calculation with our own Option<T> using Map, Bind and Match, and show why LINQ query syntax works once Select/SelectMany exist, along with the map + flatten intuition behind monads.

15 Nov 2026 15 min 12
Algebraic Data Types: Product and Sum Types, Discriminated Unions and Making Illegal States Unrepresentable
Software Design PART 05

Algebraic Data Types: Product and Sum Types, Discriminated Unions and Making Illegal States Unrepresentable

Algebraic data types combine types with "and" (product types) or "or" (sum types) so that the number of combinations in the model equals the number of states in the business rule, making impossible states impossible to build. We turn Bookstore's flagged order status into a sum type with abstract records, write transitions with types, and show why C# 14 wants a _ arm, TypeScript discriminated unions, JSON polymorphism and C# 15 union types with real compiler output.

15 Nov 2026 14 min 12
Higher-Order Functions and Composition: map/filter/reduce, Currying and Building Pipelines
Software Design PART 04

Higher-Order Functions and Composition: map/filter/reduce, Currying and Building Pipelines

A higher-order function takes or returns functions; composition connects them into a new function, and its order is a business rule. We combine Bookstore's coupon and member discount as Func<decimal, decimal> rules with Then, Compose and Pipe, test that the order changes the result by 1.50 TL, and show fold, currying, a TypeScript pipe and the cost of closure allocations with real output.

15 Nov 2026 12 min 12
Pure Functions and Side Effects: Referential Transparency, Hidden Inputs and Testability
Software Design PART 03

Pure Functions and Side Effects: Referential Transparency, Hidden Inputs and Testability

A pure function always gives the same result for the same input and leaves no trace outside; such a call can be replaced by its value. Starting from decimal.Parse reading 189.50 as 18950 under the Turkish culture, we separate Bookstore's discount calculation from the clock, the console and static state, test it with xUnit theories and no fakes, and show memoization and the purity assumption of Angular computed() and pure pipes with real output.

15 Nov 2026 12 min 11
Immutability: Why Unchanging Data? record, readonly and TypeScript Readonly in Practice
Software Design PART 02

Immutability: Why Unchanging Data? record, readonly and TypeScript Readonly in Practice

Immutability means a value can't be changed after creation and every change produces a new value; it solves aliasing, lost cache keys and race conditions at the same point. We rewrite Bookstore's cart with record, with and ImmutableList, and show with real output shallow immutability, the cost of copying, the limits of TypeScript readonly and Object.freeze, and why an array pushed in place doesn't update an Angular signal.

15 Nov 2026 13 min 8
What Is Functional Programming? Declarative Thinking for C# and TypeScript Developers
Software Design PART 01

What Is Functional Programming? Declarative Thinking for C# and TypeScript Developers

Functional programming means building a computation as a combination of functions that take and return values, rather than as commands that change values step by step. Using Bookstore's checkout code that silently changes the cart, we show the difference between imperative and declarative code, first-class functions, a short history and the functional ideas you already use in LINQ, RxJS and Angular signals, with real output.

15 Nov 2026 12 min 7
Refactoring Catalog 7: Dealing with Inheritance — Pull Up/Push Down, Extract Superclass, Replace Type Code with Subclasses and Replace Subclass with Delegate
Software Design PART 16

Refactoring Catalog 7: Dealing with Inheritance — Pull Up/Push Down, Extract Superclass, Replace Type Code with Subclasses and Replace Subclass with Delegate

Inheritance refactorings move shared code up to a base class, move misplaced code back down, and replace inheritance with delegation when you hit its limits. The post transforms Bookstore's book and wishlist classes with eleven refactorings, showing with real output the calls that bypass the Add hidden by a List subclass, what the compiler points to during Push Down and the discriminator in a TPH table, and closes the series with all 66 refactorings.

15 Nov 2026 18 min 13
Refactoring Catalog 6: Refactoring APIs — Separate Query from Modifier, Remove Flag Argument, Parameterize Function, Factory Functions and Commands
Software Design PART 15

Refactoring Catalog 6: Refactoring APIs — Separate Query from Modifier, Remove Flag Argument, Parameterize Function, Factory Functions and Commands

API refactorings make the methods a class exposes clearer, safer and easier to test; but in an API shipped as a package, even adding a parameter with a default value breaks code that isn't recompiled. The post transforms Bookstore's Notifications module with twelve refactorings, showing with real output the old contract kept alive with [Obsolete], the CS0200 and CS0618 diagnostics, and the MissingMethodException of an old app running against the new DLL.

15 Nov 2026 17 min 12
Refactoring Catalog 5: Simplifying Conditional Logic — Decompose/Consolidate Conditional, Guard Clauses, Replace Conditional with Polymorphism and Introduce Special Case
Software Design PART 14

Refactoring Catalog 5: Simplifying Conditional Logic — Decompose/Consolidate Conditional, Guard Clauses, Replace Conditional with Polymorphism and Introduce Special Case

Conditional refactorings turn complex ifs into named functions, guard clauses, switch expressions or polymorphism; but a special case that removes null checks can also remove a side effect the check was quietly preventing. The post transforms Bookstore's CheckoutPolicy with seven refactorings, showing with real output dotnet format's IDE0066 fix, a special case that shows a guest 12 points while the tests stay green, and a Debug.Assert that disappears in a Release build.

15 Nov 2026 15 min 13
Blog Map