İçeriğe atla
Ayhan Sipahi Ayhan Sipahi

BFF ile Mobil API Sürümleme: İstemciyi Geri Alamadığınızda Ship

Mobil binary geri alınamaz ve eski sürümler kalıcıdır; güvenlik ve hız sunucuya kayar: BFF, tüketici güdümlü sözleşmeler ve geriye dönük uyumlu sürümleme.

Sunucuda kötü bir deploy saniyeler içinde geri alınabilir; mobilde ise ship edilen binary kalıcıdır, app store incelemesi sizin kontrolünüz dışındadır ve eski istemci sürümleri aylarca kullanımda kalır. Bu asimetri, release stratejinizi belirlemesi gereken tasarım kısıtıdır: istemci, sistemin geri alamayacağınız tek parçasıdır; bu yüzden hem güvenlik hem hız, değiştirebildiğiniz tarafa kaymak zorundadır. Bu kısıttan doğan kollar şunlar: bir backend-for-frontend katmanı, bağımsız deploy için tüketici güdümlü sözleşmeler, geriye dönük uyumlu API evrimi ve server-driven UI’ın değerini nerede kanıtladığına dair net bir sınır.

Asimetrik Saat

Bir mobil ürünü iki saat yönetir ve bunlar farklı hızlarda çalışır. Sunucu saati hızlı ve geri alınabilirdir: production’da yakalanan bir regresyon, saniyelerle dakikalar arasında ölçülen bir redeploy ya da rollback uzaklığındadır. İstemci saati ise yavaş ve tek yönlüdür. Bir binary kullanıcıların eline geçtiğinde onu geri çağıramazsınız; iOS’ta kullanıcılar bilinen iyi bir eski sürüme geri dahi inemez. Düzeltme, app store incelemesinden geçmek ve sonra kullanıcıların kurmayı seçmesini beklemek zorundadır.

İnceleme sınırlıdır ama kontrol edilemez. Apple, ortalama olarak gönderimlerin %90’ının 24 saatten kısa sürede incelendiğini, birkaç güne uzayabilen bir kuyruk olduğunu belirtiyor. Bu, paydaşlara söz verebileceğiniz bir release zamanı değil, faydalı bir planlama girdisidir. Problemin daha yavaş yarısı ise adopsiyon. Yeni bir release’in benimsenmesi kademeli ve gönüllüdür; büyük bir mobil OS ship edildikten aylar sonra bile kurulu tabanının yalnızca üçte ikisi kadarına ulaşır ve aynı şekil uygulama güncellemeleri için de geçerlidir. Pratik çıkarım kesin bir eğri değil, yönseldir: eski istemciler haftalardan aylara kalır ve trafiğin anlamlı bir kısmı her zaman çok önce yayınladığınız sürümlerden gelir.

Istemci saati (tek yonlu, yavas)

Build gonder

Inceleme: %90 24 saatte, gunluk kuyruk

Haftalar ve aylar boyunca gonullu adopsiyon

Eski surumler tam olarak yok olmaz

Sunucu saati (geri alinabilir, hizli)

Deploy

Bug bulundu

Saniyeler icinde rollback

İstemci saati hızlandırılamadığı ya da geri alınamadığı için güvenlik kollarının sunucu tarafında yaşaması gerekir. Minimum sürüm kapısı (minimum-version gating) ve uzaktan kill switch’ler tam da bu nedenle yaygın bir uygulamadır: incelemeyi beklemeden bozuk bir özelliği devre dışı bırakmanıza ya da en eski istemciler için güncellemeyi zorlamanıza izin verirler. Forced-update’i genelde başvurabileceğiniz bir araç olarak görün; store’un her zaman onaylayacağı bir garanti olarak değil. Asıl köklü hamle ise yapısaldır. Değiştiremediğiniz parça binary ise, mümkün olduğunca az davranışın onun içine kilitlenmesi için tasarlayın.

BFF Katmanı

İlk yapısal kol, bir backend-for-frontend (BFF): her kullanıcı deneyimi için bir backend, UI’ı sahiplenen ekibin sahiplendiği bir backend. Sam Newman bu pattern’i, tek bir deneyime adanmış ve hem istemci hem sunucu bileşenlerinin release’ini hizalama sürecini basitleştiren bir backend olarak tanımlıyor. Kılavuz, her tüketici için tek bir ortak gateway değil, “bir deneyim, bir BFF”. Pattern, SoundCloud’da Phil Calçado’nun ekibi tarafından ortaya kondu; API gateway kataloğu da aynı fikri her istemci türü için ayrı bir API gateway olarak çerçeveler.

BFF burada önemli çünkü sunucu tarafı değişimi mümkün kılan sınırdır. Uygulama, UI ekibinin kontrol ettiği bir backend’le konuştuğunda, aksi halde binary içinde donmuş kalacak kararlar (hangi alanların gösterileceği, yanıtın nasıl şekilleneceği, hangi downstream servislerin çağrılacağı ve biri kullanılamaz olduğunda nasıl degrade edileceği) saniyeler içinde redeploy edebileceğiniz bir yüzeye taşınır. Her iki tarafı aynı ekibin sahiplenmesi bir koordinasyon devrini de ortadan kaldırır: bir istemci release’ini bir sunucu değişikliğiyle hizalamak, ekipler arası bir pazarlık olmaktan çıkıp tek ekibin deploy sırasına dönüşür.

Mobil uygulama (donmus binary)

BFF (UI ekibinin sahibi)

Servis A

Servis B

Servis C

Bedeli dürüsttür: bir BFF, çalıştırılacak, izlenecek ve güvenliği sağlanacak başka bir deployable’dır ve “deneyim başına bir tane” kuralı, bir iOS, Android ve web ürününün birkaç tane taşıması anlamına gelebilir. Takas, UI ekibi her değişiklik için backend ekiplerine bağımlı kalacaksa ya da her deneyim anlamlı biçimde farklı bir yanıt şekline ihtiyaç duyduğunda değerlidir. Tek ince bir istemci, tek bir kararlı servisle konuşuyorsa gerekçelendirmek zorlaşır; orada BFF, soğuracak fazla bir şey olmadan bir gecikme ve on-call yükü katmanıdır. Bu katman, aksi halde istemci saati release hızınızı belirleyecekse yerini hak eder.

Tek Başına Ship Etmenizi Sağlayan Sözleşmeler

BFF, UI ekibinin hareket etmesini sağlar ama başka ekiplerin sahiplendiği downstream servislerin önünde durur ve uygulama da BFF’in önünde durur. Bu sınırlar arasında bağımsız deploy edilebilirlik bir sözleşme problemidir. Hata modu big-bang entegrasyondur: ekipler değişikliklerini koordineli bir release penceresine kadar tutar, önceden test edilmiş bir uygulama setini birlikte deploy eder ve uyumsuzlukları ancak her şey bir araya geldiğinde keşfeder. O pencere, BFF’in kazandırması gereken hızı silen darboğaza dönüşür.

Tüketici güdümlü sözleşmeler bağımlılığı tersine çevirir. Her tüketici, gerçekten dayandığı sağlayıcı davranışının alt kümesini yayınlar; sağlayıcı da bu beklentilerin birleşimine karşı doğrulanır. Pact dokümantasyonu temel özelliği şöyle yakalar: mevcut tüketicilerin kullanmadığı herhangi bir sağlayıcı davranışı, testleri bozmadan serbestçe değiştirilebilir. Kırıcı değişiklikler, günler sonra ortak bir staging ortamında değil, gerçek tüketicilerin gerçek beklentilerine karşı CI’da, merge öncesinde yüzeye çıkar. (Pact, açık kaynak araç seti ve Pact Broker’dır; PactFlow ise SmartBear’ın ticari barındırılan broker’ıdır. Bi-directional contract testing, çalışan sağlayıcıyı doğrulamak yerine sağlayıcının kendi spec’ini tüketici beklentileriyle karşılaştıran ilişkili ama daha zayıf bir moddur; bu yüzden onu tam tüketici güdümlü doğrulamadan daha hafif bir garanti olarak görün.)

Bunu operasyonel hale getiren kapı can-i-deploy’dur. Koordineli bir seti birlikte deploy etmek yerine, broker’a tek bir uygulamanın belirli bir sürümünün, hedef ortamda zaten deploy edilmiş olanla uyumlu olup olmadığını sorarsınız:

pact-broker can-i-deploy \
  --pacticipant mobile-bff --version 4.2.0 \
  --to-environment production

Tüketici ve sağlayıcı sürümlerinin matrisini inceler ve deploy’a izin vermek için 0, engellemek için sıfır dışı bir kodla çıkar. Pact dokümanları bunu doğrudan, önceden test edilmiş uygulama setlerini birlikte deploy eden ve bir darboğaz yaratan eski yöntemle karşılaştırır.

uyumlu

dogrulanmamis cift

can-i-deploy: surum + ortam

Matris dogrulandi mi?

exit 0: deploy devam eder

sifir disi: deploy engellenir

Aynı ilkenin olay güdümlü bir karşılığı vardır. BFF ya da servisleri bir mesaj kuyruğu üzerinden haberleştiğinde, bir schema registry deploy sırasını belirleyen uyumluluk modlarını dayatır. Confluent’in Schema Registry’sinde varsayılan BACKWARD’dır; yani önce tüketiciler güncellenir; FORWARD önce üreticileri günceller; FULL her iki yönü de karşılar; ve TRANSITIVE kontrolü yalnızca bir önceki sürüm yerine tüm önceki sürümlere genişletir. O BACKWARD varsayılanı Confluent’e özgüdür; AWS Glue ve Apicurio gibi diğer registry’ler kendi varsayılanlarını seçer; bu yüzden varsaymak yerine çalıştırdığınız registry’nin davranışını doğrulayın. Sözleşme, senkron ya da asenkron biçimiyle, bir ekibin Newman’ın Building Microservices’te çerçevelediği bağımsız deploy edilebilirlik sorusunu yanıtlamasını sağlayan şeydir: bu servisi değiştirip başka hiçbir şeyi değiştirmeden tek başına deploy edebilir miyim.

Eski İstemciler Kaldığı İçin Geriye Dönük Uyumlu Evrim

Sözleşmeler bir değişikliğin deploy etmek için güvenli olup olmadığını söyler. Asimetrik saat ise ne tür bir değişikliğin güvenli olduğunu söyler: eklemeli, geriye dönük uyumlu olanı. Eski istemciler hiçbir zaman tamamen kaybolmadığı için her sunucu değişikliği, aylar önce ship ettiğiniz bir sürüm için çalışmaya devam etmek zorundadır. Mobil bir backend’in varsayılan duruşu bu yüzden yalnızca-eklemeli evrimdir ve iyi anlaşılmış birkaç pattern bunu pratik kılar.

Semantic versioning sözü sürüm numarasının kendisine kodlar. Bir MAJOR artış uyumsuz bir değişikliği, MINOR geriye dönük uyumlu eklemeleri, PATCH geriye dönük uyumlu düzeltmeleri işaret eder; şema yalnızca beyan edilmiş bir public API’ye karşı bir anlam taşır. Mobil bir backend için çıkarım nettir: MAJOR artışlar, kaçınmaya çalıştığınız değişikliklerdir, çünkü eski istemcileri ortada bırakanlar onlardır. Stripe, pratikte yalnızca-eklemeli evrime faydalı bir örnektir. Tarih tabanlı API sürümleri yapısı gereği geriye dönük uyumludur ve dokümantasyonu bu şema içindeki yükseltmeleri mevcut kodu bozmadan uygulanabilir olarak tanımlar. (Herhangi bir özel Stripe sürüm dizesini bir örnek olarak görün; şema zamanla ileri sarar.)

Gerçekten uyumsuz bir değişikliğe ihtiyaç duyduğunuzda, parallel change (expand/migrate/contract olarak da bilinir) bunu koordineli bir cutover olmadan güvenli kılar. Önce sunucuyu hem eski hem yeni şekli destekleyecek biçimde genişletirsiniz (expand), sonra tüketicileri kendi hızlarında geçirirsiniz (migrate) ve eski şekli ancak onu kullanan istemciler tükendiğinde kaldırırsınız (contract). Üretici başlangıçta bir kez deploy eder ve istemcilerin geçişini beklerken hiçbir zaman bloke olmaz; bu da tam olarak mobil durumun talep ettiği ayrıştırmadır. Bedel gerçektir: migrate aşamasında aynı davranışın iki sürümünü sürdürürsünüz ve mobilde bu aşama uzundur, çünkü ancak eski istemciler destek eşiğinizin altına düştüğünde biter.

Contract

Eski istemciler tukenince eski sekli kaldir

Migrate (mobilde uzun)

Yeni istemciler yeni sekli kullanir

Eski istemciler eski sekilde kalir

Expand

Sunucu eski + yeniyi destekler

İstemci tarafının kendi disiplini vardır: tolerant reader. Postel Yasası’nı izleyerek bir istemci gönderdiği şeyde tutucu, kabul ettiği şeyde liberal olmalıdır; bu da pratikte yalnızca ihtiyaç duyduğu alanları ayrıştırmak ve tanımadığı her şeyi yok saymak anlamına gelir. Toleranslı bir istemci, sunucunun serbestçe alan eklemesine izin verir, çünkü bilinmeyen alanları yok sayan eski bir binary daha zengin bir yanıta karşı çalışmaya devam eder. Eklemeli evrimi istemci saatinde hayatta tutan özellik budur: bugün eklediğiniz alan, birinin altı ay önce kurduğu binary’yi bozmaz. BFF ve tüketicilerinin tek bir repository’de mi yoksa birkaçında mı durduğu ayrı bir takastır ve buradaki kol değildir; kol, eski istemciler tükenene kadar her değişikliğin eklemeli kalmasıdır.

Server-Driven UI ve Bedeli

İstemci saatinden kaçmanın en agresif yolu server-driven UI (SDUI): yalnızca veriyi değil layout’u ve mevcut aksiyonları da sunucu temposuna taşımak; böylece binary, sunucunun gönderdiği talimatların genel bir renderer’ına dönüşür. Airbnb’nin Ghost Platform’u belgelenmiş bir örnektir; ekibi onu iOS, Android ve web genelinde layout ve aksiyonları orkestre eden, eski istemcilerin render etmeye devam etmesi için geriye dönük uyumlu section’lara sahip birleşik, belirli kararları dayatan bir server-driven UI sistemi olarak tanımlar. İşe yaradığında, tüm ekranlar için istemci saatini çökertir: hiç binary ship etmeden bir feed’i yeniden düzenleyebilir ya da bir akışı değiştirebilirsiniz.

Bedel kalıcıdır. Sunucunun sürdürebildiği her UI yeteneği, eski istemciler var olduğu sürece sunucunun uymak zorunda olduğu bir sözleşmeye dönüşür; bu da SDUI’nin bir önceki bölümün geriye dönük uyumluluk yükünden kaçmak yerine onu katladığı anlamına gelir. Ayrıca mühendislerin iyi anladığı bir karmaşıklığı (uygulamadaki tipli UI kodu) daha az tanıdık bir yere taşır (sunucu güdümlü bir şema ve sahadaki her sürüm için zarifçe degrade etmek zorunda olan bir renderer). Bedel sektör kaydında görünürdür: Spotify, HubFramework’ü inşa etti ve sonra emekliye ayırdı; kendi repository’si onu server-driven değil, backend güdümlü layout’lar için bir component-driven UI framework olarak tanımlar. SDUI’yi evrensel bir öneri değil, belgelenmiş bir vendor deneyimi olarak görün; onu sürdüren ekipler genelde yüksek ekran varyasyon oranlarına ve buna denk gelen platform yatırımına sahiptir.

YaklaşımSunucu kontrol ederİstemci kontrol ederGeriye dönük uyum / karmaşıklık bedeli
Yalnızca-veri APIVeri değerleriLayout, aksiyonlar, renderEn düşük: alanları eklemeli geliştir
BFF-şekilli yanıtlarVeri artı deneyim başına yanıt şekliLayout ve renderOrta: deneyim başına yanıt sözleşmeleri
Tam SDUIVeri, layout ve mevcut aksiyonlarYalnızca genel renderEn yüksek: her UI yeteneği kalıcı bir sözleşme

Spektrum bir karardır, tırmanmak zorunda olduğunuz bir merdiven değil. Çoğu ürün için orta yol yeterlidir: deneyim başına yanıtları şekillendiren bir BFF ve render’ı sahiplenen bir istemci. Tam SDUI, UI varyasyon oranı, her değişiklik için binary ship etmeyi baskın darboğaz yapacak kadar yüksek olduğunda ve ekip sahadaki her sürüm boyunca geriye dönük uyumlu kalan bir renderer taşıyabildiğinde doğru karardır. Onu varsayılan olarak seçmek, anladığınız bir problemi sonsuza dek ödediğiniz bir bedelle takas eder.

Kapanış

Savunulabilir varsayılan, “tam SDUI’ye geç”ten daha dardır. Sınırda bir BFF sahiplenin ki UI ekibi binary release’i olmadan davranışı değiştirebilsin; her sunucu değişikliğini eklemeli tutun, parallel change’i nadir uyumsuz olan için saklayın; ekiplerin big-bang penceresinde değil bağımsız deploy etmesi için tüketici güdümlü sözleşmeler ve bir can-i-deploy kapısı kullanın; ve SDUI’ye yalnızca UI varyasyon oranı kalıcı bedelini açıkça gerekçelendirdiğinde başvurun. Görüş alanında tutulması gereken şey sınırdır: eklediğiniz her sunucu tarafı kol, daimi bir geriye dönük uyumluluk yükümlülüğüdür, çünkü onu çağıran istemciler hiçbir zaman tamamen yok olmaz. Faydalı bir sonraki adım, en eski desteklediğiniz istemcinin hâlâ neyi çağırdığını denetlemektir; çünkü o yüzey, sürdürmeyi taahhüt ettiğiniz gerçek sözleşmedir.

Bunun parçası olduğu daha geniş release-temposu resmi için Üretime Giden Süreyi Kısaltmak yazısına, güvenlik ekseninde paralel argüman için İnceleme Kuyruğu Olmadan Güvenlik yazısına bakın.

Kaynaklar

İlgili yazılar