pnpm Catalog ile Dependency Drift Sorununu Çözmek: Production'da Kanıtlanmış Monorepo Stratejisi
pnpm'in catalog özelliği JavaScript monorepo'larındaki dependency drift sorununu temelden nasıl çözüyor - pratik uygulama pattern'leri ve kanıtlanmış stratejilerle
Özet
JavaScript monorepo’larındaki dependency drift versiyon çakışmaları, phantom bug’lar ve ciddi developer overhead yaratıyor. pnpm’in catalog özelliği, enforcement yetenekleriyle merkezi dependency governance sağlar; önemli disk alanı tasarrufu, daha hızlı kurulum ve production ortamlarında daha az merge conflict getirir.
Dependency Drift Sorunu
API gateway’ler kritik demo’lar sırasında kriptik TypeScript hataları vermeye başladığında, ve authentication microservice’ler payment processor’lardan farklı @types/node versiyonları çalıştırdığında, dependency drift ciddi bir architectural problem haline gelmiş demektir.
Bu pattern yaygın olarak launch schedule’ları yok eder, phantom bug’lar yaratır ve tüm sprint’leri yakar. Birçok takım dependency yönetimini workspace tool’larla çözmeye çalışır, oysa asıl ihtiyaç versiyon tutarlılığı üzerinde architectural control’dür.
Gerçek Dünya Etkisi
Dependency drift pratikte şöyle görünüyor. Birden fazla service’iniz var, her birinin kendi package.json’ı:
// packages/service-a/package.json
{
"dependencies": {
"lodash": "^4.17.21",
"axios": "^1.6.2"
}
}
// packages/service-b/package.json
{
"dependencies": {
"lodash": "^4.17.20", // Farklı versiyon!
"axios": "^1.6.5" // Farklı versiyon!
}
}
Zararsız görünüyor ama duplicate paketler, runtime conflict’leri ve şişmiş bundle’lar yaratıyor. Production monorepo’larda, birden fazla service’e yayılan bu pattern gigabyte’larca node_modules ile sonuçlanabilir - aynı paketler farklı versiyonlarda defalarca yüklenir.
Geleneksel Yaklaşımların Sınırları
Çeşitli çözümler mevcut: npm workspaces, Yarn workspaces, Lerna, Rush. Her birinin yeri var ama hiçbiri core problemi tam olarak çözmüyor:
| Özellik | npm Workspaces | Yarn Workspaces | pnpm Catalogs |
|---|---|---|---|
| Merkezi Versiyonlar | |||
| Phantom Dep’leri Önler | Kısmen | ||
| Disk Alanı Verimliliği | (%70 tasarruf) | ||
| Merge Conflict Azaltma | |||
| Performans | En Yavaş | Orta | En Hızlı |
Birçok organizasyondaki gizli maliyet? Developer cognitive load’u. Merge conflict çözme saatlerinin ötesinde, team’ler architectural momentum kaybediyor. Engineer’lar versiyon uyumsuzluklarını debug etmekle sistem tasarlamak yerine önemli zaman geçirdiğinde, stratejik engineering kapasitesi kaybediliyor. Bu pattern fintech, e-commerce ve SaaS platformlarda görülüyor - dependency management overhead’i team büyüklüğüyle exponential olarak ölçekleniyor.
Merkezi Dependency Kontrolü Sağlamak
Mevcut çözümlerin eksikliklerini analiz ettikten sonra, enforcement yetenekleriyle gerçek merkezi dependency governance kurmamız gerekiyordu. Zorluk şunları yapabilecek bir sistem implement etmekti:
- Tüm service’lerde versiyon uyumsuzluklarını önlemek
- Duplicate dependency’leri ve phantom dependency’leri elimine etmek
- Merge conflict’leri ve developer cognitive load’u azaltmak
- Enterprise ihtiyaçlarına ölçeklenirken performansı korumak
- Legacy service’ler için migration path’leri sağlamak
pnpm Catalog’ların Uygulanması
pnpm v9.5’te (2025) release edilip v10.17.0’a kadar (Eylül 2025 itibariyle güncel) olgunlaşan catalog’lar enterprise monorepo’ların ihtiyaç duyduğu şeyi sağlıyor: enforcement capability’leri olan gerçek merkezi dependency governance. İşte architectural implementation:
# pnpm-workspace.yaml
packages:
- 'apps/**'
- 'packages/**'
- 'services/**'
catalog:
# Core dependency'ler
typescript: ^5.9.2
lodash: ^4.17.21
axios: ^1.6.5
# React ekosistemi (stabil versiyonlar kullanarak)
react: ^18.3.1
react-dom: ^18.3.1
"@types/react": ^18.3.3
# Testing
vitest: ^1.2.0
"@testing-library/react": ^14.1.2
Artık individual paketleriniz sadece catalog’a referans veriyor:
{
"name": "@mycompany/user-service",
"dependencies": {
"lodash": "catalog:",
"axios": "catalog:",
"react": "catalog:"
}
}
Tek bir doğruluk kaynağı. Artık versiyon uyumsuzluğu yok. Artık merge conflict yok.
Migration Stratejisi: Kaostan Kontrole
Monorepo’ları catalog’lara migrate etmek için sistematik bir yaklaşım. Süreç genellikle iki hafta sürer ve anında faydalar sağlar.
Adım 1: Otomatik Catalog Oluşturma
Mevcut dependency manzarasını anlamak önemlidir. Bu script tüm monorepo’yu analiz eder ve ilk catalog’u oluşturur:
// scripts/migrate-to-catalogs.js
const fs = require('fs');
const yaml = require('js-yaml');
const glob = require('glob');
// Tüm unique dependency'leri topla
const dependencies = new Map();
glob.sync('**/package.json', {
ignore: ['**/node_modules/**', '**/dist/**']
}).forEach(file => {
const pkg = JSON.parse(fs.readFileSync(file, 'utf8'));
Object.entries(pkg.dependencies || {}).forEach(([name, version]) => {
if (!dependencies.has(name) || dependencies.get(name) < version) {
dependencies.set(name, version);
}
});
});
// Catalog konfigürasyonu oluştur
const catalog = Object.fromEntries(dependencies);
// pnpm-workspace.yaml'ı güncelle
const workspace = yaml.load(fs.readFileSync('pnpm-workspace.yaml', 'utf8'));
workspace.catalog = catalog;
fs.writeFileSync('pnpm-workspace.yaml', yaml.dump(workspace));
console.log(`${dependencies.size} dependency catalog'a migrate edildi`);
Adım 2: Legacy Service Yönetimi
Her şey hemen en son versiyonlara geçemez. Legacy service’ler React 17’de kalırken yenileri React 18 kullanabilir. Named catalog’lar bir çözüm sağlar:
catalogs:
# React 17'deki legacy service'ler
legacy:
react: ^17.0.2
react-dom: ^17.0.2
"@types/react": ^17.0.39
# React 18'deki modern service'ler
modern:
react: ^18.3.1
react-dom: ^18.3.1
"@types/react": ^18.3.3
Service’ler catalog’larını seçebiliyordu:
{
"name": "@mycompany/legacy-dashboard",
"dependencies": {
"react": "catalog:legacy",
"react-dom": "catalog:legacy"
}
}
Bu, anında güncelleme zorlamadan bir migration path sağlar.
Adım 3: Enforcement ve Validation
Validation uyumluğu sağlar. CI pipeline’lara strict validation eklemek tutarlılığı korumaya yardımcı olur:
// scripts/validate-catalogs.js
const validateCatalogs = () => {
const violations = [];
glob.sync('**/package.json', {
ignore: ['**/node_modules/**']
}).forEach(file => {
const pkg = JSON.parse(fs.readFileSync(file, 'utf8'));
Object.entries(pkg.dependencies || {}).forEach(([name, version]) => {
// workspace protocol ve local paketleri atla
if (version.startsWith('workspace:') || version.startsWith('file:')) {
return;
}
// Catalog kullanmalı mı kontrol et
if (!version.startsWith('catalog:')) {
violations.push(`${file}: ${name}@${version} catalog kullanmalı`);
}
});
});
if (violations.length > 0) {
console.error('Catalog ihlalleri bulundu:', violations);
process.exit(1);
}
console.log('Tüm dependency'ler catalog protocol kullanıyor');
};
validateCatalogs();
Gözlemlenen Kazanımlar
Performans İyileştirmeleri
Migration’dan sonraki benchmark’lar genellikle önemli iyileştirmeler gösterir:
# Kurulum hızı (50 paketlik monorepo)
npm install: 45.2s
yarn install: 31.4s
pnpm install: 22.1s # npm'den %51 daha hızlı
# Warm cache ile
npm install: 28.3s
yarn install: 18.7s
pnpm install: 8.4s # npm'den %70 daha hızlı
# Disk alanı kullanımı
npm: 2.8 GB (duplicate dependency'ler)
yarn: 2.1 GB (kısmi hoisting)
pnpm: 0.85 GB (hard link'ler, %70 tasarruf)
Önemli iyileştirmeler developer experience metriklerinde görülür:
- Dependency güncelleme süresi: önemli ölçüde azaldı
- Haftalık merge conflict’ler: büyük ölçüde azaldı
- “Benim makinemde çalışıyor” incident’leri: minimize edildi
Production Metrikleri ve İş Etkisi
Teknik performans iyileştirmelerinin ötesinde, iş etkisi önemlidir:
Developer Experience İyileştirmeleri:
- Dependency güncelleme süresi: drastik olarak azaldı
- Haftalık merge conflict’ler: minimize edildi veya tamamen ortadan kalktı
- Environment tutarlılık sorunları: önemli ölçüde azaldı
Kaynak Optimizasyonu:
- Dependency yönetim yükü: önemli ölçüde azaldı
- CI/CD compute zamanı: ölçülebilir azalma
- Developer verimliliği: kayda değer iyileşme
Uzun Vadeli Sonuçlar
Migration’dan aylar sonra, takımlar genellikle şunları rapor eder:
- Azalış gösteren dependency-related production incident’ler
- Birden fazla takımda daha hızlı build süreleri
- CI/CD environment’larda önemli disk alanı tasarrufu
- Dependency yönetim yükünde önemli azalma
- Staging’de daha az “environment parity” sorunu
Yaygın Hatalar ve Çözümler
Aşırı Merkezileştirme Tuzağı
Yaygın bir hata her dependency’yi catalog’a koymaktır. Service’e özel dependency’ler (uzmanlaşmış parser’lar veya araçlar gibi) catalog’a ait değil. Gerçekten paylaşılan dependency’lere odaklanın.
Phantom Dependency Sürprizi
Migration sırasında, service’ler bazen yanlışlıkla hoist edilmiş dependency’lere güvenme nedeniyle çökebilir. Kod, package.json’da açıkça belirtilmemiş ama hoisting yoluyla mevcut olan paketleri import edebilir.
Çözüm? Development’ta strict mode ile çalışın:
# .npmrc
strict-peer-dependencies=true
shamefully-hoist=false
Publishing Tuzağı
Önemli bir husus: paketleri publish ettiğinizde, catalog: protocol’ü gerçek versiyonlarla değiştirilir. Bu, publish edilen paketlerin beklenenden farklı versiyonlara sahip olmasıyla sonuçlanabilir.
CI’da her zaman publish edilen paketleri validate edin:
# .github/workflows/publish.yml
- name: Published paketi validate et
run: |
npm pack
tar -xzf *.tgz
cat package/package.json | jq '.dependencies'
Gelişmiş Uygulama Pattern’leri
Multi-Environment Catalog’lar
Environment’lar arasında farklı Node versiyonları çalıştırıyorsanız, environment-specific catalog’lar kullanın:
catalogs:
# Production (Node 22 LTS - Eylül 2025 itibariyle güncel)
production:
"@types/node": ^22.0.0
# Development (Node 22 - production consistency için)
development:
"@types/node": ^22.0.0
# CI/CD (Node 22 LTS stability için)
ci:
"@types/node": ^22.0.0
Otomatik Dependency Güncellemeleri
Catalog’ları Renovate ile birleştirerek otomatik güncellemeler yapın:
// renovate.json
{
"extends": ["config:base"],
"pnpm": {
"enabled": true
},
"packageRules": [
{
"matchManagers": ["pnpm"],
"matchFileNames": ["pnpm-workspace.yaml"],
"groupName": "catalog dependency'leri",
"schedule": ["her hafta sonu"]
}
]
}
Tek bir PR tüm monorepo’daki dependency’leri günceller. Artık 50+ individual PR yok.
Genel Değerlendirme
Geriye dönüp baktığımda, keşke bilseydim dediğim şeyler:
-
İlk günden catalog’larla başlayın. Monorepo büyüdükçe retrofit etmek katlanarak zorlaşıyor.
-
Strict mode’u hemen implement edin. Başta esnek olmak hala ödediğimiz teknik borç yarattı.
-
Named catalog’ları daha erken oluşturun. Her şeyi tek bir catalog’a zorlamaya çalışarak haftalar kaybettik.
-
Tooling’e baştan yatırım yapın. O migration ve validation script’leri? İlk gün yazmalıydım.
-
“Nasıl”ı değil “neden”i dokümante edin. Team buy-in’i, kurallara uymaktan değil problemi anlamaktan gelir.
Uygulama Rehberi: Adım Adım Geçiş
İkna olduysanız (ve olmalısınız), işte migration checklist’iniz:
Hafta 1: Değerlendirme
- Tüm paketlerdeki mevcut dependency’leri denetle
- Versiyon conflict’lerini ve duplicate’leri belirle
- Mevcut disk kullanımını ve build sürelerini hesapla
- Gerçek metriklerle team buy-in’i al
Hafta 2: Pilot
- pnpm v10.x+ kur (Eylül 2025 itibariyle latest stable)
- En küçük 2-3 service’i net başarı metrikleriyle migrate et
- CI’da otomatik enforcement’la catalog validation kur
- Catalog protocol’ü kullan:
"lodash": "catalog:"package.json’da - Edge case’leri ve architectural kararları dokümante et
- Performans iyileştirmelerini ve developer velocity kazançlarını ölç
Hafta 3: Ölçekle
- Otomatik migration script’lerini çalıştır
- Farklı environment’lar için named catalog’lar implement et
- Otomatik dependency güncellemeleri kur
- Catalog compliance için monitoring ekle
Hafta 4: Optimize Et
- Catalog organizasyonunu ince ayarla
- Strict enforcement implement et
- Team’i eğit
- Kazanımları kutla
Sonuç
Dependency drift sadece teknik bir problem değil - gerçek para maliyeti olan bir verimlilik katili. pnpm catalog’lar ölçekte gerçekten çalışan native, zarif bir çözüm sunuyor. Migration göz korkutucu görünebilir ama kazanç anında ve önemli.
Stratejik kazanç? Engineering team’leri toolchain maintenance yerine product innovation’a odaklanabiliyor. Senior engineer’larınız versiyon conflict’lerini debug etmeyip, business value sağlayan next-generation architecture tasarlıyorken gerçek değer yaratılıyor.
Monorepo’nuz bir dependency kabusuna dönüşmek zorunda değil. pnpm catalog’larla, esneklikten ödün vermeden merkezi kontrol sahibi olabilirsiniz. Araçlar burada, pattern’ler kanıtlanmış ve faydalar gerçek.
Catalog’lar aracılığıyla merkezileşmiş dependency yönetimi, sürdürülebilir ve ölçeklenebilir monorepo mimarisine doğru anlamlı bir adım.
Kaynaklar
- pnpm Katalog Dokümantasyonu - pnpm-workspace.yaml dosyasında yeniden kullanılabilir bağımlılık versiyonu sabitleri tanımlamak için resmi pnpm katalog özelliği rehberi.
- pnpm Çalışma Alanları Dokümantasyonu - pnpm’in yerleşik monorepo desteğine yönelik resmi rehber; workspace protokolü ve paket bağlantısını kapsar.
- pnpm-workspace.yaml Referansı - Katalog ve workspace tanımları dahil pnpm-workspace.yaml yapılandırma dosyası için tam referans.
- pnpm Paket Yöneticisi - Disk kullanımını azaltan içerik adreslenebilir depo ve hard-link yaklaşımını kapsayan resmi pnpm dokümantasyonu.
- pnpm Paket Kaynakları - pnpm’nin paketleri nasıl çözdüğüne dair dokümantasyon; catalog: protokolünü ve bağımlılık çözümlemesini anlamak için yararlı.
İlgili yazılar
Serverless ortamlarda Node.js'den Go'ya geçiş sürecinden gerçek deneyimler: performans kazanımları, takım zorlukları ve pratik karar çerçeveleri.
Production zaman hatalarının kökleri, Moment.js'den Day.js ve date-fns'e geçiş ve her yerde UTC kullanıp dönüşümü görüntüleme sınırına bırakma.
Yönlendirme motoru, analytics toplama ve API Gateway yapılandırması: günlük milyonlarca yönlendirme için performans optimizasyonları ve debugging stratejileri.
Bizi Middy'nin sınırlarının ötesine iten production zorlukları ve performance için optimize edilmiş özel bir middleware framework'ünü nasıl geliştirdiğimiz.
Runtime seçimi, veritabanı ayarları, bundle boyutu azaltma ve caching ile AWS Lambda'da sub-10ms response süreleri elde edin. Gerçek benchmark'larla.