İçeriğe geç

BFF — Backend for Frontend

Orta 10 dk Çok sık karşılaşılır

Önce şunu oku: Mikroservis Katmanları — İstek Nereden Geçiyor

30 saniyede özet

BFF, tek bir ekrana (mobil, web) özel bir arka uçtur ve onu BFF yapan şey teknoloji değil, sahibidir: o ekranın ekibi. Herkesin ortak kullandığı bir BFF, adı değişmiş sıradan bir API'dir.

Bir düğünde her masaya atanmış bir garson, o masanın alerjisini ve çocuk menüsünü bilir. Bütün salona tek garson bakarsa kimsenin özel isteği takip edilemez.

  1. Bayt: Mobil ekibi ekrana ne göstereceğini değiştirmek istiyor, ama her seferinde başka bir ekipten izin bekliyor.

  2. Sen: Peki kendi arka uçları olsa?

  3. Bayt: İşte BFF. Ama onu BFF yapan kullandığı çatı değil, kimin sahip olduğu.

  4. Bayt: Masaya atanmış garson, masanın ne istediğini herkesten iyi bilir!

Mobil uygulamanın ekibi, ekrana ne göstereceğini başka bir ekipten izin almadan değiştirmek istiyor. Oysa BFFBackend for Frontend: tek bir istemci türüne (mobil, web, TV) hizmet eden, o istemcinin ekranlarına biçilmiş yanıt döndüren backend.Sahipliği istemci ekibindedir. Genel amaçlı bir API herkese yetecek kadar veri döndürmek zorundayken BFF tam gerekeni döndürür; bedeli, her istemci türü için ayrı bir servis bakmaktır.Sözlükte gör →’i BFF yapan şey kullandığı çatı değil, kimin sahip olduğu.

Sahiplik olmadan BFF olmaz

BFF’in tek üstünlüğü taraflı olabilmesi. Mobil ekranların ne istediğini bilir ve tam onu döndürür; genel amaçlı bir API ise herkese yetecek kadar döndürmek zorundadır.

Bu taraflılık ancak sahiplik istemci ekibindeyse sürer. Platform ekibinin baktığı bir BFF’de her ekran değişikliği yine başka bir ekibin kuyruğunda bekler — yani BFF’i kurma sebebin ortadan kalkar.

Sayı kuralı basit: istemci türü başına bir BFF. Ekran başına değil — o zaman yüzlerce servis bakarsın; tüm istemcilere tek tane de değil — o zaman BFF olmaktan çıkar.

Backend
Arka uç: sunucuda çalışan küçük bir servis...
For
...için:
Frontend
...bir ön yüz. Yalnızca tek bir istemcinin, örneğin mobil uygulamanın ihtiyacına göre yazılır.
Kafam karıştı, daha basit anlat

BFF, bir ekranın kişisel garsonudur: ne istediğini bilir ve tam onu getirir. Garsonu o ekranı yapan ekip yönetmezse, her istek başka bir ekibin sırasında bekler.

Hızlı kontrolBaşlangıç

Bir backend'i BFF yapan şey nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

BFF ile genel amaçlı bir API arasındaki temel fark nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

BFF’e ne girer, ne girmez?

BFF’e girerBFF’e girmez
Beş servisin yanıtını tek yanıtta birleştirmekİndirim tutarını hesaplamak
Mobilin kullanmadığı alanları çıkarmakSiparişin iptal edilebilir olup olmadığı
Tarih ve para biçimini istemcinin beklediği şekle çevirmekStok düşme kuralı
Hangi bağımlılığın zorunlu hangisinin isteğe bağlı olduğuFiyatın nasıl belirlendiği

Ayıran soru tek: aynı kural ikinci bir istemcide de geçerli mi? Geçerliyse orası BFF değil, domain servisidir. Geçerli değilse ve yalnızca bu ekranların derdiyse BFF’e aittir.

Kafam karıştı, daha basit anlat

Bir kural ikinci bir istemcide de geçerliyse, BFF’in değil asıl servisin işidir. BFF’e yalnızca o ekrana özel düzenlemeler girer.

Hızlı kontrolOrta

Bir mantığın BFF'e mi domain servisine mi ait olduğunu nasıl anlarsın?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Satır satır: bir servis düştüğünde

Bir BFF’in en kritik kararı birleştirme değil, her bağımlılık için zorunlu mu isteğe bağlı mı sorusuna verdiği cevap.

Beş bağımlılığın her biri %99,9 ise, hepsini zorunlu sayan sayfanın kullanılabilirliği kaç olur? Cevabı göster

Yaklaşık %99,5. Kullanılabilirlik toplanmaz, çarpılır: 0,999⁵ ≈ 0,995. Ayda yaklaşık 3,6 saat kesinti demek — ve bunun büyük kısmı yorumlar gibi isteğe bağlı bir servisten gelir.

Masaya atanmış garson, hangi tabağın şart olduğunu bilir.
Adım adım oku
  1. Mobil BFF, tek bir ekrana atanmış garson gibidir.
  2. Sayfa için beş servisten veri toplar: ürün, fiyat, stok, kargo ve yorumlar.
  3. Yorum servisi çöker.
  4. Yorumlar isteğe bağlı sayıldığı için sayfa yine açılır; yalnızca yorum kutusu boş gelir.

Zorunlu ve isteğe bağlı ayrımı

ProductPageBff.java
1// istemciye 3 sn sonra timeout dönüyor
2// BFF'in her servis çağrısı: 2 sn timeout, 1 retry
3
şu an çalışan satırvar product = catalogue.get(id);
5var price = pricing.get(id);
6var reviews = reviewService.get(id);
7
8return new PageDto(product.join(), price.join(), reviews.join());

Debug

Adım 1/6

zorunlu Ürün olmadan sayfa diye bir şey yok. Bu bağımlılık gerçekten zorunlu.

karar
= zorunlu
Java 21UTF-8LF4:1

Sol/sağ ok tuşlarıyla da gezebilirsin.

Buna timeout bütçesiBir zincirdeki timeout değerlerinin içten dışa artacak şekilde bölünmesi. Dıştaki içtekinden küçükse çağıran vazgeçer ama iş devam eder.Sözlükte gör → denir: aşağı indikçe süre küçülmeli. Retry’ı da bütçeye dahil etmen gerekir, çünkü retry süreyi katlar.

Aynı kararları bir mobil bankacılık ana ekranında görelim. Hesaplar şart, kart özeti ve döviz kurları olmasa da olur; bak ekran bu ayrımla nasıl ayakta kalıyor.

Derinleş · Mobil bankacılık ana ekranı: hesaplar şart, gerisi olmasa da olur 3 dosya · ~101 satır · ilk okumada atlayabilirsin
Proje dosyaları

mobile-bff/src/main/java/com/bank/bff/home/ HomeScreenView.java Ekrana biçilmiş cevap; gelemeyen bölümler ayrıca işaretlenir.

mobile-bff/src/main/java/com/bank/bff/home/HomeScreenView.java
// Shaped for this one screen. The app shows a quiet placeholder for each unavailable section.
public record HomeScreenView(
List<AccountTile> accounts,
List<CardTile> cards,
List<RateRow> rates,
Set<Section> unavailable) {
public enum Section { CARDS, RATES }
public record AccountTile(String name, String maskedIban, String balance) {} // "12.450,75 TL"
public record CardTile(String last4, String periodDebt) {}
public record RateRow(String pair, String buy, String sell) {}
public HomeScreenView {
unavailable = Set.copyOf(unavailable);
}
// Formatting helpers (Ibans, Money) are left out.
static HomeScreenView of(List<AccountDto> accounts, List<CardSummary> cards,
List<FxQuote> rates, Set<Section> unavailable) {
return new HomeScreenView(
accounts.stream().map(a -> new AccountTile(a.name(), Ibans.mask(a.iban()), Money.format(a.available()))).toList(),
cards.stream().map(c -> new CardTile(c.last4(), Money.format(c.periodDebt()))).toList(),
rates.stream().map(q -> new RateRow(q.pair(), q.buy().toPlainString(), q.sell().toPlainString())).toList(),
unavailable);
}
}

mobile-bff/src/main/java/com/bank/bff/home/ HomeScreenController.java Üç çağrı aynı anda başlar, her biri 1 saniyelik bütçeyle; kart ve kur hatası ekranı düşürmez.

mobile-bff/src/main/java/com/bank/bff/home/HomeScreenController.java
@RestController
@RequestMapping("/mobile/home")
class HomeScreenController {
// The app gives up after 3 s. One second per call and no retry keeps us inside that.
private static final long CALL_BUDGET_MS = 1_000;
private final AccountsClient accounts;
private final CardsClient cards;
private final FxClient fx;
private final Executor io; // a bounded pool for the blocking HTTP calls
HomeScreenController(AccountsClient accounts, CardsClient cards, FxClient fx, Executor io) {
this.accounts = accounts;
this.cards = cards;
this.fx = fx;
this.io = io;
}
@GetMapping
HomeScreenView home(@AuthenticationPrincipal Jwt token) {
String customerNo = token.getSubject();
// All three start at once: the screen waits for the slowest call, not the sum.
var accountsCall = call(() -> accounts.listFor(customerNo));
var cardsCall = optional(call(() -> cards.summariesFor(customerNo)));
var ratesCall = optional(call(fx::homeScreenRates));
// Required: without accounts there is no home screen, so this join may fail the request.
List<AccountDto> accountList = accountsCall.join();
Optional<List<CardSummary>> cardList = cardsCall.join();
Optional<List<FxQuote>> rateList = ratesCall.join();
Set<Section> unavailable = EnumSet.noneOf(Section.class);
if (cardList.isEmpty()) unavailable.add(Section.CARDS);
if (rateList.isEmpty()) unavailable.add(Section.RATES);
return HomeScreenView.of(accountList, cardList.orElse(List.of()), rateList.orElse(List.of()), unavailable);
}
private <T> CompletableFuture<T> call(Supplier<T> remote) {
return CompletableFuture.supplyAsync(remote, io).orTimeout(CALL_BUDGET_MS, TimeUnit.MILLISECONDS);
}
// Optional sections: a failure or a timeout becomes "not available", not an error page.
private static <T> CompletableFuture<Optional<T>> optional(CompletableFuture<T> call) {
return call.thenApply(Optional::of).exceptionally(ex -> Optional.empty());
}
}

mobile-bff/src/main/java/com/bank/bff/home/ HomeScreenControllerAllRequired.java Şöyle de yazılabilirdi: her servis zorunlu, sırayla ve retry'lı. Bak, kur kutusu düşünce bütün ana ekran düşüyor.

mobile-bff/src/main/java/com/bank/bff/home/HomeScreenControllerAllRequired.java
// Another way to write it: shorter, and it works on a good day.
@RestController
@RequestMapping("/mobile/home")
class HomeScreenControllerAllRequired {
private final AccountsClient accounts; // each client: 2 s timeout and 1 retry
private final CardsClient cards;
private final FxClient fx;
HomeScreenControllerAllRequired(AccountsClient accounts, CardsClient cards, FxClient fx) {
this.accounts = accounts;
this.cards = cards;
this.fx = fx;
}
@GetMapping
HomeScreenView home(@AuthenticationPrincipal Jwt token) {
String customerNo = token.getSubject();
// One after another: the waits add up, and one slow call alone can take 4 s.
var accountList = accounts.listFor(customerNo);
var cardList = cards.summariesFor(customerNo);
var rateList = fx.homeScreenRates(); // if the FX service is down, the whole home screen fails
return HomeScreenView.of(accountList, cardList, rateList, Set.of());
}
}
Hızlı kontrolOrta

Beş bağımlılığın her biri %99,9 kullanılabilir. Hepsini zorunlu sayan sayfanın kullanılabilirliği ne olur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Her sorumluluğu, BFF'e mi domain servisine mi ait olduğuna göre ayır.

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Sınıflandırılmamış

BFF

Yalnızca bu istemcinin derdi

    Domain servisi

    İkinci bir istemcide de aynı

      Kendin gör

      Aynı ürün sayfası BFF’i. Servislerin sağlığını, timeout’u, retry’ı, paralel çağrıyı ve isteğe bağlı servis için politikayı değiştir. Çubuklardaki dikey çizgi, istemcinin vazgeçtiği üçüncü saniye.

      BFF fan-out — bir servis düşünce sayfa ne olur?

      Tohum 316767
      ProductPageBff.java
      1// her çağrı: 2000 ms timeout, 1 retry; istemci 3000 ms bekler
      2var product = catalogue.get(id); // hepsi aynı anda başlar
      3var price = pricing.get(id);
      4var reviews = reviewService.get(id);
      5
      6return new PageDto(product.join(), price.join(), reviews.join());
      Java 21UTF-8LF
      • cataloguezorunlu
      • pricingzorunlu
      • reviewsisteğe bağlı
      • | istemcinin sınırı: 3000 ms
      Hız
      Adım 0

      Şu an ne oldu?

      Ürün sayfası isteği BFF'e geldi

      BFF üç servisi aynı anda çağırıyor. İstemci 3 saniye bekleyecek.

      Görevler0/3

      • Yalnızca yorum servisi düşükken bütün sayfayı düşüraçık

        İpucu

        Varsayılan ayarlarla oynat: ürün ve fiyat sağlıklı, yorumlar düşük, politika "sayfa hata dönsün".

      • Aynı durumda sayfayı yorumlar olmadan ayakta tutaçık

        İpucu

        Politikayı değiştir: isteğe bağlı servis boş liste dönebilir.

      • Yorum servisi YAVAŞKEN bile sayfa istemcinin 3 saniyesine sığsınaçık

        İpucu

        Yavaş bir servis, timeout × deneme kadar bekletir. İkisinin çarpımı 3 saniyenin altında kalmalı.

      Olay günlüğü (0)

      Henüz olay yok. Oynat veya adımla.

      1. Varsayılanla oynat. Yorum servisi düşük ve bütün sayfa 502 dönüyor.
      2. Politikayı “Yorumlar boş gelsin” yap. Aynı arıza artık kısmi bir sayfa.
      3. Yorum servisini “Yavaş” yap. Timeout ve retry, istemcinin üç saniyelik bütçesini aşıyor.
      4. Timeout’u 1 saniyeye indir. Sayfa yine zamanında ve kısmi dönüyor.
      5. Paralel çağrıyı kapat. Süre, en yavaş çağrı yerine üç çağrının toplamı oluyor.
      Hızlı kontrolOrta

      Simülatörde yorum servisi yavaş, politika "yorumlar boş gelsin", çağrı başına timeout 2 sn ve 1 retry var. İstemci 3 sn bekliyor. Ne olur?

      Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

      Tuzaklar

      BFF’e iş kuralı sızması “sadece şu küçük kontrol” diye başlar. Altı ay sonra indirim mantığının bir kısmı BFF’te, bir kısmı domain servisinde olur ve ikisi ayrışır. Ölçüt hep aynı: ikinci bir istemcide de geçerli mi?

      Ekran başına BFF. Sahiplik doğru ama sayı yanlış. Her ekran için ayrı bir servis, bakım yükünü sağladığı esnekliğin çok üstüne çıkarır.

      BFF’i servisler arası ortak çağrı noktası yapmak. Domain servisleri birbirini BFF üzerinden çağırmaya başlarsa BFF kritik yol hâline gelir ve elinde dağıtık monolitServisleri ayırıp bağımsızlığı kazanamamış sistem: ortak veritabanı, koordineli deploy, senkron zincirler.En kötü bileşim — monolitin kolaylığını kaybeder, mikroservisin faydasını almazsın. Teşhis sorusu tek: bir servisi tek başına deploy edebiliyor musun?Sözlükte gör → kalır. BFF yalnızca kendi istemcisine bakar.

      Kendini sına

      Şimşek turu1/5

      Bir BFF'i BFF yapan, kullandığı teknoloji değil sahipliğidir.

      Soru 1/4Orta

      Katalog servisi yanıt vermiyor. İstemci ne zaman ne görür?

      Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.
      TimeoutButcesi.java
      1// gateway istemciye 3 sn sonra timeout dönüyor
      2// BFF'in her servis çağrısı: 2 sn timeout, 1 retry
      3
      4var product = catalogue.get(id);
      5var price = pricing.get(id);
      6
      7return new PageDto(product.join(), price.join());
      Java 21UTF-8LF

      Aklında kalacak üç şey

      1. 1 BFF'i BFF yapan şey sahipliktir. Ekranın ekibi sahip değilse ortada ikinci bir genel amaçlı API vardır.
      2. 2 BFF'e ekranı hazırlama mantığı girer, iş kuralı girmez. Aynı kural başka bir ekranda da geçerliyse o kural BFF'e ait değildir.
      3. 3 Beş servisi sorgusuz birleştiren bir BFF, birinin düşmesiyle bütün ekranı düşürür. Her servis için 'zorunlu mu, olmasa da olur mu?' kararı verilmelidir.
      Sonraki kapı Başka bir servise yapılan çağrı sıradan bir metot gibi görünüyorsa, neyi gözden kaçırırsın? Feign Client — Kolaylığın Gizlediği Şeyler · 10 dk

      5 kart sonraki derste seni bekliyor

      0/5 kart bu dersten toplandı

      Bu dersin üstüne kurulanlar

      Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.