Java Programlama Dilinin Gelişimi Üzerine: Başlangıç
Giriş
Java denince 1990'lı yıllarda-- tam olarak 21 Ocak 1996-- ortaya çıkan ve kişisel bilgisayarlardaki Wintel (Windows-Intel) egemenliğini Sun'ın Netscape ile yaptığı 'stratejik' ortaklık yoluyla sarsmasına bayraktarlık eden nesne yönelimli, genel amaçlı programlama dili akla gelir. Sonunda da, günümüz söylencelerine inanılacak olursa, kimine göre Netscape'in Java'nın popülerliğine dayanarak JavaScript adını verdiği dile, kimine göre Android platformu için uygulama yazmakta kullanılan bir diğer JSM dili olan Kotlin'e, kimine göre ise bulut bilişimin istemci-sunucu paradigmasını köklü bir şekilde değiştirmesi sonrasında Google'ın 'modern C' olarak lanse ettiği Go diline-- Google yerine Mozilla, Go yerine Rust koyarak da okuyabilirsiniz-- yenilerek programlama dilleri tarihinin çöplüğüne gönderilmiştir. Kesinlikle doğru değil! Bu ve takip eden yazılarımda yapmaya çalışacağım şey, bunun neden yanlış bir sav olduğunu Java'nın evrimine dair bilgiler ve yazılım dünyası geneline ilişkin bazı gözlemlerle destekleyerek ortaya koymak olacak."Too Big to Fail"
İçinde bulunduğumuz ve küresel salgın nedeniyle daha da büyüyen krizin başladığı 2008-2009 yıllarından anımsayacaksınız bu sloganı: sistemin ayakta kalabilmesi için figüranlar feda edilebilir ama oyunun baş aktörleri asla! Çünkü, baş aktörün ortadan kalkması filmin bitmesi demektir. Bu yazılım dünyası için de geçerli bir kural. Kullanımı kritik kütleye ulaşan paradigmalar, teknolojiler, araçlar, vb. uzun süre taşınması gereken yükümlülükler oluşturur. Yazılım dünyası bu konuda pek çok örnekle dolu. Bunlardan en somut olanı mini bilgisayarların ortaya çıkmasıyla benimsenen ve kişisel bilgisayarların yaygınlaşmasıyla bileşenler arası etkileşimi tanımlayan istemci-sunucu paradigmasının merkezi ana bilgisayarları gereksiz duruma getireceği iddiasıdır. Dünya üzerinde gerçekleştirilen trilyonlarca dolarlık bankacılık hareketlerinin, finans, sigorta, uçak rezervasyonu, vb işlemlerin 70 yıla yakın bir süredir ana bilgisayarlar kullanılarak gerçekleştirildiği düşünüldüğünde, bunun aslında pek de gerçekçi olmadığı anlaşılacaktır.1 Şu doğrudur: katı hal teknolojilerinin ilerlemesi sonrasında büyüyen transistör bütçeleri sayesinde, mini bilgisayarların sayısı ana bilgisayarları kat kat aşmıştır. Ne var ki, aynı eğilim, kişisel bilgisayarlar ve mini bilgisayarlar için de söz konusu olmuştur ve cep telefonları-tabletler ile kişisel bilgisayarlar için de olmaktadır.2 Ama şu gerçek değişmemektedir: İster onlarca yıldır hayatımızda olan ATM'leri kullanarak olsun, isterse işyerimizdeki masaüstü bilgisayardaki tarayıcıyı kullanarak olsun, isterse de cep telefonu-tablete indirdiğimiz uygulamayla olsun; bastığımız tuş bizi arkalarda bir yerlerde gezegenimizdeki aygıtlar arasında çok çok ufak bir azınlığı oluşturan ana bilgisayarlardan birine götürmektedir. Milyarlarca aygıtın sağlıklı işlemesinde böylesine büyük bir öneme sahip aktörün kadro dışı bırakılması, sadece aktörün değil tüm filmin bitmesi anlamına gelecektir.3 Dolayısıyla, Java dili kendi haline bırakılıp ölmeye terk edilmiş olsaydı bile-- ki, böyle bir şey kesinlikle söz konusu değil-- 'merhumun' cenazesini kaldırmak epey uzun ve zahmetli bir olay olurdu.Tarihi Arkaplan: Başlangıçtaki Temel Kaygılar
Java'nın öncüsü olan Oak dili, 1991 yılında Sun şirketi araştırmacıları tarafından uzaktan kumanda aygıtlarında çalışacak yazılımların geliştirilmesi için gerçekleştirilmiştir. Aynı kodun farklı donanımlarda çalışabilmesini olanaklı kılmak amacıyla daha sonra Bytecode adı verilen bir ara dile derlenmesini takiben sanal bir makinede (İng., virtual machine) yorumlanarak çalıştırılan Oak programları, nesne yönelimlilik kavramları kullanılarak geliştirilmekteydi. Böylece; hem yazılım geliştirmenin farklı aşamalarında hem de son ürün olan kodun sevk edilmesi aşamasında yeniden kullanım desteklenmiş oluyordu. Yeniden kullanıma ek olarak, yazılım geliştirme aşamalarının (çözümleme, tasarım, gerçekleştirim ve bakım) akıcı bir şekilde tümleştirilmesi de o dönemlerde yavaş yavaş kabul görmeye başlayan nesne yönelimlilik paradigmasının seçiminde rol oynadı. Ne de olsa, problem uzayındaki varlıklar arasında gidip gelen iletileri çözüm uzayındaki nesneler arasındaki metot çağrılarına dönüştürmek, gerçekleştirim öncesindeki aşamalarla (çözümleme ve tasarım) gerçekleştirim ve bakım aşamalarını birbirine daha sıkı bağlıyordu. Tüm aşamalardaki üstkavramları içeren nesne yönelimlilik, önceki aşamalarda verilen kararların sonraki aşamalara taşınmasını kolaylaştıryordu. Ne de olsa, hem çözümleme ve tasarımdaki hem de gerçekleştirim ve bakımdaki paydaşlar Java'da doğrudan karşılıkları bulunan kavramlardan oluşan aynı dili konuşuyorlardı. C++ etkisinin bariz şekilde görüldüğü Oak (Java) dili, bir noktada bu dilden ayrılır: Programcı insandır ve hata yapabilir; programlama dilinin temel görevlerinden birisi, programcının hata yapabileceği durumların sayısını azaltmak olmalıdır. Çoğu zaman programın çalışma hızını olumsuz etkileyen bu yaklaşım, hata sayısını azaltması nedeniyle geliştirme hızını yükseltir. Örneğin, C++'da yığın bellek yönetimi programcının payına düşerken, Java'da bu iş JSM'nin bir parçası olan çöp toplayıcı tarafından üstlenilir. Böylece, çöplerin birikmesinin ve kullanımda olmayan belleğin yanlışlıkla kullanımının önüne geçilirken, işini görmek için ne zaman harekete geçeceği öngrülemeyen çöp toplayıcının ortalığı temizlemek için harcadığı zaman programı kritik noktalarda sekteye uğratabilecektir. Düşen donanım maliyetleri ve yükselen insan maliyeti nedeniyle, yapılan bu seçim zamana uygun gözükmektedir. Buna benzer bir diğer örnek, C++'da nesneler için her üç bellek bölgesinde de (statik, çalışma anı yığıtı ve yığın bellek) yer ayrılabilirken, Java'da yer sadece yığın bellekten ayrılabilmekte ve nesne bu bölgeyi gösteren bir tutacak yoluyla kullanılabilmektedir. Ne var ki, programın bakımını kolaylaştıran bu seçim, grafik işleme biriminin kullanıldığı hesaplama yoğunluklu programlarda zaman ve bellek açısından performans kaybına neden olmaktadır. Yakın zamana kadar zararsız gözüken bu olumsuzluk, makine öğrenme algoritmalarının daha yaygın kullanılmaya başlanması nedeniyle Java'nın konumunu olumsuz etkileyecektir. Dolayısıyla, bunu düzeltmeye dönük değişikliklerin programlama diline eklenmesine dair çalışmalar yapılmaktadır.Tarihin Cilvesi: İnternet
Adı 1994 yılında Java olarak değiştirilen Oak programlama dili, 1996'da Sun şirketi dışındakilere standart bir kitaplık ve derleyici, yorumlayıcı gibi araçlar ile birlikte açıldı. O günün koşullarıyla çok güzel örtüşen bu hamle, Sun için pek de fazla bir maliyet oluşturmuyordu. Ne de olsa, Sun sonuçta bir donanım şirketiydi ve sunucu sistemleri pazarında saygın bir yere sahip olmakla birlikte Intel'e göre çok küçük bir paya sahipti; belki de Java bu pazarı genişletmek için bir fırsat olabilirdi. Dolayısıyla, İnternet dünyasının ilk depremi olan Microsoft-Netscape tarayıcı savaşının toz bulutları arasında Sun geri durmadı ve sanal makine üzerinde yorumlama özelliğini kullanarak Java'yı tarayıcı sayfalarına değişken içerik sağlamakta kullanılan uygulamacıklarla (İng., applet) birlikte İnternet'in programlama dili olarak lanse etti.4 Uygulamacıklara ek olarak JDK'deki ağ desteği ve Java bileşenleri arasında uzak metot çağrı standardını tanımlayan RMI-- nesne yönelimli RPC olarak okuyabilirsiniz-- ile bu iddia daha da pekiştirildi. Java programları sunucudan tarayıcıya indirilebildiği gibi diğer Java programlarını da çağırabiliyorlardı. Wintel'in İnternet'e çözüm olarak sunduğu Windows dünyasının COM-temelli OLE bileşenlerinin İnternet uyarlamaları olan ActiveX bileşenlerine göre bu çözüm, donanımdan bağımsız bir şekilde çalıştığı için büyük bir avantaja sahipti. Artık programlarınızı Wintel platformunda geliştirip aynı platforma sevketmek zorunda değildiniz. Programlarınız yazılımda gerçekleştirilen JSM'nin bulunduğu tüm platformlarda çalışabiliyordu. Microsoft ileri sürülen bu avantajı yorumlamanın getirdiği yavaşlamayı bahane ederek bir süre kabul etmedi. Halbuki, söz konusu yavaşlama ağ üzerinden kullanılan kodların ağdan kaynaklanan bekleme süresi nedeniyle önemsizleşiyor, kullanıcı tarafından fark edilebilir bir gecikme oluşturmuyordu. Nitekim, Microsoft bu olguyu daha sonraki yıllarda gerçekleştirdiği C# dilinin merkezinde yer aldığı .NET ortamıyla kabul ettiğini gösterdi. Ayrıca, Sun da boş durmadı ve yorumlamanın getirdiği yavaşlamayı adaptif anında derleme (İng., just-in-time compilation) teknikleriyle en aza indirdi.Sunucu Programlarının Dili Olarak Java: İzlekler, Açımlamalar ve Kurumsal Java Çerçeveleri
Java'nın uygulamacıklar yoluyla tarayıcıya yapılan eklentilere göre geleceği açısından çok daha belirleyici olan bir yönü, sunucu programlarının gerçekleştirilmesinde sağladığı avantajlardı. Evet, tarayıcı sayfalarında göbek atan animasyonlar seyirci topluyordu ama asıl iş İnternet'in mutfağında yani sunucu tarafında idi. Bu noktada ilk çarpışma sunucu tarafındaki Perl betiklerinin tarayıcı sayfalarından çağrılmasına yarayan CGI protokolüne karşı verildi. Sun'ın donanım şirketi olması bu konuda belirleyici bir avantaj sağladı. Geliştirdiği SPARC mimarisinin yanısıra UNIX-temelli Solaris işletim dizgesinin de gerçekleştiricisi olan Sun, hali hazırda aynı makinedeki uygulamaların yalıtım birimi olarak kullanılan süreçlerin (İng., process) yer ve zaman maliyetlerini düşürmekte başarılı işler yapmıştı. Evet, birbirlerine düşmanca davranma olasılığı bulunan programlar söz konusu olduğunda süreç kavramı gerekli yalıtımı sağlıyordu. Ne de olsa, hiç kimse yanlış ya da kötü niyetle yazılmış bir programın çalışmakta olan diğer programları etkilemesini istemezdi. Ama ya ortaklaşa bir iş yapmaya dönük çalışan denetim akışları söz konusu ise? Ya da birbirlerine çelme takmayacağı bilinen denetim akışları olduğu garanti edilebiliyorsa? Bu durumda, güvenlik amacıyla istenen yalıtımın maliyeti, çalıştırılan programlara karşılık yaratılan süreçlerin başlama zamanlarına ve bellekte kapladığı alana olumsuz anlamda etki etmeye başlıyordu. Solaris'de bu durumları hafif-siklet süreç (İng., light-weight process) kavramıyla karşılayan Sun, bu birikimini Java programlama diline izlek (İng., thread) kavramıyla taşıdı. İzleklerin desteklenmesi sayesinde, tarayıcıdan gönderilen her istemde yeni bir süreç yaratmak zorunda kalan CGI betiklerinin aksine, sunucu tarafındaki Java programları aynı süreç içinde yeni izlekler yaratarak işi daha ucuza halledebiliyordu. Böylece, sunucu tarafındaki ilk çarpışma kazanılmıştı. Sunucu programları yazıldıkça ortaya çıkan bir durum, Java programlama dilinin kalıcılığını sağlayan bir diğer sonucu doğurdu. Sunucu programları, yaptıkları iş farklı olsa da, temelde bazı şeyleri aynı şekilde yapıyorlardı. Mesela, ister öğrenci notlarının işlenmesini sağlayan bir yazılım olsun, isterse çevrimiçi alışveriş yapmanızı sağlayan bir kitap sitesi olsun aşağıdakilerle sınırlı olmayan pek çok şey ortaktı:- tarayıcıdan ya da istemci programdan parametrelerin paketlenerek gönderilmesi,
- isteme dair yetki denetimlerinin yapılması,
- istemin diğer kullanıcıların istemleriyle birlikte çalışmasını sağlayan izleklerin yönetilmesi,
- sunucunun sağladığı geri bildirimi içeren paketin açılması,
- ...
Ufukta Görünen Yeni Paradigmalar
Ne kadar iyi geliştirilmiş olursa olsun, her program eninde sonunda elden geçirilecektir. Bu, çözümleme ve tasarım aşamalarının zorluğu nedeniyle, programın yaratılmaktan ziyade üstünden geçe geçe belirmesi şeklinde kendini gösterir. Program, en baştan satır satır yazılmaktansa, yazılan kısımların çözümleme ve tasarım aşamalarından gelen geri bildirimlerin değişmesi ile yeniden yapılandırılarak (İng., refactoring) tekrar tekrar yazılır. Bu noktada nesne yönelimliliğin sağladığı üstkavram dağarcığı yetersiz kalacaktır. Her şeyin nesne olarak görülmesi, davranışın ve denetim akışının yeniden yapılandırılmasının gerektiği pek çok durumda anlaşılması zor ve uzun kodlara neden olur. Çözüm, bu amaçla çok daha yalın bir kavram olan matematiksel fonksiyonları programlama dünyasına taşıyan fonksiyonel programlamadan (İng., functional programming) gelir. Bir diğer yaklaşım da, buluta sevkedilen yazılımların gerçekleştirilmesinde sınıf dosyası temelli bileşen gerçekleştirilmesi yönteminin sebep olduğu maliyetleri ortadan kaldırmak amacıyla birimsel programlamaya (İng., modular programming) başvurmayı gerektirir. Yazı dizimizin önümüzdeki bölümlerinde yapacağımız şey, rasgele değişiklikler gibi gözüken yenilikleri yeni programlama paradigmaları bağlamında ele almak ve bütünsel bir çerçeveye oturmak olacak. Görüşmek üzere!
1 CICS işlemlerinin sayısı Google aramalarının 17 katı kadardır.↩
2 Şeylerin İnterneti düşünüldüğünde, bu eğilimin bir adım daha öteye taşınabileceği görülecektir.↩
3 Ana bilgisayarların bulut temelli sistemler ile değiştirilebileceğini düşünebilirsiniz. Ne var ki, onlarca yıldır desteklenen kodun değişmesi söylendiği kadar kolay olmayacaktır. Ayrıca, oturmuş prosedürler, çevre aygıtların kanıtlanmış üstün performansları ve güvenlik desteğinin yıllar içinde yazılımdan donanıma aktarılmış olması da bu işi neredeyse uygulanmaz kılmaktadır.↩
4 Bu kavram zaman içinde, tarayıcı gerçekleştirimcilerinin JavaScript/HTML'de var olan özellikleri kullanarak işi halletmek yönünde yol alması nedeniyle, Adobe Flash gibi tarihin karanlığına gömüldü ve hem taraycılardan hem de Java standardından çıkarıldı.↩
Yorumlar
Yorum Gönder