Folly API stability 정책 — 어떤 보장도 없다는 솔직함
한 줄 요약: Folly는 API/ABI 안정성을 약속하지 않는다. 이는 무책임이 아니라 fbcode monorepo의 운영 모델을 OSS에 그대로 노출한 결과다. 외부 사용자는 commit 단위 freeze로 이를 보완한다.
#동기 — 왜 보장을 하지 않는가
fbcode 안에서는 모든 호출자가 동시에 빌드된다. Folly 헤더를 바꾸면 그 시점의 trunk에 들어 있는 모든 호출자가 같이 컴파일된다. signature를 바꾸고 싶다면 호출자도 함께 바꾸면 된다. 언제든 가능하다.
OSS 사용자는 그 가정 밖에 있다. Meta는 OSS 사용자가 fbcode와 다른 schedule로 업데이트한다는 점을 안다. 그래서 다음 둘 중 하나를 택해야 한다.
- OSS 사용자를 위해 별도의 안정화 layer를 둔다.
- 안정성 약속을 하지 않고, 사용자가 lockstep으로 따라오게 한다.
Meta는 두 번째를 택했다. Folly는 그래서 다음을 보장하지 않는다.
- API 호환성 (signature, default argument)
- ABI 호환성 (struct layout, virtual table)
- behaviour 호환성 (throw 여부, exception type)
- header 위치 (
folly/Foo.h가folly/bar/Foo.h로 이동 가능) - 이름 (
folly::Promise::setException이setError로 rename 가능)
#실제로 일어나는 변화
GitHub commit history를 보면 패턴이 보인다.
v2023.06.05.00 → v2024.05.06.00 사이 변화 (예시)
- folly::SmallLocks::MicroLock layout 변경 (ABI break)- folly::futures::Future::onError → thenError로 deprecated- folly::experimental::* → folly::로 승격- AtomicHashMap의 일부 method signature 변경- IOBuf::create_combined 추가, IOBuf::wrap_buffer signature 보강대부분은 API 추가/개선이지만 ABI break도 드물지 않다. Header 위치 변경, namespace 이동도 분기마다 한두 건씩 일어난다.
#외부 사용자의 전략
#1. Tag로 고정
FetchContent_Declare( folly GIT_REPOSITORY https://github.com/facebook/folly.git GIT_TAG v2024.11.04.00 # 특정 release)main branch는 언제든 깨질 수 있다. CI green이라 해도 다음 commit이 우리 코드를 깨지 않는다는 보장은 없다.
#2. 격리 layer
// my_async.h — 외부에 노출되는 인터페이스namespace myapp { class AsyncOp { public: std::future<int> Run(); // 표준 future로 반환 };}
// my_async.cpp — 내부 구현#include <folly/futures/Future.h>std::future<int> AsyncOp::Run() { folly::SemiFuture<int> sf = ...; return std::async(std::launch::deferred, [sf = std::move(sf)]() mutable { return std::move(sf).get(); });}Public header에서 Folly type을 노출하지 않으면 Folly 버전 업그레이드 시 cpp 파일만 영향받는다. 다운스트림은 무관하다.
#3. 단위 테스트로 회귀 감지
TEST(FollyContract, FutureThenValueReturnsValue) { auto f = folly::makeFuture(42).thenValue([](int x) { return x + 1; }); EXPECT_EQ(std::move(f).get(), 43);}Folly의 behaviour를 우리 가정대로 동작하는지 검증하는 테스트를 둔다. 다음 버전에서 깨지면 즉시 알 수 있다.
#4. 큰 점프 회피
| 전략 | 평가 |
|---|---|
v2022 → v2024 한 번에 업그레이드 | 위험 |
v2022 → v2023 → v2024 단계적 | 안전 |
분기마다 changelog가 따로 있지는 않지만, tag 사이의 diff는 작다. 작은 점프를 자주 하는 게 큰 점프 한 번보다 안전하다.
#ABI 측면
ABI break는 링크 시점에 들킨다.
undefined symbol: folly::AsyncSocket::AsyncSocket(folly::EventBase*, int, ...)Folly와 application이 다른 시점의 헤더로 컴파일되면 발생한다. 해결책은 단 하나, 같은 commit으로 동시 빌드다.
# 정적 링크 + 단일 toolchainset(BUILD_SHARED_LIBS OFF)add_compile_options(-fvisibility=hidden -fvisibility-inlines-hidden)Folly를 dynamic library로 배포하지 마라. 다른 application이 다른 시점의 Folly와 링크되면 undefined behaviour다.
#Meta의 입장 — Compatibility Document
folly/CMake/COMPATIBILITY.md(혹은 folly/docs/ 안)에 다음 취지의 문서가 있다.
Folly does not guarantee API or ABI stability between any two commits. External users are expected to update Folly together with their applications, treating Folly as part of their own source tree.
이는 Boost의 모델과는 정반대다. Boost는 release를 통한 안정성을 약속한다. Folly는 fbcode trunk를 약속한다.
#std/Abseil과의 비교
| 라이브러리 | API 안정성 | ABI 안정성 | 버전 schedule |
|---|---|---|---|
| C++ 표준 | 강력 (deprecation cycle) | 처리계별 | 3년 |
| Abseil | LTS 안에서 약속 | 동일 빌드 내 | LTS + main |
| Boost | release 안에서 강력 | release 안에서 | 4개월 |
| Folly | 어떤 약속도 없음 | 어떤 약속도 없음 | 불규칙 tag |
#코드 리뷰 포인트
mainbranch가 import되는가? PR에서 즉시 거절. tag로 고정한다.- public header에 Folly type이 있는가? SDK라면 격리한다.
- Folly upgrade PR이 단독으로 올라왔는가? Folly만 올리지 말고 application code와 동시에 올린다.
- 버전 점프가 1년 이상인가? 단계적 업그레이드를 고려한다.
#자주 보는 안티패턴
// 1. Public API에 folly::Future 노출namespace mylib { folly::SemiFuture<Result> ComputeAsync(); // 다운스트림이 Folly에 결박됨}
// 2. Folly object를 dynamic library 경계로 전달extern "C" folly::IOBuf* GetBuffer(); // ABI는 internal — 위험# 3. main branch 사용FetchContent_Declare(folly GIT_TAG main)
# 4. shared library로 배포add_library(folly SHARED ...)# 다른 application이 다른 commit의 folly와 충돌#정리
- Folly는 API/ABI 안정성을 약속하지 않는다. 이는 fbcode 운영 모델의 직접적 결과다.
- 외부 사용자는 tag 고정 + 격리 layer + 회귀 테스트 + 단계적 업그레이드로 보완한다.
- Folly를 dynamic library로 배포하지 말고 정적 링크로 application과 lockstep을 유지한다.
- Public header에 Folly type을 노출하지 마라. SDK 호환성이 깨진다.
- Abseil/Boost와는 완전히 다른 운영 가정 위에 있다.
#다음 편
Part 1-05: Production validation 문화에서 Meta production scale이 라이브러리 품질에 미치는 영향을 본다.
#관련 항목
Folly Code Review · 5 of 89
- 1 Folly Code Review — Meta의 production-grade C++ 라이브러리 코드 분석
- 2 Folly 개요 — Meta가 production에서 검증한 utility 모음 분석
- 3 Folly vs Abseil 철학 비교 — performance-first vs std-compatible
- 4 Folly 빌드와 fbcode 환경 — monorepo의 그림자
- 5 Folly API stability 정책 — 어떤 보장도 없다는 솔직함
- 6 Folly production validation 문화 — peta-scale에서 단련된 코드
- 7 folly::Future 분석 — std::future의 한계를 넘는 composable async
- 8 folly::Promise·makeFuture — Future를 만드는 두 길
- 9 folly::SemiFuture vs Future — executor binding의 명시화
- 10 folly::Future thenValue·thenError·thenTry — continuation 체인 분석
- 11 folly::collect·collectAll·collectAny — fan-in 패턴 분석
- 12 folly::Future retry·window·via — 제어 흐름 조합자
- 13 folly::fibers 분석 — M:N stackful coroutine
- 14 folly::InlineExecutor — 호출자 thread에서 즉시 실행
- 15 folly::CPUThreadPoolExecutor — CPU-bound 작업의 표준 thread pool
- 16 folly::IOThreadPoolExecutor — libevent 기반 I/O pool
- 17 folly::ManualExecutor — 결정적 테스트를 위한 수동 진행
- 18 folly::EventBase 분석 — libevent 이벤트 루프의 핵심
- 19 folly::IOBuf 분석 — zero-copy buffer chain의 기본 단위
- 20 folly::IOBufQueue — chain의 push/pull 추상화
- 21 folly::io::Cursor·RWCursor — chain 위의 stream
- 22 folly Zero-copy 패턴 — IOBuf로 ScatterGather I/O 표현
- 23 folly::IOBuf shared semantics — clone·unshare·takeOwnership
- 24 folly::FBString 분석 — SSO + COW 구현
- 25 folly의 fmt::format 통합 — 모던 포맷팅 채택
- 26 folly::StringPiece — string_view 호환 분석
- 27 folly Join·Split utilities — 문자열 분해와 결합
- 28 folly::to·tryTo — text↔num 변환 분석
- 29 folly Conv Customization — 사용자 타입 지원
- 30 folly Conv 성능 비교 — sprintf·stringstream 대비
- 31 folly::F14ValueMap vs std::unordered_map
- 32 folly::F14NodeMap — stable pointer가 필요할 때
- 33 folly::F14VectorMap — cache-friendly iteration
- 34 folly::F14FastMap — auto-select 동작
- 35 folly F14 internals — SIMD probing 메커니즘
- 36 folly::small_vector — inline storage 분석
- 37 folly::FixedString — compile-time string
- 38 folly::AtomicHashMap — lock-free read 분석
- 39 folly::ConcurrentHashMap — sharded 동시 해시 맵
- 40 folly::EvictingCacheMap — LRU 구현 분석
- 41 folly::Synchronized — lock wrapper 패턴
- 42 folly::SharedMutex 분석
- 43 folly::Baton — one-shot wait 동기화
- 44 folly::RWSpinLock 분석
- 45 folly::PicoSpinLock — 1-byte spinlock
- 46 folly::ProducerConsumerQueue — SPSC 큐 분석
- 47 folly::MPMCQueue — multi-producer multi-consumer
- 48 folly::UnboundedQueue — 동적 크기 lock-free
- 49 folly::fibers::Channel — Go-like channel
- 50 folly::dynamic — JSON-like dynamic type 분석
- 51 folly JSON conversion — toJson·parseJson
- 52 folly dynamic ↔ struct — manual marshaling
- 53 folly dynamic Visitor pattern — type별 분기
- 54 folly::Singleton vs Meyers/static — 왜 Folly의 Singleton인가
- 55 folly::SingletonVault 분석 — 등록·소멸·의존성
- 56 folly::Singleton try_get·try_get_fast — TLS-cached 접근
- 57 folly::ExceptionWrapper — type-erased exception holder
- 58 folly::ScopeGuard·SCOPE_EXIT — RAII cleanup
- 59 folly::Optional vs std::optional
- 60 folly::Function vs std::function
- 61 folly::Lazy — 지연 초기화 wrapper
- 62 folly Meta 스타일 code review 패턴
- 63 folly anti-patterns — 잘못 쓰면 std보다 느림
- 64 folly vs std 선택 기준 분석
- 65 folly::coro 개요 — production C++20 코루틴 어댑터
- 66 folly::coro::Task — lazy single-shot 코루틴
- 67 folly::coro::AsyncGenerator — 비동기 스트림
- 68 folly coro blockingWait·collectAll — 동기 경계와 fan-in
- 69 folly::coro::Baton·Mutex — 코루틴-aware 동기화
- 70 folly::Expected — 결과 또는 오류
- 71 folly::Try — Future 결과 wrapper
- 72 folly::Try vs Expected 선택 기준
- 73 folly::Range — 일반 iterator pair
- 74 folly::Uri — URL 파서
- 75 folly Fingerprint64·128 — 분산 hash
- 76 folly SpookyHashV2 — fast non-crypto hash
- 77 folly::Init — main() 부트스트랩
- 78 folly::Indestructible — global lifetime 패턴
- 79 folly::MicroLock — 1-byte 락
- 80 folly::MicroSpinLock — 가장 좁은 spin lock
- 81 folly::format — legacy formatter 분석
- 82 folly::demangle — typeid 디망글링
- 83 folly::DynamicConverter — dynamic ↔ struct
- 84 folly::RecordIO — append-only 로그 파일 포맷
- 85 folly::io::Compression — zstd·lz4·snappy wrapper
- 86 folly::AsyncIO — io_uring·Linux AIO
- 87 folly::CancellationToken — 코루틴·Future 취소 전파
- 88 folly::observer — hot config의 atomic refresh
- 89 fbcode 패턴 모음 — folly 사용의 실전
관련 글
folly::F14NodeMap — stable pointer가 필요할 때
F14NodeMap — value를 별도 heap node에 두어 pointer/reference 안정성을 보장하는 F14 변형.
같은 시리즈에서 이어 읽기
fbcode 패턴 모음 — folly 사용의 실전
Meta fbcode 코드 리뷰에서 반복적으로 등장하는 folly 사용 패턴 — overview + 시리즈 마무리.
같은 시리즈에서 이어 읽기
folly::observer — hot config의 atomic refresh
folly::observer — read mostly 값의 atomic refresh, hot config·feature flag·LB weight 같은 패턴의 표준.
같은 시리즈에서 이어 읽기