11P by GN⁺ | ★ favorite | 댓글 1개
  • 돈을 핵심 상태로 다루는 시스템은 데이터를 만들지 않고, 잃지 않으며, 아무 것도 신뢰하지 않는다는 원칙 위에서 설계되어야 함
  • 금액 표현은 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함

댓글과 토론

Hacker News 의견들
  • 훑어봤는데, 이 핸드북은 얕고 일부 영역에서는 나쁜 조언에 가깝다고 봄
    예를 들어 금액이 정수가 아닌 형태로 저장된 걸 보면 비명을 지르며 도망갈 것 같음. Rust의 decimal이 JSON 부동소수점으로 표현되는 경우 같은 것 때문임. 아주 강한 이유가 없는 한 항상 정수여야 하고, 내보내는 뷰는 이상한 비트코딩 형식이든 뭐든 가능함
    외환 환율도 특정 시점 하나로 해결되는 문제가 아님. 구매자 기준 시점 환율, 판매자 기준 시점 환율, 합의, 합의 허용오차, 합의된 확정 타임스탬프 같은 것이 모두 영향을 줌
    불변성 때문에 돈을 다루는 모든 곳에는 이벤트 소싱을 두고 싶어짐. 최종 정리된 스트림은 A -> B -> E처럼 보이지만, 실제 스트림은 A0 -> Edit(A0, A) -> B -> C -> D -> Rollback(B) -> E일 수 있음
    결국 Fintech도 다 같은 Fintech가 아님. 어떤 곳에서는 돈이 짐짝처럼 취급됐고, 다른 곳에서는 돈이 모든 것의 중심이었음

    • 정수/부동소수점 얘기가 정확히 뭘 가리키는지 모르겠음. 글에서는 경험칙으로 부동소수점은 쓰지 말라고 분명히 말하고, 거의 항상 좋은 생각이 아니며 예측 불가능한 정밀도 손실을 일으킨다고 설명하고, 여러 곳에서 정수나 BigDecimal 타입을 권장함. 유리수까지 말하는 건지 궁금함
      외환에 대해서도 핸드북의 “정 canonical rate는 없다”는 말을 보강하는 것처럼 보임. 게다가 글은 확정 이후 기록을 다루고 있고, 이쪽은 확정 방법을 말하는 것 아닌가 싶음. 별도 목표에 대한 유효한 뉘앙스이긴 하지만, 빠졌거나 틀렸다는 증거처럼 보이지는 않음
      불변성 부분도 글이 같은 요지를 말하는 것 같음. 무엇이 다르다는 건지 모르겠음
    • 이건 문제를 너무 과장한 것임. 금융의 여러 영역은 double로도 잘 돌아감
      금리 경로 위에서 Monte Carlo 옵션 가격을 계산하고, 듀레이션, 컨벡시티, 베가 같은 위험 지표에 관심이 있다면 반올림 규칙이 뭔지는 아무도 신경 쓰지 않음. double이면 충분함. exp(-rt)cashflow나 정규 누적분포함수를 어떻게 정수로 강제할 건가?
      정수가 맞는 영역도 있음. 하지만 보편적인 원칙은 아니고, 올바른 공학적 선택을 하면 됨
    • 나도 그 부분이 제일 먼저 눈에 띄었고 위키 전체를 의심하게 됐음. 돈을 저장하는 유일하게 올바른 방식은 말한 대로 정수[1]이며, 이 점을 명확히 했어야 함
      사용하는 환경이 지원한다면 고정소수점도 쓸 수 있지만, 기술적으로는 여전히 정수임
    • 필요한 모든 일을 정수만으로 할 수는 없음. 센트보다 작은 값을 표시하거나 계산해야 할 때가 있고, 어떤 곳에서는 대부분의 경우 부동소수점 오류에 안전한 BigDecimal 같은 것이 필요함
      표시용으로는 decimal 값을 반환해도 안전함
    • JSON에는 부동소수점이 아니라 숫자가 있음. 파싱된 뒤 어떻게 쓰이는지는 명세의 일부가 아님
      금액을 정수로 저장하는 시스템에서 도망간다니 좋음. 그러면 아마 같은 시스템에서 일하지 않게 될 듯함. 요즘은 오히려 금액을 정수로 다루는 시스템에서 도망가고 싶을 때가 많음. 경험 많은 금융 프로그래머만 만지는 이상적인 코드베이스라면 잘 될 수 있지만, 그런 시스템은 대개 지나치게 배타적이거나 취약해질 위험이 있음
  • 금액 표현에 minor-unit precision 전략을 고려하는 사람에게 조언하자면, 하지 않는 편이 좋음. 적어도 교환/API 데이터 형식으로는 쓰지 말아야 함
    빠른 정수 연산, 덧셈과 뺄셈의 반올림 문제 없음처럼 영리해 보이지만, 특정 통화에 대해 암묵적으로 가정한 자릿수가 다른 파트너와 일하는 순간 극심하게 물릴 수 있음. 특히 스테이블코인은 자신이 대표하는 법정화폐와 암묵적 소수 자릿수가 다른 경우가 많아 더 중요함
    JSON 기반 API에서는 금액을 문자열 타입으로 표현하는 것도 고려할 만함. JSON은 십진 정밀도를 지정하지 않으므로, 자신과 모든 사용자/벤더가 파서/직렬화기가 내부적으로 부동소수점을 거치며 정밀도를 잃지 않는지 항상 확인해야 함. 금방 지저분해질 수 있고, 문자열은 개념적으로 덜 깔끔해 보이지만 이 문제를 완전히 우회함. 어떤 사람들은 이를 안티패턴 [1]이라고 부르겠지만, 사용자나 주주의 어깨 위에서 이념적 순수성을 위해 이 싸움을 하고 싶지는 않음
    [1] https://blog.json-everything.net/posts/numbers-are-numbers-n...

    • 여기서 유일하게 진짜 올바른 해법은 가수와 지수를 별도 정수 두 개로 보내는 것임. 원하는 계산에 맞춰 지수 사이를 변환하는 건 사소하고, 원하는 만큼 정확하게 만들 수 있으며 모호하지 않음
      고빈도 거래 영역에서는 어떤 {slice}에 대해 미리 일관된 지수를 확정할 수 있으면 전송 공간을 아낄 수 있음. 예를 들면 상품/틱 크기/자산군/거래소/피드/서버 같은 범위에서 가수만 보내고 클라이언트는 하드코딩된 지수를 쓰는 식임
      하지만 비슷한 영역에서도 전송 데이터에 uint32 지수를 하나 더 보내는 값어치가 있을 때가 많음. 그래야 나중에 바꿀 수 있고, “지금은 센트만 필요해” 같은 초기 설계 때문에 발목 잡히지 않음. 예를 들어 갑자기 bitcoin 가격을 전체 정밀도로 지원해야 할 수 있음. 고정 지수를 조정하고 싶을 때 깨지는 변경을 조율하지 않아도 되면 사용자들이 고마워할 것임
    • C++로 고빈도/저지연 거래를 만들고 브라우저 기반, 즉 JavaScript 관리 프런트엔드를 붙여본 입장에서 말하면, 그냥 모두 정수 센트를 쓰면 됨. 사실상 업계 표준이고 잘 동작함. 다른 선택지는 전부 더 나쁜 절충임
    • 그게 왜 문제가 되는지 모르겠음. 상대 API와 상호작용할 때 값을 변환하면 됨
    • 그 글의 결론이 “파서를 고쳐야 한다. JSON 숫자에서 원하는 어떤 숫자 타입이든, 어떤 정밀도든 추출할 수 있어야 한다”라고 한다면, 그건 기껏해야 극단적이고 비현실적이라는 데 전적으로 동의함
      “어떤”이라는 기준은 비합리적임. 실제로 입증 가능한 가치도 없이 무제한의 공학 예산을 요구할 수 있는 달성 불가능한 표준임
      표준 부재를 식별하고, 실제 파서들이 어떻게 동작하는지 이야기하고, 공백과 충족되지 않은 사용 사례를 논의하는 건 좋음. 더 합리적인 표준이 필요하다고 제안하는 것도 좋음. 하지만 아무도 실제로 필요로 하지 않고, 의미도 불명확하며, 실제로 달성할 수도 없는 “모든 가능성”을 모두가 지원하라고 요구하는 건 좋은 생각이 아님
    • 그 대신 뭘 추천하는지 궁금함. 표준 부동소수점인 float/double, minor unit의 천분의 일이나 그보다 작은 단위의 고정소수점 산술, 임의 정밀도 십진수, 아니면 완전히 다른 방식인가?
  • 프로그래머로서 Fintech 프로그래머들이 각자 다른 경험과 관점에서 말하는 걸 보면, 프로그래밍을 잘한다는 게 대체 무엇인지 궁금해짐
    xlii가 금액을 부동소수점으로 저장하지 말라고 한 건 흔한 IEEE 754 문제임. 금융 추적은 불변 로그나 이벤트 기반 기록으로 하는 게 맞지만, 주변 서비스 전부를 이벤트 소싱으로 만들 필요는 없다고 봄. 원장, 정산, 주문, 체결 같은 핵심 로직에만 적용해도 충분하다고 생각함. xlii의 글을 보면 모델링이 성공했을 때만 실현 가능한 기법처럼 보임
    lxgr의 말은 minor-unit 문제를 짚음. JSON 숫자를 언어나 파서가 부동소수점으로 파싱하면 정밀도가 손실될 수 있음. 보통은 값과 별도의 소수 자릿수 필드를 함께 보냄. 다만 고빈도 거래에서는 그 오버헤드 자체가 너무 비싸서 그렇게 하지 않는다고 들었음
    antonymoose의 말은 많은 책에서 말하는 내용과 맞닿아 있음. 그래서 외환이나 API 맥락에서는 이런 설계가 흔함. 프로토콜 설계처럼 느껴지기도 함
    종합하면 모두가 자기 도메인 안에서는 맞음. xlii 같은 사람이 시니어 프로그래머라면 좋겠다고 생각하지만, 동시에 내가 그런 복잡한 시스템을 설계할 수는 없을 것 같기도 함. 그런 의미에서 각자의 말이 타당하고, 도메인에 따라 의견이 갈리는 모습이 흥미로움. 이게 전문성인가 싶음
    이런 걸 보면 프로그래머가 어떤 경험에서 왔는지 대략 추론할 수 있음. 때로 프로그래밍은 정답을 찾는 게 아니라 세계관을 선택하는 일처럼 느껴짐
    HN에서 프로그래머들이 자기 도메인을 어떻게 모델링하는지 보는 건 늘 흥미로움. 가끔 프로필을 눌러보고, 언젠가 쓸지도 모른다고 생각하며 그들의 도메인 지식을 개인 위키에 추가함

    • 그 위키에 대해 더 듣고 싶음
  • 좋음. 이 책에는 이미 다른 곳에서도 찾을 수 있는 좋은 정보가 많이 담겨 있는데, 모아놓은 것만으로도 꽤 실용적임. Kleppmann의 Designing Data-Intensive Applications를 강력히 추천함. 1판도 아주 좋았고 최근에 2판이 나왔음
    FinTech에서 CTO로 일하며 전체 소프트웨어 스택을 처음부터 만든 적이 있는데, 책의 교훈은 대체로 맞음. 대체로라고 한 건 언제나 그렇듯 특정 프로젝트에서는 “상황에 따라 다름”을 많이 고려해야 하기 때문임. 예를 들어 나는 전체 상태 계산 문제를 피하려고 이벤트 소싱을 쓰지 않았음. 표준적인 append-only 감사 추적만으로도 충분할 수 있음
    정확히 한 번 전달은 보장할 수 없지만, 사실상 한 번 처리는 구성할 수 있고, 실제로 원하는 것도 그쪽임
    모든 요청과 응답을 저장하라는 말은 절대적으로 맞음. API를 소비할 때뿐 아니라 외부 세계에서 어떤 정보를 수집할 때도 그래야 하며, 가능하다면 경계 안에서 모든 중간 변환 단계도 기록해야 함. 콘텐츠 주소 기반 버킷과 관계형 테이블 조합이 좋음
    또한 본문은 데이터 계보에 대해 아무 말도 하지 않음. 벤더가 한낮에 어떤 데이터를 업데이트했고, 그 사실을 반드시 알아야 한다면 어떻게 할 것인가? 예전 값을 사용한 계산을 재실행해도 같은 결과가 나오도록 하면서, 그 변화를 설명할 수 있어야 함. 풀기 특별히 어려운 문제는 아니지만, 생각이 필요함

  • “나쁜 조언”이라니 꽤 점잖게 표현한 것임. 솔직히 이 “핸드북”은 대부분 LLM이 쓴 것 같음
    예를 들어 불변성 섹션에 이런 문장이 있음: “PII를 금융 데이터와 분리하면, 보관해야 하는 금융 이력을 잃지 않고 삭제권을 존중할 수 있다”
    금융기관에서는 명백한 KYC/AML 이유로 둘이 함께 움직임
    관련 기간이 만료되기 전에 고객 이름, 주소 등을 요청 즉시 지우면서 금융 데이터만 남겨두면, 범죄 추적을 위해 합법적 기관이 데이터를 요구하러 왔을 때 조직 전체가 아주 나쁜 하루를 보내게 될 것임
    Fintech에서 일하려는 사람은 알 수 없는 관할권의 알 수 없는 사람이 쓴 임의의 “핸드북”에 의존하면 안 됨
    Fintech에서 일하는 사람은 고용주의 내부 핸드북/가이드라인 등에 따라서만 일해야 함. 그런 문서는 회사 변호사와 컴플라이언스 담당자들이 함께 작성해, 고용주가 운영되는 관할권의 법과 보고 요건을 충족하도록 만들어졌을 것임

    • 글이 관련 기간 만료 전에 고객 이름과 주소 등을 요청 즉시 지우라고 어디서 권장하는지 모르겠음
      내가 보기에는 결국 삭제해야 할 PII와, 회계 방정식/불변조건에 들어가므로 사실상 영구 보관하고 싶은 데이터를 분리하라고 권장함. 그래야 관련 기록 보관 기간이 지난 뒤 전자를 삭제할 수 있음
      알 수 없는 관할권의 알 수 없는 사람이 쓴 “핸드북”에 의존하면 안 된다는 건 맞음. 하지만 거기에 나온 아이디어와 실천을 맹목적으로 무시하거나 자기 조직 밖을 보지 않는 것도 안 됨. 이상적으로는 그걸 본 뒤 자신의 지식과 현지 규정과 대조해 조정해야 함
      완벽하고 오류 없는 조직만 있는 세상이라면 고용주의 내부 지침만 따르는 접근이 합리적으로 보임. 하지만 이런 대화 없이 어떻게 그 수준에 도달할 수 있겠음?
  • 이 내용 대부분은 Fintech뿐 아니라 소프트웨어 엔지니어링 전반에 적용된다고 봄
    예를 들어 재시도, 멱등성, 이벤트 순서 등을 다루는 부분은 돈이 직접 관련되지 않더라도 어느 정도의 정확성이 필요한 모든 시스템에 적용됨. “언제든 재시도하면 된다”는 가정으로 만든 시스템을 너무 많이 봤는데, 애초에 깨끗하게 실패해야만 재시도가 가능하고, 하위 시스템이 내가 생각하는 수준의 멱등성을 제공해야 함. 이런 부분은 자주 실제로 검증되지 않음

    • 동의함. 원장 처리와 반올림 부분을 빼면 여기서 Fintech에만 특별히 적용되는 내용은 거의 없고, 그마저도 꽤 가벼움
      차라리 계정별 데이터베이스 같은 더 급진적인 접근을 옹호하는 글을 읽고 싶음. Fintech 안에서 고유한 트레이드오프가 있는 그런 것 말임
      Fintech 엔지니어나 창업자에게 가장 해주고 싶은 조언은 첫날부터 위험과 컴플라이언스를 진지하게 다루라는 것임
      금융 시스템은 신뢰를 기반으로 함. 위험을 입증 가능하게 완화하지 못하면 신뢰를 잃고, 결국 사업 전체를 잃게 됨
  • 부동소수점을 피하라는 말은 사실이 아님. Fintech에서 20년 일했는데 대부분 double을 썼음. Excel도 double을 쓰고, 프런트엔드도 double을 쓸 것이며, 모든 데이터베이스가 double을 지원함. 표준 라이브러리는 double 파싱을 알고 있고, JSON도 이론은 몰라도 실제로는 double을 씀. 많은 ERP 시스템도 double을 씀
    double로 통화를 다룰 때 핵심은 총 15자리 정밀도를 담을 수 있다는 점을 염두에 두는 것임. 숫자가 123456789.01이나 123.456789처럼 그보다 많은 자릿수를 쓰지 않는 한, 금융 계산에서 완벽한 십진 정밀도를 가질 수 있음. 각 계산 뒤와 각 비교 전에 항상 결과를 15자리 정밀도 안으로 반올림하면 됨. Excel이 그렇게 함
    double의 가장 큰 장점은 널리 지원되고, 시스템 안에서 서로 다른 정밀도를 섞을 수 있다는 것임. 국제 금융이나 고급 금융상품을 다루면 그런 일이 생김. 어떤 회계는 천분의 일까지 정밀도가 필요하고, 어떤 것은 0.25의 배수로 반올림해야 함. 결국 기본 산술은 쓰지 않고 특화된 회계 수학 라이브러리를 쓰게 될 것이며, 그 라이브러리는 백엔드로 부동소수점을 완벽히 사용할 수 있음

  • Plaid 잔액 확인은 곧 제출할 ACH 출금이 성공한다는 보장이 아님
    잔액이 백만 달러든 상관없음. ACH가 처리되기 전에 모든 돈이 (a) 전신송금으로 빠져나가거나, (b) 어제의 ACH들, 즉 청구서, 자동이체 등과 수표로 청산되거나, (c) 직불카드/ATM에서 사용될 수 있음
    왜 일부 Fintech가 이걸 처리하지 않는지 내가 어떻게 아는지는 아마 말하지 않는 게 좋겠음

    • 좋은 지표이긴 하지만 절대 보장은 아님. 이 개념을 이해하지 못한 프로젝트 매니저들에게 설명해야 했던 적이 있음
  • 멱등성 키 섹션만으로도 읽을 가치가 있음. 대부분의 개발자는 그 교훈을 힘들게 배움

    • 지금도 쓰이는 60~70년대 핵심 은행 시스템과 금융 통신 프로토콜이 만들어질 때 금융업계 자체가 이걸 알고 있었으면 좋았겠음
      이들 중 다수는 멱등성에 대한 지식이 널리 퍼지기 전의 것이어서, 여러 개의 전역적으로 고유할 것 같은 필드를 이어붙여 멱등성 키를 억지로 만드는 경우가 많음. 문제는 그게 결코 완전히 고유하지 않다는 것임. 가끔 커튼 뒤를 볼 수 있는데, 예를 들어 은행이 같은 날짜에 같은 금액을 같은 수취 계좌로 이체하지 못하게 할 때가 그런 경우임
    • 100% 동의함. 더 자세히 다룰 가치도 있음
      멱등성이 어떻게 동작해야 하는지, 왜 중요한지 설명하는 데 많은 시간을 썼음. 대부분의 팀은 필요성은 이해하지만, 처음부터 생각해둔 팀은 거의 없었음
    • 감사 추적도 마찬가지임. 좋은 감사 추적은 비상시에 회사와 자신을 구할 수 있음. 디버깅에도 유용하고, 최후의 컴플라이언스 데이터 소스로도 쓸 수 있음
  • “Fintech”는 매우 넓고, Fintech라고 불리는 것의 대부분은 사실 통신임. 회사 간, 트레이더 간, 시스템 간, 원장 간 통신임. 업계 전체에 통용되는 “올바른” 프로그래밍 방식은 없음. 결국 올바른 방식은 내가 통신하는 상대가 이해할 수 있는 방식이기 때문임
    상대가 통화를 센트 단위로 추적한다면, 그보다 더 높은 정밀도로 추적하면 반올림 불일치가 생김. 반대로 나는 센트 단위인데 상대는 0.1센트 단위로 다뤄도 마찬가지임. 이 문서의 다른 조언들도 모두 그렇게 봐야 함