Monday, October 31, 2005

Bir Makinaya SSH ile Şifresiz Giriş

SSH gizli/açık anahtar kavramına göre çalışır (public/private key encryption). Bu sistemi başka yazılarda anlatacağız. Şimdilik, uzak bir makinada şifresiz giriş yapmak, komutlar işletmek, ve scp ile şifresiz kopyalama yapmak için, şunları yapmamız lâzım.

Kendimiz için bir gizli/açık anahtar çifti yaratmak için şu komutu çalıştırın.

$ ssh-keygen -t rsa

Sorulan sorular için hiç cevap girmeden ENTER'e basarak geçin.

Bu bittikten sonra, $HOME/.ssh/ dizini icinde 2 dosya göreceksiniz. id_rsa.pub ve id_rsa. ($HOME'un nerede olduğunu Cygwin'den ya da Linux komut satırından echo $HOME ile öğrenebilirsiniz). Bu kayıtlardan id_rsa isimli olan sizin gizli anahtarınızdır, id_rsa.pub ise açık anahtarınızdır. Şimdi, id_rsa.pub kayıdını, erişeceğiniz bilgisayara (meselâ CVS havuzunu tutan bilgisayara) scp ya da ftp ile gönderin (scp kullanilinca simdilik sifre sorulacak). O bilgisayardaki kullanıcı adınız altında girin, ve $HOME/.ssh/ dizini altına id_rsa.pub kayıdını bırakın.

Sonra, sunucu sisteminde sunu calıştırın: "cat $HOME/.ssh/id_rsa.pub >> authorized_keys". Kutlarım. Artık ssh ya da CVS komutları kullanırken şifreye ihtiyacınız olmayacak.


Not: authorized_keys dosyasina ekleme yapmak yerine, baglanilan bilgisayardan ssh-copy-id komutu da ayni islemi yapiyor, tabii ki sifre soruluyor (simdilik), fakat bu yontem daha kolay.

Unix cat komutu ile >> işlecini kullandığımıza dikkat edin. Bu demektir ki, birden fazla .pub dosyasına tek bir authorized_keys dosyasına ekleyebiliriz. Yâni, birden fazla erişen kişi, aynı servis makinasına ve aynı kullanıcıya değişik açık anahtarlar ile erişebilir.

Önemli bir ek detay, servis tarafındaki authorized_keys dosyasının güvenliğinin çok fazla açık olmamasıdır. Eğer dosyanın Unix bazında güvenliği çok açıksa, sshd bağlanmaya çalışan ssh/scp komutunu bir şifre girmeye zorlayacaktır. authorized_keys dosyasının yeterince kapalı hale getirmek için

chmod 600 authorized_keys

Çift Anahtar Bazlı Şifresiz Giriş Ne Kadar Güvenli?

Bu kullanım güvenli, çünkü bir korsan, servis bilgisayarına sadece ve sadece id_rsa dosyasına sahipse başarabilir. Bu dosya da, sizin bâğlanan bilgisayarınızda duruyor olacaktır, ve o dosyayı almak için bâğlanan bilgisayara, (yâni ssh-keygen komutunu işlettiğiniz bilgisayara) sızılması gerekecektir. Demek ki akılda tutulması gereken kıstas şudur: Çift anahtar yaklaşımını kullanarak iki makina arasında şifresiz giriş kurduğunuzda, bağlanılan makina, bağlanan makinanın güvenli olduğu kadar güvenli olacaktır.

Sorun Çıkarsa

Bazı tipik kuruluş problemleri şunlar oluyor. SSH bağlanamama problemlerinde, sunucu bilgisayarında sshd programınının calıştığını kontrol edin. "ps -eaf | grep sshd" ile bunu kontrol edebilirsiniz.

Bağlanan bilgisayarlarda Cygwin'e özel bir problem de Windows'da çıkabiliyor. Bunun tarifi ve tamiri de şöyle:

Cygwin ssh programı (OpenSSH), gizli anahtarın üzerindeki erişim haklarının "kullanıcıya özel" olmasını istiyor. Bu normal tabii çünkü bu anahtar gizli, ve her kullanıcı tarafından okunamaması lâzım.

Hata şöyle:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Permissions 0644 for '/cygdrive/h/.ssh/id_rsa' are too open.

It is recommended that your private key files are NOT accessible by others.

This private key will be ignored.

Hiç problem degil (diye düşünüyoruz) chmod, vs. iş biter. Bir tek problem, Windows ve Unix erişim hakları yöntemleri uyuşmaması. Chmod'u çalıştırdığınızda, komut bir sey yapmış gibi geri geliyor, fakat dosyada bir değişiklik olmuyor. Unix dosya haklarının Cygwin'de "simule" edilmesi için, cygwin.bat içine şunu eklemek lazım.

set CYGWIN=tty ntea

Bundan sonra

$ chmod 0600 id_rsa

.. ve bundan sonra ssh ve scp komutlarınız düzgün çalışacak.

Sunday, October 30, 2005

Nesne Tasarımı

Java veya diğer dillerde kodlama eylemi nesne etrafında dönmektedir. Merkezi yer tutan ve en küçük veri yapısını teşkil eden nesnelerin tasarımı, temiz bir mimari için çok mühim bir olaydır.


Bu yazıda, nesne tasarımı hakkında bazı dersleri paylaşacağız.

Tek Eylem Nesneleri

Bu tür nesneler, tek bir işlem çevresinde yazılmıştır. Turnosol testi olarak 'bu nesnenin sistemdeki rolü nedir' sorusuna, 'bu nesne X yapar' cevabı alınmasıdır.

Halbuki bir nesne, çok özel şartlar olmadıkça, birden fazla işlemin toplamı olmalıdır. Ünlü nesnesel tasarımcı Bertrand Meyer, bir nesneyi üzerinde düğmeler (işlemler), okuma göstergeçleri (sorgular) ve anlık durumu (state) olan bir makinaya benzetir.

Örnek olarak bilgisayar bilimden yakınen bildiğimiz yığıt (stack) nesnesini gösterebiliriz. Yığıtta, üst noktayı işaret eden göstergeç bilgisi, kaç eleman olduğuna dair bir sayaç, ve eleman ekleyen/çıkartan işlemlerden oluşan bir yığıt sınıfı vardır. İhtiyaca göre kullanıcı program, bu yığıt işlemlerini istediği sırada çâğırabilir. (Tabii nesnenin iç bütünlüğünü bozmadıkça, mesela boş bir yığıttan eleman çıkartmaya çalışmak gibi).

Buna kıyasla, tek bir işlem etrafında yazılmış nesnelere şüphe ile bakmak gerekir. Bu tür nesneler, tasarımcısının işlevsel geçmişini yansıtıyor olabilir.

Bir nesneyi, durumu, alışveriş listesi halindeki işlevleri, ve anlık durumu olan bir makina olarak görmeye başlamak lazımdır.

Yan etkisi olan sorgular

Yan etkisi olan sorgulardan kaçınılmalıdır. Mesela,

public class Yığıt {
public void ekle(Object o) { .. }
public Object siradakiEleman() {
.. elemani bul
.. yigittan cikart
return nesne;
}
..
}

Bu örnekteki siradakiEleman sorgusunun yan etkisi var, çünkü, hem sıradaki elemanın ne olduğunu söylemekte, hem de bu elemanı yığıttan çıkartmaktadır. Bu sebeple aynı sorgu iki kere üst üste çâğırıldığında, aynı sonuç gelmeyecektir.

Bu tür bir sorgu, o sorguyu taşıyan nesneyi kullananlar için karışık bir durum yaratır. Makina örneğine dönersek, bir termometreye baktığınız ve sıcaklığı okuduğunuz her seferde sıcaklık değerinin değişmesi nasıl olurdu? Çok karışık olurdu değil mi? Nesneler üzerindeki sorgu tasarımı da böyledir. Kullanıcı programcılar açısından üst üste ne kadar çağırılsa da, sorgu çağırımının, nesnenin anlık durumunu değiştirmeyecek şekilde yazılmış olması, tasarım açısından çok önemlidir.

Yukarıdaki nesne, şu şekilde değiştirilmelidir.

public class Yığıt {

public void ekle(Object o) { .. }

public Object siradakiEleman() {
.. elemani bul
return nesne;
}
public void siradakiElemaniCikart() {
.. elemani bul
.. yigittan cikart
}
..
}

Anlık Nesneler

Nesnesel teknoloji kullanan projelerde, programcıların çoğunun programın çalışması esnasında anlık hafızaya alınıp hemen atılacak türden nesneleri, her nedense nesneden saymadığını görüyoruz.

Meçhul bir sebepten dolayı, nesnelerin illâ ki uzun süre hafızada kalması gereken şeyler olduğunu zanneden programcı arkadaşlarımız var. Burada herhalde sorumlu olan, nesnesel tasarımı sürekli gerçek dünya nesnelerine bağlayarak anlatan, benzetimsel bir hava içinde sunan belgeler olmuştur.

O zaman dersimiz şöyle olabilir: Bir nesneyi hafızaya yükleyip orada uzun süre tutmak ile, nesneyi yükleyip gereken işlemleri çağırıp hemen atmak arasında, bilgisayar donanımı için hiç bir fark yoktur. Eğer her iki şart altında da işlem1, işlem2 ve işlem3 çâğırıldı ise, nesnemizin anlık durumu işlem3'ten sonra her iki şartta da aynı olacaktır.

Galiba, hemen yüklenip, kullanılıp, atılan nesneler programcılara Tek Eylem Nesnesi gibi geliyor. Bu yanlış bir saptamadır. İşlem1, işlem2, işlem3'ten bahsettiğimizi hatırlayınız. Bu işlemleri arka arkaya çağırdık, fakat diyelim ki 1 milisaniye içinde çâğırdık. Ama nesne açısından 1 milisaniye içinde 3 işlem câğırılması ile, 10 saniye içinde aynı işlemlerin çağırılmasının hiç bir farkı yoktur.

Bu yüzden, bu şekilde çabuk yüklenen/atılan nesneleri kullanın. Yardımcı nesne olmaları açısından mimarinize temizlik katacaklardır.

Sürekli Gönderilen Bildirgeç

Eğer nesneninizdeki işlevlere gönderilen bildirgeçler, sürekli aynı bir bildirgeç tipini taşıyorsa, bu tanımlanmamış yani eksik olan bir nesnenin göstergesidir. Mesela aşağıdaki gibi bir nesne düşünelim:

public class Isleyici {

public void birIslem() {
}

public void baskaBirIslem() {
}

public void ekle(Object bunu, Vector bunaEkle) {
...
...
}

public Object cikart(Vector bundanCikart) {
...
...
}

...
...

}

Gördüğümüz gibi aynı Vector nesnesi sürekli olarak Isleyici nesnesinin işlemlerine gönderiliyor. Niye? Üzerinde işlem yapılsın diye. Fakat, bize göre bu tür bir nesne tasarımı, işlevsel tasarım kokuyor, nesnesel değil. Sürekli tekrar eden bildirgeçler, eksik olan bir nesnenin işareti ise, demek ki, Vector'ü kapsayan (encapsulate) etmesi gereken bir nesne eksik.

Nesneler, anlık durumları olan ve bu durumu hatırlayabilen kavramlardır. Bu özelliği kullanalım: Vector gibi bir değeri sadece bir kere gönderip, bu Vector'ün bu yeni kapsayan yeni nesne tarafından muhafaza edilmesini sağlamalalıyız. Bu yapıldıktan sonra, artık sonraki bütün işlemler içerde tutulan Vector üzerinde yapılacaktır, yani Vector'ün bir daha geçilmesine gerek kalmaz.

//
// yeni sınıf
//
public class VectorYığıtı {

protected int tepeIndisi = ...;

protected Vector vector = null;

public VectorYığıtı(Vector v) {
vector = v;
}

public void ekle(Object eleman) {
vector.add(eleman);
}

public Object cikart() {
...
return vector.get(tepeIndisi);
}
}

public class Isleyici {

public void birIslem() {
}

public void baskaBirIslem() {
}
}

İşte bu kadar! Böylece İşleyici nesnesi daha anlaşılır hale geldi, ve yeni VectorYığıtı nesnesi çok daha temiz.

JSP'nin Geleceği - JSTL

JSP etiket dilinin temel özelliklerini gördüğümüz yazıda, HTML etiketleri içeren bir sayfanın içine nasıl Java kodları koyabildiğimizi göstermiştik. Ayrıca, JSP'nin bir standart olarak yeni etiketlere izin verdiğine kısaca değindik.

JSTL, Sun şirketinin JSP üzerine kurduğu bir etiket kütüphanesidir. JSP'nin dil olarak ve özellikle bilgi işlem uygulamaları için yetersiz kaldığı farkedilince, JSTL dili piyasaya çıktı. Zaten, ATG gibi güçlü Uygulama Servis programları, standart dışında kalmış olmalarına rağmen kendi etiket kütüphanelerini uzun süredir kullanıyorlardı. Bunda JSP'nin çok temel oluşu, ATG örneğinde ise, daha revaçta bile olmayışı tabii ki büyük bir rol oynamıştır.

JSTL'in JSP'den üstünlüğü birkaç yerde toplanıyor:


* Sayfa içinde uzun Java kodları koymaya gerek kalmıyor. Normal Java kavramlarının karşılıkları "etiket olarak" mevcut.
* JSTL altında XML tarzı etiket kullanımı fazlalaştığı için, içerik üreten program(cı)lar, sayfaları daha rahat değiştirebiliyorlar ve geliştirilen sayfa, geliştirme safhasında önizlenirken (preview) tarayıcıda aslına daha yakın gözüküyor.
* JSTL, Model/Şekil/Kontrol kavramını tercih ettiği için, bu yazılım kalıbını program üzerinde teşvik etmiş oluyor, ve dolaylı olarak daha temiz mimariye yönelmiş oluyoruz.

Model/Şekil/Kontrol mimarisi, 'model' olarak yazılmış işlem mantığının 'kontrol' kodları tarafından değiştirildiği ve sonucun 'şekil' üzerinde gösterecek şekilde kurulmuş sistemlere (mimariye) verilen addır. Günümüz Internet/Java mimarisinde model Java bean/işlem mantığı kodları, şekil JSTL etiketleri (ve yardımcı görsel kütüphaneleri), kontrol da Servlet ya da görüntüsüz JSP kodları olarak tanımlanabilir.

Bizim tavsiyemiz, örnek mimari olarak Servlet/JSTL/Java-JDO dörtlüsü ile çalışmanız.

Kurmak İçin

Tomcat için JSTL kurmak istiyorsanız, Jakarta adresinden Etiket Kütüphanesini indirin. Kurduktan sonra, eğer Tomcat altında çalışıyorsanız, (sitenizin-ismi)/WEB-INF/web.xml altında, şunu tanımlayın.

<web-app>
..
<taglib>
<taglib-uri>http://java.sun.com/jstl/core</taglib-uri>
<taglib-location>/WEB-INF/tags/c.tld</taglib-location>
</taglib>
..
</web-app>


Not: Burada tarif edilen bütün basamakları, sitenin kaynak kodlarında, ayartanım dosyalarında, ve Ant build.xml dosyasında bulabilirsiniz. Detaylı tarif edebilmek bakımından yazıda belirtmeyi uygun gördük. Kod detayları için her zaman site arşivine bakabilirsiniz.

Şimdi, (sitenizin-ismi)/WEB-INF/tags/ adlı bir dizin altına, Jakarta'dan gelen tld dosyalarını kopyalayın. Bunu Ant'e otomatik olarak yaptırabilirsiniz.

(sitenizin-ismi)/WEB-INF/lib/ altına, Jakarta'dan gelen jar dosyalarını kopyalayın. Bunu da Ant'e otomatik olarak yaptırabilirsiniz.

Artık JSTL kullanmayı istediğiniz her sayfanın başında, şu ibareyi kullandıktan sonra, JSTL'iniz çalışıyor olacak.

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>


Örnek olarak, JSTL'in etiketlerinin neler içerdiğini görelim.

JSTL Kullanım Kalıpları

JSTL, oturum veya istek seviyesinde Java nesnelerine erişerek, get..() işlemlerini çağırabilir, ve sonuçları döngü kullanarak tablo içinde, ya da bağlantı olarak tıklanabilir şekilde sayfanızda gösterebilir. Basit bir örnekten başlayacak olursak, 1..10 arası sayan bir döngü kurmak için,

<c:forEach var="i" begin="1" end="10">
<c:out value="${i}"/>
</c:forEach>


Bu tabiri kullanmak, şu şekilde kodlamaktan çok daha iyi değil mi?

..
<%
for (int i=0; i<10; i++) {
%>
<%=i%>
<%
}
%>



JSP kodu üzerinde Java'nın nerede bitip nerede başladığı anlaşılmıyor. JSTL ile herşey etiket. Yani JSTL kodunun bakımı ve değiştirilmesi daha rahat olacak.

Bağlantı göstermek için, c:url tabirini kullanabilirsiniz.

<a suraya="<c:url value="urun_detay_goster.jsp">
<c:param name="urun" value="${urun.no}"/></c:url>">
<c:out value="${urun.isim}"/>
</a>


Eğer, List arayüzünü uzatmış olan bir Java nesnesinin 'elemanlarını' teker teker işlemek istiyorsanız, JSTL ile bu çok basit:

<c:forEach var="i" items="${nesne.liste}">
<!-- ${i} ile istedi�inizi yapın.. -->
</c:forEach>


Bu örnekte, nesne değişkeni üzerinde getListe() işleminin tanımlanması gerektiğini belirtelim. JSP standardi, get.. önek kısmının koyulmasına gerek bırakmadan, 'liste' dediğinizde 'getListe' işlemini çağırıyor.

Peki O İlk Nesne Nereden Geliyor?

Bu çok önemli bir soru, ve cevabı programınız üzerinde mimari etkileri olacak. Pür dikkat..:)

JSTL örneklerinde çoğu zaman, bir oturum nesnesine ya da istek (request) üzerinden bildirgeçlere erişildiğini görürsünüz. Fakat, filanca listeyi döken hangi nesnedir, bu sonucu JSTL'e nasıl iletir gibi soruları cevaplamak gerekir, çünkü bu soruların cevabı yazılım mimarisi üzerinde etkileri vardır. Bu tür bir kullanım stratejik bir karardır, kalıp olarak bir kez karar verilir, ve her ihtiyaç olan yerde kullanılır.

JSTL, en rahat olarak oturum üzerinden get..() işlemlerini tanımlamış nesneler ile çalıştığı için, şöyle bir mimari size kolaylık sağlayacaktır.


* Kullanıcı isteği (bağlantı tıklaması), bir Servlet'e gider.
* Bu servlet, işlem mantığı nesnesi ya da direk JDO (veya JDBC ile) kullanarak veri tabanına erişir.
* Tabandan gelen sonuçları bir Java "List" nesnesi üzerinde saklar (ArrayList olabilir).
* Servlet bu List nesnesini, Oturum (session) üzerine ekler.
* Yönlendirme (redirect) ile kontrolü JSTL'e aktarır
* JSTL, aynı şekilde oturuma erişerek verileri "alır" ve ekranda biçimlendirerek gösterir.

Bu şekilde kullanımı site kodlarının yeni sürümünde bulabilirsiniz.

Referans olarak Manning adlı yazardan JSTL komut listesi yararlı olabilir.

Saturday, October 29, 2005

Java İle Nasıl Dosya Kopyalanır?

Java 1.4 Öncesi

Şu anki mevcut "engin" Java arayüzleri ve kütüphaneleriyle bile, bâzen basit bir istek bizi hazırlıksız yakalayabiliyor. "Bir dosyayı Java'da nasıl kopyalayabiliriz?". java.io.File sınıfında gerekli işlemin olduğuna inanırken, Javadoc'larda bir inceleme durumun böyle olmadığını gösterdi. Eh, o zaman bu kopyalama sınıfını sıfırdan yazmak gerekti. Aşağıdaki kod 1.4 öncesi ve sonrası Java derleyicileri için verilmiştir.

import java.io.*;

public class Kopyalayici{

public static void main(String args[]){
try {
Kopyalayici j = new Kopyalayici();
j.dosyaKopyala(new File(args[0]),new File(args[1]));
}
catch (Exception e) {
e.printStackTrace();
}
}

public void dosyaKopyala(File giris, File cikis) throws Exception {
FileInputStream fis = new FileInputStream(giris);
FileOutputStream fos = new FileOutputStream(cikis);
byte[] buf = new byte[1024];
int i = 0;
while((i=fis.read(buf))!=-1) {
fos.write(buf, 0, i);
}

fis.close();
fos.close();
}

}


Java 1.4

import java.nio.channels.*;
import java.io.*;

public class Kopyalayici2 {
public static void main(String args[]){
try {
Kopyalayici2 j = new Kopyalayici2();
j.kopyala(new File(args[0]),new File(args[1]));
}
catch (Exception e) {
e.printStackTrace();
}
}

public void kopyala(File giris, File cikis) throws Exception {
FileChannel kaynakKanali = new
FileInputStream(giris).getChannel();
FileChannel hedefKanali = new
FileOutputStream(cikis).getChannel();
kaynakKanali.transferTo(0, kaynakKanali.size(), hedefKanali);
kaynakKanali.close();
hedefKanali.close();
}
}

Java İle Eposta (JavaMail)

Java ile e-posta göndermek oldukça basit. Referans olması açısından aşağıdaki kod parçasını paylasıyoruz.

import java.util.*;
import java.io.*;

import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;

public class Postaci
{

public static void main(String args[]) throws Exception {

Properties props = System.getProperties();
props.put("mail.smtp.host", "mail.sizinsirket.com");
Session session = Session.getDefaultInstance(props, null);

Message msg = new MimeMessage(session);

msg.setFrom(new InternetAddress("ben@orada.com"));

InternetAddress[] tos =
InternetAddress.parse("alici-eposta-adresi@sizinsirket.com");

msg.setRecipients(Message.RecipientType.TO,tos);

msg.setSubject("Java Eposta testi");

msg.setSentDate(new Date());

msg.setText("Bu mesaj Java'dan gönderilmistir...");

Transport.send(msg);

}
}



Java Mail'in çalışması için Java Tetikleyici Altyapısı (Javabeans Activation Framework) gerekiyor. Aşağıda gerekli bağlantıları bulabilirsiniz.

Kaynaklar


* Java Eposta (JavaMail)
* Java Tetikleyici Altyapısı (Javabeans Activation Framework)

Friday, October 28, 2005

Hibernate ve Önbellekleme

Eğer bir bilgi işlem uygulaması, herhangi bir tip veriyi veri tabanından yazdığından daha fazla okuyorsa, o veriyi tabandan servislemek yerine hafızadan servislemek daha hızlı olacaktır. Önbellekleme tekniğinin altında yatan fikir, özet olarak, budur.

Önbellek tekniğini çoğu uygulamada görebilirsiniz. Meselâ, her modern ticari veri tabanı paketi (Oracle, DB2, Informix), kullanıcı ile tablolara erişim arasında bir önbellek katmanı koyarlar. Aynı sorguyu birden fazla arka arkaya işletirseniz, ikinci sorgunun sonuçları önbellekten veriliyor olacaktır. Veri tabanları, özellikle eski olanları, bu tür optimizasyonları artık hakkıyla yapmışlardır. Parçası olduğum bir projede, önbellekleme dahil işlem (transaction) ve eşzamanlı (concurrency) işletim kontrolleri, veri erişimi gibi altyapı kodlarını elle yazmakta olan takım, projenin geciktiğini farkedince bu kodları atıp şunu demişti: "Sonuçta Oracle da önbellekleme yapıyor, buna güveneceğiz". (Not: Yıl 1996 idi, yâni doğru dürüst yardımcı paketler daha ortada yoktu).

Hakikaten de, bir bilgi işlem uygulamasının %80 kadar zamanının veri tabanında geçtiğini düşünürsek, veriye erişim ile alâkalı iyileştirmelerin veri tabanı tarafında en iyi olarak yapılacağını da görmemiz gerekir.

Ayrı Önbellek Paketleri

Peki o zaman son zamanlardaki başgösteren uygulama servisini içinde, ayrı işleyen önbellek paketleri arayışının sebebi nedir?

Bu arayışın nüksetme zamanının, programcılari veri tabanından daha iyi izole eden araçlar (JDBC ve daha üst seviyede kalıcılık araçları) kullanımlarının artması ile aynı zamanlarda olması ilginçtir. Özellikle modern kalıcılık araçları, proje takımlarını hem veri tabanı paketinden bağımsız olabilme hem de bunu temiz bir kodla yapabilme yeteneğini çok rahat sağladıkları için (pür JDBC kodu rezalettir), teknik liderler şunu düşünür olmuşlardır. "Artık yazdığım kodu, hem Oracle hem de MySql üzerinde işletebilirim".

Bu fikir takip edersek, evet Oracle'dan bağımsız olabiliriz, ama Oracle'ın o uzun yıllardır optimize edilmiş önbellek katmanını da kullanamayacağız. En azından, o "diğer" veri tabanı paketinin önbellekleme kodlarına gözü kapalı güvenemeyeceğiz. Sonuç: Önbellekleme artık uygulamanın bir parçası olmalıdır, ve bu tür özellikleri sağlayabilen "veri tabanından ayrı" paketler aranmalıdır.

Tabii şunu da eklemek gerekir: Veri tabanı önbellekleme yapsa bile, uygulama seviyesinde de elle önbellekleme yapması uygun/gereken uygulamalar vardır. Teknik olarak en basit türden önbellekleme tekniği, bir transaction başında önbelleğe okuyan ve bu veriye birçok kez erişen, ve sonra önbellek içindeki verileri atan ve tekrar başlayan uygulamadır. (Transaction sınırlarını aşan önbellekleme, önbelleğin güncellenmesi problemini beraberinde getirir, bunun elle yapılmasını kod temizliği açısından tavsiye etmiyoruz. Hattâ, yazının geri kalanında önbelleklemenin hiçbir şekilde, elle yapılmamasını tavsiye ettiğimiz göreceksiniz. Bu tür altyapı (infratructure) türü kodları bu işte uzmanlaşmış kimselere/paketlere bırakılmalıdır).

Hibernate

Şimdi gelelim Hibernate bağlamında önbellek kullanımına. Hibernate paketini kalıcılık aracı olarak seçmemizin önemli bir sebebi de, bağlantı havuzu, önbellekleme gibi işleri dış araçlara bırakmış olması, ve kendi öz kodu olarak, sadece veriye erişim problemine odaklanmış olmasıdır. Önbellekleme ihtiyaçları, Hibernate içinde tanımlanmış olan kod çengelleri sayesinde ve bu çengellere takılabilen her dış paket sayesinde halledilmiştir.

Bu çengellere takılabilen açık kaynak önbellek paketleri arasında EHCache, OSCache, SwarmCache, JBoss TreeCache sayılabilir. Hibernate ile uyumlu ticari önbellek paketleri de vardır: Coherence, GigaSpaces bunlardan sayılabilir.



Dağıtık (Distributed) Önbellek Kullanımı

Kavram ve kullanım açısından tek JVM içinde önbellek oldukça basit olduğu için, bu seçeneği daha fazla tartışmayacağız. Mimarinizi etkileyebilecek kararlar ve çoğu teknik liderin bilmediği, Hibernate'i dağıtık bir mimari içinde kullanırken elde olan seçeneklerdir, yâni dağıtık mimarida önbelleğin nasıl kullanılacağıdır.

Genel olarak konuşmak gerekirse, ilk prensibimiz şu olmalıdır. Occam'ın Usturası desturundan yola çıkarak "iki açıklama arasından, en basitini seçiniz" sözünü, mühendisliğe uygularsak, her zaman en basit, temiz ve işleyen yolu seçmemiz gerekir. Dağıtık mimari için önbellek kullanımı, tek JVM için önbellek kullanımından farklı olmamalıdır. Eğer önbellek kullanmak için mimari değişiriyorsanız, kendinizi tokatlayın. En görünmez (transparent) olması gereken ihtiyaç için, mimarinizi feda etmektesiniz.

Alt resimde görülen mimari, bir gerçek hayat uygulamasından alınmıştır. Tasarımı yapan mimar, uygulamayı fonksiyonel olarak dağıtmayı planlamış (her parça bir fonksiyonel öbeğe tekabül etmektedir). Uygulamasını hızlandırmak için de önbellek kullanmayı mimar daha baştan aklına koymuştur.

Ve akabinde, "peki, önbellek içeriği değiştiğinde diğer öbeklerin bundan nasıl haberi olacak?" sorusu ile karşı karşıya kalmıştır. İşte bu noktada, teknik liderin pergeli şaşmış, ve basitlik için önbelleği feda edip veri tabanına bırakmak yerine, bütün dağıtık fonksiyonel birimleri tek bir makinaya, önbelleğin tutulduğu yere yöneltmeyi seçmiştir. Üstelik erişilen veri kolon seviyesinde olduğundan, bu seçim, network üzerinden birimler arasında çok fazla git/gel'e (chatter) sebebiyet verecektir. Önbellek kodunun elle yazılacak olması ayrı bir külfettir, ve bakım (maintanance) gerektiren kodu arttırdığı için ayrı bir eksidir. Ne açıdan bakarsak bakalım, bu mimari idaresi kodlaması zor bir mimaridir.

Önbellek "paylaşmak" için network'e giden kod yazmayın.


Doğru prensipler/altın kurallar (rule of thumb) insanı yeteri kadar teknik bilgisi olmasa da başına ağrıdan kurtarır. "Basitlik" ve "network üzerinden getXX yapılmaz" prensibini taşımayan lider, "illâ önbellek" için mimarinin temizliğini ve performansı feda etmiştir. Bahsedilen tabloların büyüklüğü de hiçbir kendine saygısı olan veri tabanına problem verecek ölçüde değildir, üstelik bahsedilen erişim nokta sorgusu yapacaktır. PRIMARY KEY, DB, tek satır sonuç.

Dağıtık Önbellek

Fakat eğer Hibernate seçenekleri seçim torbasında ise, dağıtık mimariler için OSCache ve JBossTree Cache mevcuttur.

Bu paketlerin çalışması çok ilginç: Meselâ makina #1,makina #2,makina #3 aynı uygulamanın değişik öbekleri (cluster) olsunlar. Ya da fonksiyonel şekilde bölünmüş ama aynı veriye erişen hatta değiştiren katmanlar olsunlar, hiç farketmez.

Her uygulama parçası, kendi önbelleğini başlatabilir. Ve her uygulama parçasının önbelleği, Hibernate kullandığı ve hibernate.properties dosyasında uygun şekilde OSCache ya da JBoss Tree Cache kulllandığı anda, diğer önbellek birimleri ile multicast protokolü üzerinden -yayın (broadcast) bazlı- iletişime geçmektedirler. Alt katmandakı önbellek kodu bizden habersiz bir şekilde (JBoss Tree Cache durumunda) yeni eklenen ya da (OSCache durumunda ise) silinen nesnelerin ne olduğunu birbirlerine bu protokol üzerinden iletip, tüm önbelleklerin tüm makinalarda güncel ve birbirleri ile uyumlu kalmasını sâğlamaktadırlar. Eh zaten veri tabanın da kapı anahtarı Hibernate'in elinde olduğu ve bu önbellek araçlarının Hibernate'e eklemlenmiş olduğunu düşünürsek, önbellek veri tabanı ile de uyumlu hâlde olacaktır.

Ve tüm bu aynı tutma (synchronization) işlemi tamamen arka planda, kodcuya görünmez bir şekilde yapılmaktadır. Programcının tek yapması gereken, ayar babında, önbelleğin ne kadar büyük ya da küçük olacağını tanımlamaktır. Akılda tutulması gereken programlama püf noktası, JBoss Tree Cache için commit() işleminin, OSCache için de session.close() komutunun önbelleklere bilgi göndermeyi tetiklemesidir. JBoss Tree Cache değişen nesneleri, OSCache ise silinen nesnelerin diğer önbelleklerden silinmesini haber verir.

Yâni sıfır ek kod yazarak, alttaki resme kavuşmuş oluyoruz.


Performans olarak, bir Ethernet network'ünün zaten donanım olarak yayın bazlı olduğunu düşünürseniz, yayın bazlı donanım üzerinde yayın bazlı protokolün (multicast) çok hızlı olacağı sonucu çıkar.

Bir Matematikçi'nin Savunması Hakkında

Bu yazıda, İngiliz matematikçi Hardy'nin kitabından [1] bahsedeceğiz. Bu kitapta katılmadığımız bazı görüşlere cevap vermek, ve aynı zamanda matematiğin çeşitleri, zorlukları hakkında bazı düşünceleri paylaşmayı amaçlıyoruz.

Şahsi görüşümüze göre, Hardy'nin "Bir Matematikçinin Savunması" adlı eseri, Charles Snow'un İki Kültür [2] adlı kitabı ile beraber okunmalıdır. Charles Snow, Hardy ile aynı yıllarda Cambridge üniversitesi'nde araştırma yapmış, hem bilim, hem de edebiyat dünyasına aynı derecede yakın olan ender bir insandı. Eseri olan İki Kültür, bu iki dünyanın arasındaki farkları ortaya çıkaran önemli bir yapıttır. İki kültür arasındaki farkları açıklarken Snow, içinden çıktığı bilim dünyasının ilginç simâlarını tanıtmış, ve çuvaldızı bazen kendisine de batırmaktan kaçınmamıştır.

Snow'dan öğrendiğimize göre, üniversitede olduğu zamanlar Cambridge Üniversitesi'nde yaygın bir "uygulamalı bilimci/temel bilimci" ayrımı vardır. Snow, bu zamandan şöyle bahseder: "Mühendisler ve uygulamalı bilim karşısında temel bilimciler genelde donuk bir tavır takınır. Onlarla bir türlü ilgilenmezler. Bu alandaki sorunların çoğunun düşünsel açıdan temel bilimlerin ilgilendiği sorunlar kadar çaba istediğini, bulunan çözümlerin çoğunun da onların çözümleri kadar tatmin edici ve güzel olduğunu fark etmezler. Galiba, bu ülkede (İngiltere) sık rastlanan, mümkün olan her yerde yeni bir züppelik bulma, eğer yoksa bir yenisini icat etme ihtirasının da keskinleştirdiği içgüdüler, onları, uygulamalı bilimlerin ikinci sınıf kafalara göre bir uğraş olduğu kanısını sorgusuz sualsiz benimsemeye iter. Bunu böyle kesin bir edayla dile getiriyorum, çünkü otuz yıl önce ben kendim de tam olarak bu kanıdaydım" [3]

Snow baştaki fikirlerini değiştirerek, II. Dünya Savaşında sanayi ile yakın alâka kurması gerektiği için, mühendisliğe daha bir saygı kazanmıştır. Son vardığı fikrini şöyle belirtiyor: "Birini uçak tasarlarken görürseniz, parçacık fiziğinde bir deney yaparken yaşanan -estetik, düşünsel, ahlâki- deneyimin aynısını yaşadığını fark edersiniz" [4]

Hardy, bu görüşlerin benzerini, "temel matematiğe karşı bilimde kullanılan matematik" bağlamında savunuyordu. Hardy'ye göre, asıl/gerçek/zor olan matematik "yararsız" olmalıydı.

Yararsız matematik hakkındaki Hardy'nin görüşlerini tarih biraz geçersiz kılmıştır dersek yeridir. Meselâ en yararsız gözüken sayılar teorisi (hatta bu örnek Hardy'nin kendisi tarafından da kullanılmıştır), şifreleme sistemlerinde büyük uygulama alanı bulmuştur. Burada ünlü matematikçi Lobachevksy'nin sözleri daha geniş ve daha uygundur sanıyorum: "Ne denli soyut olursa olsun, hiçbir matematiksel çalışma yoktur ki, bir gün gerçek dünyada olup bitenlere uygulanma olasılığı bulmasın" [5].

Yâni aslında Hardy'nin görüşlerine ekleme yapıp, tersine çevirerek şöyle düzeltmek gerekir:

"Herşeyi uygulama merceğinden görmeyelim. En yararsız gözüken matematik bile, bir gün kendisine uygulama sahası bulacaktır. Matematik için matematikten, yararsız olduğu düşüncesi ile uzaklaşmayalım".

Bizce, bilim dalı seçme meselesi bir mizaç meselesidir. Eğer, kesin ve değişmez gerçeklere meraklı, felsefi yapılar kurmaya meyilli, ve ne olduğunu merak eden türden bir insansanız, matematik için matematik sizin içindir.

Eğer, doğada neler olduğunu merak ediyorsanız, ve oldukça ileri matematiksel yöntemlerle kuramlarınızı modellemek [6] istiyorsanız, temel bilim ve uygulamalı matematik sizin içindir.

Eğer olanları kontrol etmek istiyorsanız, doğa yasalarını kullanarak emrinize almak, bunun ile doğa üzerinde güç kazanmak istiyorsanız, mühendislik size göredir.



Yazmak Hakkında

Şimdi gelelim, Hardy'nin evirilse de çevirilse de düzeltilemeyecek olan son görüşüne: "Açıklama, eleştiri, övgü ikinci sınıf beyinlerin işidir". Ünlü fizikçi Richard Feynman bu sözleri duysa herhalde mezarında ters dönerdi. Kendisi yıllarca, Caltech üniversitesi 1. ve 2. sınıf öğrencilerine Fiziğe Giriş dersi vermişti. Feynman'a göre, "bir şeyin özünü anlamışsak, onu her düzeyde anlatabilirdik". Bu konu hakkında Feynman'ın arkadaşı David Goodstein şunu anlatır.

"Bir gün Feynman'a şöyle dedim: "Dick, bana öyle izah et ki, 1/2 spinli parçacıkların neden Fermi-Dirac istatistiğine uyduğunu anlayabileyim. Feynman, dinleyici kitlesini aklınca şöyle bir tartarak "Bu konuda bir birinci sınıf dersi hazırlayacağım" demişti. Fakat birkaç gün sonra geri gelip "Yapamayacağım. O konuyu birinci sınıf düzeyine indirgeyemiyorum. Aslında bu, onu iyice anlamadığımızı gösteriyor" demişti" [7].

Feynman, çok iyi bir hocaydı, ve öğretmek, öğretmek teknikleri hakkında sürekli düşünen bir insandı. Nobel ödülü kazanmış bir fizikçi olduğuna göre, Hardy'nin yazanlar, öğretenler hakkındaki görüşlerinin ne derece geçersiz olduğu belli olmaktadır.

Kaynakça


* [1] G.H. Hardy, Bir Matematikçi'nin Savunması, Tübitak
* [2] C.P. Snow, "İki Kültür", Tübitak
* [3] C.P. Snow, "İki Kültür", Tübitak, s. 125
* [4] C.P. Snow, "İki Kültür", Tübitak, s. 166
* [5] Cemal Yıldırım, "Matematiksel Düşünce, Remzi Kitabevi, s. 122
* [6] Matematiksel Modelleme (Sayilar ve Kuramlar makalesi)
* [7] D.L. Goodstein, J.R. Goodstein, "Feynman'ın Kayıp Dersi", s. 37

Wednesday, October 26, 2005

DB Şemasının Grafiği

Veri tabanı şemaları ile çalışırken, özellikle daha önceden kurulmuş bir şemayı anlamaya uğraşırken, tabloları ve onların arasındaki ilişkileri (foreign key constraints) görsel olarak görebilmek büyük bir avantaj sağlar. Bunu yapacak olan araç, Oracle (ya da diğer bir) veri tabanına bağlanarak sözlük (dictionary) yapısını sorgulayacak, ve aldığı ilişki bilgilerine dayanarak çok rahat bir şekilde bir figür çizebilecektir.

Meselâ piyasadaki Erwin gibi bir araç, bir şemayı grafik olarak tasarlamaya bile izin vermektedir. Şema tasarımı grafik olarak yapıldıktan sonra, gerekli olan DDL (CREATE TABLE, ALTER TABLE) komutları araç tarafından bir metin dosyasına yazılabilmektedir. Bu komutlar Oracle komut satırı sqlplus üzerinden direk veri tabanı üzerinden çalıştırılabiliyor.

Bir tek problem var: O da Erwin'in ticari bir araç olması. Projemizin gerekleri için açık yazılım olan bir uygulamaya ihtiyacımız vardı, ve biz de dbViz adlı bir aracı bulduk. Projemizin ihtiyacı olan, mevcut şemayı grafik olarak göstermekten ibaretti ve dbViz tüm bu ihtiyaçlarımızı yeterli bir şekilde karşıladı.

Kullanım

dbViz'i başlattıktan sonra, "File | Import Schema | Import From Database" seçeneklerini takip edin. Bunlardan sonra aşağıdaki Oracle bağlantı bilgilerini isteyen bir kutu gelecektir.


Bu bilgiler girildikten sonra, diyelim ki aşağıdaki gibi bir şemayı daha önceden sqlplus ile Oracle üzerinde yaratmış olalım:

-- A tablosu
CREATE TABLE A
(
ANAHTAR VARCHAR2(10),
B_ANAHTAR VARCHAR2(10),
DEGER1 NUMERIC,
DEGER2 NUMERIC
);

-- A'nin asal anahtari
ALTER TABLE A ADD CONSTRAINT pk_A PRIMARY KEY(ANAHTAR);

-- B tablosu
CREATE TABLE B
(
ANAHTAR VARCHAR2(10),
DEGER1 NUMERIC,
DEGER2 NUMERIC
);

-- B'nin asal anahtari
ALTER TABLE B ADD CONSTRAINT pk_B PRIMARY KEY(ANAHTAR);

-- A dan B'ye iliski (foreign key constraint)
ALTER TABLE A ADD CONSTRAINT fk_A_DAN_B_YE FOREIGN KEY (B_ANAHTAR) REFERENCES B(ANAHTAR);

Bu şemanın grafik olarak çıktısı aşağıdaki gibi gösterilecektir.


Dikkat edelim: Üstteki resimde, aracı kullanırken B kutusunun üzerine tıklamış olduğumuz gözüküyor. Bu kutuya tıklayınca B'ye ait olan kolon isimleri ve B tablosunun diğer tablolara olan bağlantılarının bir listesi gözüküyor (sol alttaki iki kutu). Listelenen her değerin yanındaki checkbox'u kullanarak grafik olarak neyin gözüktüğünü kontrol etmek bizim elimizde.

Kaynaklar


* DbViz Projesi
* Erwin

Sunday, October 23, 2005

CVS Nasıl Kurulur - SSH Kullanarak

Öteki yazılarımızda CVS özelliklerinden bahsettik. Bu yazımız, sistem idarecileri için. CVS sistemini kurmanın birkaç değişik yolu olabilir; burada sunacağım yöntem SSH kullanıyor. Basit ve güvenilir olduğu için tavsiye ederim.

İlk önce CVS programını indirelim. Solaris için www.sunfreeware.com adresinden, ya da CVS'i silbaştan derlemek için, ftp://ftp.gnu.org/gnu/non-gnu/cvs/cvs-1.11.tar.gz adresinden size lazım olan dosyaları alabilirsiniz.

Eğer silbaştan derleme yapıyorsanız, TAR dosyasını açın, ve ortaya çıkan dizin içine cd ederek gidin. Sonra şunu işletin:
./configure
make
make install

Kullanıcı Yaratmak

'cvs' adlı bir Unix gurubu yaratın. Ayrıca, CVS kullanacak her programcı için, ayrı bir Unix kullanıcısı yaratmanız lâzım.

Deneme Havuzu

Kurduğumuz CVS programını denemek için, /tmp/deneme1 adlı bir dizin yaratın. Kaynak kod havuzu bu dizin altina gidecek. Dizin sahipliğini cvs gurubuna verin. Ayrıca, sahip gurup için dizini okunur/yazılır hale getirin. Sonra aşağıdaki komutu işletin:
$ cvs /tmp/deneme1 init

CVS servisi

root olarak servis sistemine girin ve aşağıdaki satırları inetd.conf dosyasına ekleyin.
cvspserver stream tcp nowait root /usr/local/bin/cvs cvs -b /usr/local/bin pserver

Sonra, tekrar root olarak /etc/services dosyasina girin. Şunu ekleyin:
cvspserver      2401/tcp

En son inetd işlemini (process) HUP edin (tekrar baslatin yani). Şu komutu kullanabilirsiniz: kill -HUP (islem nosu).

sshd işleminin calıştığını kontrol edin. Kutlarım, sunucu tarafındaki işiniz bitti.

Bağlanan kullanıcı sistemler için

CVS'e bağlanan sistemler için bazı ayarlamalar lazım. Her CVS kullanıcısı, öncelikle hangi havuzda işlem yapacağını belirtmeli. cvs -d (havuz_ismi) seçeneği ile bunu rahatça yapabilir, ya da CVSROOT çevre degişkenini tanımlayabilir, böylece sürekli -d kullanmasına gerek kalmaz.

Genelde CVSROOT yöntemini kullanmanızı tavsiye ederim.

Eğer kod havuzu yerel ise (aynı makina üzerinde yani), o zaman
export CVSROOT=/tmp/deneme1
kullanılabilir.

Fakat havuz ile kullanıcı ayrı sistemlerde ise (ki umumiyetle böyle olur), o zaman
$ export CVSROOT=:ext:remoteuser@hostname:/tmp/deneme1
ve
$export CVS_RSH=ssh
kullanmak lâzımdırr.

En son satır, bağlantı protokolu icin SSH kullanılmasını belirtir. Eger bunu boş bırakırsanız, rsh kullaıllacaktır. "ext:" demek 'external' kelimesinden gelir, yani 'dışarıda' demektir. Kod havuzunun dışarıda olmasının sebebi ile ext kullanmak zorunda kaldık.

Kullanıcı Denemesi

Kullanıcı makinasında $HOME dizinine gidin ve $HOME altında yeni bir 'çalışma' dizini yaratın. İsmi 'benim_projem' olsun mesela. Sonra, aşağıdaki komutları işletin.
$ mkdir benim_projem
$ cd benim_projem
$ cvs update .

En son komut, CVS havuzunda olan bütün kodları alıp, benim_projem altına koyacaktır. Öteki CVS komutları için yardım dosyalarına başvurun.

Yukarıdaki tariflerden sonra, SSH üzerinden havuza erişsim mümkün olacak. Fakat, SSH kullandığınız için sistem sizden habire şifre girmenizi isteyecektir. Merak etmeyin, bu problemin de bir kestirmesi var. SSH programı, 'şifresiz giriş' denen kavramı destekliyor. Tam bize lazım olan teknoloji.. Nasıl kurulacağını ekteki yazıdan okuyabilirsiniz.

Sorun Çıkarsa

Ekteki problemler çıkabilir.


* 2401 portu ile ilgili problemler: Bazen kullanıcı sistemi, uzaktaki sistemini 2401 nolu portuna erişemeyebilir. Bunun değişik sebepleri olabilir, belki sistem idarecileri güvenlik için o portu kapattılar. Kontrol etmek icin "telnet havuz_bilgisayar_ismi 2401" komutunu işletin. Eğer hata yoksa port açık demektir.
* End-of-file mesajları: Eğer CVS_RSH değişkeni doğru tanımlanmamış ise bu problemler çıkabilir. Değişkene değer yükledikten sonra belki export etmeyi unuttunuz.

Saturday, October 22, 2005

Cebirde Çift Yanlış Yöntemi - Ali Kuşçu

(Aşağıdaki makale, ünlü Türk matematikçisi Ali Kuşçu'nun Fâtih Sultan Mehmet'e 1473 tarihinde sunduğu eserinden alınmıştır. Eserin ismi el-Muhammediye fi el-hisab'tır. Çift yanlış yöntemi, doğrusal denklemlerde bilinmeyen(ler)i hesaplamak için kullanılmaktaydı. Makale, dil ve matematiksel simgeler olarak günümüze uyarlanmıştır).

Çift yanlış yöntemi, bilinmeyeni dilediğimiz herhangi bir sayı varsaymamız ve üzerine sonuca ulaşana değin soranın sözünden anladığımız şekilde işlem yapmamızdır. Sonuç bilinen sayıya uyuyorsa istenen sayı odur. Uymuyorsa yaptığımız işlemden hâsıl olan ile bilinen sayı arasıdanki farkı alırız. Bu birince yanlış olarak adlandırılır. Sonra bilinmeyeni başka başka bir sayı varsayarız. İkinci bir sonuca ulaşana dek yaptığımız işlemleri ona da uygularız. Sonuç bilinen sayıya uyuyorsa istenen o sayıdır. Uymuyorsa onun ile bilinen sayı arasındaki farkı alırız. Bu da ikinci yanlış olarak adlandırılır. Daha sonra iki yanlıştan bir doğru çıkartılır.

Şöyle ki: Birinci varsayılan ile ikinci yanlış, benzer biçimde ikinci varsayılan ile birinci yanlış çarpılır. Her iki yanlış beraberce bilinen sayıdan artık ya da eksik ise iki çarpım sonucunun farkını iki yanlışın farkına böleriz. Bu işlemden çıkan sonuç talep edilen bilinmeyen sayıdır. Artıklıkta ve eksiklikte muhtelif iseler iki sonucunun toplamını iki yanlışın toplamına böleriz. Çıkan sonuç talep edilen sayıdır [1].


Çok basit bir örnek


Ve buradan ikinci förmüle göre,


Kaynakça


* [1] Kutadgubilik Felsefe ve Bilim Araştırmaları Yayını, Mart 2003 Sayısı

Gavin King İle Mülâkat

Gavin King, Java için bir nesne/ilişkisel serbest yazılım ürünü olan Hibernate projesinin kurucusudur. Gavin, Melbourne'da yaşamaktadır, ve burada uzun süredir J2EE danışmanlığı yapmakta, açık yazılım ve çevik metodları yaymak için uğraşmaktadır. Gavin şu anda Expert IS şirketinde çalışıyor.


Gavin, bize biraz kendinden ve uğraştığın projeden bahsedebilir misin?

Hibernate projesinin kurucusuyum. Şu anda bâzen öteki projelere de girmem gerekiyor, çünkü bu projeler Hibernate'in de kullandığı araçlar; XDoclet ve Middlegen gibi. Bu tür yardımlara devam etmeyi planlıyorum, ve tabii ki Hibernate ile tam zamanlı uğraşıyorum ve gelişmesi için uğraşıyorum. Fakat çok fazla değişik proje ile uğraşmamaya özen gösteriyorum, çünkü temel işler ve başladığımız temel misyona en fazla zamanı ayırmak istiyorum.

Hibernate projesi nasıl başladı?

Hibernate'i başlattım çünkü EJB CMP ve EJB 1.1 ile uğraşırken, en önemli olan iş mantığı ile uğraşmak yerine, CMP/EJB teknolojisinin boşlukları/eksikliklerinin etrafından dolaşmak ile uğraştığımı farkettim. Çok fazla altyapı kodlaması yapıyordum ve bundan hoşnut değildim, ve bütün bu Entity Bean'ler yüzünden kaybedilen efordan sonra bile baktım ki eldeki kod halâ bir şeye benzemiyor, taşınabilir değil, tekrar kullanılır hâlde değil. Uygulama servisi dışında kullanılır değil, başka bir kalıcılık mekanizması ile kullanılabilir durumda değil, ve test edilebilir durumda hiç değil. Bu tür bir sürü problem... Bundan önce, TheServerSide sitesindeki forumlarda bu tür problemlerin varlığını hep işitirdik, şimdi bu sorunların gerçek olduğunu tecrübeme dayanarak söyleyebilirim. Bu sorunlar gerçek. Bu kadar insan Entity Bean teknolojisini bilmediği için bunu söylemiyor, bu teknolojinin (Entity Bean) yapısal problemleri var, ve bunları söyleyenler uzun süredir Java servis tarafı uygulamaları geliştiren insanlar.

En son sürümler EJB 2.0 ve EJB 2.1 bu problemlerin bazılarını çözmedi mi?

Evet ilerleme var, fakat Entity Bean'lerin en temel problemi olan geniş arayüzlü olan bir bileşen ile, iş alanı (domain) parçası bir kalıcı (persistent) nesnesinin birbirine uydurulmaya çalışılması problemi halen mevcut. Ve evet, EJB 2.0 bir ilerlemedir, fakat halâ koca bir özellik eksik: Kalıtım. Röportajın daha ilersinde herhalde öteki EJB eksikliklerine gireriz, biraraya toplama (aggregation) ve izdüşüm (projection) ve diğer eksikler. Bence yapılması gereken ilişkisel model ve nesnesel modelin biraz daha birleştirilmesi, ve iki model ile aynı anda çalışabilmemizin sağlanması.

Sizce Hibernate neden bu kadar başarılı oldu?

Bunu bizim Wiki sistemi üzerinde bir liste olarak yazmaya çalıştık, çünkü bu konu hakkında hakikaten kafa yorduk. Liste, "bir açık yazılımını başarılı yapan faktörler" olarak geçiyordu. Bu listede birçok şey var, fakat bence en önemlisi bir yazılımın etrafında bir topluluk, bir cemaat oluşturabilmemizdir. Öyle ki, kullanıcıların isteklerine kulağımız açık olması çok önemliydi ve yazılımda sorun çıktığında tamir edilerek çabuk bir şekilde kullanıcın problemine yardım edilmesi isabetli oldu. Kullanıcılarımız bir tavsiyede bulunduğu zaman da, ciddiye alınmış olmaları yazılım etrafındaki güçlü topluluk ruhunu teşvik etmiştir zannediyorum. Topluluk ruhu bu projenin etrafını sarmalayan güzel bir şey, ve proje bu sayede topluluğun gurur duyacaği bir eser haline geliyor. Bir başka yazılım projesinde, mesela, belki çok fazla akıllı insan olabilir ve bütün bu programcıların hepsinin çok güçlü fikirleri olabilir, ama bu fikirler çok çatışır ve anlaşmazlık olursa, beraberlik bozulabilir. Anlaşmazlık tabii ki normal, değişik fikirler de öyle, fakat bir açık yazılım geliştirmek istiyorsanız bence biraz birlik halinda olmanız lazım. Birşeyleri beraber yaptığımız hissini yaşıyor olmamız lazım.

İkincisi, proje belgelerimiz (documentation). Revaçtaki çok kaliteli olan birçok açık yazılım projesi, eğer belgelemeyi şöyle bir gurur ruhu ile yapabilselerdi ne kadar daha çok daha başarılı ve proje olarak daha iyi olurlardı! Bu benim için yaptığım işten gurur duymak gibi bir şey. Güzel bir iş yapınca, bunu belgeleyip herkes ile paylaşmak istemez misiniz? Herkes Hibernate'in belgelerinden iyi şekilde bahsediyor, çünkü bu belgeler ile gurur duyuyoruz. Bunu herkesin duymasını istiyoruz.

Üçüncü olarak, ve bu kanımca diğer açık yazılım projeleri tarafından da uygulanmalı, bu projeye başlarken şöyle dedim: "Kalıcılık konusunda uzman değilim, bütün cevapları bilmiyorum, ama kullanıcılar ile konuşarak, istediklerini öğrenerek onları tatmin edecek bir çözümü sağlamaya çalışacağım". İlginçtir ki şu anda Hibernate, benim başta hiç luzumlu olacağını zannetmediğim özelliklere sahip. Hatta bu özelliklerin bazıları Hibernate'in en popüler ve sevilen özellikleri! Kullanıcılar bana gelmişler ve demişler ki, "aslında ihtiyacım olan şöyle ve şöyle bir özellik". Burada tarif etmek istediğim galiba "uzmanlar" tarafından, tepeden indirilen bir tasarım yerine, kullanıcıların yönlendirdiği, evrim gecirerek büyüyen bir tasarım şekli. Bazen diyorum ki, herşeyin merkezi kontrollü olduğu bir ekonomi işlemezse, herşeyin merkezden yönetildiği bir yazılım türü neden işlesin?

Biraz önce bahsettiğiniz bu en iyi özellikler hangileri?

Bu projeye başladığımda bakış açım bir pür Java geliştiricisininki gibiydi. Hibernate'in sunduğu hizmet düşünülürse, başta SQL bilgimin iyi olmaması, programcıların SQL ile yapmaya çalıştıklarını bilmemem komik gelebilir. Ayrıca veri ile "veri kümeleri" olarak çalışmaya da alışık değildim. Java Kalıcılık kavramı pür nesne bazlıdır, ve tekil, tek nesne etrafında döner. Bir nesne alırsınız, onunla bazı işlemler yaparsınız, sonra oradan başka bir nesneye atlarsınız ve sadece bu nesne ile işlemler yapmaya devam edersiniz. Fakat öteki taraftaki ilişkisel veri tabanları içinde apayrı bir dünya var, bu dünyada veri kümeleri ile iş yapıyoruz. Bence bu iki temsil şekli ile de iş yapabilmemiz lazım.

Ve kabul edeyim, başta bu problemleri veri kümeleriyle çalışma ile alâkalı problemler olarak görmüyordum. Fakât kullanıcılar ile konuşurken bu gündeme geldi, "biz bu şekilde çalışmak istiyoruz" dediler. Birden bire kristâlleşen bir sonuç şu oldu ki, nesne kümeleri ile çalışmamızı sağlayacak bir tasarım yapmamız lazım. Yâni, soyutluk derecesi öyle olmalı ki, nesneler üzerinden hem onların metotlari, özellikleri, kalıtımları ile uğraşabilelim, hem de kümesel planda biraraya toplama, dışsal birleşim (outer join), iç sorgular (nested queries), sıralama, vs. gibi özellikleri kullanabilelim. Ve bu kümesel işlemler Java tarafında olmayacak, veri tabanı içinde işletilen şeyler olacak.

Hibernate ile yarışan diğer ürünlere bakarsanız, işte bu sorunu, yani iki dünyayı birleştirme sorununu çözmeye uğraşmadıklarını göreceksiniz. Genelde nesne/tablo eşleme sorununu bir "köprü kurma" ya da eşleme problemi olarak duyarsınız, bence probleme böyle bakılmamalı, problem bir dünyaları birleştirme problemi olarak görülmeli ve nesne kümeleri ile çalışmayı öngeren çözümlerde odaklanmalıyız.

Nesne ağını, nesneden nesneye atlayarak gezmenin nesi var? Sorgulara niye ihtiyacımız var ki?

İlk önce, eğer arkada bir ilişkisel veri tabanı var ise, nesni ağını göstergeç takip ederek gezmek, performans olarak çok pahalı bir işlem, özellikle veri tabanı fiziksel olarak başka bir makina üzerinde yaşıyorsa. Eğer bu şekilde nesne gezen kod yazmışsanız, eninde sonunda N+1 problemi ile yüzyüze gelmek zorunda kalacaksınız. Bunu derken oldukça "genel" bir N+1 probleminden bahsediyorum, BMP ile uğraşanlar bunu iyi bilecektir, ufak ufak parçalar halinde veri aldığımız zaman ortaya çıkan N+1 problemi yani. Bunu yapmak ilişkisel veri tabanları üzerinde performansı öldürecektir.

Bir diğer karşılaştığımız problem de, nesne/tablo eşlemesinin herkes tarafından bir acele yama (hack) olarak görülmesi idi. İdealist yaklaşımlardan kaynaklanan fikirlere göre, "aslında bizim arkada kullanmak istediğimiz bir nesnesel veri tabanı (object database) idi, fakat o yok, o zaman nesne veri tabanına uygulayacağımız API'ları ilişkisel veri tabanına uygularız olur biter". Bu yaklaşım ne yazık ki işlemiyor, çünkü ilişkisel veri tabanı kökten farklı bir yapıda. İlişkisel veri tabanında veriye erişmek nesnesel veri tabanında veriye erişmekten çok daha farklı.

Bu iki yaklaşımı Hibernate nasıl birleştirebildi?

Bizim için en önemli, ve çabalarımızın odak noktasını teşkil eden özellik, Hibernate'in sorgulama dili HQL'dir. Bu dilin sözdizimi, SQL'in ufak bir uzantısıdır, çünkü insanların zaten kullanmakta olduğu birşeye benzemesini özellikle istedik. SELECT birşey FROM başkabirşey, falan, fişman. Herkes ilişkisel bir sorgunun neye benzediğini bilir, bu bizim icin önemli idi.

Utanarak söylemem gerekiyor ki, Java dünyasına programcılar çoğu zaman "ilişkisel şeylere" bakıyorlar ve biraz kirli iş olarak görüyorlar, ve bu sebeple kalıcılık katmanına programcıyı bu kirlilikten kurtaracak, izole edecek bir şeymiş gibi bakıyorlar. Fakat biraz oturup bu ilişkisel model ve ilişkisel modelleme üzerinde biraz düşünürseniz, farkedersiniz ki aslında çok zarif ve güçlü bir yapısı var. Onu kirli yapan "uyuşmazlık problemi", "eşleme problemi", işte bunlar. Onu kirli yapan JDBC ile çalışıp, JDBC'den gelen veriyi çetrefil bir nesne ağına dil eşlemeye çalışmak. Kirli olan iş, SQL yazmamak, SQL ile çalışmamak.

Bizim sorgu dilimiz SQL'i baz aldı. Bu dilin güzel olduğunu düşünüyorum. Küçük bir dil ama güzel bir dil. Nesnesel kavramları koyabildiğimiz kadar bu dilin içine koymaya çalıştık ve koymaya devam edeceğiz.

ODMG'nin OSL standartına baktınız mı? Eğer baktıysanız, sizce yanlış olan bir tarafı var mıydı?

OQL de güzel bir yaklaşım, ve bazı yönlerden HQL'in bir parçası OQL ile aynı. Fakat OQL nesnesel veri tabanı öngörüyor, o yüzden meselâ içinde metot çâğırımı yapabiliyor. Bu tip şeyler ilişkisel veri tabanlarında geçersiz olan şeyler. Bir de, ilişkisel veri tabanında null eşittir null, null sonucu verir. Nesnesel veri tabanlarında böyle olmaz.

JDOQL hakkında ne düşünüyorsunuz?

JDOQL de birşeyler yapıyor işte. Tasarlanma amacı, CICS gibi bir takım işlemsel (transactional) veri tabanlarına, düz dosyalara, XML dosyalara, bir ihtimal ilişkisel veri tabanına ve kesinlikle nesnesel veri tabanlarına erişmek için. JDOQL hiçbir veri depoloma metotunu öngörmüyor, bu yüzden de ilişkisel veri tabanı ile eşleme yapmak için gerekli olan fikirleri ekleyememişler. Dışsal birleştirme (outer join) bunun en güzel örneği, biraya toplama da aynı şekilde. Biraraya toplama, izdüşüm şeklinde kullanım olmazsa olmazlardan, bizim kullanıcılarımız bunları sürekli kullanıyorlar.

Depolanmış İşlemler (stored procedures) kavramını ne tür bir muamele getirdiniz?

Depolonmış işlemler temelde ilişkisel bir veri tabanının, ilişkisel olmayan bir görüntüsüdür. Dİ kavramı, ilişkisel tabanı çâğırım merkezli, metot merkezli bir kullanımla görür, bu sebeble, benim bu konu hakkındaki düşüncem, ki bu düşünce ateşli tartışmalar yaratabilir çünkü herkes benimle hemfikir değil, bir nesne/ilişkisel eşleme aracının, nesnelerle tablolar arasında eşleme yapması gerektiğidir, nesnelerle "başka şeyler" arasında değil.

Tabii bunu söylerken eklemem gerekir ki, bazıları Hibernate'i depolanmış işlemler ya da başka tür karışık/hetrojen yöntemler ile veriye erişildiği ortamlarda kullanıyorlar. Bu yüzden biz de, karışık yöntemlerle uygulama içine gelen verileri desteklemek için uğraşıyoruz. Bütün bu desteği de Hibernate arkasında bir yerlere saklayarak yapmaya uğraşmadık, çünkü Hibernate tek bir şeyi, ve o bir şeyi çok iyi yapmalı (çevirmen - işte Unix felsefesi!). Bu ek desteği, Hibernate'den JDBC veri tabanı bağlantısını kullanıcıya direk vererek sağlıyoruz, böylece kullanıcı bu bağlanti üzerinde istediklerini yapabiliyorlar.

İkinci olarak Hibernate içine kod çengelleri takılmasına izin veriyoruz. Hibernate'in güzel taraflarından biri birleşik model tipleri denen kavramlar, bir nesnenin özelliklerinin (property) tiplerinin modeli. İsteğe uyarlı tipler denen bir kavram sâğladık, böylece kullanıcılar kendilerine göre yeni bir tip yaratabiliyorlar. Bu yeni tip, bir nesne referansı üzerinden JDBC ile depolanmış işlem çâğıran bir başka nesne olabilir, LDAP'e bağlanan bir nesne olabilir, vs.vs.. Tablolar haricindeki antiteleri bu şekilde desteklemeye uğraşıyoruz.

Siz bariz belli olduğu üzere, saydam kalıcılık (transparent persistence) hakkında çok heyecanlı ve tutkulusunuz, fakat bazı büyük paket program satan şirketlere göre bu müşterilerinin istediği bir şey değil. Bu şirketler saydam kalıcılığı önemli bir şey gibi görmüyorlar, Sun'ın içindeki bazı guruplar da böyle düşünüyor. Sizce saydam kalıtım niye önemli?

İlk önce yorumunuzun ilk kısmını cevaplayayım, müşterilerin ne istediği hakkında olan bölümü. Benim bu konu hakkındaki görüşüm şu: Müşteriyi kim olarak tanımlıyorlar? Müşteri dedikleri, bu şirketlerin sattığı teknolojiler ile günbegün uğraşmak zorunda olan programcılar mı? Yoksa müşteri diye tanımladıkları satış zamanında karşılaştıkları alım görevlileri, kodla uğraşmayan kimseler mi? Bunun cevabını bilmiyorum, soru olarak bırakıyorum. Bana gözüken o ki, Hibernate'e olan ilginin boyutuna bakılırsa programcılar saydam kalıcılık ile çok, çok ilgililer.

İkinci olarak, saydam kalıcılık önemli çünkü bu sâyede iş mantığına daha fazla zaman harcıyabiliyorsunuz. Bu çok önemli. Saydam kalıcık, bizim gibi altyapı programcılarını, size, yani kullanıcıya ve programcıya fazla kod yazdırMAmak için uğraşması yönünde zorluyor. Bir POJO (Plain Old Java Object/Basit Java Nesnesi) kod satır sayısı bakımından yazabileceğiniz en basit koddur, ve saydam kalıcılık ile, bu kelimeyi telâfuz etmek Hibernate'in programcıları olarak bizi "bir POJO'dan daha fazla" kod yazmaya mecbur kalMAmanız için uğraşmaya mecbur eder. Saydam Kalıtım bu seviyede önemli. Ek olarak, taşınabilir kod seviyesinde de önemli. EJB 1.1'de yazılmış kod EJB 2.0'a taşınamaz, çünkü altyapı parmaklarını ve burnunu iş modeli kodlarının içine sokuyor. Bence iş modeli (business model) Hibernate'den, JDO'ya, ya da JDO'dan Toplink'e taşınabilir olabilmeli. Çok uç bir görüş sunuyor olabilirim, ama bana öyle geliyor ki POJO'lardan bahsettiğimiz an, benim anladığım bütün bir iş modelinin bir altyapıdan bir başkasına taşınabilmesi özgürlüğünün olmasıdır. Ayrıca, bu sistem kolay test edilebilen, kolay birim testlere tâbi tutulabilen bir sistem de olmalıdır. Bu sistem bir toptan (batch) işlemde de kullanılabilmelidir, eşzamansız bir dinleyicinin içinde de kullanılabilmelidir.

Ve bütün bunlar çok önemli. Hernedense EJB'nin "avantajlarından" biri olarak tekrarkullanılabilirlik (reusability) sayılır. Fakat aslında EJB'ler en az tekrarkullanılır kodlara sebebiyet veriyorlar. POJO'lar tekrarkullanılabilir şeylerdir. Kalıtım ile başka bir nesneyi uzatan (Java extend), gerçekleştirme yapan (Java implement) nesneler, tekrarkullanılabilir özelliklerini kaybetmeye başlarlar.

Saydam kalıtıma çok ilgi gösterilmemesinin sebebi şu olabilir mi: Birçok insan alan modeli (domain model) yazmıyorlar. Çoğunluk iyi bir yöntem olan böyle bir yöntemi niye kullanmıyor acaba?

İlkin belirteyim, her uygulamanın bir alan modeline ihtiyacı yoktur. Öyle uygulamalar var ki, alan modeli bu uygulamalar için fuzulidir. Meselâ öyle uygulamalar var ki "veri tabanından gelen veri kümeleri" görüşü onlar için cuk oturur. Zâten Java standart alet kutusu içinde, ya da açık yazılım çevresi içinde bu tür uygulamaları yazmaya yardım edecek araçlar mevcut. Spring altyapısı var, dağınık, karmaşık JDBC kodlarından kurtulmanızı sağlıyor, başka araçlar var, sâdece ekrana listeler dolusu veri basan, ve arada sırada tek tabloya tek satır ekleyen uygulamalar için size yardım ediyorlar. Böyle uygulamalar için alan modeline ihtiyacınız yok.

Öte yandan, diğer bir sınıfa giren uygulamalar var ki aşırı miktarda işlem mantığı işletmenizi gerektiriyor. Ama hemen ekleyeyim, bu her uygulama değildir. Ne yazık ki revaçta olan çoğu Java kitabı, insanlara, "işlem mantığını görsel mantığın olduğu kodlardan kesinlikle çıkarmaları" gerektiği görüşünü dayatıyor. Fakat yeteri kadar iş mantığınız yoksa, o seviyede bir ayırıma, o tür bir soyutlamaya ihtiyacınız olmayacaktır.

Fakat bunu muhakkak yapması gereken uygulamalar var. İşte bu tür uygulamalar için, düzgün işleyen bir saydam kalıcılık yönteminin olmaması insanları alan modeli kurmaktan, POJO temelli sınıflar yazmaktan küstürdü. Java bazlı bir alan modeli hakkındaki ilginç bir gözlem de şudur; Bu modellerin %98'i ilişkisel bir veri tabanına yazılacaktır. İnsanların bunu hem temiz hem de verimli bir şekilde yapacak araçlarının olmaması, bu stilde yazılım geliştirmenin önünü tıkamıştır diye düşünüyorum.

Bir kalıcılık altyapısını yazarken karşınıza çıkan en büyük zorluklar nelerdi?

Teknik bağlamda aşmamız gereken problemler aslında işin kolay tarafıydı. En büyük problemler sosyal, ve iletişimsel problemlerdi. Algoritma olarak, orta seviye zorlukta, diğer açık yazılımlardan alıp kullanamadığımız, onlarda da benzerini görmediğimiz bazı algoritmalarımız var. Yani, orta karar çetrefilli algoritmalar diyelim.

Hibernate'in iç yapısının nasıl işlediğini insanlara anlatmak (ve bunu derken iç yapıdan bahsediyorum, anlambilimsel (semantics) dış yapıdan, kullanıcıya bakan arayüzlerin nasıl kullanılacağınan bahsetmiyorum) en, en çetin işlerden biriydi. Bir kişi ile aynı odada olmadığın zaman, kelimeler, diagramlar ile iletişim kuramıyorsunuz, ve bütün iletişim e-posta'lar gibi metin bazlı araçlara indirgeniyor. Ben Hibernate'i hep daha fazla kişinin duymuş olmasını, bilmesini istedim, neyse ki şimdi yeteri kadar insan var, fakat ilk başta o kodu hakikaten anlayan insan sayısında bir azlık vardi. Tabii ki Javadoc, kod içine konan kod yorumları yardımcı oluyor, fakat bu tür teknik iletişim için en ideali, öteki insanın yanına oturmak ve anlatmak, "bak, işte şu, şu, şöyle işliyor!".

Hibernate, JDO teknolojisine de karşı bir duruş olarak gösteriliyor. Niye?

Ben bunu JDO'ya değil, JDO mentalitesine bir karşı duruş olarak betimlemek istiyorum. Bizim şu an söylediğimiz, şimdilik JDO tarifnâmesini gerçekleştirmeyeceğimizdir, çünkü JDO'nun bazı eksiklikleri var, ve bu eksikler yüzünden kullanıcılar yerel arayüzleri kullanmak zorunda kalacaklar. Kullanıcılar şu konuştuğumuz anda, Hibernate ile JDO ile yapamadıkları şeyleri yapabiliyorlar. Eğer ki eğer JDO 2.0 eksiklerini kapatır ise, o zaman Hibernate bu teknolojiyi destekleyebilir. Fakat şu anda JDO 2.0 oldukça havada, ne olacağı, ne yapacağı belli değil. (Çevirmen - bu mülakattan sonra JDO 2.0 piyasaya çıktı, ve Gaven King, ünlü başka bir beyanında bu yeni standartın da halâ temel problemleri barındırdığını söyledi). JDO'yu gerçekleştirmememizin diğer bir sebebi de, artık bizim için çok büyük bir engel teşgil etmese de, JDO'nun sadece kullanıcı arayüzlerinde değil, gerçekleştirme seviyesinde de bazı zorunluluklar getirmesi.. TheServerSide'da bir süre önce birçok tartışma olmuştu, JDO'nun öngördüğü gibi baytkodu işlemden geçirmek gerekli mi, iyi mi, kötü mü, kalıtım kullanarak başka şeyler yapılabilir mi.. Bu konular hakkında birçok karışıklık var.

Benim görüşüm şöyle ki, eğer saydam kalıcılık yapıyorsanız, baytkod işlemeye ihtiyacınız var. Baytkod işlemenin külfetli bir şey olduğunu imâ etmek istemiyorum, ama JDO'nun bunu zorunlu yapmasına gerek olmadığını imâ etmek istiyorum. Yâni, belki de JDO tarifnâmesine iki aşamalı, iki türlü bir uyum kriteri olabilir. Biri, işlerkod seviyesinde bir uyum kriteri olur, ve derlenmis POJO'lar bir üründen ötekine taşınabilir, bir de ikinci seviyede bir uyum kriteri olur, buna göre kaynak kod taşınabilir hâle gelir. Bu işlerkod taşınabilme probleminin nereden geldiğini ben de bilmiyorum, kimin çözmeye uğraştığından da haberim yok.

Bana göre, kullanıcılar kaynak kod seviyesinde bir taşınabilirlikten mutlu olurlar, ve bu yeterli olur. JDO bazı gerçekleştirim üzerinde koyduğu zorunlulukları gevşetirse de iyi olacak, mesela Java Reflection yöntemi kalıtım kodu yazmak için hârika bir yöntem, bu teknolojiyi çok seviyorum. JDO'nun bu yaklaşımı da içinde barındıramaması için hiçbir sebep yok. Bence tarifnameleri değiştirerek, iki yaklaşımı da barındırabiliriz. Tepkilerim genelde bunlar, fakat başa dönmek gerekirse JDO ile en temel sorunum, kullanıcılarımızın bizden JDO'nun yapamacağı şeyler istemesi.

JDO'ya neler eklenirse sizin desteğinizi alır?

Anlatayım. bir numara sorun şu: Klasik nesne/tablo eşleme dünyasında veri tabanından birşey yüklemenin, veri almanın iki yolu vardır. Kriter usulü sorgulama, ve sorgulama dili kullanarak sorgulama. Bu iki model de sağlam modellerdir, ve bazı özel şartlar için mükemmel modellerdir. Fakat öyle olmuş ki, sanki JDO'cu arkadaşlar bu modelden hangisini seçeceklerine karar verememişler, ve hafiften bir kriter bazlı sorgulama dilini, öteki Java sözdizim bazlı başka bir tanım diline evlendirmişler, filan, ve bütün bunların nereye gittiği belli değil. Bu kırma sonuç ta daha önce bahsettiğimiz sorunlar için uygun şekilde uzatılamıyor, bu sorunlar biraraya getirme, izdüşüm yapma, dışsal birleştirme yapma gibi şeyler. O yönde harekete yer bırakılmamış. JDO'nun bir numaralı problemi işte bu, sorgulama dili zarif değil, ve nasıl uzatılacağı ve yeni özellikler ekleneceği bariz değil, ve buna yer yok.

Sizin ve Hibernate için sırada ne var?

Şu anda Hibernate 2.0'ı sürdük, sürüm oldukça sorunsuz geçti. Çoğu Hibernate kullanıcısı da 1.2.x'ten 2.0'a geçti. Birkaç tane pürüz çıktı, ama genelde işler iyi gitti diyebilirim. Bu sürüm uzun bir çalışmanın ve fikirlerin sonucuydu. Sürüm bitti, biz de şimdi yeni fikirlerle oynuyoruz, yapacak işleri tartıyoruz, belki biraz ara verip dinlenebiliriz.

Hemen önümüzde yapılması gereken en büyük iş "dağıtık önbellek" işi, ve bu dağıtık önbellek ile çalışabilen bir işlem (transaction) yapısı. Orada olan birkaç şey var. Şu JCache JSR'ını çıkarabilseler (Sun), çok iyi olurdu, ama ondan önce de bizim yapabileceğimiz işler var.

Baytkod üzerinde değişim yapmanın neresi kötü?

Baytkod üzerinde değişim yapmanın o kadar kötü bir tarafı yok. Baytkod değiştirmek iyi, eğer 'ihtiyacınız varsa'. Özellikle AOP altyapısında bazı durumlar var ki alan seviyesinde çağrı yakalama (interception) yapıyorlar, filan, eğer bunu yapıyorsanız baytkod değişimi lazım, kullanılması gerekir. Her derleme (build) sürecinin, işleminin bir parçası olarak her defasında işletilen bir baytkod değiştirme bence problemli. Bütün geliştirme araçlarınızda bunun desteklenmesi gerekiyor, yoksa derleme sürecinize bir fazla seviye daha katıyor. Bunlar aşılmayacak problemler değil tabii. Benim JDO tarifinde söylenen baytkod değiştirme işlemiyle problemim, zorunlu hale getirilmesi. Baytkod değiştirmek JDO'ya zarar vermiştir demiyorum, ama tarifnamede bulunması için güçlü bir sebep olmadığını söylemek istiyorum.

Hibernate'in bu konuya yaklaşımı nasıl?

Parçası olduğum ve şu anda da sürmekte teknik tartışmalardan biri, AOP altyapılarını nasıl kuracağız sorusu üzerine idi; Burada Rod Johnson'un yaptıkları var. Rod bazı fikirlerini kodlamak için bir hiyerarşi kurmaya başlıyor, dinamik yer tutucu (proxy) yazıyor, ve gidip gidip sonuç olarak ortaya AspectJ çıkıyor. Bu kodu geliştirme evresindeyken önüne çıkan seçeneklerden biri, baytkod değiştirme tekniği imiş, ilginçtir ki şimdiki AOP altayapısı koşma zamanında bu işi Uygulama Sunucusunun ClassLoader'ına eklemlenerek "aradan sıkıştırıp" yapmaya uğraşıyor. Fakat buradaki sorunlardan biri bunu taşınabilir hâlde yapabilmek, çünkü Uygulama Servislerinin ClassLoader'ları farklı çalışıyor, ve nasıl çalıştıkları hakkında kontrolümüz yok. Bu çözüm için cevabını ne olduğunu bilmiyorum çünkü probleme yakınen bakmadım, fakat birkaç kişiden farklı fikirlerin etrafta gezindiğini biliyorum.

Fakat bu sorunun başka bir açıdan çözümü var, ki Hibernate'in yer tutucu (proxy) nesneleri bu çözümü kullanıyor, bu çözümün ismi CGLib... CGLib birkaç ilginç şey yapıyor. CGLib baytkod üretimi için kullanabileceğiniz yararlı kodların bir toplamı. Bu konudaki bazı genel ihtiyaçlara çözüm sağlamışlar. CGLib, yeni bir .class yüklemek için baytkod üretmenizi sağlıyor. Bunu yapmak, baykodları yüklenirken değiştirmeye çalışmaktan biraz daha hafif ve ucuz bir çözüm. CGLib yeni bir .class'ı yükleyebiliyor. Hibernate'in baytkod kullanımı işte böyle.

İşte bu yer tutucu nesneleri yaratıyoruz, ve bu nesneler JDK'nin dinamik yer tutucu nesnelerinden daha güçlü. Burada, CGLib'in yaptığı şeyin, JDK'nin dinamik yer tutucu çözümüne bir alternatif olduğunu düşünebilirsiniz, üstüne üstlük CGLib JDK 1.2 üzerinde de çalışıyor. En önemlisi, CGLib ile bir başka nesneden dinamik olarak kalıtım yapabilmeniz, ya da interface'lerini dinamik olarak gerçekleştirebilmeniz. JDK'nin dinamik yer tutucusu bunları yapmanıza izin vermez. CGLib sayesinde her şeyin yer tutucusunu kurabilirsiniz. Java kütüphanelerinde çoğu zaman, JMX ve EJB'de her zaman şu kalıp takip edilir: Bazı interface'lerin gerçekleştirimi tarifname tarafında zorunlu tutulur ki, bu interface üzerinden yakalama, yön değiştirme ve yer tutucu nesneler kullanarak kod işleten kapın (container), müşteri ve servis arasına "hissettirmeden" girmesi mümkün olsun. Bütün bunlara Hibernate'te hiç ihtiyaç yok, çünkü herhangi bir nesnenin metot çâğrımları üzerinde istediğimiz gibi yakalama yapabiliyoruz, bütün bunlar sâğlanmış. CGLib'in tarihçesini merak edenler için ekleyeyim, bu kütüphane BCel ve ASM üzerinde yazılmış.