Aspect Oriented Programming
AOP – Aspect Oriented Programming hemen hemen her yazılımıcnın defalarca işittiği ve üzerinde en az bir kere konuştuğu bir konudur. Ancak ya hiç kullanılmamıştır ya da kullanılırken farkına varılmamıştır. Örneğin bir çoğumuz Spring Framework bileşenlerini kullanırız. Ancak Spring’te temel özellik olarak kullanılan AOP mekanizmasını ve/veya paradigmasından haberdar değilizdir.
Peşinen söyliyim, uzun bir yazı olacak. Aslında Enterprise Java kitabımın Spirng AOP konusundaki AOP paradigmasının anlatıldığı bölümdür.
AOP paradigma olarak OOP için çok önemli bir yere sahip olsa da ülkemizde gerek çeviri, gerek anlatım olarak biraz eksik kalındığından meraklı gözlerden hep uzak kalmıştır. Gelin sizlerle 10-15 dakikalık bir AOP yolculuğu yapalım.
Seperation of Concerns
Modül, uygulamaya ait benzer davranışları taşıyan bileşenleri bir araya getiren küçük alt parçacıklar olarak düşünülebilir. Projelerde, proje paketlerini oluştururken model, dao, util, test gibi paketler oluşturarak içlerinde benzer davranışları taşıyan sınıflar geliştirilmektedir.
Örneğin dao paketi içerisinde veri tabanı işlemlerini yapan sınıflar yerleştirilmektedir. Bu paket büyüdükçe davranış olarak benzer operasyonlarla yani veri tabanı işlemleri ile ilgilenen dao katmanları karşımıza çıkmaktadır. Burada asıl amaç benzer davranışlarla ilgilenen uygulama parçalarını ayrı modüller olarak ele almaktır. Böylece okuma, yönetim kolaylaşacak ve uygulama esneklik kazanacaktır.
Burada dikkat çekici nokta ilgi’dir. Benzer davranışlar benzer ilgilerden doğar. Şöyle ki veri tabanı işlemlerini yapan sınıfların hepsi veri yönetme işlemi ile ilgilenirler. Yani benzer davranış sergilerler. Bu benzer davranış ilgi alanlarının aynı veya ortak olmasından kaynaklanmaktadır. Veri yönetimi ile ilgilenmeyen bir sınıfın veri tabanı işlemlerine ait bir metod taşıması beklenemez. (en azından ortalama güzellikteki bir tasarım içerisinde)
Separation of Concerns, dilimize genelde ilgilerin ayrışması olarak çevrilir, bence davranışların ayrıştırılması olarak çevrilmelidir. Uygulamanın belirli davranışlar baz alınarak paketlere ya da modüllere ayrılması yöntemine genel olarak davranışların ayrıştırılması denilebilir. Bu ayrışma atomik düzeyde metod tasarımından başlayarak ele alınmalıdır.
* Bir metod bir atomik işi yapar,
** Bir sınıf bir işlemi yönetir,
*** Bir paket benzer davranışları taşır.
Proje paketlerinin model, dao, util gibi kavramlar etrafında ayrıştırılması davranış, ayrıştırma yönteminin en temel düzeydeki kullanımıdır. Böylece az çok yazılımdan anlayan biri proje paketlerini incelediğinde kabaca hangi pakette neler bulabileceğini kestirebilecektir. Bu ayrıştırmayı gerçek ve ciddi büyüklükte bir projede üzerinde hayal edersek.
Proje bileşenleri yani modülleri,
- Logging
- Transaction Management
- Pooling
- Security
- Caching
- Performance
- Exception Handling
- Operations
olarak sıralanabilir.
Bunlar da makro düzeydeki ayrıştırmadır. 1000’lerce sınıftan oluşan bir projede 50-100 tane log sınıfı, 150-200 tane dao, 100-150 tane service bileşenine ait sınıfa sahip projeler yukarıdaki birçok özelliğe sahip olacaktır. Bu katmanlardan bir kaçını inceleyelim.
DAO
DAO katmanı Transactiona sahip olmalıdır. Transaction, veri yönetiminden sorumlu değildir. Transaction verilerin güvenli şekilde kaydedilip, silinmesinden sorumludur. Veri yönetimi işlemlerinin doğruluğunu garanti etmek için kurulan yapılardır. Veri yönetiminden aslında, esasında DAO katmanı sorumludur. Ancak yönetimde hata olmaması için Transcation mekanizmasına sahip olması gerekmektedir.
O zaman elimizde iki davranış var bir tanesi veri yönetimi diğeri veri yönetim güvenliğidir. İşin ilginçleştiği nokta ise bu iki davranışın birbirleri ile sıkı etkileşim içerisinde olmalarıdır. Transaction veri güvenliğinden emin değilse DAO katmanındaki yapılan işlemler veri tabanına kaydedilmeyebilir. Transaction mekanizması bunu engeller. Burada yolların kesişmesi durumu söz konusudur. Bazen de bir modül diğerinin yolunu keser.
Logging
Loglama, örneklerden biliyorsunuz log4j2 apisini kullanılabilir. Loglama davranışı genelde bu api yardımı ile çözülmektedir. Uygulamaların birçok yerinde metodların loglanma ihtiyacı olduğunda bu apiye ait metodlar ile loglama yapılmaktadır. O zaman loglama modülleri ile uygulamanın da yollarının kesişmesi söz konusudur.
Exceptions
Hata yönetimi, birçok projede exception handlig mekanizması kurulmaktadır. Hata yönetimi ile uygulamanın yolları sadece kesişmiyor bazen hata yönetimi uygulamanın yolunu bile kesecek duruma gelebiliyor. Bunlara benzer örneklemeleri yukarıdaki tüm proje bileşenleri için yapabiliriz.
Code Scattering & Tangling
Görüntüde sol tarafta JDBC ile sağ tarafta ise JPA ile veri tabanı işlemi yapılan iki örnek yan yana yer almaktadır. Her ikisinde de DAO katmanında belirli aralıklarla; Transaction Managment, Logging ve Exception Handling yapılmış olmasıdır. Bu yapılar bir şekilde metodların asıl operasyonlarının arasına girerek operasyonların davranışlarına etki etmektedirler.
Buradaki dikkat edilecek nokta tüm bu davranışlar Java nesne yaratma ve yönetme mantığı içerisinde sınıf ya da metod içerisinde doğrudan tanımlıdırlar ve çağrıldıkları sıra ile çalışırlar. Örneğin loglama mekanizmasının metodlarda kullanılması için sınıf içerisinde bir log nesnesi yaratılmış durumdadır ve sırası gelince çalışacaktır. Normal Java akış mantığında metodlar yukarıdan aşağıya satır satır çalıştırılacak ve sonuç döndürülecektir.
Görüntüdeki metodlar yüklendikleri operasyonların yani asıl amaçlarının dışına çıkarak,
- Transaction başlatıyorlar.
- Veriyi kaydetmeye çalışıyorlar.
- Veri kaydetmede sorun yok ise commit yapıyorlar. (transaction)
- Başarılı işlemin loglamasını yapıyorlar.
- Veri kaydetmede sorun var mı diye exception handling yapıyorlar.
- Hatayı loglaması yapıyorlar
- Veri kaydetmede sorun var ise veri commit edilmiyor. (transaction)
akışına giriyorlar.
Böyle bir akış içerisinde metodtan beklenen asıl işlev veriyi sadece ve sadece veri tabanına kaydetmesidir. Bu akışta metod odak noktasından uzaklaşmış birçok işlevi yapmak zorunda bırakılmıştır. Burada fazla olan her bir davranış o metoda yüklenen ilgi – endişe kaynaklıdır. Metod transaction, loglama ve hata ayıklama gibi birçok farklı operasyonla ilgilenmek ya da onlar hakkında endişelenmek zorunda kalmıştır. OOP paradigması burada çözüm üretmekte güdük kalmaktadır.
Code Scattering
Kod Saçılması, bir davranışın birden çok metodta, sınıfta veya modülde kullanılması durumudur.
Code Tangling
Kod Dağılması, birden çok davranışın aynı metod sınıf veya modül kullanılması durumudur.
Yukarıdaki görüntü baz alınarak Jpa ve Jdbc yapıları kabaca incelendiğinde, Metodlarda Kod Dağılması durumu söz konusudur. Yani neredeyse tüm metodlarda görüntüdeki akışa benzer bir yapı uygulanmaktadır. Bu yapıda metodlara “ilgilerine – endişelerine” göre davranışlar eklenmiştir.
İlgi veya endişeden kasıt metodların operasyonlarını tamamlarken garanti etmek zorunda oldukları yan etkiler veya operasyon aşamalarının bir geçmişidir. Bunlar ile metodun operasyonu başarı ile tamamlayıp tamamlamadığından emin olabilmekteyiz.
Metodlar
- Transaction ile ilgilidirler.
Çünkü bu davranış veri güvenliğini garanti etmektedir. - Loglama ile ilgilidirler.
Çünkü operasyon kayıtları, hata olup olmadığının incelenmesini sağlar. - Exception Handling ile ilgilidirler.
Çünkü operasyon süresince oluşabilecek hataları yakalayıp göstermeleri gerekir ki düzeltilebilsin.
OOP içerisinde bu akış tüm JDBC ve JPA modülleri boyunca uygulanabilir. Projeler büyüdükçe bu kurgunun getireceği yük de artacaktır. Kötü senaryoda kaosa doğru bile gidebilir. OOP içerisinde Separation of Concerns, “davranışları ayrıştıran” modüler yapılar kurularak bile bu işi çözmek mümkün görünmüyor.
Crosscutting Concerns
Enine Kesen İlgiler diye dilimize çevrilmektedir. Ben kesişen davranışlar olarak yorumlamayı tercih ediyorum. Concerns kelimesi çevrisi bire bir olarak endişe ve türevleri şeklinde olmaktadır. Bu çeviriden yola çıkarak birkaç tanımlama yapalım.
- Modüler tasarlanarak geliştirilmiş birimlerin veya metodların ihtiyaç duydukları farklı ilgiler olabilir. –ya da–
- Modüler tasarlanarak geliştirilmiş birimler veya metodlar farklı ilgilere ihtiyaç duyabilirler.
Bu ilgiler zaman zaman bu birimlerin veya operasyonların akışına etki ederek onların akışlarında değişime neden olabilirler.
Şeklindeki ilgi odaklı anlatımlar yaygın iken.
- Modüler tasarlanarak geliştirilmiş birimler veya metodlar farklı davranışlara ilgi duyabilirler.
- Bu davranışlar, yapısal olarak ilgili birimlerin operasyonlarında olmayan başkaca işlevler olabilir.
Bu fazladan eklenen davranışlar ilgili metodların operasyonlarını etkileyerek değişime neden olabilirler.
Şeklindeki iki tanımlamadan hangisi programatik iş akışını daha net ifade etmektedir?
Crosscutting Concerns kesişen ilgiler olarak çevrilebilir. Ancak bu konu anlatılırken her yerde ilgi kelimesinin kullanılmasını özellikle metodların ihtiyaç duydukları davranışlardan ilgi diye bahsedilmesi bana çok doğru gelmiyor.
Evet metodlarda bir ilgi oluşuyor. Bu o metodun ihtiyaç duyduğu davranışa olan ilgisidir. Davranışa vurgu yapmadan yapılan her enine kesen, kesişen ilgiler tanımlaması eksik gibi geliyor.
Örneğin loglama bir ilgi değil, bir davranıştır. Metod ya da sınıfın bu davranışa ihtiyacı varsa loglamaya ilgi duyduğu söylenebilir. Ancak ilgi, metod içerisinde loglamanın yaptığı işi ve önemini açıklamada yetersiz kalacaktır. Tanımı toparlarsak…
Croscutting Concerns
Kesişen Davranışlar, Modüler tasarlanarak geliştirilmiş birimler veya metodlar farklı davranışlara ilgi duyabilirler. Bu davranışlar, yapısal olarak ilgili birimlerin operasyonlarında değişime neden olabilirler.
Örneğin veri kaydetme başarısız olduğunda transaction mekanizması devreye girerek tüm değişikliklerin geri alınmasını sağlayabilir. Bu sonucu değiştiren bir müdahaledir.
Ya da veri kaydetme işlemi başarılı olduğu anda metodtan çıkılmaz yani metod sonlanmaz. Metod veri kaydetme işleminin başarılı olduğunu log olarak yazar ve öyle sonlanır. Bu da sonucu değiştirir. Etkisi az da olsa metod veri kaydetme yanında bir de log üretmek zorunda kalmaktadır.
Her iki senaryoda da metodun işlevi sona erdi. Ancak tüm davranışlar beklenildiği gibi yerine getirilmeden metodtan çıkamıyoruz. (hadi bu son cümlede davranış yerine ilgi diyelim, cuk oturur mu?)
Bu fazla davranışların doğrudan ilgili metod tarafından çalıştırılması gerekmektedir. Bu kesişim davranışları OOP altında modüler tasarlanıp geliştirilen projelerde bile net olarak çözülememektedir. Kesişme çözülemediği gibi metodlar veya sınıflar karmaşıklaşarak okuma kalitesi azalmaktadır. Kod kalitesi azaldığında ise uygulama kalitesi için zorunlu olması gereken her türlü esnek yaklaşım stratejisi geçersiz olacaktır. Bu nokta da farklı bir programlama paradigması olan AOP, Aspect Oriented Programming devreye girmektedir.
Aspect Oriented Programming
Aspect Oriented Programming, ilgiye yönelik programlama olarak dilimize çevrilmektedir. Aspect kelimesini bir de google‘a soralım.
Bu çevirideki Türkçe anlamları beri kenara bırakalım ingilizce tanımlayıcı olarak verilen kelimelerde bile bir tane ingilizce ilgi var mı? Eskiden cephe yönelimli programlama diyenler de vardı. Cephenin, ilgiye yönelik programlamadan daha iyi durduğu kesin. Hatta biraz böyle OOP’a yeni bir paradigma getirdiğinden cephe açmış, cepheden yaklaşıyor gibi bile düşünülürse ilginden çok çok daha iyi ifade ediyor. Concern’e yeniden bakalım.
Burada ilgi geçiyor. Ancak ilgi en yaygın olanı değil. Tüm anlamlar toparlandığında bir kaygı veya endişe durumu hakimdir.
Tercüme sana ilgilerim var demiyor. Bu kelimelere daha üst pencereden bakılarak incelendiğinde. Çevirilerin toplamında davranışsal bir durum ortaya çıkar. Ve bu Türkçe’ye doğrudan çevrilecekse bence ilgilerin ayrışması değil endişelerin ayrışması olmalıdır.
Çünkü uygulama veya metod kendisine verilen işlevi yerine getirebilecek mi getiremeyecek midir? Bu işlevi tamamlamak için sahip olduğu bileşenlerin doğru çalışıp çalışmadığından ya da bu bileşenlerin kendi çalışmasını etkileyip etkilemeyeceğinden endişe mi duyar ilgi mi duyar?
Aspect Oriented Programming, bence cephe yönelimli programlama olarak düşünmek daha güzeldir. Çünkü AOP paradigmasında modüllere eklenecek bileşenler modüllerin doğrudan parçaları olmayacaklar. Kendilerine verilen görevi yapıp çıkacaklar. Bakıp çıkacağım abi durumu…
Neden bu konuya takıldım? Kavramlara yüklenen anlamlar yaptıkları işi tam karşılamadığında konu güdük kalıyor. Programcı bir uygulamayı geliştirirken herhangi bir paradigmadan yararlanmak istiyor. Ancak paradigma kafasında bir türlü oturmuyor. Oturmayınca en yol bildiğin yol deyip eski usul devam ediyor. O zaman yine yeniden voltron voltron … diyelim ve toparlayalım.
Aspect Oriented Programming
Birbirinden farklı işlevler yürüten ancak kesişen davranışların birbirlerinden ayrışması metodolojisine AOP denilmektedir.
- Loglama
- Transaction Management
- Pooling
- Security → Güvenlik
- Caching → Kaynak Yönetimi
- Performans Ölçümü → kaynak yönetimi
- Exception Handling → Hata yönetimi
- Operations → İş kuralları
AOP, yukarıda sıralanan birçok işlevin ayrı ayrı tasarlanarak sadece gerektiğinde uygulama ile ahenk içinde çalıştırılabilmesi yöntemidir. Burada her uygulama birimi, Aspect olarak tasarlanmış herhangi bir modülü istediği zaman edinip kullanabilir.
Bu sıralanan işlevlerin ilginç bir yönleri daha var, dikkatiniz çekti mi? Bu işlevler herhangi bir uygulamadaki en genel yani en generic özellikleri ifade ediyorlar. Yani hemen hemen her uygulamanın ihtiyaç duyabileceği bileşenlerdir. Herhangi bir uygulamanın birden çok yerinde, defalarca kullanılmaları gerekebilir.
Bu özellikler için güzel bir tasarım ile yapılacak her geliştirme bizleri büyük iş kaybından kurtaracaktır. Örneğin öyle bir tasarım yapmalıyız ki, uygulamadaki metodlar loglama işlevini sürekli çağırarak kullanmak zorunda kalmasın.
* Modüllerin bir tanesi loglamayı yönetsin.
* İşi yürütecek asıl modülde de ne zaman ve neresinin loglanacağını basitçe söylemek yeterli olsun.
Bu durumda Loglama ve operasyon modülleri kardeş kardeş çalışsınlar. Olabilir mi? Göreceğiz…