- PostHog, ANTLR tabanlı C++ SQL ayrıştırıcısını birden fazla Claude Code oturumuyla yeniden yazarak 16 bin satırlık bir Rust ayrıştırıcısı, 5 bin satırlık araçlar ve binlerce satırlık test oluşturdu; dizüstü bilgisayar ölçümünde yaklaşık 70 kat hız artışı elde etti
- Yeni uygulama, öngörülü özyinelemeli iniş ayrıştırıcısı ve Pratt ifade çekirdeği etrafında şekilleniyor; yalnızca gerekli yerlerde sınırlı önden bakma ve varsayımsal geri izleme uygulayarak ANTLR’nin genel amaçlı grafik dolaşımı maliyetini ortadan kaldırıyor
- Mevcut C++ ayrıştırıcısını referans uygulama olarak tutup özellik tabanlı testler, anonimleştirilmiş gerçek sorgular, regresyon testleri, kod kapsamı güdümlü üretim ve ShrinkRay küçültmeyi birleştirerek iki ayrıştırıcı arasındaki uyumsuzlukları yinelemeli olarak giderdi
- Üretimde gölge modda milyonlarca ayrıştırma sonucu mevcut ayrıştırıcıdan bir kez bile farklı çıkmayınca birkaç saat içinde trafiği yeni ayrıştırıcıya yönlendirdi ve üretimde ortalama 454 kat hız artışı kaydetti
- Ayrıştırıcı üretecinin dilbilgisini ve referans uygulamayı sağladığı, LLM’nin ise fuzzing ile eşdeğerliği doğruladığı bu yaklaşım, uzmanlık gerektiren aylar ölçeğindeki yüksek performanslı ayrıştırıcı geliştirme işini günlere indirebileceğini gösteriyor
PostHog’un neden bir SQL ayrıştırıcısına ihtiyacı var?
- PostHog, kullanıcıların SQL ile verilere doğrudan erişebilmesi için girilen SQL’i ham ClickHouse SQL’e dönüştürür
- Veritabanının fiziksel yerleşiminden bağımsız mantıksal veri görünümleri sağlar
- Veritabanı katmanı değişse bile mevcut sorguların bozulmasını önler
- Dönüşüm sürecine performans optimizasyonu ve erişim denetimi ekler
- Ürün analitiği, oturum tekrar oynatma, hata izleme gibi PostHog araçlarının çoğu da SQL ile yazılmış sorguları aynı dönüşüm sürecinden geçirir
- SQL’i dönüştürmek için önce onu bir soyut sözdizimi ağacına (AST) çevirmek gerekir; bu ağaç daha sonra ClickHouse SQL’e dönüştürülür
- Ayrıştırıcı, güvenilmeyen sorgu girdisini ilk işleyen bileşendir
- Sonraki erişim denetimi ve optimizasyonların tamamı da ayrıştırıcının oluşturduğu ağaca dayanır
Mevcut ANTLR ayrıştırıcısının yapısı ve maliyeti
- Yapay zeka ile kodlama öncesinde bir ayrıştırıcıyı elle yazmak ve sürdürmek çok zor olduğundan PostHog, açık kaynak ayrıştırıcı üreteci ANTLR’yi kullandı
- Dilbilgisi bildirime dayalı bir .g4 dosyası olarak verildiğinde ANTLR, ayrıştırıcı kodunun büyük kısmını üretir
- Mevcut ayrıştırıcı zaten C++ olarak üretilmişti; dolayısıyla bu performans artışı yalnızca uygulama dilinin Rust’a çevrilmesinin sonucu değil
- ANTLR güçlü ve esnektir, ancak her token’ı işlerken daha fazla iş yapması gerekir
- Dilbilgisini artırılmış geçiş ağına (ATN), yani yığın içeren belirsiz sonlu otomata (NFA)’ya yakın bir biçime derler
- Çalışma zamanında genel amaçlı bir yorumlayıcı bu grafiği dolaşır
parseExpression()gibi elle yazılmış doğrudan fonksiyonlar yerine ek soyutlama ve dolaylı çağrı katmanlarından geçer
- Keyfi dinamik önden bakmayı da desteklediği için birden fazla alternatif olduğunda yalnızca biri geçerli kalana kadar tüm yorumları aynı anda simüle eder
- Yeterince optimize edilmiş bir ANTLR bile grafik dolaşımı yorumlayıcısı yapısıyla elle yazılmış bir özyinelemeli iniş ayrıştırıcısından daha hızlı olmakta zorlanır
İki ayrıştırıcı uygulamasını paralel deneme
- Yapay zekadan yararlanmak, elle yazılmış bir ayrıştırıcı oluşturmayı ve sürdürmeyi kolaylaştırsa da Claude’dan hatasız bir Rust ayrıştırıcısı istemek tek başına yeterli olmadı
- Claude çok hata yaptı
- Yeniden yazmanın mümkün olup olmadığını sürekli sorguladı
- Her kodlama turunun sonunda işi bitirme eğilimi gösterdi
- Uzun süren birden fazla Claude Code oturumunda iki yaklaşım paralel olarak denendi
- Performans odaklı yaklaşım, özyinelemeli iniş ayrıştırıcısı ve Pratt ifade döngüsü kullanıp yalnızca gerekli yerlere önden bakma ve geri izleme ekledi
- Başarı olasılığı odaklı yaklaşım, ANTLR’nin davranışını mümkün olduğunca izledi; ancak genel amaçlı grafik dolaşımı yerine geçişleri açık kodla uyguladı
- İki yaklaşım sonunda benzer düzeyde çalıştı, ancak bunu doğrulamak birkaç gün aldı
- Hedef, gerçekçi tüm sorgularda mevcut C++ ayrıştırıcısıyla tamamen aynı olmak ve yapay sorgularda da mümkün olduğunca yakın sonuç vermekti
SELECT SELECT FROM FROM WHERE WHERE AND ANDgibi anormal görünen ama geçerli SQL de test kapsamına alındı
- Mevcut C++ ayrıştırıcısı referans uygulama (oracle) olarak alındı; farklı işlenen SQL’ler bulunup yeni ayrıştırıcı düzeltildikten sonra yeniden karşılaştırılan test güdümlü bir yöntemle geliştirildi
Özellik tabanlı testlerle uyumsuzluk üretme
- Önce mevcut ayrıştırıcı geliştirme sürecinde biriken regresyon testleri geçirildi, ardından yeni uyumsuzluklar sistematik olarak üretildi
- Hypothesis kullanan özellik tabanlı testlerde (PBT) doğrulama özelliği “yeni ayrıştırıcı referans uygulamayla eşleşir” olarak tanımlandı
- Girdi değerleri SQL sorgularıdır
- Hypothesis, iki ayrıştırıcının sonuçlarının uyuşmadığı sorguları arar
- İlginç SQL üretmek için ANTLR dilbilgisi dosyasından SQL üreteci kodu oluşturan bir araç Claude ile birlikte yapıldı
.g4dosyasının kendisini okuyan ayrı bir ayrıştırıcı da yazıldı- Daha sonra token değiştirme veya parantez ekleme gibi varyasyonlar üretim aşamasına dahil edildi
Kırılgan düzeltmeleri önleyen prompt yapısı
- PBT kararlı biçimde yeni testler üretti, ancak Claude bir vakayı tek token önden bakmayla düzeltip sonra iki token önden bakma gerektiğini keşfetmek gibi kırılgan düzeltmeleri tekrarladı
- Bağlam penceresi sık sık dolup sıkıştırıldığı için gerçek dilbilgisini veya referans ayrıştırıcının davranışını unutmuş halde düzeltme yapmış olması mümkündü
- Her uyumsuzluğu düzeltecek kodu yazmadan hemen önce ilgili dilbilgisi dosyasını ve C++ kaynak kodunu bağlama yüklemesi istenerek bu sorun hafifletildi
CPU ile Claude’u birlikte sürekli çalıştırma
- PBT arka planda sürekli çalışıp başarısız örnekleri dosyaya kaydetti; Claude’un başka işi olmadığında bu örnekleri alması için araçlar yapılandırıldı
- Başarısız örnekler birden fazla yoldan toplandı
- Mevcut regresyon testleri
- PBT ile üretilen SQL
- Üretim sorgu günlüklerinden alınan anonimleştirilmiş sorgular
- Arka plan ajanından “sınır durumlarını gerçekten derinlemesine düşünmesini” isteyerek oluşturulan vakalar
- Paralel geliştirilen iki ayrıştırıcı regresyon testi kümesini paylaştı; böylece bir oturumda bulunan hata diğer oturuma da hemen yansıdı
- Hypothesis, kendi ürettiği vakaları en küçük yeniden üretime indirebilir; ancak dış SQL’e uygulanamadığından bu vakalarda ShrinkRay kullanıldı
- Daha sonra kod kapsamı güdümlü test üretimi de eklendi
- Henüz çalıştırılmamış SQL bileşenleri algılanıp bu yapıların daha sık üretilmesi için yönlendirme yapıldı
- Üretim sorguları kümesinde %100 doğruluğa ulaşmak için şart değildi, ancak çok ince vakaları bulmaya yardımcı oldu
Hataları bulup düzelten otomatik yineleme süreci
- Nihai geliştirme döngüsü şu adımları otonom olarak yineledi
- PBT, gerçek sorgu kümesi, regresyon testleri ve sınır durumu keşfiyle yeni hatalar üretir
- Hatayı küçültüp sürekli genişleyen regresyon testi listesine ekler
- Genel çözümleri önceliklendirirken dilbilgisinin ve C++ referans uygulamanın işleme biçimini kontrol eder
- Düzeltmeden sonra insanın okuyabileceği tek paragraflık bir özet çıktılar
- Tüm regresyon testlerini çalıştırıp tüm vakaların geçtiğini doğrular
- Aynı süreci yeniden otonom olarak çalıştırır
- Yeni ayrıştırıcı çok daha hızlı olduğu için üretimde mevcut C++ ayrıştırıcısıyla birlikte gölge modda çalıştırılıp sonuç farklarını raporlayabildi
Üretim doğrulaması ve geçiş
- Üretim sorgu günlükleriyle yapılan ön karşılaştırmada yaklaşık 50 bin sorgu test edildi
- Gölge modda milyonlarca ayrıştırma hızla çalıştırıldı ve mevcut ayrıştırıcıyla tek bir uyumsuzluk bile oluşmadı
- Başta gölge modu birkaç gün sürdürmek planlanıyordu, ancak sonuçlar yeterince güçlü olduğundan birkaç saat içinde üretim trafiği yeni ayrıştırıcıya geçirildi
- Geçişten sonra mevcut ayrıştırıcıyla yeniden karşılaştırma yapan %0,1 ters gölge korundu
- Yeni ayrıştırıcı yalnızca AST’yi değil, kaynak konumu bilgilerini de C++ ANTLR ayrıştırıcısıyla aynı biçimde çıktı verir
Dizüstünde 70 kat, üretimde 454 kat
- Dizüstü bilgisayar benchmark’ında mevcut ayrıştırıcıdan yaklaşık 70 kat daha hızlı performans kaydedildi
- Üretim sorgularında ortalama 454 kat hızlandı
- Üretimde ayrıştırıcı önbelleğine isabet etmeyen daha uzun SQL’ler ağırlıklı olarak işlendiği için performans farkı dizüstüne göre daha büyük oldu
- Nihai çıktı yaklaşık 16 bin satır ayrıştırıcı kodu, yaklaşık 5 bin satır araç ve binlerce satır testten oluştu
- Gerçekçi sorgularda mevcut ayrıştırıcıyla eşdeğer; farklar yapay olarak oluşturulmuş çok az sayıdaki sorguyla sınırlı
Nihai ayrıştırıcı yapısı ve değişen geliştirme biçimi
- Nihai ayrıştırıcı şu yapıdan oluşuyor
- Büyük bölümü öngörülü özyinelemeli iniş ayrıştırıcısı olarak uygulandı
- İfade işleme için Pratt ayrıştırıcı çekirdeği kullanıldı
- Temel imleç LL(2); yalnızca belirli noktalarda girdiyi tüketmeyen sınırlı önden bakma aramasıyla kapsam genişletiliyor
- Mutlaka gerekli az sayıdaki kararda, sıralı seçim tabanlı yerel varsayımsal geri izleme uygulanıyor
- Tüm ayrıştırıcı 2026 Mayıs’ında Claude Opus 4.7 tarafından Rust ile yazıldı; kod elle doğrudan yazılmadı
- Dilbilgisiyle girdi üretip kod kapsamıyla üretimi yönlendiren PBT yapısı, ayrıştırıcı fuzzing’inin modern yöntemlerine yakın ve basit “vibe coding”den ayrılıyor
- Belirli ayrıştırıcı bilgisine sahip bir geliştirici için bile aylar sürebilecek bir iş birkaç günde tamamlandı
- Gelecekte ANTLR gibi ayrıştırıcı üreteçlerinin referans uygulama sağladığı, LLM’nin ise PBT ve fuzzing ile eşdeğerliği yakalarken daha hızlı, doğrudan uygulanmış ayrıştırıcılar yazdığı yaklaşım yaygınlaşabilir
Henüz yorum yok.