Bir ödeme kütüphanesini güncelliyorsunuz. Fonksiyon isimleri aynı, TypeScript derlemesi başarılı, testler yeşil. Ancak üretimde bazı işlemler başarısız oluyor: Önceden null dönen bir fonksiyon artık hata fırlatıyor.
Değişiklik birkaç satırdan oluşabilir. Entegrasyon üzerindeki etkisi ise çok daha büyüktür.
Semantik versiyonlama 1.2.3 sayıları aslında ne söylüyor? Bu sayılar, bir güncellemenin mevcut kullanıcılarla uyumluluğu hakkında ne vaat ettiğini anlatır. Bu yazıda sürüm kararlarını, kurgusal bir ödeme SDK’sının geliştirme süreci üzerinden inceleyeceğiz.
Semantik versiyonlama nedir?
Semantik versiyonlama, sürümleri MAJOR.MINOR.PATCH biçiminde ifade eder:
| Bölüm | Anlamı | Örnek geçiş |
|---|---|---|
| MAJOR — Büyük sürüm | Geriye uyumsuz API değişikliği | 1.2.3 → 2.0.0 |
| MINOR — Küçük sürüm | Geriye uyumlu yeni işlev | 1.2.3 → 1.3.0 |
| PATCH — Yama sürümü | Geriye uyumlu hata düzeltmesi | 1.2.3 → 1.2.4 |
Minor artırıldığında patch; major artırıldığında diğer iki bölüm sıfırlanır. Sistemin temeli, açıkça tanımlanmış bir public API sözleşmesidir. SemVer 2.0.0 şartnamesi
1.2.3 içindeki sayılar özellik veya hata adedini göstermez. Hangi işlemlerin değiştiğini öğrenmek için sürüm notlarını incelemek gerekir.
Vaka: Ödeme SDK’sında sürüm kararı vermek
Aşağıdaki senaryo öğretici amaçla oluşturulmuştur; gerçek bir şirketin olay raporu değildir.
Üç farklı uygulamanın kullandığı payment-client adlı bir TypeScript SDK’sı düşünelim. Mevcut sürüm 1.2.3 olsun.
SDK’nın belgelenmiş sözleşmesi şöyle:
type Payment = {
id: string;
amount: number; // Kuruş cinsinden tam sayı
status: "pending" | "paid";
};
declare function getPayment(
id: string
): Promise<Payment | null>;Belgelerde ayrıca şu davranışlar tanımlanmış:
- Ödeme bulunamazsa fonksiyon
nulldöndürür. - Tutar, kuruş cinsinden ifade edilir.
- Ağ hatalarında
NetworkErrorfırlatılır.
Ekibin önünde üç ayrı değişiklik var. Aşağıdaki kararların her biri, başlangıç sürümü 1.2.3 kabul edilerek değerlendiriliyor.
Değişiklik 1: Belgelenmiş davranışı düzeltmek
SDK, bazı 404 yanıtlarında yanlışlıkla NetworkError fırlatıyor. Oysa sözleşme, ödeme bulunamadığında null döneceğini belirtiyor.
Düzeltme sonrasında:
if (response.status === 404) {
return null;
}Bu senaryoda 1.2.4 uygun bir sürüm kararıdır. Değişiklik, tanımlanan davranışı sağlıyor ve desteklenen kullanım biçimlerini koruyor.
Yine de sürüm öncesi şu soruyu araştırmak gerekir: Tüketici uygulamalar hatalı davranışı fark edip etrafına özel bir çözüm geliştirmiş mi?
Böyle bir kullanım varsa düzeltmenin duyurusu ve geçiş planı ayrıca ele alınmalıdır. “Bug fix” etiketi tek başına kullanıcı etkisini açıklamaz.
Değişiklik 2: İsteğe bağlı özellik eklemek
Ürün ekibi, ödeme sorgusunda makbuz bilgisinin de alınmasını istiyor:
type GetPaymentOptions = {
includeReceipt?: boolean;
};
declare function getPayment(
id: string,
options?: GetPaymentOptions
): Promise<Payment | null>;Mevcut çağrı geçerliliğini koruyor:
await getPayment("pay_123");Yeni özellik isteyen tüketici ise ikinci parametreyi kullanıyor:
await getPayment("pay_123", {
includeReceipt: true
});Eski çağrıların davranışı korunduğu varsayımıyla 1.3.0 uygun seçimdir.
Buradaki kritik kontrol, parametrenin gerçekten isteğe bağlı kalmasıdır. Yeni seçenek verilmediğinde ek ağ isteği yapılıyor veya farklı hata koşulları oluşuyorsa uyumluluk değerlendirmesi genişletilmelidir.
Değişiklik 3: Tutarın birimini değiştirmek
Ekip, geliştiricilerin işini kolaylaştırmak için amount alanını kuruş yerine TL olarak döndürmek istiyor:
// Önce
{ amount: 12500 }
// Sonra
{ amount: 125 }Alan adı ve veri tipi aynı kaldığından derleme başarılı olabilir. Fakat mevcut tüketici şu işlemi yapıyorsa:
const displayAmount = payment.amount / 100;Ekranda 125 TL yerine 1,25 TL gösterilir.
Bu değişiklik için 2.0.0 gerekir. Sözleşmede belirtilen ölçü birimi değişmiştir. Statik tip kontrolü, bu örnekteki anlam değişikliğini yakalayamaz.
İleri seviye mesele: Uyumluluğun kapsamı
Bu vakada yalnızca fonksiyon imzasını karşılaştırmak yeterli değildir. İnceleme sırasında tüketicinin gözlemlediği davranışları da değerlendirmek gerekir:
| Değişiklik | Bu SDK’da incelenecek etki |
|---|---|
null yerine hata fırlatılması | Tüketicinin kontrol akışı değişir |
| Kuruş yerine TL döndürülmesi | Hesaplamalar yanlış sonuç üretir |
| Yeni durum değeri eklenmesi | Tüm durumları ele alan tüketici kodu etkilenebilir |
| Desteklenen çalışma ortamının daraltılması | Bazı tüketiciler paketi çalıştıramayabilir |
| Varsayılan yeniden deneme davranışının değişmesi | İstek sayısı ve işlem süresi değişebilir |
Örneğin status alanına "refunded" eklemek ilk bakışta yalnızca genişletme gibi görünür. Ancak tüketici, olası değerleri eksiksiz ele alan bir kontrol yazmış olabilir:
function assertNever(value: never): never {
throw new Error(`Beklenmeyen durum: ${value}`);
}
function label(status: Payment["status"]): string {
switch (status) {
case "pending":
return "Bekliyor";
case "paid":
return "Ödendi";
default:
return assertNever(status);
}
}Tip birleşimi genişletildiğinde bu kod derleme hatası verebilir. Bu SDK için durum kümesinin kapalı mı, genişletilebilir mi olduğu baştan belgelenmelidir.
Kırıcı değişikliği aşamalı uygulamak
Tutar birimini değiştirmek için doğrudan mevcut alanın anlamını değiştirmek yerine şu geçiş tasarlanabilir:
1.3.0sürümündeamountTRYalanını ekleyin;amountdavranışını koruyun.- Belgelerde eski alanı kullanımdan kaldırılacak olarak işaretleyin.
- Tüketici uygulamaları yeni alana taşıyın.
- Eski alanı
2.0.0sürümünde kaldırın.
Public API’de kullanımdan kaldırma bildirimi minor artış gerektirir; uyumsuz kaldırma major değişikliktir. SemVer sürüm artırma kuralları
Bu geçişte kabul ölçütü somuttur: Eski tüketiciler kuruş hesabını sürdürebilmeli, yeni tüketiciler TL alanını kullanabilmelidir. İki alanın dönüşüm tutarlılığı da test edilmelidir.
^1.2.3 kullanmak güncellemeyi güvenli kılar mı?
npm ekosisteminde sürüm aralıkları, hangi sürümlerin seçilebileceğini belirler. Kararlı sürümler açısından:
| Tanım | İzin verilen aralık |
|---|---|
1.2.3 | Yalnızca bu sürüm |
~1.2.3 | 1.2.3 ve üzeri, 1.3.0 altı |
^1.2.3 | 1.2.3 ve üzeri, 2.0.0 altı |
^0.2.3 | 0.2.3 ve üzeri, 0.3.0 altı |
^0.0.3 | Yalnızca 0.0.3 |
Ön sürümlerin aralığa dahil edilmesi ayrıca kurallara bağlıdır. ^ ve ~, npm’in aralık yorumlama davranışlarıdır. node-semver belgeleri
Vakamızda ekip, tutar birimini yanlışlıkla 1.2.4 altında yayımlarsa ^1.2.3 bu hatalı sınıflandırmayı anlayamaz. Aralık denetimi paketin iş mantığını incelemez.
package-lock.json, çözümlenen bağımlılık ağacını kaydederek aynı ağacın yeniden kurulabilmesini sağlar. Uyumluluğu ise uygulama testleriyle değerlendirmek gerekir. npm package-lock.json belgeleri
Sürüm kararını CI sürecine taşımak
Bu SDK için yayın kontrolünü üç parçaya ayırabiliriz.
API kontrolü: Dışa aktarılan tipleri karşılaştırın. Kaldırılan alanları ve zorunlu hâle gelen parametreleri görünür kılın.
Davranış kontrolü: 404 → null, tutarın kuruş olması ve ağ hatasının türü gibi vaatleri test edin.
Tüketici kontrolü: SDK’nın aday sürümünü kullanan örnek uygulamalarda derleme ve entegrasyon testleri çalıştırın.
Örneğin tutarın anlamını koruyan bir sözleşme testi şöyle olabilir:
it("125 TL tutarını 12500 kuruş olarak döndürür", async () => {
// Test sunucusundaki kayıt: 125 TL
const payment = await client.getPayment("pay_125_try");
expect(payment?.amount).toBe(12500);
});Bu test, veri tipi değişmeden yapılan birim değişikliğini yakalar. Yayın kontrolünde sorulacak soru da nettir: Değişiklik hangi tüketici beklentisini etkiliyor ve seçilen sürüm bunu doğru anlatıyor mu?
Ön sürüm ve derleme bilgisi nasıl okunur?
2.0.0-rc.1+build.482 örneğinde rc.1 ön sürümü, build.482 derleme üstverisini belirtir. Ön sürüm, aynı numaralı normal sürümden önce sıralanır; derleme üstverisi önceliği değiştirmez. Yayımlanmış sürümün içeriği değiştirilmemelidir. SemVer şartnamesi
Vakamızda rc.1, tüketici uygulamaların yeni tutar modelini deneyeceği bir aday olarak kullanılabilir. Yayın kararı, yalnızca SDK testlerine değil, bu uygulamaların geçiş sonuçlarına da bağlanabilir.
Vakanın sonucu: Sürüm numarası bir mühendislik kararıdır
Ödeme SDK’sındaki üç değişiklik, farklı kontroller gerektirdi: Hata düzeltmesinde belgelenmiş davranış, yeni özellikte eski çağrıların korunması, birim değişikliğinde tüketicinin hesaplamaları incelendi.
Ekibinizin bir sonraki sürüm incelemesinde şu soruyla başlayın:
“Mevcut kullanıcı bu güncellemeyi aldığında hangi varsayımları geçerliliğini koruyacak?”
Bu soruya kod, belge ve testlerle cevap verebildiğinizde, 1.2.3 anlamlı bir uyumluluk iletişimine dönüşür.