Standart Java API’ler Neden Tercih Edilmeli?

2008 senesinde yazdığım kodlara şöyle bir göz attım. Kullandığım hemen hemen her çatı beni mutlaka sahip olduğu soyut ya da somut bir sınıfı genişletmeye zorlamış. Örnek mi? Buyrun!

[sourcecode language=”java”]
// Junit 3.8.1 ile birim testi
public class AbcTest extends TestCase{
}
[/sourcecode]

[sourcecode language=”java”]
// Spring 2.5 ile MVC controller sınıfı
public class AbcController extends AbstractController{
}
[/sourcecode]

[sourcecode language=”java”]
// RMI örneği
public interface AbcInterface implements Remote
}
[/sourcecode]

[sourcecode language=”java”]
// DBUnit 2.2 ile entegrasyon testi
public abstract class AbcIntegrationTest extends DBTestCase{
}
[/sourcecode]

[sourcecode language=”java”]
// Selenium ile onay/kabul testi
public class LoginTest extends SeleneseTestCase {
}
[/sourcecode]

[sourcecode language=”java”]
// JMock 1.2 ile birim testi
public class LoginDaoImplTest extends MockObjectTestCase{
}
[/sourcecode]

Bu tarz sınıf genişleterek mevcut kodları kullanmaya çalışmak beraberinde birçok sıkıntıyı birlikte getirmekte. Örneğin:

  • Kod kullanılan çatıya bağımlı hale geliyor. Kodun o çatı olmadan kullanılması hemen hemen imkansız.
  • Kodu başka bir amaç için kullanmak zorlaşıyor.
  • Kodun test edilmesi zorlaşıyor.
  • Kullanılan çatının yeni sürümleri ile genişletilen sınıfların geri uyumlulukları ortadan kalkabiliyor. Bu her yeni sürümle kodun yeniden derlenmesi anlamına gelebiliyor.

2014 yılında Java’da state of the art programming anotasyon bazlı program geliştirme haline geldi. Her bir şey için bir anotasyon mevcut. Aşağıdaki iki değişik kod parçasından hangisini tercih ettiğinizi söyleyebilir misiniz? Peki seçiminiz neden öyle oldu?

[sourcecode language=”java”]
// Spring 4 controller sınıfı
@Controller
public class LoginController
    @Autowired
    LoginService service;
}
[/sourcecode]

[sourcecode language=”java”]
// Spring 4 controller sınıfı
@Named
public class LoginController
    @Inject
    LoginService service;
}
[/sourcecode]

@Controller ve @Autowired anotasyonları Spring çatısında yer alan anotasyonlardır. Bu anotasyonları kullandığımız taktirde, uygulamayı yine göbekten Spring çatısına bağımlı kılmış oluyoruz. Uygulama nereye giderse, peşinde her zaman Spring kütüphanelerini sürüklemek zorunda. İkinci  kod örneğinde JSR 330 ile gelen standart Java Dependency Injection anotasyonları kullanılmış. Böyle bir kod beraberinde Spring çatısını taşımak zorunda değildir. Burada yine tercih standart Java API’leri yönünde olmalıdır.

Bazen düşünüyorum da Java’da extends ve implements direktifleri olmasaydı, ne olurdu? Bu kodun bakımı ve geliştirilmesi adına programcılara çok büyük bir kolaylık sağlamış olurdu. Tüm Java sınıfları POJO (Plain Old Java Object) olurdu. POJO sınıfların test edilmesi çok kolay ve mümkün mertebe her zaman POJO sınıfları oluşturmaya gayret ederim.

Görüldüğü gibi Java dünyasında standartlaşmaya ve standartların kullanımına doğru bir akım var. Aksi taktirde JSR 250 ya da JSR 330 gibi çalışmaların ardından Java’ya bu tür anotasyonlar eklenmezdi.

Java’da yazılım genel olarak POJO bazlı uygulama geliştirmeye doğru gidiyor. Eskiden EJB 1 ve 2 de bir takım interface sınıfları genişletmek zorunda kalırdık. Aynı şey RMI uygulamaları için de geçerli. EJB 3 ile gelen yeni POJO bazlı EJB modeli ve dependency injection ile POJO sınıfları işletme mantığını oluşturmak için kullanabiliyoruz. Dependency injection mekanizması ile sınıflar daha sade bir yapıya dönüşmeye başladı. Eskiden kırk dereden su getirirken, şimdilerde programcı olarak sadece işletme mantığına konsantre olabiliyoruz. İşletme mantığına konsantre olabildiğimiz için birim ve diğer tür testleri de daha kolay bir şekilde yapabiliyoruz, çünkü oluşturduğumuz sınıflar safkan POJO sınıflar ve test edilmeleri çok kolay. Biz programcılar için bunlar ne güzel günler değil mi?

Eski kodlarımı incelerken bir şeyin daha farkına vardım. Artık POJO’ları test etmekte çok kolay bir hale gelmiş. Bir Spring MVC uygulamasını uygulama sunucusunda çalışır hale getirmeden şu şekilde test edebiliyorum:

[sourcecode language=”java”]
// Spring MVC Test çatısı kullanımı
this.mockMvc
    .perform(post("/login")
    .contentType(MediaType.APPLICATION_FORM_URLENCODED)
    .param("email", "")
    .param("password", ""))
    .andExpect(model().attributeHasFieldErrors("loginForm", "email"))
    .andExpect(    model().attributeHasFieldErrors("loginForm", "password"))
    .andExpect(model().attributeErrorCount("loginForm", 2));
[/sourcecode]

Bu test için oluşturduğum controller sınıfı da bir POJO:

[sourcecode language=”java”]
// Spring 4 MVC controller sinifi
@Named
@RequestMapping("/login")
public class LoginController {

    private static final String LOGIN_VIEW = "login";
    private static final String LOGIN_FORM = "loginForm";

    @Inject
    private LoginManager manager;

    @RequestMapping(method = RequestMethod.POST)
    public String login(
            final ModelMap model,
            @ModelAttribute(LOGIN_FORM) @Valid final Customer customer,
            final BindingResult result) throws IOException {
        if (result.hasErrors()) {
            return LOGIN_VIEW;
        } else {
            LoginResult loginResult = this.processLogin(customer);
            
            if(loginResult.getStatus() == StatusCodes.LOGIN_SUCCESSFULL.getValue()){
                return "home";
            }
            return LOGIN_VIEW;
        }
    }
}
[/sourcecode]

Bu kodu şöyle de test edebilirim:

[sourcecode language=”java”]
@Test
public void testController(){
    LoginController controller = new LoginController();
    assertThat(controller.login(), is(equals("home"));
}
[/sourcecode]

Bir sınıfı test edebilmenin anahtarı new direktifinde yatmaktadır. New ile bir sınıftan bir nesne oluşturamıyorsam, o sınıfı test etmek için kırk dereden su getirmek zorundayım demektir. Bazen böyle bir sınıf için birim testi yazmak bile mümkün değildir. Test yazamassam gözüme uyku girmez.

Son zamanlarda iyi uyuyorum ama!


EOF (End Of Fun)
Özcan Acar


Yorumlar

“Standart Java API’ler Neden Tercih Edilmeli?” için 4 yanıt

  1. zafer avatarı
    zafer

    Merhabalar Ozcan Bey,

    Ben sizin “Tasarim Sablonlari ve Yazilim Mimarileri” adli kitabinizi okumaktayim.Bu kitapta ogrendiklerimden dolayi 1 soru sormak istedim.Ilk paragraftaki implements ve extends kullaniminin bagimliligi arttirdigindan bahsettiniz ve kullanimini kotulediniz bu bir nevi design patterns lari da kotulemek anlamina gelmiyo mu? Ogrendigim kadariyla tekrar eden sorunlari cozmek amaciyla kullanilan ve tekrar kullanilabilir tipte yazilimi destekleyen “design patterns” kavrami bir nevi kotulenmis oldu bu yazida 🙂 Kitabinizda anlattiginiz konular tamamen interface ve abstract class uzerine kurulu oldugu icin bu soruyu sorma geregi hissettim.Cevabiniz icin simdiden tesekkurler iyi calismalar…

  2. Özcan Acar avatarı
    Özcan Acar

    Kötüleme degil, daha ziyade ben biraz hayal kurdum, nasil olurdu acaba diye kendime sordum.

    Java 8 ile abstract sinifi kullanimi ortadan kalmis oldu. Interface siniflar bünyesinde default implementasyonlar olusturabiliyoruz. Bu yüzden extends ortadan kalmis gibi görünüyor. Geriye sadece implements kaldi 🙂

    Interface bazli yazilim modüler yapilar olusmasi icin vazgecilmez bir durum. O yüzden tasarim sablonlarinda sikca kullanilmakta ve kullanilmali. Modüller arasi esnek bir bag olusturmak icin interface siniflar gerekli.

  3. Fırat Gürsoy avatarı
    Fırat Gürsoy

    Hocam merhaba, Ben restful web servis ve web uygulaması oluştururken Spring Mvc kullanıyorum. Yanlış anlamadıysam Controller oluştururken Spring anotasyonları yerine JSR 330 anotasyonlarının tercih edilmesinin uygun olacağını söylemişsiniz. Fakat metodlarda @RequestMapping ve @ModelAttribute anotasyonlarını kullanmışsınız. Sorum ise; Bu anotasyonlara alternatif anotasyonlar JSR 330 da var mı ve Spring Mvc ile sorunsuz çalışabiliyorlar mı ? Ve eğer Spring anatasyonlarını kullanmayacaksak, neden Spring dependency lerini aplikasyona ekleyelim? Yani direk bir ejb projesi yapılandırmak daha mantıklı değil mi ?

    1. Özcan Acar avatarı
      Özcan Acar

      JSR 330 sadece dependency injection icin gerekli anotasyonlari ihtiva ediyor. Tamamen Spring anotasyonlarindan bagimsiz bir REST uygulamasi gelistirmek icin Java API for RESTful Web Services, kisaca JAX-RS API’sini kullanmalisiniz. Böylece uygulamayi üst katmanda standart Java anotasyonlari ile yapilandirirken, alt katmanlar icin Spring catisini kullanabilirsiniz.