Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
GoF Dışında Bilmen Gereken Kod Seviyesi Pattern'ler: Null Object, Specification, Result ve Pipeline
GoF kataloğunda olmayan dört pattern günlük C# kodunda sürekli işe yarar: Null Object ve Special Case "yok" durumunu davranışı olan bir object'e çevirip null kontrollerini kaldırır, Specification iş kuralını EF Core'un SQL'e çevirebileceği birleştirilebilir bir Expression olarak taşır, Result adımları Then ile hata akışına bağlar, Pipeline da dönüşümleri sıralı filter'lara böler. Func ile yazılan kuralın bütün tabloyu çekmesi, ExpressionVisitor ile parametre birleştirme ve Options pattern.
Anti-Pattern'ler: God Object, Service Locator, Singleton Abuse, Anemic Domain Model ve Pattern Hastalığı
Anti-pattern, ilk bakışta makul görünen ama aynı sıkıntıyı tekrar tekrar üreten bir çözümdür ve tanımak, onu daha iyi bir yapıya taşıyan refactoring'i de bilmek demektir. Service Locator'ın ValidateOnBuild'den kaçırdığı bağımlılık, CA1506 ile ölçülen God Object, sıraya göre kırılan singleton test'leri, kuralı atlanan anemic model, Golden Hammer, Lava Flow, Poltergeist ve patternitis.
Visitor Pattern: Double Dispatch, ExpressionVisitor ve Pattern Matching ile Karşılaştırma
Visitor, C#'ın tek boyutlu virtual dispatch'ini Accept ve Visit çağrılarıyla ikiye katlayarak sabit bir tip hiyerarşisine element'lere dokunmadan yeni işlemler eklemeyi sağlar; bedeli, yeni bir tipin bütün visitor'ları kırmasıdır. Overload seçiminin static tip tuzağı, expression problem, ExpressionVisitor ve Roslyn CSharpSyntaxWalker, ve exhaustiveness kontrolü olmayan switch expression ile karşılaştırma.
Template Method Pattern: Algoritma İskeleti, Hook'lar ve Delegate'li Alternatifi
Template Method, algoritmanın iskeletini base class'taki override edilemeyen bir method'a sabitler ve değişen adımları abstract method'lara ya da boş hook'lara bırakır. Unutulan override'ın sessizce yutulan hook'u (CS0114), Stream.CopyTo ve .NET 10'da davranışı değişen BackgroundService.ExecuteAsync, constructor'dan virtual çağrı tuzağı (CA2214) ve aynı akışı delegate'lerle composition ile kurmak.
Strategy Pattern Derinlemesine: Keyed Services, IEnumerable<IStrategy> ve Func ile Runtime Seçim
Strategy'yi yazmak kolay, zor olan doğru strategy'yi runtime'da seçmek: keyed services tek bir key'le, IEnumerable<IStrategy> ve CanHandle object'in birden fazla özelliğine bakarak, Dictionary<string, Func<>> ise bağımlılığı olmayan formüllerde en az törenle seçer. Kayıt sırasının sessizce fiyat değiştirmesi, keyed kayıtların GetServices'te görünmemesi ve BCL'deki IComparer ile StringComparer örnekleri.
State Pattern: Sipariş Durumlarını switch Yerine State Object'leriyle Yönetmek
State pattern, durumla değişen davranışı her method'daki switch'ten alıp durum başına bir class'a taşır; base class'ın varsayılan cevabı "izin yok" olunca unutulan bir durum sessiz bir hata değil, gürültülü bir exception olur. Yeni eklenen OnHold durumunun kargoya izin verdiği naif koddan başlayıp state class'larını, derleyicinin async state machine'ini, tuple pattern'li switch expression alternatifini ve EF Core'da enum kolondan state object'ini yeniden kurmayı gerçek çıktılarla görüyoruz.
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ğı.