Breaking change: ne sayılır ve nasıl gönderilir
8 dk okuma güncellendi:
Bir breaking change, doğru yazılmış bir çağıranın hayatta kalamayacağı bir değişikliktir. Tanım önemlidir çünkü bir şeyin “sayılıp sayılmadığı” hakkındaki çoğu tartışma gerçekte kimin onu yanlış tuttuğu hakkındadır. Bir çağıran dokümanınızı takip ettiyse ve değişikliğiniz kodunun çalışmasını durdurduysa, değişiklik breaking’ti. Ne amaçladığınızın bununla hiçbir ilgisi yoktur.
Tüm test budur. Bu makalenin geri kalanı ondan çıkan şeydir: neyin testi geçemediği, neyin geçtiği, bir başarısızlığı merge edilmeden önce nasıl yakalayacağınız, ve bir tane gönderdiğinizi bildiğinizde ne yapmanız gerektiği.
Ne bir breaking change sayılır?
Testi çağırana uygulayın, diff’e değil. Sadece dokümante edilmiş davranışa güvenen bir çağıranın çalışmaya devam etmek için kodunu, yapılandırmasını veya verisini değiştirmesi gerektiğinde bir değişiklik breaking’tir. Bir alanı kaldırmak, bir endpoint’i yeniden adlandırmak, doğrulamayı sıkılaştırmak, bir varsayılanı değiştirmek ve bir değerin türünü değiştirmek hepsi buna uyar. İsteğe bağlı bir alan eklemek uymaz. Bir hatayı düzeltmek genellikle uymaz, aşağıda önemli bir istisna ile.
| Değişiklik | Breaking mi? | Neden |
|---|---|---|
| Bir alanı, endpoint’i, flag’i veya seçeneği kaldırmak veya yeniden adlandırmak | Evet | Doğru çağıranlar ona referans verir |
| İsteğe bağlı bir alan veya yeni bir endpoint eklemek | Hayır | Mevcut çağrılar değişmez |
| İsteğe bağlı bir girdiyi zorunlu yapmak | Evet | Onu atlayan çağrılar artık başarısız olur |
| Daha önce kabul edilen doğrulamayı sıkılaştırmak | Evet | Çalışan girdiler artık reddedilir |
| Bir varsayılan değeri değiştirmek | Evet | Onu ayarlamayan çağıranlar yeni davranış alır |
| Bir türü değiştirmek (string’den sayıya, tek değerden dizeye) | Evet | Dokümante edilen türe yazılmış parser’lar başarısız olur |
| Bir nesnenin anahtarlarını yeniden sıralamak | Hayır | Sırayı dokümante etmediyseniz |
| Çağıranların dayandığı bir hatayı düzeltmek | Pratikte evet | Kazara sözleşmeler bölümüne bakın |
| Bir hız sınırını veya boyut üst sınırını yükseltmek | Hayır | Çalışan hiçbir şey çalışmayı durdurmaz |
| Bir hız sınırını veya boyut üst sınırını düşürmek | Evet | İyi olan trafik artık kısıtlanır |
| Bir hata mesajının ifadesini değiştirmek | Değişir | Dokümante ettiyseniz veya çağıranlar buna göre eşleştiriyorsa breaking |
Ne breaking change sayılmaz?
Bir değişiklik, daha önce çalışan her çağrı değişmeden çalışmaya devam ediyor ve aynı anlama geliyorsa breaking değildir. Yeni bir endpoint eklemek, isteğe bağlı bir istek parametresi eklemek, yanıta bir alan eklemek, zorunlu bir girdiyi isteğe bağlı yapmak, bir sınırı yükseltmek ve kimsenin eşleştirmediği bir hata mesajını iyileştirmek testi geçer. Bu eklemeli değişiklikler sıradan bir changelog girdisiyle bir minor sürümde gönderilebilir.
Eklemeli değişiklikler yine de üç durumda çağıranları bozar. Deserializer’ı bilinmeyen alanları reddeden bir istemci ilk yeni yanıt alanında başarısız olur, bu yüzden çağıranların tanımadıkları alanları yok saymaları gerektiğini erkenden dokümante edin. Yeni bir enum değeri, kapsamlı bir switch’e sahip her çağıranı bozar (aşağıda daha fazlası var). Ve büyüyen bir yanıt, bir çağıranı hiç düşünmek zorunda kalmadığı bir boyut sınırının, zaman aşımının veya sütun genişliğinin ötesine itebilir.
Tablodaki dört satır daha yakından bakmayı hak ediyor, çünkü anlaşmazlıklar orada olur.
Ekiplerin kaçırdığı dört breaking change
Kazara sözleşmeler. API’niz üç yıl boyunca aynı dokümante edilmemiş alanı döndürdüyse, bir çağıran onun üzerine inşa etmiştir. Hyrum’un Kanunu kısa versiyondur: yeterince kullanıcıyla, sisteminizin gözlemlenebilir her davranışına biri bağımlı olacaktır. Bu yüzden “bu bir hata düzeltmesiydi” bir savunma değildir. Düzeltme doğru olabilir ve yine de breaking olabilir. Onu öyle gönderin.
Şema değişikliği olmayan davranış değişiklikleri. Alan hâlâ orada, tür aynı, ve değer artık
farklı bir şey ifade ediyor. Eskiden active veya inactive olan ve şimdi suspended de döndüren
bir status, kapsamlı bir switch’e sahip her çağıranı bozar. Yerel saatten UTC’ye geçen bir
timestamp, dokümanları iki kez okumayan herkesi bozar. OpenAPI dosyasının bir diff’inde bunların
hiçbiri görünmez.
Sıkılaştırılmış doğrulama. TLD’siz e-postaları, veya sondaki boşlukları, veya 80 karakterden uzun isimleri reddetmeye başlarsınız. Tam olarak bunu gönderen her çağıran şimdi geçen hafta çalışan bir istek için 400 alır. Doğrulama değişiklikleri en yaygın olarak “sıkılaştırma” düzeltmesi olarak gönderilendir.
Değişen varsayılanlar. Değeri açıkça ayarlayan kimse hiçbir şey fark etmez. Ayarlamayan herkes, ki bu çoğu çağırandır, bir satır değiştirmeden yeni davranış alır. Değişen bir varsayılan, kullanıcılarınızın çoğunluğunu tam olarak ayarı hiç görmedikleri için bozar.
Bir breaking change gönderilmeden önce nasıl tespit edilir?
Pull request’teki sözleşmeyi ana daldaki sözleşmeyle CI’da karşılaştırın ve breaking bir farkta build’i başarısız yapın. Çoğu arayüz formatı için şema diff araçları vardır ve her biri kendi formatının breaking kurallarını bilir:
| Arayüz | Araç | Neyi karşılaştırır |
|---|---|---|
| REST (OpenAPI) | oasdiff | İki OpenAPI spec’i, breaking-changes raporuyla |
| gRPC (Protobuf) | buf breaking | .proto dosyaları, wire veya kaynak düzeyinde |
| GraphQL | GraphQL Inspector | İki şema, breaking ve tehlikeli değişiklikleri işaretler |
| Rust crate’leri | cargo-semver-checks | Public API’yi son yayımlanan versiyonla |
| TypeScript paketleri | API Extractor | Paketin public API’sinin commit edilmiş bir raporu |
Bu araçlar kaldırılmış alanları, yeniden adlandırılmış operasyonları ve değişen türleri güvenilir şekilde yakalar. Yukarıdaki dört türün ilk ikisini, yani kazara bir sözleşmeyi veya bir davranış değişikliğini göremezler, çünkü ikisi de bir şemada görünmez. Aracı bariz olanları durdurmak için, geri kalanı için ise “doğru bir çağıran bunu fark eder miydi?” inceleme sorusunu kullanın. Aynı CI işi, bir changelog girdisini zorunlu kılmak için de doğal bir yerdir; bunu CI’da changelog girdilerini zorunlu kılma anlatır ve gRPC ve Protobuf API değişiklikleri wire düzeyindeki durumları ele alır.
Bir breaking change commit’te nasıl işaretlenir?
Conventional Commits ile bir breaking change, iki
noktadan önce bir ! ile (feat(api)!: remove the legacy export endpoint) veya BREAKING CHANGE: ile
başlayan ve bir açıklamanın izlediği bir footer ile işaretlenir. İkisi de bir major versiyona karşılık
gelir. Footer’ı changelog girdisinin ilk taslağı olarak yazın: kimin etkilendiğini ve ne yapması
gerektiğini söyleyin. Conventional commit’ler ve changelog,
bu kuralın sizi ne kadar ileri götürdüğünü anlatır.
Aynı kural kütüphaneler için de geçerlidir. Kaldırılmış bir public fonksiyon, daraltılmış bir parametre türü veya değişen bir dönüş değeri, semantik versiyonlama altında bir major versiyondur. Kütüphaneler bunu her zaman izlemez: 119.879 Maven Central yükseltmesi üzerine bir çalışma, bunların %16,6’sının semantik versiyonlamayı bozduğunu, ama istemci projelerin yalnızca %7,9’unun etkilendiğini buldu, çünkü bu değişikliklerin çoğu hiçbir istemcinin çağırmadığı koda dokunuyordu. Bozulma, çağıranda ölçülür.
Bir breaking change nasıl gönderilir?
Onu açıkça, bir tarihle, bir yolla gönderirsiniz. Aşağıdaki adımlar sırayla, ve sonuncusu çoğu ekibin atladığıdır: etkilenen insanlara bekledikleri şeyin şimdi olduğunu söylemek.
- Öyle olup olmadığına karar verin. Diff’i değil yukarıdaki testi kullanın. İki mühendis anlaşamıyorsa, breaking’tir; anlaşmazlık bir çağıranın makul bir şekilde eski davranışa dayanabileceğinin kanıtıdır.
- Versiyonlayın. Semantik versiyonlama altında bir breaking change bir major versiyondur. Tarihli veya versiyonlu bir API çalıştırıyorsanız, yeni bir versiyona girer ve eski, belirtilen bir tarihe kadar çalışmaya devam eder. Versiyonlayamıyorsanız, bir breaking change göndermiyorsunuz, bir changelog girdisiyle bir kesinti gönderiyorsunuz. Hangi şemanın versiyonu taşıdığı API versiyonlama en iyi uygulamaları’nın konusudur.
- Kod merge edilmeden önce girdiyi yazın. Girdinin sabit bir şekli vardır: ne değişiyor, kimi etkiliyor, ne yapmaları gerekiyor, ve ne zamana kadar. Dördünü de dolduramıyorsanız, değişiklik hazır değildir. Release notes şablonu, tam olarak bu yüzden bu girdileri bir sürüm numarası yerine bir tarihle önce koyar.
- Bir sürüm numarası değil bir son tarih verin. “v5’te kaldırıldı” sürümlerinizi takip etmeyen biri için hiçbir şey ifade etmez. “1 Kasım 2026’da çalışmayı durduruyor” herkes için aynı şeyi ifade eder.
- Göçü sağlayın. Eski çağrının yeni olanın yanında bir kod örneği. Değişiklik bir yeniden adlandırmaysa, her iki adı da aynı cümlede söyleyin. Kaldırılmış bir alansa, verinin nereye gittiğini söyleyin.
- Eski davranışın dokümante edildiği her yerde duyurun. Changelog, endpoint’i tarif eden doküman sayfası, SDK’nın release notes’u, ve varsa yanıttaki deprecation header’ı. Tek bir yerde duyurulmuş, orayı görmüş olan insanlara duyurulmuştur.
- Döngüyü kapatın. Bir müşteri değişikliği istediyse, veya ona yol açan hatayı bildirdiyse, gönderildiğinde ona söyleyin. Bu adım onu kullanıcılarınıza yapılan bir şeyden onlarla yapılan bir şeye dönüştürür.
İyi bir breaking-change girdisi nasıl görünür?
İyi bir girdi ilk satırda etkilenen çağıranı belirtir, tarihi belirtir, ve düzeltmeyi içerir. İşte sıkılaştırılmış doğrulama durumu için kullandığımız şekilde bir tane:
Alan adı olmayan e-posta adresleri 1 Kasım 2026’dan itibaren reddediliyor.
POST /usersvePATCH /users/:idşu andaalice@localhostgibi400 invalid_emaildöndürecek. Dahili dizinlerden kullanıcı oluşturan herhangi bir entegrasyonu etkiler. Göç: tam olarak nitelikli bir adres gönderin, veya alanı atlayıp sonra ayarlayın. Adresleriniz zaten bir alana sahipse hiçbir değişiklik gerekmez, ki bu yıl oluşturulan hesapların %99,4’ü için doğrudur.
Bu bildirimin nerede yaşadığı, ve yanında başka nelerin olması gerektiği, API changelog’un konusudur.
Sondaki yüzde bir dekorasyon değildir. Okuyucuya endişelenip endişelenmeyeceğini söyler, ki bu girdiyi açtığı sorudur.
Neden onları basitçe önlemiyoruz?
Çünkü alternatif daha kötü. Hiçbir zaman bir şeyi bozmayan bir API, yaptığı her hatayı biriktirir: yanlış adlandırılmış alan, yanlış varsayılan, yerel saatteki timestamp. Her biri, bir öğleden sonrada göç edebilecek çağıranları korumak için her yeni çağıran için sonsuza kadar bir vergidir. En iyi kararlılık itibarına sahip ekipler, nadiren, bir programa göre, bir göç yolu ve hedeflendiği insanlara ulaşan bir uyarıyla bir şeyleri bozar.
Bu uyarının mekaniği bir API’yi deprecate etmek üzerine olan yoldaş makalenin konusudur. Onu duyuran girdi, changelog akışındaki başka herhangi bir girdi gibi hazırlanır: merge edilmiş pull request’ten, bir insan için tutulur, sonra etkilenen çağıranların zaten okuduğu yerde yayımlanır.
FAQ
Breaking ile breaking olmayan bir değişiklik arasındaki fark nedir? Breaking bir değişiklik, doğru bir çağıranı çalışmaya devam etmek için kodunu, yapılandırmasını veya verisini değiştirmeye zorlar. Breaking olmayan bir değişiklik, mevcut her çağrıyı aynı anlamla çalışır bırakır; bu yüzden eklemeler genellikle güvenlidir, kaldırmalar, yeniden adlandırmalar ve sıkılaştırılmış kurallar ise genellikle değildir.
Zorunlu bir alan eklemek sayılır mı? Evet. Mevcut her çağrı onu atlar, bu yüzden mevcut her çağrı şimdi başarısız olur. Onu makul bir varsayılanla isteğe bağlı olarak ekleyin, veya endpoint’i versiyonlayın.
Bir hata düzeltmesi sayılır mı? Olabilir. Çağıranlar hatalı davranışa dayanıyorsa, düzeltmek dokümantasyon ne derse desin onları bozar. Gözlemlenebilir çıktıyı değiştiren herhangi bir düzeltmeyi, kimsenin dayanmadığını gösteremiyorsanız breaking olarak ele alın.
Semantik versiyonlama bir web API’sine uygulanır mı? Kural evet: breaking change’ler yeni bir major versiyon alır ve eski, belirtilen bir süre boyunca çalışmaya devam eder. Numara genellikle bir paket versiyonu yerine URL’de veya bir tarih header’ında yaşar.
Ne kadar bildirim yeterli? Bir çağıranın bildirimi bulup işi yapmasına yetecek kadar. Doksan gün, genel API’ler için yaygın bir taban çizgidir; uzaktan güncellenemeyen ve son kullanıcılara gönderilen kodda kullanılan herhangi bir şey için daha uzun.
Bu yazıdaki teknik iddialar bağımsız olarak kontrol edilmedi. Yanlış bir şey varsa bize söyle, düzeltelim.