Karmaşıklıkla Barışık Yaşamak: A Philosophy of Software Design Üzerine
John Ousterhout'un "A Philosophy of Software Design" kitabını bitirdim. Notlarımı toparlarken fark ettim ki kitabın anlattığı çoğu şeyi zaten biliyordum, ama bilmekle onu bir çerçeveye oturtmak arasında ciddi bir fark var. Kitap, yıllardır kod yazarken sezgisel olarak hissettiğim ama hiç isimlendirmediğim şeylere isim koydu.
Bu yazı bir kitap özeti değil, daha çok kendi kod tabanımda ve data migration takımındaki işlerimde nerede karşıma çıktığını düşünerek yazdığım bir okuma günlüğü.
Karmaşıklık tek bir hatadan gelmez
Ousterhout'un ilk tezi basit:
Karmaşıklık, kodun anlaşılmasını ve değiştirilmesini zorlaştıran her şeydir. Ve neredeyse hiçbir zaman tek bir büyük hatadan gelmez. Küçük küçük birikir. Bir yerde kötü bir değişken adı, bir yerde eksik bir yorum, bir yerde gereksiz bir bağımlılık.
Bunun karşılığı "sıfır tolerans" felsefesi. Küçük bir karmaşıklık gördüğünde "zaten kod öyle, dokunmayayım" demek yerine düzeltmek. Bunu çalıştığım proje üzerinde çalışırken fark ettim. Import mantığı zamanla o kadar çok küçük özel durum biriktiriyor ki, her biri tek başına zararsız görünüyor ama toplamda kod tabanını okunmaz hale getiriyor.
Taktik tornado ile tanışma
Kitaptaki en çarpıcı kavramlardan biri "taktik tornado". Çok hızlı kod yazan, sürekli özellik teslim eden ama arkasında temizlenmesi gereken bir yıkım bırakan geliştirici tipi. Yöneticiler onu kahraman sanıyor, ama gerçekte diğer mühendisler onun bıraktığı dağınıklığı topluyor.
Bunu okurken kendi kariyerimde hem bu role yaklaştığım hem de arkasını toplamak zorunda kaldığım dönemleri düşündüm. Startup baskısı altında "önce çıkaralım sonra düzeltiriz" mantığı çok tanıdık geliyor. Kitap bunun bir yanılsama olduğunu söylüyor: iyi tasarım aslında daha hızlı teslimat demek, kısa vadede değilse bile birkaç ay içinde.
Sayı da veriyor:
Geliştirme süresinin yüzde on ila yirmisini tasarıma yatırım olarak ayırmak, projeyi önemli ölçüde geciktirmiyor. Bu oranı bilinçli tutmak, "zamanım yok" bahanesine karşı elle tutulur bir karşılık.
Derin modüller, sığ modüller
Kitabın omurgası bu kavram. Bir modülün değeri, sunduğu işlevsellik ile arayüzünün karmaşıklığı arasındaki orana bakılarak ölçülüyor. Basit bir arayüzün arkasında güçlü bir işlevsellik varsa, o modül derin. Karmaşık bir arayüzün arkasında az bir şey varsa, sığ.
Unix'in dosya sistemi çağrıları (open, read, write, lseek, close) klasik örnek. Beş fonksiyon, arkasında devasa bir karmaşıklık gizli. Buna karşılık kitap "classitis" dediği bir hastalığı eleştiriyor: her şeyi küçük küçük sınıflara bölme takıntısı. Küçük sınıflar iyi diye düşünülür ama sistem seviyesinde tam tersi oluyor, çok fazla sığ parça birbirine bağımlı hale geliyor.
Bu kısmı okurken "boring Rails" yaklaşımıma çok yakın buldum. Rails ekosisteminde her problem için yeni bir soyutlama katmanı, yeni bir service object, yeni bir gem eklemek cazip geliyor. Ama bazen en derin modül zaten elimizdeki, sade Active Record modelidir. Soyutlama eklemek karmaşıklığı azaltmıyorsa, o soyutlamayı hiç eklememek daha iyi.
Bilgi gizleme ve bilgi sızıntısı
Bir tasarım kararı birden fazla modüle yayılmışsa, bilgi sızıntısı var demektir. Kitabın verdiği örnek zamansal ayrıştırma: bir işlemi zaman sırasına göre (önce oku, sonra işle, sonra yaz) sınıflara bölmek, çünkü okuma ve yazma sınıfları genelde aynı formatı bilmek zorunda kalıyor.
Bunu import araçlarında sık görüyorum. Farklı kaynak formatlarını okuyan kod ile bu veriyi veritabanına yazan kod arasında format bilgisi ileri geri sızabiliyor, format değiştiğinde iki yerde de değişiklik gerekiyor. Kitap bunun çözümünü zaman sırasına değil bilgiye odaklanarak tasarlamak olarak öneriyor.
Karmaşıklığı aşağı çekmek
Bir modülde kaçınılmaz bir karmaşıklık varsa, onu kullanıcıya (ya da çağıran kodlara) yansıtmak yerine modülün içine gömmek gerekiyor. Kitabın kuralı net: bir modülün basit bir uygulamaya sahip olmasından çok basit bir arayüze sahip olması önemli. Çünkü bir modülün kullanıcı sayısı genelde geliştirici sayısından fazla.
Bunun en somut örneği konfigürasyon parametreleri. Emin olamadığın her şey için bir ayar eklemek, aslında kararı erteleyip başka birine (genelde sistem yöneticisine ya da gelecekteki kendine) devretmek. Kitap şunu soruyor:
Kullanıcı bu değeri gerçekten benden daha iyi belirleyebilir mi?
Çoğu zaman cevap hayır.
İki kere tasarlamak
Bu bölüm bana en çok dokunan yerlerden biriydi. Önemli bir tasarım kararı için en az iki farklı alternatif düşünmek, her birinin arayüzünü kabaca çizmek, artı eksilerini karşılaştırmak. İlk fikrin zaten en iyisi olsa bile bu süreç seni çok şey öğretiyor. Kitap burada ilginç bir gözlem yapıyor:
Zeki insanlar ilk denemede doğru yapar.
Okulda böyle öğreniyoruz çünkü okul problemleri küçük. Ama gerçek yazılım sistemleri o kadar zor ki, kimse ilk seferde mükemmel tasarım yapamıyor. Tech lead yönünde ilerlerken bu bölümü özellikle önemsedim, çünkü tek başına doğru kararı bulmaya çalışmak yerine alternatifleri açıkça karşılaştırıp takıma sunmak, hem daha iyi kararlar çıkarıyor hem de kararın arkasındaki mantığı paylaşılabilir kılıyor.
İsimler ve yorumlar üzerine
Kitabın son kısımları isim seçimi ve yorum yazma üzerine. İki fikir özellikle aklımda kaldı. Birincisi, bir değişkene ya da metoda iyi bir isim bulmak zorsa, bu genelde isim probleminden çok tasarım probleminin belirtisi. İkincisi, "iyi kod kendi kendini belgeler" cümlesine karşı çıkış. Kod, tasarımcının kafasındaki niyeti asla tam yakalayamaz. delete(start, end) metodunda end dahil mi değil mi, kod tek başına bunu söylemiyor. Yorumlar burada eksik kalan boşluğu dolduruyor.
Son not
Bu kitabı rubyforum.org üzerinde birlikte yürüttüğümüz kitap kulübü için okudum, bölümleri haftada dört tane olacak şekilde beş haftaya yaydık. Bir kitabı tek başına okumakla bir grupla tartışarak okumak arasındaki fark da ayrı bir yazının konusu olabilir, ama şunu söyleyebilirim: başkalarının aynı bölümden çok farklı örnekler çıkarması, kitabın anlattığı "değişim amplifikasyon" ya da "bilişsel yük" gibi kavramların ne kadar farklı bağlamlarda karşımıza çıktığını görmemi sağladı.
Kitabı bitirdikten sonra elimde kalan tek cümle şu:
Karmaşıklık asla tamamen yok edilmez, sadece nereye taşınacağına karar verilir. Mesele bu kararı bilinçli vermek.
Comments ()