Thursday, October 31, 2002

Yazılım Çeşitleri

Yazilim cesitleri ve metodlari tek degildir. Bir metodu ogrenerek butun problemleri cozeceginizi sanmayin. Kariyerimiz boyunca "Rational Metodu", "Extreme Metodu" ogrenip Istanbul'u fethedecigini zanneden cok programci tanidik. Bu metodlar, her turlu yazilim problemine deva olacaklarini reklam ederler, fakat degisik yazilim problemlerinin ve cozumlerinin ne oldugunu bilmezseniz, hangi metodu ogrenirseniz ogrenin, basariya ulasamazsiniz.

Ana software "problem alanlarini" sayalim..


* Internet "site" programlari.
* "Anlik" calismasi gereken programlar.
* Gunluk, "toplu" halde calisabilen programlar.
* Gorsel Programlar

Butun bu problemlerin kendine gore "teknolojik" cozumleri vardir. Mesela, veri tabani paket programiniz Oracle; yani SQL dili kullanabileceginiz bir paket. Musteriniz dedi ki: "Bana oyle bir progrem yazki, her gun ABC kayitlarini isleyip XYZ kayidi haline getirsin. Ne kadar cabuk yapabilirse o kadar iyi. Sadece islesin. Gorsel falan hic bir sey istemem."

Yukaridaki program 'gunluk' program kategorisine girer. Boyle programlar surekli 'uyanik' durmak zorundadir, ve isleyecek veri beklerler. Sanki ac bir hayvan gibidirler, veri buldugu anda yerler. Yoksa gelmesini beklerler. Gorsel program orasina burasina klik edilsin diye bekler, o yuzden daha degisik programlama gerektirir.

Anlik programlarin degisik ihtiyaclari vardir. Mesela bir uzay mekigini kontrol eden, ya da son model arabanizda benzin pompasini ayarlayan program, anlik programdir. 1~2 milisaniye arasinda karar vermesi gerekir, o yuzden kod ona gere yazilir. Bilgisayarlar tabii ki herseyi yapabilecekleri kadar hizli yapmaya ugrasirlar, fakat birden fazla, ayni anda islem gerektiren olaylar oluyorsa, belki bazi seylerin birbirini beklemesi gerekebilir. Mesela benzin pompasi dogru olcude benzin vermekle gorevlidir, ama ayni anda fren sinyallerini dinleyen bir bolumude vardir. Fren sinyali geldigi anda herseyi birakmasi mecburdur. Bunlar "anlik" program problemleridir. Gunluk programlarin problemleri yukarida gordugunuz gibi degisik.

Site programlari bir baska hikaye: Internet siteleri ayni anda birden fazla kisiye hizmet versin diye yazilir. Yani, ayni anda degisik kullanicilara hizmet verir, ama bu isler aslinda birbirinin kopyasidir, ve kullanicilar birbirlerini "aninda" etkileyemezler. "Anlik" program kategorisine bu yuzden benzemesine ragmen, aslinda cok ayri bir metod gerektirirler. Mesela amazon.com sitesine girdiniz, uye oldunuz, kitap satin aldiniz. Fakat ayni anda, amazon.com sitesinde ayni islemleri yapan belki binlerce kullanici vardir. O kullanicilarin yaptiklari sizi etkilemez, herkes sanki kendi odasinda, izole bir sekilde isini yapmaya ugrasir. Bu tip programlar "kapasite" icin yazilirlar, problemler veri tabanina daha hizli erisim, sayfa hizli yukleme gibi seyler etrafinda doner. Son zamanin Internet Java paketleri, sanki siteleri bir kisi icin yaziyormus gibi yardim eder size; ondan sonra kopya kagidindan cikarmis gibi 10,000 kisi icin ayni kodu kullanabilirsiniz.

Gorsel programlar Windows programlari gibidir. Unlu windows 'fal' oyunu bir gorsel programdir. Klik edilebilen nesneler vardir, bu nesnelerin bazilari her zaman kliklenemez, kullanici hatasi verilir bu zamanlarda, yada kullanici o isi yapamaz. Bu tip programlarin temelinde bir 'hadise/vaka dongusu' vardir. Bir gorsel hadise oldugu anda, (nesne uzerine klik) hadise icin yapilan gorevler teker teker, onceden programa kayitlanir. Bu stili ilginc yapan, programi tamamen 'gorsel hadiseler' uzerine kurulmasidir. Oteki tip programlarda sanki duz bir sira yoktur. 'Su olursa sunu yap, bu olursa bunu yap' seklinde programlardir.

Görsel Uygulamalar (Swing) Nasıl Test Edilir?

Java bazlı, görsel olmayan kodlarımız için, JUnit ile test yazabiliyoruz. Bu tip kodlar için, aşağıdaki gibi bir ifade yeterli oluyordu...

..
IslemNesnesi i = new IslemNesnesi();
assertEquals(2, i.topla(1, 1));
...


Fakat diyelim ki, elimizde Swing bazlı görsel bir uygulama var. Extreme programcılık dahilinde, müşteri rolünde olan kişinin yeni kodlanan sistem özelliğini kabul edebilmesi (acceptance) için, kabul testleri denilen görsel testleri işletmesi gerekir. Kabul testleri, ya kağıt üzerinde yazılı "önce A'ya bas, sonra B'ye, çıkan metinin X olup olmadığını kontrol et" şeklinde direktifler olur, ya da daha iyisi, bilgisayar tarafından arka arkaya çok hızlı bir şekilde işletilebilen XML bazlı dosyalar olur.

Otomatik olmayan testler için bir altyapıya gerek yok. Otomatik olanlar için, Swing Tıklayıcı adlı geliştirdiğimiz altyapı yardımcı olabilir.

Swing Tıklayıcı

Swing Tıklayıcı programını indirip kurduktan sonra, kullanmaya başlamadan önce birkaç kavramını anlamamız yerinde olur.

Swing Tıklayıcı mimarisi üç bölümden oluşuyor.


* XML testleri (swing-tikla/test/acceptance/tests altındaki dosyalar)
* Görsel birim etiketleri (swing-tikla/test/acceptance/tags)
* Görsel, Java arasında tutkal kodlar (swing-tikla/test/gui)

XML Testleri

Kabul testleri için düğmeye basmak, görsel listeden seçim yapmak gibi işlevleri yapmamızı sağlayan bir "dil" olması lazım. Bu dil söyle olabilir.

<AcceptanceTest>
<startApplication/>
<lookAtWindow name="Stylepad"/>
<enter name="Fatura" value="1000" />
</AcceptanceTest>


Bu teste göre Swing uygulamamızı başlatıyoruz, sonra ekrandaki pencerelerin arasından, başlığı "Stylepad" olan uygulamayı buluyoruz (seçiyoruz). "Fatura" adlı metin kutusuna (TextBox) içine 1000 değerini yerleştiriyoruz.

Etiketlerin Gerçekleştirimi

lookAtWindows (pencereyeBak) olarak gözüken etiketin Java altyapısını tags dizini altında bulabilirsiniz. Kendi etiketlerinizi de bu dizin altına bırakın. Swing Tıkla etiket mimarisinin ilginç bir özelliği, Java Değişken Çâğırım (Introspection) özelliğini kullanarak, etiketlerin içerdiği değerleri tekâbül eden Java nesneleri üzerine direk aktarma yapabilmesidir.

Tutkal Kodlar

Bu dizin altında her Swing nesnesi üzerinde işlem yapabilen tutkal kodlar var. Eğer uygulamanıza özel yeni bir görsel Swing nesnesi mevcut ise, o zaman bu yeni birimi test altyapısına "tutkallamanız" gerekir. GuiAdapter.java dosyası altında bunu gerçekleştirebilirsiniz. Bizim projemiz dahilinde JCTable, vs gibi standart Swing'e dahil olmayan birçok nesne mevcut idi. Bu kodları ayreten tutkallamamamız gerekti.

Kullanılan Örnek

Swing Tıklayıcı ile beraber, bir demo sâglamak açısından Stylepad adlı JDK sürümüne zaten dahil olan bir programı kullandık. Fakat bu programı aslında sıkı bir şekilde testten geçirmiyoruz. Tam teferruatlı testler ileri yazılarda gösterilecek. Şimdilik test altyapısına acil ihtiyacı olanlar için burada sunmayı uygun gördük.

Diğer Mevcut Test Ürünleri

Serbest yazılımlar arasında Maraton programı oldukça kullanışlı. Bu programa da alternatif olarak bakmanızı tavsiye ederim. Maraton, testler için dil olarak bizim XML'imiz yerine, Phyton adlı bir dilde test betikleri üretiyor. Yaklaşımın oldukça benzediğini belirtmeliyim. Bizim projemiz Maraton'a eklenti yapmak bakımından biraz karışık buldu, fakat demo'u için fazla zamanımız yoktu. Bu yüzden Maraton'un içyapısını öğrenip şirket içinde standart haline getirmeye ortam var ise, kullanılabilir olacağını zannediyoruz.

Not: Swing tıklayıcı, yakın zamanda tamamen Türkçeleştirilecektir.

Kaynaklar

arayüzlerini kullanıyor.

* Swing Tıklayıcı
* Maraton
* Görsel tıklayıcı kodlarımız, perde arkasında Jemmy

Uygulama Servisi Başlatmak ve Beklemek

Farzedelim ki bazı testlerimizin (entegre testleri) işlemesi için, Weblogic, JBoss ya da Tomcat'in çalışıyor olması gerekiyor. Entegre testleri, birim testlerinin aksine direk komut satırından ya da müşteri tarafında (client side) çalıştırılamaz, meselâ, yazdığımız bir EJB modülünü test etmek için, EJB'nin kesinlikle çalışıyor olması, yâni Weblogic üzerine konmuş ve Weblogic'in çalışıyor durumda olması gerekecektir.

Biz de bunun üstüne entegre testlerini otomize olarak çalıştırmak istersek, ki Extreme Programcılık dahilinde bunu yapmamız gerekecektir, o zaman bir problemle karşılaşırız. Diyelim ki Weblogic'i startup.bat gibi bir betik ile ateşledik. Arkasından hemen entegre testlerini işleteceğiz. Fakat, Weblogic'in başlamış olduğunu nasıl anlayacağız ki hemen arkasından entegre testlerine devam edebilelim? Weblogic bâzen 30 saniye, bâzen 1 dakikada ayağa kalkıyor olabilir. Zamanlama ile bu işi çözemeyiz.

Demek ki, bir yere bakarak Weblogic'in durumunu öğrenmemiz gerekiyor. Bunu her uygulama servisinin dışarı afişe ettiği port üzerinden öğrenebiliriz. Fakat daha da kolayı, her uygulama servisinin muhakkak yazdığı bir log dosyasında belli aralarla Perl ile tarama yaparak bir anahtar kelimenin gelmesini beklemektir. Bu, Weblogic için "listenin on port 7001" dir, Tomcat için başka bir şey olabilir.

Alttaki Perl programı ve Ant komutları, bu amaç için kullanılabilir. İlk önce, bir uygulama servisi log dosyasını okuyan ve belli bir kelime bekleyen programı gösterelim.

while (! /$ARGV[1]/) {
open IN, $ARGV[0];
undef $/;
$_ = <IN>;
print "\nServisin ba�lamasını bekliyoruz ... $ARGV[0] taranıyor\n";
sleep (2);
close(IN);
}


Bu program, Perl programına $ARGV[0] (ilk parametre) ile gönderilen log dosya ismini okuyarak, $ARGV[1] kelimesininde belirtilen kelimeyi tarayarak, beklemektedir. Kelime bulunmazsa, 2 saniye uyuyarak tarama tekrar yapılır. Bu betik, genelde build.xml içinden çalıştırılacaktır, çünkü entegre testlerini Ant içinden işletiriz. Ant içinde bu çağırımın nasıl yapıldığını görelim. Dikkat, bu çağırım sadece beklemek için; Servisi başlatmak için değil.

 <target name="servis-bekle">
<exec executable="perl">
<arg line="./servisBasladimi.pl"/>
<arg line="${bea.dizin}/gmlcdomain.log"/>
<arg line="${sunucu.hazir.kelimesi}"/>
</exec>
</target>


Ant içinde kullandığımız değişkenleri, build.properties içinde tutuyoruz.

bea.dizin=D:/bea/user_projects/domains/gmlcdomain
bea.dizin.win=D\:\\bea\\user_projects\\domains\\gmlcdomain
cygwin=d:/cygwin
sunucu.hazir.kelimesi="listening on port 7001"

Ant içine aşağıdaki ibareyi ekleyerek, bu değişkenleri okuyabiliriz

    


Komut satırından servis-bekleyi çağırdığımız zaman, ve Weblogic başlar başlamaz bu komut geri dönecektir. Geri dönmesi de bizim için yeterli, çünkü "ant filan falan servis-bekle entegre-testleri" komutu verince, servis-bekle geri dönünce, entegre-testlerine geçilebilecektir.

Şimdi, servisi başlatmayı da otomize hâle getirelim. Fakat ondan da önce, o anda çalışıyor olan servisi öldürmemiz gerekiyor.

Bu, Unix programcıları için gereksiz bir paragraf olabilir. Sonuçta pkill ile isi vererek Linux ve Solaris üzerinde istediğiniz süreci öldürebiliyorsunuz. Windows için bazı ekler yapmak gerekecek.

Cygwin ve ps

Windows üzerinde Unix komutlarını kullanabilmek için Cygwin programını kullanıyoruz. Cygwin içinde ps mevcut,. Seçeneksiz olarak kullanılan ps komutu, sadece Cygwin tabanlı süreçleri göstermektedir. Windows süreçlerini de görmek istiyorsak, ps -W komutunu kullanmamız gerekiyor. O zaman şöyle bir betik yazabiliriz.

01:   $_ = `ps -W | grep bea`;
02: /^\s*(\d*)\s*/;
03: exit if ($1 eq "");
04:
05: `$ARGV[0]/bin/kill --force -9 $1`;

Tamam. Bu kodda neler oluyor? İlk satırda (#1) grep ile "bea" kelimesini taradığımızı görüyoruz. Bu kelime yerine istediğiniz anahtar kelimeyi kullanabilirsiniz. ps -W ile tüm listeye bakın, öldürmek istediğiniz sürecin satırında kendine has bir kelime var mı? O kelimeyi kullanın.

ps -W çıktısı şöyle gözükecek:

1064       0       0       1064    ?    0 19:04:43 C:\emacs-21.3\bin\emacs.exe
1448 0 0 1448 ? 0 19:31:43 C:\Program Files\Mozilla
1596 0 0 1596 ? 0 19:04:24 C:\WINDOWS\Explorer.EXE

Şimdi, ps komutu çıktısından PID (process no'su) çıkartılması/alınması gerekiyor. Bunu yapmamız lâzım, çünkü, kill komutuna verecek PID numarasını bir şekilde bulmamız gerekiyor. Yâni yukarıdaki örnekte 1596 sayısı... Bu işlemi basit bir düzenli ifade ile (#2) hemen yapabiliyoruz. Bundan sonra tek yapmamız gereken kill komutu ile bu PID'i öldürmektir. Ama dikkat! Direk Unix kill, Windows süreçleri üzerinde çalışmıyor, --force seçeneğini de geçmemiz gerekecek.

(#5)'de $ARGV[0] kullanımına dikkat; Bu ARGV Cygwin programının kurulduğu dizini gösteriyor. Ps ve kill komutlarının PATH'te olmama şansına karşı bunu yapmak daha uygun oldu.

Bu betiğin Ant'ten nasıl çağırıldığına gelelim.

        ...
<target name="weblogic-durdur">
<exec executable="perl">
<arg line="./servisOldur.pl"/>
<arg line="${cygwin}"/>
</exec>
<exec executable="${cygwin}/bin/rm">
<arg line="${bea.dizin.win}/gmlcdomain.log"/>
</exec>
</target>



Artık servis başlatmaya hazırız! Bunun için birkaç takla daha atmamız lazım: Ant'in başlatma işlemine "kitlenmemesi" yâni ona takılıp kalmaması için, exec etiketinde spawn=yes seçeneğini kullanmamız gerekiyor. Bekleme işini exec'de değil, Perl betiği ile dışarıdan yapıyoruz, unutmayalım. Spawn seçeneği exec'de verilen komutu sallar, ve sonucunu beklemeden geri döner. Bizim istediğimiz de bu zaten, çünkü hemen arkasından servis-bekle komutunu işletecegiz.

 <target name="weblogic-baslat" depends="weblogic-durdur">
<exec executable="./run.bat" spawn="yes">
<arg line="${bea.dizin.win}"/>
<arg line="${bea.dizin.win}/startWebLogic.cmd"/>
</exec>
</target>


Run.bat, exec için bir sıçrama tahtasından ibarettir. Tek amacı dizin değiştirmek aslında, yoksa direk startWebLogic komutunu da işletebilirdik. Run.bat aşağıda gösteriliyor.

cd %1
start %2

Güzel. Artık tek kalan, herşeyi işletmek.

$ ant weblogic-baslat servis-bekle entegre-testleri-islet

Wednesday, October 30, 2002

İnternet Yazılımları için Örnek Mimari

İnternet bazlı program yazmaya karar verdiniz. Müşteriniz kapıda, ya da patronunuz soruyor "Hangi teknolojileri kullanacaksın bu iş için?"

Teknolojiden sonra "hangi mimariyi kullanalım" sorusu kapımıza gelecek. Yemek yapmak ile kıyaslamak gerekirse, teknoloji yumurta, domates gibi ana maddelerdir, mimari ise "yemek tarifidir". Hangi tarif daha iyidir? JSP içine JDBC'mi koyalim, yoksa JDBC kodunu Java nesneleri icine mi koyalım? Sonra JSP->nesne->JDBC->Veri tabanı gibi olsun.. Ne kadar çok soru!

Bu soruları her proje başında, teknik liderler kendilerine sorarlar. Yanlız değilsiniz, merak etmeyin. Soruları sıralayalım:


* Hangi teknoloji?
* Genel Mimari nasil olsun?
* Geliştirme ortamını nasıl kuralım, programcıların gündelik geliştirme işlemi nasıl kurulsun
* Sonuç ortamı hangi işletim sistemi üzerinde çalışsın?
* Sonuç ortamını biz mi yönetelim, yoksa Site Barındırma şirketine mi verelim

Bu yazımızda bu sorulara cevap vermeye calisacağız. Alt kattan baslayarak, yukarıya dogru çıkalım:

Ara Kat (Alt)

Alt arakat dahilinde veri tabanına bağlanmamız lâzım. Bu kat içinde, normal Java nesneleri ile JDO ya da Hibernate kütüphaneleri kullanılarak veriye bağlanılabilir. Daha önceki bir yazımızda JDO metodunu işledik. JDO nesneleri, aynen bildiğiniz Java nesnelerine benziyor, çok basitler. Sadece veri deposu görevini gören bu nesneler 'akıllı' olmayabilirler. Üzerlerindeki işlemler sadece get/set işlemleri olacak. (Not: get/set Turkceye çevirmek isterdik, fakat Java tarifnamesi buna izin vermiyor. Bazı durumlarda get/set ile başlayan kelimeler kullanmak zorunlu).

İşte JDO ve Hibernate için hazır bir nesne modeli..
public class Musteri
{
protected String no;
protected String isim;
protected Portfoy portfoy;
public String getNo() { return no; }
public setNo(String no) {this.no = no; }
// oteki get/set islemleri buraya...
}

public class Portfoy
{
public List gecmisIslemler;
// get/set islemleri buraya...
}

public class Islem
{
protected Senet satilanSenet;
protected Senet alinanSenet;
// get/set islemleri buraya...
}

public class Senet
{
protected String sirketIsmi;
protected long kacLotAlindi;
//get/set islemleri buraya...
}
Nesneler tanımlandıktan sonra, veri tabanı tablolarına bağlantıyı kuralım. Bunu, bir XML ayartanım dosyası kullanarak yapacağız. (Sadece müşteri icin tanımladık, tüm tanımlama değil)

JDO için;

<?xml version="1.0"?>
<!DOCTYPE jdo SYSTEM "jdo.dtd">
<jdo>
<package name="sk">
<class name="Musteri">
<field name="no"/>
<field name="isim"/>
</class>
</package>
</jdo>


Hibernate için;

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
<hibernate-mapping package="sk">
<class name="Account" table="Tablo">
<id name="bizimId" column="bizimId" type="int">
<generator class="increment"/>
</id>
<property name="no" column="no" />
<property name="isim" column="isim" />
</class>
</hibernate-mapping>


Bundan sonra JDO ya da arayüzlerini çağırarak, nesneleri istediğiniz veri tabanına yazabilirsiniz. JDO için makePersistent, Hibernate için save işlemleri, tek başına bütün nesneyi alıp veri tabanına yazacak güçtedir.

Ara Kat (Üst)

Ara kat dahiline, JDO nesnelerini kullanan tabaka da girer. Bu tabakayı proje büyüklüğüne göre es geçebilirsiniz, o zaman JSP/Servlet/Struts Action'lar direk Java/JDO ile bağlantı kurar. Yok eğer büyük bir proje ise, bir arayüz daha çekmenin mahsuru yok.

Arakat dahilinde kullanılması uygun teknoloji EJB Session Bean olacak. Entity Bean kullanmaya gerek yok, Entity Bean ve JDO birbirinin rakibi teknolojilerdir, ve JDO'nun daha rahat olduğunu sanırım ispatladık. EJB Entity Bean katiyen kullanmayın. Session Bean metodu, sayfalar ile veri tabanı arasında bir arayüz oluşturma bakımından önemlidir. Dış dünyaya göstereceğiniz arayüz budur yani.. Dış dünya derken, JSP yerine Swing bile kullanabilirsiniz.

Tavsiyem, üst arayüzleri geniş tutmanızdır. Yani bir işlem, tek çağrıda çok iş yapsın, veri geriye getirebileceği kadar veri geri getirsin. Örnek aşağıda:
public class HesapBean
{
public Collection musteriPortfoyGecmisIslemleriGetir(String musteriNo) {
...
}
}
MusteriPortfoyGecmisIslemleriGetir işlemi içinde, JDO bağlantısı yapıp, get/set ile istediğiniz nesneyi kullanabilirsiniz.

Sayfalar

Her modern internet yazılımı, sunucu sayfa metodu denen bir metod kullanıyor bu günlerde. Mesela PHP, JSP bunlardan sayilabilir. JSP, yani Java Sunucu Sayfaları, kodu sunucuda işletip, tarayıcı programınıza görsel bilgileri gönderir. Kıyas etmek gerekirse, Javascript kodu tarayıcı içinde işletilir, sunucu ile alakası yoktur yani.

İlk projeniz icin salt JSP işinizi gorur. JSP kullanarak <jsp:include>, <% %> icinde Java kullanarak güçlü programlar yazılabilir. Eğer daha kuvvetli bir sayfa dili kullanmak isterseniz, J2EE, istediniz sayfa kütüphanesini (dilini), JSP altında kullanmaniza izin veriyor. Mesela JSTL ve Struts bu sayfa dillerinden bazılarıdır. Apache projesi altındaki bu diller cok kullanışlıdır.

Alt katlardan bahsettik: Buna göre, JSP/Servlet/Action icinde, EJB baglantısı kurup musteriPortfoyGecmisIslemleriGetir işlemini çagırmanız lazım olacak. Geri gelen Collection (liste) içinde ihtiyacınız olan veriyi bulabilirsiniz, JSP ya da Struts komutları kullanarak veriyi görsel bir biçimde ekrana nakledin.

Özetle...


* Veri tabanı: Oracle, MySql, ya da Pür Java JDO'ya Hazır Veri Tabanı - ObjectDB
* Nesne/Veri Bağlaşımı: Hibernate, TJDO (Serbest Yazılım), Kodo (Ticari)
* Alt Ara Kat: WebLogic JBoss ya da herhangi bir J2EE uyumlu sunucu programı
* Üst Ara Kat: Tomcat WebLogic , ya da herhangi bir J2EE uyumlu sunucu programı
* Görsel Katman: Tomcat, WebLogic veya Tomcat üzerinde JSTL, Struts veya JSP

Oracle Tablolarından CSV Dosyası Üretmek

Oracle'daki bir tablonun verilerini metin bazlı bir dosyaya almak istiyorsanız, bunun için aşağıdaki gibi bir betik yardımcı olabilir.

SET TERMOUT OFF
SET HEADING OFF
SET SHOWMODE OFF
SET LINESIZE 2000
SET FEEDBACK OFF
SET VERIFY OFF
SET ECHO OFF
SET TIMING OFF
SET NEWPAGE 1
SET WRAP ON
SET LONG 32767
SET ARRAYSIZE 1
SET HEADING OFF

spool c:/temp/cikti.cvs

select KOLON1||','||KOLON2||','||... from TABLO;

exit;

 
$ sqlplus kulanici/sifre@SID @dump.sql

.. olarak isletildikten sonra, bir CSV dosyasi c:/temp/cikti.csv olarak üretilecektir.

Projeleri Kurtaran Nedir?

Bilgi işlem dünyasında karşımıza çıkan iki katmanlı projelerden, günümüzdeki çok katmanlı mimarilere kadar bir programcının ve teknik liderin kendine sorması gereken en önemli soru şudur.

"Hangi çeşit bilgi, projemi kurtarır ve zamanında sürüm yapmamı sağlar?"

Bu sorulara her projenin ya da şahsın değişik cevaplar verdiğini görebilirsiniz. Bazen de başarılı olan programcılar bile işi nasıl becerdiklerini kelimelere koyamamakta, içgüdüsel bir halde doğru alanlara odaklanıp projeyi başarıya kavuşturan bu arkadaşlara ne zaman bu soruyu sorsak, şöyle bir cevap vermektedirler: "Bilmem, oluyor işte".

Zamanla, yakından gözlem yaparak ve karşılaştırmalı olarak kendimizin de içinde bulunduğu projelerden esinlenerek şu cevabı verebiliyoruz.


Bilgi işlem için odaklanması gereken en önemli konu, kullanılan teknolojinin açıklarını, faydalarını hemen anlayarak, sürekli karşımıza çıkan genel bilgi işlem problemlerine bu teknolojinin verdiği cevapları masaya yatırabilen/kavrayabilen zihniyettir.

Bu cevap bariz gelse de, niye cevabın programlama dilleri, proje idare teknikleri, nesnesel tasarım, oklar/balonlar çizmemizi sağlayan CASE araçlari olMAdığını açıklamamız gerekiyor. Çünkü bazılarının cevabı bu paragrafta yeralan seçenekler olmuştu, ve bu cevaplar verildiğinde mantıklı olan açıklamalar beraberinde kabul görmüşlerdi.

Niye Programlama Dilleri Cevap Değil

1996 tarihinde milyon dolarlık bir proje içinde, milyar dolarlık bir müşterimize CORBA bazlı bir çözüm vermek üzere kolları sıvamıştık. Takımda her türlü alanda güçlü olan arkadaşlar vardı; Dili (C++) iyi bilen, proje idarisinde tecrübeli, işkolu (thread) programcılığını iyi bilen, veri tabanlarında muazzam bilgili sahsiyetler proje takımımızın üyeleri idi. Bir arkadaşımız, KKİ sisteminde herkesin aynı şekilde yaptığı bir kodlama hatasını 3 satırlık Perl koduyla düzeltmiş, ve geri kayıtlayarak (check in), hepimizi bir haftalık düzeltmeden kurtarmıştı. İnanılmaz bu performans karşısında daha projenin başı olduğu için, işi 5-6 ayda bitireceğimizden hepimiz gayet emin olmuştuk.

Fakat yukarıdaki kurala dönersek, en önemli olan faktör C++ ya da Perl dilindeki ustalık değildi. Çünkü projemiz vaktinde bitmedi. Cevap niye dil değildi?

Bir proglama dili boşlukta yaşamaz. Bilgi işlem işi, aslında bir tümleştirme (integration) eylemidir, bu yüzden C++ dilinin 'birşeyler yapabilmesi için', mutlaka XYZ kütüphanesinden 'birtakım kodları' işletmesi gerekir. Bu kütüphane kodları (kod adacıkları), başlıbaşına apayrı bir dünyadırlar. Neredeyse her kütüphane, aslında kendi başına bir dil olarak adledilebilir.

Karşılaştırırsak, "Java'ya Giriş" gibi kitapların öğretikleri dilin, soyut olarak düşünürsek, tekrarlama, koşullar ve metin bazlı giriş çıkış evreni öngeren bir dil olduğunu görürüz. Tabii ki bu temelin mutlaka kavranması gerekir, ama bilgi işlem dünyası için bu kadarı yetmemektedir. Akademik bir ortamda sadece algoritma odaklı bir çevrede iseniz, sırf dil bilgisi yetebilir. Çünkü akademik çevrede amacınız daha işlevsel (functional) olacaktır. Bilgi işlem dünyası tümleştirir, bilgi işlem, çetrefilli algoritmaların dünyası değildir.

İşte bu sebepten ötürü, dil bilgisini önem sırasında en tepeye koymuyoruz.

Niye Nesnesel Tasarım Yöntemleri Değil

80'li yıllarda başlayan, 90'lara damga vuran nesnesel idare teknikleri, bizim projemizde en gözde konu idi. O zamanın danışmanlık dünyası, nesnesel tasarımı tamâmen kabullenmişti. Her teknik liderin kolunun altında bir Gready Booch kitabı, ya da yeni çıkan Design Patterns (Tasarım Kalıpları) kitapları ile etrafta dolaşmaktaydılar. Bir programcının bir ötekine söyleyebileceği en ağır hakaret şu idi: "Ama bu tasarımın, nesnesel değil!". :)

Bu tip teknikleri de oldukça iyi bilen takım arkadaşlarımız vardı. Şahsen yeni okuldan mezun olmuş şahsımız ve birkaç arkadaş ile beraber, modelleyemiyeceğimiz bir problemin daha doğmamış olduğunu adlediyorduk. Bunda da haklıydık. Fakat bilgi işlemde modelleme, yukarıdaki kurala tekrar dönersek, en önemli faktör değildi. Neden?

Nesnesel modelleyi şöyle düşünebilirsiniz. Önümüzde gereksinimleri listelenmiş olan bir bilgi işlem problemi olduğunu düsünelim. Bu problem için, a, b ve c işlemlerinin yapılması gerekiyor. Dikkat edin, işlemler diyoruz. Yani komut dizisi. Bu komutların, bir nesnesel programdan ya da LISP gibi işlevsel bir programdan gelip gelmediği hiç önemli değildir. Sonuçta herşey dönüp dolaşıp ASSEMBLER koduna, yani makina koduna dönecektir, değil mi? Bu yüzden, nesnesel tasarım, bir komut dizisini vesaire şekilde parçalara bölen, taksim eden bir yöntemdir, e tabii vesaire_2 şeklinde kodu parçalara bölen yöntemler de vardır. Nesnesel tasarım sihirli bir şekilde programımıza işlev katan bir yöntem değildir. Nesnesel tasarım, kodun okunabilirliğini, bakım evresinde rahat anlaşılmasını sağlayan bir düzenleme yöntemidir. İyi yazılmış nesnesel kodun amacı, gereksiz şekilde tekrar eden kodu merkezileştirerek, tek bir yere toplamaktır. Böylece yazılmış olan kod miktarı azalır. Bu iyi bir şeydir. Fakat zil takarak oynamamıza sebebiyet verecek bir vahşet bir numara değildir.

Cevap Niye CASE Araçları Değil

CASE araçları, balonlar ve oklar çizmemizi sağlayan, kodumuzu kuşbakışı bakmamıza yardım eden araçlardır. Eğer sunum (presentation) amacı, ya da kodumuzdan geri-mühendislik yaparak şekiller üretecek şekilde kullanılırsa, yararlı araçlardır.

Fakat eğer tasarım/geliştirme sürecinin tam ortasına konulup, kod yazmadan önce şeklini çizmeniz lazım gibi bir kural konulacak olursa, projeniz tehlikeye girecektir. Çünkü, CASE araçları da nihayi sonuçta bir projenin belkemiği olamaz. CASE araçları hâla şekilden kod üretip, sonra aynı kod metinyazar ile değiştirildikten sonra koddan geriye düzgün şekilde yeni şekiller yaratabilecek bir halde değildir. Olsa bile, kod bu sefer iki formatta tutulmuş olacak ve karışıklık yaratacaktır. Eğer kodlar/figürler ikilisini tamtamına uyum halinde otomatik olarak tutamıyorsaniz, figürler geliştirme sürecinin merkezi olamaz.

Otomatik gitme/gelme mümkün olsa bile, kodun tanımlama gücü (expression power) figürlerden her zaman daha yüksektir. "Bir resim, bin kelimeye bedeldir" sözü yazılım dünyasında bazen kullanılıyor, fakat bu söz yazılım dünyası için geçersiz bir sözdür. Yazılımda geçerli olan şekli şöyle olmalıydı: "Üzerinde anlaşma sağlanmış olan bir kelime (kod), bin resime bedeldir".

Cevap Niye Proje İdare Teknikleri Değil?

Bu sorunun cevabında, nesnesel modelleme için verdiğimiz cevaba bir paralellik göreceğiz.

Proje idare teknikleri, yapılacak işi her nasıl taksim, işbölümü, görevlendirme ile dağıtıyor olsa da, sonuçta iş dönüp dolaşıp tek bir şeye bâğlanır. Takım, doğru alanlara odaklanabilen bir teknik lidere, ve yetenekli takım elemanlarından oluşuyor mu? Eğer oluşmuyorsa, takım XYZ projesini diyelim ki 9 ayda bitirecektir. Eğer biliyorlar ise, 6 ayda bitireceklerdir. Bilinmezlik seçeneğinde verilen 9 ayı, her nasıl böler, katlar, görevlendirir, tekrar görevlendirseniz de, sonuçta toplam 9 ay olacaktır. Proje idare yöntemleri hiç yoktan yetenek yaratamazlar.

Bu yüzden en iyi idare yöntemi, ortada en az gözükendir. Yani programcının ayaklarına en az dolaşan proje idare yöntemi en uygunudur. Sitemizde öğretmek için Extreme Programcılığın seçilmesinin sebebi budur: XP'nin merkezi bireydir, yöntemin kendisi değil.

Fakat XP bile, yeteneksiz bir gurup programcıya gaipten teknoloji bilgisi veremez. Bu yüzden proje idare yöntemleri en önemli faktör değillerdir.

En Önemlisi: Teknoloji Kullanımı

Evet, olmazlardan olura geldik. Niye en önemli konu, kullanılan teknolojinin açıklarını, faydalarını hemen anlayarak, sürekli karşımıza çıkan genel bilgi işlem problemlerine bu teknolojinin verdiği cevapları masaya yatırabilmektir?

Çünkü, yapılması gereken iş miktarının ne olduğuna karar veren yegane faktör, teknolojinin nasıl kullanıldığıdır. Bir örnek ile açıklayalım.

Başta bahsettiğimiz CORBA projesinde karşımıza, o zamana göre çetrefilli şu problem çıktı. Kullanıcı bilgisayarlar ile servis bilgisayarı arasında bazı sonuç listelerini (resultset) göndermemiz gerekiyor.

1) Müşterinin kayıtlı olduğu planlar bir değil, birden fazla. Eğer plan sayıları mesela 100 tane ise, temel bir veri yapısı (int, boolean, String gibi) tabii ki kullanamayız, bize bir liste veri yapısı lâzım.

2) Kullanıcı bilgisayar ile servis bilgisayarı bir ağ üzerinden haberleşiyorlar. Aynı bilgisayar üzerinde değiller, bu sebeple dil salt seviyesinde düşünülen bir "return liste" gibi bir çözüm bizi kurtarmıyor.

Bu problem katmanlı bilgi işlem dünyasından çok klasik bir problemdir. Teknolojiden, idareden, modelden bağımsız düşünün: Gayet soyut olarak bakalım. Bu problem hangi çok-katmanlı bilgi işlem projesinde olursak olalım, kesinlikle karşımıza çıkacak.

Bu klasik problemin klasik bir problem olduğunu bilmek öncelikle tecrübe gerektir. Bundan sonra, atılacak adım şudur.

Projeniz için seçilmiş olan teknoloji çorbasına bakarsınız. Hangi teknoloji bu probleme çözüm olacak? Bizim örneğimiz için cevap CORBA.

CORBA'nın bu soruna verdiği cevap nedir? String[] gibi bir tip çeşidi buluyoruz. Fakat bir ağ ortamındayız, iki bilgisayar birbirinden uzakta. Ya 1000 sonuç göndermemiz gerekiyorsa? Bir seferde 1000 tane kayıt ağ üzerinden gönderemeyiz ya?

Kullanıcı tarafında görsel programı şöyle değiştirelim. Listeyi parça parça göstersin, ve "Sonraki" diye bir düğme kullanıcıya sonraki parçayı göstersin.

Peki CORBA otomatik olarak 1000 elemanı parçalara bölüp öyle geriye gönderebiliyor mu?

Cevap hayır.

İşte kullandığımız teknolojinin zayıf tarafını bulduk. Şimdi bu zayıflığın üstesinden nasıl geleceğiz? Bulacağımız cevap yeni baştan bir uygulama servisi yazmayacak şekilde, kısa, etkili, kötünün iyisi bir cevap olmalı.

Potansiyel Çözüm 1: Kullanıcı tarafı, CORBA bağlantısı üzerinden bir servis nesnesine bağlantısını koparmasın, o servis nesnesi de son işletilen veri tabanı sorgusundan gelen sonuç listesine olan bağlantısını koparmasın. Kullanıcı tarafı yeni parça istediğinde, yeni parça mevcut veri tabanı bağlantısı üzerinden verilsin.

Olmaz. Çünkü, bir çok-kullanıcılı mimariyi ölçeklemek istiyorsak, veri taban bağlantısını tek bir kullanıcıya bağlı tutamayız. Bâğlantılar veri taban dünyasında en pahalı kaynaktırlar, çok tutumlu kullanılmalari gerekir. Eğer kullanıcı-bağlantı birebir bağlanırsa, mimarimiz iki katmanlı demektir, üç katmanlı değil! CORBA, RMI, Servlet'leri boşu boşuna kullanmış olurduk. Veri tabanlarının bu özelliğini bilmek, kuralımızın tekrar ilginç bir şekilde ispatladığı üzere, kullandığımız bir teknolojinin zayıf tarafını bilmekten geçer. Veri tabanlarının eşzamanlı şekilde servis edebildiği kullanıcı sayısı, veri tabanının açılmasına izin verdiği "bağlantılar (database connection)" ile orantılıdır.

Birinci çözümü attık.

Potansiyel Çözüm 2: Servis nesnesi, liste istendiğinde listenin bir parçasını geriye göndersin (güzel). Bu işlem yapıldıktan sonra veri taban bağlantısını koparsın (güzel). Şimdi ilginc tarafa geldik: Listenin ikinci parçasını nasıl bulacağız?

Şöyle yapalım: Oracle'ın ROWID denen özelliğini kullanabiliriz. ROWID, her satıra verilen özebir (unique) kimlik numarasıdır. İlk parçayı geri gönderdikten sonra, bu listenin ilk parçasının en son elemanının ROWID'sini bir tarafa yazalım. İkinci parça istendiğinde servis nesnesi aynı sorguyu tekrar işletsin, ama bu sefer sadece son ROWID'den büyük olan satırları geri göndersin. Bu da ikinci parça olur.

Bu çözüm iyiye benziyor. Fazladan yazılan, yani CORBA'nın zayıflığı yüzünden yazmamız gereken kod miktarı çok değil. Kötünün iyisi bir çözüm bulduk galiba. Hem veri tabanı bağlantısına denize düşen yılana sarılır gibisinden sarılmadık, hem de bir sürü yeni kod yazarak projeye fazla yük getirmedik. Her taraftan omuzumuza düşmüş olan gereklilikleri gözettik, ve bir çözüm bulduk.

Ve işin özünü böylece açıklamış olduk. Dikkat ederseniz, potansiyel çözümlerden bahsederken, ne XYZ modeli dedik, ne CASE aracından şöyle balonlar çizelim dedik, ne de "sayın arkadaşlar, Extreme Programcılık bağlamında yönteminde birileri ABC özelliğini karta yazsın, bir tahmin yapsın ve kodlamaya başlasın" dedik. Bunların hiçbiri bize çözüm için yardımcı olmayacaktı.

Doğru çözümü bulduktan sonra yazılması gereken kodu, istediğimiz şekilde keser biçer taksim edebilir ve bir temiz nesne modeli yaratabiliriz.

Doğru çözümü bulduktan sonra harcanması gereken zamanı Extreme Programcılık ile istediğimiz gibi taksim eder, takip edebilirdik.

Doğru çözümü bulduktan sonra bir CASE aracı ile (ya da Visio ile) cözümümüzü anlatan şekiller çizebilir, müşterimizi, takım arkadaşlarımızı bilgilendirebilirdik.

Ve en son olarak, doğru çözümü bulduktan sonra istediğimiz dilde (o dilin izin verdiği şekilde) kodlayıp işi bitirebiliriz.

Yani: İkinci derece önemde olan eylemleri, birinci derece önemli olan bittikten sonra istediğimiz gibi yapabiliriz. Fakat ikinci derece önemde olan eylemler, projeyi kurtarmaz. Önce yapılması, odaklanılması ve katiyetle öğrenilmesi gereken birinci derece önemli olan eylemdir. Yani teknolojiyi doğru şekilde kullanabilmek, anlayabilmek, gerekiyorsa etrafından dolaşabilmek.

Yanlış anlaşılmaması için tekrar belirtmeyi uygun görüyoruz. Tabii ki nesnesel modelleme, mevcut diğer kod düzenleme yöntemleri arasında en iyisidir. XP'nin esnek bir yöntem olduğu muhakkaktır, programcıya rahat nefes aldırır, ve proje içinde özgürlük sağlar. Evet Java rahat bir dildir, ve revaçta olan nesnesel dillerin arasında en temiz sözdizim yapısına sahip olandır. Fakat bunlar bilgi işlem dünyasında tabiri yerinde ise, "buzdağının görünen kısmıdır". Bu yazımızın amacı, düşüncesel, bakış açısı olarak içinde bulunmamız gereken zihin durumunu yansıtmaktır. İkinci derece önemli yöntemleri gereksiz olarak etiketlemek değil.

Doğru Çözümün Bir Tarifi Daha

Doğru çözümden bahsederken, bu sonuç çözümün belli karakteristiklerinden bahsetmeyi uygun görüyoruz. Bu karakteristiklerin en önemlisi, çözümün basit olmasıdır. Mühendislikte de, temel bilimde de basitliğin önemi büyüktür. Bilim dünyasında basitliğe vurgu, Occam'ın Usturası (Occam's Razor) adlı özdeyiş ile yapılır. Occam, şöyle demiştir: "Hiçbir şeyi gereksizce çoğaltmayalım", bunun Latinceden, İngilizceye ve günümüze taşınması sonucu özdeyiş şu hali almıştır: "İki hipotez arasında, daha basit olan hipotezi seçiniz". Bilim dünyası da Occam'ın zamanından beri böyle yapmıştır.

ABD'de programcılar arasında da yaygın bir deyiş vardır: Çözüm basit ve aptal olsun (keep it simple, stupid - KISS)

Yâni çözümü hazırlarken, bunu elimizdeki teknolojilerin açıklarına, güçlü taraflarına göre kurar, ve çözümün her zaman basit olmasına dikkat ederiz. Bu basitlik, her seviyede geçerli bir basitlik olabilir: Kodlamada basitlik, idarede (administration) basitlik, kod miktarının az olması, az sayıda dış arayüz kullanılıyor olunması, vs..vs..

Bağlaşım: Nesneler, Veri Tabanları

İş hayatına danışman/programcı olarak başladığımızdan beri önümüze şöyle bir problem çıkmıştır. Nesnesel bir dil ile yazdığımız programlarımızı veri tabanına nasıl bağlayacağız?

"İnsanlar bunu niye problem haline getirdi?" diyebilirsiniz. Bunun birkaç sebebi var, ama çoğunun ana teması aynıdır: Programların bakım evresinde daha rahat değiştirebilmek... Zaten tasarım yaparken, ana amaçlarımızdan biri bu olmalıdır: Okunabilen, rahat değistirilebilen kod yazmak. Özet olarak: Yukarıda bahsettiğim arkadaşlarımızın (ve şimdi de benim) ana ilkesi şu idi. Veri tabani mimarisini, Java program tasarımından mümkün olduğunca uzak tutmak/bağlantısını hafifletmek. Biraz daha açıklayalım.


* Java, nesne tabanlı olduğu için, Java programcıları her şeyi nesne olarak görürler. Mesela Javacılar için, insan.setIsim(yeniIsim) demek, UPDATE INSAN SET ISIM='' demekten daha rahattır. Eğer SQL kodunu Java içine koyarsanız, programın ne yaptığı rahat anlaşılmaz.
* Java kodunuz, veri taban cizelgesine direk bağlantı yapıyorsa, çizelge değişince Java programı değistirmeniz gerekecektir.

Şimdi iki türlü kod parçası vereceğiz. Hangisinin daha rahat veri tabanına erişim sağladığı belli olacaktır.

//
// JDBC kullanıyoruz
//
class VeriKontrol
{
public void guncellestir(Isci isci, Fabrika fabrika, String
yeniIsim, String yeniSoyad, String yeniFabrika)
{
Connection c = d.getConnection();
PreparedStatement stmt = c.prepareStatement("UPDATE ISCI set
ISIM=?, SOYAD=?, FABRIKA_NO=?");
stmt.setString(1, yeniIsim);
stmt.setString(2, yeniSoyad);
stmt.setString(3, yeniFabrika);
}

public void FabrikaCalisanIscileriIsle(String fabrikaNo)
{
Connection c = d.getConnection();
PreparedStatement stmt = c.prepareStatement("SELECT * FROM
ISCI WHERE FABRIKA_NO=?");
stmt.setString(1, id);
rs = stmt.executeQuery();
while (rs.next())
{
String id = rs.getString("ISCI_NO");
// .. birseyler yap isci ile
// ama dikkat edin, elimizde hala Isci nesnesi yok
// nesneyi NO kullanarak yaratmamiz lazim.
}
}

}

Eğer nesne/veri baglaşımı dışarıda yapılmış ise, program şöyle olabilirdi.

class VeriKontrol
{
public void guncellestir(Isci isci, Fabrika yeniFabrika)
{
// bu iki satiri nesne icinde daha once isletim, sonra
// gerektikce oradan kullanabilirsiniz. Hep yazmaya gerek yok.
PersistenceManagerFactory pmf = JDOFactory.getPersistenceManagerFactory ();
PersistenceManager pm = pmf.getPersistenceManager ();

// kritik yer burasi
fabrika.isciEkle(isci);
pm.guncellestir(isci);
}

public void FabrikaCalisanIscileriIsle(String fabrikaNo)
{
// yukaridakinin aynisi
PersistenceManagerFactory pmf = JDOFactory.getPersistenceManagerFactory ();
PersistenceManager pm = pmf.getPersistenceManager ();

// veriyi al
Collection results = null;

// sorgu yarat
q = pm.newQuery (e, "fabrikaNo == " + fabrikaNo);
sonuclar = (Collection)q.execute ();

Iterator sonucTarayici = results.iterator ();

while (sonucTarayici.hasNext ())
{
Isci isci = (Isci)sonucTarayici.next ();
// isci ile birseyler yap.
// isci.getFabrika() diyerek fabrika objesine erismek mumkun
// mesela..
..
}
}
}

Aradaki fark herhalde belli oluyordur. 2'inci kod parçasının üstün tarafı şurada, sadece nesneler ile haşır neşir oluyoruz ve setDeger, getDeger gibi ifadeler kullanabiliyoruz. Birinci şekilde, bir takım karmakarışık SQL kodunu Java içine koymak gerekiyor, iki dil ile uğrasmak gerekiyor.

Nesne/Tablo Eşleme Programları İçin Aranan Özellikler

Evet, bağlaşım dogru yapılınca Java kodumuz nasıl olacak gördük. Şimdi, bize yardımcı olacak yazılımı tanıyalim. Biraz da tarihçe.

Bağlaşım yazılımlarının tarihi, nesnesel programcılık kadar eskidir. Mesela bazı standardlar 90'li yılların başında ortaya çıkmıştır: POS (Persistent Object Specification/Kalıcı Nesne Tarifnamesi) OMG adlı gurup tarafından ortaya atılmıştı. Oldukça ses getiren yaklaşımlardan biri olsa da, ne yazik ki ürün desteği olmayınca kağıt üzerinde kaldı, ve tarifname'ye göre geliştirmeye calışanlar hüsrana uğradı. Şahsen tanıdığımız bir arkadaş bu tecrübeden geçti, ve geçtiğine pişman.

Fakat sektör pes etmedi, çünkü nesne içine SQL koymak nesneci programcıların hiç icine bir türlü sinmedi. Fakat bağlaşım hazir olmayınca, herkes kendi mutfağında bir şeyler pişirmek zorunda kaldı. Şahsen, bir projede her nesne için güncelleştir(), sil() ve oku() gibi işlemler yazarak, nesne/tablo bağlantısını bir nevi 'yapay' bir şekilde kurmaya calıştık. (Yukarıdaki yöntemler içinde SQL yazıyorduk).

Ayrıca, nesnesel programcıların veri tabanı kolonlarına (column) Java nesne özellikleri (attributes) olarak erişme isteği arkasında bir baska itici kuvvet daha var. Internet Sunucu programları için yazılan sayfalar, mesela JSP, JHTML, Struts gibi diller akabinde sayfa içinde bilgiyi, 'nesne' olarak sayfaya bağlamak gerekiyor. Yani, üzerinde setXX, getXX olan türden nesnelerin olması bu tür programlar için şart. Bu da önümüze kanun gibi çıkınca, veri tabanı ve Java aradasındaki bağlantıyı kurmanın gerekliliği iyice ortaya çıkıyor, ve bağlaşım dünyasında hareketlenme de bu yüzden hızlanıyor.

Son çözümlerden önümüzde olanlar:


* JDO (Java Data Objects) yani Java Veri Nesneleri
* EJB 2.0 Kap Kontrollu Kalıcılık/Container Managed Persistence

Yukarıda verilen ikinci örnek, JDO kullanarak yazılmıştır.

İlerideki yazılarımızda, oldukça yayılmaya başlayan JDO teknolojisini yakından tanıyacağız, ve bağlaşım yazılımı seçerken nelere dikkat etmemiz gerekiyor yakından inceleyeceğiz.

MQSeries Nasıl Kurulur

Bu yazının amacı Solaris 2.7 MQSeries 5.2 kurmayı öğretmek. Ayrıca JMS kullanarak bir örnek kuyruğa mesaj koymayı göstereceğiz.

MQ Kuralım


* İlk once Unix üzerinde mqm adlı bir kullanıcı yaratın.
* mqm adlı bir gurup yaratın.
* MQ program dosyasını IBM sitesinden indirin.
* pkgadd dosya_ismi kullanarak programı kurabilirsiniz. İşiniz bittikten sonra MQ /opt/mqm altında olacak.
* Şimdi JMS kütüphanesini kurmamız lazım. IBM sitesinden ma88_sol.tar adlı kayıdı bulup indirin. Bunu da pkgadd kullanarak kurun. İşiniz bitince program /opt/mqm/java altında olacak.
* /opt/mqm/java altındaki bütün JAR dosyalarını CLASSPATH'inize ekleyin.
* MQ kullanacak bütün Unix kullanıcılarının mqm gurubu altında olmasına dikkat edin.

Kuyruk Yaratmak

Kuyruk yaratmak için aşağıdakini uygulayın

crtmqm -q venus.queue.manager

Kuyruk gözleyicisini başlatmak için

strmqm

Solaris başlayınca otomatik olarak kuyruk gözleyicisi başlasın istiyorsanız, aşağıdaki satırları /etc/inetd.conf dosyasına ekleyin.

MQSeries stream tcp nowait mqm /opt/mqm/bin/amqcrsta amqcrsta -m venus.queue.manager

Bu satırları da /etc/services dosyasına ekleyin.

MQSeries       1414/tcp      # MQSeries channel listener

Aşağıdakiler için, MQ komut satırına inmeniz lazım.

$ runmqsc

0783889, 5765-B75 (C) Copyright IBM Corp. 1994, 2000. ALL RIGHTS RESERVED.
Starting MQSeries Commands.

- kuyruk yaratan komut budur
define qlocal (orange.queue)

-- kanala yaratan budur
DEF CHL('JAVA.CHANNEL ')CHLTYPE(SVRCONN)TRPTYPE(TCP)MCAUSER('')+
DESCR('Java icin ornek kanal')

-- komut satirindan cikmak icin
end

Tetikleyici gözlem programı için:

runmqtrm

Kanal baslangıç programı için:

runmqchi

Komut işlem programı için

strmqcsv

Örnek Java/JMS Nesnesi

Aşağıdaki kod sayesinde, yukarıda yarattığımız kuyruğa bağlanıp bir mesaj koymamiz mümkün.

import com.ibm.mq.jms.MQConnectionFactory;
import com.ibm.mq.jms.MQQueueConnectionFactory;
import java.io.PrintStream;
import javax.jms.*;
import com.ibm.mq.jms.JMSC;

public class Test
{

public static void main(String args[])
{
Test test = new Test();
test.addDataItem();
}

public Test()
{
kuyrukIdareciIsmi = "venus.queue.manager";
makinaIsmi = "localhost";
kanal = "JAVA.CHANNEL";
port = 1414;
kuyrukIsmi = "ORANGE.QUEUE";
transportType = JMSC.MQJMS_TP_CLIENT_MQ_TCPIP;
}

public void addDataItem()
{
try
{
MQQueueConnectionFactory baglantiFabrikasi = new MQQueueConnectionFactory();
System.out.println("kuyrukIdareciIsmi :" + kuyrukIdareciIsmi);
System.out.println("Makina ismi :" + makinaIsmi);
System.out.println("Kanal :" + kanal);
System.out.println("port :" + port);

baglantiFabrikasi.setQueueManager(kuyrukIdareciIsmi);
baglantiFabrikasi.setTransportType(nakilTuru);
baglantiFabrikasi.setHostName(makinaIsmi);
baglantiFabrikasi.setPort(port);
baglantiFabrikasi.setChannel(kanal);

QueueConnection kuyrukbaglantisi =
baglantiFabrikasi.createQueueConnection();

kuyrukbaglantisi.start();

QueueSession queuesession =
kuyrukbaglantisi.createQueueSession(false, getTransportType());

javax.jms.Queue kanal = queuesession.createQueue(getRemoteQueueName());

QueueSender queuesender = queuesession.createSender(queue);

ObjectMessage mesaj = queuesession.createObjectMessage();

mesaj.setObject(new String("---------------"));

queuesender.send(mesaj);

}
catch(JMSException jmsexception)
{
jmsexception.printStackTrace();
}
catch(Exception exception)
{
exception.printStackTrace();
}
}

public String getQueueManagerName()
{
return kuyrukIdareciIsmi;
}

public void setQueueManagerName(String s)
{
kuyrukIdareciIsmi = s;
}

public String getHostName()
{
return makinaIsmi;
}

public void setHostName(String s)
{
makinaIsmi = s;
}

public int getPort()
{
return port;
}

public void setPort(int i)
{
port = i;
}

public String getChannel()
{
return kanal;
}

public void setChannel(String s)
{
kanal = s;
}

public int getTransportType()
{
return nakilTuru;
}

public void setTransportType(int i)
{
nakilTuru = i;
}

public String getRemoteQueueName()
{
return kuyrukIsmi;
}

public void setRemoteQueueName(String s)
{
kuyrukIsmi = s;
}

private String kuyrukIdareciIsmi;
private String makinaIsmi;
private String kanal;
private int port;
private int nakilTuru;
private String kuyrukIsmi;
}

MQ Series

Bilgisayarlarda mikroişlemci temeline kadar inerseniz, aslında herşeyin basit bir temel üzerine oturtulduğunu göreceksiniz. Programlar ana bellek içinde durur, ve program kodlarını işleten merkez işlemci, kodları teker teker bellekten alıp işleme koyar. Ve bu kodlar işlerken onların sonucunu BEKLER.

Bilgisayarları tasarlayan mühendisler için, bu işlet/bekle döngüsü rahat anlaşılır bir kavramdır. İşleri kolaylaştırır, bu yüzden genelde kullanılan kavram budur. Ve en temelden desteklendiği icin, bu bütün program dillerine yansımış, mesela bir Java işlemi de aynen makina dilinin yaptığı gibi (assembler) işlem sonuçlarını bekler olmuştur.

Fakat bazen, alternatif bir yaklaşımı kullanmak yararlı olabilir. Bu değişik yaklaşım şudur: "İşlemi çağır ama sonucu beklemeden yoluna devam et, sonucu bir şekilde geri alirsın".

Bu tip kavramlar, programlama dili seviyesinde kullanılabilir, fakat genelde bu iş, dış paket programlar yardımı ile yapılıyor günümüzde. MQ Series bu programlardan biridir.

İleti (Mesaj) kuyruğu denen programlar, isimleri üzere, cağırılan işlemleri depolarlar. Mesajları yüksek bir hızda, sistemler arasında değiş/tokuş yapmak için yazılmışlardır, ve iyi taraflarindan biri, mesajı KAYBETMEME garantisi verirler (sabit diske yazarak).

Örneğe gelelim.

Birbirinden alakasız iki sistem düşünelim: A ve B sistemi tamamen ayrı makinalar üzerinde çalışıyor olsunlar. Hatta 'işletim sistemleri' bile farklı olsun. Bu iki sistem arasındaki bağlantı TCP/IP bağlantısı, yani Internet usûlü bir bağlantı olabilir fakat bildiğimiz gibi TCP/IP, mesaj iletiminde 'garanti' vermez. Paket düşmesi denen olay sık olmasa bile, olması mümkün vakâlardandır.

Olayı renklendirmek için, B sistemine bir servis programı koyalım. Bu 'sunucu' program, çarpma servisi yapsın bizim için. 3 ve 5 sayısını verince geri cevap 15 verecek yani. Mucize program!

Arayüz şöyle olabilir.
public class Islem
{
public int carp(int sayi1, int sayi2)
{
return sayi1 * sayi2;
}
}

Oldu. Fakat, A sisteminden B sistemine nasıl bağlantı yapacağız? Java dünyasında RMI kullanabiliriz. RMI ile, B sistemindeki arayüzü, A sistemine uzaktan göstermek mümkün oluyor. yani nesne->carp(3, 5) islemini RMI A'dan alip B'ye, cevabı ağ sistemi ile geriye getirebiliriz.

Peki, ya, tam bu işlemi yaparken, B sistemi çökerse?

"Amma da zorlastırdın işi kardeşim, arada sırada çökerse çöksün!"

Bu cevabın geçerli olduğu iş şartları olabilir. Fakat bazı şartlarda B sistemi çökünce, geriye yanlış cevap vermek kabul edilemez olabilir. Bunun üstesinden gelmek icin RMI dünyasında, "olmazsa tekrar dene" gibisinden 'istisna kodu' yazabilirsiniz, fakat bu A sistemindeki kodu iyice karıştıracaktır. Peki çözüm nedir?

Mesaj kuyruk programları bu günler için yazılmıştır. Önce bir kuyruk tanımlarsınız. Kuyruk_1 ismini verelim: Bu kuyruğa mesaj koymak ve mesaj okumak mümkündür. Kuyruk_1'in kendisi, cismen A sisteminde, B sisteminde, ya da en iyisi, bir C sisteminde yaşıyor olabilir. Nerede yaşarsa yaşasın, sabit mesajları diske yazdığı için onları kaybetmeyecektir. Ayrıca MQ Series gibi programlar ile, kuyrukta biriken mesajlar, mesela C sistemi hayata döndüğünde, ona tekrar iletilmeye başlanır.


Böylece, mesaj kaybı sorununu çözmüş olduk.

Yanlız bu yeni sistemde biraz değişik düşünmek zorundayız. Artık, nesne->carp() islemi 'anında' geri dönecek, ve programınızın geri kalan kısmı işleme koyulacaktır, 'çarpım sonucu elinize geçmeden'. Çarpım sonucunu belki başka bir kuyruktan geri almanız mümkün olabilir. Ama, bu tip kararlar program mimarinizi etkileyecektir. Kuyruk bazlı ve olmayan programlar arasındaki mimari farkı o yüzden büyük olabilir; Önemli olan, hangi mimarinin ne zaman lazım olduğunu görebilmek. Eğer,


* İki değisik sistem, birbiri ile mesaj alışverişi yapıp, mesajları kaybetmek istemiyorsa
* Bu iki sistem birbirinden degişik zamanlarda ve kişiler tarafından kontrol ediliyor, o yüzden indirilip/kaldırılması gerekiyorsa
* Bilgi alışverisinin anlık olması gerekmiyorsa

Mesaj kuyruk bazlı programlar ihtiyacınızı karşılıyabilir.

Matlab Öğrenelim

Bkz Python Öğrenelim yazisi.

Artik Matlab yerine Python tavsiye ediyoruz; tum matematik icerigimiz bu yeni dile gecirildi.

--

Üç Boyutlu Çizimler

Üç boyutlu çizim yapmak için, meshgrid fonksiyonunu kullanmamız gerekiyor.

Herhangi boyutta fonksiyonu çizmek için, fonksiyona "verilen" değerler gerekir. Eğer bir fonksiyonu soyut hâliyle çizmek istiyorsak, yâni elimizde test verileri o anda yok ise, belli aralıklarla olan girdi X değerlerini "üretmemiz" gerekecektir. 2 boyutlu fonksiyonda, tek x vektörü yeterli olacaktır, fakat üç boyutlu çizimler için "iki" tâne "iki" boyutlu matris gerekir. Bu matrisleri Matlab'de meshgrid fonksiyonu ile otomatik olarak üretebiliyoruz.

Bu matrisler kurulduktan sonra, mesh çizim fonksiyonu ile X, Y ve hesaplanmış fonksiyon değeri olan meselâ R, bir küpe dönüştürülür, öyle ki, girdi x matrisi küpün X tarafından bakılınca görülen değerler, y matrisi Y tarafından bakınca görülen değerler olacaktır. Mesh fonksiyonu bu iki matris değerlerinin tüm kombinasyonlarını üçüncü hesap sonucu matrise bakarak (lookup) üç boyutlu uzayda bir çizim yaratabilecektir.


01:   [X,Y] = meshgrid(-4:2:4);
02:   display(X);
03:   display(Y);
04:   R = X.^2 + Y.^2;
05:   mesh(X,Y,R);

#1'de meshgrid ile -4 ve +4 arasında, her 2 noktada bir, bir nokta oluşturulacaktır. #4'te gösterilen '.' fonksiyonu ise, üst alma işlemini her matris elemanı üzerinde işletmek için kullanılır. Eğer '.' kullanılmazsa (X^2 gibi) sonuç sıfır matrisi olurdu.

Sonuç:


X =

-4    -2     0     2     4
-4    -2     0     2     4
-4    -2     0     2     4
-4    -2     0     2     4
-4    -2     0     2     4

>>
Y =

-4    -4    -4    -4    -4
-2    -2    -2    -2    -2
 0     0     0     0     0
 2     2     2     2     2
 4     4     4     4     4


Temel Vektör, Matris İşlemleri

X matrisini vektöre dönüştürmek için x(:) komutu kullanılır. Bu komut n x n boyutundaki bir matrisi, (n*n) x 1 boyutunda bir matrise çevirecektir. Örnek:


>> r = [3 4; 5 3]

r =

 3     4
 5     3

>> r(:)

ans =

 3
 5
 4
 3
>>

Bir matrisin tek bir satırına ya da kolonuna erişmek için : sembolünü boş olarak kullanınız. Meselâ


>> Z = zeros(3,3);
>> Z

Z =

 0     0     0
 0     0     0
 0     0     0

>> Z(1,:) = [ 1 2 3];
>> Z

Z =

 1     2     3
 0     0     0
 0     0     0

>>

Bu örnekte, önce boş bir matris yarattık, ve 1. satırına bir vektör ataması yaptık.

Vektör Elemanları Arasında İşlemler

Bir de, bâzen ihtiyacımız olan ama standart operasyon olarak gözükmeyen, "iki matrisin elemanları arasında birebir yapılan aritmetik işlemlerden" bahsedelim. Bu işlemler . (nokta) işleci ile gerçekleştirilir.


>> A = [ 4 4 4];
>> B = [ 2 2 2];
>> display(A./B);

ans =

 2     2     2

M Dosyalarını Test Etmek İçin

Kod organizasyonu açısından da yararlı olacağını umduğumuz bir numara paylaşmak istiyoruz: Önce bazı Matlab zorunlulukları: 1- Matlab, her fonksiyonunun aynı isimli bir dosya içinde tutulmasını mecbur kılar. Bu dosyaya birden fazla fonksiyon koyabilirsiniz, fakat bir tane dosya ile aynı isimde fonksiyon kesinlikle olmalıdır. 2- fonksiyon içeren dosyaların, betikleme (script) dosyası olmaları mümkün değildir, betikleme derken, dosya ismini Matlab komut satırından yazarak işletilebilecek türden bir dosyadan bahsediyoruz.

Şartlar böyle olunca, bir fonksiyonu geliştirirken, o dosya ismini komut satırına girip test etmek imkansız olmaktadır, çünkü test eden kod işleyen bir koddur ve Matlab'e göre fonksiyon ıceren kodla aynı yerde olamaz.

Bu problemin çözümü şöyle. Fonksiyona her giriş yapıldığında parametrelerin sayısını kontrol edin. Eğer parametre yok ise, fonksiyon komut satırından boş çâğırılıyor demektir. Bu durumda daha önce yazılmış bir betikleme/test/demo kodunu bir fonksiyon üzerinden işletebilirsiniz. Eğer parametre var ise, zâten normal çağırım yapılmış demektir, ve özel bir durum değildir, herşey normal halinde seyredebilir. Aşağıda bunun bir örneğini görüyoruz (dosya isminin fonk.m olduğunu farzedin).


function [ciktiA, ciktiB] = fonk (girdi, M)

if nargin==0, kendiniislet; return; end
...
... (fonk fonksiyonun kodlari buraya)
...

function kendiniislet
A = [ 2 3; 4 5]; % vs vs ...
[ciktiA, ciktiB] = fonk (A, 3);

Sonraki Satıra Geçme

Eğer uzun bir satırı birkaç satıra bölmek istiyorsanız, ... işaretini kullanabilirsiniz. Meselâ


s = 1 -1/2 + 1/3 -1/4 + 1/5 - 1/6 + 1/7 ...
  - 1/8 + 1/9 - 1/10 + 1/11 - 1/12;

.. gibi.

Lego Oyuncaklarınızı Java ile Kodlayın

Java proglama dilinin esnekliği kendini her yerde gösteriyor. Bu yazımızda ufak ortamlarda calışan bir örnek sunmaya calışacağım.

Büyük çoğunlugumuz küçükken Lego ile oynadık, ya da ne olduğunu biliyoruz. Bizim zamanımızda olan Lego parçaları, mekanik ve yerinden oynamayan parçalardı. Oynayan parçalar olsa bile, çocuklar eliyle tutup evirip çevirirdi. Buna rağmen, Lego parçaları zeka geliştirmesi ve çocukları üretmeye teşvik ettiği için muazzam bir ortam olmuştur. Hayal dünyası ile yakın bağlantı halinde olan çocukların, yaptıkları şeylere hayat vermesi ve oynamaları gayet rahattı.

Simdi filimi ileri sararak 21. yüzyıla gelelim. Lego tekrar büyük bir devrim yaratarak, oyuncak parçalarının içine programlanabilen bir beyin ekledi. RCX adı verilen bu beyin, öteki parçalar gibi, ötekilere yapışabilen türden tabii ki. Fakat en önemli özelliği, üzerinde 5 tane olan çıkış bağlantısı, ve bu bağlantıların tekerlek, ışık kontrol, dokunma kontrolü gibi öteki parçalara bağlanması. Bu bağlantı çok basit. Aç/Kapa şeklinde komutlar, beyinden uzuv parçalara basit komutlar ile gönderilebiliyor.

Programlama diline gelelim. Lego Mindstorm kutusunu alırsanız, içinden çıkan CD-ROM üzerinde, görsel bir program ortamı bulacaksınız. Fakat bu program, görsel çoğu ortamın olduğu gibi zaman alan bir ortam. Ayrıca gelişmiş bir programlama dilinin gücü yok.

İşte burada, Java sahneye giriyor. RCX kodunu anlayıp tersine çeviren programcılar, ufak bir Java VM programını Lego beynine koymayı başardılar. Tiny VM denen bu ortam üzerinde, Lego Mindstorm motor ve arayıcı/tarayıcı kontroller icin arayüzü yazdılar, ve sonuç olarak Java kullanarak Lego oyuncağımızi kontrol etmeniz mümkün oldu. Bu yeni Lego işletim sistemine LeJos deniyor. (Lego Java Operating System/Lego Java İşletim Sistemi)


Bu yazımızda, LeJos ortamını nasıl kuracağımızı anlatacağız.

Lego Mindstorm icin yazılan programlar, önce dizüstü yada masaüstü bilgisayarında geliştirilir. Geliştirme ortamı bilgisayarınızda USB çıkış noktası olmasına dikkat edin. Mindstorm kutusundan çıkan bir İnfrared verici USB ile bağlandıktan sonra, derlenen programları infrared üzerinden Lego beynine aktarılır. Java ya da basit RCX programları için bu işlem aynıdır.

Lego Mindstorm paketinizi alınca, CD-ROM'u takip sistemi kurun. Menüden çıkan seçenekleri takip edip bunu yapabilirsiniz. Bu işlem tamamlanınca, Lego işletim sisteminin kurulması lazım. (Bu sistem LeJos'dan farklı, ama kurulması gerekir).

Bu işlemler bittikten sonra, LeJos sitesinden gerekli programı yükleyin. Windows ve Linux ortamları için geliştirme kodları bulacaksınız. Bu kodlar, sıkıştrılmış şekilde tar yada zip ortamında gelecek. Bu dosyaları açıp, sabit disk üzerine kurun. Nereye kurduğunuz önemli değil.

Kurulduktan sonra, bazı 'ortam değişkenlerini' tanımlamanız gerekiyor. Windows ortamında iseniz, Settings | Control Panel üzerinden Environment Variables seçeneğine gelin. Buradan, PATH değişkeni için c:\lejos\bin; ekleyin, ve RCXTTY değişkeni için USB yazın.

Ayrıca Java geliştirme ortamınız olması lâzım. Bunun için ekteki baglantidan alabilirsiniz.

Bu işlemler bittikten sonra, komut satırına gelin ve şu komutu işletin.
lejosfirmdl

İşlem sonunda Lego beyni, iki kere 'bip' sesi çıkartacak. Kutlarım, artık Lego'nuz Java için hazır.

import josx.platform.rcx.*;

public class Test
{
public static void main (String[] arg)
throws Exception
{
for (int rot = 0; rot < 2; rot++)
{
Motor.A.forward();
Motor.C.forward();
for (int k = 0; k < 10000; k++) { }
Motor.A.stop();
Motor.C.stop();
for (int k = 0; k < 10000; k++) { }

}

for (int rot = 0; rot < 2; rot++)
{
Motor.A.backward();
Motor.C.backward();
for (int k = 0; k < 10000; k++) { }
Motor.A.stop();
Motor.C.stop();
for (int k = 0; k < 10000; k++) { }
}

}
}


Programı yazıp kaydedin. Tekrar komut satırına dönün ve şunu işletin:
lejos Test
lejos -o Test.bin Test
lejosrun Test.bin

Tekrar kutlarım, yeni yazdığınız program, Lego beynine yüklendi. Geriye kalan tek yapmanız gereken, Legoyu açıp (On-Off düğmesi), Run (çalıştır) düğmesine basmak. Programınız işleme girecek.

Örnek olarak gördüğünüz program için, Lego beyni üzerindeki A ve C motor bağlantılarını iki tekerleğe baglayın. Program çalışınca, oyuncak arabanız iki kere ileri, iki gere geri gidecek.

Türkiye'den LEGO Mindstorm temini için
Adore Oyuncak
Maslak/İstanbul

Tel: 212 286 0748 / 0765
e-mektup adresi: yurur@adoreoyuncak.com