Cumartesi, Eylül 23, 2006

Nesneye Yönelik (Object Oriented) Yazılıma Geçiş

Nesneye yönelik yazılım ile ilk karşılaştığım zaman, çoğu kişinin tepkisine benzer olarak, ilginç gelmişti ancak bunun nasıl işime yerayacağı veya beni nasıl hızlandıracağı hakkında bilgi sahibi olamamıştım.

Ortada bir takım nesnelerin olması, iletişimi bunların kurması ve bu nesnelerin gerçek dünya benzeri davranışlar sergileyebilmeleri gerçekten ilginçti, ama vadedilen şeyler çok fazlaydı, bunlarda nesnelerin nasıl yardımcı olacağını veya nasıl başaracağını anlayamıyordum, sadece class tanımlayarak nasıl üstesinden gelinebilecekti ?

Üstelik, bu vaatlerin çoğunu ben zaten prosedürel programlama kullanarak, fonksiyonlar ile yaptığımı düşünüyordum, yeterince iyi tasarlanmış bir altyapıda nesneler beni prosedürel kodda yazdığımın nasıl daha ilerisine götürebilecekti ?

Bununla ilgili birkaç deneme yaptım, denemelerimin sonucunda ilginç kodlar ortaya çıkmıştı ancak bu kod mucize bir kod değildi, bunları prosedürel de yapabilirdim. Üstelik, veritabanı mimarisine alıştıktan sonra, bunların nesnelere uyarlanması sonucunda ortaya çıkabilecek yapılar etkili ve kullanışlı da gözükmüyordu.

Tekrar kullanılabilirlik, kolay değişiklik yapma, yazılım hızı, kolay değişiklik gibi vaatlerin karşılığını prosedürel yazılım kadar dahi alamıyordum ki.

Daha sonra nesneye yönelik yazılım ile ilgili bildiğim ufak tefek şeyleri bir rafa kaldırdım ve veritabanı üzerinden prosedürel gitmeye devam ettim.

Ancak, sürekli olarak beni rahatsız eden birşey vardı. Bunlardan birincisi, her yazdığım yazılım sonrasında, bu yazılıma bir takım özellikler ekledikçe, yazılımın şişip kontrolden çıktığını farkettim. Ne kadar çok özellik isteği gelir ve ben kod üzerinde ne kadar çok çalışırsam, o kadar yeni değişiklik veya ekleme süresi artıyor, bir yerlere müdahele ettikçe o kadar çok yer bozulmaya başlıyor, değişiklik yaparken sürekli aynı yerlerdeki aynı bugları temizlemekten kendi kuyruğumu takip ediyor gibi hissediyordum.

Ayrıca, veritabanı mimarisini çıkarıp sonradan kodlamaya geçtiğim zamanlarda tüm hissettiğim şey aynı şeyi tekrar tekrar yaptığımdı. Bazı kodlar birleştilip bir dizi fonksiyon ile beraber çalıştırılabiliyordu, ancak çoğu şeyi tekrar tekrar ufak değişikliklerle yazmak zorunda kalıyordum. Üstelik, her yaptığım yazılım, bir önceki yaptığım yazılımdaki bazı kısımlara çok benziyor, nadir olarak copy paste ile oradan bir takım kodları alıyor ancak çoğunlukla daha önce yapıtğım işi çok beğenmediğim için tekrar baştan yazıyordum.

Bunu yapmanın daha kolay bir yöntemi vardı ancak neydi ?

Tekrar kullanılabilirlik çok önemliydi. Her uygulamanın sabit ihtiyaç duyduğu şeyleri tekrar kullanılabilir yapmalıydım. Ancak ne yaparsam yapayım, bir sonraki uygulamada birtakım ekstra özelliklere ihtiyacım oluyor ve daha önce yazdığım kodu anlayıp içerisinden çıkamıyordum.

Bunun üzerinde düşünürken, bir projede, aklıma bu kodların dinamik olarak üretilebileceği geldi. Aslında, çoğu uygulama select insert update delete içeren şeylerdi, bunların veritabanı ilişkileri ve ekranlarını üretebilirsem, bu yapıyı standart bir hale getirebilirsem, hem tekrar kullanılabilirlik benim kod üretme sistemim tarafından sağlanmış olacak, hemde ufak değişiklikler yüzünden duplicate kod tutmamış olacaktım.

Bir süre üzerinde çalıştıktan sonra veritabanına bazı satırların girilmesi sonrasında ekranından sql kodlarına kadar kodu üretecek bir yapı kurmayı başardım. Bu yapı, veritabanından belirli bir tabloyu okuyor, o tablodaki alanlara göre yeni tablolar oluşturuyor, sql cümleleri ve ekranlar oluşturuyor, daha sonra bunları sistemin kullanacağı dosyalar içerisine yazıyordu. Değişiklik tekrar compile gerektiriyordu ancak gene de işler çok hızlı yürüyordu. Daha sonra runtimeda bu yeni kısımları implement edecek bir sistem geliştirdim ve dha da memnun kaldım.

Ancak sorunum hala çözülmemişti, sistemin belirli kısımları için bunları uygulayabilsem de açıkta kalan birçok nokta oluyordu. Bu sistem tarafından üretilemeyen kısımları gene her proje için ayrı ayrı yazmak zorunda kalıyor, saatlerce debug ile uğraşıyordum.

Daha da araştırdım ve nesneye yönelik programlama gene karşıma çıktı. Daha önce başarısız bir denemem olmuştu ancak bazı noktaların bende eksik olduğunu farketmiştim, acaba şimdi bir cevap alabilecekmiydim ? Başka şeyler aradım ancak sürekli olarak nesneye yönelik yazılım karşıma çıkıyordu.

İlk anladığım şey, benim nesneye yönelik yazılım yanlış ve eksik anladığımdı. Ciddi yapıları araştırdığım zaman, anlayamadığım nesneye yönelik kodlar ve girift ilişkiler vardı ki bunlara neden ihtyiaç duyulduğu veya niye yapıldığı hakkında en ufak bir fikrim yoktu. Kodları anlamaya çalışıp biraz daha araştırma yapınca, tasarım kalıpları (design patterns) ile karşılaştım, vaat ettikleri çok ilginçti, ancak anlayamıyordum, uml diyagramları biraz kafamı karıştırıyordu ve kod örneklerini kısmen anlasam da bana çok yabancı idi. Daha sonra karşıma mda (model driven architecture) çıktı. Bunları anlamam için uml bilmem gerekiyordu.

Umli araştırıp öğrendikten sonra, okuduğum şeyler beni heyecanlandırmaya başlamıştı. Değişik yerlerdeki makalelere giriyor ve çok akıllıca tasarlanmış nesneye yönelik yapılarla karşılaşıyordum. Ciddi yapıların hiçbirisinden uml eksik değildi ve onu öğrenmem sonrasında bir mana ifade etmeye başlamıştı.

Objelerin sakladığı sırların bazılarını öğrendim.

1. Nesne tabanlı yazılım anlattığını iddia eden çoğu kitap laf kalabalığı ve syntax bilgisi veriyor idi, özellikle dil öğreten kitaplar (C#,C++,Java vb.)

Bu tür kitaplar dilin öğrenilmesinde faydalı olabilir, ancak nesneye yönelik tasarım bilgisi aslında dilden bağımsız birşeydir, bir kere öğrenildiği zaman tüm nesneye yönelik dillerde kullanılabilir, ve bu bilgi dil bağımlı kaynaklarda çok zor bulunur.
1.a Uygulamanın türü önemli değildi, Web Application ile Client application veya Embedded bir nesneler kullanıldığında hep aynı şeydi

Tabii ki yazılımcı kendi alanını bilmeli ve Web bilmeyen birisinin web application yazarken çektii sıkıntıları göz ardı etmemelidir, ancak, asıl işi nesneler yapacak ise, bunlar uygulamanın nerede çalıştığı ile ilgilenmeyecek kısımların çoğunlukta olduğu bir gruptur. Yani asıl mimari kurulurken nerede çalışacağından soyutlayıp ne yapması gerektiğine odaklanırsak, hem eldeki problem daha kolay çözülüyor, hemde kod tekrar kullanılabilir oluyordu. Ayrıca, görev bölümü de çok kolay ortaya çıkıyordu, bir kişi sadece işi yapacak objeleri tasarlar ve yazarken diğer bir kişi bunlara ihtiyaç duymadan önyüzleri hazırlayabiliyordu.

1.b Microsoft Kaynaklarından bu bilgilere ulaşmak çok zordu, stratejileri hızlı kod yazan ucuz işgücü oluşturmaya yönelikti

Microsoft ile ilgili kaynakları araştırdığım müddetçe bu tür bir bilgiye ulaşmak çok eziyetli oluyor, bu bilgi belki de kasıtlı olarak saklanıyordu, dotnet frameworkün asıl yapısını anlamak için bulunan kaynaklar çok sınırlı idi.
2. Nesnelerle düşünmek için özgür olunmalıydı, veritabanına bağımlı bir yapı özgür olamazdı

Daha önce yaptığım gibi veritabanından hareket ettiğim durumlarda, mimariyi veritabanına göre tasarladığım durumlarda, hem veritabanındaki değişikliklere korkunç savunmasız kalıyordum hemde objeleri istediğim gibi kullanmaıyor ve tablolara kolonlara bağımlı bir kod yazmak zorunda oluyordum. Ancak anladığım bir şey var ki, benim için en değerli bilgilerden birisi, objelerle çalışınca, veritabanı, objelerin saklanılmasını istediğim kısmı saklamak için kullanılacaktı. Yani veritabanının sistemi yönetmek veya en değerli parçası olmak işlevi yoktu, sadece bir takım bilgileri bir yerde tutup bilgisayar kapandığında kaybolmamasını sağlayacak, tekrar istediğimde geri alabileceğim bir yapı için geçerli idi. O zaman nesneleri veritabanı ile sınırlandırmak, aslında bir uygulamanın o uygulama içerisindeki loglama sistemine bağlı olması kadar saçmaydı. Nesneleri istediğim gibi yazabilmeliydim, işi yapacak olan onlardı, veritabanı değil, sadece yapılan işin sonucunda ortaya çıkan şeyi kaydetmem gerekiyordu. (Tabii burada yapılan işten kasıt sistemin belirli kısımlarının ayrı ayrı yaptığı işlerdir, yoksa bütün nesneler her işini bitirir, uygulamanın çalışması biter sonra veritabanı erişimi sağlanıp objeler veritabanına yazılır gibi bir iddiam olamaz, özellikle web uygulamaları için.)
3. Yazılımın mimarisi aslında nesnelerin mimarisinden yola çıkılarak yapılmalı idi.

(2) de belirttiğim gibi, yazılım veritabanı mimarisinden bağımsız olmalıydı. Ayrıca, gösterimden de bağımsız olmalı idi. Ancak o zaman nesneler yazılımın belkemiği olabilir ve ancak o zaman nesneye yönelik yazılımın gerçek meyvelerini alabilirdim. Bu durumda, yazılımın belkemiği nesnelerdi, yazılım tasarımı da nesnelere göre yapılmalı idi. Ancak, nesne derken, asıl işi yapacak nesnelerden bahsediyorum. Bir uygulamanın menüsüde nesne yapısında olabilir. Ama uygulamanın aslında ne iş yaptığı önemlidir. Bir elektronik pazaryeri uygulamasında mimarinin asıl üzerine dayanacağı yerler veritabanı tablosunu temsil eden nesne, menüyü temsil eden nesne, sessionu temsil eden nesne değil, satılacak ürünleri temsil eden nesneler, açıkartırmayı temsil edecek nesneler vb. olmalıydı.


4. Nesneye yönelik olduğun iddia eden çoğu yazılım aslında nesneye yönelik değildi
Özellikle Türkiye için, yazılımın içerisinde bir nesne kullanıldığı anda o yazılım nesneye yönelik kabul ediliyordu, bu saçmaydı. Genelde veritabanına bağlı mimari kullanan firmalar, daha sonra yazılımlarının veritbanı bağlantısı kısmını nesneler yaptığı için yazılımlarına nesneye yönelik yazılım adını taktıklarını farkettim.


5. Nesnelerin birbirlerini etkilemeden değiştirilebilir ve çalışabilir yapılar olmasını sağlamak için çok dikkat gerekliydi.

Hatalarımdan birisidir bu, çoğu kişinin de aynı yanlışa düştüğünü farkettim. Nesnelerin avantajları, kendilerini bir diğerinden gizleyebildiği sürece maksimuma çıkıyordu. Daha önce nesneye yönelik yazılım yaptığımda, her metodu ve özelliği public olarak tanımlayıp heryerden her türlü objenin her türlü objeye ulaşmasının işimi kolaylaştırdığını ve protected ile private yapıların aslında benim kadar zeki olmayan :) insanlar tarafından ortaya konduğunu düşünmüştüm.

Public metodlar, bir nesnenin zayıf yönleridir. Bir nesnenin ne kadar çok public elemanı var ise o nesne o kadar zayıftır, çünkü onun diğerleri ile bağlantısı o kadar kuvvetlidir. Bu da, o nesneyi değiştirdiğim anda birsürü yerin etkileneceği veya başka bir yerde kullanabilmek için o nesne üzerinden sırayla çalışan birsürü fonksiyonu o yazılımda tekrar implement etmem gerekeceği, dolayısı ile nesnenin çalışma şeklini tekrar anlayıp bilmem gerekeceği manasındaydı.

Yaşayan bir sistemin ortasından bir parça alıp onu başka bir sistemin ortasına oturtmak için o nesnenin kodlarını tekrar tekrar çözmem gerekmemeliydi.

6. Tasarım kalıpları (design patterns) çok iyi öğrenilmesi gereken bir konu idi.

Tasarım kalıpları çok faydalı bir konuydu. Bunları inceleyip hem çok ciddi öğrenmek hemde bunlara bakarak nesneye yönelik yazılım yapmayı öğrenmek gerekiyordu.




Bu yazdıklarım ışığında devam edip kanaatimce uzun bir yol katettim. Bunların farkına vardıktan sonra izlenmesi gereken yol, nesneye yönelik mimarilerin kurulması esnasında verilecek kararlar ile ilgili bilgi edinmektir. Bu yazdıklarımı farkedip bilmek ayrı, bunları uygulamaya geçirmek ayrı birer bilgi. İkincisi birincisinden önce gelemiyor tabii ki.

Geldiğim noktadan çok memnunum ve prosedürel yazılıma dönmeyi kesinlikle düşünmüyorum. Tekrar kullanılabilir kod, sistemin tümünü etkilemeden değişiklik yapabilme, veritabanı değiştirebilme, bir uygulamayı her platformda tekrar baştan yazmaya gerek kalmadan çalıştırabilme gibi özellikleri yazılımlarıma verebiliyorum.

Benim için öğrenecek çok şey var, yolun ortalarındayım sanırım, ancak yolumu bildiğim için memnunum.