10 puan yazan GN⁺ 2025-10-16 | 2 yorum | WhatsApp'ta paylaş
  • SQLite, performans, uyumluluk, düşük bağımlılık ve kararlılık nedeniyle en başından beri (2000) C dili ile geliştirildi
  • C, neredeyse tüm işletim sistemlerinde ve dillerde kullanılabilir; özellikle düşük seviyeli kütüphaneler için hızlı çalışmayı destekler
  • Nesne yönelimli diller yerine C’nin seçilme nedeni; genişletilebilirlik, farklı dillerden çağrılabilme ve geliştirme döneminde C++ ile Java’nın henüz olgunlaşmamış olmasıydı
  • SQLite, neredeyse hiç bağımlılığı olmayan tek dosyalık bir yapıya sahiptir ve yalnızca C standart kütüphanesinin en temel işlevlerini kullanır
  • Rust ve Go gibi "güvenli diller" ile yeniden yazma tartışmaları olsa da kalite yönetimi, performans ve kütüphane olarak çağrılabilirlik açısından C hâlâ üstün kabul ediliyor

1. C neden en iyi seçimdi

  • SQLite, 29 Mayıs 2000’deki ilk geliştirmesinden bu yana bugün hâlâ C diliyle sürdürülüyor
    • Şu anda başka bir dilde yeniden yazma planı yok
  • C, donanıma yakın denetim gücü sunarken aynı zamanda yüksek taşınabilirliğe sahip olduğu için “taşınabilir assembly dili” olarak anılır
  • Başka diller “C kadar hızlıyız” diyebilir, ancak C’den daha hızlı olduğunu iddia eden bir dil yoktur

1.1. Performans

  • SQLite gibi düşük seviyeli kütüphaneler sık sık çağrıldığından son derece hızlı çalışmaları gerekir
  • C dili, hızlı kod yazmak için uygundur; hem yüksek taşınabilirlik sağlar hem de donanıma yakından erişebilir
  • Diğer modern diller de “C kadar hızlı” olduklarını söylese de genel amaçlı programlamada C’den daha hızlı olduğundan emin olunan bir dil yoktur
  • C, bellek ve CPU kaynaklarını ayrıntılı biçimde denetleyebildiği için dosya sisteminden %35 daha hızlı performans gösterebilir

1.2. Uyumluluk

  • Neredeyse her sistem C ile yazılmış kütüphaneleri çağırabilir
  • Örneğin Android’de (Java tabanlı) bile bir adaptor üzerinden SQLite kullanılabilir
  • SQLite Java ile yazılmış olsaydı iPhone’da (Objective-C, Swift) kullanılamazdı; bu da genel kullanım alanını ciddi biçimde daraltırdı

1.3. Düşük bağımlılık

  • C kütüphanesi olarak geliştirildiği için çalışma zamanı bağımlılıkları çok azdır
  • En küçük yapılandırmada yalnızca standart C kütüphanesinin şu temel işlevleri kullanılır: memcmp(), memcpy(), memmove(), memset(), strcmp(), strlen(), strncmp()
  • Daha tam özellikli derlemelerde bile malloc(), free(), dosya girdi/çıktısı gibi az sayıdaki bağımlılıkla yetinir
  • Modern diller çoğu zaman çok sayıda büyük çalışma zamanı bileşeni ve binlerce arayüz gerektirir

1.4. Kararlılık

  • C, eski, çok değişmeyen ve sıkıcı bir dil olabilir; ancak bu aynı zamanda öngörülebilirlik ve kararlılık anlamına gelir
  • SQLite gibi küçük, hızlı ve güvenilir bir veritabanı motoru geliştirirken, standardı sık değişmeyen bir dil daha uygundur
  • Dilin özellikleri ya da uygulamaları sık sık değişirse bu, SQLite’ın kararlılığı açısından olumsuz olur

2. Neden nesne yönelimli bir dille yazılmadı?

  • Bazı geliştiriciler nesne yönelimli değilse SQLite gibi karmaşık bir sistemi kurmanın zor olduğunu düşünür; ancak C’ye kıyasla C++ ya da Java ile kütüphane yapmak, başka dillerden çağırmayı zorlaştırır
  • Haskell, Java ve başka birçok dili desteklemek için C kütüphanesi seçimi mantıklıdır
  • Nesne yönelimlilik bir dil değil, bir tasarım desenidir; dolayısıyla belirli bir dille sınırlı değildir
    • C’de de struct ve function pointer kullanılarak nesne yönelimli desenler uygulanabilir
  • Nesne yönelimlilik her zaman en iyi yapı değildir; kimi zaman prosedürel kod daha açık, daha kolay yönetilebilir ve daha hızlı sonuç verebilir
  • SQLite’ın ilk geliştirildiği dönemde (2000 civarı)
    • Java olgunlaşmamıştı
    • C++’ta ise derleyiciler arası uyumluluk sorunları ciddiydi
      → O dönemde C, en pratik ve en güvenli seçimdi
  • Bugün bile SQLite’ı yeniden yazmayı haklı çıkaracak kadar güçlü bir avantaj görünmüyor

3. Neden "güvenli bir dil" ile yazılmadı?

  • Son yıllarda Rust ve Go gibi güvenli programlama dillerine ilgi artsa da SQLite ilk geliştirildiğinde (ilk 10 yılında) bu diller mevcut değildi
  • Go ya da Rust ile yeniden yazılırsa daha fazla hata ortaya çıkma veya performansın düşme ihtimali vardır
  • Bu diller bellek denetimi gibi ek branch kodları ekler; oysa SQLite’ın kalite stratejisinde %100 branch coverage çok önemlidir ve bu gereksinim burada karşılanmaz
  • Güvenli diller genellikle out-of-memory durumunda programı sonlandırır; SQLite ise bellek yetersizliği durumundan kurtulabilecek şekilde tasarlanmıştır
  • Rust, Go ve benzeri diller hâlâ görece yenidir ve gelişmeye devam etmeleri gerekir
  • Bu yüzden SQLite geliştiricileri güvenli dillerin gelişimini desteklese de SQLite’ın uygulanmasında hâlâ kanıtlanmış C kararlılığını öncelikli görüyor

Buna rağmen, bir gün Rust ile yeniden yazılması yine de mümkün olabilir. Go’nun assert() sevmemesi nedeniyle Go ile yazılma olasılığı düşüktür

  • Ancak Rust ile yazılabilmesi için bazı ön koşullar vardır:
    • Rust’ın daha da olgunlaşması, değişim hızının yavaşlaması ve “eski, sıkıcı bir dil” hâline gelmesi
    • Birden çok dilden çağrılabilen genel amaçlı bir kütüphane üretilebildiğinin kanıtlanması
    • Gömülü sistemler gibi işletim sistemi olmayan aygıtlarda da çalışabilecek nesne kodu üretebilmesi
    • Derlenmiş ikili dosyalar için %100 branch coverage test araçlarının bulunması
    • OOM (bellek yetersizliği) hatalarından kurtulabilmesi
    • SQLite’ta C’nin yaptığı her şeyi Rust’ın performans kaybı olmadan yapabilmesi
  • Eğer bir Rust meraklısı (rustacean) bu koşulların zaten sağlandığını ve SQLite’ın Rust ile yeniden yazılması gerektiğini düşünüyorsa, SQLite geliştiricileriyle doğrudan iletişime geçip görüşünü savunması öneriliyor

2 yorum

 
GN⁺ 2025-10-16
Hacker News görüşleri
  • Güvenli programlama dilleri ilk 10 yıl boyunca ortada yokken bile, SQLite’ı Go ya da Rust ile yeniden uygulamanın düzeltebileceğinden daha fazla hata üretme ihtimali olduğunu ve hatta daha yavaş olabileceğini düşünüyor. Zaten muazzam zaman ve test sürecinden geçerek hatasız hale gelmiş bir kod varsa, değişim oranı düşük olduğunda hangi dilde yazıldığının pek önemi yok. Hatta assembly olsa bile fark etmez denecek düzeyde
    • “Değişim oranı düşükse sorun da az olur” noktası Google Security Blog’da da açıklanmıştı. Burada bellek güvenliği sorunlarının çoğunun yeni kodda ortaya çıktığı ve kodun zaman geçtikçe daha güvenli hale geldiği savunuluyor ilgili bağlantı
    • Rust tarafında Turso gibi projeler oldukça aktif ilerliyor Turso
    • Linux’un temel yardımcı araçlarının Rust ile yeniden yazılmaması gerektiğini savunanlar da var. On yıllardır kullanılan ve çoğu hatası zaten ayıklanmış yazılımların yeniden yazılmasına gerek olmadığı düşünülüyor
    • Zig’in bazı C kodlarının yerini almak için iyi olduğunu düşünüyor. Python ve mevcut C binary’leriyle de iyi uyum sağlıyor. Go felsefesi güzel olsa da optimizasyonun zor olması ve çok yetenekli geliştiriciler gerektirmesi gibi sınırlamalar vardı. Rust da kullanılabilirdi ama mevcut C’yi kullanmaya devam ederken Zig’i kademeli olarak devreye almak çok daha kolaydı. C kodundaki hataları tamamen ortadan kaldıramasak da Rust’a geçmenin pratikte zor olduğu hissediliyor
    • Zaten Go’ya port edilmiş bir sqlite uygulaması var cznic/sqlite
  • SQLite ilk geliştirildiğinde C’nin en iyi tercih olmasının nedenleri ya da bugünkü avantajlarının ötesinde, SQLite’ı başka bir dille yeniden yazmak için özel bir sebep olmadığını düşünüyor. Hafif bir SQL veritabanı uygulamak herkesin yapabileceği bir şey; dolayısıyla Rust, C++, Go, Lisp gibi istenen dilde yeni bir uygulama geliştirilebilir. Mevcut, C ile iyi çalışan uygulamayı gereksiz yere bırakıp, 25 yılı aşkın süredir SQLite’ı C ile sürdüren geliştiricilere zorla yeni bir dil öğrenip her şeyi baştan yapmalarını söylemeye gerek olmadığı düşünülüyor
    • Birçok dil fandomunda insanların başkalarına kendi istediklerini dayatma eğilimi olduğu ve dil benimsemenin bir tür sıfır toplamlı kavgaya dönüştüğü hissediliyor. Bir proje belli bir dille geliştiriliyorsa, o dili kullanmamak bile diğer dillerin gerekliliğini sorgulatan bir şey haline geliyor. Oysa seçenekler çok daha çeşitli ve yeniden yazılsa bile masada Rust, Go, D, Lisp, Julia gibi birçok dil olurdu
    • Gerçekte SQLite geliştiricileri Rust ile yeniden yazıma açık. Rust gerekli ön koşulları sağlarsa yeniden yapma ihtimali de var. Rust hayranlarının SQLite geliştiricileriyle doğrudan iletişime geçmeleri yönünde bir not da bulunuyor
    • Zaten Rust ile uygulanmış rqlite ve turso gibi projeler var
    • Go ile yazılmış bir adaptör bulunduğu için golang içinde cgo olmadan sqlite kullanılabiliyor. Artık sqlite sadece bir C kütüphanesi değil, aynı zamanda bir veritabanı dosya formatı. İleride pure Rust bir uygulamanın çıkıp bir gün ana uygulama haline gelmesi de mümkün olabilir
    • Bugünlerde 5 yıldan eski teknolojileri demode diye küçümseme eğilimi can sıkıcı bulunuyor. Uzun süre boyunca olgunlaştırılmış teknolojilere daha fazla saygı gerektiği düşünülüyor
  • Güvenli diller dizi erişiminde sınır kontrolü için ek branch’ler üretir ama doğru çalışan kodda bu branch’ler fiilen çalışmaz. Yani %100 branch testi zordur ve bu nokta SQLite’ın kalite stratejisiyle bağlantılıdır. Bu yeni mantığı duymanın ilginç olduğu söyleniyor
    • Eğer o kod branch’inin asla çalışmayacağından eminseniz, o kısmı test etmeye gerçekten gerek yok değil mi? %100 test kapsamı uğruna güvenlikten ödün veriliyormuş gibi hissettiriyor
    • Güvenli dillerde derleyici otomatik olarak if (i >= array_length) panic("index out of bounds") gibi savunma kodları ekliyor ama o kodun kendisi zaten Rust derleyicisi tarafından iyi test edildiği için endişe etmeye gerek olmadığı düşünülüyor. Bu mantığı doğru anlayıp anlamadığından emin değil
    • Dr Hipp gibi bir uzman ve sqlite gibi bir proje söz konusuysa, bu argümanın burada da bir ağırlığı olduğu düşünülüyor
    • Rust’taki get_unchecked() gibi yöntemlerle bounds check olmadan erişim de mümkün; bununla hem güvenliği koruyup hem performansı artırmak mümkün olabilir get_unchecked belgeleri
    • Koşullu olarak panic’e giden branch’leri zorunlu kapsam dışında bırakmak bu sorunu azaltabilir mi diye merak ediliyor
  • SQLite’ın bir gün Rust ile yeniden yazılma ihtimalini açık bıraktığı, Go’nun ise assert() ile ilgili kısıtlar nedeniyle pek olası görünmediği söyleniyor. Rust’a geçiş için şu ön koşulların gerekli olduğu düşünülüyor: Rust’ın daha uzun süre az değişir hale gelmesi, genel amaçlı kütüphane yazımına uygun olması, OS olmayan gömülü ortamlarda çalışabilmesi, %100 branch coverage araçlarının bulunması, OOM hata işleme mekanizmasının olması ve performans kaybı olmadan C’nin rolünü üstlenebilmesi
    • Rust, 1.0’dan sonra 10 yılı aşkın süredir uyumlu şekilde evriliyor. Tamamen değişmez hale gelmesini isteyenlerle, değişimin kabul edilebilir olduğunu düşünenler arasında fark var. Genel amaçlı kütüphane geliştirme zaten kanıtlanmış durumda ve OS’siz gömülü destek de açıkça mümkün. Branch coverage konusunda yorum yapan kişi uzman olmadığını söylüyor ama Ferrocene gibi tarafta ilgili çalışmalar yürütülüyor. Rust dilinin kendisi bellek tahsisi yapmadığı için OOM işleme standart kütüphane düzeyinde belirlenebilir. Performans meselesi ise nasıl tanımlandığına göre değişebilir
    • Go’da da if condition { panic(err) } yapısının bir assert fonksiyonu gibi kullanılamayacağı merak ediliyor
  • Çoğu iddia ilk bakışta makul görünse de dikkatle incelendiğinde kusursuz değil gibi geliyor. 2000 civarında neden C’nin seçildiği net şekilde açıklansa, bugün için de iyi olgunlaşmış kod tabanını kabul etmek yeterli olmaz mı diye düşünülüyor. Yan argümanların bazıları çürütülebilir bulunuyor
    • Özellikle hangi iddiaların çürütülebilir olduğunun duyulmak istendiği söyleniyor
    • Sunulan argümanlar geçmiş kod tabanını korumak için işe yarayabilir ama yeni geliştiricileri daha karmaşık diller yerine C seçmeye yönlendirmek için daha fazla gerekçe gerektiği söyleniyor
    • (İlgili belge 2017’de yazılmış)
    • Muhtemelen uzun yıllar boyunca gelen sayısız “neden X ile yeniden yazmıyorsunuz” sorusuna yanıt vermek için ayrıntılı ve uzun bir belge hazırlanmış
  • SQLite’ı otomasyonla Go’ya taşıyan bir proje zaten yıllardır var ve aktif olarak dağıtılıyor modernc.org/sqlite. Aynı test paketini de başarıyla geçiyor. Ancak Go sürümü oldukça yavaş ve çoğu durumda önemli olan hızın kendisinden çok Go yerel portunun sunduğu kolaylık. Sonuç olarak SQLite’ı Go, Rust, Zig, Nim, Swift gibi dillerle baştan yazmaktan çok, C’den otomatik çeviriyle üretmenin daha gerçekçi olduğu düşünülüyor
    • Açık test paketi geçilse de, SQLite’ın çok daha ağır iç test paketleri de olduğu söyleniyor
    • Test paketini geçmek = hatasız olmak demek değil; yeni edge case’ler ya da performans sorunları kalabilir
  • “SQLite neden C ile geliştirildi?” sorusu resmi belgede iyi açıklanıyor ama “neden Rust değil?” sorusu duyulunca akla önce “neden Rust olmak zorunda?” geliyor
    • Bunun, sonradan eklenmiş başlıktan kaynaklandığı söyleniyor
    • Zaten böyle bir Rust yeniden yazım projesi var: tursodatabase/turso ve blog yazısında da Why üzerine bir tartışma vardı
    • SQLite’ın neden BASIC yerine C ile yazıldığının da sorulabileceği tonunda bir yorum
  • Kod yazma, yazılım kullanma ve yeniden yazım üzerine metinler okudukça görülen temel sorunlardan biri şu: Yeniden yazım sadece “işlevsel eşdeğerlik” amacıyla yapılırsa, zaman içinde birikmiş sayısız istisna işleme ve yamalar kolayca kaybolabiliyor. Sonuçta yazılım yeniden bozulabiliyor ya da eskiden düzgün çalışan şeyler çalışmaz hale gelebiliyor. Bu tür yeniden yazımlarda yeterli vurgu ve dikkat gerektiği, %100 geri üretimin zor olduğu düşünülüyor. SDL gibi kritik kütüphanelerde de durum benzer. Tekrarlayan biçimde bozulan sürümler ve kullanıcı şikayetleri beklenebilir. C’nin Rust baskın hale geldikten sonra bile uzun süre yaşamaya devam edeceği düşünülüyor. Yeniden yazım varsayılan seçenek olmamalı
  • DuckDB’nin Rust değil de C++ ile yazılmış olması daha ilginç bulunuyor; çünkü DuckDB 2019’da ortaya çıkan yeni bir proje ve sanki Rust’ı seçebilirmiş gibi görünüyor ama sonuçta C++ tercih edilmiş. DuckDB yeni ve kod tabanı da SQLite’tan çok daha küçük
    • DuckDB geliştiricilerinin C++ konusunda kendilerine güvendiği ve derleyicinin auto-vectorization yeteneğine inandıkları için bunu seçtikleri söyleniyor. O dönemde (2019) Rust’ta net bir yüksek seviyeli SIMD desteği yoktu. Elle yazılmış SIMD kodunu bakımda tutmak istemedikleri belirtiliyor
    • Amaç azami performanssa, C++’ın daha az kodla daha hızlı binary’ler üretebildiği düşünülüyor. Modern C++’ın compile-time güvenliği de yüksek olduğundan veritabanı gibi kodlar için uygun olduğu söyleniyor
    • Modern C++ ile yazılırsa sorun olmayacağı düşünülüyor
  • Daha önce de SQLite yeniden yazım tartışmaları çok oldu 2021, 2018
    • tptacek’in yorumu ilginç bulunuyor; önceki belgede security ile ilgili bir paragraf varken son belgede bu kısmın çıkarıldığı söyleniyor. C, SQLite için de açık bir güvenlik zafiyeti. Eski sürümde “SQLite o kadar güvenlik hassasiyetli bir kütüphane değil” şeklinde bir açıklama vardı. Güvenilmeyen SQL çalıştırmanın başlı başına daha büyük bir mesele olduğu, dış dosya içe aktarma tarafında ise savunma kodları ve güçlü testlerle sorunların önlendiği, ayrıca ön doğrulama rutinlerinin bulunduğu yazıyordu 2021 web archive belgesi
 
aer0700 2025-10-16

C’nin SQLite için de bir güvenlik riski olduğu ifadesi var; bu, testleri yeterince iyi yazsanız ve yeterince deneyimli geliştiriciler olsanız bile yine de geçerli mi? Sorun mantıkta ve geliştirme sürecinde olabilir, ancak dilin kendisinin bir güvenlik açığı olması bana anlaması zor geliyor. Aslında C ile yazılmış altyapıya dayanmayan program neredeyse yok denecek kadar az değil mi?