JavaScript ve Aspect Oriented Programming

Merhaba, uzun zamandır bu konu hakkında bir şeyler yazmak istiyordum fakat iş yerindeki yoğunluktan dolayı vakit bulamamıştım. Kısmet bu zamanaymış. Aspect Oriented Programming (AOP) nedir? Kullanmalı mıyız? Nasıl kullanabiliriz? Nerede kullanabiliriz? JS’de nasıl uygulayabiliriz gibi soruların cevabını vermeye çalışacağım.

AOP nedir? Neden kullanmalıyız ?

Kullandığımız yazılım dilleri sadece tek yazılım geliştirme yaklaşımını desteklemez. Birden fazla yaklaşımı uygulayarak kolay, kullanılabilir, esnek, okunabilir, çok kafa yormayan, bakımı kolay kod yazabilmemizi amaçlar. Object Oriented Programming (OOP) tabanlı dillerde yapılan işler davranışlarına göre sınıflara, paketlere ayrılarak yönetmeyi amaçlar. Fakat bu sınıflar arasında yapılan bazı işler davranışsal olarak birbirine benzeme eğilimindedir. Örnek vermek gerekirse veritabanı işlemlerinden sorumlu olan paketimiz içinde log tutma ihtiyacı duyuyorken network işlemlerinden sorumlu olan paketimizde log tutma ihtiyacı duyabiliyoruz. İki pakette de böyle bir ihtiyacın olması davranışsal olarak benzer işlerin yapılmasına neden olur. OOP, Separation of Concerns’i (ilgi-davranışların ayrılmasını) amaçlamasına rağmen bu gibi durumlarda isteklerimize cevap vermemektedir. AOP bu gibi problemlerde OOP’yi tamamlayan bir teknik olarak karşımıza çıkar. En çok ;

  • Kayıt tutma (Logging)
  • Doğrulama (Validation)
  • Ön bellekleme (Caching)
  • Hata Ayıklama (Exception Handling)
  • Yetkilendirme (Authorizing)
  • Performans Yönetimi
  • Transaction Yönetimi
  • Pooling

gibi işlemlerinde AOP’i kullanabiliyoruz.

Yukarıdaki koddan anlaşılacağı üzere User sınıfına ait metotlar çağrılırken hem o sınıfa ait işlemler yapılıyor hem de log atılıyor. Tam da istediğimiz işlemleri yapmasına rağmen sınıfların birbirine olan bağımlılıklarının artması projede işlerin iyi gitmediğini gösterir. SOLID prensiplerine uymayan bu tür kodlar projelerde okunabilirliği azaltır ve projenin bakım maliyeti artırır.

SOLID prensipleri de neymiş arkadaş benim kodum benim kararım diyen arkadaşlara tabi ki diyebileceğim bir şey yok. Sonuçta hepimiz özgür iradeye sahip insanlarız :)

JavaScript’de AOP’i uygulamanın bir kaç yolu mevut. JS’in ne kadar esnek bir dil olduğunu anlamamıza yarayacak bir örnekle başlayacağım.

JS’de sınıflara ait metotlar izin verildiği takdirde ezilebiliyor (override). Bu da bize bir metot çağrılmadan önce metodun arasına girebileceğimiz anlamına geliyor. originalCreateFn ve originalDeleteFn değişkenleri User’a ait metotlara işaret ediyor. Bu metotlar ezilerek yerine eklemek isteğimiz kodu ekleyebiliyoruz.

Decorator Deseni ile Uygulama

GOF desenlerinden Decorator Pattern’i kullanarak yine AOP’i Javascript’de uygulayabiliyoruz.

Decorator Pattern’in uygulama alanları sadece bu değil tabi ki. Çok farklı problemleri çözmek için de kullanılabiliriz. İlerideki yazılarımda bu konulara da değinmeyi düşünüyorum.

Yukarıdaki kod blokunda görüldüğü üzere User sınıfının metotları üzerinde yapmak istediğimiz işleri ayırdık. UserRoleDecorator ve UserLogDecorator sınıfları User’dan türemiş sınıflar, aynı metotlara sahipler ve aynı işleri yapıyorlar fakat User’ın niteliğini değiştirmeden üzerinde yapmak istediğimiz işlemleri ayırmış olduk (Cross-Cutting Concerns).

Değindiğimiz üzere OOP’de amaç Separation of Concern (ilgi-davranışların ayrılması) idi. AOP kullanırak merkezimize Cross-Cutting Concerns’i (Kesişen ilgi-davranışların ayrılması) aldık. Görüldüğü üzere aynı problemi farklı yöntemle çözmeye çalışıyoruz.

ES7 ile gelecek olan Decorator özelliği

C#’in Attribute’i, Java’nin Annotation’i, Pyhton’un Decoratorleri kodlara işlevsel katmayı amaçlayan Meta Programming teknikleridir. JavaScript’e de ECMAScript 7 ile Pyhton’dakine çok benzer bir çözüm getirmek isteniyor. Her ne kadar JS’e böyle bir özellik daha gelmemiş olsa da Typescript, Babel gibi JS dönüştürücüleri sayesinden bunu uygulamamız mümkün. Ben örneğimi Typescript üzerinden vereceğim.

Gelecek olan bu özelliği takip etmek isterseniz https://github.com/tc39/proposal-decorators adresini takip edebilirsiniz.

Aslında bu yazmış olduğumuz kod ilk örneğimiz ile aynı işi yapmakta. JS’e gelmesi planlanan bu özellik Decorator Pattern’den çok farklı değil hatta bire bir aynısı, sadece uygulama biçimi farklı. log fonksiyonu işaretlenmiş olan herhangi bir metodun niteliğini değiştirmeden (isterseniz niteliğini de değiştirebilirsiniz ama konumuz bu değil) üzerinde işlem yapabiliyoruz. Parametre olarak gelen descriptor, EcmaScript 5 ile JS’e kullanımaya başladığımız Object.defineProperty metodunun parametresi aslında. descriptor’a ait value alan adını yeni bir fonksiyon ile değiştirilerek işaret etmiş olduğumuz metodunu kapsüllemiş (Encapsulation) olduk. User’a ait işaretlemiş olduğumuz metotları kullanmak isteyen istemci bu metotları çağırdığında bizim değiştirmiş olduğumuz fonksiyonu çağırmakta. Bu değişim sayesinde araya girip istediğimiz işlemi asıl metoda erişmeden ya da eriştikten sonra yapmamız mümkün.

Yukarıdaki örnekleri mümkün olduğu kadar kısa tutmaya çalıştım :) Görüldüğü üzere 3 farklı şekilde de AOP’yi JS’de uygulamak mümkün. Size kolay gelen, beğendiğiniz yöntemi istediğiniz şekilde projelerinizde kullanabilirsiniz. Ayrıca bu konu üzerine yazılmış bazı kütüphaneler de mevcut. Aspect.js de bunlardan bir tanesi ve JS’nin eski versiyonlarını da desteklemektedir. Bir daha ki yazıda görüşmek üzere bol ama temiz kodlu projeler diliyorum :)