O Telefon Neden Çalar? API Tasarımında "Bugünü Kurtarma" Tuzağı
Hadi dürüst olalım, bir yazılımcının en büyük kâbusu nedir? Sunucuların çökmesi mi? Veri kaybı mı? Bence bunlardan daha sinsi, daha can sıkıcı bir durum var: Sabahın köründe, tam da kahvenizi yudumlayıp güne başlamaya hazırlanırken (veya benim gibi ormanda huzurlu bir sabah yürüyüşü hayal ederken) telefonun çalması ve karşıdaki sesin şunu söylemesi: "Uygulama çalışmıyor, veriler gelmiyor!"
2005 yılından beri bu sektördeyim, Pixel Lab®'ı kurarken de, öncesindeki o uykusuz gecelerde de şunu çok acı bir şekilde tecrübe ettim: Genellikle sistemin "patlaması", sunucunun fişinin çekilmesinden değil, bizim "küçük, masum bir değişiklik" yapmamızdan kaynaklanır. API yanıtında bir JSON anahtarının adını değiştirmek (`user_id` yerine `id` demek gibi) o an size çok mantıklı, çok daha temiz gelebilir. "Zaten doğrusu bu, kodu düzeltiyorum" dersiniz. Ama o API'yi tüketen mobil uygulama, o değişikliği bilmediği için duvara toslar. İşte o an, dijital dünyadaki huzurunuz kaçar ve kriz yönetimi başlar.
Bugün biraz kod editöründen kafamızı kaldırıp, mimariye, yani işin strateji kısmına odaklanalım istiyorum. Çünkü API tasarımı, sadece veri tabanından veri çekip JSON olarak fırlatmak değildir. API tasarımı, karşıdaki geliştiriciye (veya gelecekteki kendinize) verdiğiniz bir sözdür. Ve bu sözü tutmak, sürdürülebilir yazılım geliştirmenin temelidir.
Neden Sürdürülebilirlik? (Ve Neden Orman Metaforu?)
Beni tanıyanlar bilir, doğada vakit geçirmeyi, kamp yapmayı severim. Ormanda bir patika açıldığında, o patika yıllarca orada kalır. İnsanlar, hayvanlar o yolu kullanır. Siz bir gün gidip "Bu yolun manzarası kötü, şuradan geçsin" diye patikayı bir anda kapatıp 500 metre öteye taşırsanız, o yolu ezbere bilen herkes kaybolur. Yazılımda da durum tam olarak budur.
API Versioning (Sürümleme) ve Geriye Dönük Uyumluluk (Backward Compatibility), o patikayı kullananları mağdur etmeden yeni yollar inşa etme sanatıdır. Eğer bir API tasarlıyorsanız, sadece bugünün ihtiyaçlarını değil, 6 ay sonra bu sistemi kimin, nasıl kullanacağını da düşünmek zorundasınız. Aksi takdirde, yazdığınız kod bir süre sonra "teknik borç" bataklığına dönüşür ve o bataklıkta ilk boğulan da genellikle siz olursunuz.
Strateji Masası: Hangi Versioning Yöntemi?
Bir API'yi güncellerken, eski kullanıcıları kırmadan yeni özellikler eklemenin en garantili yolu versiyonlamadır. Ancak burada yazılım dünyasında bitmek bilmeyen o kutsal tartışmaya giriyoruz: "Versiyon bilgisini nerede taşımalıyız?"
Yıllar içinde farklı projelerde, farklı ekiplerle çalıştım. Gördüğüm en yaygın üç yöntemi ve kendi tecrübelerime göre avantaj/dezavantajlarını şöyle özetleyebilirim:
1. URI Versioning (Yol Üzerinde Sürümleme)
Muhtemelen en sık karşılaştığınız yöntem budur ve açıkçası benim de en sevdiğim, en pragmatik bulduğum yöntemdir.
GET /api/v1/products
GET /api/v2/products
Neden Seviyorum?
Çok net. Tarayıcıya linki yapıştırdığınızda hangi versiyonla konuştuğunuzu görüyorsunuz. Karmaşık header ayarlarına gerek yok, dokümantasyonu okumayan bir geliştirici bile URL'ye bakıp "Ha, bu versiyon 1" diyebiliyor. Pixel Lab® projelerinde sadeliğe önem verdiğim için genellikle bu yöntemi tercih ediyorum.
Eleştiriler:
REST puristleri (safkan REST savunucuları) buna kızabilir. "URI kaynağı temsil eder, versiyon kaynak değildir" derler. Haklılık payları var ama pratiklik çoğu zaman teorik mükemmelliği yener.
2. Query Parameter Versioning
Versiyonu bir parametre olarak geçmek:
GET /api/products?v=1
Bu yöntem de oldukça basittir ancak bazı CDN ve önbellekleme (caching) mekanizmalarında sorun çıkarabiliyor. Ayrıca URL'nin bir parçası gibi değil de, sanki bir filtreleme işlemiymiş gibi durması benim estetik algıma pek uymuyor. Yine de, hızlı ve kirli (quick and dirty) çözümler için kullanılabilir.
3. Header Versioning (Content Negotiation)
İşin "akademik" olarak en doğru görülen yolu budur. İsteğin başlık (header) kısmında versiyonu belirtirsiniz:
Accept: application/vnd.myapi.v1+json
Tecrübem Ne Diyor?
Bu yöntem çok temiz bir URL yapısı sunar (`/api/products` hep aynı kalır). Ancak geliştirici deneyimi (DX) açısından bazen tam bir işkenceye dönüşebilir. API'yi tarayıcıdan hızlıca test etmek istediğinizde header ekleyemezsiniz (eklenti kullanmadan). Basit bir `curl` isteği atarken bile ekstra parametre yazmanız gerekir. Eğer devasa, kurumsal ve çok sıkı standartları olan bir yapı kurmuyorsanız, bu karmaşıklığa girmenizi pek önermem.
Yıkıcı Olmayan Değişiklikler: Breaking Changes Sanatı
Versiyonlama stratejisini seçtik diyelim. Peki, her değişiklikte versiyon mu atlayacağız? `v1`'den `v150`'ye mi geleceğiz? Tabii ki hayır. İşte burada Geriye Dönük Uyumluluk devreye giriyor.
Bir API tasarlarken altın kuralım şudur: Var olanı kırma, üzerine ekle.
Diyelim ki bir kullanıcı objeniz var ve şöyle dönüyor:
{
"id": 120,
"name": "Buğrahan"
}
Müşteriniz geldi ve dedi ki: "Biz artık adı ve soyadı ayrı ayrı istiyoruz." Acemi bir yazılımcı (ki zamanında ben de yaptım bu hatayı) hemen kodu şöyle değiştirir:
{
"id": 120,
"first_name": "Buğrahan",
"last_name": "Soyad"
}
Bunu yaptığınız an, `name` alanını bekleyen tüm mobil uygulamalar, web siteleri ve 3. parti entegrasyonlar çöker. Tebrikler, breaking change (yıkıcı değişiklik) yaptınız!
Peki Nasıl Yapmalıydık?
Doğrusu "Additive Change" yani eklemeli değişikliktir. Eski alanı silmeyiz, yenilerini ekleriz:
{
"id": 120,
"name": "Buğrahan Soyad", // Eski alan hala burada, içi dolu.
"first_name": "Buğrahan", // Yeni alan
"last_name": "Soyad" // Yeni alan
}
Bu sayede eski entegrasyonlar `name` alanını okumaya devam eder, sistemleri çalışır. Yeni entegrasyon yapacak olanlar ise `first_name` ve `last_name` alanlarını kullanır. Herkes mutlu.
Eskiyi Ne Zaman Sileceğiz? (Deprecation Süreci)
"Buğrahan, sonsuza kadar çöp alanları mı taşıyacağız?" dediğinizi duyar gibiyim. Haklısınız, kod tabanını çöplüğe çevirmemek lazım. Ama bunu yapmanın yolu "silip kaçmak" değil, haber vermektir.
Eğer bir alanı kaldırmayı planlıyorsanız, önce onu Deprecated (kullanımdan kaldırılacak) olarak işaretlersiniz. Bunu dokümantasyonda belirtirsiniz, hatta API yanıtında özel bir header ile (örneğin `X-API-Warn: 'name' field is deprecated...`) geliştiriciyi uyarırsınız. Makul bir süre (örneğin 6 ay veya bir sonraki ana versiyona kadar) hem eski hem yeni alanı desteklersiniz. Süre dolduğunda ise `v2`'ye geçer ve temizliği orada yaparsınız.
Sözleşme Tabanlı Geliştirme ve İletişim
Teknik detaylar bir yana, sürdürülebilirliğin en önemli ayağı iletişimdir. Kod yazarken aslında diğer insanlarla (veya gelecekteki yorgun halinizle) konuşursunuz. API dokümantasyonu, bu konuşmanın metne dökülmüş halidir. Ama hepimiz biliyoruz ki, o dokümantasyonlar genellikle ya hiç yazılmaz ya da güncel değildir.
Benim projelerimde uyguladığım yöntem, kodun kendisinin dökümantasyon gibi davranmasıdır. Anlaşılır alan isimleri, tutarlı hata mesajları ve öngörülebilir HTTP durum kodları kullanmak, sayfalarca PDF'ten daha değerlidir. Bir API `200 OK` dönüp body içinde `{ "error": "Something went wrong" }` diyorsa, orada bir iletişim kopukluğu vardır. Standartlara uymak, karşı tarafa duyduğunuz saygının bir göstergesidir.
Geleceğe Not Bırakmak
Bisikletimle uzun bir rotaya çıktığımda, lastiğim patlarsa yanımda yedek iç lastik ve pompa olduğundan emin olmak isterim. Bu, yolculuğun sürdürülebilirliği için şarttır. Yazılımda da versiyonlama ve geriye dönük uyumluluk, işte o yedek lastiktir. İhtiyaç duyduğunuzda orada olduğunu bilmek size güven verir.
Bugün yazdığınız bir API endpoint'i, belki 5 yıl sonra, siz o şirketten ayrıldıktan çok sonra bile bir yerlerde çalışmaya devam edecek. O kodu devralacak genç geliştiricinin, arkanızdan "Bunu kim yazdıysa eline sağlık, ne kadar temiz düşünülmüş" demesi mi, yoksa kulaklarınızı çınlatması mı daha iyi? Ben şahsen, hem ormanda hem de kod dünyasında arkamda temiz bir iz bırakmayı tercih ediyorum.
Bir sonraki projenizde "Hızlıca yapıp geçeyim" dürtüsü geldiğinde, bir an durun ve o sabah çalacak telefonu düşünün. İnanın bana, şimdi harcayacağınız fazladan bir saatlik planlama, gelecekte size uykusuz gecelerden tasarruf ettirecek.
Yorumlar
Henüz yorum yapılmamış. İlk yorumu siz yazın!
Yorum Yaz