35.000 satır JavaScript’i Rust’a taşımak
Dubai’de kurulu LeanScale için Ankara’dan uzaktan çalıştım. 35.000 satırlık kripto işlem sistemini altı yedi haftada Rust’a taşıdım: çeviriyi Cursor yaptı, ayıklamayı ben. Sistem 60 kat daha bellek verimli hâle geldi.
JavaScript ile yazılmış 35.000 satırlık işlem sistemi altı yedi haftada Rust’a taşındı ve 60 kat daha bellek verimli hâle geldi.
Rakamlarla LeanScale
- Rust’a taşınan JavaScript
- 35.000 satır
- Bellek verimliliği
- 60 kat
- Çeviri ve ayıklama
- 6–7 hafta
Kasım 2024’te Dubai’de kurulu LeanScale DMCC ile sözleşmeli çalışmaya başladım; Ankara’dan, uzaktan. Ortada çalışan bir kripto işlem sistemi vardı: JavaScript ile yazılmış, 35.000 satır. Benden istenen şey onu Rust’a taşımaktı. Ocak 2025’te iş bitmişti.
Sistem ne yapıyordu
Söyleyebileceğim kadarıyla: sistem kripto ağlarına RPC ile doğrudan bağlanıyor, gelen işlemleri ayrıştırıyor, hepsini tek bir süreç içinde işliyor ve sonucu React ile yazılmış ön yüze gönderiyordu. Hedef, en azından Solana ağı üzerinde kârlı işlem yapmaktı.
Ağa doğrudan bağlanmak bir tercihtir. Hazır bir aracının derli toplu verisini almakla arasında ciddi fark var: aracıyı seçerseniz veri temiz gelir ama ne zaman geleceğine siz karar vermezsiniz. Doğrudan bağlanırsanız işlemin ham hâlini görürsünüz, karşılığında ayrıştırma, sıralama ve ağın kendi tuhaflıkları sizin sorununuz olur. Bu sistem ikinci yolu seçmişti; dolayısıyla işin ağırlığı Rust sürecinin içindeydi.
Bu şeklin iki sonucu var. Birincisi, verinin hızını siz belirlemiyorsunuz, ağ belirliyor. Süreç yetişemezse kuyruk büyür; kuyruk büyüdükçe elinizdeki görüntü eskir ve eskimiş bir görüntüye bakarak verilen karar, işlem tarafında yanlış karardır. İkincisi, ön yüz bir görüntüleme katmanı; karar sürecin içinde veriliyor. Ön yüzü yavaşlatan bir şey can sıkar, süreci yavaşlatan bir şey para kaybettirir.

60 katlık fark nereden geliyor
Sonuç şu: sistem Rust’ta 60 kat daha bellek verimli hâle geldi. Bu tür bir farkın tek bir numaradan gelmediğini söylemem gerekir.
JavaScript’te her nesnenin bir başlığı, her dizginin bir kopyası ve çöp toplayıcının rahat çalışabilmesi için ayrılmış boş bir alanı vardır. Tek tek bakınca hiçbiri sorun değildir. Ama sürekli akan bir veriyi ayrıştıran bir süreçte bunlar çarpan etkisi yapar: aynı veriyi birkaç kere kopyalarsınız, her alan için bir sözlük girdisi tutarsınız, sonra bunların hepsinin toplanmasını beklersiniz. Rust tarafında aynı veri, alanları önceden belli bir yapıya oturuyor. Ayrıştırma sırasında çoğu zaman kopya bile çıkarmıyorsunuz, gelen tamponun içine bakıyorsunuz. Kazanç zekice bir çözümden değil, aynı küçük kararın kod boyunca art arda doğru verilmesinden geliyor.
Bellek verimliliği kendi başına bir hedef değil. Değeri, aynı makinede ne kadar durum tutabildiğinizde ve gecikmenizin ne kadar tahmin edilebilir olduğunda ortaya çıkar. Çöp toplayıcısı olan bir sistemde ortalama gecikmeniz iyi olabilir; sizi vuran şey ortalama değil, en kötü andır. Piyasa da size ortalama anlarda gelmiyor.
Çeviriyi model yaptı, ayıklamayı ben
40–50 dosyayı Cursor’a çevirttim.
Model bu işte iyi. Bir dilin deyimlerini başka bir dilin deyimlerine çevirmek imza imza, döngü döngü ilerleyen mekanik bir iştir ve mekanik işte model insandan hızlıdır. Ama çeviri bittiğinde elinizde çalışan bir sistem olmuyor; derlenmeye çalışan bir metin oluyor. İşin maliyeti yazmaktan okumaya kayıyor. Bu takas çoğu zaman kârlı — ama bedelsiz değil: 35.000 satırın hangi bölümünü okumadığınızı bilmiyorsanız, hiçbirini okumamış sayılırsınız.
Okurken nereye bakacağınızı bilmek de gerekiyor. Bir çevirinin tehlikeli yerleri modelin karıştırdığı yerler değil, iki dilin aynı yazılıp aynı davranmadığı yerlerdir. Sayılar bunun başında gelir: JavaScript’te her sayı kayan noktalıdır, Rust’ta yazdığınız tipte durur. Para tutan bir sistemde bu fark, derlenen ve testlerden geçen bir kodun sessizce yanlış rakam üretmesi anlamına gelebilir. Aynı şey eşzamanlılıkta da geçerli: JavaScript tarafında kendiliğinden sıraya girmiş işler, Rust’a taşındığında o sırayı kendiliğinden korumaz.
Üretilen kodu üç büyük parçaya böldüm, her parçayı ayrı ayrı ayıkladım, sonra birleştirdim. Bunun sebebi basit. Bir çeviriyi tek parça hâlinde ayağa kaldırmaya çalışırsanız, her şey çalışana kadar hiçbir şey çalışmaz. Haftalarca elinizde derlenmeyen bir yığın durur ve ilerlediğinizi gösteren tek işaret derleyici hatalarının sayısı olur; o da ilerleme tablosu değil, moral tablosudur. Parçalara böldüğünüzde ölçü netleşiyor: parça ayakta kalıyorsa o iş bitmiştir, bir daha oraya dönmezsiniz.
Yeniden yazımda doğru cevap zaten elinizde
Sıfırdan yazmakla yeniden yazmak arasındaki en büyük fark şu: yeniden yazarken doğru cevabı biliyorsunuz. Eski sistem çalışıyor. Aynı girdiyi ikisine birden verip çıktıları karşılaştırabilirsiniz. “Bence böyle olmalı” demek zorunda kaldığınız her yerde, onun yerine bakabileceğiniz bir kaynak duruyor. Bir dil değiştirme işini dayanılır kılan şey budur.
Rust’un burada beklemediğim bir faydası oldu. JavaScript’te bir alanın
gelmemesi sessiz bir durumdur; undefined akıp gider ve birkaç fonksiyon sonra
tuhaf bir sonuç olarak ortaya çıkar. Aynı alanı Rust’a taşıdığınızda Option
oluyor ve derleyici size “burada bir şey olmayabilir, ne yapacaksınız” diye
soruyor. Bu sorunun cevabı çoğu zaman eski koda bakınca bulunmuyor, çünkü eski
kodda kimse o soruyu sormamış. Yani çeviri, ister istemez, orijinalin belirsiz
bıraktığı yerleri sayıp döküyor. Bir sistemi başka bir dile taşımanın en
değerli çıktısı çoğu zaman yeni kod değil, eski kod hakkında öğrendikleriniz
oluyor.
İki ayın faturası
Bir yeniden yazımın faturası takvimde görünmez. O süre boyunca ürün ilerlemez, sadece yerini korur; sonunda elinizde daha çok işlev değil, aynı işlevin daha sağlam bir hâli olur. Bu yüzden yeniden yazma kararı, mühendislikte savunması en zor kararlardan biridir ve çoğu zaman verilmemesi gerekir. Burada gerekçeyi ikna edici bulduğum yer şuydu: sistemin işi, hızını kendisinin belirlemediği bir veri akışına yetişmekti; o akışa yetişmek için gereken şeyler de JavaScript’in kolay kolay vermediği şeylerdi.
Buradan alıp kullanabileceğiniz tek şey şu. Bir dil değiştirme işini modelle yapacaksanız, kazandığınız zamanı okumaya harcamayı baştan kabul edin ve işi tek seferde ayağa kalkmayacak kadar büyük tutmayın. Modelin size verdiği şey bitmiş bir sistem değil, gözden geçirilmeyi bekleyen bir taslaktır. Taslağın büyüklüğü sizi korkutuyorsa, çeviriyi değil, bölmeyi yanlış yapmışsınızdır.
Teknoloji
- Rust
- JavaScript
- React
- RPC
- Cursor
Yorumlar
Burada henüz kimse konuşmamış. İlk sözü siz söyleyin — katılmadığınız yeri yazarsanız daha da iyi.
Yorum yazın
Yorumlar önce bana geliyor. Onayladığımda burada, adınızla birlikte yayımlanıyor.