8 dk

Rich Hickey & Clojure: Basitlik, Değişmezlik, Daha İyi Varsayılanlar

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.

Rich Hickey & Clojure: Basitlik, Değişmezlik, Daha İyi Varsayılanlar

Neden karmaşıklık gerçek projelerde kazanıyor

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 makale ne (ve ne değil)

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.

Varsayılanların düşündüğünüzden daha önemli olmasının nedeni

Ç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:

  • Basitlik: daha az özellik değil; daha az hareketli parça ve daha az özel durum.
  • Değişmezlik: verileri değişmeyen değerler olarak ele almak, böylece üzerine akıl yürütmek kolaylaşır.
  • Daha iyi varsayılanlar: güvenli, öngörülebilir seçeneği en kolay seçenek yapmak.

Bu fikirler alanınızdaki karmaşıklığı ortadan kaldırmaz ama yazılımınızın onu katlamasını engelleyebilir.

Rich Hickey ve Clojure’un düzeltmeyi hedeflediği şeyler

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 nedir (yüksek seviye, jargon yok)

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.

Azaltmayı hedeflediği problemler

Clojure küçük komut dosyalarını kısaltmak için yaratılmadı. Tekrarlayan proje acılarına çözüm amaçlıydı:

  • Paylaşılan durumdan kaynaklanan büyüyen karmaşıklık: sistemin birçok parçası aynı veriyi değiştirebildiğinde hatalar zamanlamaya bağlı ve yeniden üretmesi zordur.
  • Veri ile davranış arasında sıkı bağlılık: bilgi nesnelerin içine kilitlendiğinde, yeniden kullanım zorlaşır ve değişiklik kod tabanına dalga dalga yayılır.
  • Eşzamanlılık baş ağrıları: arka plan işleri, kuyruklar ve paralel işler eklendikçe "kim neyi, ne zaman değiştirdi?" günlük bir problem olur.

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.

Clojure’u hiç benimsemeseniz bile faydası var

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.

Basitlik: “kolay” değil, daha az hareketli parça

Rich Hickey basit ile kolay arasında keskin bir çizgi çizer—ve çoğu proje farkına varmadan bu çizgiyi geçer.

Basit vs. kolay (günlük örneklerle)

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.

  • Anında erişilen erişte kolaydır. Basit bir güveç az sayıda malzeme, tek pota ve gizli hiç şey olmayabilir.
  • 60 düğmeli bir kumanda bir özelliği “kolay” yapabilir (oradadır), ama basit değildir. 6 net kontrole sahip bir kumanda daha basittir; öğrenmesi bir dakika sürebilir ama daha az karmaşıktır.

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.

“Şimdi kolay” nasıl gelecekte karmaşıklık yaratır

Takımlar genellikle kısa vadeli sürtünmeyi azaltan kestirmeleri seçer ama görünmez yapılar ekler:

  • “Bir bayrak ekleyelim.” Artık her özellik o bayrağı göz önünde bulundurmalı.
  • “Hesaplanan değeri saklayalım zaman kazanalım.” Artık onu tüm kod yollarında senkronize tutmanız gerekir.
  • “UI’da yamayız.” Artık aynı iş kuralı birçok yerde var.

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ız basitlik demek değildir

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.

Kazara karmaşıklık için kısa kontrol listesi

Bir tasarım veya PR incelerken şu soruları sorun:

  • Yeni modlar, bayraklar veya yapılandırma dalları ekledik mi?
  • Tutarlı tutulması gereken veri önbelleğe alınıyor veya çoğaltılıyor mu?
  • Bir davranış için birden fazla modül birlikte değişmek zorunda mı?
  • Kural birden fazla yerde mi uygulanmış?
  • Yeni bir ekip üyesi ekstra açıklama olmadan bunun nasıl çalışacağını tahmin eder mi?

Durum: sessizçe çoğaltan faktör

“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: göremediğiniz değişiklik

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.

Neden hata ayıklama çok acı verir

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:

  • Aynı eylem zamanlamaya bağlı olarak farklı sonuçlar üretir.
  • Düzeltmeler "benim makinemde çalışıyor" ama üretimde çalışmıyor.
  • Log eklemek zamanlamayı değiştirir ve hata kaybolur.

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.

Bilgisayar bilimi jargonuna girmeden değişmezliği açıklamak

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.

Neden sürprizleri azaltı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:

  • Bir değere sahipseniz onun öyle kalacağına güvenebilirsiniz.
  • Hataları yeniden üretmek daha kolaydır çünkü aynı girişler sabit kalır.
  • Sistemin parçaları arasında veri paylaşmak daha güvenlidir çünkü kimse başkasının işini kazayla bozamaz.

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" vs. "yerinde düzenleme"

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.

Açık konuşmak gerekirse fedakarlıklar

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.

Veri değişmedikçe eşzamanlılık daha kolay olur

Earn credits for learning
Earn credits by creating content about how you reduced complexity with Koder.ai.

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.

Paylaşılan, değiştirilebilir veri neden yarış koşulları yaratı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.

  1. İstek A toplamı = 100 okur
  2. İstek B toplamı = 100 okur
  3. A 20 ekler ve 120 yazar
  4. B 10 ekler ve 110 yazar

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şmezlik koordinasyonu minimuma indirir

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:

  • Okuyucular baktıkları şeyin ortasında değişeceğini düşünmek zorunda kalmaz.
  • Yazanlar aynı hafıza üzerinde "savaşmaz"; yeni sürümler üretirler.
  • Sistem en son sürümü yayınlamak için basit, iyi test edilmiş yapıları tercih edebilir.

Sonuç: yük altında öngörülebilir davranış

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" pratikte ne demek

"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.

Riski azaltan varsayılanlar

"Daha iyi varsayılan", her kararı sizin yerinize vermek değildir. Yaygın yolu daha az hata getirir hale getirmektir.

Örnekler:

  • Sınırlar itibarıyla değişmez veri: "şeyi değiştirmek" yerine yeni sürüm yaratmak. Bu, eski değere güvenen başka parçaları istemeden etkilemeyi zorlaştırır.
  • Saf fonksiyonlar normal stil: bir fonksiyon girdileri alır ve çıktı üretir, paylaşılmış veriyi gizlice değiştirmez veya gizli küresel duruma bağlı değildir. Bu davranışı tahmin etmeyi ve test etmeyi kolaylaştırır.
  • Açık durum değişiklikleri: bir şey mutlaka değişecekse, bu açık, iyi tanımlanmış mekanizmalarla yapılır (kodun herhangi bir yerinin her şeyi değiştirebilmesi yerine).

Bunların hiçbiri karmaşıklığı ortadan kaldırmaz ama yayılmasını durdurur.

Varsayılanlar ekipleri ve kod incelemelerini nasıl şekillendirir

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.

Bakım ve işe alıştırma

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.

Gerçekler ile görünümleri ayırmak: zaman, geçmiş ve izlenebilirlik

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.

Gerçekler ekleme odaklıdır; görünümler türetilir

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.

Geçmişi tutmanın getirileri

Gerçekleri sakladığınızda kazanırsınız:

  • Denetlenebilirlik: güncel değerin neden böyle olduğunu açıklayabilirsiniz.
  • Hata ayıklama: diziyi tekrar oynatıp sapmanın nerede olduğunu bulabilirsiniz.
  • İzlenebilirlik: "Bunu kim ne zaman değiştirdi ve öncesi neydi?" artık dedektiflik değil veri sorunudur.

Yaklaşılabilir bir örnek: üzerine yazma vs ekleme

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.

Her sistem tam event sourcing gerektirmez

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.

Veri odaklı: bilgiyi dayanıklı ve esnek yapın

Make changes reversible
Ship changes with snapshots and rollback so experiments do not turn into long recoveries.

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.

Değerler vs eylemler (jargonsuz)

  • Veri (değerler): "Gerçek nedir?" Bir müşterinin e-postası, bir sipariş toplamı, zaman damgası, durum.
  • Davranış (eylemler): "Ne yapıyoruz?" Doğrulama, indirim hesaplama, bildirim gönderme, bir durumun anlamını kararlaştırma.

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.

Daha az bağlılık, daha fazla yeniden kullanım

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.

Örnek: temiz veri saklamak vs içinde mini programlar saklamak

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.

Bu neden sistemlerin evrilebilir olmasını sağlar

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.

Karmaşık sistemlere fikirleri uygulamak (yeni baştan yazmadan)

Çoğu kurumsal sistem bir modülün "kötü" olmasından değil, her şeyin her şeyle bağlı olmasından çöker.

İzlemeniz gereken hata modları

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.

Daha basit sınırlarla etki alanını azaltın

Bu fikirleri dil değiştirmeden veya her şeyi yeniden yazmadan uygulayabilirsiniz:

  • Sınırlarda değişmez veriyi tercih edin. Mesajları, olayları ve API girdilerini "yerinde düzenleme" yerine düzenlenmeyen gerçekler olarak ele alın. Bir şey değişiyorsa yeni bir sürüm oluşturun.
  • Durumu kenarlara taşıyın. Temel mantığı saf dönüşümler olarak tutun: girdi verisi → çıktı verisi. Veritabanları, önbellekler ve UI’lar "güncel durumu" yönetsin.
  • Paylaşılan değiştirilebilir yapıların kullanımını durdurun. İki modül aynı nesneye yazıyorsa birbirine bağlıdırlar. Referanslar değil, değerler geçirin.

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.

Takımlar arasında “daha iyi varsayılanlar”

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.

Mevcut kod tabanlarında işe yarayan artışlı benimseme

Değişimin zaten olduğu yerden başlayın:

  1. Mevcut modülleri, değişmez veri kabul/geri döndüren bir API ile sarın.
  2. Yoğun değişen bir iş akışını ekleme odaklı "append-only" kayıtlara dönüştürün.
  3. Paylaşılan değiştirilebilir önbellekleri dayanıklı gerçeklerden yeniden hesaplanabilir görünümlere çevirin.

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.

Platformlar ve araçların “daha iyi varsayılanları” desteklemesi

Build the core app fast
Create a React web app with a Go and PostgreSQL backend without wiring everything by hand.

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:

  • Planning mode, sınırları ve veri şekillerini uygulama öncesinde açıkça yapmanızı teşvik eder—çoğu zaman basit veri akışı ile kazara bağımlılıklar arasındaki fark budur.
  • Snapshots ve rollback, değişiklikleri daha güvenli yayınlamayı sağlar; çünkü "kolay" bir kestirme karmaşıklık patlamasına dönüşürse hızlıca geri alabilirsiniz.

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.

Fedakarlıklar, sınırlamalar ve ideolojiden kaçınma

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.

Mutabilitenin kabul edilebilir olduğu zamanlar

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.

Sahiplik ve arayüzlerle karmaşıklığı sınırlayın

Büyük ölçüde işlevsel bir stil olsa bile takımların net sahipliğe ihtiyacı vardır:

  • Bir modül bir durum parçasına sahip olsun ve küçük bir API açsın.
  • Veriler sınırları aşarken düz değerler olarak geçsin (gizli davranışı olan canlı nesneler değil).
  • Yan etkiler kenarlara itilsin (I/O, veritabanları, zaman).

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.

Clojure neyi çözmez

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.

Dogmadan kaçının: riski en küçük değişiklikle azaltın

Sisteminiz zaten üretimdeyse, bu fikirleri bütün ya hep ya hiç şeklinde ele almayın. Riski azaltacak en küçük hamleyi arayın:

  • Modül sınırlarındaki paylaşılan değiştirilebilir yapıları değişmez verilerle değiştirin.
  • Denetlenebilirlik önemli alanlara olay günlükleri veya append-only geçmiş ekleyin.
  • Miras durumunu dar bir arayüzün arkasına sarın ve yayılmasını durdurun.

Amaç saflık değil—her değişiklik başına daha az sürprizdir.

Daha basit yazılıma doğru pratik kontrol listesi

Bu, dilleri, çerçeveleri veya ekip yapısını değiştirmeden uygulayabileceğiniz sprint boyutunda bir kontrol listesi.

Bir sonraki sprintte denenecek 3–5 şey

  1. Veri şekillerinizi varsayılan olarak değişmez yapın. İstek/yanıt nesnelerini, olayları ve mesajları oluşturup bir daha değiştirmeyin. Değişmesi gerekiyorsa yeni bir sürüm oluşturun.
  2. İş akışlarının ortasında saf fonksiyonları tercih edin. Bir iş akışını (fiyatlandırma, izinler, ödeme) seçip çekirdeği veri alıp veri döndüren fonksiyonlara refaktör edin—gizli okuma/yazma yok.
  3. Durumu daha az ve daha net yerlere taşıyın. Her kavram için tek bir doğruluk kaynağı seçin (müşteri durumu, özellik bayrakları, envanter). Eğer birden fazla modül kendi kopyasını tutuyorsa bunu açık bir karar haline getirin ve bir senkronizasyon stratejisi belirleyin.
  4. Ana gerçekler için append-only günlük ekleyin. Bir alan için "ne oldu"yu kalıcı olaylar olarak kaydedin (hala güncel durumu saklasanız bile). Bu izlenebilirliği artırır ve tahmin yürütmeyi azaltır.
  5. API'lerde daha güvenli varsayılanlar tanımlayın. Varsayılanlar şaşırtıcı davranışları en aza indirmelidir: açık zaman dilimleri, açık null işleme, açık yeniden denemeler, açık sıralama garantileri.

Tasarım inceleme soruları (bunları aynen kullanın)

  • Buradaki değiştirilebilir parçalar neler ve kim bunları değiştirebilir?
  • Bunu alanları üzerine yazmak yerine "gerçekler + türetilmiş görünüm" olarak modelleyebilir miyiz?
  • İki istek aynı anda çalışırsa ne kırılır?
  • Hangi varsayılanlara güveniyoruz (zaman, sıralama, yeniden denemeler, önbellekleme) ve belgelenmişler mi?
  • Bunu üç ay sonra hata ayıklamak için neye ihtiyacımız olur?

Hickey’nin konuşmalarından yeniden gözden geçirilecek konular

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.

SSS

Why does complexity keep “winning” in real projects?

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.

What’s the difference between “simple” and “easy” in software?

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?”

How do programming language and framework defaults create accidental complexity?

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.

Why is state described as a “complexity multiplier”?

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?

What does immutability mean in practical, non-academic terms?

Değişmezlik, bir değeri yerinde düzenlememek; güncelleme için yeni bir değer yaratmaktır.

Pratikte faydaları şunlardır:

  • Okuyucular verinin kullanım sırasında değişmeyeceğine güvenebilir.
  • Hataları yeniden üretmek daha kolaydır (girdiler sabit kalır).
  • Veriyi iş parçacıkları veya modüller arasında paylaşmak daha güvenlidir.
When is mutability acceptable (or even preferable)?

Her zaman değil. Mutasyon, izole edildiği sürece iyi bir araç olabilir:

  • Bir fonksiyon içindeki yerel değişkenler
  • Performans kritik alanlar (sık döngüler, ayrıştırma, sayısal işler)
  • Dar bir arayüzün arkasındaki özel önbellekler

Ana kural: değişken yapıları, birçok parçanın okuyup yazabildiği sınırların ötesine sızdırmayın.

How does immutability help with concurrency under load?

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.

What does it mean to separate “facts” from “views,” and how can I apply it incrementally?

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:

  • Kritik değişiklikler için bir denetim tablosu ekleyin
  • Yüksek riskli bir akış için değişim olaylarını kaydedin
  • Geriye dönük hata ayıklama için anlık görüntüler + sınırlı geçmiş saklayın
What is “data-first” design and why does it reduce coupling?

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ı:

  • Kod değiştiğinde eski kayıtlar okunabilir kalır
  • Yeni tüketiciler aynı veri yapısını yeniden kullanabilir
  • Mantığı değiştirmek için geçmişi yeniden yazmanız gerekmez
What are the first 3 concrete changes to try next sprint to reduce complexity?

Sık değişen bir iş akışı seçin ve üç adım uygulayın:

  1. Sınır verilerinizi değişmez yapın: API giriş/çıkışları, mesajlar ve olaylar "bir kere oluştur, değiştirme" olarak davranır.
  2. Çekirdeği saf dönüşümlere refaktör edin: girdi verisi → çıktı verisi; I/O ve yan etkileri kenarlara itin.
  3. Paylaşılan değiştirilebilir yapıların sayısını azaltın: her durum parçasının bir sahibi olsun ve dar bir arayüzle erişilsin.

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.

Related posts