Bir yazılımcı için inheritance, yani miras, kulağa neredeyse aile toplantısı gibi gelir: Bir üst sınıf vardır, çocuk sınıflar vardır, herkes bir şeyler devralır, bazıları memnundur, bazıları ise içinden sessizce refactor etmek ister. Genetikte de tablo çok farklı değildir. Göz renginden metabolizmaya, yatkınlıklardan davranış örüntülerine kadar biyolojik kodlar kuşaktan kuşağa aktarılır. Fakat mesele yalnızca aktarım değildir; asıl hikâye, devralınan şeyle ne yapıldığıdır.
OOP’de bir sınıf başka bir sınıftan türediğinde, üst sınıfın özelliklerini ve davranışlarını alır. Diyelim ki bir Canli sınıfımız var: solunum yapar, beslenir, çoğalır. Bundan Memeli sınıfı türetiriz; sonra Insan. Kodda bu pratik görünür. Aynı mantık biyolojide de vardır: Önce ortak özellikler, sonra özelleşmeler. Fakat işin dramatik kısmı burada başlar. Çünkü her çocuk sınıf, üst sınıfın her davranışını aynen taşımak zorunda değildir. Override eder. Yani der ki: Bunu senden aldım ama böyle kullanmayacağım.
Kuşak çatışması bir override problemidir
Anne babanın çocuğuna devrettiği şey yalnızca genetik değildir; alışkanlıklar, korkular, ekonomik refleksler, sevme biçimleri, susma teknikleri ve öfke protokolleri de aktarılır. OOP diliyle söylersek, aile bir base class gibi çalışır. Çocuk ise ondan türeyen ama kendi runtime koşullarında çalışan yeni bir sınıftır. Sorun, üst sınıfın kendi metodlarının evrensel olduğunu sanmasıyla çıkar. Baba sınıfı şöyle der: calis() metodu böyle yazılır. Anne sınıfı ekler: guvendeKal() metodu asla değiştirilmez. Çocuk sınıf ise çağın API’larına bakar ve cevap verir: Bu sistem artık başka bağımlılıklarla çalışıyor.
Programlamada kötü miras tasarımı, bağımlılık cehennemi üretir. Bir alt sınıf, üst sınıfın gereksiz tüm yükünü taşımaya mecbur kalırsa esneklik kaybolur. Buna kırılgan temel sınıf problemi denir. Biyolojik ve kültürel düzeyde de benzeri yaşanır. İnsan, atalarından gelen kodları taşır; ama bütün kodlar bugünün dünyasında anlamlı değildir. Bir zamanlar hayatta kalmayı sağlayan aşırı tetikte olma hali, modern ofiste anksiyeteye dönüşebilir. Bir zamanlar kabileyi koruyan içe kapalılık, bugün iletişim krizine neden olabilir.
Burada önemli ayrım şudur: Miras kötüdür demek sığ bir sonuç olur. OOP’de inheritance doğru yerde kullanıldığında güçlüdür. Ortak davranışı tekrar yazmayı önler, sistemi anlaşılır kılar, soyutlamayı kuvvetlendirir. Genetik miras da böyledir. Bedenimiz milyonlarca yıllık başarılı denemelerin arşividir. Reflekslerimiz, bağışıklığımız, öğrenme kapasitemiz bu büyük kod tabanından gelir. Fakat hiçbir ciddi yazılımcı, eski kod çalışıyor diye ona dokunmama dogmasına tapmaz. Çalışan kod da incelenir, test edilir, gerekirse yeniden tasarlanır.
Kompozisyon mu, miras mı?
Modern yazılım tasarımında sıkça duyulan ilke şudur: Miras yerine kompozisyonu tercih et. Yani bir nesnenin ne olduğundan çok, hangi yetenekleri bir araya getirdiğine bak. Bu fikir kuşak çatışmasına da şaşırtıcı biçimde uyar. İnsan yalnızca ailesinin alt sınıfı değildir. Sadece soyadından, genlerinden, çocukluk klasöründen ibaret değildir. Okudukları, dostları, şehirleri, başarısızlıkları, terapileri, aşkları ve kayıplarıyla kendini besteler. Yani insan, inheritance ile başlar ama composition ile olgunlaşır.
Kuşaklar arasındaki çatışma çoğu zaman şu yanlış beklentiden doğar: Üst sınıf, alt sınıfın kendisini genişletmesini ister ama değiştirmesini istemez. Oysa polymorphism tam da değişik biçimlerde davranabilme gücüdür. Aynı aileden gelen iki çocuk, aynı yasam() metodunu bambaşka biçimde çalıştırabilir. Biri geleneksel rotayı seçer, diğeri radikal bir kariyer değişimi yapar. Biri şehirde kök salar, diğeri dünyayı gezer. Bu hata değil; sistemin çok biçimliliğidir.
Elbette her override özgürlük değildir. Bazen çocuk, ailesine karşı çıkıyorum sanırken yine aile kodunun tersinden çalışan bir versiyonudur. Babası gibi olmamak için aldığı her karar, hâlâ babayı merkez alan bir algoritmadır. Gerçek özgürlük, mirası inkâr etmek değil, onu okumaktır. Hangi metod bana ait, hangisi devralınmış? Hangi değişken hâlâ çocuklukta set edilmiş? Hangi exception her ilişkide tekrar fırlatılıyor? Kendini tanımak, kaynak kodu açıp korkmadan bakmaktır.
Sonuçta OOP ile genetik arasındaki benzetme bize şunu öğretir: Hiçbir sınıf boşluktan doğmaz, hiçbir insan da sıfırdan yazılmaz. Hepimiz bir kod tabanının devamıyız. Ama iyi haber şu: Devraldığımız her şey kader değildir. Bazı metodları override edebilir, bazı bağımlılıkları silebilir, bazılarını adapter ile dönüştürebiliriz. Kuşak çatışması da belki bir savaş değil, büyük bir refactoring sürecidir. Eski kodu aşağılamadan, yeni sistemi boğmadan, daha temiz, daha esnek ve daha insani bir mimari kurma çabası.