BFF(Backend for Frontend)는 특정 프론트엔드를 위해 구축된 전용 백엔드 서비스입니다. 모든 클라이언트(웹, iOS, Android, 서드파티)가 동일한 범용 백엔드와 통신하는 대신, 각 클라이언트는 마이크로서비스의 데이터를 집계하고 인터페이스에 정확히 필요한 페이로드 형태로 재구성하는 자체 서버측 레이어를 갖게 됩니다.
샘 뉴먼(Sam Newman)은 2015년 사운드클라우드(SoundCloud)에서 진행된 작업을 바탕으로 이 패턴을 명명하고 대중화했습니다. 10년이 지난 지금도 BFF 패턴은 여러 클라이언트 앱 뒤에서 마이크로서비스를 실행하는 팀을 위한 표준 도구이며, Microsoft는 이를 핵심 클라우드 아키텍처 패턴으로 문서화하고 있습니다.
BFF가 해결하는 문제
단일 웹 앱과 단일 백엔드로 시작한 시스템을 상상해 보세요. 백엔드는 REST 엔드포인트를 노출했고, 웹 앱은 이를 사용했으며, 모든 것이 간단했습니다. 그러다 회사는 모바일 앱을 출시했습니다. 그리고 파트너 연동 기능을 추가했습니다. 이어서 스마트워치 위젯도 만들었습니다. 갑자기 네 개의 매우 다른 클라이언트가 모두 동일한 백엔드에서 데이터를 가져오려 하고, 그 백엔드는 모든 클라이언트를 동시에 만족시키려고 노력하게 됩니다.
이는 두 가지 반복적인 문제를 야기합니다.
과도한 가져오기(Over-fetching) 및 불충분한 가져오기(Under-fetching). 범용 엔드포인트는 고정된 형태의 데이터를 반환합니다. 데스크톱 대시보드는 주문 내역, 추천, 계정 설정을 포함한 전체 고객 기록을 한 번의 응답으로 원할 수 있습니다. 불안정한 셀룰러 연결을 사용하는 모바일 앱은 세 가지 필드만 원하며 그 이상은 필요 없습니다. 둘 다 동일한 엔드포인트에 요청하면 둘 중 하나는 잘못된 양의 데이터를 받게 됩니다. 모바일 클라이언트는 버려야 할 불필요한 페이로드를 다운로드하거나(과도한 가져오기) 필요한 것을 조립하기 위해 여러 번의 추가 왕복 요청을 해야 합니다(불충분한 가져오기).
다량의 요청을 보내는 클라이언트(Chatty clients). 백엔드가 특정 화면에 맞춰져 있지 않을 때, 클라이언트는 여러 번의 호출로 이를 보완합니다. 프로필 데이터, 알림 개수, 피드가 필요한 모바일 홈 화면은 세네 개의 마이크로서비스에 각각 세네 개의 개별 요청을 보낸 다음, 기기 내에서 결과를 조합할 수 있습니다. 모든 추가 왕복 요청은 지연 시간과 배터리 소모를 유발하며, 오케스트레이션 로직이 클라이언트로 누출되어 테스트 및 버전 관리가 어려워집니다.
근본적인 문제는 기술적인 만큼이나 조직적인 문제입니다. 공유 백엔드는 모든 프론트엔드 팀으로부터 상충되는 요구 사항을 받습니다. 한 팀의 변경 사항은 배포 전에 다른 모든 팀의 요구 사항에 대해 검증되어야 하므로, 백엔드는 병목 현상과 팀 간 마찰의 원인이 됩니다.
BFF 패턴 작동 방식
BFF 패턴은 하나의 프론트엔드와 하위 서비스 사이에 얇은 서버측 레이어를 도입합니다. 각 인터페이스는 자체 백엔드를 갖게 됩니다.
[ 웹 앱 ] ---> [ 웹 BFF ] ---\
[ iOS 앱 ] ---> [ iOS BFF ] -----> [ 마이크로서비스 ]
[ 안드로이드 앱 ] ---> [ 안드로이드 BFF ] ---/
각 BFF는 클라이언트를 위해 세 가지 작업을 수행합니다:
- 집계(Aggregate). 화면에 필요한 하위 마이크로서비스를 호출하고 응답을 결합하여, 클라이언트가 다섯 번 대신 한 번의 요청만 하도록 합니다. 이는 단일 사용자 경험에 적용된 API 집계입니다. 이 아이디어의 일반적인 버전을 원하시면 API 애그리게이터 패턴에 대한 설명을 참조하십시오.
- 재구성(Reshape). 필드를 다듬고, 클라이언트 친화적인 용어로 이름을 변경하며, 중첩된 구조를 평면화하고, 해당 인터페이스가 예상하는 방식으로 값을 포맷합니다. 모바일 BFF는 간결한 페이로드를 반환하고, 데스크톱 BFF는 풍부한 페이로드를 반환합니다.
- 번역(Translate). 페이지네이션 전략, 해당 클라이언트에 맞춰 조정된 응답 캐싱, 프로토콜 선택과 같은 클라이언트 특정 문제를 처리하며, 이러한 결정을 하위의 공유 서비스에 강요하지 않습니다.
하위 마이크로서비스는 범용적이며 프론트엔드에 구애받지 않습니다. 이들은 깔끔하고 재사용 가능한 기능을 노출합니다. BFF는 클라이언트 특정 형상화가 이루어지는 곳으로, 이 로직을 마이크로서비스와 클라이언트 앱 모두에서 분리합니다. 하위 서비스 레이어에 대해 잘 모르신다면, API와 마이크로서비스의 비교 및 모놀리식에서 마이크로서비스로의 전환에 대한 개요를 통해 맥락을 이해하실 수 있습니다.
클라이언트 경험당 하나의 BFF
뉴먼의 핵심 가이드는 간결합니다: 하나의 경험, 하나의 BFF. iOS 앱과 Android 앱이 의미 있게 다른 경험을 제공한다면, 각각에 자체 BFF를 제공하세요. 웹 앱과 모바일 앱이 달라진다면, 동일한 규칙이 적용됩니다.
이 규칙의 요점은 각 BFF의 초점을 유지하는 것입니다. 단일 BFF가 서로 다른 요구 사항을 가진 두 클라이언트를 서비스하려고 하는 순간, 조건부 로직(예: "모바일이면 이거 반환; 웹이면 저거 반환")이 쌓이기 시작하며, 결국 동일한 조정 문제를 가진 범용 백엔드로 돌아가게 됩니다. 초점을 맞춘 BFF는 작게 유지되어, 전체 패턴이 효과를 발휘하게 하는 속성을 가집니다.
사운드클라우드에서 뉴먼 자신이 제시한 합리적인 예외가 있습니다: 한 팀이 iOS 및 Android 앱과 같이 거의 동일한 경험을 공유하는 두 개의 유사한 클라이언트를 소유할 때, 그들 사이에 단일 모바일 BFF를 공유하는 것이 합리적일 수 있습니다. 결정적인 요소는 플랫폼 이름이 아니라 소유권과 유사성입니다. 이 규칙은 법이 아니라 기본값입니다.
소유권은 프론트엔드 팀에 속한다
BFF는 플랫폼 팀이 구축하여 넘겨주는 계층이 아닙니다. 클라이언트를 소유한 프론트엔드 팀이 해당 BFF를 소유합니다. 이것이 이 패턴이 작동하게 만드는 두 번째 요소입니다.
프론트엔드 팀이 BFF를 소유할 때, 그들은 출시 주기, 언어 및 런타임 선택, 백로그 우선순위 지정, 그리고 클라이언트 및 지원 서비스에 대한 변경 사항을 함께 배포하는 것을 제어합니다. 새로운 집계 엔드포인트가 필요한 UI 변경은 별도의 백엔드 팀에 티켓을 제출하고 해당 팀의 대기열이 비워지기를 기다릴 필요가 없습니다. 어려움을 겪는 팀이 해결책을 소유합니다.
이러한 자율성이 진정한 승리입니다. BFF는 경계를 이동시켜 클라이언트별 결정이 클라이언트를 담당하는 사람들에 의해 이루어지도록 합니다. 이는 API 주도 연결 사고방식이 "경험" 계층을 두는 곳과 정확히 일치합니다.
BFF vs API 게이트웨이
이것은 대부분의 팀이 혼란스러워하는 비교입니다. 왜냐하면 BFF와 API 게이트웨이는 다이어그램상으로는 비슷해 보이기 때문입니다. 둘 다 클라이언트와 서비스 사이에 위치합니다. 둘 다 라우팅 및 집계를 할 수 있습니다. 그러나 이들은 다른 질문에 답합니다.
API 게이트웨이는 인증, 속도 제한, 라우팅, TLS 종료, 요청 로깅 등 모든 트래픽에 대한 교차 관심사를 처리하는 범용 진입점입니다. 이는 플랫폼 또는 인프라 팀이 소유하며 의도적으로 클라이언트와 무관합니다. 하나의 게이트웨이가 모든 사람에게 동일한 방식으로 서비스를 제공합니다.
BFF는 그 반대입니다. 설계상 클라이언트 전용이며, 프론트엔드 팀이 소유하고, 그 목적 자체가 각 인터페이스마다 달라지는 것입니다. 이는 단일 클라이언트의 페이로드 형상화가 이루어지는 곳이며, 공유되는 병목 지점이 아닙니다.
두 가지는 라이벌 관계가 아닙니다. 일반적인 프로덕션 배치에서는 API 게이트웨이가 전면에 위치하여 모든 트래픽에 대한 인증, 속도 제한 및 모니터링을 처리한 다음, 각 클라이언트를 게이트웨이 뒤의 전용 BFF로 라우팅합니다. Microsoft의 참조 아키텍처는 바로 이것을 보여줍니다: 교차 관심사를 관리하는 게이트웨이가 있고, 그 뒤에 클라이언트당 하나의 서버리스 BFF가 있습니다. 클라이언트 간에 동일한 것은 게이트웨이를 사용하고, 다른 것은 BFF를 사용하십시오. (이 대비의 심층 버전은 별도의 기사에서 다루겠지만, 여기서는 서로 다른 계층에 위치하며 다른 요구 사항에 답한다는 것을 아는 것으로 충분합니다.)
주변 게이트웨이 환경에 대해서는 다음 비교 자료가 도움이 됩니다: API 관리 vs API 게이트웨이, API 게이트웨이 vs 로드 밸런서, 그리고 서비스 메시 vs API 게이트웨이.
BFF를 사용해야 할 때
다음 조건이 충족될 때 이 패턴은 제 역할을 합니다:
- 여러 개의 진정으로 다른 클라이언트가 있는 경우. 웹, 모바일, 파트너 통합 등 각각 고유한 데이터 요구 사항을 가집니다. 경험이 더 많이 분기될수록 BFF가 더 많이 도움이 됩니다.
- 공유 백엔드가 병목 현상이 된 경우. 모든 프론트엔드 변경이 팀 간 협상을 강요한다면, 클라이언트별 형상화를 팀별 BFF로 분할하면 조정 비용이 제거됩니다.
- 클라이언트 최적화 페이로드를 원하는 경우. 모바일은 간결한 응답과 공격적인 캐싱을 필요로 하며, 데스크톱은 풍부하게 집계된 데이터를 원합니다. BFF를 사용하면 타협 없이 각각을 최적화할 수 있습니다.
- 특정 언어가 하나의 프론트엔드에 더 잘 맞는 경우. 팀은 다른 BFF가 사용하는 런타임과 관계없이 클라이언트에 적합한 런타임으로 BFF를 구축할 수 있습니다.
BFF를 사용하지 말아야 할 때
이 패턴은 무료가 아니며, 비용만 추가하고 이점이 없는 명확한 경우가 있습니다:
- 클라이언트가 하나뿐인 경우. 단일 인터페이스에서는 BFF는 추가적인 한 단계에 불과합니다. 일반적인 백엔드를 구축하세요.
- 클라이언트가 동일한 요청을 하는 경우. 웹과 모바일이 동일한 형태의 거의 동일한 데이터를 원한다면, 별도의 BFF는 이점 없이 노력을 중복하게 됩니다. 대신 통합하세요.
- GraphQL이 이미 형상화 문제를 해결하는 경우. GraphQL을 사용하면 각 클라이언트가 단일 엔드포인트에서 필요한 필드만 정확하게 쿼리할 수 있으며, 이는 페이로드 형상화를 위해 BFF가 하는 작업의 대부분을 커버합니다. 프론트엔드별 리졸버를 가진 GraphQL 계층이 있다면, 별도의 BFF 계층은 종종 가치를 추가하지 않습니다. BFF 계층을 추가하기 전에 GraphQL이 적합한지 판단하려면 GraphQL이 무엇인지 확인하세요.
- 게이트웨이와 마이크로서비스만으로 충분한 경우. 더 간단한 시스템의 경우, 잘 설계된 마이크로서비스 앞에 있는 API 게이트웨이가 전용 클라이언트별 계층 없이도 허용 가능한 결과를 제공할 수 있습니다.
솔직한 단점
BFF가 올바른 선택일지라도, 실제 비용이 발생합니다. 눈을 뜨고 들어가는 것이 이 패턴을 잘 활용하는 방법의 일부입니다.
코드 중복. 이것이 주요 트레이드오프이며, Microsoft 문서에서도 직접 언급하고 있습니다. 세 개의 BFF가 모두 동일한 인증 확인을 호출하거나 동일한 날짜를 동일한 방식으로 포맷해야 할 때, 해당 로직은 세 번 작성되는 경향이 있습니다. 맞춤형 구현을 위해 중복을 감수하는 것입니다. 해결책은 규율입니다: 진정으로 공유되는 로직은 BFF가 가져오는 라이브러리에 유지하고, BFF 자체는 클라이언트별 형상화를 위해 남겨두십시오. 진정한 교차 관심사(인증, 속도 제한, 모니터링)는 각 BFF마다 재구현하는 대신 게이트웨이로 푸시하십시오.
운영할 서비스 증가. 각 BFF는 자체 수명 주기, 파이프라인, 온콜 로테이션 및 보안 영역을 가진 또 다른 배포 가능한 단위입니다. 더 많은 서비스는 더 많은 운영 오버헤드를 의미합니다.
추가적인 네트워크 홉. 클라이언트는 더 이상 서비스와 직접 통신하지 않습니다. BFF는 홉을 추가하며, 이는 지연 시간을 증가시킬 수 있습니다. 이는 일반적으로 BFF가 여러 클라이언트 왕복 요청을 제거하기 때문에 가치 있는 트레이드오프이지만, 측정해야 할 비용이지 가정해서는 안 됩니다.
BFF가 비대해질 위험. BFF가 여러 클라이언트에 서비스를 제공하거나 마이크로서비스에 속해야 할 비즈니스 로직을 흡수하기 시작하면, 탈출하려 했던 범용 백엔드로 다시 돌아가게 됩니다. 간결하게 유지하십시오.
Apidog로 BFF 계약 동기화 유지하기
실제로 BFF를 운영하는 데 어려운 부분은 계약(contracts)입니다. 각 BFF는 자체 클라이언트향 API를 노출하며, 또한 하위 마이크로서비스의 계약에 의존합니다. 이는 서로 다른 계층을 소유한 팀 간에 많은 인터페이스가 이동하며, 그들 간의 불일치에서 버그와 깨진 클라이언트가 발생합니다.

이것이 Apidog가 워크플로우에 적합한 이유입니다. Apidog는 API 설계, 테스트, 목업, 문서화 플랫폼이므로, 각 BFF의 API 계약은 프론트엔드 팀과 백엔드 팀 모두가 함께 작업할 수 있는 단일 홈을 가집니다:
- 계약 먼저 설계. Apidog의 비주얼 디자이너에서 OpenAPI 기반으로 각 BFF 엔드포인트와 요청 및 응답 스키마를 정의하여, 코드를 작성하기 전에 클라이언트향 형태를 합의합니다. 이는 BFF 계층에 적용된 계약 우선 접근 방식이며, API 계약을 명시적으로 유지합니다.
- 존재하기 전에 목업. 프론트엔드 팀은 계약이 합의된 날부터 BFF 또는 하위 서비스가 준비될 때까지 기다리지 않고, Apidog 스마트 목업을 기반으로 BFF 구축을 시작할 수 있습니다.
- 계약 테스트. Apidog의 자동화된 테스트 및 어설션은 각 BFF가 클라이언트가 예상하는 집계되고 재구성된 페이로드를 반환하는지 확인하며, CI에 통합되어 BFF 응답을 깨뜨리는 하위 변경 사항이 조기에 감지되도록 합니다.
- 양측을 위한 문서화. Apidog는 계약으로부터 대화형 문서를 자동 생성하므로, BFF의 API를 읽는 프론트엔드 팀과 하위 서비스를 소유하는 백엔드 팀이 단일 정보원을 공유합니다.
범위를 명확히 하자면: Apidog는 BFF를 구축, 호스팅 또는 실행하지 않으며, API 게이트웨이도 아닙니다. Apidog는 각 BFF가 기반으로 하는 API 계약을 설계, 목업, 테스트 및 문서화하는 곳이며, 이는 BFF가 발전함에 따라 프론트엔드 팀과 백엔드 팀을 동기화하는 역할을 합니다. 각 BFF를 안정적이고 잘 문서화된 계약을 가진 제품으로 취급하는 것이 이 패턴을 지속 가능하게 만듭니다.
FAQ
BFF는 마이크로서비스인가요? BFF는 서버측 서비스이며, 마이크로서비스 설정에서는 일반적으로 마이크로서비스 중 하나로 실행됩니다. 하지만 그 역할은 일반적인 마이크로서비스와 다릅니다. 마이크로서비스는 비즈니스 기능을 소유하고 클라이언트와 무관하게 유지됩니다. 반면 BFF는 한 클라이언트의 경험을 소유하며, 해당 클라이언트를 위해 마이크로서비스를 집계하고 재구성하기 위해 존재합니다. 이는 비즈니스 기능 서비스가 아니라 경험 계층 서비스입니다.
BFF는 몇 개나 있어야 하나요? 기본적으로는 각기 다른 클라이언트 경험당 하나입니다: 웹용 하나, iOS용 하나, Android용 하나 등. 단일 팀이 거의 동일한 요구 사항을 가진 클라이언트를 소유할 때만 두 개를 결합합니다. 하나의 BFF가 클라이언트별 조건부 로직을 축적하기 시작하면 더 분할해야 합니다.
GraphQL이 BFF 패턴을 대체할 수 있나요? 페이로드 형상화 부분에서는 가능합니다. GraphQL을 사용하면 각 클라이언트가 하나의 엔드포인트에서 필요한 필드만 정확하게 요청할 수 있어, 클라이언트별 백엔드 없이 과도한 가져오기 및 불충분한 가져오기를 해결합니다. 프론트엔드별 리졸버를 가진 GraphQL이 있다면, 별도의 BFF 계층은 거의 가치를 추가하지 않습니다. 하지만 공유 GraphQL 서버가 쉽게 제공할 수 없는 클라이언트별 오케스트레이션, 프로토콜 변환 또는 런타임 선택이 필요할 때는 여전히 BFF가 도움이 됩니다.
BFF와 API 게이트웨이를 함께 사용할 수 있나요? 네, 일반적인 구성입니다. API 게이트웨이는 인증, 속도 제한, 모니터링 등 모든 클라이언트에서 공유되는 관심사를 처리하고, 트래픽을 올바른 BFF로 라우팅합니다. 각 BFF는 해당 클라이언트에 특정한 부분을 처리합니다. 이들은 서로 다른 계층에 위치하며 다른 역할을 수행합니다.
BFF는 누가 소유해야 하나요? 클라이언트를 소유한 프론트엔드 팀이 소유해야 합니다. 그 소유권이 이 패턴의 핵심입니다. 이를 통해 팀은 UI 변경 사항과 백엔드 엔드포인트를 함께 배포하고, 자체 런타임을 선택하며, 별도의 백엔드 팀의 대기열을 기다리지 않고 작업을 진행할 수 있습니다.
BFF는 지연 시간을 추가하나요? 하나의 네트워크 홉을 추가하여 비용이 발생합니다. 실제로 BFF는 여러 클라이언트-서비스 왕복 요청을 하나의 클라이언트-BFF 요청으로 대체하고, BFF가 서비스에 가까이에서 병렬로 호출할 수 있도록 하여 전체 클라이언트 지연 시간을 줄이는 경우가 많습니다. 어느 쪽이든 가정하기보다 워크로드에 대해 측정해보세요.
