Yazılım

128 satırlık Markdown çeviricim marked'dan 3 kat hızlı — ve 14 testin 13'ünü kaybediyor

Bağımlılıksız bir Markdown çevirici yazdım, sonra gerçekten ölçtüm. Hız gerekçesi çürük çıktı; doğru gerekçe bambaşkaydı.

Bu yazının İngilizcesi: English version.

Bu blogu ayağa kaldırırken küçük bir karar verdim: Markdown çeviricisini kendim yazacaktım. content/blog/*.md dosyalarını okuyup public/blog/ altına HTML üretecek bir betik lazımdı ve npm i marked yazmak yerine oturup 128 satır kod yazdım.

Karar verirken kendime söylediğim gerekçe "daha hızlı olur" idi. Bugün oturup ölçtüm. Gerekçem çürüktü. Ama karar yine de doğruydu, sadece sebebi başkaymış. Ölçümleri de gerekçeleri de aşağıda anlatıyorum.

Ölçüm düzeneği

Girdi olarak uydurma metin kullanmak istemedim. Deponun kendi Markdown dosyalarını (README ve bir plan dokümanı) altı kez birleştirdim: 70.960 karakter, 9.085 kelime. Bu, aşağı yukarı sekiz blog yazısı eder — yani gerçek bir derleme işinin büyüklüğü.

Üç çeviriciyi karşılaştırdım: kendi md.mjs dosyam, marked ve markdown-it. Her biri için 20 ısınma turu, ardından 50 ölçüm; aşağıdaki sayılar medyan. Node 24.18.0, Apple Silicon Mac.

ÇeviriciMedyanEn iyiKurulu boyut
md.mjs (benim)0,88 ms0,76 ms4,8 kB, tek dosya
marked2,55 ms2,20 ms484 kB
markdown-it2,63 ms2,28 ms1,9 MB

Soğuk başlangıçta da fark var: ayrı süreçte ölçtüğümde marked modülünün yüklenmesi 5 ms, markdown-it 5,9 ms sürüyor. Benim dosyamın yüklenme maliyeti ölçüm hassasiyetinin altında kaldı.

Yani "3 kat hızlı" iddiası doğru. Şimdi bu iddianın neden hiçbir işe yaramadığını açıklayayım.

Hız gerekçesi neden çürük

Bu çevirici, sitede derleme sırasında çalışıyor. Kullanıcı bir sayfa açtığında değil, ben node tools/build-blog.mjs yazdığımda. Yani ömrü boyunca belki günde beş kez koşacak.

70 kB'lik girdide fark 1,7 milisaniye. Günde beş çalıştırma × 1,7 ms = günde 8,5 milisaniye tasarruf. Bu tasarrufu bir yılda toplasam 3 saniye eder. 128 satır kodu yazmak ve hata ayıklamak bana bunun binlerce katı zaman aldı.

Kısacası: hız argümanı gerçek ama alakasız. Kendi kodunu yazan herkesin ilk söylediği şey bu ve çoğu zaman aynı sebeple boş.

Kaybettiklerim: 14 testin 13'ü

Asıl ilginç kısım burası. Yaygın 14 Markdown yapısını hem kendi çeviricime hem marked'a verip çıktıları karşılaştırdım. Sadece biri birebir tuttu.

Bir kısmı kozmetik: marked etiketlerin arasına boşluk koyuyor, ben koymuyorum; tablo hücrelerine align özniteliği ekliyor, ben class ile hallediyorum. Bunlar sorun değil.

Ama şu altısı gerçek kayıp:

YapıBenim çıktımOlması gereken
İç içe listeAlt maddeler üst seviyeye düzleşiyorİç içe ul
Görsel sözdizimiÜnlem işareti metin olarak kalıyor, gerisi bağlantı oluyorimg etiketi
Otomatik bağlantı (açılı parantez içinde URL)Kaçışlanmış düz metinTıklanır bağlantı
Kalın içinde eğikYıldızlar ekranda görünüyorİç içe strong ve em
Girintili kod bloğuNormal paragrafpre bloğu
Satır sonunda iki boşlukSatırlar birleşiyorSatır sonu

Bunların hiçbiri hata mesajı vermiyor. Sessizce yanlış HTML üretiyor. Görsel eklemeye çalıştığım gün ekranda ünlem işaretini görene kadar sorunu fark etmemiştim.

Bu, kendi çeviricini yazmanın gerçek maliyeti: kaybettiğin özelliklerin listesini kimse sana vermiyor. Kendin bulmak zorundasın, genellikle yayına çıktıktan sonra.

Ben bunu iki şekilde yönetiyorum. Birincisi, desteklenen alt kümeyi yazılı hâle getirdim ve yazarken ona uyuyorum. İkincisi, sitede görsel kullanmıyorum zaten — telifi belirsiz görsellerle uğraşmak istemiyorum — yani img kaybı beni hiç yakmıyor. İç içe liste kaybını ise düz listeye çevirerek geçiştiriyorum ve dürüst olmak gerekirse yazıların okunurluğuna zararı olmadı.

Bu arada tutan tek test şuydu: başlık içinde satır içi kod. Yani marked ile birebir aynı HTML'i ürettiğim tek yapı, hiç düşünmeden yazdığım en basit olanıydı. Bunda bir ders var sanırım.

Tedarik zinciri gerekçesi de çürük

İkinci gerekçem "bağımlılık istemiyorum, tedarik zinciri riski" idi. Bunu da kontrol ettim ve yine haksız çıktım:

Yani marked tarafında savunacak bir tedarik zinciri argümanım yok. Tek paket, kendi kodu, başka hiçbir şey çekmiyor. "npm bağımlılığı yüzlerce paket getirir" korkusu burada geçerli değil.

Peki doğru gerekçe neydi

Bunları eleyince geriye tek bir şey kaldı ve o da yeterince güçlüymüş.

Bu depoda package.json yok. Hiç. node_modules yok, kilit dosyası yok, npm ci adımı yok. Dağıtım hattı şundan ibaret: kaynağı çek, public/ klasörünü sunucuya kopyala. Toplam iki adım.

marked'ı eklemek 484 kB'lik bir kütüphane eklemek değil. Şunları eklemek:

  1. package.json ve kilit dosyası
  2. CI'ya bir npm ci adımı ve onun ağ bağımlılığı
  3. Bakılması gereken bir bağımlılık güncelleme akışı
  4. Node sürümü ile paket sürümü arasında ileride çıkabilecek bir uyumsuzluk

Dördü de tek başına küçük. Ama bu, tek kişilik bir stüdyonun tek başına baktığı bir tanıtım sitesi. Buradaki her bakım kalemi, oyunla ilgilenmediğim bir saat demek. Sıfır bağımlılıklı bir depoyu sıfır bağımlılıklı tutmanın değeri, o depoyu üç yıl sonra açtığınızda ortaya çıkıyornpm install çalışmadığı için önce onu tamir etmek zorunda kalmıyorsunuz.

Yani gerçek gerekçe hız değil, hiçbir şeyin yokluğunu korumak.

Bunu sizin de yapmanız gerekir mi

Muhtemelen hayır. Kararı şuna indirgerdim:

Son bir not: ölçümler tek bir makinede, tek bir girdiyle yapıldı. Başka bir metinde, özellikle bol tablolu ya da bol satır içi biçimli metinlerde oranlar değişebilir. Ama bu yazının sonucu zaten hız oranına dayanmıyor — tam tersine, hız oranının önemsiz olduğuna dayanıyor.

Bu blogda reklam vermek ya da birlikte iş yapmak

MCALAB bağımsız bir stüdyo. Sponsorluk, çapraz tanıtım ya da bir iş birliği için:

ads@mcalab.com.tr

Ayrıntılar: Reklam & iş birliği. Kullanıcı desteği için destek sayfası.