Banking System Coding 面试深度解析:账户、转账、Top Spender、Scheduled Payment 和 Merge
Banking System面试FinTech SDE面试Stripe面试Airbnb面试Stateful Coding北美SDE面试

Banking System Coding 面试深度解析:账户、转账、Top Spender、Scheduled Payment 和 Merge

基于 Airbnb、Affirm、Stripe、Plaid 等 FinTech / Marketplace 面经抽象的 banking system coding 面试指南,拆解 ledger、idempotency、scheduled payment、account merge、history balance、edge cases、测试和英文讲解。

Sam · · 14 分钟阅读

Banking system coding 是 FinTech、marketplace、payment、risk 和 ledger 类岗位里非常高频的题型。你可能面的是 Airbnb、Affirm、Stripe、Plaid、Robinhood、Coinbase,也可能是一个普通 backend team,但题目会长得很像:创建账户、存钱、转账、查询 top spender、执行 scheduled payment、merge account、查询历史余额。

这类题不是难在算法,而是难在状态会不断变化。每一问都建立在前一问的数据模型上。如果你一开始只用一个 balance map 硬写,后面遇到 scheduled payment、account merge、history balance 时会非常痛苦。

这篇文章基于多类公开面经做匿名抽象,拆解 banking system coding 的稳定建模方式和面试表达。

快速答案

Banking system coding 面试主要考:

  • 你能不能设计稳定的 state model。
  • 你能不能处理时间顺序和 delayed execution。
  • 你能不能区分 balance、transaction、ledger、history。
  • 你能不能在 multi-part follow-up 下保持代码可扩展。
  • 你能不能主动提 edge cases:重复请求、余额不足、账户不存在、merge 后历史查询。

这类题要先建模,再写函数。不要一上来就写代码。

常见题目结构

典型面试会分成 4-5 个 level:

Level功能核心考点
1create account、deposit、transfer基础状态和输入校验
2top spender / top activitytransaction aggregation、排序和 tie breaker
3scheduled payment时间推进、pending task、execution order
4merge accountidentity、alias、history preservation
5historical balanceledger / snapshots / event replay

越往后越不是“写个 map”能解决的问题。

第一步:先定义数据模型

面试前 2-3 分钟,你应该先和面试官确认:

  • account id 是否唯一?
  • transaction timestamp 是否单调递增?
  • transfer 是原子操作吗?
  • scheduled payment 是在每次 API call 前执行,还是有独立 scheduler?
  • merge 后旧 account id 是否还能查询历史?
  • top spender 统计 outgoing amount 还是 total activity?

一个稳的初始模型:

accounts:
  account_id -> {
    active: boolean
    balance: number
    created_at: timestamp
  }

ledger:
  list of {
    txn_id
    timestamp
    type
    account_id
    counterparty_id
    amount
    status
  }

outgoing_total:
  account_id -> number

scheduled_payments:
  min-heap ordered by execute_at, payment_id

alias:
  old_account_id -> canonical_account_id

你不一定一开始全部实现,但脑子里要有这个方向。

面试中可以说:

“I will start with current balance for fast operations, but I will also record ledger events because later follow-ups like historical balance or account merge are much easier with an append-only transaction log.”

这句话能直接体现你考虑到了后续扩展。

Level 1:账户、存款、转账

基础 API 通常包括:

  • createAccount(timestamp, accountId)
  • deposit(timestamp, accountId, amount)
  • transfer(timestamp, sourceId, targetId, amount)

常见规则:

  • 创建重复账户失败。
  • 存款到不存在账户失败。
  • 转账双方必须存在且 active。
  • 不能自己转给自己。
  • 余额不足失败。
  • amount 必须为正数。
  • 成功后返回新余额或 transaction id。

这部分不要写复杂。重点是输入校验顺序清楚。

更稳的 transfer 逻辑:

resolve source and target canonical accounts
validate accounts exist and active
validate source != target
validate amount > 0
validate source balance >= amount
debit source
credit target
append debit and credit ledger events
update outgoing_total[source]
return success

很多候选人会忘记 top spender 需要 outgoing_total,所以后面再补时要回扫全部交易。可以提前在成功转账时维护。

Level 2:Top Spender / Top Activity

这类 follow-up 常见要求是:

“Return top N accounts by total outgoing transfer amount. If tie, sort by account id.”

关键点:

  • 只统计成功 outgoing transfer,失败不算。
  • deposit 不算 outgoing。
  • scheduled payment 执行成功后通常算 outgoing。
  • merge 后金额归到 canonical account 还是保留旧 account,要问清楚。
  • tie breaker 要明确。

如果 N 很小、账户不多,直接排序可以:

sort accounts by (-outgoing_total, account_id)
return top n

如果面试官追问 scale,可以讲:

  • 读多写少:每次 query 排序可以接受。
  • 写多读多:维护 balanced tree / heap with lazy update。
  • 分布式:按 account shard 聚合,再做 top-k merge。

但现场 coding 不要过早优化。先写对。

Level 3:Scheduled Payment

Scheduled payment 是这类题最容易出错的部分。

常见 API:

  • schedulePayment(timestamp, accountId, amount, delay)
  • cancelPayment(timestamp, accountId, paymentId)
  • 每次 operation 前,先执行所有 execute_at <= timestamp 的 pending payment。

关键问题:

  • 如果到期时余额不足,payment 是失败、跳过、还是继续 pending?
  • cancel 一个已经执行的 payment 要返回什么?
  • 同一时间多个 payment 执行顺序是什么?
  • payment id 如何生成?
  • scheduled payment 是否计入 outgoing total?

稳的实现方式:

processDuePayments(timestamp):
  while heap not empty and heap.peek.execute_at <= timestamp:
    payment = pop
    if payment.status != pending:
      continue
    account = resolve(payment.account_id)
    if account active and balance >= amount:
      debit balance
      mark executed
      append ledger event
      outgoing_total[account] += amount
    else:
      mark failed

每个 public API 一开始先调用 processDuePayments(timestamp)。这样系统状态始终推进到当前时间。

注意不要遍历所有 scheduled payments,这会慢。用 min-heap 按 execute_at 排序。

Level 4:Merge Account

Account merge 通常是最容易把代码打乱的 follow-up。比如:

“Merge account B into account A. Balance should move to A. Future operations on B should fail or redirect. Historical balance queries should still work.”

这里一定要问清楚语义。常见选择:

  • current balance:B 的余额转入 A,B inactive。
  • future operations:B 不再允许 deposit / transfer。
  • historical query:B 在 merge 前的历史仍然能查。
  • top spender:B 的 outgoing total 是否合并到 A。
  • scheduled payments:B 的 pending payment 是否转到 A,还是取消。

一个 pragmatic 做法:

canonical(account_id):
  follow alias until active canonical account

merge(timestamp, target, source):
  processDuePayments(timestamp)
  validate target and source active
  target.balance += source.balance
  target.outgoing_total += source.outgoing_total
  source.active = false
  alias[source] = target
  append merge ledger event

但是 historical balance 不能只靠 current balance。你需要 ledger。

面试中可以说:

“For current operations I will resolve aliases to canonical accounts. For historical queries I will not rewrite old ledger events; I will keep original account ids in the ledger so pre-merge history remains answerable.”

这能避免很多逻辑混乱。

Level 5:History Balance

最后一问常见是:

“Return balance of account X at timestamp T.”

如果你只存 current balance,就很难答。常见方案有三种。

方案一:Event replay

从 ledger 开始回放到时间 T,计算余额。

优点:实现简单,历史准确。
缺点:每次 query 慢。

适合面试 coding 的第一版。

方案二:Balance snapshots

每次交易后记录:

balance_history[account_id] = [
  (timestamp, balance)
]

查询时二分找到 timestamp <= T 的最后一条。

优点:查询快。
缺点:merge、alias 和 backfill 更复杂。

方案三:Ledger + periodic snapshot

生产系统常用折中:定期 snapshot,加上之后的 events replay。

面试中可以先实现方案二,因为代码比较直接:

recordBalance(account_id, timestamp):
  history[account_id].append((timestamp, current_balance))

getBalance(account_id, timestamp):
  entries = history[account_id]
  idx = upper_bound(entries, timestamp) - 1
  return entries[idx].balance

merge 的时候要注意:source account merge 后,旧 account 的历史不能消失;target account 在 merge timestamp 的 balance 要记录一次。

Ledger 思维为什么重要

Banking system 题本质是 ledger 题。真实支付系统不会只存一个余额字段,因为你需要:

  • audit trail
  • dispute / refund
  • idempotency
  • reconciliation
  • historical balance
  • fraud investigation
  • compliance

即使现场代码不需要完整 ledger,你也应该在 design discussion 里提到。

可以这样表达:

“For the coding version, I will keep current balance for simplicity. But I will also append transaction records so that audit, history, merge, and reconciliation can be supported later.”

这句话对 FinTech 面试很加分。

必测 edge cases

建议现场主动说你会测这些:

  • create duplicate account
  • deposit negative amount
  • transfer to self
  • transfer with insufficient balance
  • transfer to missing account
  • top spender tie breaker
  • scheduled payment with insufficient balance
  • cancel already executed payment
  • two payments at same timestamp
  • merge missing account
  • merge account into itself
  • transfer from merged account
  • historical balance before account creation
  • historical balance after merge

如果时间不够,至少手动 dry run 3-4 个高风险 case。

常见挂法

只用 balance map

前两问能过,后面 history 和 merge 会崩。

没有统一处理时间推进

scheduled payment 到期后,有的 API 执行了,有的 API 忘了执行,状态不一致。

Merge 后重写历史

把 source account 的历史全改到 target account,导致 pre-merge 查询失真。

Top spender 统计错

把 deposit 算进去,或者失败 transfer 也算出去。

英文不讲 trade-off

FinTech 面试官很在意 reliability。你只写代码不讲 idempotency、audit、reconciliation,会少很多信号。

英文讲解模板

可以提前准备这些表达:

  • “I will keep current balances for fast reads, and append ledger events for audit and historical queries.”
  • “Before every public operation, I will process scheduled payments due at or before the current timestamp.”
  • “For merge, I will keep old ledger events unchanged so historical balance remains correct.”
  • “Only successful outgoing transfers should count toward top spender.”
  • “In production, I would add idempotency keys to avoid double charging on retries.”
  • “If this needs to scale, I would shard accounts by account id and reconcile ledger events asynchronously.”

一周准备计划

第 1 天:基础账户 API

写 create、deposit、transfer,补所有 validation。

第 2 天:Top N

实现 outgoing total、排序、tie breaker,练 scale follow-up。

第 3 天:Scheduled Payment

实现 min-heap、cancel、process due payments、同 timestamp 顺序。

第 4 天:Merge Account

实现 active flag、alias、balance merge、pending payment 语义。

第 5 天:History Balance

实现 balance snapshots 和 binary search。

第 6 天:Ledger Discussion

准备 audit、idempotency、reconciliation、refund、duplicate request 的回答。

第 7 天:完整 mock

用 60 分钟从 level 1 写到 level 4,最后 15 分钟做 code review 和 system follow-up。

相关阅读

需要 FinTech / Stateful Coding Mock?

Banking system coding 最需要练的是状态建模、时间推进、edge cases 和英文解释。Interview Coach Pro 可以按 Stripe、Airbnb、Affirm、Plaid、Robinhood、Coinbase 这类风格做 stateful coding mock,帮你把多问 follow-up 练到稳定。

查看 SDE 面试辅导服务
预约一次面试准备咨询

S

关于作者

Sam 是 Interview Coach Pro 的技术面试教练,长期辅导在美国求职的中文候选人准备 SDE、System Design、Behavioral、Data Engineer 和 ML Engineer 面试。

本文基于匿名面试复盘、公开岗位要求和一对一辅导中的高频问题整理,发布前会检查内容结构、术语准确性和可操作性。你也可以查看我们的 辅导团队辅导方法

相关面试辅导

如果你正在准备类似面试,可以直接从下面的专项辅导开始。

准备好拿下下一次面试了吗?

获取针对你的目标岗位和公司的个性化辅导方案。

联系我们