핀테크 엔지니어링 핸드북
4 days ago
4
돈을 핵심 상태로 다루는 시스템은 데이터를 만들지 않고 , 잃지 않으며, 아무 것도 신뢰하지 않는다는 원칙 위에서 설계되어야 함
금액 표현은 float를 피하고 BigDecimal, 최소 단위 정수, 유리수 등을 책임에 맞게 조합해야 하며, JSON 숫자 직렬화도 IEEE-754 double 문제를 다시 만들 수 있음
장부는 복식부기 , 불변 감사 추적, value time·booking time·settlement time 분리, 정정·취소 기록을 통해 잔액과 보고서를 재구성 가능하게 유지함
실제 돈의 흐름은 예약, 멱등성, 재시작 가능한 상태 머신, 외부 API·웹훅 검증, outbox·CDC, 대사(reconciliation) 로 중복 지출과 누락을 막아야 함
접근 제어, four-eyes 승인, SDLC 변경 추적, 속성 기반 테스트와 장애 주입은 내부 운영자와 코드 변경까지 신뢰 경계 로 취급하게 만듦
핀테크 시스템의 기본 원칙
돈이 시스템의 주된 관심사인 소프트웨어 엔지니어링에서는 일반적인 CRUD보다 추적성, 불변성, 검증 가능성이 훨씬 중요함
대상 독자는 핀테크에 새로 합류한 사람, 이미 핀테크에서 일하는 사람, 핀테크 밖에서 돈 시스템이 일반 시스템과 어떻게 다른지 이해하려는 사람임
모든 패턴은 세 가지 원칙을 지키기 위한 수단임
No invented data : 돈은 없던 곳에서 만들어질 수 없으므로 중복 처리와 임의 잔액 변경을 허용하지 않음
No lost data : 돈에 일어난 모든 일은 추적되고 영속화되어야 함
No trust : 외부 제공자, 내부 컴포넌트, 현실 세계를 신뢰하지 않고 검증함
돈을 표현하는 방식
금액 표현은 금융 시스템의 가장 기본적인 결정이며, 잘못 고르면 상위 계층 전체가 오류를 물려받음
float/double 은 예측하기 어려운 정밀도 손실을 만들 수 있어 거의 항상 좋은 선택이 아님
빠르고 메모리 효율적이며 추가 라이브러리나 자료구조가 필요 없다는 장점은 있음
BigDecimal 같은 임의 정밀도 타입은 계산 정밀도와 반올림 위치를 명시적으로 제어할 수 있음
FX나 가격 계산처럼 여러 연산이 이어지는 중간 계산에 적합함
최소 단위 정수 저장은 대부분의 법정화폐에서 중앙은행 시스템과 같은 고정 정밀도를 쓰는 방식임
€12.34는 1234로 저장됨
ISO 4217의 자릿수를 따라야 하며 항상 2자리라고 가정하면 안 됨
암호화폐도 satoshi, wei 같은 최소 단위 정수를 쓰지만, 정밀도는 자산별로 다르고 ERC-20의 decimals처럼 토큰이 정의함
암호화폐 금액은 64비트 정수를 넘을 수 있어 임의 폭 정수가 필요할 수 있음
유리수 는 정밀도 손실이 허용되지 않을 때 가장 강력하지만 느리고, 다른 형식으로 변환할 때 정밀도 손실 없이 바꾸기 어려우며, 보통 커스텀 타입이나 라이브러리가 필요함
저장 방식과 계산 방식은 별도 결정이며, 한 시스템이 정수 저장과 BigDecimal 중간 계산을 함께 쓸 수 있음
금액 직렬화에서도 경계 처리가 중요함
일반 JSON 숫자는 대부분의 파서에서 IEEE-754 double이므로 내부 표현을 조심해도 경계에서 float 문제가 다시 생김
돈은 "12.34" 같은 문자열이나 최소 단위 정수로 보내야 함
반올림과 통화 처리
반올림 은 나눗셈, 통화 변환, 수수료, 이자, 비율 적용, 정밀도 이동에서 불가피하므로 암묵적으로 두면 안 됨
반올림 전략은 비즈니스 결정임
보수적으로 내려야 하는 경우가 있고, 통계적 효과를 위해 half-even을 쓸 수도 있음
누가 잔여 소수분을 가져가는지는 법률·세무 영향을 가질 수 있음
가능한 한 오래 전체 정밀도를 유지하고, 보통 저장 전이나 사용자 표시 전 같은 경계에서만 반올림해야 함
값을 여러 부분으로 나눈 뒤 반올림하면 부분 합이 원래 값과 달라질 수 있음
상황에 따라 명시적 rounding account 가 필요함
돈은 숫자만으로 표현할 수 없고 항상 통화와 함께 다뤄야 함
Money 같은 newtype, struct, class, record로 금액과 통화를 함께 묶으면 오류 가능성이 줄어듦
서로 다른 통화의 덧셈은 금지하고, 변환은 엄격히 통제된 환율로 명시적으로 수행해야 함
임의 통화 코드를 받아들이지 말고 시스템 경계에서 통제된 통화 집합으로 검증해야 함
법정화폐 코드는 식별자로 쓸 수 있지만, 암호화폐는 (network, contract address) 같은 더 복잡한 식별이 필요함
pegged, bridged, wrapped 암호화폐는 기초 자산과 동등하지 않음
FX 환율
FX rate 는 항상 방향성을 가짐
EUR/USD 환율은 USD/EUR의 단순 역수가 아님
거래소에서 매수와 매도는 bid/ask spread 때문에 서로 다른 가격의 주문임
환율의 시점도 결과를 바꿈
현재 시점 환율은 현재 보유분이나 지금 발생한 것처럼 가정한 거래 가치를 계산하는 데 쓰임
value-date 환율은 가치 변화나 세액 계산에 쓰임
변환에서는 두 종류의 환율이 중요함
Transactional rate 는 실제 변환이 일어난 환율이며, 원래 금액과 결과 금액에서 도출됨
Reference rate 는 보유분 가치나 세무 기준 같은 평가와 동등성 판단에 쓰이며 실제 거래 가격은 아님
표준적인 단일 환율은 없음
환율은 시장에서 나오며 거래 장소나 계산 방식에 따라 달라짐
중앙은행 환율은 표준에 가장 가깝지만 reference rate로만 쓸 수 있고, 대안 소스도 유효할 수 있음
금액과 reference rate의 출처를 함께 보관해야 나중에 검증할 수 있음
장부와 복식부기
돈의 이동은 감사 가능하고 몇 년 뒤에도 재구성 가능한 방식으로 기록되어야 함
복식부기 는 금융 거래를 (credit account, debit account, amount) 형태의 entry 목록으로 저장하는 널리 쓰이는 방식임
고전적 표현은 이동마다 debit row와 credit row를 따로 둠
모든 entry가 같은 금액을 한 계정에서 다른 계정으로 이동하므로 장부는 항상 균형을 이룸
돈에는 항상 출처와 목적지가 있음
외부 제공자도 전용 계정을 가져야 시스템에 들어오고 나가는 돈을 추적할 수 있음
잔액은 저장하지 않고 돈의 이동에서 파생함
계정에는 asset, liability, equity 같은 타입이 있음
accounting equation assets = liabilities + equity가 유지됨
실제로는 수수료 수익이나 write-off 손실을 기록하기 위해 revenue와 expense 계정도 필요함
확장 식은 assets = liabilities + equity + revenue - expenses임
하나의 거래는 보통 여러 이동을 만듦
순금액 이동과 수수료 이동이 별도로 생길 수 있음
posted entry는 관례상 불변이며, 정정은 원본을 상쇄하는 새 entry를 추가해 처리함
시간 모델: value, booking, settlement
거래에는 보통 두 개 이상, 때로는 세 개의 타임스탬프가 붙음
Value time : 거래가 실제로 발생한 시점
Booking time : 시스템에 기록된 시점
Settlement time : 돈이 실제 이전되거나 실체화된 시점
Settlement time은 모든 거래에 존재하지 않으며 보통 T+X로 표현됨
T+2는 value date로부터 2일 뒤 settlement가 일어난다는 뜻임
value time과 booking time은 거의 항상 어긋남
booking > value이면 backdated이며, 보고 기간이 달라질 때 특히 중요함
booking < value이면 forward-dated이며, 예약 결제나 미래 날짜 결제에서 발생함
카드 결제 예시는 T1에 결제가 발생하고, T2에 시스템이 기록하며, T3에 결제 제공자가 계좌로 돈을 이전하는 흐름임
비즈니스 보고서는 value time이나 settlement time을 주로 보고, booking time은 추적성에 유용함
여러 시점을 created_at 하나로 합치면 나중에 재구성할 수 없는 정보를 잃음
감사 추적, 이벤트 소싱, 불변성
금융 시스템은 규제 감사 대상이며, 사용자 자금과 회사 자금의 혼합 여부, 수익의 설명 가능성, 외부에 제공한 정보와 현실의 일치 여부, 자금 보호 상태 등을 증명해야 할 수 있음
audit trail 은 현재 상태뿐 아니라 그 상태가 어떻게 만들어졌는지의 전체 이력임
무엇이 일어났는지
언제 일어났는지
누가 또는 무엇이 트리거했는지
왜 일어났는지
돈의 이동뿐 아니라 수동 개입, fee schedule, rate source, limit 같은 설정 변경, 권한 변경도 감사 추적이 필요함
compliance check나 risk score 같은 결정은 결과만 저장하면 부족할 수 있음
DMN, Drools, Decisions4s 같은 decision table이나 rules engine에 있으면 어떤 규칙이 어떤 입력에서 실행되어 어떤 결과가 나왔는지 재생 가능한 구조가 됨
Event sourcing 은 audit trail을 만들기 위한 체계적인 접근임
현재 상태와 로그를 따로 저장하지 않고 이벤트만 저장한 뒤 상태를 파생함
복식부기 ledger는 balance를 저장하지 않고 entry에서 계산한다는 점에서 이 패턴의 예임
Event sourcing에는 실무 제약도 큼
모든 곳에 필요하지 않으며, ledger가 돈을 이미 커버하면 주변 도메인은 일반 모델과 신뢰 가능한 change log로 충분할 수 있음
성능을 위해 balance와 projection을 캐시하거나 snapshot할 수 있음
이벤트 원본은 효율적으로 질의하기 어려워 projection 작업이 많아질 수 있음
이벤트는 수년간 남으므로 오늘의 코드가 오래전 이벤트도 읽어야 함
감사 추적은 수정 가능하면 증거가 되지 않으므로 append-only여야 함
append-only table, DB 권한에서 UPDATE·DELETE 제거, 애플리케이션 계층의 mutating operation 차단, checksum이나 hash chain을 통한 tamper evidence가 도구가 됨
실제 시스템에서는 버그 때문에 event log나 audit trail을 고쳐야 할 때가 있음
보통 데이터가 외부에 보고된 뒤에는 고정되어야 하며, 보고 전이라면 문제를 찾아 시스템 밖으로 나가기 전에 제자리 수정이 가능할 수 있음
취소와 정정
잘못된 금액 posting이나 잘못된 계정 posting 같은 실수는 발생함
불변성은 앞으로 고치는 방식을 요구함
새 compensating entry를 posting하고 원본 record와 양방향으로 연결함
Reversal 은 원본을 경제적으로 없었던 것처럼 완전히 상쇄하지만, 원본과 reversal은 모두 이력에 남음
Correction 또는 adjustment는 실제 기록과 올바른 값의 차이를 booking하거나, 되돌린 뒤 올바른 값으로 다시 posting함
정정은 원본과 다른 보고 기간에 들어갈 수 있음
연결 정보가 있어야 보고서가 정정을 올바르게 귀속하고 실제 활동과 cleanup을 구분할 수 있음
이미 닫힌 보고 기간에 backdate가 허용되지 않는 경우가 보통이므로, 정정 시 과거 value time을 지정할지는 보고 일정에 좌우됨
돈 흐름 실행: 불변 조건과 자금 예약
Invariant 는 시스템에서 항상 참이어야 하는 특성임
accounting equation이 한 예이며, 비즈니스 이해관계자가 여러 조건을 정의할 수 있음
invariant를 강제하는 방법은 상호 보완적임
생성 단계에서 유효한 객체만 만들도록 설계함
런타임에서 assertion, 테스트, property-based testing으로 확인함
저장된 데이터를 reconciliation job이나 nightly check로 사후 분석함
외부 세계와 상호작용하는 거래는 race condition을 피해야 함
외부 호출 후에야 잔액 부족을 발견하거나 같은 돈을 두 번 쓰는 상황을 막아야 함
Funds reservation 또는 hold-and-release는 외부 상호작용 전에 특정 거래를 위해 자금을 예약하는 패턴임
성공하면 reservation을 settle하고 거래를 진행함
실패하면 release해 available balance로 돌림
이 패턴은 total balance와 available balance를 구분함
available = total - reserved
잔액 확인과 새 reservation은 available balance 기준으로 수행됨
최종 금액은 사전 추정과 다를 수 있음
수수료나 환율이 달라지면 예상 금액을 예약하고 실제 금액을 settle한 뒤 나머지를 release함
reservation은 반드시 settle 또는 release되어야 함
고아 reservation은 사용자 자금을 잠그지만 돈을 잃거나 만들지는 않음
expiry나 timeout은 안전망이 될 수 있지만 필수는 아님
잔액 확인과 reservation 기록은 linearizable해야 함
stale read에서는 두 거래가 모두 확인을 통과해 같은 자금을 뒷받침할 수 있음
Overdraft와 멱등성
Overdraft 는 계정 잔액이 음수가 되는 상황임
의도적 overdraft는 한도와 이자가 있는 신용 상품이며, 보통 별도 overdraft 계정으로 모델링됨
의도하지 않은 overdraft는 정책상 금지되어도 발생할 수 있음
settlement가 예약 추정보다 크게 들어오거나, reversal이 자금이 이미 빠져나간 뒤 들어올 수 있음
funds reservation은 window를 줄이지만 제거하지 못함
“금지”와 “표현 불가능”은 다름
unsigned integer나 CHECK (balance >= 0)로 음수 잔액을 표현하지 못하게 만들면, 현실적으로 음수 잔액을 받아야 할 때 crash, zero clamp, 잘못된 처리로 이어질 수 있음
음수 잔액을 0으로 clamp하면 돈을 만들어냄
overdraft가 감지되면 조사 신호로 보고, future deposit과 netting, repayment 요청, expense/loss 계정으로 write-off 같은 방식으로 명시적으로 회수 또는 처리해야 함
분산 시스템에서는 exactly-once delivery를 보장할 수 없으므로 재시도가 필요하고, 재시도는 중복 전달을 만들 수 있음
Idempotency 는 같은 메시지가 두 번 전달되어도 처리가 한 번만 효과를 내게 하는 성질임
명시적 idempotency key가 payload 기반 deduplication보다 보통 단순하고 안전함
key는 특정 operation과 client 범위로 제한해야 함
오류를 재생할지 재처리할지 결정해야 하며, 영구 오류는 그대로 재생하는 편이 보통 단순함
중복 호출 payload가 원본과 같은지 검증하는 것은 좋은 관행이지만 구현 복잡도와 유연성 비용이 있음
대규모에서는 수십억 요청 deduplication과 동시 접근에서 atomic barrier가 필요함
24시간 같은 idempotency window는 구현을 단순하게 하지만 correctness 비용이 큼
retry 테스트와 out-of-order retry 처리도 필요함
재시작 가능한 흐름
돈 흐름은 여러 단계에 걸치며 단계 사이 어디서든 죽을 수 있다고 가정해야 함
Full resumability 는 반쯤 끝난 흐름이 항상 복구 가능한 상태에 놓이도록 만드는 설계임
진행 상태는 메모리가 아니라 영속 저장소에 저장해야 함
흐름을 명시적 state machine으로 모델링하고 각 단계 완료를 다음 단계 시작 전에 commit해야 함
중단된 흐름을 다시 밀어주는 독립 driver가 필요함
scheduler, worker, poller가 orchestrator crash 뒤에도 incomplete flow를 처리해야 함
재개 시 이미 부분적으로 일어난 단계를 다시 실행할 수 있으므로 각 단계는 멱등적이어야 함
외부 효과는 rollback할 수 없음
외부 세계를 호출한 뒤에는 호출하지 않은 상태로 되돌릴 수 없음
완료될 때까지 roll forward하거나, 이후 단계가 영구 실패하면 saga pattern처럼 compensating action을 posting해야 함
Temporal, Camunda, Workflows4s, AWS Step Functions 같은 durable-execution engine을 쓰거나 직접 persistent state machine을 만들 수 있음
외부 API 소비
결제 제공자, custodian, blockchain node, KYC vendor 같은 외부 API는 코드, 품질, 가동 시간을 통제할 수 없으므로 방어적으로 다뤄야 함
스키마를 신뢰하면 안 됨
필드 누락, 타입 변경, 예상 밖 null이 생길 수 있음
중요한 부분은 경계에서 검증하고 예상 밖 데이터는 크게 실패해야 함
필요 없는 부분까지 검증하면 제3자의 계약 위반 때문에 불필요한 장애가 생길 수 있음
외부 API에서는 URL에 token 전달, 정밀도 손실, 의미와 다른 HTTP code, 200 안의 error body, 일관성 없는 pagination, custom date format 같은 일이 충분히 발생함
모든 호출은 실패할 수 있으므로 timeout과 retry가 필요함
Circuit breaker는 주로 과부하 서버에 대한 courtesy이며 클라이언트 복잡도를 늘림
다만 latency와 thread, connection 같은 유한 자원을 보호할 때 필요할 수 있음
rate limit과 quota는 사전 계산으로 예상 호출량과 provider limit을 맞춰봐야 함
모든 request와 response를 구조화되고 질의 가능한 형태로 저장하면 조사, audit trail, provider 행동 분쟁의 증거, 버그 뒤 재처리 자료가 됨
핵심 영역에서는 provider redundancy를 고려할 수 있음
두 blockchain node로 데이터 검증, backup bank partner, crypto custodian, KYC vendor 같은 방식이 있음
개발, 수수료, 복잡도 비용이 매우 큼
sandbox는 production과 크게 다를 수 있으므로 canary release나 영향이 작은 controlled usage로 production test를 준비해야 함
웹훅 처리
웹훅은 외부 시스템 신호를 받는 흔한 방식이지만 안전한 처리가 쉽지 않음
순서를 가정하면 안 됨
메시지는 out-of-order로 오거나 stale data를 담을 수 있음
방금 받은 웹훅이 최신 진실이라고 보고 상태를 덮어쓰면 안 됨
유효성을 가정하면 안 됨
웹훅은 issuer의 다른 하위 시스템에서 오며 stale 또는 잘못 변환된 데이터를 담을 수 있음
웹훅 본문은 trigger로만 쓰고 API를 조회해 authoritative state를 확인하는 방식이 좋음
API도 eventually consistent일 수 있어 바로 조회하면 이전 상태를 반환할 수 있으므로 retry가 필요함
전달을 가정하면 안 됨
issuer가 강한 redelivery policy를 약속해도 웹훅은 언젠가 유실됨
reconciliation 같은 독립 프로세스가 데이터 완전성을 보완해야 함
단일 전달도 가정하면 안 됨
같은 웹훅은 여러 번 전달되며 처리는 멱등적이어야 함
빠르게 acknowledge하고 비동기로 처리해야 함
raw event를 durable store에 저장한 뒤 즉시 2xx를 반환하고 실제 작업은 비동기로 수행함
raw payload는 그대로 저장해야 함
안정적 처리, audit trail, 버그 뒤 재처리에 필요함
호출자는 검증해야 함
일반적으로 issuer가 payload signature를 붙이고, 수신자는 shared secret의 HMAC이나 공개키 기반 비대칭 서명으로 검증함
서명 검증은 재직렬화한 payload가 아니라 받은 raw bytes 위에서 해야 함
웹훅은 무엇이 일어났는지의 진실이 아니라 뭔가 일어났다는 hint로 취급해야 함
신뢰 가능한 알림: Outbox와 CDC
시스템 변경을 Kafka event, webhook call 등 외부 채널로 안정적으로 알려야 할 때 transactionality가 문제가 됨
publish가 성공했는데 네트워크 문제로 응답을 받지 못해 시스템 상태를 rollback하거나, state change는 commit됐지만 publish가 실패하는 상황이 생길 수 있음
textbook 답은 2-phase commit 또는 distributed transaction이지만 복잡성과 재사용 표준화 어려움 때문에 드물게 쓰임
실용적 선택지는 여러 가지임
Outbox pattern : 상태 변경과 함께 publishing intent를 전용 store에 transactionally 기록하고, 나중에 성공할 때까지 처리함
Change Data Capture : database write-ahead 또는 replication log를 읽어 commit된 변경을 event stream으로 바꿈
Debezium과 AWS DMS가 CDC를 제공함
CDC는 table row 형태의 raw event를 내보내므로 내부 schema 누출을 피하려면 postprocessing이 필요함
Listen-to-yourself는 먼저 event를 publish한 뒤 자기 상태를 그 event에서 다시 만듦
Event sourcing은 event log가 이미 DB에 있으므로 거기서 publish하면 됨
어떤 메커니즘을 고르든 delivery는 at-least-once임
relay나 connector가 publish 후 기록 전에 crash하면 재시작 때 다시 보낼 수 있음
consumer는 stable event id로 deduplicate하고 멱등적으로 동작해야 함
Reconciliation
외부 데이터에 의존하는 시스템은 두 시스템의 상태가 어긋나는 data drift 에 취약함
웹훅을 놓치거나, ledger에는 transaction이 posting됐지만 external provider 시스템에는 반영되지 않을 수 있음
Reconciliation은 두 시스템을 맞추는 프로세스임
실제로는 ledger, payment processor, bank처럼 셋 이상일 수 있음
cadence는 맥락과 제약에 따라 hourly, daily, monthly, yearly일 수 있음
drift는 missing data일 수도 있고, 같은 transaction의 금액이 다른 경우처럼 더 복잡한 차이일 수도 있음
timing도 중요함
settlement가 T+3이면 record는 3일 동안 unreconciled 상태일 수 있으므로 이를 process에 반영해야 불필요한 alert를 막음
matching algorithm이 핵심 난점임
보통 external provider id를 내부에 저장하면 matching이 단순해짐
없으면 amount와 time 기반 heuristic이 필요할 수 있음
one-to-many reconciliation도 필요함
하나의 settlement transfer가 여러 transaction을 포괄할 수 있음
discrepancy를 reconciliation이 맞도록 단순 overwrite하면 안 됨
correction record, webhook data reprocessing 같은 first-class 지원으로 원인을 이해하고 고쳐야 함
제어와 접근
돈 시스템은 데이터뿐 아니라 누가 어떤 행동을 할 수 있는지도 통제하고 사후에 절차 준수를 증명해야 함
Segregation of duties 는 한 사람이 전체 프로세스를 소유하지 못하게 하는 통제임
Four-eyes , maker-checker, dual control은 특정 action이 적용되기 전에 두 번째 사람이 승인해야 하는 방식임
적용 대상은 대규모 또는 수동 withdrawal, manual ledger correction, treasury와 cold-wallet 이동, fee schedule이나 limit 변경처럼 자금을 이동시키거나 잘못 표시할 수 있는 행동임
엔지니어링에도 같은 통제가 적용됨
code merge, production deploy, infrastructure change는 돈 시스템에서 민감한 action이므로 review와 approval이 필요함
approval 자체도 trail의 일부임
누가 요청했고 누가 승인했으며 두 사람이 달랐는지 기록해야 control을 증명할 수 있음
emergency를 위해 명시적이고 강하게 감사되는 break-glass 경로가 필요함
Access control은 시스템 상태의 일부이며 시간이 지나며 변함
human과 service 모두 최소 권한을 부여해야 함
per-person grant보다 RBAC를 선호하면 review가 쉬움
capability grant와 revoke도 민감 이벤트이므로 무엇이, 누가, 왜 바뀌었는지 기록해야 함
scheduled access review로 오래되거나 부정확해진 permission drift를 잡아야 함
SDLC 변경 추적
규제 환경에서는 코드가 production에 도달하는 과정을 감사할 수 있어야 함
source control은 변경 기록임
commit history는 모든 변경을 author에 귀속하고, review와 linked ticket을 통해 이유와 연결함
signed commit, protected branch, shared history force-push 금지로 보호해야 함
review와 pipeline은 강제되어야 함
required review, status check, main branch direct push 금지가 중요함
deployment는 추적 가능해야 함
어떤 version이 실행 중인지, 누가 언제 release했는지 재구성 가능해야 incident를 원인 변경과 연결할 수 있음
테스트 전략
돈 시스템에서는 operation sequence 공간이 크고 흥미로운 실패가 조합에서 나오므로 테스트가 특히 중요함
Property-based testing 은 특정 출력보다 어떤 입력에서도 성립해야 하는 property를 검증함
invariant와 money math에 잘 맞음
operation sequence를 생성할 때 마지막뿐 아니라 매 단계 뒤 invariant를 확인해야 함
수동으로 대규모 수행하기 어려우므로 assertion을 자동 주입하는 testing harness가 필요함
Generative idempotency testing은 외부 세계를 만지는 모든 operation이 두 번째 호출에서 영향이 없는지 검증함
Crash and resume injection은 long flow가 어떤 단계 사이에서 죽어도 살아나는지 검증함
Round-trip testing은 encode/decode, serialize/deserialize, convert/convert back 뒤 시작점으로 돌아오는지 또는 알려진 tolerance 안에 있는지 확인함
money와 currency type의 boundary 정밀도 손실과 serialization bug를 잡는 빠른 방법임
Golden testing은 fee breakdown, statement, report 같은 계산 결과를 저장된 기대 결과와 비교해 의도치 않은 diff를 드러냄
Backward-compatibility testing은 오래된 real-format payload corpus를 유지하고 현재 코드가 여전히 deserialize와 project를 올바르게 하는지 검증함
Production testing은 sandbox가 production과 크게 다를 때 필요할 수 있음
canary release, 작은 blast radius의 controlled rollout, 작은 실제 금액을 지속적으로 흐르게 하는 synthetic transaction이 예임
production test는 실제 돈을 움직이므로 ledger, reconciliation, audit trail을 똑같이 거쳐야 하며, 정상 correction/reversal 경로로 정리해야 함
도메인 용어와 참고 자료
핀테크 입문에서는 코드보다 vocabulary와 concept이 더 어려울 수 있어 핵심 용어를 별도로 정리함
회계와 ledger 영역에는 ledger, general ledger와 sub-ledger, debit/credit, posting, chart of accounts, receivable/payable, IOU, accrual vs cash basis, trial balance, suspense/clearing account, write-off, commingling, reconciliation break가 포함됨
Money와 FX 영역에는 Money type, minor units, basis point, notional, fiat vs crypto, stablecoin, pegged/wrapped/bridged, bid/ask/spread, mid-market rate, reference rate, mark-to-market가 포함됨
거래와 settlement 영역에는 value date, booking date, settlement date, T+X, clearing vs settlement, cut-off time, float, netting, backdating, reversal/correction이 포함됨
결제, 카드, 시장, crypto, compliance 용어도 별도로 정리됨
PSP, omnibus account, FBO account, chargeback, issuer/acquirer, authorization vs capture
order book, market vs limit order, maker/taker, slippage, liquidity, derivative, futures, perpetual, liquidation
custody, hot/cold wallet, private key, multisig, MPC, gas, confirmation/finality, reorg, UTXO vs account model
KYC, AML/CFT, sanctions screening, PEP, SoF/SoW, Travel Rule, VASP, MiCA, least privilege, RBAC, audit trail
참고 자료는 회계와 ledger, payments와 cards, markets와 trading, crypto, engineering, KYC와 AML로 나뉨
세 가지 end-to-end 예시
Crypto withdrawal
사용자가 0.5 ETH를 외부 주소로 출금하는 흐름임
요청은 idempotency key를 포함해 중복 제출이 하나의 withdrawal만 만들게 함
0.5 ETH와 예상 network fee를 available balance에서 예약함
compliance gate는 sanctions, AML, destination address를 확인하며 외부 호출과 수동 review 때문에 며칠 동안 sleep할 수 있음
on-chain broadcast는 idempotent해야 하며, crash 뒤에는 두 번째 broadcast가 아니라 chain을 다시 확인해야 함
충분한 confirmation 뒤 ledger에 user account debit, external on-chain account credit, network fee expense, service fee revenue를 posting함
nightly job이 ledger와 chain reality를 reconcile함
Card deposit
PSP를 통한 카드 충전 흐름임
사용자는 금액과 카드 정보를 제출하고 PSP에 idempotency key로 deposit transaction을 엶
authorization은 hold만 만들며 아직 돈이 회사 것이 아니므로 user balance를 credit하지 않음
captured 웹훅은 raw bytes signature 검증, raw payload 저장, 빠른 2xx 응답 뒤 비동기로 처리함
웹훅은 trigger일 뿐이므로 PSP API에서 authoritative state를 조회함
captured but not settled 상태는 clearing account를 통해 posting하며, settlement는 T+X 뒤 batch로 도착할 수 있음
chargeback은 원본을 수정하지 않고 linked compensating entry로 처리함
In-app conversion with cashback
1,000 EUR를 USDC로 바꾸고 promotional cashback을 주는 흐름임
EUR→USDC quote는 USDC→EUR의 역수가 아니며 directional rate임
EUR와 USDC는 서로 더하지 않고, USDC는 (network, contract address)로 식별되며 pegged fiat와 같지 않음
계산은 전체 정밀도를 유지하고 경계에서 한 번만 명시 전략으로 반올림함
spread는 revenue account에 명시적으로 booking해야 하며 rounding residual로 사라지면 안 됨
cashback은 무료 balance bump가 아니라 company promotional/expense account에서 user balance로 이동하는 실제 돈임
결과 publish는 outbox, CDC, event log 같은 메커니즘으로 reliable delivery를 보장하고 downstream consumer는 stable event id로 dedupe함
Homepage
Tech blog
핀테크 엔지니어링 핸드북
🔉 볼륨 줄이기
🔊 볼륨 키우기
🔇 음소거
⏭️ 다음 곡