Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
Observer Pattern Derinlemesine: event, IObservable<T>, IChangeToken ve Domain Event'ler
Observer, bir object'in durumu değiştiğinde ona bağlı object'lerin haberdar edilmesidir; C#'ta event, BCL'de IObservable<T>/IObserver<T>, ASP.NET Core'da IChangeToken ve IOptionsMonitor olarak karşına çıkar. Kayıttan önce tetiklenen bir event'in gönderdiği hayalet onay e-postasından başlayıp OnNext/OnError/OnCompleted sözleşmesini, Rx.NET operatörlerini, tek kullanımlık change token'ları ve kayıttan sonra izole dağıtılan domain event'leri gerçek çıktılarla inceliyoruz.
Memento Pattern: Snapshot Almak, Geri Yüklemek ve Encapsulation'ı Bozmamak
Memento, bir object'in iç durumunu encapsulation'ı bozmadan dışarı alıp sonra geri yüklemeyi sağlar; C#'ta bunun en temiz yolu private nested bir record ve caretaker'a gösterilen dar bir interface'tir. with expression'ının shallow kopya tuzağını, ödeme sihirbazında kapasiteli undo'yu, Utf8JsonReader'ın JsonReaderState'ini, Command ile undo'yu, JSON'a yazılan snapshot'ın sürümlenmesini ve immutable state ile bellek farkını gerçek çıktılarla görüyoruz.
Mediator Pattern: Object'ler Arası Konuşmayı Merkezileştirmek ve "MediatR'a Gerçekten İhtiyacım Var mı?"
Mediator, birbirini doğrudan çağıran bileşenlerin etkileşim kurallarını tek bir object'e toplar; MediatR ise bu pattern'den çok request tipine göre handler bulan bir in-process dispatcher'dır. Ödeme ekranında birbirini tanıyan bileşenlerin ürettiği hatayı bir CheckoutForm mediator'ıyla düzeltiyor, Blazor'un EditContext'ini gerçek bir örnek olarak inceliyor, ardından aynı sipariş işini MediatR 14.3, düz bir service class ve 30 satırlık kendi dispatcher'ımızla yazıp karşılaştırıyoruz.
Iterator ve Interpreter: C#'ın İçine Gömülmüş İki Pattern — yield return ve Expression Tree
Iterator, bir collection'ın içini göstermeden element'lerini sırayla dolaşmayı sağlar ve C#'ta IEnumerable, IEnumerator ve yield return olarak dilin içindedir; Interpreter ise küçük bir dilin gramerini bir AST olarak temsil edip yorumlar. Sayfalı bir katalog API'sini yield ve IAsyncEnumerable ile okumayı, kampanya kuralları için küçük bir kural dili yazıp onu Expression tree'ye derlemeyi, Regex'in içindeki interpreter'ı ve dinamik expression'larda güvenlik sınırını gerçek çıktılarla görüyoruz.
Command Pattern: İsteği Object'e Çevirmek, Undo/Redo ve Kuyruğa Atmak
Command, bir isteği object olarak paketler; böylece invoker ne yapıldığını bilmeden çalıştırabilir, geri alabilir, queue'ya koyabilir ve loglayabilir. Bookstore katalog editöründe undo/redo stack'i ve MacroCommand, BCL'deki System.Windows.Input.ICommand, command'ı System.Text.Json ile serialize edip Channel üzerinden background'da çalıştırmak, GoF command'ı ile CQRS command'ının farkı, MediatR 13'ün lisansı ve kütüphanesiz bir dispatcher.
Chain of Responsibility: ASP.NET Core Middleware, DelegatingHandler ve Validation Zinciri
Chain of Responsibility, isteği gönderenle ele alan arasındaki coupling'i kırmak için isteği bir handler chain'i boyunca, biri ele alana kadar iletir; ASP.NET Core middleware'i ve DelegatingHandler bu pattern'in short-circuit edebilen biçimleri. Bookstore'da indirim onay chain'i, DI'da IEnumerable kayıt sırasının taşıdığı gizli iş kuralı, ilk hatada duran validation chain'i ile her şeyi toplayan pipeline farkı ve chain'in sonundan düşen istek tuzağı.
Proxy Pattern: Lazy Loading, Remote Proxy ve DispatchProxy ile Araya Girmek
Proxy, gerçek object ile aynı interface'i implement edip ona erişimi kontrol eder: oluşturmayı erteler (virtual), yetki kontrol eder (protection), uzaktaki bir servisi temsil eder (remote) ya da erişimde ek iş yapar (smart reference). EF Core'un Castle.Proxies.AuthorProxy'si ve gizlediği N+1, Lazy<T> ile virtual proxy, typed HttpClient'ın remote proxy olması, DispatchProxy'nin async ve TargetInvocationException tuzakları ve Decorator ile farkı.
Flyweight Pattern: Paylaşılan State ile Bellek Kazanmak — string.Intern ve ArrayPool
Flyweight, çok sayıda object'in tekrar eden ve değişmeyen kısmını (intrinsic state) bir factory üzerinden bir kez saklayıp paylaşır, satıra özel kısmı (extrinsic state) dışarıda tutar. Bir milyon satırlık raporda belleği 377 MB'tan 30 MB'a indiren BookInfoFactory, string.Intern'ün yan etkileri, .NET'in önceden paylaştığı Task ve array instance'ları, ArrayPool'un neden flyweight değil object pool olduğu ve BenchmarkDotNet ölçümleri.
Facade Pattern: Karmaşık Alt Sistemi Tek Kapıdan Sunmak
Facade, birden fazla subsystem'i doğru sırayla ve doğru compensation adımlarıyla kullanma bilgisini tek bir class'a toplar; subsystem'i kapatmadan client'a kolay bir giriş noktası verir. Bookstore'da stok, ödeme, fatura ve bildirimi koordine eden bir CheckoutFacade, File.ReadAllTextAsync ve GetFromJsonAsync'in arkasındaki gerçek kod, Facade'ın Service Layer, Adapter ve Mediator'dan farkı ve god facade tuzağı.
Decorator Pattern: Caching, Logging ve Retry'ı Koda Dokunmadan Eklemek
Decorator, aynı interface'i implement edip içindeki object'e iş devrederek ona runtime'da davranış ekler; decorator'ların sırası ne ölçtüğünü ve neyi koruduğunu belirleyen bir tasarım kararıdır. Bookstore kataloğuna cache, log ve retry eklemek, Stream ailesi ve leaveOpen ile sahiplik, DI'da elle registration ve Scrutor Decorate, DelegatingHandler ve default interface method'ların decorator'ı sessizce atlatması.
Composite Pattern: Ağaç Yapıları Tek Interface ile Gezmek
Composite, leaf'i ve onları içeren composite'i aynı interface arkasına koyarak client'ın tek bir item'la iç içe bir ağacı ayırt etmeden kullanmasını sağlar; recursion ağacı bilen tek yerde, composite'in içinde kalır. Bookstore'da iç içe kitap paketlerinin fiyatı, transparency ile safety tercihi, IConfiguration ve CompositeChangeToken örnekleri ve döngüsel ağacın stack overflow'u.
Bridge Pattern: Abstraction ile Implementation'ı Ayrı Ayrı Büyütmek
Bridge, iki bağımsız değişim eksenini (mesaj tipi ve kanal gibi) tek bir inheritance hiyerarşisine sıkıştırmak yerine iki hiyerarşiye ayırıp bir referansla bağlar; class sayısı çarpım yerine toplam olur. Bookstore bildirimlerinde 3 × 3 class patlamasından 3 + 3'e geçiş, HttpClient/HttpMessageHandler ve ILogger/ILoggerProvider köprüleri ve Adapter ile farkı.