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.
| Çevirici | Medyan | En iyi | Kurulu boyut |
|---|---|---|---|
md.mjs (benim) | 0,88 ms | 0,76 ms | 4,8 kB, tek dosya |
marked | 2,55 ms | 2,20 ms | 484 kB |
markdown-it | 2,63 ms | 2,28 ms | 1,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ım | Olması gereken |
|---|---|---|
| İç içe liste | Alt maddeler üst seviyeye düzleşiyor | İç içe ul |
| Görsel sözdizimi | Ünlem işareti metin olarak kalıyor, gerisi bağlantı oluyor | img etiketi |
| Otomatik bağlantı (açılı parantez içinde URL) | Kaçışlanmış düz metin | Tıklanır bağlantı |
| Kalın içinde eğik | Yıldızlar ekranda görünüyor | İç içe strong ve em |
| Girintili kod bloğu | Normal paragraf | pre bloğu |
| Satır sonunda iki boşluk | Satırlar birleşiyor | Satı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:
marked: sıfır bağımlılık. Tek paket, 12 dosya, 484 kB.markdown-it: 6 doğrudan bağımlılık, toplam 7 paket.
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:
package.jsonve kilit dosyası- CI'ya bir
npm ciadımı ve onun ağ bağımlılığı - Bakılması gereken bir bağımlılık güncelleme akışı
- 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ıyor — npm 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:
- Projenizde zaten
package.jsonvarsa,markedkurun ve bu yazıyı unutun. Kendi çeviricinizi yazmanın hiçbir getirisi yok, kaybedeceğiniz 13 test var. - Çıktı üzerinde özel kontrol istiyorsanız (bende tablolar kaydırılabilir bir kutuya sarılıyor, dış bağlantılara otomatik
relekleniyor), bunun için de kendi çeviricinizi yazmanıza gerek yok —markedözel renderer destekliyor, 20 satırla aynı sonucu alırsınız. - Deponuz gerçekten bağımlılıksızsa ve bunu bir ilke olarak koruyorsanız, o zaman evet. Ama gerekçenizi "daha hızlı" diye yazmayın, çünkü değil. "Bu depoya npm sokmuyorum" diye yazın. Dürüst olan bu.
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.trAyrıntılar: Reklam & iş birliği. Kullanıcı desteği için destek sayfası.