사전 BFF
패턴

BFF

gabury1고친 사람 github-actions[bot]

BFF 는 화면 종류마다 그 화면만 상대하는 서버를 하나씩 세웁니다. 웹 화면에는 웹용 서버가, 모바일 앱에는 모바일용 서버가 붙습니다. 이 서버가 뒤쪽 여러 서비스에 대신 물어봅니다. 받은 답은 화면이 바로 쓸 모양으로 묶어 줍니다.

쉽고 빠른 이해

BFF 는 화면 종류 하나를 위해 일하는 전용 서버입니다. 웹 화면에 하나, 모바일 앱에 하나를 둡니다. 모바일 앱의 주문 페이지가 주문 상태와 상품 이름과 리뷰 수를 원하면, 모바일용 서버가 세 서비스에 물어 그 세 값만 한 번에 돌려줍니다.

모든 화면이 공용 서버 하나를 같이 쓰면 서로 발목을 잡습니다. 웹은 많이 받고 싶고 모바일은 적게 받고 싶습니다. 한쪽에 맞추면 다른 쪽이 필요 없는 값을 받거나 여러 번 다시 물어야 합니다.

순서는 이렇습니다.

  1. 화면이 자기 전용 서버에 한 번 요청합니다
  2. 전용 서버가 뒤쪽 서비스 여럿을 부릅니다
  3. 받은 답을 화면에 맞게 줄이고 합쳐서 돌려줍니다

대가가 있습니다. 화면 종류만큼 서버가 늘어납니다. 비슷한 코드도 서버마다 따로 생깁니다.

그래서 화면 종류가 하나뿐이거나 여러 화면이 거의 같은 값을 쓰면 BFF 는 필요 없습니다. 공용 서버 하나로 충분합니다.

상세

이 절은 먼저 모든 화면이 공용 서버 하나를 같이 쓸 때 무엇이 문제인지 봅니다. 그다음 화면 종류마다 서버를 하나씩 두면 그 문제가 어떻게 풀리는지를 그림과 코드로 따라갑니다. 끝으로 이 설계가 치르는 값과 쓰지 않을 때를 짚습니다.

예로는 쇼핑몰 하나를 끝까지 씁니다. 이 쇼핑몰에는 웹 화면과 모바일 앱이 있습니다. 뒤에는 주문 서비스, 상품 서비스, 리뷰 서비스가 서 있습니다.

이 문서에서 「화면 종류」는 웹 화면이나 모바일 앱처럼 사용자가 쓰는 프로그램 하나를 말합니다. 「페이지」는 그 안의 한 장입니다. 주문 내역을 보여 주는 장이 그 예입니다.

BFF 라는 이름

BFF 는 Backend for Frontend 의 줄임말입니다. 우리말로는 프론트엔드를 위한 백엔드라고 풉니다.

프론트엔드와 백엔드는 짝을 이루는 말입니다. 프론트엔드는 사용자가 직접 보는 화면 쪽 코드입니다. 백엔드는 그 화면에 데이터를 대 주는 서버 쪽 코드입니다.

이름에는 화면 종류 하나를 위해 서버를 둔다는 뜻이 담겨 있습니다. 화면 종류마다 하나씩 생기므로 복수형으로 Backends for Frontends 라고 쓰기도 합니다. 두 표기는 같은 것을 가리킵니다.

공용 API 하나로 버틸 때

BFF 가 없으면 모든 화면이 공용 서버 하나의 API(Application Programming Interface)를 같이 부릅니다. API 는 프로그램이 다른 프로그램을 부를 때 지키는 약속입니다. 이 문서에서는 서버가 밖에 열어 둔 요청 주소와 응답 모양을 가리킵니다.

공용 API 는 어느 화면에도 치우치지 않게 만듭니다. 주문 하나를 물으면 주문에 관한 값을 전부 돌려줍니다. 웹 화면은 그 값을 거의 다 씁니다. 모바일 앱은 그중 셋만 씁니다.

모바일 앱은 쓰지도 않을 값까지 받아 옵니다. 필요 없는 값까지 받아 오는 일을 오버페칭이라고 부릅니다. 모바일 망은 데이터 요금이 들어서 이 낭비가 눈에 띕니다.

반대 방향의 문제도 있습니다. 주문 페이지 하나를 그리려면 주문 API, 상품 API, 리뷰 API 를 차례로 불러야 합니다. 한 번으로 모자라 여러 번 부르는 일을 언더페칭이라고 부릅니다. 앱과 서버 사이를 오가는 횟수가 늘어난 만큼 화면이 늦게 뜹니다.

고칠 때도 걸립니다. 모바일 화면에 값 하나를 더하려면 공용 API 를 고쳐야 합니다. 그 API 는 웹도 쓰므로 웹 팀과 맞춰야 합니다. 두 팀의 일정이 서로 묶입니다.

화면마다 서버를 하나씩

BFF 는 이 공용 API 대신 화면 종류별 서버를 하나씩 세웁니다. 웹 화면은 웹용 BFF 만 부릅니다. 모바일 앱은 모바일용 BFF 만 부릅니다. 뒤쪽 서비스는 바뀌지 않습니다.

flowchart TD
    W["웹 화면"] --> WB["웹용 BFF"]
    M["모바일 앱"] --> MB["모바일용 BFF"]
    subgraph S["뒤쪽 서비스"]
        O["주문 서비스"]
        P["상품 서비스"]
        R["리뷰 서비스"]
    end
    WB --> S
    MB --> S

두 BFF 는 같은 서비스를 부릅니다. 다른 것은 돌려주는 모양입니다. 웹용 BFF 는 웹 화면이 원하는 대로, 모바일용 BFF 는 모바일 화면이 원하는 대로 답을 만듭니다.

이런 구조는 마이크로서비스에서 자주 보입니다. 마이크로서비스는 기능마다 작은 서비스를 따로 두고 그 여럿으로 시스템을 짓는 방식입니다. 서비스가 잘게 쪼개질수록 페이지 하나가 불러야 할 곳이 늘어나서 모아 줄 서버가 아쉬워집니다.

왕복이 옮겨 가는 곳

BFF 를 두면 앱이 서버와 오가는 횟수가 한 번으로 줍니다. 여러 서비스를 부르는 일은 BFF 가 서버들 사이에서 대신 합니다. 아래 그림은 모바일 앱의 주문 페이지 한 장을 그리는 순서입니다.

sequenceDiagram
    participant 앱 as 모바일 앱
    participant B as 모바일용 BFF
    participant 주문 as 주문 서비스
    participant 상품 as 상품 서비스
    participant 리뷰 as 리뷰 서비스
    앱->>B: 주문 페이지를 달라
    B->>주문: 주문 상태와 상품 번호
    주문-->>B: 배송 중 · 상품 7
    B->>상품: 상품 7의 이름
    상품-->>B: 티셔츠
    B->>리뷰: 상품 7의 리뷰 수
    리뷰-->>B: 12
    B-->>앱: 화면에 쓸 값만 한 번에
    Note over 앱,B: 모바일 망은 한 번만 건넌다

앱과 BFF 사이에는 요청과 응답이 한 번씩만 오갑니다. 나머지 호출은 BFF 와 서비스 사이에서 일어납니다. 서버끼리는 대개 같은 데이터센터 안에 있어서 이 왕복은 모바일 망을 건너는 왕복보다 훨씬 짧습니다.

코드로 본 BFF

모바일용 BFF 안의 주문 페이지 처리 하나를 자바 코드로 보겠습니다. order·product·review 는 각각 주문·상품·리뷰 서비스를 부르는 객체입니다. OrderPage 는 앱에 돌려줄 세 값을 담는 묶음입니다.

item 에는 주문된 상품의 번호가 담깁니다. 각 줄 오른쪽 주석이 그 호출이 돌려준 값입니다.

Java
OrderPage orderPage(long id) {
  var state = order.state(id);    // 배송 중
  var item = order.item(id);      // 7
  var name = product.name(item);  // 티셔츠
  var count = review.count(item); // 12
  return new OrderPage(state, name, count);
}

이 함수는 세 서비스를 불러 값 셋을 모읍니다. 주문 서비스는 주문에 관한 값을 많이 갖고 있습니다. 이 함수는 그중 상태와 상품 번호만 꺼냅니다. 앱이 받는 응답에는 상태, 이름, 리뷰 수 세 값만 들어 있습니다.

서로 기다릴 필요가 없는 호출은 동시에 보내기도 합니다. 위 코드에서 상품 이름과 리뷰 수는 상품 번호만 있으면 따로 물을 수 있습니다. 둘을 함께 보내면 응답이 빨라집니다.

BFF 가 맡는 일

BFF 가 하는 일은 대개 아래 셋으로 모입니다. 셋 모두 화면 종류 하나의 사정에 맞추는 일입니다.

일 무엇을 하나 쇼핑몰 예
모으기 여러 서비스를 불러 한 응답으로 합친다 주문 · 상품 · 리뷰를 한 번에
다듬기 화면이 안 쓰는 값을 빼고 모양을 바꾼다 상품 설명 전문을 빼고 이름만
버티기 한 서비스가 죽어도 나머지로 답한다 리뷰 서비스가 안 되면 리뷰 수만 비운다

셋째가 놓치기 쉽습니다. 서비스 하나가 응답하지 않았다고 페이지 전체를 실패로 돌리면 사용자는 아무것도 못 봅니다. 이렇게 일부만 실패한 상태를 부분 실패라고 부릅니다. BFF 는 그 값만 비워 두고 나머지를 돌려줍니다. 화면은 빈 값이 와도 깨지지 않게 만듭니다.

응답이 늦는 서비스를 끝없이 기다리지 않도록 타임아웃도 BFF 가 겁니다. 정해 둔 시간이 지나면 그 호출을 포기하고 그 값만 비웁니다.

누가 BFF 를 맡나

BFF 는 대개 그 화면을 만드는 팀이 맡습니다. 모바일 팀이 모바일용 BFF 를, 웹 팀이 웹용 BFF 를 고치고 배포합니다. 화면에 값 하나를 더할 때 다른 팀과 일정을 맞추지 않아도 됩니다.

얼마나 잘게 나눌지에 대한 경험칙이 하나 있습니다. 사용자가 겪는 경험 하나에 BFF 하나를 둡니다. 여기서 경험 하나는 페이지 한 장이 아니라 웹이나 모바일 앱 같은 화면 종류 하나입니다. 안드로이드 앱과 아이폰 앱이 같은 화면을 보이고 같은 팀이 맡으면 BFF 하나를 같이 써도 됩니다.

API 게이트웨이와 가르는 선

API 게이트웨이도 화면과 서비스 사이에 섭니다. API 게이트웨이는 모든 요청이 지나는 단일 입구입니다. 화면 종류와 상관없이 모든 요청에 걸 일을 한곳에서 처리합니다. 요청한 사람이 누구인지 확인하는 인증, 한 사용자가 너무 자주 부르지 못하게 막는 속도 제한이 그런 일입니다.

BFF 는 화면 종류마다 하나씩 있습니다. 그리고 그 화면만의 사정을 담습니다. 그래서 BFF 를 화면 종류별로 갈라 둔 API 게이트웨이로 보기도 합니다. 둘을 함께 쓰면 게이트웨이가 맨 앞에서 인증을 합니다. 그 뒤에서 BFF 가 화면별 응답을 만듭니다.

치르는 값

BFF 를 두면 서버가 화면 종류만큼 늘어납니다. 서버마다 배포하고 지켜봐야 할 일도 같이 늘어납니다.

비슷한 코드가 BFF 마다 따로 생깁니다. 주문과 상품을 합치는 코드가 웹용과 모바일용에 둘 다 들어갑니다. 공통 라이브러리로 빼면 중복은 줄어듭니다. 대신 두 BFF 가 그 라이브러리에 함께 매여 따로 고치기 어려워집니다.

요청이 지나는 단계도 하나 늘어납니다. 앱과 서비스 사이에 서버 하나가 더 끼므로 그만큼 지연이 붙습니다. 앞에서 본 왕복 절약이 이 비용보다 커야 남는 장사입니다.

비즈니스 로직이 BFF 로 새기 쉽습니다. 비즈니스 로직은 할인 계산이나 재고 확인처럼 화면과 상관없이 지켜야 하는 업무 규칙입니다. 이런 규칙이 BFF 에 들어가면 웹과 모바일이 서로 다르게 계산하게 됩니다. 그래서 업무 규칙은 뒤쪽 서비스에 둡니다. BFF 는 모으고 다듬는 일만 맡습니다.

쓰지 않을 때

화면이 웹 하나뿐이면 BFF 를 따로 둘 까닭이 약합니다. 공용 API 를 그 화면에 맞추면 되기 때문입니다. 여러 화면이 거의 같은 값을 쓸 때도 공용 API 하나로 충분합니다.

화면이 원하는 값을 스스로 고르게 하는 방법도 있습니다. GraphQL은 화면 쪽 코드가 받고 싶은 필드를 요청에 적어 보내는 질의 언어입니다. 화면마다 서버를 두는 대신 서버 하나가 화면마다 다른 모양을 내줍니다. 두 방법을 섞어 BFF 안에서 GraphQL 을 쓰기도 합니다.

관련 항목

BFF 가 속하는 아키텍처 양식

마이크로서비스 · 모놀리스 · 소프트웨어 아키텍처 · 아키텍처 양식 · 서비스 지향 아키텍처 · 분산 모놀리스

BFF 와 함께 앞단에 서는 중개자

API 게이트웨이 · 게이트웨이 · 리버스 프록시 · 로드 밸런서 · 프록시 · 서비스 메시

BFF 가 응답을 맞춰 주는 클라이언트

프론트엔드 · 클라이언트 · 브라우저 · 모바일 개발 · 모바일 앱 · 단일 페이지 애플리케이션

BFF 가 뒤에서 부르는 서버 쪽 구성 요소

백엔드 · API · 엔드포인트 · REST · gRPC · 서비스 디스커버리

BFF 가 응답을 모으며 쓰는 기법

요청 집계 · 타임아웃 · 재시도 · 서킷 브레이커 · 부분 실패 · 우아한 성능 저하 · 캐싱

BFF 를 대신할 수 있는 다른 수단

GraphQL · GraphQL 페더레이션 · API 조합 · 범용 API

BFF 가 풀거나 새로 낳는 문제

오버페칭 · 언더페칭 · 왕복 시간 · 지연 · 코드 중복 · 비즈니스 로직

BFF 앞의 게이트웨이가 맡는 기능

인증 · 인가 · 속도 제한 · TLS 종료 · 요청 라우팅

BFF 를 맡는 팀의 구조 원칙

콘웨이의 법칙 · 팀 토폴로지 · 독립 배포 · 스트림 정렬 팀

다른 이름: Backend for Frontend · Backends for Frontends · Backend for Frontends · 프론트엔드를 위한 백엔드 · BFF 패턴