Performans İpuçları
Önce ölç, sonra optimize et
Tahmine dayalı optimizasyon zaman israfıdır ve genellikle yanlış yeri hızlandırır. Veri olmadan etki ölçülemez.
Lighthouse / WebPageTest ile lab ölçümü; gerçek kullanıcılar için RUM (Real User Monitoring) — Web Vitals JS, Sentry Performance, New Relic Browser, Application Insights. p75 ve p95 metriklerine bak.
p50 hızlı görünür ama p95 yavaşsa kullanıcıların %5'i kötü deneyim yaşıyor demektir.
Core Web Vitals hedeflerini tut: LCP < 2.5s, INP < 200ms, CLS < 0.1
Google CWV'yi sıralama sinyali olarak kullanır ve kullanıcı algısı doğrudan bunlarla ölçülür. Eşiği geçemezsen hem SEO hem dönüşüm düşer.
LCP için kritik görseli preload + uygun boyut/format. INP için ana iş parçacığını uzun bloklardan koru (web worker, code split). CLS için görsel/iframe için boyut zorunlu, font swap stratejisi.
<img width="1200" height="630" loading="eager" fetchpriority="high"> ile hero LCP'sini 500ms düşürmek mümkün.
Görselleri modern formatta ve doğru boyutta sun
Görseller toplam payload'ın genelde %50+ ini oluşturur. PNG/JPG yerine AVIF/WebP %30–80 küçülme verir. Yanlış boyut indirip CSS ile küçültmek bandwidth israfıdır.
<picture> ile AVIF→WebP→JPEG fallback. srcset/sizes ile responsive. Foldun altındaki görsellere loading="lazy". CDN üzerinden on-the-fly resize (Cloudflare Images, ImageKit, Cloudinary).
Next.js: <Image>; .NET: ImageSharp.Web ile URL parametreleriyle (?width=800&format=avif) on-demand resize.
JavaScript bundle boyutunu kontrol altında tut
JS hem indirilir hem parse edilir hem çalıştırılır — üç maliyet. 3G mobil cihazda 200KB JS, 4–6 saniye CPU zamanı demektir.
Code splitting (route bazlı, dynamic import). Tree-shaking. Gereksiz polyfill'lerden kaçın (modern target). Bundle analyzer ile büyük modülleri tespit et. Üçüncü taraf script'leri performans bütçesine dahil et.
Hedef: kritik JS < 100KB gzip. moment.js → date-fns/Day.js (~70KB tasarruf). lodash → modüler import.
Cache header'ları ve CDN doğru kur
Statik varlıkların kullanıcıya en yakın noktadan ve cache'ten gelmesi RTT'leri kaldırır. Yanlış header → her seferinde yeniden indirme.
Hash'li dosyalar (app.abc123.js) için Cache-Control: public, max-age=31536000, immutable. HTML için no-cache veya kısa max-age + ETag. CDN katmanını her statik kaynak için aç.
Cloudflare/Bunny CDN: cache-everything kuralı + Cache-Control respected. ASP.NET Core: app.UseStaticFiles + ResponseCachingMiddleware.
Veritabanında doğru indeksleri oluştur
Indexsiz sorgular table scan demektir; veri büyüdükçe latency lineer artar ve ürün belli bir noktada 'duvara çarpar'.
EXPLAIN/EXPLAIN ANALYZE ile sorgu planını oku. WHERE/JOIN/ORDER BY kolonları için indeks. Composite indeksleri sıralama önemli; cardinality yüksek kolon önde. Yazım yoğun tablolarda fazla indeks yazma maliyetini artırır — dengele.
PostgreSQL: CREATE INDEX CONCURRENTLY ON orders(user_id, created_at DESC); — kullanıcının siparişlerini tarihe göre listeleyen sayfa için.
N+1 sorgu problemini tespit et ve elimine et
ORM'ler bazen 1 sorgu yerine N+1 sorgu üretir. Sayfa açılışında 100 kullanıcı için 101 sorgu — hem DB hem latency için yıkıcı.
EF Core: .Include / .ThenInclude / projeksyon. Prisma: include / select. Dapper: çoklu sorgu birleştir. Geliştirme ortamında query log'u aç ve kritik sayfaları ölç.
EF Core: db.Orders.Include(o => o.Items).ThenInclude(i => i.Product) — tek SQL'de fetch.
Sıkıştırma (Brotli/gzip) ve HTTP/2-3 etkin olsun
Brotli HTML/JS/CSS'i %15–25 daha küçük tutar. HTTP/2 multiplexing ile head-of-line blocking'i çözer; HTTP/3 (QUIC) mobil ağlarda kayıp toleransı sağlar.
Sunucu/CDN seviyesinde Brotli aç. Görseller zaten sıkıştırılmış olduğu için tekrar sıkıştırma. ASP.NET Core: app.UseResponseCompression + Brotli/Gzip provider'lar.
Cloudflare otomatik Brotli sunar. Kestrel/IIS arkasında Response Compression Middleware tipik kullanım.
Yazı tipi (font) yüklemesini optimize et
Web fontları render bloklayabilir, CLS'e neden olabilir. Yanlış yüklenirse FOIT (görünmez metin) ya da geç ortaya çıkma yaşanır.
WOFF2 kullan. Sadece kullanılan ağırlık/karakter setlerini al (subsetting). font-display: swap. Kritik fontu <link rel="preload"> ile preload. Variable font'lar tek dosyada birden çok ağırlık.
Inter Variable Latin subset (~30KB) tüm ağırlıkları kapsar; Google Fonts yerine self-host hızı artırır + GDPR dostu.
Kritik CSS'i inline et, geri kalanını lazy-load
Render-blocking CSS LCP'yi geciktirir. Above-the-fold için gerekli minimum CSS inline edilirse ilk paint anında olur.
Critical/critters/penthouse araçlarıyla kritik CSS çıkar. Geri kalan CSS'i media trick ile async yükle: <link rel="preload" as="style" onload="this.rel='stylesheet'">.
Tailwind: JIT modunda zaten kullanılan sınıfları üretir; sayfa-bazlı CSS bölmek faydalıdır.
Üçüncü taraf script'leri bütçe ile yönet
Analytics, chat widget, A/B testing — her biri ek 50–300KB ve onlarca uzun task. Yönetilmezse ana sayfa hızını yarıya düşürür.
Sadece gerçekten gereken script'leri yükle. Async/defer kullan. Mümkünse Partytown ile ana iş parçacığından çıkar. Üçüncü taraf script'leri Lighthouse 'third-party-summary' ile ölç.
Hotjar/FullStory benzeri session replay araçları INP'yi ciddi kötüleştirir; sample rate %5–10'a düşürmek genelde yeterli sinyal verir.
Connection pooling ve eşzamanlı bağlantı limitlerine dikkat
Her HTTP isteğinde yeni DB bağlantısı açmak çok pahalı; havuz dolarsa istekler kuyruğa girer ve cascading yavaşlama olur.
ORM/driver'da connection pool boyutunu CPU/RAM'a göre ayarla. Dış API çağrılarında HttpClient'i singleton tut (IHttpClientFactory). Async/await zincirini kesintisiz tut.
.NET: services.AddHttpClient<ApiClient>(); — handler havuzu otomatik. EF Core: Pooling=true (default), Max Pool Size connection string'de.
Büyük yanıtları stream et, belleğe alma
Büyük JSON/dosya'yı tüm belleğe alıp dönmek GC baskısı + bellek tüketimi yaratır; yüksek concurrency'de OOM riski.
ASP.NET Core: IAsyncEnumerable döndür, FileStreamResult kullan. Node: response.pipe(stream). Büyük import/export işlerini queue'ya at.
10K satırlık CSV export → arka plan job + signed URL ile sonuç dosyasını sun; sync HTTP'de yapma.
Hot path'lerde cache kullan, geçersiz kılmayı planla
Aynı sorguyu saniyede 1000 kez çalıştırmak savurganlık. Cache 10–100x kazanç verir ama 'cache invalidation' yazılım mühendisliğinin en zor 2 problemden biridir.
Read-heavy ve nadiren değişen veri: Redis/Memcached cache. Cache key tasarımına dikkat (versiyon ekle). TTL + event-based invalidation kombine. Stale-while-revalidate stratejisi.
.NET 9+: HybridCache (memory + distributed) tek API ile. CacheKey: "user:{id}:profile:v2". Bellek sızıntılarını uzun-ömürlü uygulamalarda izle
Server uygulaması haftalarca çalışır. Yavaş büyüyen bir leak (event listener, statik koleksiyon, IDisposable) sonunda restart zorlar veya OOM eder.
Heap snapshot karşılaştırması (dotnet-counters, Visual Studio Diagnostic Tools, Chrome DevTools). IDisposable'ları using ile saraj. Statik koleksiyonlara ekleme yapan kod yolu varsa boundedConcurrentDictionary kullan.
ASP.NET: ConfigureAwait gerekmez (sync context yok), ama iptal token'larını her async path'e geçir.