16 puan yazan GN⁺ 2025-02-25 | 3 yorum | WhatsApp'ta paylaş
  • Clojure, ana akım programlama dillerinden biri değildir ve bazı kişiler için yabancı olabilir
  • Clojure’un başlıca avantajları
    • Geliştirici üretkenliği : Clojure etkileşimlidir, tekrarlayan işleri azaltır ve verimli bir geliştirme ortamı sunar. Geliştiriciler memnun kalarak ürünleri hızlıca piyasaya sürebilir
    • Uzun vadeli bakım kolaylığı : Clojure dili ve ekosistemi olgun ve kararlıdır. Yüksek kaliteli sistemler kurarken bakım maliyetlerini düşürmek mümkündür
    • Fikir odaklı kültür : Clojure topluluğu, geçmişten ve günümüzden, akademiden ve endüstriden gelen fikirleri inceleyerek daha iyi yazılım geliştirme yolları arar. Geliştiricilere yeni meydan okumalar ve öğrenme fırsatları sunar

(hello 'clojure)

  • Clojure, 1950’lerde oluşturulan Lisp ailesi dillerden biridir
    • Lisp kuramsal bir model olarak başladı, ancak gerçek programlamada da yüksek düzeyde kavramsal zarafet sundu
    • Kodun sözdizimi doğrudan veri yapısıyla örtüştüğü için, geleneksel olarak sözdizimi karmaşık dillere göre çeşitli avantajlara sahiptir
    • Geçmişteki yapay zeka patlaması sırasında başlıca dillerden biri olarak kullanıldı
  • Lisp ailesi dilleri dönem dönem popülerlik kazanıp kayboldu, ancak son 10 yılda Clojure dikkat çekti
  • Clojure, Java’nın JVM’i üzerinde çalışır ve modern programlama kavramlarını yansıtır
    • Güçlü değiştirilemez veri yapıları desteği
    • Eşzamanlılık göz önünde bulundurularak tasarlanmış olması
  • Büyük kurumsal şirketlerin desteği olmadan büyümüş küçük bir topluluk olsa da, güçlü dil özelliklerine sahiptir
  • Clojure çeşitli ortamlarda çalıştırılabilir
    • ClojureScript: JavaScript’e dönüştürülerek çalıştırılır
    • ClojureCLR: .NET ortamında çalışır
    • Babashka: GraalVM kullanan hızlı bir betik yorumlayıcısı
    • Jank: Yerel derleme desteği
  • Clojure öğrenildiğinde, aynı bilgiyi birden çok ortamda kullanabilme avantajı vardır

Etkileşimli geliştirme biçimi

  • Programlama, kod yazma ve doğrulama sürecinin tekrarından oluşur
    • Geri bildirim yoksa, kodun düzgün çalıştığından emin olmak zordur
    • Yaygın geri bildirim yöntemleri:
      • Betik çalıştırmayı tekrar etmek
      • UI etkileşimi ve log çıktıları
      • Birim testlerinden yararlanmak
      • Derleyici ve statik analiz araçlarını kullanmak
    • Hızlı geri bildirim, geliştirici üretkenliği üzerinde büyük etkiye sahiptir
      • Geri bildirim yavaşladıkça hata ayıklama süresi artar, kod yazma süresi azalır
  • Clojure, mevcut geri bildirim yöntemlerine ek olarak etkileşimli geliştirme (interactive development) yaklaşımı sunar
    • Bunun merkezinde REPL (Read-Eval-Print Loop) tabanlı geliştirme vardır
    • Geliştirici, kod yazmadan önce Clojure çalışma zamanını başlatır ve editöre bağlar
    • Kod parçalarını tek tek çalıştırarak anında geri bildirim alabilir
    • Lisp’in tutarlı sözdizimsel yapısı sayesinde küçük kod parçalarından büyük kod bloklarına kadar serbestçe çalıştırmak mümkündür
  • Sıradan bir REPL’den farklı olarak Clojure, çalışmakta olan sisteme bağlı durumdayken kod parçalarını çalıştırmaya izin verir
    • Bu yaklaşım, klasik “kodu yaz → çalıştır → hata ayıkla” yöntemine göre çok daha güçlü bir geri bildirim döngüsü sağlar
    • Programı gerçek zamanlı olarak değiştirmek ve hata ayıklamak mümkündür
    • Bu sadece basit bir REPL değil, üretim ortamında da kullanılabilen güçlü bir etkileşim aracıdır

Kararlılığa önem veren kültür

  • Clojure’u seçmek, yalnızca güçlü bir teknoloji edinmek değil, aynı zamanda kendine özgü felsefe ve ilkelere sahip bir topluluğun parçası olmak demektir
    • Sadece teknolojiyi benimseyip toplulukla iletişim kurmamak, Clojure’un gerçek değerini deneyimlemeyi zorlaştırır
  • Clojure topluluğu, kararlılık ve geriye dönük uyumluluğu önemli değerler olarak görür
  • Çekirdek dil, neredeyse hiçbir zaman kırıcı değişiklik yapmadan sürekli iyileştirilip genişletilir
  • Clojure’un açık kaynak ekosistemi de aynı felsefeyi izler ve gereksiz değişimi (churn) en aza indirir
    • Bu, diğer çoğu modern programlama dili ekosistemiyle tezat oluşturur
    • Gereksiz değişimden doğan kaynak israfı, dünya genelinde milyarlarca dolarlık bir ölçeğe ulaşır
  • Clojure’da dilin ve kütüphanelerin en güncel sürümlerine yükseltme yapmak son derece doğaldır
    • Hata düzeltmeleri, güvenlik güncellemeleri ve performans iyileştirmelerinden yararlanırken kod tabanını yeniden yazmak gerekmez
    • Diğer dillerde yeni sürüm çıktığında bozulabilen mevcut kod, Clojure’da olduğu gibi kalır
  • Bazı geliştiriciler “Değişiklik olmadan nasıl ilerleme olabilir?” diye düşünebilir
    • Ancak kararlılık ile durgunluk aynı şey değildir
    • Clojure, mevcut özellikleri bozmadan yeni özellikler ekleyip iyileştirerek gelişir
    • Geliştiriciler gereksiz kod değişiklikleri yapmadan sürekli daha iyi araçlar kullanabilir

Bilgi sistemleri ve bilginin ifadesi

  • Web ve iş uygulaması geliştirmede bilginin toplanması, erişilmesi ve işlenmesi temel unsurdur
  • Ancak ana akım programlama dilleri, bilgiyi ifade etme ve işleme açısından çoğu zaman verimsiz tasarımlar sergiler
    • Düşük seviyeli veri yapıları dayatarak gereksiz karmaşıklık yaratırlar
    • Statik tip sistemleri aşırı katı olabilir, bu da esnek veri işlemesini zorlaştırır
  • Clojure, işlevsel veri yapıları ve güçlü veri işleme yeteneklerini varsayılan olarak sunar
    • Dinamik tipli bir dil olarak “Açık Dünya Varsayımı (Open World Assumption)” yaklaşımını benimser
      • Bu, veri genişletilebilirliğini ve esnekliğini en üst düzeye çıkaran bir yöntemdir
    • RDF’nin (Semantic Web için veri modelleme çerçevesi) etkisini güçlü biçimde taşır
      • Örneğin Datomic gibi grafik veritabanlarıyla sinerjisi büyüktür
      • Namespace içeren anahtar sözcükler kullanarak bağlamdan bağımsız anlam verme mümkündür
  • Namespace anahtar sözcüklerini kullanan Clojure map yapısı, basit JSON’dan daha incelikli anlam ifadesi sağlayabilir
  • Ek veri genişletmek kolaydır ve isim çakışmalarından kaçınırken sezgisel veri ifadesi mümkündür

Küçük, birleştirilebilir fonksiyonlar ve değiştirilemez veri

  • Clojure’da programlama genellikle saf fonksiyonlar (pure functions) ve değiştirilemez veri (immutable data) etrafında şekillenir
  • Java, Ruby ya da C tarzı emirsel kod yazmak mümkün olsa da, Clojure’a özgü yazım tarzı (idiomatic Clojure) oldukça farklıdır
    • Saf fonksiyonlar: Yalnızca girdilere dayanarak sonuç üretir, dış durumu değiştirmez
    • Değiştirilemez veri: Referans veya nesne kimliğinden çok değer (value) temelli bir anlam taşır
  • Dış durumdan etkilenmediği için kodun öngörülebilirliği yüksektir
  • Genel değişkenlerin değiştirilmesi ya da beklenmedik yan etkiler yoktur
  • Verinin değişme riski olmadığı için paralel işlem ve eşzamanlılık sorunlarını çözmek daha kolaydır

Eşzamanlılık işleme

  • Modern hesaplama çok çekirdekli işlemcilere dayanır ve eşzamanlılık artık zorunlu bir unsurdur
    • Moore Yasası sınırına ulaştıkça, paralelliği kullanmak performans artışının anahtarı haline gelir
    • Ancak değiştirilebilir durumla (mutable state) çalışıldığında senkronizasyon sorunları ve karmaşık zamanlama kontrolü gerekir
  • Clojure, değiştirilemezliği (immutability) vurgulayarak eşzamanlılık sorununu kökten çözer
    • Değiştirilebilir belleği manipüle etmek, zamanlama ve sıraya bağımlılık yaratır
    • Saf veri dönüşümü (data-in, data-out) yaklaşımı her zaman güvenle paralel çalıştırılabilir
  • Clojure, JVM’in mevcut eşzamanlılık özelliklerinden (java.util.concurrent) yararlanırken daha yüksek seviyeli soyut araçlar sunar
    • Atoms: CAS (Compare-and-Set) ve otomatik yeniden deneme ile atomik işlemler sağlar
    • Refs: Software Transactional Memory (STM) sunar
    • Agents: Güncellemeleri asenkron biçimde uygulayan yaklaşım
    • Futures: Thread pool tabanlı fork-and-join arayüzü sağlar
  • core.async kütüphanesi de sunulur
    • Go’nun goroutine’ine benzer CSP (Communicating Sequential Processes) desenini destekler
    • Erlang/Elixir’in Actor modeli ve Scala’daki Akka ile karşılaştırılabilir
  • Clojure’un yüksek seviyeli soyutlama araçları kullanılmadan da daha düşük seviyeli eşzamanlılık kontrol teknikleri uygulanabilir
    • Senkronize kuyruklar, atomik referanslar, lock’lar, semaphore’lar, çeşitli thread pool’lar ve manuel thread yönetimi gibi olanaklar vardır
  • Gerektiğinde ince ayarlı eşzamanlılık kontrolü mümkündür, ancak çoğu durumda soyut araçları kullanmak daha güvenli ve verimlidir

Yerel akıl yürütme (Local Reasoning)

  • Aynı anda kavranabilecek kod karmaşıklığının bir sınırı vardır
  • Programın durumu ve değişiklikleri birden çok yerde gerçekleştiğinde, kodu anlamak ve bakımını yapmak zorlaşır
  • Clojure’un yerel akıl yürütmeyi kolaylaştırmasının nedenleri
    • Saf fonksiyon odaklı kod
      • Bir fonksiyonun davranışı yalnızca girdilere bakılarak tamamen anlaşılabilir
      • Fonksiyon dışındaki durumu hesaba katmak gerekmez
    • Nesne yönelimli dillerden farkı
      • Clojure, çok biçimliliği (polymorphism) sınırlı tutarak kodun nerede çalıştığını kolayca anlamayı sağlar
      • Nesne yönelimli programlamada (OOP) “her şey başka bir yerde olur”;
        Clojure’da ise yalnızca namespace içinde tanımlı fonksiyonları izlemek yeterlidir
  • Clojure’un tutarlı sözdizimsel yapısı sayesinde kodu refactor etmek kolaydır
    • Değiştirilemez veri ve saf fonksiyonların kullanımı, kod değişikliklerinde beklenmedik yan etkileri azaltır
    • En az düzeydeki emirsel kod ayrı tutulur, böylece emirsel kod ile işlevsel kod uyumlu biçimde bir araya getirilebilir

Kolay test

  • Clojure’da saf fonksiyon temelli kod, girdi verip çıktı kontrol ederek test edilebilir
    • Test için karmaşık durum başlatma, mock nesneleri kurma ya da zamanlama kontrolü gerekmez
    • Bu nedenle testlerin güvenilirliği artar ve “flaky” testler daha az görülür
  • İleri düzey bir test tekniği olan Property Based Testing (Generative Testing) desteklenir
    • Rastgele girdiler üretilerek belirli özelliklerin veya değişmezlerin ihlal edildiği durumlar aranır
    • En küçük başarısız örneği bulan shrinking tekniği de desteklenir
  • Bu kavram Haskell’de ortaya çıktı ve birçok dilde QuickCheck tabanlı test çerçeveleriyle uygulandı
  • Clojure’un değiştirilemez veri yapıları ve REPL tabanlı geliştirme biçimiyle sinerji kurarak daha da etkili hale gelir

Clojure geliştiricisi işe almanın avantajları

  • Genel olarak JavaScript, Python gibi popüler dillere kıyasla Clojure geliştiricisi sayısı daha azdır
  • Ancak Clojure geliştiricisi az olduğu gibi, Clojure kullanan şirket sayısı da çok fazla değildir
    • Bu nedenle genel arz-talep dengesi korunur
    • Gerçekte Clojure geliştiricisi arayan şirketlerle geliştiriciler çoğu zaman uygun şekilde eşleşir
  • Clojure geliştiricileri çoğu zaman yüksek seviyede problem çözme becerisine sahiptir
    • Sadece popüler teknolojileri öğrenmek yerine, yeni düşünme biçimlerini ve fikirleri araştıran geliştiriciler çoktur
    • Clojure kullanan şirketler pratikte başvuru sayısının az ama geliştirici kalitesinin yüksek olduğunu değerlendirir
    • Örnek: Nubank, Brezilya’da yüzlerce geliştiriciyi doğrudan Clojure konusunda eğiterek başarılı bir örnek oluşturdu
  • Clojure geliştiricisi bulmak zor olsa da, uygun kişiyi bulduğunuzda çok yetenekli bir geliştirici kazanma ihtimali yüksektir
    • Yalnızca dil deneyimi olan birini aramak yerine, öğrenme becerisi yüksek geliştiricileri eğitmek de iyi bir tercihtir
    • Clojure topluluğunun kendisi de problemleri derinlemesine düşünen ve çözen geliştiricileri çekme eğilimindedir

Trade-off’lar ve soyutlama düzeyini ayarlama

  • Clojure, yüksek seviyeli (high-level) bir dildir; kısa, öz ve ifade gücü yüksek kod yazımını hedefler
    • İşlevsel (değiştirilemez) veri yapıları ve güçlü veri işleme API’leri sayesinde gereksiz karmaşıklık azalır
  • Clojure’un veri yapıları, değiştirilemezliği garanti etmek için içeride ağaç yapıları (Hash Array Mapped Trie) kullanır
    • Güncelleme sırasında path copying oluşur ve bu GC (garbage collection) yükünü artırabilir
    • Java ile birlikte çalışırken çalışma zamanında reflection, boxing/unboxing da ortaya çıkabilir
    • Genel uygulamalarda bu maliyet çoğu zaman ihmal edilebilir düzeydedir ve geliştirici üretkenliği kazancı çok büyüktür
  • Gerçek zamanlı grafik motorları, sinyal işleme, sayısal hesaplama gibi yüksek performans gerektiren alanlarda düşük seviyeli optimizasyon mümkündür
    • Clojure’da type hint vererek reflection ortadan kaldırılabilir ve ilkel tip işlemleri optimize edilebilir
    • Ardışık ilkel tip dizileri kullanılarak CPU cache’den yararlanılabilir
    • GPU hızlandırma kütüphaneleri kullanılabilir
  • Çoğu yüksek seviyeli dilde performans kritik olduğunda C/Rust gibi yerel uzantılara ihtiyaç duyulur, ancak
    Clojure, JVM optimizasyonlarını (JIT derleme) kullanarak performans sorunlarının büyük bölümünü çözebilir
    • Profiling ve küçük optimizasyonlarla event loop gibi yapıların performansı en üst düzeye çıkarılabilir

Metaprogramlama ve veri odaklı API’ler

  • Clojure, Lisp ailesinden geldiği için kodu veri gibi ele alabilir
    • JSON’a benzer ama daha okunabilir bir yapı ile programları ifade etmek mümkündür
    • EDN (Extensible Data Notation) adlı veri formatı sayesinde JSON benzeri veri ifadesi sunar
  • Clojure, macro’larla kodun kendisini dönüştürme yeteneği sağlar
    • Ancak Clojure topluluğunda macro kullanımını dikkatli sınırlama kültürü vardır
    • Macro’lar hata ayıklamayı zorlaştırabilir ve statik analiz araçlarıyla uyumu düşürebilir
  • Bunun yerine veri odaklı (data-driven) API tasarımı tercih edilir
    • Örnek: HTTP routing, HTML/CSS üretimi, veri doğrulama
    • Belirli fonksiyonları doğrudan çağırmak yerine, davranış veri yapıları (map, vector) ile tanımlanır
    • Veri tabanlı API’ler dinamik olarak manipüle edilebilir ve kullanıcı ayarlarını kolayca kaydetmeye ve değiştirmeye uygundur
  • Veri odaklı API’ler sayesinde sistem çalışma anında dinamik olarak yeniden yapılandırılabilir
    • Bu da yüksek esnekliğe sahip simülasyon sistemleri, dinamik yapılandırma yönetimi ve metaprogramlamayı kolayca hayata geçirmeyi sağlar

Java ile birlikte çalışabilirlik (Interop) ve ekosistemden yararlanma

  • Modern uygulama geliştirme, çok sayıda açık kaynak kütüphane ve API’yi bir araya getirme sürecidir
    • Clojure JVM üzerinde çalıştığı için Maven Central’daki milyonlarca Java paketinden yararlanabilir
    • Reflection olmadan da Java kütüphanelerini kolayca çağırmak mümkündür
  • Clojure, Java’ya göre çok daha kısa ve öz kod sunar; REPL ile deneysel programlama yapmak da kolaydır
    • API’leri Java’ya göre çok daha hızlı keşfedip birleştirmek mümkündür
    • ClojureScript ile aynı yaklaşım kullanılarak JavaScript ve NPM ekosisteminden de yararlanılabilir

Fikir odaklı kültür

  • Hangi dil kullanılırsa kullanılsın başarılı projeler mümkündür; tersine yanlış kullanımla her dilde başarısız olunabilir
    • İyi araçlar iyi geliştiriciler yaratmaz
  • Clojure’un giriş eşiği yüksektir ve öğrenme sürecinde deneme-yanılma gerekir, ancak bu süreç daha derin düşünmeye imkân verir
  • Bazı Clojure projelerinde Java veya Python tarzı yazım alışkanlıkları kaldığı için dil tam anlamıyla değerlendirilemez
    • Ancak Clojure’un felsefesini ve fikirlerini benimseyen ekipler daha iyi yazılım tasarlama yetkinliği kazanır
  • Clojure topluluğu, mevcut geliştirme biçimlerini sürekli sorgular ve daha iyi yöntemler araştırır
    • Rich Hickey’nin konuşmaları, yalnızca teknik tanıtım değil, yazılım tasarımının temel ilkelerini irdeleyen içeriklerdir
    • Clojure konferanslarında kütüphane tanıtımlarından çok fikirler, makale analizleri ve deneyim paylaşımı öne çıkar

Sonuç

  • Clojure, yalnızca bir programlama dili değil, daha iyi yazılım geliştirme yollarını düşünen insanların topluluğudur
  • Bu toplulukta kişinin kendi sınırlarını genişletmesi ve yeni olasılıkları keşfetmesi temel bir değerdir
  • Böyle bir kültürde gelişen geliştirici, sadece Clojure’u iyi kullanan biri olmanın ötesine geçer; daha iyi problem çözme becerilerine sahip bir yazılım mühendisi haline gelir

3 yorum

 
roryk 2025-02-26

Ben de kişisel olarak Clojure kullanıyorum ve metindeki görüşlere büyük ölçüde katılıyorum.
İş tarafında ağırlıklı olarak Python ve Java(Type)Script kullandım; ancak biraz bile bakım yapılmadığında hem dilin kendisindeki hem de kütüphanelerdeki değişimlere ayak uydurmak zorlaşıyor ve kod kolayca legacy hale geliyor. Buna karşılık Clojure’da bir kez yazdığım koda bir yıl sonra dönüp baktığımda bile hemen düzenleme ve geliştirme yapabilmenin çok kolay olması beni son derece memnun etti.
Ondan sonra da kişisel projelerde, belirli bir kütüphanenin zorunlu kıldığı durumlar dışında, Clojure’u sıkça kullanıyorum.

 
plumpmath 2025-02-25

Neden Clojure?

Jank Jank~!

 
GN⁺ 2025-02-25
Hacker News görüşleri
  • En çok hangi tür programlamadan keyif aldığım sorulursa, shell üzerinde veri işleyen pipeline'lar kurmak ve son 5 yıldır Clojure ile ClojureScript yazmak derim

    • Şu anda 4 kişi birlikte Clojure yazıyoruz ve toplamda 30 yılı aşkın Clojure deneyimine sahibiz
    • Prag'da Clojure'u tercih eden bir danışmanlık şirketi kurduk ve bunun çeşitli sistemler için uygun bir seçim olabileceğini düşünüyoruz
  • Clojure'u 12 yıldır kullanıyorum; ondan önce de 12 yıldan uzun süre Java kullandım

    • Clojure ve Java ile harika uygulamalar ve kütüphaneler yaptım
    • Clojure'u "en az kötü programlama dili" olarak tanımlıyorum; çekirdeği güçlü ve kararlı
    • Araçlara hakim olunca çalışma hızı ve hassasiyet artıyor
    • Clojure'un REPL odaklı iş akışı önemli bir değer önerisi
  • Clojure yazmayı seviyorum ve başka dillerle kıyaslasam bile Clojure'a duyduğum derin sevgiyi ayrıca açıklamam gerekmiyor

    • Başka dillere dair kişisel sorunlarla ilgilenmiyorum; Clojure sevgim teorik, pratik, duygusal ve finansal nedenlere dayanıyor
    • Clojure kusursuz değil ama genel amaçlı programlama dilleri arasında en tatmin edici olanı
  • Kurucu ortak, mümkün olan en küçük şirketle mümkün olan en büyük ürünü üretmeyi hedefliyor

    • 5 yıl boyunca bootstrap ederek 1 milyon doların üzerinde ARR'ye ulaştık ve Clojure bunda büyük rol oynadı
    • Clojure, programcı olarak mutluluğuma da katkı sağladı ve gelecekte Clojure çekirdek ürün ekibini büyütmeyi planlıyorum
  • Clojure kullanarak 10 yıl boyunca bir SaaS işi yürüttüm ve Clojure olmasaydı bu mümkün olmazdı

    • Dilin kararlılığı çok faydalı; diğer ekosistemlerde yazılımı sık sık yeniden yazmak gerekebiliyor
    • Yüzeysel eleştiriler yerine, dili gerçekten kullanmış kişilerin içgörülü yazılarını okumayı tavsiye ederim
  • Clojure kullananlara <a href="https://www.flow-storm.org/">Flow Storm</a> tavsiye ediliyor

    • İyi bir test paketiyle birlikte kullanıldığında farklı senaryoları tetikleyebilirsiniz
  • Rich Hickey'den çok şey öğrendim ve Clojure ile FP'ye karşı büyük bir tutkum vardı

    • Ancak iş büyüdükçe dinamik tipleme bir yük haline geldi ve kilit kişiler ayrıldıktan sonra Clojure geliştiricisi bulmakta zorlandım
    • Şu anda stack'imizin büyük kısmı Python ve Go'dan oluşuyor
  • ClojureDocs belgelerinin eski olduğuna dair bir eleştiri vardı ve yanıtlara oy verilebilmesini sağlayan bir özellik eklemek istiyordum

    • Google algoritması sayesinde ClojureDocs ağırlıklı olarak kullanılıyor
  • Clojure'un kararlılığıyla ilgili kısım şaşırtıcı geldi; çünkü her yıl denediğimde her şeyin değişmiş olduğunu hissettim

    • "Hello World" çalıştırmak hâlâ yavaş mı diye merak ediyorum; Clojure'u okumak keyifli ama yazmak her zaman bir engel olmuştu
  • Common Lisp ile başladıktan sonra Go ve Rust'a geçtim ama son zamanlarda tekrar Clojure'a bakıyorum

    • REPL ve interaktif programlama sayesinde işleri hızlıca halledebilirsiniz
    • JVM harika bir runtime