Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
UI Mimari Pattern'leri Neden Var? Separated Presentation ve MVC'den Signal'lara Kısa Tarihçe
UI mimari pattern'leri tek bir problemi çözmek için var: ekran kodu ile domain mantığı iç içe geçince ikisi de değiştirilemez ve test edilemez hâle geliyor. Bu yazıda Bookstore'un sipariş formunu tüm mantığı event handler'da olan Smart UI hâlinden Separated Presentation'a taşıyor, view state ile domain state'i ayırıyor ve MVC'den signal'lara uzanan tarihçeyi her pattern'in çözdüğü problemle birlikte görüyoruz.
MVC Pattern'i: Orijinal Smalltalk MVC ile Web MVC Aynı Şey Değil
Smalltalk-80'deki orijinal MVC'de view'lar model'i observe eder ve controller yalnızca kullanıcı input'unu yorumlar; Web MVC'de ise view model'i hiç observe etmez, her HTTP request'te controller bir kez çalışır ve view bir kez render edilir. Aynı sipariş formunu önce TypeScript'te observable bir model ile, sonra ASP.NET Core MVC ile kurup iki akışı, fat controller ve anemic view model tuzaklarını karşılaştırıyoruz.
MVP Pattern'i: Passive View, Supervising Controller ve Test Edilebilir Presenter
MVP'de view bir interface'in arkasına çekilir ve tüm ekran mantığı presenter'a taşınır; böylece presenter, DOM olmadan sahte bir view ile milisaniyeler içinde test edilir. Sipariş formunu TypeScript'te OrderFormView interface'i, DOM implementasyonu ve Vitest testleriyle kuruyor, Passive View ile Supervising Controller farkını ve presenter'ın şişmesini önlemenin yolunu görüyoruz.
MVVM ve Presentation Model: Data Binding, Command ve ViewModel
MVVM, Fowler'ın Presentation Model'inin data binding üzerine kurulmuş hâlidir: ViewModel view state'i ve view logic'i taşır, view ile senkronizasyonu binding yapar, kullanıcı aksiyonları CanExecute'u olan command'lara dönüşür. Sipariş formunun ViewModel'ini C#'ta CommunityToolkit.Mvvm 8.4 source generator'larıyla ve Angular 22'de signal'larla yazıyor, ikisini de view olmadan test ediyor ve binding'in sessiz hatalarını gerçek çıktılarla görüyoruz.
Framework'lerde Karşılıkları: Angular MVC mi, MVVM mi? React, Blazor, WPF ve ASP.NET Core
Angular ne klasik MVC ne de saf MVVM'dir: component class bir ViewModel gibi view state ve view logic taşır, template ona bağlanır, signal'lar ise UI'ı React'teki gibi state'ten türetir. Aynı sipariş formunu React, Blazor ve Razor Pages ile de yazıp çalıştırıyor, framework'leri etiketle değil üç soruyla (state nerede, senkronizasyon nasıl, view'sız test mümkün mü) okumayı gösteriyoruz.
Flux ve Unidirectional Data Flow: Two-Way Binding Neden Ölçeklenmedi?
Two-way binding ve birbirini güncelleyen observable model'ler, sonucu listener sırasına bağlı cascading update'ler ve hiç geçerli olmamış ara state'ler (glitch) üretir; Flux bunu tek yönlü akışla (action → dispatcher → store → view) çözdü. Aynı sipariş formunda bu glitch'i gerçek çıktıyla gösteriyor, Redux'un üç prensibini ve Elm Architecture'ı işliyor, 40 satırlık bir TypeScript store yazıp immutability'nin ve boilerplate'in bedelini tartışıyoruz.
Angular'da Unidirectional Data Flow: Signal, input/output ve Service'te State
Angular'da unidirectional data flow, state'in tek sahibinin olması, verinin input() ile aşağı inmesi, değişiklik isteklerinin output() ile yukarı çıkması ve türetilmiş değerlerin computed() ile hesaplanmasıdır. Effect ile yazılan state'in geride kaldığını, model()'in iş kuralını atlattığını ve default OnPush'un yerinde değiştirilen array'i görmediğini gerçek testlerle gösteriyor, state'i signal tutan bir service'e taşıyoruz.
Component Architecture: Container ve Presentational Component'ler, Composition ve Contract'lar
Container component veriyi ve yan etkileri bilir, presentational component yalnız input alıp output ile ne olduğunu bildirir; bu ayrım katı bir kural değil, test edilebilirlik ve yeniden kullanım için bir düşünme aracıdır. Bookstore'un ürün listesini üç component'e bölüyor, input adını değiştirmenin NG8002/NG8008 hatası verdiğini, content projection'ı ve presentational testin ne kadar hafif olduğunu gerçek çıktılarla gösteriyoruz.
Büyük Angular Uygulamasında Sınırlar: Feature Folder, Facade ve Katmanlar
Büyük bir Angular uygulamasında kodu feature'a göre klasörlemek, her feature'ı ui, state, data ve domain katmanlarına ayırmak ve feature'lar arası import'u yalnız public API (index.ts) üzerinden, lint ile zorlanan kurallarla serbest bırakmak gerekir; derleyici bu sınırları bilmez. Üç kestirmenin ng build'den geçip eslint-plugin-boundaries'e takıldığını gerçek çıktıyla gösteriyor, facade service'i ve API client katmanını işliyoruz.