Yazılım dünyasında başlıca endişelerinden biri, yazılımdaki parçaların biri birine çok bağlanmasıdır(high coupling, cross-cutting concerns). Bu durum yazılımın belirli bir noktadan sonra anlaşılmaz, ayrıştırılamaz, ilerletilebilemez hale gelmesine yol açar. Çare olarak yazılımcılar, en yaygın yöntem olan yazılım şablonlarını kullanırlar. Fakat, bazen işler o kadar karmaşık bir hal alır ki artık, yazılım şablonları da karmaşayı sonlandıramaz. Bu noktada cepheye yönelik programlama(aspect-oriented programming, AOSD) yazılımcıların imdadına yetişmektedir. Cepheye yönelik programlama, destekleyen yada yardımcı olarak görev yapan kısımların, asıl parçalardan arındırılmasıdır. AOSD, farklı işlevlere sahip kısımların, biri birinden ayrı(seperation of concerns) programlanmasına olanak tanıyarak karmaşayı giderebilir. Yazımın devamında, biri birine bağlanan parçalarından, AOSD’den ve son olarakta AOSD uygulamalarından bahsedeceğim.
Parçaların biri birine bağlı olması, gerçek hayatta karşımıza sıkça çıkan sorunlardan biridir. Çoğu zaman, yazılımın içindeki bağlılıkların(dependency) ortaya çıkmasında başlıca rol oynamaktadır. Bu duruma örnek verecek olursak, bir fonksiyonun güvenlik(security), kayıt düşme(logging) ve veri işleme(transaction processing) bağlılıkları olabilir. Bunları aynı yerde yazmak, yazılımın çok karmaşık bir hale gelmesine neden olur. Bu durum, önemli bir dez avantaja, yazılım yeniden kullanılmasına yada varolanın değiştirilmesine engel teşkil eder. Aşağıdaki örnekte bu duruma örnek verebileceğimiz bir fonksiyon görebilirsiniz.
public boolean saveStory(String story) throws Exception{
if (user.isAuthenticatedUser()) {
if (persister.save(user.id, story)) {
logger.info("Story for the user has been added.");
return true;
} else{
logger.error("Story is not saved.");
throw new StoryNotSavedException();
}
} else{
logger.error("User is not authorized.");
throw new UnAuthorizedUserException();
}
}
Yazılımdaki kısımların biri birine bağlı olması sorununu AOSD ile etkili bir şekilde çözebiliriz. AOSD bizim asıl fonksiyonu hayata geçirip, yardımcı fonksiyonlardan kurtulmamızı sağlayan bir yaklaşımdır. Yukarıdaki örnek üzerinden gidecek olursak, fonksiyondaki asıl amaç kullanıcı hikayesini başarılı bir şekilde kaydetmektir. Ama hikayeyi kaydederken, hikayenin kaydedildiğine dair kayıt düşme, kullanıcının bu işlem için yetkili olup olmadığına bakma ve veri işleme fonksiyona yardımcı yada fonksiyonu destekleyen işlevlerdir. AOSD, bizim asıl fonksiyona yoğunlarşıken, dışarıdan müdahale ile(by the help of pointcut) gerekli diğer işlevleri yerine getirmemizi sağlar. Bu bağlamda Spring framework ile AOSD, nasıl uygulanabileceğine değinmek istiyorum.
Spring Framework AOSD’ye aspectj paketiyle destek oluyor. Dahası, Spring Framework kendiliğinden bazı cepheleri(aspect) sağlıyor çünkü Spring’in uyguladığı annotation’lar cepheye yönelik programlamanın parçalarıdır denebilir. Mesela, @Autowired-Spring Bean olan bir nesnenin başka bir nesne içinden kısa yoldan çağrılmasına yarar yada @Component-Sınıfın Spring Bean olduğunu gösterir. Bu tip kullanımlar koddaki bağımlılığı azaltarak, fonksiyonların yada sınıfların daha basit olmasına yardımcı olur.
Cepheye yönelik programlamanın uygulamasını Spring Framework’un AspectJ paketini kullanarak yapabiliriz. Aşağıdaki kodda size yukarıda verilen fonksiyonun, cephe yardımıyla nasıl kayıt düşme bağımlılığından kurtaracağımızı görebilirsiniz. Kısaca bir kaç kavramdan bahsetmek istiyorum. AOSD’de fonksiyonlara erişim noktası pointcut adıyla tanımlanmıştır. Belirli bir erişim noktasıyla, istediğiniz fonksiyona ulaşıp fonksiyonun işleyişine(@AfterReturning) göre işlem yapabiliriz. Verdiğimiz örnekte within ve execution erişim noktalarını kullanarak fonksiyona ulaşıp, işleyişine göre kayıt düşme işlemini gerçekleştirdik. Kullanım detayları için Spring AOSD referansına bakabilirsiniz.
package com.yusufaytas.ao;
import org.apache.log4j.Logger;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.yusufaytas.example.StoryNotSavedException;
import com.yusufaytas.example.UnAuthorizedUserException;
@Aspect
public class LoggingAspect {
Logger logger = Logger.getLogger(LoggingAspect.class.getName());
@Pointcut("execution(public * saveStory(..))")
public void saveStory(){}
@Pointcut("within(com.yusufaytas.example.LoggingExample)")
public void inLoggingExample(){}
@Pointcut("saveStory()&&inLoggingExample()")
public void saveStoryInLoggingExample(){}
@AfterThrowing(pointcut="saveStoryInLoggingExample()",throwing="ex")
public void logUnAuthorizedUserException(UnAuthorizedUserException ex){
logger.error("User is not authorized.");
}
@AfterThrowing(pointcut = "saveStoryInLoggingExample()",throwing="ex")
public void logStoryNotSavedException(StoryNotSavedException ex) {
logger.error("Story is not saved.");
}
@AfterReturning(pointcut="saveStoryInLoggingExample()",returning="isSaved")
public void logDatabaseAccess(boolean isSaved) {
logger.info("Story for the user has been added.");
}
}
Yazılımda öncelikli amacımız, yazdığımız kodun basit ve olabildiğince geliştirilebilir, sürdürülebilir yada rahat bir yapıya sahip olmasıdır. Bu durum göze alındığında, cepheye yönelik programlama, bu ihtiyaçları karşılamak için kullandığımız bir yöntemdir. Bunun haricinde daha öncede bahsettiğimiz, yazılım şablonları yada kullanılan kütüphaneler yine yukarıda saydığımız gereksinimleri karşılamaya yöneliktir. Yazıda sıkça bahsettiğim Spring Framework de sınıfların biri birine bağlanmasını önleyen bir şablonu(inversion of control) hayata geçirerek yazılımcıya basit bir ortam sunarak gereksinimlerimizi karşılamaktadır. Sonuç olarak, cepheye yönelik programlama bazı noktalarda iyi bir yöntem olsa da öncelikli tercihin yazılım şablonları yada kütüphane desteğini kullanmak olduğuna inanmaktayım. Her konuda olduğu gibi değişik yaklaşımlar arasından en iyisini seçmenin yada birden fazla yaklaşıma sahip olmanın fark yaratacağını düşünüyorum.
Bu seferki makaleye daha çok benzemiş bence iyi. Tek tavsiyem madem kod bağımlılığını anlattın, koddaki bağımlılığı nasıl görebileceğin konusundaki yardımcı statik kod analiz toollarının oluşundan bahsedip bir kaç tanesine link verebilirdin ve belki daha sonra onların kullanımı konusunda bir makale yazılabilir ve içerik geliştirilirdi.
karmaşa dan nasıl kurtuluruz yazısını gerçekten çok karmaşık bir şekilde anlatmışsın