Zig'in gerçek dünyadaki CLI araç geliştirmede neden Rust'tan daha pratik hissettirdiği
(dayvster.com)- Bellek yönetimi konusunda Zig, Rust'a kıyasla daha basit ve sezgisel bir yaklaşım sunar
- Rust'un borrow checker'ı güçlüdür, ancak küçük CLI araçları geliştirirken gereğinden fazla karmaşıklık ve geliştirici yükü yaratır
- Zig'in manuel bellek yönetimi, uygun araçlar ve biraz geliştirici disipliniyle verimli bellek güvenliği sağlama imkanı sunar
- Program güvenliği, bellek güvenliğinin ötesinde öngörülebilir davranış, yönetilebilir performans, veri koruma gibi çeşitli unsurları da kapsar
- Rust büyük ölçekli sistemler için uygundur, ancak küçük ve pratik CLI araçlarında Zig, geliştirme verimliliği ve bakım açısından daha avantajlıdır
Genel Bakış
Son zamanlarda CLI araçları geliştirirken Rust yerine öncelikli olarak Zig'i seçiyorum.
Bellek Yönetiminin Temeli: Stack ve Heap
- Stack, fonksiyon parametreleri, yerel değişkenler, dönüş adresleri gibi çok geçici verileri saklayan hızlı ve sabit boyutlu bir bellek alanıdır
- Heap, dinamik bellek tahsisi için kullanılan alandır; verinin ömrü uzun olduğunda veya boyutu çalışma zamanında belirlendiğinde tercih edilir
- Stack yapısal olarak basittir ama alanı sınırlıdır; heap ise hız ve parçalanma açısından daha fazla dikkat gerektirir
Rust'un Borrow Checker'ı
- Rust'un borrow checker'ı, derleme zamanında bellek güvenliğini garanti eder
- Referans, sahiplik ve yaşam süresi (
lifetime) gibi kuralları zorunlu kılarak null pointer dereference, dangling pointer gibi hataları daha oluşmadan engeller - Ancak bellek güvenliği yalnızca derleme zamanı ölçütlerine göre denetlenir; kullanıcının hatalarını ya da karmaşık sahiplik tasarımı sorunlarını tamamen ortadan kaldırmaz
Örnek: Kendi Notes CLI Aracım
- Kişisel not yönetimi için bir CLI aracını Rust ile yazmaya çalışırken borrow checker nedeniyle yapıyı zorlayarak yeniden tasarlamak zorunda kaldım
- Buna karşılık Zig'de yalnızca allocator kullanarak pointer tabanlı indeks oluşturma ve serbestçe değiştirme/silme işlemleri çok daha basit şekilde yapılabildi
- Rust'un borrow checker'ının amacı nettir; ancak Zig, temel bellek yönetimi bilgisi ve disiplinle bile yüksek düzeyde verimlilik ve güvenlik sağlamayı mümkün kılar
Bellek Güvenliğinin Ötesinde CLI Araçlarında Güvenlik
- Bir ürünün gerçek güvenliği; öngörülebilir davranış, hata durumunda anlamlı geri bildirim, hassas verilerin korunması, saldırılara dayanıklılık gibi birçok unsuru içerir
- Rust da Zig de bellek güvenliği dışındaki koşulları karşılamıyorsa "güvenli" sayılmaz
- Örneğin bir CLI, hata durumunda sessizce verinin üzerine yazıyor ya da dosya izinlerini yanlış ayarlıyorsa kullanıcı ciddi sorunlar yaşayabilir
-
CLI araçlarında güvenlik
- Öngörülebilir davranış: Hatalı girişte veya beklenmeyen durumlarda bile tutarlı ve açık davranış garanti edilmelidir
- Çökme ve veri bozulmasını önleme: Hatalar zarif biçimde ele alınmalı; veri bozulması veya raporlanmayan çökme durumları engellenmelidir
- Performans yönetimi: Büyük miktarda veri işlendiğinde bile kaynak tüketimi veya yanıt verebilirlikte bozulma olmamalıdır
- Hassas bilgilerin korunması: Geçici dosyalar ve izin ayarları konusunda dikkatli olunmalıdır
- Saldırılara dayanıklılık: Girdi doğrulama, bellek taşması, injection saldırıları gibi durumlara karşı sağlam olunmalıdır
Rust Borrow Checker'ın Güçlü ve Zayıf Yanları
-
Güçlü yanlar
- Veri yarışı ve yinelenen referansları engelleme: Derleyici, tek bir mutable referans ve birden çok immutable referans kuralını garanti eder
- Güçlü derleme zamanı garantileri: Bellekle ilgili hataların çoğu çalıştırmadan önce engellenir
- Hataları erken bulma: Ticari servislerde veya eşzamanlılık içeren sistemlerde büyük avantaj sağlar
-
Sınırlar ve zorluklar
- Bilişsel yük: Küçük CLI işlerinde bile sahiplik/yaşam süresi/referans yönetimi üzerine düşünmek kaçınılmazdır
- Boilerplate / yapısal çarpıtma:
Rc,RefCellgibi wrapper'lar, aşırıclonekullanımı, yapıyı yeniden tasarlama gibi nedenlerle "sorun çözmeye" değil "derleyiciyi memnun etmeye" odaklanılır - Mantıksal / durumsal hatalar karşısında etkisiz kalma: Yalnızca bellek kurallarını garanti eder; öngörülebilirlik, mantık hataları veya veri bütünlüğünü garanti etmez
- Uç durum karmaşıklığı: Cache, global durum, mutable index gibi yapılarda lifetime çatışmaları kolayca ortaya çıkabilir
- Sonuç olarak küçük CLI projelerinde Rust'un borrow checker'ı geliştirici için bir "zihinsel vergi" haline gelir ve gereğinden fazla karmaşıklık yaratabilir
Zig'in Güvenlik ve Basitlik Yaklaşımı
- Zig, isteğe bağlı güvenlik kontrolleri ve manuel bellek yönetimi temeline dayanır
- Yerleşik allocator kavramı sayesinde yapısal ve öngörülebilir bellek kullanımı uygulanabilir
- Hatta özel allocator'lar oluşturarak projenin özelliklerine uygun bir bellek yönetimi yaklaşımı belirlemek mümkündür
- Zig'in
defersözdizimi sayesinde kapsam sonlandığında otomatik serbest bırakma ve kaynak temizliği çok daha sezgisel hale gelir - Rust'tan farklı olarak geliştirici sorumluluğunu öne çıkarır; disiplin gerektirir, ancak yapı iyi tasarlanırsa bellek güvenliğine ulaşmak ve bunu korumak kolaydır
- Zig'de kod daha sadedir; pointer, liste ve index gibi yapıların değiştirilmesi Rust'a kıyasla çok daha basittir
- Rust'taki kadar kısıtlanmadan da aynı düzeyde güvenli ve verimli kod yazmak mümkündür
- Buna ek olarak Zig'in comptime özelliği, derleme zamanında kod çalıştırma, test ve optimizasyon için büyük fayda sağlar
Geliştirici Deneyiminin (Developer Ergonomics) Önemi
- Geliştirici deneyimi (ergonomics), dilin sözdizimi, araçları, dokümantasyonu ve topluluğunu kapsayan bir unsurdur
- Rust, çok katı kuralları sayesinde nihayetinde bellek güvenliği sağlar; ancak aşırı kuralcılık ve ceremony üretkenliği düşürür
- Zig, geliştirici odaklı tasarımı öne çıkararak kodu daha kolay ve hızlı yazmayı, değiştirmeyi ve anlamayı mümkün kılar
- Zig, sezgisel kod, hızlı yineleme, düşük zihinsel yük sayesinde geliştiricinin araçlarla boğuşmak yerine probleme odaklanmasını sağlar
- Zig geliştiriciye güvenir ve uygun araçlarla seçim özgürlüğü sunar; buna karşılık Rust zaman zaman fazla denetleyici ve kısıtlayıcı hissettirebilir
- Geliştirici dostu ortam, geliştiriciyi sadece "hatalardan korumak" değil, kendi hatalarından öğrenip gelişme fırsatı vermek anlamına da gelir
Sonuç
- Büyük, çok iş parçacıklı, uzun süre çalışan sistemler gibi Rust'un avantajlarının en üst düzeye çıktığı alanlarda Rust hâlâ en iyi seçimdir
- Ancak küçük ve pratik CLI araçları için Zig'in hafifliği, sadeliği, hızlı geliştirme ve bakım kolaylığı daha uygundur
- Bellek güvenliği, güvenlik yapbozunun yalnızca bir parçasıdır; öngörülebilir davranış, bakım kolaylığı ve dayanıklılık gibi CLI araçları için kritik unsurlar Zig'de daha kolay sağlanabilir
- Sonuçta önemli olan "daha iyi dil" değil, **kişinin iş akışına ve projenin özelliklerine uygun "doğru aracı seçmek"**tir
- Zig, "bellek güvenliği + düşük zihinsel maliyet + geliştirici dostuluğu / üretkenlik" birleşimiyle küçük araç geliştirme için çok iyi uyum sağlayan bir dildir
3 yorum
Bence ekosistemi henüz Rust kadar istikrara kavuşmuş görünmüyor.
Zig’de yeni sürümlerde kırıcı değişiklikler oldukça sık olduğu için... küçük bir proje olsa bile mümkünse CI ekleyip düzenli olarak yönetmek gerektiğini fark ettim.
Hacker News görüşü
Zig'in avantajı, C geliştiricisi gibi düşünmeye devam etmeyi sağlaması; ama bunun bir noktaya kadar sadece aşinalık meselesi olduğunu düşünüyorum
Rust'a yeterince alışmış geliştiriciler artık borrow checker ile savaşmıyor; zaten kodu o yapıda düşünmeye başlıyorlar
Rust'ta “object soup” benzeri bir yaklaşım pek işlemiyor ama bunun temelde daha kolay bir yöntem olduğunu da sanmıyorum; sadece alışık olduğumuz için kolay geliyor
ergonomics'i ölçmenin ya da sayısallaştırmanın zor olduğunu kabul edince, bu tür tartışmalar doğal olarak muğlak kalıyor
“borrow checker ile savaş” söylemi, Rust'ta sadece lexical lifetime'ların anlaşıldığı dönemden kalma bir anlatı
Benim deneyimimde usta Rust geliştiricileri her yere Arc serperek onu fiilen otomatik garbage collection gibi kullanıyor
Usta Rust geliştiricilerinin bile açık kaynak Rust projelerinde her yere Arc, Clone, Copy vb. kullandığını çok gördüm
Zig'in artısı, C'deki tanıdık geliştirme tarzını korurken dil ve tooling tarafında güvenliği destekleyen özellikler sunması
Ben asıl yazının çoğuna katılmıyorum
Rust da C veya Zig gibi lifetime, ownership ve borrow scope üzerine düşünmeyi gerektiriyor; fark, derleyicinin yardım edip etmemesi
Ne kadar zeki olursan ol, yorgunken ya da dikkatin dağınıkken hata yapmak insanidir; bunu kabul etmek akıllıcadır
Rust derleyicisinin güvenli saydığı programlar kümesi yeterince geniş değil; bu yüzden gayet normal programları epey sık reddediyor
Örnek: Foo adlı bir struct içinde
barvebazayrı string'lerse,bariçin mutable reference aldıktan sonrabaziçin immutable reference almaya çalıştığında derleme başarısız olur; böyle durumlarda kod yapısını zorla dolandırmak zorunda kalırsınBuna karşılık şu da var: “gerçekte sorun olmayan bir durumun derleyici tarafından reddedilmesini önlemek için” kodu ikinci ya da üçüncü en iyi tasarıma çevirmek başlı başına büyük bir yük
Bu örnek gerçekten çok iyi görünüyor; blogumda ya da bir yazıda ele almamda sakınca olur mu diye sormak isterim
O kodu görünce tam tersine iddiama olan güvenim biraz daha azaldı
Her programın mutlaka bu kadar "güvenli" olması gerekmediğini hatırlamalıyız
Bir sürü unsafe yazılımla eğlenerek büyüdük; Star Fox 64, MS Paint, FruityLoops gibi
Zig'in yaratıcısı Andrew Kelley'nin de, müzik prodüksiyon yazılımı (DAW) geliştirmek için uygun ortam olmadığı için Zig'i yaptığını okumuştum; Zig'in böyle yaratıcı yazılımlara iyi uyduğunu düşünüyorum
Bellek hatalarına duyarlı olan herkes Rust kullanabilir
Hatta Super Mario World'ün bellek hataları yüzünden daha eğlenceli olduğuna inanıyorum
"Güvenlik", "programım amaçladığım gibi çalışıyor" ifadesinin kısaltmasıdır
unsafe) ile bunları bilerek yapmak mümkünBiraz kafam karıştı; söylediklerimin kötü bir görüş sayılmasının nedeni bellek güvenliğinin önemsiz olduğunu ima etmem mi diye merak ettim
borrow checker'ın değerinin küçümsenmesi bana üzücü geldi
Rust'ın borrow checker'ı geçersiz bellek erişimlerini derleme zamanında engeller
Elbette bunun bedeli, kodu derleyicinin kurallarına uyan bir yapıya dönüştürmek zorunda kalmaktır
Rust'ı tek başıma kullanırken hiç lifetime annotation'ların yanlış olduğunu düşünmedim; biraz angarya gibiydiler ama hızlıca alıştım
unsafekullanmadığın sürece Rust'ta iki thread aynı belleğe aynı anda yazamaz"CLI araçlarında Zig neden daha pratik geliyor" sorusuna pek katılmıyorum; Rust'ın CVE'leri önleme tarafında hâlâ güçlü bir avantajı var
Ben zaten çoğu işi GC'li dillerle de rahatça yapıyorum; başka dillere katkı verirken de Rust, Zig, C/C++ fark etmiyor
CLI araçları özel bir kategori değil mi?
unsafekullanmadan iki thread'in aynı belleğe aynı anda yazamaması konusu da o kadar net değilRust'ta backlinks uygulamanın gereksiz yere karmaşık olduğuna katılıyorum
Rc,Weak,RefCell,.borrow()gibi araçlarla mümkün ama kolay değilKısa süreli çalışan programlarda arena allocation da bir yöntem olabilir; sanırım CLI aracı derken kastedilen de bu
Rust asıl gücünü büyük, çok iş parçacıklı ve uzun süre çalışan uygulamalarda gösteriyor
Ben gerçekten Rust ile büyük bir metaverse istemcisi yazdım ve onlarca thread'i 24 saat çalıştırmama rağmen bellek sızıntısı ya da çökme yaşamadım
Aynı şeyi C++ ile yapmak için QA ekibi ve Valgrind gibi araçlar şart olurdu; script dilleri ise performans açısından fazla yavaş kalır
Ben de Rust ile Dünya'nın eğriliğini ve yerçekimi sapmalarını hesaba katan fizik simülasyonlu bir uçak yaptım
Zig çekici ama D de hâlâ var ve kişisel olarak D'nin benim istediğim C/C++ alternatifi olduğunu hissediyorum
Zig'in sözdizimi bana biraz tuhaf geliyor; Rust ise artık ekosistemin merkez oyuncularından biri
Go da birçok dil aracında yüksek paya sahip ve yapay zeka alanında Python'dan sonra en çok kullanılan dillerden biri
Rust'tan önce Go vs. D tartışmaları vardı; ben de D kitabı bile almıştım ama sonunda Go'ya geçtim
int64gibi tür adları daha sezgiseldiD iyi ama onu yaygınlaştıracak bir killer app çıkmadı
CLI aracı yazmak için neden özellikle Rust ya da Zig seçmek gerektiğini pek anlamıyorum
Darboğaz genelde I/O'dur; GC'nin yavaşlığı değil
GC meselesi oyunlar, veritabanları gibi bellek yoğun alanlar dışında esas tartışma konusu değil
Bellek güvenliği tartışmaktan çok, neden GC'siz bir dil seçmek gerektiğini düşünmenin daha önemli olduğunu vurguluyorum
Eğer sebep “no-GC eğlenceli olduğu için” ise bu tek başına yeterlidir; ayrıca tartışmaya gerek yok
Anında startup time, yani açılışta gecikme olmaması, gerçekten çok faydalı
Go ile CLI yapmak gerçekten gayet iyiydi, her ne kadar Go dilini kendim çok sevmesem de
Ben bir dil seçerken sum type, pattern matching ve async desteğini öncelikli ararım
GC'siz geliştirmenin sadece oyun alanına özgü olduğu itirazına karşılık
GC tartışması bana biraz bandwagon etkisi gibi geliyor
Rust'ın built-in borrow/reference modeliyle basit bir not aracı yaptım ve düşündüğüm kadar karmaşık değildi
Bir
noteslistesinde indeksleri saklayıp bunları bir map ile bağlayan bir yapı düşünürsen, hız farkı neredeyse yok ve güvenlik açısından da bir eksisi yokİndekste hata yapsan bile bu, kernel belleğini ezmektense sınır aşımı hatası olarak yakalanır; bu çok daha iyi
printfdebugging sırasında da çok daha kolay ve sezgisel oluyorraw pointer ya da reference genelde allocator veya async runtime gibi gerçekten gerektiği yerlerde kullanılmalı; genel mantıkta index-based yaklaşım daha uygun
Rust async tarafında self-referential struct kullanılamadığı için
Pinile ilgili sorunların çıkmasının meşhur nedeni de buveciçine konmuş değerlerin pointer'larıreallocgibi durumlarda geçersiz olabildiğinden, bu durumda Miri hemen hata verirBir C++ geliştiricisi olarak güvenli bir dil arıyor olsam Swift bana en uygun seçenek gibi gelirdi
İnsanın tanıdık ya da benzer bir dile daha hızlı alışması doğal
Swift son dönemde cross-platform desteğini de güçlendirdi ve aktif C++ standart komitesi üyelerinden birkaç kişi de işin içinde
Ama Apple bağlantısı ve yerel UI framework eksikliği gibi nedenlerle Apple dışı tarafta yayılması daha sınırlı kaldı
Swift'in daha da popülerleşmesini isterim
Swift ile Zig/C'yi karşılaştıran iyi kaynaklar varsa öneri almayı isterim
Zig'in biraz dikkatle bellek güvenli yazılım üretebileceği söyleniyor ama aslında C de yeterince disiplinli kullanılırsa benzer sonuca ulaşabiliyor
Sonuçta sorun da bu “biraz disiplinin” gerçek hayatta çoğu zaman eksik olması
Zig ayrıca şu sorunları da çözüyor
C 50 yıldan uzun süredir bu disiplin meselesinde başarısız olduysa, demek ki bu iş "Shaolin yolu"ndan bile daha zor