Rich Hickey’in Clojure fikirlerine erişilebilir bir bakış: basitlik, değişmezlik ve daha iyi varsayılanlar—daha sakin, daha güvenli karmaşık sistemler inşa etmek için pratik dersler.

Yazılım nadiren bir anda karmaşık olur. Oraya her seferinde bir "makul" kararla ulaşır: teslim tarihini yakalamak için hızlı bir önbellek, kopyalamaktan kaçınmak için paylaşılan değiştirilebilir bir nesne, "bu sefer özel" diye kurallara istisna. Her seçim küçük görünür, ama birlikte sistem değişiklik yapmayı riskli hissettiren, hataların yeniden üretimini zorlaştıran ve özellik eklemenin inşa etmekten daha uzun sürdüğü bir hale getirir.
Karmaşıklık kısa vadeli konfor sunduğu için kazanır. Yeni bir bağımlılığı eklemek genellikle mevcut bir şeyi basitleştirmekten daha hızlıdır. Durumu yamamak, durumun beş servis arasında yayılmasının nedenini sormaktan daha kolaydır. Sistem dokümantasyondan daha hızlı büyüdüğünde ise geleneklere ve kabile bilgisine dayanmak caziptir.
Bu bir Clojure eğitimi değil ve Clojure bilmenize gerek yok; amaç Rich Hickey’nin çalışmalarına sıkça atfedilen uygulanabilir fikirleri ödünç almak—dili ne olursa olsun günlük mühendislik kararlarına uygulayabileceğiniz fikirler.
Çoğu karmaşıklık, sizin bilinçli olarak yazdığınız koddan değil, araçlarınızın varsayılan olarak kolaylaştırdıklarından kaynaklanır. Varsayılan “her yerde değiştirilebilir nesneler” ise gizli bağımlılığa yol açarsınız. Varsayılan "durum bellekte" ise hata ayıklama ve izlenebilirlikle zorlanırsınız. Varsayılanlar alışkanlıkları, alışkanlıklar da sistemleri şekillendirir.
Üç temaya odaklanacağız:
Bu fikirler alanınızdaki karmaşıklığı ortadan kaldırmaz ama yazılımınızın onu katlamasını engelleyebilir.
Rich Hickey, Clojure’u yaratması ve yaygın programlama alışkanlıklarını sorgulayan konuşmalarıyla tanınan uzun süreli bir yazılım geliştiricisi ve tasarımcıdır. Odağı trendleri takip etmek değil—sistemlerin büyüdükçe neden değiştirmenin, akıl yürütmenin ve güvenmenin zorlaştığı tekrarlayan sebeplerdir.
Clojure, JVM (Java’nın çalışma zamanı) ve JavaScript gibi bilinen platformlarda çalışan modern bir programlama dilidir. Mevcut ekosistemlerle çalışacak şekilde tasarlanmıştır ve belirli bir stili teşvik eder: bilgiyi düz veri olarak temsil et, değişmeyen değerleri tercih et ve "ne oldu" ile "ekranda ne gösteriyorsun"u ayrı tut.
Bunu, sizi gizli yan etkilere değil daha net yapı taşlarına doğru iten bir dil olarak düşünebilirsiniz.
Clojure küçük komut dosyalarını kısaltmak için yaratılmadı. Tekrarlayan proje acılarına çözüm amaçlıydı:
Clojure’un varsayılanları daha az hareketli parçaya doğru itiyor: kararlı veri yapılarına, açık güncellemelere ve koordinasyonu daha güvenli kılan araçlara.
Değer yalnızca dili değiştirmekle sınırlı değildir. Hickey’nin temel fikirleri—gereksiz bağımlılıkları kaldırarak basitleştirmek, veriyi dayanıklı gerçekler olarak ele almak ve değişken durumu en aza indirmek—Java, Python, JavaScript ve ötesindeki sistemleri iyileştirebilir.
Rich Hickey basit ile kolay arasında keskin bir çizgi çizer—ve çoğu proje farkına varmadan bu çizgiyi geçer.
Kolay, şu an nasıl hissettirdiği ile ilgilidir. Basit ise kaç parçaya sahip olduğu ve ne kadar sıkı bağlı oldukları ile ilgilidir.
Yazılımla, “kolay” genellikle "bugün yazması hızlı" anlamına gelirken, “basit” gelecek ay kırılmasının daha zor olduğu anlamına gelir.
Takımlar genellikle kısa vadeli sürtünmeyi azaltan kestirmeleri seçer ama görünmez yapılar ekler:
Her seçim hız gibi gelebilir, ama hareketli parça, özel durum ve çapraz bağımlılık sayısını artırır. Böylece sistemler tek bir dramatik hata olmadan kırılgan hale gelir.
Hızlı yayınlamak harika olabilir—ama basitleştirmeden hız, genellikle geleceğe borçlanmaktır. Faiz, yeniden üretmesi zor hatalar, yavaş onboarding ve "dikkatli koordinasyon" gerektiren değişiklikler olarak ortaya çıkar.
Bir tasarım veya PR incelerken şu soruları sorun:
“Durum” sisteminizde değişebilen şeydir: bir kullanıcının alışveriş sepeti, bir hesap bakiyesi, mevcut yapılandırma, bir iş akışının hangi adımında olduğu. Sorun değişimin varlığı değil—her değişiklik yeni anlaşmazlık fırsatları yaratır.
Bir bilgi aynı anda farklı zamanlarda (veya farklı yerlerde) farklı olabilirse, kodunuz sürekli olarak “Şu anda gerçek olan sürüm hangisi?” sorusuna cevap vermek zorunda kalır. Bu cevabı yanlış almak rasgele görünen hataları üretir.
Mutabilite, bir nesnenin yerinde düzenlendiği anlamına gelir: "aynı" şey zaman içinde farklı hale gelir. Bu verimli gibi görünse de akıl yürütmeyi zorlaştırır çünkü bir an önce gördüğünüze güvenemezsiniz.
İlişkilendirilebilir örnek, paylaşılan bir elektronik tablo veya belgedir. Birden fazla kişi aynı hücreleri aynı anda düzenleyebiliyorsa, anlayışınız anında geçersizleşebilir: toplamlar değişir, formüller bozulur veya bir satır yeniden düzenlendiği için kaybolur. Kimse kötü niyetli olmasa bile paylaşılan, düzenlenebilir doğası kafa karışıklığı yaratır.
Yazılım durumu aynı şekilde davranır. İki parça aynı değiştirilebilir değeri okursa, bir parça sessizce onu değiştirirken diğeri güncel olmayan bir varsayımla çalışmaya devam edebilir.
Değiştirilebilir durum, hata ayıklamayı bir arkeolojiye dönüştürür. Bir hata raporu nadiren "veri 10:14:03'te yanlış değiştirildi" der. Sadece sonuç görürsünüz: yanlış bir sayı, beklenmedik bir durum, yalnızca bazen başarısız olan bir istek.
Durum zaman içinde değiştiği için en önemli soru olur: buraya hangi düzenleme dizisi getirdi? Bu geçmişi yeniden oluşturamıyorsanız, davranış öngörülemez hale gelir:
Bu yüzden Hickey durumu bir karmaşıklık çoğaltanı olarak görür: veri hem paylaşılıyor ve değiştirilebiliyorsa, olası etkileşim sayısı anlayışınızı hızla aşar.
Değişmezlik basitçe oluşturulduktan sonra değişmeyen veri demektir. Mevcut bir bilgiyi yerinde düzenlemek yerine, güncellemeyi yansıtan yeni bir bilgi parçası oluşturursunuz.
Bir fiş düşünün: bir kez yazdırıldıktan sonra satır öğelerini silip toplamları yeniden yazmazsınız. Bir şey değiştiğinde düzeltici bir fiş verirsiniz. Eski hâl hâlâ vardır ve yenisi açıkça “son sürüm”dür.
Veri gizlice değiştirilemediğinde, arkanızdan yapılan görünmez düzenlemeler konusunda endişelenmeyi bırakırsınız. Bu günlük akıl yürütmeyi çok kolaylaştırır:
Bu, Hickey’nin basitlik üzerinde konuşmasının önemli bir kısmıdır: daha az gizli yan etki, takip edilecek daha az zihinsel dal anlamına gelir.
Yeni sürümler oluşturmak israf gibi gelebilir ama alternatifiyle karşılaştırın. Yerinde düzenleme size şunu sordurabilir: “Bunu kim değiştirdi? Ne zaman? Öncesi neydi?” Değişmez veride değişiklikler açıklığa kavuşur: yeni bir sürüm vardır ve eski sürüm hata ayıklama, denetim veya geri alma için kullanılabilir.
Clojure, güncellemeleri eski değerlerin mutasyonu yerine yeni değerler üretmek olarak ele almayı doğal hale getirir.
Değişmezlik ücretsiz değildir. Daha fazla nesne ayırabilirsiniz ve "şimdi sadece şeyi güncelle"ye alışkın ekiplerin uyum sağlaması zaman alabilir. İyi haber şu ki modern uygulamalar altında yapıyı paylaşarak bellek maliyetini azaltır ve kazanç genellikle daha az açıklanamaz olay içeren daha sakin sistemlerdir.
Eşzamanlılık sadece "birçok şeyin aynı anda olması"dır. Binlerce isteğe hizmet eden bir web uygulaması, bakiyeleri güncellerken fişler oluşturan bir ödeme sistemi veya arka planda senkronize olan bir mobil uygulama—bunların hepsi eşzamanlıdır.
Zor olan, genellikle aynı veriye dokunmalarıdır.
İki işçi aynı değeri okuyup sonra değiştirebiliyorsa, nihai sonuç zamanlamaya bağlı olabilir. Bu bir yarış koşuludur: üretim yoğun olduğunda ortaya çıkan ve kolayca yeniden üretilemeyen bir hatadır.
Örnek: iki istek bir sipariş toplamını güncellemeye çalışır.
Hiçbir şey "çatlamadı" ama bir güncelleme kayboldu. Trafik arttıkça bu zamanlama pencereleri daha sık görülür.
Geleneksel çözümler—kilitler, synchronized bloklar, dikkatli sıralama—işe yarar, ama herkesin koordine olmasını zorunlu kılar. Koordinasyon pahalıdır: verimi düşürür ve kod tabanı büyüdükçe kırılganlaşır.
Değişmez veri ile bir değer yerinde düzenlenmez. Bunun yerine değişikliği temsil eden yeni bir değer oluşturursunuz.
Bu tek değişiklik birçok problem kategorisini ortadan kaldırır:
Değişmezlik eşzamanlılığı bedava yapmaz—hangi sürümün güncel olduğuna dair kurallar hâlâ gerekir. Ama veri kendisi hareketli bir hedef olmadığından eşzamanlı programlar çok daha öngörülebilir olur. Trafik arttığında veya arka plan işler biriktiğinde gizemli, zamanlamaya bağlı hatalar daha az görülür.
"Daha iyi varsayılanlar" demek, daha güvenli seçeneğin otomatik olarak gerçekleşmesi ve ekstra risk üstlenmenin ancak açıkça vazgeçildiğinde olması demektir.
Bu küçük görünür ama varsayılanlar Pazartesi sabahı yazdığınız kodu, Cuma öğleden sonra kabul edilen PR’ları ve yeni bir ekip üyesinin ilk dokunduğu kod tabanından öğrendiğini sessizce yönlendirir.
"Daha iyi varsayılan", her kararı sizin yerinize vermek değildir. Yaygın yolu daha az hata getirir hale getirmektir.
Örnekler:
Bunların hiçbiri karmaşıklığı ortadan kaldırmaz ama yayılmasını durdurur.
Takımlar sadece belgeleri takip etmez—kodun "sizin yapmanızı istediği" şeyi takip ederler.
Paylaşılan durumu değiştirmek kolay olduğunda, bu bir normal kestirme haline gelir ve incelenenler niyet tartışmasıyla uğraşır: "Burada bu güvenli mi?". Değişmezlik ve saf fonksiyonlar varsayılan olduğunda, inceleyenler mantık ve doğruluğa odaklanabilir, çünkü riskli hareketler öne çıkar.
Başka bir deyişle, daha iyi varsayılanlar daha sağlıklı bir taban yaratır: çoğu değişiklik tutarlı görünür ve olağan dışı desenler sorgulanacak kadar belirgin olur.
Uzun vadeli bakım esas olarak mevcut kodu güvenle okumak ve değiştirmekle ilgilidir.
Daha iyi varsayılanlar yeni ekip üyelerinin hızlanmasına yardımcı olur çünkü gizli kurallar azalır ("bu fonksiyon gizlice şu global haritayı güncelliyor, dikkatli ol"). Sistem daha kolay akıl yürütülür hale gelir ve bu her gelecekteki özellik, düzeltme ve refaktör maliyetini düşürür.
Hickey’nin konuşmalarında yararlı bir zihinsel kayma, gerçekleri (ne oldu) ile görünümleri (şu anda neye inandığımız) ayırmaktır. Çoğu sistem bunları birbirine karıştırır ve sadece en son değeri saklayarak zamanı yok eder.
Bir gerçek, değiştirilmeyen kayıttır: "Sipariş #4821 10:14'te verildi", "Ödeme başarılı oldu", "Adres değiştirildi." Bunlar düzenlenmez; gerçekler eklendikçe eklenir.
Bir görünüm uygulamanızın şu anda ihtiyacı olan şeydir: "Güncel gönderim adresi nedir?" veya "Müşterinin bakiyesi ne?" Görünümler gerçeklerden yeniden hesaplanabilir, önbelleğe alınabilir, indekslenebilir veya hız için materialize edilebilir.
Gerçekleri sakladığınızda kazanırsınız:
Kayıtları üzerine yazmak bir hücreyi güncellemek gibidir: sadece en son sayıyı görürsünüz.
Append-only bir günlük bir çek defteri gibidir: her giriş bir gerçektir ve "güncel bakiye" bu girişlerden hesaplanan bir görünümdür.
Tam bir event-sourced mimariye geçmeniz gerekmez. Birçok ekip daha küçük başlayabilir: kritik değişiklikler için append-only bir denetim tablosu tutmak, yüksek riskli iş akışları için değişim olayları saklamak veya yeniden oynatma/hata ayıklama için anlık görüntüler + sınırlı geçmiş saklamak. Önemli olan alışkanlık: gerçekleri dayanıklı, güncel durumu kullanışlı bir projeksiyon olarak ele almak.
Hickey’nin en pratik fikirlerinden biri veri önce: sisteminizin bilgisini düz değerler (gerçekler) olarak ele alın ve davranışı bu değerlere karşı çalıştırın.
Veri dayanıklıdır. Açık, kendi içinde yeterli bilgiyi saklarsanız, daha sonra yeniden yorumlayabilir, servisler arasında taşıyabilir, yeniden indeksleyebilir, denetleyebilir veya yeni özelliklere girdi sağlayabilirsiniz. Davranış daha az dayanıklıdır—kod değişir, varsayımlar değişir, bağımlılıklar değişir.
Bu ikisini karıştırdığınızda sistemler yapışkanlaşır: veriyi yeniden kullanmak için beraberinde davranışı sürüklemek zorunda kalırsınız.
Gerçekleri eylemlerden ayırmak bağımlılığı azaltır çünkü bileşenler bir veri şekli üzerinde anlaşabilir ama ortak bir kod yolu üzerinde anlaşmak zorunda değillerdir.
Bir raporlama işi, bir destek aracı ve bir faturalama servisi aynı sipariş verisini tüketebilir ve her biri kendi mantığını uygular. Mantığı saklanan temsile gömerseniz, her tüketici bu gömülü mantığa bağımlı hale gelir—ve bunu değiştirmek riskli olur.
Temiz veri (evrilebilirliği kolay):
{
"type": "discount",
"code": "WELCOME10",
"percent": 10,
"valid_until": "2026-01-31"
}
Depolamada mini programlar (evrimleşmesi zor):
{
"type": "discount",
"rule": "if (customer.orders == 0) return total * 0.9; else return total;"
}
İkinci versiyon esnek görünür, ama veri katmanına karmaşıklık itiyor: şimdi güvenli bir değerlendirme aracı, versiyonlama kuralları, güvenlik sınırları, hata ayıklama araçları ve kural dili değiştiğinde bir göç planına ihtiyacınız var.
Saklanan bilgi basit ve açık kaldığında davranışı zaman içinde değiştirebilirsiniz. Eski kayıtlar okunabilir kalır. Yeni servisler "miras yürütme kurallarını" anlamadan veriyi tüketebilir. Yeni yorumlar—yeni UI görünümleri, yeni fiyatlandırma stratejileri, yeni analizler—yeni kod yazarak getirilebilir; verinin anlamını mutasyona uğratmak zorunda kalmazsınız.
Çoğu kurumsal sistem bir modülün "kötü" olmasından değil, her şeyin her şeyle bağlı olmasından çöker.
Sıkı bağlılık küçük değişikliklerin haftalar süren yeniden testlere yol açtığı durumlarda kendini gösterir. Bir alana eklenen bir alan üç alttaki tüketiciyi bozar. Paylaşılan bir veritabanı şeması koordinasyon darboğazı olur. Tek bir değiştirilebilir önbellek veya singleton "config" nesnesi sessizce kod tabanının yarısının bağımlılığı haline gelir.
Bunun doğal sonucu zincirleme değişimdir: birçok parça aynı değişen şeyi paylaştığında etki alanı genişler. Takımlar daha fazla süreç, daha fazla kural ve daha fazla el değiştirme ekleyerek yanıt verir—bu genellikle teslimatı daha da yavaşlatır.
Bu fikirleri dil değiştirmeden veya her şeyi yeniden yazmadan uygulayabilirsiniz:
Veri ayağınızın altından değişmediğinde, “bu duruma nasıl geldi?” sorusuyla daha az uğraşırsınız ve kodun ne yaptığını düşünmeye daha fazla zaman ayırırsınız.
Tutarsızlığın sızdığı yer varsayılanlardır: her ekip kendi zaman damgası formatını, hata şekillerini, yeniden deneme politikasını ve eşzamanlılık yaklaşımını icat eder.
Daha iyi varsayılanlar şunlar gibidir: versiyonlanmış olay şemaları, standart değişmez DTO'lar, yazma sahipliğinin netliği ve serileştirme, doğrulama ve izleme için onaylanmış küçük bir kütüphane seti. Sonuç daha az sürpriz entegrasyon ve daha az tek-off düzeltmedir.
Değişimin zaten olduğu yerden başlayın:
Bu yaklaşım sistemi çalışır durumda tutarken güvenilirliği ve takım koordinasyonunu iyileştirir—ve kapsamı küçük tutarak bitirilebilir kılar.
Bu fikirleri uygulamak, iş akışınız hızlı, düşük riskli iterasyonu desteklediğinde daha kolaydır. Örneğin, eğer yeni özellikler geliştiriyorsanız Koder.ai içinde (web, backend ve mobil uygulamalar için sohbet tabanlı vibe-coding platformu), iki özellik doğrudan “daha iyi varsayılanlar” bakış açısıyla örtüşür:
Yığınız React + Go + PostgreSQL (veya mobil için Flutter) olsa bile temel nokta değişmez: her gün kullandığınız araçlar sessizce bir çalışma varsayılanı öğretir. İzlenebilirlik, geri alma ve açık planlama rutinini kolaylaştıran araçları seçmek, o anda "sadece yamala" baskısını azaltabilir.
Basitlik ve değişmezlik güçlü varsayılanlardır, ahlaki kurallar değil. Sistemler büyüdüğünde beklenmedik şekilde değişebilecek şeylerin sayısını azaltırlar. Ama gerçek projelerin bütçeleri, son teslimleri ve kısıtları vardır—ve bazen mutabilite doğru araçtır.
Mutabilite performans kritik noktalarında (sık döngüler, yüksek verimli ayrıştırma, grafik ve sayısal işlemler) mantıklı olabilir çünkü ayırmalar baskındır. Ayrıca kapsamın kontrollü olduğu durumlarda uygundur: bir fonksiyon içindeki yerel değişkenler, dar bir arayüzün arkasındaki özel önbellek veya tek iş parçacıklı bir bileşen.
Önemli olan sınırlamadır. Eğer "değişken şey" sızmazsa, karmaşıklık kod tabanı boyunca yayılmaz.
Büyük ölçüde işlevsel bir stil olsa bile takımların net sahipliğe ihtiyacı vardır:
Bu noktada Clojure’un veri ve açık sınırlar eğilimi yardımcı olur, ama disiplin mimariye dayalıdır, dil spesifik değil.
Hiçbir dil kötü gereksinimleri, belirsiz bir alan modelini veya "tamam"ın ne olduğunu kararlaştıramayan bir takımı çözmez. Değişmezlik kafa karıştırıcı bir iş akışını anlaşılır kılmaz ve "fonksiyonel" kod yanlış iş kurallarını daha düzgün saklayabilir—sadece daha derli toplu.
Sisteminiz zaten üretimdeyse, bu fikirleri bütün ya hep ya hiç şeklinde ele almayın. Riski azaltacak en küçük hamleyi arayın:
Amaç saflık değil—her değişiklik başına daha az sürprizdir.
Bu, dilleri, çerçeveleri veya ekip yapısını değiştirmeden uygulayabileceğiniz sprint boyutunda bir kontrol listesi.
Basitlik vs kolaylık, durumu yönetme, değer-yönelimli tasarım, değişmezlik ve "geçmişin" (zaman içindeki gerçekler) hata ayıklama ve operasyonlara nasıl yardımcı olduğu üzerine kaynaklara bakın.
Basitlik eklenecek bir özellik değildir—küçük, tekrarlanabilir seçimlerde uyguladığınız bir stratejidir.
Küçük, yerel olarak makul kararlar (ek bayraklar, önbellekler, istisnalar, paylaşılan yardımcılar) zamanla birikerek karmaşıklık oluşturur ve modlar ile bağımlılıkları getirir.
İyi bir gösterge, “küçük bir değişiklik”in birden fazla modül veya serviste eşzamanlı düzenlemeler gerektirdiği ya da inceleyenlerin güvenliği değerlendirmek için kabile bilgisinden yararlandığı durumdur.
Kestirme yollar bugünün sürtünmesini (gönderme süresi) optimize ederken maliyeti geleceğe kaydırır: hata ayıklama süresi, koordinasyon yükü ve değişiklik riski.
Tasarım/PR incelemelerinde yararlı bir alışkanlık şu soruyu sormaktır: “Bu yeni hangi hareketli parçaları veya özel durumları ekliyor ve kim bunları sürdürecek?”
Varsayılanlar, mühendislerin baskı altında ne yaptığını şekillendirir. Eğer mutasyon varsayılan ise paylaşılan durum yayılır. Eğer "bellekte tutmak yeterli" varsayılan ise izlenebilirlik kaybolur.
Güvenli yolu en kolay yol haline getirerek varsayılanları iyileştirin: sınırlarda değişmez veriler, açık zaman dilimleri/null işlemleri/yeniden denemeler ve net durum sahipliği.
Durum, zaman içinde değişen her şeydir. Zor olan, değişimin anlaşmazlıklar için fırsat yaratmasıdır: iki bileşen farklı “güncel” değerler tutabilir.
Hatalar genellikle zamanla alakalı davranışlar olarak ortaya çıkar (“sende çalışıyor”, üretimde aralıklı problemler) çünkü soru şudur: hangi veri sürümüne göre hareket ettik?
Değişmezlik, bir değeri yerinde düzenlememek; güncelleme için yeni bir değer yaratmaktır.
Pratikte faydaları şunlardır:
Her zaman değil. Mutasyon, izole edildiği sürece iyi bir araç olabilir:
Ana kural: değişken yapıları, birçok parçanın okuyup yazabildiği sınırların ötesine sızdırmayın.
Yarış koşulları genellikle paylaşılan, değiştirilebilir verinin birden çok işçi tarafından okunup sonra yazılmasıyla ortaya çıkar.
Değişmezlik koordinasyon yüzeyini azaltır çünkü yazanlar paylaşılan bir nesneyi düzenlemek yerine yeni sürümler üretir. Hangi sürümün yayınlanacağına dair bir kural gerekir, ama veri kendisi artık hareketli bir hedef olmaz.
Olayları append-only (ekleme odaklı) kayıtlar olarak tutun ve “güncel durum”u bu olaylardan türetilmiş bir görünüm olarak düşünün.
Tam event sourcing’e geçmeden küçük adımlarla başlayabilirsiniz:
Bilgiyi açık, düz veriler (değerler) olarak saklayın ve davranışı bunlara karşı çalıştırın. Saklanan kayıtların içine çalıştırılabilir kurallar yerleştirmekten kaçının.
Bunun yararları:
Sık değişen bir iş akışı seçin ve üç adım uygulayın:
Başarıyı daha az aralıklı hata, değişimin daha küçük etki alanı ve sürümlerde daha az “özenli koordinasyon” ile ölçün.