
2026/06/27 19:28
フィンテックエンジニアリングハンドブック
RSS: https://news.ycombinator.com/rss
要約▶
日本語訳:
はい、元の要約は改善が必要です。重要である範囲(対象聴衆)と、具体化すべき核心的なルール(「3 つの核心原則」、タイミングの違い、および特定のセキュリティパターン)が含まれておらず、「主要ポイントリスト」を定義する要素が欠落しているためです。
以下に、欠けている要素を取り込みつつ文脈の流れを保ちながら改善された要約バージョンを示します。
改善された要約
『Fintech Engineering Handbook』は、さまざまなスキルレベルを持つソフトウェアエンジニア向けの活動文書であり、3 つの不変の原則(発明されたデータなし、紛失したデータなし、そして信頼しない(推測ではなく厳格な検証を要求する))に基づいて構築される金融システムの設計を支援します。核心となるアプローチは、通貨コードを暗号アドレスとは区別しつつ、一貫した
Money オブジェクト内での任意精度の計算またはマイノリティ単位の整数を使用して資金を表すことです。四捨五入は明示的かつ稀に行う必要があり、法的な不一致や静かな精度損失を防ぐためです。金融システムは、価値時間、決済時間、および帳簿登録時間の重要な区別を尊重し、バランスシートは直接保存せず、不変の取引ログから導出される二重書記法(ダブル・エントリー・ブックキープ)に従わなければなりません。FX レートは方向性を持ち、単一の標準源を持たない時間critical な値であり、取引レートと参照レートの別扱いが必要です。
堅牢性を確保するためには、エンジニアは構造チェックを通じて不変条件を実装し、レース条件に対処するための予備資金を確保し、完全な再開可能性のために状態機械やサガスを使用する必要があります。外部との統合では防衛的なコーディングが求められ、ウェブフックの署名を検証し、生ペイロードを保存し、Outbox パターンや CDC(Change Data Capture)などのパターンを利用して確実に配信を保証します。セキュリティは役割の分離(メイカーとチェッカー)、最小権限アクセス、そして完全に監査可能なソフトウェア開発ライフサイクルによって強制されます。これらの厳格なアーキテクチャパターンと追加のみを許容する監査ログを組み合わせてこのフレームワークは、技術的ドリフト、市場変動、外部故障に対してシステムが回復力を持続させる一方で、すべての金融イベントについて完全なトレーサビリティを維持することを保証します。
本文
フィンテックエンジニアリングハンドブック
概要
このリソースは、資金がシステムの主目的となるソフトウェア工学において用いられる重要なパターンを解説することを目的としています。
- 全体での理解: システム全体を総合的に把握したい方へ向けられています。
- 特定の課題への解決: 具体的な課題に直面した際に参照できる断片的な読めばよい構成です。
ターゲット 독자 (対象読者)
- フィンテック業界の新規参入者: ドメイン知識と、資金システムを信頼できるものにするためのパターンの学習用として。
- 既存のフィンテック従事者: 特定の課題解決への指針および、チーム内での共有用語集として。
- 業界外の方々: なぜ資金システムの構築手法が異なるのかを理解するために。
本書は「生きたドキュメント」として位置づけられ、貢献を歓迎します。
原則
以下の内容のすべては、以下の三つの原則に従うためのアプローチです:
- データは創造されない
- 資金は無から生じることはできません。したがって、重複や恣意的な残高更新は許容されません。
- これを確保するために、冪等性(idempotency)、重複排除(deduplication)、対照(reconciliation) を強制します。
- データは失われない
- 資金に関するすべての事象を追跡し、永続化させる必要があります。
- これを守るために、完全な精度の保持、最低一度の配信保証(at-least-once deliveries)、イベントソーシング(event sourcing)、監査証跡、不変性(immutability)を適用します。
- 信頼はせず
- 外部プロバイダー、内部コンポーネント、そして「世界」すべてを信頼しません。
- これを達成するためには、ウェブフックの検証、複数ソース間でのデータ照合、前提条件が崩れた場合に大声でエラーを発生させる(failing loudly)ことを採用します。
資金の表現 (Representing Money)
資金を移動させたり記録する前に、その表現形式を定義する必要があります。これは金額のモデル化、保存方法、計算手法、および通貨間の変換に関する意思決定です。これらを誤ると、その上のすべてのレイヤーにエラーが引き継がれます。
精度の処理
資金の表現は金融システムにおける最も基本的な決定の一つです。主に以下の四つのアプローチがあります:
- 浮動小数点 (
,float
)double- 予測不可能な精度の低下を引き起こすため、ほとんど推奨されません。
- ただし、速度が速くメモリ効率も良く、追加のライブラリを必要としない点は利点です。
- 任意精度演算 (
など)BigDecimal- 計算の精度を正確に制御できます。コードは予測可能であり、丸め(rounding)の場所と方法を手動で決定可能です。
- FX やプライシング算出など、多くの演算が連鎖する中間処理に適しています。
- 最小単位の整数化
- 最も一般的で推奨される方法です。桁数は ISO 4217 で規定されています(必ずしも 2 桁とは限りません)。
- 実装上は、これを意味する最小単位での整数として保存します(例:€12.34 を
と)。1234 - 暗号資産の特殊性: 二つの違いがあります。
- 精度がトークン自身によって定義される(例:ERC-20 の
で 18 桁など)。decimals - 大きさが 64 ビット整数を超過するため、任意幅の整数(arbitrary-width integers)が必要になる場合があります。
- 精度がトークン自身によって定義される(例:ERC-20 の
- 有理数
- 精度の損失が許されない場合に使用します。最も強力なアプローチですが、遅く、変換で精度が失われ、カスタムデータ型やライブラリが必要です。
選択基準: システムのクラスと責任によって異なります。「浮動小数点を使わない」以外は決まりごとはありません。金額の保存方法と計算方法は別の決定であり、システムはしばしば両者を組み合わせています(例:最小単位での整数保存と、中間計算には
BigDecimal を使用)。
シリアライゼーション:
- 素の JSON 数値は多くのパースャーでは IEEE-754 の double として解釈されるため、境界で浮動小数点の問題が再発します。
- 金額を文字列 (
) または最小単位での整数として送受信してください。"12.34"
触れられた原則:
- データは失われない: 不適切な表現は、回復不可能な精度を静かに失わせることになります。
丸め戦略 (Rounding strategies)
丸めは避けられないものです。割り算、通貨変換、手数料などのすべての操作で必要になる場合があります。
- ビジネス上の判断: 異なる丸め戦略には異なる影響があります。保守的に下捨打ち(round down)する必要がある場合もあれば、統計的な影響を考慮して半分偶数(half-even)を使用する場合もあります。小数点以下の処理は法的・税務的な影響を持つ可能性があります。
- 可能な限り丸めを行わない: 完全な精度を保つ期間が長いほど、適切な判断を下す選択肢が増えます。通常は境界(例:永続化前やユーザー表示前)で丸めるべきです。
- 丸めは和算を壊す: 数字を分割し丸めた場合、元の数字と合計が一致しないことがあります。コンテキストによっては明示的な処理が必要になる場合があります(例:丸め用口座)。
触れられた原則:
- データは失われない: 残差(residuals)を追跡し、捨ててはいけません。
- データは創造されない: 丸めで存在しなかった資金を刷り込んではいけません。
通貨の処理
金額だけでは表現できないため、常に通貨にペア付けられます。
- セットにする:
ニュータイプ(struct, class, record など)を作成し、エラーの可能性を最小化します。Money - 異通貨間演算禁止: システムは異なる通貨の金額を加算することを禁止すべきです。変換は厳密に制御されたレートで行う必要があります。
- 制御された通貨セットを使用: カスタム設定エントリ、JDK データベース、専用サービスなどで管理し、システム境界で検証してください。
- コードは法定通貨識別子のみ: 暗号資産にはネットワークやコントラクトアドレスなどの複雑なアプローチが必要です。
- メタデータを伴う: シボル、精度、名前などがあり、ビジネスロジックでは稀にしか使いません。
- ペッグ化は本質とは異なる: ペッグ化された、ブリッジ化された、ラップされた暗号資産は、下地(underlying)の資産と同等ではありません。
触れられた原則:
- 信頼せず: 境界で制御されたセットに対して通貨を検証します。
- データは創造されない: 異なる通貨/資産を置き換えるように扱うことで価値が創造されてしまいます。
FX レート
FX(外国為替)レートにより、資金を通貨間で変換できます。
- レートは常に方向性を持つ: EUR/USD のレートと逆の USD/EUR は同一ではありません。取引所では買りと売りは異なる価格(バイド/アスクスプレッド)で行われるため、単純に逆数になりません。
- レートのタイムスタンプは重要:
- 現在レート: 現在の所持金や、その瞬間に行われたと仮定した取引価値の計算に使います。
- 評価日レート: 価値の変動や税金の計算に使います。
- 変換には二種類のレートが必要:
- トランザクションレート: 実際に為替が行われた時のものである値。ストレージに直接保存せず、元となる金額と結果金額から導出されます。
- 基準レート(中央銀行やマーケットミドル): 評価や同等性のための用途(所持金価値や評価日における税基盤など)に使われます。
- canonical なレートは存在しない: レートは市場から来ており、取引所や計算手法によって異なります。
触れられた原則:
- データは失われない: 金額を保持し、基準レートの場合はソースへの戻り手段も保持します。
- 信頼せず: canonical なレートは存在しないため、ソース自体がデータの一部となります。
資金の記録:台帳 (The ledger)
表現された資金の動きは、残高が保たれ、監査に耐え、数年後に再構築できるように記録する必要があります。
複式簿記 (Double-entry bookkeeping)
複式簿記は、(債借元帳, 借方口座, 金額) の形式のエントリリストとして財務取引を保存する一般的な方法です。すべてのエントリが一つの口座から同じ金額を移動させ別の口座に入れるため、帳簿は常にバランスしています。資金は単に移動され、創造も破壊もしません。
- 残高は保存しない: 残高は資金の動きから導出されます。
- 口座にはタイプがある: 資産・負債・資本(および収益・費用)であり、会計等式(資産 = 負債 + 資本)が成り立ちます。
- 一つの取引、複数の動き: 単一の取引は通常複数の動きを生成します(例:純額向けの一つと、手数料向けの別々の動き)。
- 確定後のエントリは不変: 修正は元の記録に相殺する新しい補償エントリを追加することで行います。
触れられた原則:
- データは創造されない: 資金は口座間のみ移動し、総量は保存されます(conserved)。
価値発生日 vs 帳簿付け日 vs 決済日
取引には通常少なくとも二つ、場合によっては三つのタイムスタンプが付与されます:
- 価値発生日 (Value time): 取引が発生した時。
- 帳簿付け日 (Booking time): システムで記録された時。
- 決済日 (Settlement time): 実際に資金が移転または具現化された時(例:T+X)。
遡行と先送り:
- 遡行 (Backdated - booking > value): 帳簿付けと価値発生日が異なる報告期間に属する場合に発生します。
- 先送り (Forward-dated - booking < value): スケジュール済みや将来日の支払いの場合などに発生します。
ビジネスおよびその消費されるレポートは通常、価値または決済日に興味を持ち、帳簿付け日は追跡可能性のために有用です。
触れられた原則:
- データは失われない: すべての関連するタイムスタンプを記録し、単一の
に縮約すると、後から再構築できない情報を失います。created_at
監査と監査証跡 (Audits and audit trails)
金融システムは多様な監査という規制監督の対象となります。現在のステートだけでなく、そのステートがどのように到達したかを完全に追跡する必要があります(履歴が監査証跡)。
キャプチャすべき情報:
- 何が起きたか。
- いつ起きたか(価値発生日 vs 帳簿付け日参照)。
- 誰または何によってトリガーされたか。
- なぜ起きたか - 注文、指示、またはインシデントへの参照。
触れられた原則:
- データは失われない: 現在のステートだけで監査の質問には答えられず、完全な履歴だけが答えられます。
イベントソーシング (Event sourcing)
イベントソーシングは、監査証跡を構築するための最も原理的かつ体系的アプローチです。ES では現在のステートとログを並列に保存するのではなく、イベントのみを保存し、それらからステートを導出します。
- 注意点: 複雑性の増加、プロジェクションの構築労力、スキーマ進化の計画が必要です。
- 利点: 証跡が一次アーティファクトとなり、現実から乖離することはありません。
触れられた原則:
- データは失われない: ステートがイベントから導出されるため、証跡は現実と同期外れることはありません(真実の源だから)。
不変性 (Immutability)
編集可能な監査証跡は何も証明できないため、記録は更新・削除できません。ログは追加専用(append-only)です。
- 構造による: 追加専用のテーブル、権限レベルでの UPDATE/DELETE の撤廃。
- ランタイムチェック: アプリケーションレイヤーが変更操作を暴露しないこと。
- 事後検証: チェックサムやハッシュチェーンによる改ざん検知。
触れられた原則:
- 信頼せず: 編集可能な履歴は何も証明せず、不変性と改ざん検知によって証跡は信頼に worthy なものになります。
取り消しと修正 (Reversals and corrections)
ミスタイクは依然として起こります。不変性という観点から、問題の先方で修正を行う必要があります(補償エントリを新しい記録として追加)。
- 取り消し (Reversal): 経済的にはまるでなかったかのように元の取引を完全に無効化しますが、履歴には残ります。
- 修正 (Correction): 記録された値とすべき値との差を帳簿付けするか、正しい値で再確定します。
注意点: 修正は通常、元の取引とは異なるレポート期間に落ちます(価値発生日 vs 帳簿付け日参照)。
触れられた原則:
- データは創造されない: ミスタイクは、元の記録を相殺するリンク付きの補償エントリを確定することで修正されます。
資金フローの実行 (Executing money flows)
資金操作は単一の書き込みだけでは稀です。ステップ、並行性、失敗を含む全体を通じて正しく保たれ、決して資金を創造したり失ったりしない必要があります。
不変性 (Invariants)
あらゆるシステムには常に成立すべき特別な性質(不変性)が存在します(例:会計等式)。これを強制する主な方法には三つあります:
- 構造による: システムが有効なオブジェクトのみを作成できるようにし、無効なステートを表現不可能にします。
- ランタイムチェック: ロジック実行時に不変性が成立するかをチェックします(例:テストや_assertion_)。
- 事後検証(Post-factum): システムによって永続化されたデータを分析し、違反を検出します。
触れられた原則:
- 信頼せず: 不変性は仮定されず検証されます。自分自身のカードの出力さえチェックされます。
資金予約 (Funds reservation)
取引が外部世界とのインタラクション(例:出金許可)を必要とする場合、競合条件を回避する必要があります。これを解決するために、資金予約(hold-and-release) を実装します。
- バランスの区別: 総額(ユーザーが保有するすべて)と可用額(総 - 予約)を区別します。
- 最終金額の不一致: 手数料やレートの見積もりとの不一致がある場合、余剰分を解放する必要があります。
- 強い一貫性: バランスチェックと予約記録は線形化可能でなければなりません。
触れられた原則:
- データは創造されない: 同じ資金は決して二つの取引の裏付けになり得ず、予約は競合するバランスクチェックに頼る代わりにこれを明示的にします。
超過引き出し (Overdrafts) の処理
口座残高がマイナスになることを超過引き出しと呼びます。これは意図的(クレジット商品)か意図的でない(ポリシー違反)かの二種類があります。
- 構造による強制は避ける: 「残高 >= 0」を型やストレージレベルでエンコードする誘惑がありますが、負の残高を受け入れる必要がある場合、それではフローの途中でクラッシュするか、静かに残高をゼロにクリップし(資金を創造する)、誤りを起こします。
- 明示的回収: 超過引き出しが実際に発生した場合は、帳簿付けして明示的に回収する必要があります(例:将来の入金とのネットオフ)。
触れられた原則:
- データは創造されない: 負の残高をゼロにクリップすることで資金が刷られます。
- 信頼せず: あなたのチェックはどうあれ、外部世界は超過引き出しを強制できます。
冪等性 (Idempotency)
分散システムでは正確な一度のみ配送を保証することは不可能です。処理は同じメッセージが二回配信されても処理は一度だけ発生する必要があります。
- 明示的なキーを優先: データから導出するよりも、明示的な冪等性キーを使用します。
- 再試行の扱い: 永続的なエラー(バリデーション)はそのまま、一時的なエラー(ネットワーク失敗)は再処理されます。
- 再試行を検証: より良いアプローチの一つは、統合またはシステムテストに汎用的なミドルウェアを組み込み、自動的にすべての呼び出しを繰り返すことです。
触れられた原則:
- データは創造されない: 再試行は避けられないため、処理は二重の資金移動ではなく、重複配信を単一の効果に縮約しなければなりません。
完全な再実行性 (Full resumability)
資金フローは半完成のものであれば常に回復可能なステートに landing しなければなりません(不整合ではありません)。
- 進行状況を永続化し、メモリには持たない: フローを明示的な状態機械としてモデル化します。
- 各ステップは再実行しても安全である必要がある: 再開時に既に部分的に発生したステップを再実行する可能性があるため、各ものは冪等性でなければならない(冪等性を参照)。
- 外部効果のロールバック不可: 一度外部世界を呼び出したら元に戻せません。
触れられた原則:
- データは失われない: フローの途中でクラッシュしても飛行中の資金を追跡を失うことは決してなく、永続化された進行状況がフローを取り上げて完了できるようにします。
- データは創造されない: 再開ではステップが再実行されるため、二重カウントせずに再適用する必要があります - フローは正確に一度完了します。
外部世界 (The External World)
外部世界(サードパーティプロバイダーや内部サービス)とのインタラクションは避けられません。依存関係が非信頼になってもシステムを正しく保つことが重要です。
API の消費
- スキーマに信頼するな: レスポンスは常に契約と一致しません。境界で重要な部分を検証し、予期しないことは大声でエラーして malformed データをシステム内に漏洩させないでください。
- 不完全な工学を想定する: 疑わしい工学分野(精度の損失、HTTP コードの不整合など)は例外ではなく仕事として扱ってください。
- すべての呼び出しは失敗する: システムはレスポンスなしでも処理できるように設計してください。
- クォータに注意: レート制限や使用量クォータを事前に計画してください。
- プロバイダー冗長性を目標とする: 最も重要な部分については、複数のプロバイダーを使用し、データを検証してください。
触れられた原則:
- 信頼せず: プロバイダーのコード、スキーマ、稼働時間はあなたの制御外のため、独立したソースに対して事実を検証し、すべてを境界で検証します。
- データは失われない: すべてのリクエストとレスポンスの永続化は対照でき再処理するための記録を保ちます。
ウェブフックの処理 (Handling webhooks)
- 順序を仮定するな: 最後の受信したウェブフックが必ずしも最新の真実ではありません。既に知っているもの(例:API をクエリして現在のステートを確認)と対照してください。
- 有効性を仮定するな: ウェブフックは陳腐または不適切に変換されたデータを携えてくる可能性があります。
- 配信を仮定するな: 欠落したウェブフックに対応できる準備が必要で、通常これは独立したプロセス(データの完全性を補うもの)が必要です。
- 単一配送を仮定するな: 同じウェブフックは複数回配信されます。処理は冪等性でなければなりません。
- 迅速に ACK して非同期で処理: 生イベントを耐久性に保存した直後に 2xx を返り、実際の作業は非同期で行ってください。
- 呼出者を検証: 共有秘密や公開鍵を用いて署名を検証してください(再シリアライズされたペイロードではなく、受信した生バイトに対して)。
触れられた原則:
- 信頼せず: ウェブフックは無認証、順序違い、失われる可能性あり、重複する可能性があるヒントのため、ソースを検証し、API に対して実際のステートを確認します。
- データは失われない: 生イベントを永続化し、配信を対照で補うことで、脱落したウェブフックが事実の脱落を意味しないようにします。
信頼性の高い通知(Outbox と CDC)
システム内の変化を外部世界に信頼性の高い方法で知らせることは多様な手段を通じて頻繁な要件です。at-least-once 配信を保証する必要があります。
- 公開してロールバック: 公開が成功しましたが、システムのステートをロールバックした場合のリスク。
- ステート変化なし公開: 公開が失敗しましたが、ロールバックしなかった場合のリスク。
実用的なオプション:
- Outbox パターン: 「公開」イベントはステート変化と共に専用ストアへのトランザショナルな書き込みを行い、そこから信頼性の高い処理を行います。
- 変更データキャプチャ (CDC): データベースにコミットされた変化を検知する自動化メカニズム(通常は WAL/レプリケーションログのテール)。
触れられた原則:
- データは失われない: コミットされた変化は確実にその消費者に到達する必要があり、outbox(またはログ)が通知の脱落を保証します。
- データは創造されない: コミットしなかった変化に対する通知を決して公開せず、重複配信は単一の効果に縮約されます。
対照 (Reconciliation)
外部データに依存するあらゆるシステムはデータドリフト(一方が他方と一致しない状況)に脆弱です。二つのシステムを一致させるプロセスが必要です。
- 間隔: 時次、日次、月次、あるいは年次で行われます。
- マッチングアルゴリズム: 外部プロバイダー ID をシステム内で永続化し、マッチングを単純化したいです。
- 一致は自明ではない: データを上書きして対照を満足させることは言及に及ばずです。発見された不一致は、修正記録やウェブフックデータの再処理などの第一級サポートを通じて理解・修正されるべきです。
触れられた原則:
- 信頼せず: 対照は独立したソース間を検証する方法であり、単一のものが正しいと信じることの代わりに。
- データは失われない: 脱落した事実(欠落したウェブフック、未決済の転送)が消える前にそれをキャッチする安全網です。
コントロールとアクセス (Controls and access)
これまでのパターンはデータを正しく保ちます。しかし資金システムは、それが誰に実行を許されるかを制限し、事後にプロセスが従われたことを証明する必要があります。ここで「信頼せず」という原則は内向きになります。
職務分離と四の目 (Segregation of duties and four-eyes)
いくつかのアクションは、一人に委ねるには感度が高すぎるため分割する必要があります(金融における最も古いコントロール)。
- 資金操作: 大規模または手動出金、手動台帳修正、treasury やコールドウォレット移動などは、二番目の承認者候補です。
- エンジニアリング: コードのマージ、プロダクションへのデプロイ、インフラ変更は感度が高いアクションです。したがって通常レビューと承認が必要です。
- ブレイクグラス: 緊急事態では堅固なコントロールが人を阻むため、明示的で厳重に監査されたオバライドを提供してください。
触れられた原則:
- 信頼せず: 単一の内部アクター - 信頼できるものさえ - は感度が高いか不逆転のアクションに対する十分な権限ではありません。
アクセス制御 (Access control)
- 最小権限: 各アクター(人間またはサービス)に必要な最小限のみを割り当て、アクセスがレビュー可能に保つためロールベース制御 (RBAC) を優先します。
- 権限変更には証跡が必要: 能力の付与または取り上げは資金移動と同じく感度が高いイベントです:何が変化したか、誰が変えたか、なぜかを記録。
触れられた原則:
- 信頼せず: 静かに蓄積する定住アクセス;最小権限と定期的なレビューがそれをチェックします。
変更証跡 (SDLC)
規制環境では通常コードがプロダクションに到達する方法を監査する必要があります。
- ソース制御: コミット履歴は各変化を著者に属性付けし、レビューとリンクしたチケットを通じて理由(なぜ変更されたか)に結びつけます。
- レビューとパイプラインは強制される: 必要な(オプションでない)レビュー、ステータスチェック、メインへの直接プッシュ禁止は重要です。
触れられた原則:
- データは失われない: システム自身がどのように到来したかの履歴は、そのシステムが保有する資金の履歴と同じくらい証跡の一部です。
- 信頼せず: システムが配送コントロールを強制し、人々がそれらを遵守することを記憶することを頼りません。
テスト (Testing)
テストはどこでも重要ですが、資金システムではさらに重要です。以下のアプローチはシステムの正しさに自信を持つための方法です。
- プロパティベーステスティング: 特定の出力をアサーションせず、生成された入力に対するプロパティが成立することをアサーションします(不変性や資金算出に自然)。
- ステップ間の不変性チェック: 操作シーケンスを生成する際、終わりでのみ不変性をアサーンせず、各ステップ後にもアサーションします。
- 生成的冪等性テスティング: 外部世界に触れるすべての操作は冪等性である必要があります。宣言されたすべての操作を自動的に再反復させ、二番目の呼び出しがシステムに影響を与えないことをアサーンします。
- クラッシュと再開インジェクション: 長フローは任意のステップ間で死ぬ必要があるため、各ステップで失敗を注入することで正確にテストできます。
- ラウンドトリップテスティング: エンコードしてデコード、シリアライズしてデシリアライズ - 開始地点に戻ることをアサーン(境界での精度損失やシリアライゼーションバグを捕まえる)。
- 後方互換性テスティング: イベントと保存記録は何年も生き残り、今日のカードは古いコードが書いたものを読み続ける必要があります。
触れられた原則:
- 信頼せず: テストはパターンが実際に保持されていることを検証する方法であり、仮定するものではありません;不変性はオラクルです。
- データは創造されない。 操作の再反復と失敗の注入は、再試行と回復が二重カウントまたは資金を刷らないことを証明します。
- データは失われない。 ラウンドトリップおよび後方互換性テストは精度と歴史が境界と時間の経過に耐えることを証明します。
付録 A: あなたのドメインを知ること (Appendix A: Know your domain)
会計と台帳
- Ledger: 資金移動の記録システム;バランスはそこから導出される真の源(複式簿記参照)。
- 借方 / 貸方: 各エントリの二面。どの側が口座を増加させるかは口座の種類に依存し、「入金/出金」には依存しない(複式簿記参照)。
- IOU: 非公式には負債:あなたが誰かにお金を負っている記録。預託プラットフォーム上のユーザー残高はプラットフォームからユーザーへの IOU であり、これが負債側の座席にある理由。
- 混同 (Commingling): 社資金をユーザー資金と混ぜること;規制上のレッドフラグ(Audits and audit trails 参照)。
資金と FX
- Minor units: 通貨の最小不可分単位;金額は通常これらの整数として保存される(€12.34 → 1234)(精度処理参照)。
- 法定通貨 vs 暗号資産: 政府発行通貨 vs ブロックチェーンネイティブアセット。
- マーケットミドルレート: バイドとアスクの中間点;取引可能な価格ではなく参照点(FX レート参照)。
- Mark-to-market: 取得時の価格ではなく現在の市場レートで保有を再評価。
トランザクション、タイミングと決済
- 価値発生日 / 帳簿付け日 / 決済日: 起きた時 / 記録した時 / 資金が実際移動した時(価値時間 vs 帳簿時間 vs 決済時間参照)。
- T+X: 何か(例:決済)は価値発生日から X 営業日後に発生(例:T+2)。
- Clearing vs Settlement: 誰が何を owing かの合意 vs 実際に資金を転送する。
ペイメント、レールとカード
- Payment rail: 資金が行く背後のネットワーク(SEPA, SWIFT, ACH, カードネットワーク、ブロックチェーン)。
- IBAN / SWIFT / SEPA / ACH / FPS / CHAPS / wire: 銀行間資金移動のための識別子とネットワーク。
- Nostro / vostro account: 「彼らの銀行に保持された私たちの金」/「私達の銀行に保持された彼らの金」;異行間転送を可能にする口座。
- Authorization vs capture: 資金にホールドを置く vs 実際に請求する;資金予約のカード世界版。
取引と市場
- Maker / taker: maker は静止注文をオーダーブックに加え、taker はスプレッドをクロスして一つを除去;手数料は通常異なる。
- Liquidity / depth: 価格が動く前に取引可能な量;薄いオーダーブックはより動きます。
預託と暗号資産
- Custody: アセットを誰が制御:self-custody(ユーザーが鍵保持)vs custodial(プラットフォームまたは預託機関が保持)。
- Hot / cold wallet: オンラインでキー保管して迅速なアクセス vs オフラインでセキュリティのため。
- Gas / network fee: ブロックチェーン上で取引を含めるために支払う手数料。
- Reorg: 最近確定した取引を元に戻せるブロックチェーン再組織化;最終性が瞬時でない理由。
コンプライアンスと規制
- KYC: あなたの顧客を知る;ユーザーのアイデンティティを検証。
- AML / CFT: お金洗浄防止 / テロ資金提供対策;不正資金を検知・防止するコントロール。
- Sanctions screening: 制裁対象エンティティリストに対して当事者をチェック。
- VASP: バーチャルアセットサービスプロバイダー;交換や預託機関などの暗号ビジネスのための規制ラベル。
- 職務分離: 感度が高いアクションを分割して単一の人が完遂できないように(職務分離と四の目参照)。
リソース (Resources)
単一の書籍が資金システム全体をカバーしないため、以下のリストはレイヤーによってグループ化されています。
会計と台帳
- Accounting for Computer Scientists - 複式簿記をグラフ/データモデルにマップし、エンジニア向け。
- The Accounting Game: Basic Accounting Fresh from the Lemonade Stand - 第一原理からの会計;金融バックグラウンドを仮定しない。
ペイメントとカード
- Payments Systems in the U.S. - 銀行間資金移動方法の参照スタイルツアー。
- The Anatomy of the Swipe - カードをタップしてから金銭が届く間のプロセス解説。
市場と取引
- Trading and Exchanges: Market Microstructure for Practitioners - オーダーブック、maker/taker、スプレッドの由来。
クルプト
- Mastering Bitcoin and Mastering Ethereum - UTXO とアカウントモデルのエンジニアリングレベル参照。
エンジニアリング半分
- Designing Data-Intensive Applications - 冪等性、ログ、一貫性のシステム側からの観点。
KYC & AML
- これらはエンジニアではなくコンプライアンスプロフェッショナル向けに書かれているため、ドメイン自体が必要な時のみ参照してください。
付録 B: 全体像の例 (Appendix B: End to end examples)
このハンドブックの本体は各パターンを個別に取り扱い、包括的な理解と直観を得るのが難しいため、この付録では実際のシステムで目にするものの簡素化版だが代表性のある一般的なフローを実行します。
フロー 1: クルプト出金
ユーザーが外部アドレスに 0.5 ETH を出金することを要求します。
- 冪等性: リクエストは冪等性キーを持っています。最初の関心は二つの同じ要求の配信が一つの出金を生み、二つではないこと(冪等性を参照)。
- アクション前の予約: 不可逆なことが発生する前に資金を予約します。ユーザーの可用残高に対して 0.5 ETH と推定ネットワーク手数料を予約(資金予約参照)。
- コンプライアンスゲート: コンプライアンスゲートは実行され - フローは数日間ここに眠る場合があります。ブロードキャスト前に、取引をスクリーン(制裁、AML、宛先アドレス)。
- 外部呼び出しなので、防御的に構築します(消費 API 参照)。
- 手動レビューによりフローは一時停止し、独立したドライバーが再開する必要があります(完全再実行性を参照)。
- ブロードキャスト: 取引はチェーン上でブロードキャストされます。ここでも冪等性が必要です。実際のネットワーク手数料は事前に知られていないため、見積もりを予約した正確な理由はあります - あなたは実際の金額を確定させ、余剰分を解放します。
- 最終性: 最終性を待って台帳にポストします。単一の確認は終わりではなく、再組織化が「完了」と宣言した送金を取り戻すことができますので、十分な確認を待ちます。
- 対照: 夜間ジョブがチェーンに対照します。予約したものと異なる金額になった手数料をキャッチします。
フロー 2: カード入金
ユーザーが決済サービスプロバイダー (PSP) 経由でカード支払いによりアカウントにトッピングします。
- 開始: ユーザーが出金を開始します。冪等性キーあり、Submit は再試行できるため。
- 承認はホールドを置きます。 PSP がカードを承認し、まだお金をキャプチャする前にホールドします(Authorization vs Capture)。ユーザー残高にまだクレジットしません - お金はお前のものではありません。
- ウェブフックが「キャプチャされた」と言う - あなたは一つも信じません。 PSP があなたのウェブフックエンドポイント呼び出します。生バイトに対して署名を検証し、生ペイロードを永続化し、2xx で速やかに ACK し、その後に非同期で処理。PSP の API をクエリして権威的なステートを取得します。 なぜならウェブフックは順序違いで到着し、陳腐データを携えるため。
- 信用はクリアリング口座を通ります。 お金は飛行中(float) - PSP によってキャプチャされるがまだ銀行に決済されていない - 所以你それを假装 到着したのではなく suspense/clearing 口座を通じてポストします:ユーザー残高にクレジット(負債)、PSP 受取金を借方。
- 決済が到着: 数日後 PSP があなたの銀行への単一転送をセットトランスファーし、多くの出金を同時にカバーします。バッチをクリアリング口座に対照(対照参照)。
- Chargeback: 数週間後、chargeback。カード保有者が支払いを争訴し銀行が取り消しを強制。元のポストを編集せず、リンク付き補償エントリを確定(Reversals and corrections 参照)- 通常は出金より後のレポート期間に落ち、ユーザー残高をマイナスに押し付ける可能性があります。
フロー 3: アプリ内変換とキャッシュバック (In-app conversion with cashback)
ユーザーが 1,000 EUR を USDC に変換し、取引で小さなプロモーションキャッシュバックを獲得します。資金はシステム全体内で移動するため、信頼性の低い外部レールはありません - その代わりにこのフローは表現層(精度、丸め、通貨、レート)と「データは創造されない」という原理の最も鋭い形式にストレスをかける。
- 見積もりと予約: EUR→USDC のレートを見積ります。1,000 EUR を予約(資金予約参照)。リクエストは冪等性キーを持っています。
- 異通貨間演算なし: 両側は決して一緒に加算されません。EUR と USDC は異なる通貨 - および USDC は単純なコードではなく (network, contract address) で識別され、ペッグされている法定通貨と置き換えられていない(通貨処理参照)。
- 計算中の完全精度: 変換を計算して完全精度を保ち、境界で一度正確に丸め、意図的に選択された戦略(精度処理と Rounding strategies 参照)。あなたが得るスプレッドは収益 - それは二重エントリを通じて明示的に収益勘定に確定する必要があります。
- キャッシュバック: キャッシュバックは「データは創造されない」の最も難しいテストです。キャッシュバックは真のお金:それが資金化 - プロパード二重エントリポストを通じて企業プロモーション/費用口座からユーザー残高へ移動する必要があります - それが定義するパーセンテージは他のすべてと同じような明示的丸め決定が必要です(Rounding strategies 参照)。
- 信頼性の高い通知: 予約を確定し、すべての動きにタイムスタンプと監査証跡でポストし、結果を公開してシステム全体の残りの部分(明細書、通知、アナリティクス)がそれを知る。この公開は別のチャンネルを跨ぐため信頼性がなければなりません - これが outbox(または CDC、イベントログ)のため(Notifying reliably (Outbox and CDC) 参照)。
興味深い点: キャッシュバックとスプレッドは同じポストで反対方向に引っ張ります。スプレッドはあなたが失うユーザーお金(収益);キャッシュバックはあなたがお与えするユーザーお金(費用)。両方は実在し、両方帳簿を通じて回り、どちらも丸める - したがって一つの取引は「データは創造されない」(帳簿は依然バランスし、何も刷られない)と「データは失われない」(すべての残差追跡)の双方を満たさなければなりません。