Neden Clojure?

Clojure JVM(Java Virtual Machine), CLR(Common Language Runtime) ve JavaScript platformları üzerinde çalışabilen fonksiyonel bir Lisp programlama dili türüdür.

Uzun bir süredir aklımda Lisp’i öğrenmek vardı. Bunun sebebi ise üniversitede Chris Stephenson Hocam’dan aldığım bazı derslerde, kendisinin Racket(bir Lisp dialekti) dili üzerinden dersi işlemesi ve fonksiyonel programlamayla ilgili kuvvetli söylemlerinin yölendirmesidir. Bütün bunlar beni Lisp dilini araştırma konusunda düşünmeye sevk etti.

Ardından uzunca bir araştırmayla Lisp kullanan insanların internette tecrübelerini okudum/izledim ve bütün bu araştırlamalarımın bana en ilginç gelen yanı ise bu kişilerin dile karşı bir tür gizli uzay teknolojisiymiş tarzı yaklaşımları oldu.

Paul Graham adlı abimizin Lisp ile olan deneyimleri hatta Hacker News sitesini bizzat icat etmiş olduğu bir Lisp dialekti(Arc) ile yazması muazzam derecede merakımı arttırdı.

Tamam dedim. Şimdi sıra bir Lisp dialekti seçmede. Biraz araştırma sonucu bir çok Lisp türevleri arasında Clojure dilini buldum ve baktım ki JVM üzerinde çalışıyor ve bir Java geliştiricisi olarak bildiğim ve aşina olduğum bir platform. Topluluk hakkındaki yorumlar da çok olumluydu ve yavaştan başlangıç adımını atmış bulundum.

Clojure’a başlayalı yaklaşık 2.5 yıl oldu ve şimdi bu yazının başlığı olan “Neden Clojure?” ve neden önceki uğraştığım(Java, JavaScript vs.) teknolojilere geri dönüp bakmak istemiyorum ondan bahsedeceğim.

#1 Sadelik

Clojure dili çok sade ve basit bir yapıya sahip ve aynı şekilde sözdizimi de çok yalın. Örneğin aşağıdaki toplama işlemine bakacak olursak:

(+ 1 2)
=> 3

Parantez aç, çağrılacak fonksiyon ismi, parametreler, parantez kapat işte tüm dil bundan ibaret ve artık siz de Clojure nasıl yazılır biliyorsunuz. Gerisi biraz ayrıntı diyelim. :)

İşin güzel tarafı, 1958 yılında yazılan ilk Lisp versiyonu ile şimdikiler aynı semantiği kullanmaktadır. Yani Java gibi dillerde versiyondan versiyona oluşan sözdizimi evrimleri söz konusu değildir.(bknz. Java 7/8) Çekirdek yapısı çok sade ve basit tutulmuştur ve bu dile hoş bir ayrıntı katmaktadır.

#2 Java Interop

Dilin yaratıcısı Rich Hickey’nin, Clojure’u JVM üzerinde yazmasının çok pragmatik ve stratejik bir sebebi var. JVM üzerinde yazıldığı için Clojure hali hazırda olan tüm Java kütüphanelerine framework’lerine erişim sağlayabilmektedir. Yani Clojure kodundan Java kodu çağırabilirsiniz; tam tersi de mümkündür.

JVM üzerinde yazılan dillerin böyle büyük bir mirasa konması çok büyük bir avantaj olduğu göz ardı edilemez. Özellikle enterprise yazılımlar geliştirilmesi söz konusu ise.

Aşağıdaki örnekte Java’daki Character sınıfının isUpperCase() methodunu kullanarak verilen String’in tüm karakterleri büyük harf mi onu kontrol ediyoruz:

(every? #(Character/isUpperCase %) "HELLO")
=> true

#3 REPL(Read Eval Print Loop)

REPL Lisp programcılarının olmazsa olmaz gizli silahıdır, interaktif bir şekilde yazdığınız program ile anlık iletişim kurup onu evrilttiğiniz bir araçtır.

Aslında dil için bir çeşit shell gibi düşünebilirsiniz. Örneğin bilgisayarınızda python yüklüyse, terminalden python yazdığınızda, python kodunu çalıştırabileceğiniz bir shell çıkar. REPL da budur zaten(tabi bu Lisp’te çok daha gelişmiştir).

Clojure camiasında artık REPL Driven Development söylemleri bitmek bilmiyor ve çok popüler olmuş durumda. Bunun sebebi ise çok üretken ve hızlı bir şekilde kod yazabilmenizdir. Hızlı geri bildirimlerle bug bulma, özellik ekleme/çıkarma gibi işlemler kolaylıkla yapılır.

Dinamik bir dil olması itibari ile çok ciddi avantajlar söz konusudur. Örneğin web uygulamanızı ayağa kaldırdınız fakat ardından ekrana yazılacak bir mesajda hata fark edip değiştirdiniz(veya daha karmaşık bir değişiklik), Clojure altındaki Java Byte kodunu hızlı bir şekilde değiştirip istediğiniz değişikliğe hemen sahip olabiliyorsunuz. Bu da ciddi derecede size zaman kazandırıyor.

Eğer Java tarzı bir dil ile böyle bir değişiklik yapmak durumundaysanız ne yazık ki uygulamayı tekrar başlatmak durumundasınız.

Clojure’un buradaki en büyük avantajı ise JVM gibi güçlü bir sistemin altında bu kadar esnek ve dinamik olabilmesidir. Hem dinamik, hem multi-threaded (Python, Ruby aksine), hem JVM üstünde çalışıyor daha ne isteriz ki :)

#4 Macro

Lisp’in macro sistemini öğrendikten sonra gerçek anlamda bir aydınlanma yaşadım. Buradaki macro sistemi dili genişletmenize olanak sağlıyor; bir nevi dile özellik katıyorsunuz gibi düşünebilirsiniz. Aslında macro derleme anında (compile time) sizin yerinize fonksiyon(lar) üreten bir çeşit fonksiyondur.

Yani istemediğiniz tekrarlanan kodlardan (duplicate code) güzel macrolar yazarak kurtulabilirsiniz.

Örnek verecek olursak aşağıdaki gibi iç içe geçmiş bir fonksiyon dizimiz var diyelim:

(if-let [a 1]
(if-let [b 2]
(if-let [c 3]
(+ a b c))))
=> 6

Şimdi malumunuz, burada görülen kod hiç iç açıcı değil, fakat ben derleme anında bu kodu üretecek ama yazarken daha zarif bir sözdizimine sahip bir macro yazarsam işler benim istediğim gibi olur.

if-let* adlı macromuzu yazalım o zaman:

(defmacro if-let*
([bindings then]
`(if-let* ~bindings ~then nil))
([bindings then else]
(if (seq bindings)
`(if-let [~(first bindings) ~(second bindings)]
(if-let* ~(vec (drop 2 bindings)) ~then ~else)
~else)
then)))

Biliyorum çok karışık gözüküyor fakat macro örneği göstermek amaçlı sadece.

Şimdi o iç içe giren kod, benim için üretilecek fakat benim yazacağım kod sadece şu şekilde olacaktır:

(if-let* [a 1
b 2
c 3]
(+ a b c))
=> 6

Tabii ki çok daha karmaşık örnekler söz konusu olabilir. Macro sayesinde çalıştığım projelerde çok büyük ölçüde kod azalması şansına ve daha temiz bir koda sahip olma şerefine nail olabiliyorum.

Java programcıları bilirler Java 7 versiyonuna try-with-resources özelliği geldi. Böylelikle try()’in içine yazılan IO sınıfları otomatik bir şekilde işlemleri bitince kapatılıyor. Clojure’da with-open adlı bir makro bu işlemi standart kütüphanede halletmiş mesela.

Kısaca Clojure’da diğer dillerde olduğu gibi versiyondan versiyona ufak değişiklikler için bile beklememize gerek yok: Macro yazarak bu tür özellikleri kendimiz ekleyebiliyoruz.

#5 Concurrency(Eş Zamanlı Programlama)

Dilin yaratıcısı çok uzun yıllar ağırlıklı olarak concurrent(eş zamanlı) sistemler üzerinde çalışmış ve çalışırkende Java, C# ve C++ gibi çeşitli diller kullanmış. Kendisi röportajlarında bu mutable dillerle concurrent sistem yazmaya çalışmanın, saçlarını yoldurtan cinste zorluklarından bahsetmektedir ve bu problemin asıl sebebinin mutable by default olmalarından kaynaklandığını söyler.

Aslında Rich Hickey, Clojure’u kendisi için yazdığını söyler. Bu işi bu zorluklarla yürürütmek zor olduğundan, concurrent sistemler için immutable by default olan Clojure’u geliştirmiştir. Immutable data başka bir thread’e yollandığında değişmeyeceği bilindiği için bu temel sorun ortadan kalkmaktadır.

Clojure’un en büyük iddialarından bir tanesi eş zamanlı programları kolay, eğlenceli ve aynı zamanda çok daha az hataya ihtimal vererek tasarlanmış olmasıdır.

Ayrıca dil, 4 adet mutable referans tipine sahiptir ve bunlar state management konularında işimizi çok kolaylaştırmaktadır.

Var: Local scope

Atom: Atomic field(Java’daki AtomicBoolean gibi)

Agent: Async programming(Scala’daki Actor sistemi benzeri)

Ref: STM(Software Transaction Memory) birden fazla değişkenin state’ini koordineli bir şekilde değiştirmeyi ve deadlock gibi durumların olmayacağını garanti eder. Database transaction’larına benzer bir yapıya sahiptir.

#6 ClojureScript

ClojureScript Clojure’un JavaScript platformu üzerinde çalıştığı versiyonudur. Yani siz Clojure kodu yazıp sonunda optimize bir JavaScript koduna sahip olursunuz.

Frontend ve backendde çalışırken tek bir dil kullanırsınız ve böylelikle motivasyon ve zaman avantajınız söz konusu olur. Yani sunucu tarafında Java yazarken, önyüzde React yazdığınızdaki mental context switch olmaz.

Hatta Clojure ve ClojureScript aynı kodu paylaşabilmektedir. Böylelikle kodu bir kere yazıp hem önyüz hem de sunucu tarafında kullanabiliyoruz.(Örnek: Validation)

Full Stack developer olma konusunda bu teknolojiler güzel imkanlar sağlıyor diyebilirim.

#7 Topluluk

Clojure topluluğu gerçekten çok sevimli, yardım sever ve genel olarak yaşını başını almış, tecrübeli abilerimiz ve ablalarımızdan oluşmaktadır. Tabii ki diğer dillerin topluluğu kadar büyük değil. Niş bir teknoloji ekosistemi olduğu için alçakgönüllü, ufak ve sempatik bir hacme sahip.

Berlin’de sürekli gittiğim Clojure buluşmalarında gördüğüm kadarıyla, Clojure’cu profili genel olarak 15+ yıl tecrübeye sahip chief scientistler, matematikçiler ve developerlardan oluşan bir grup güzel insan diyebilirim.

Reddit’in Clojure sayfası oldukça aktif bir oluşum ve isteyen istediği şeyi sorup rahatlıkla cevabını alabiliyor.

#8 Kaynaklar

Eğer buraya kadar sıkılmayıp okuduysanız ve dile ufak bir şans vermek istiyorsanız sizlere Clojure’u öğrenme adımları için kaynaklar paylaşacağım.

# Final

Clojure, programlamaya bakış açımı tamamen değiştirdi. Kendimi öncekine göre daha üretken, daha hızlı ve daha motive bir geliştirici olarak buldum.

3 Java/tarzı programcısının yapacağı işi, bir Clojure programcısının yapabileceği bir durum oluştu.(Bu dediğimi profesyonel olarak Clojure yazanlara sorduğunuzda bana katılacaktırlar. :))

Benimle aynı şekilde bu değişimin bir parçasına sahip olan, Türkiye’de Clojure geliştiren 2 güzel insan tanıyorum. Bu kişiler Umut Gökbayrak (TalentAds’de birlikte çalışıyoruz) ve Üstün Özgür’dür.

Türkiye’de güncel olarak -bildiğim/duyduğum- “Clojure Developer” ünvanı ile proje geliştiren yaklaşık 5 kişi var.

Umarım bu sayı ilerleyen zamanlarda ülkemizde de artar. Çünkü bir çok iş için doğru bir teknoloji olduğunu ve programlama dili çeşitliliğinin topluluğumuzda artmasına ihtiyaç olduğunu düşünüyorum.

Sevgiler…