Nesne Yönelimli Programlama (OOP) Öldü mü?

2021 Sep 04

1960’lar da programlama büyük bir problem ile boğuşmaktaydı. Bilgisayarlar henüz yeteri kadar güçlü değildi ve güçlü olmayan bu bilgisayarlar bir şekilde kaynaklarını data structure ile prosedürler arasında bölmeliydi.

Bu şu anlama gelmekteydi; eğer büyük bir dataset e sahip idiyseniz, bilgisayarların limitlerini zorlamadan çok fazla iş yapamazdınız. Diğer taraftan, eğer çok fazla iş yapmak zorundaysanız bu defa büyük datalar kullanamaz ya da bilgisayarlar bu dataları uzun süreli işleyemezlerdi.

Bu süreç sonrasında Alan Kay 1966-1967 yıllarında çıkageldi kapsüllenmiş mini bilgisayarların veriyi paylaşmadan ancak daha çok mesajlaşma yoluyla iletişim kurarak kullanımını teorize etti. Bu yol ile bilgisayar kaynakları daha ekonomik kullanılabildi.

Fikrin yaratıcılığına karşın bu durum 1981 yılına nesne yönelimli programlamanın (OOP – Object Oriented Programming) ana akımı vuruşuna kadar devam etti. O zamana kadar yeni ve tecrübeli yazılım geliştiricileri kendine çekmeyi bırakmadı. Pazar OOP geliştiricileri için hiç olmadığı kadar meşguldü.

Ama son zamanlarda on yılların paradigması çok daha fazla eleştiri aldı. OOP’un kitlelere ulaşmasından 40 yıl sonra teknoloji bu paradigmayı aşabilir mi?

Data İçin Fonksiyonlarla Uğraşmak Aptalca mı?

OOP’un arkasındaki ana fikir olabildiği kadar basittir: Programı güçlü küçük parçalara bölmeye çalışırsınız, takiben veri parçalarını ve yalnızca söz konusu veriler üzerinde kullanılan işlevleri birleştirirsiniz.

Bu yalnızca kapsülleme kavramıdır ve veri ile fonksiyonlar dışarıya görünmez şekilde bir objenin içinde bulunurlar. Bir şey yalnızca mesajlar vasıtasıyla obje içeriğiyle etkileşebilir ki bu tipik olarak getter ve setter fonksiyonlar aracılığı ile gerçekleştirilir.

İlk fikirde yer almayan, ancak bugün OOP’un önemli yanlarından biri kalıtım ve çok biçimliliktir. Kalıtım basitçe yazılım geliştiricilerin alt sınıflar tanımlayarak, bu alt sınıfların tüm özelliklerini üst sınıftan alması şeklinde tanımlanabilir. Kalıtım özelliği OOP’un konseptleştirilmesinin ardından 10 yıl sonrasına kadar tanıtılmamıştı.

Çok biçimlilik de başka bir on yıl sonrasında OOP bünyesine dahil oldu. Basit terminoloji ile; çok biçimlilik, bir metodun ya da objenin diğerleri için bir şablon olarak sunulabilmesi anlamına gelir. Bir anlamda kalıtımın genelleştirilmesidir. Çünkü yeni varlığa (objeye) orijinal metodun bütün özelliklerinin aktarımına gerek yoktur. Bunun yerine geçersiz kılınacak (override) özellikler seçilebilir.

Çok biçimlilik hakkında özel olan, kaynak kodda iki varlık birbirine bağımlı olsa bile çağrılan varlığın daha çok eklenti gibi çalışmasıdır. Bu yazılım geliştiricilerin hayatını kolaylaştırır çünkü çalışma zamanı boyunca bağımlılıkların (dependencies) üzerine endişenilmesine gerek kalmaz.

Burada bahsetmeye değer bir diğer konu ise çok biçimlilik ve kalıtımın OOP’a özel olmadığıdır. Asıl özel olan fark veri parçalarının ve onlara bağlı işlevlerin kapsüllenmesidir. Bilgisayar kaynaklarının kıt olduğu dönemlerde bu harika bir fikirdi.

OOP’ta 5 Büyük Problem

OOP kitlelere ulaşır ulaşmaz, yazılım geliştiricilerin kaynak kodlarını daha iyi görüp okuyabilmeleri için bir yola dönüşmüştür. 1980’den önce prosedürel programlamayı galip getiren, prosedürel programlamanın çokça makine yönelimli olmasıydı. Yazılım geliştiriciler biraz da olsa iyi kod yazabilmek için bilgisayarın nasıl çalıştığını bilmek zordundaydılar.

Veri ve metodların kapsüllenmesiyle OOP yazılım geliştiriciliğini daha insan merkezli bir hale getirdi. Bu durum sür() fonksiyonunun ayıcık() sınıfına değil de araba() sınıfına ait olması çerçevesinde insani bir sezgisel uyumluluk olarak açıklanabilir.

Ortaya çıktığı zaman kalıtım da bu duruma çok uygundu. Hyundai() sınıfının araba() sınıfının bir alt sınıfı olduğu ancak kutupayisi() sınıfına ait olmadığı sezgisel olarak harika biçimde açıklanabiliyordu.

Bu güçlü bir mekanik olarak görünmektedir. Ancak problem, yalnızca OOP geliştirmeyi bilen yazılım geliştiricilerin yaptıkları her şeyde bu şekilde düşünmeye zorlanmalarıdır. Bu durum; insanların sahip oldukları tek şey çekiçken diğer her şeyi çivi olarak görmelerine benzer. Eğer çantanızda sadece çekiç varsa bu durum ağır problemlere de sebebiyet verebilir.

Muz-Goril-Orman Problemi

Yeni bir program yazmayı düşündüğünüzü hayal edin ve yeni bir sınıf üzerine düşündüğünüzü. Öncelikle başka bir proje için hazırladığınız yapmak istediğiniz iş için harika çalışabilecek temiz ve küçük sınıfa dönmeyi düşünebilirsiniz.

Problem yok! Yeni projenizde eski projede yarattığınız sınıfı hemen kullanabilirsiniz.

Gerçeğin aksine; bu sınıf belki de başka bir sınıfın alt sınıfıdır ve siz bu yüzden üst sınıfı da projeye dahil etmek zorundasınızdır. O zaman fark edersiniz ki üst sınıfta başka bir sınıfa bağımlı olabilir ve siz sonunda yığınlarca kodu dahil etmek zorundasınızdır.

Erlang dilinin yaratıcısı JOE Armstrong bu durumu şöyle ifade eder:

“OOP ile problem tüm bu dillerin örtük olarak kendi çevrelerini anlarında taşımalarıdır. Siz bir muz istersiniz ancak elinizde elinde muz tutan bir goril ve tüm orman vardır.”



Bu alıntı birçok şeyi hoşça ifade eder. Sınıfları tekrar kullanabilmek güzeldir hatta OOP’un en büyük erdemi bile olabilir. Ama aşırıya kaçılmamalıdır. Bazen temizlik için büyük bağımlılıkları projeye dahil etmek yerine yeni bir sınıf yazmak daha iyi olabilir.

Kırılgan Base Class Problemi

Başka bir projede bulunan bir sınıfı yeni kodunuzda başarılı bir şekilde kullandığınızı hayal edin. Base class (En üstteki sınıf) değişirse ne olacak?

Bütün kod yapısı bozulabilir. Belki de hiç dokunmamışsınızdır ama kodunuz bir gün sihirli bir el değmiş gibi çalışırken ertesi gün çalışmaz çünkü birisi base class içerisinde projeniz için çok büyük önem arz eden küçük bir değişiklik yapmıştır.

Daha fazla kalıtım kullanımı daha fazla bakım potansiyeli meydana getirir. Bu nedenle kısa vade de kodların tekrar kullanımı çok verimli görünürken, uzun vade de maliyetli olabilmektedir.

Elmas Problemi

Kalıtım bir sınıfın özelliklerini alıp başkalarına transfer edebileceğiniz küçük ve tatlı bir şeydir. Ancak ya iki farklı sınıfın özelliklerini karıştırmak isterseniz?

Evet, yapamazsınız. En azından zarif bir yolu yoktur. Örnek olarak kopyalayıcı() sınıfını düşünün. kopyalayıcı() bir dökümanın içeriğini tarar ve boş bir sayfaya yazdırır. Tarayıcı() sınıfından mı yoksa yazıcı() sınıfından mı kalıtım almalıdır?

Basitçe iyi bir cevap yoktur. Buna rağmen bu problem kodunuzu bozmaz, ancak sinir bozucu olmak için yeterince sık ortaya çıkar.

Hiyerarşi Problemi

Elmas probleminde soru hangi sınıfın kopyalayıcı() sınıfının üst sınıfı olacağıydı. Ama çözüme dair yalan söyledim ve bir yol var. kopyalayıcı() ana sınıf olduğu taktirde, tarayıcı() ve yazıcı() sınıfları alt sınıf olarak kopyalayıcı()’dan kalıtım alabilir. Böylelikle problem çözülür!

Bu temiz bir yoldur. Ama ya eğer kopyalayıcı() sadece siyah-beyaz ise ve printer() renkli baskı da yapabilecekse? Ya eğer yazıcı() wifi çalışabilecek şekilde olmalıysa ama kopyalayıcı() değilse?

Daha fazla özelliğin bir sınıfa yerleşimi, daha doğru bir hiyerarşinin yerleşimini zorlaştırır. Gerçekten de bir sınıfın sunduğu ve başka bir sınıfın sunamadığı kümelerce özellik ile uğraşmak zorunda kalınabilir ve eğer bu hiyerarşi içerisinde takılıp kalınırsa bu durum işleri ağır bir felakete sürükleyebilir.

Referans Problemi

Belki şu şekilde bir beyanatta bulunabiliriz; tamam o zaman, hiyerarşiler olmaksızın OOP uygulanabilir. Kümelerce özellikle, kalıtımla, çok biçimlilik ile geçersiz kılmalarla uğraşmak yerine yalnızca ihtiyaç kadar kullanılabilir. Doğal olarak bu biraz dağınık olurdu, ama elimizdeki probleminde doğru bir temsili olurdu.

Yalnız bir sorun var. Kapsülleme tüm yapısı ile veri parçalarını birbirlerine karşı güvende tutar. Böylece hesaplamalar daha verimli hale gelir. Sıkı bir hiyerarşi yoksa eğer bu durum çalışmayacaktır.

Düşünün eğer bir A objesi B objesi ile etkileşimi sonucu aldığı hiyerarşiyi geçersiz kılarsa (override). A objesinin B objesi ile ilişkisi B objesinin direk üst sınıf olması dışında önemsizdir. O halde A objesi B objesi için private bir referans taşımalıdır çünkü diğer türlü etkileşmeyi başaramaz.

Ama eğer A objesi alt sınıf olarak B objesinin tüm bilgisini içeriyorsa ve sahipse bu durumda bir çok yerden düzenlenip değiştirilebilir. O halde de B objesi üzerindeki bilgi artık güvende değildir ve kapsülleme bozulmuştur.

Buna rağmen bir çok OOP geliştiricisi buna benzer mimarileri kullanarak yazılımlar hazırlıyor. Bu OOP değildir, bu sadece işi batırmaktır.

Tek Paradigma Tehlikesi

Bu beş sorununda ortak noktası en iyi çözüm olmadığı halde kalıtımı kullanmasıdır. Kalıtım OOP’un orijinal yapısına dahil edilmemiş olsaydı, bu problemleri nesne yönelimli kalıtımın problemleri olarak isimlendiremeyecektik. Bunlar sadece çok ileri götürülen bir dogmanın örnekleridir.

Yine de sadece OOB abartılı olmayabilir. Saf fonksiyonel programlamada kullanıcı girişlerinin işlenmesi veya mesajların ekrana yansıtımı ağır zorluklar barındırır. OOP veya prosedürel programlama bu amaçlar için çok daha iyidir.

Yine de kimsenin anlayamayacağı binlerce satır kodu saf fonksiyonlar ile bahsedilen şeyleri entegre etmeye çalışan yazılım geliştiriciler vardır. Başka bir paradigmanın kullanımı, tüm kodu kolaylıkla birkaç okunabilir satıra düşürebilir.

Paradigmalar biraz dinler gibidir. İsa, Muhammed ve Buda güzel bir sürü şey söylemişlerdir. Ama onları en ince ayrıntısına kadar takip ederseniz, kendinizi ve çevrenizdekilerin hayatını oldukça perişan hale getirebilirsiniz.

Aynısı yazılım paradigmaları için de geçerlidir. Şüphe yok ki fonksiyonel programlamaya ilgi artarken OOP son birkaç yılda sert eleştiriler almış durumda. Bu durum yeni yazılım paradigmaları hakkında bilgi edinmeyi ve uygun olduklarında kullanmayı mantıklı hale getiriyor. Eğer OOP bir çekiçse ve yazılım geliştiricilerin her şeyi birer çivi olarak görmesini sağlıyorsa bu çekici pencereden atmak için bir sebep değil midir? Hayır. Bir tornavida ve bir bıçak ya da bir makası belki araç kutunuza ekleyebilirsiniz ve karşılaştığınız problemlere göre uygun araçları seçebilirsiniz.

Fonksiyonel ve OOP yazılım geliştiriciler de kendi paradigmalarına bir dinmiş gibi muamele etmeyi durdurmalılar. Onlar birer araçtır ve bir yerler de kullanılırlar. Ne kullanacağınız yalnızca çözmeye çalıştığınız elinizdeki probleme bağlıdır.




Büyük Soru: Yeni Bir Devrimin Eşiğinde miyiz?

Günün sonunda kuşkusuz oldukça ısıtılmış olan fonksiyonel programlama ve OOP arasındaki çekişme şuna indirgeniyor: OOP çağının sonuna varmış olabilir miyiz?

Fonksiyonel programlamanın çözüm olarak görüldüğü yerlerde daha fazla sorunlar ortaya çıkıyor. Veri analizi, makine öğrenmesi ve paralel programlamayı düşünün. Bu alanlara daha fazla girildiğinde fonksiyonel programlama daha çok seviliyor.



Ama statükoya bakıldığında fonksiyonel kodlayıcılar için tek tük önerilere karşın OOP geliştiricilerine yönelik binlerce öneri var. Fonksiyonel programlamayı tercih ederseniz iş bulamayacağınız anlamına gelmemesine rağmen, fonksiyonel geliştiriciler hala bu anlamda korkutucu günler yaşıyorlar.

Genel senaryo OOP yaklaşımının başka bir on yıl daha ortalarda olacağı yönünde. Elbette avangard olan fonksiyonel programlamadır ancak bu OOP’tan vazgeçilmesi anlamına gelmez. OOP hala inanılmaz biçimde repertuarınızda olabilmesi için iyi bir paradigmadır.

Dolayısı ile OOP’u çantanızdan önümüzdeki birkaç yıl için çıkarmayın. Ama emin olun sahip olduğunuz tek araç o değil.

Kaynak: https://towardsdatascience.com/why-developers-are-falling-in-love-with-functional-programming-13514df4048e