卷 V · CH 18 · 深度 18/18

把十八章压进一场面试

好的回答不是把知道的全倒出来,而是先给判断,再给机制、取舍和一段亲手做过的证据。

PLAYBOOKSYSTEM DESIGNTHREE DAYS
▷ 先答一下

面试官问:「StateFlow 和 SharedFlow 有什么区别?」最好的开头是哪句?

  1. 把两者所有构造参数背一遍
  2. 「一个有 value,一个没有」
  3. 「先看你要表达当前状态,还是一次广播事件」
  4. 「项目里统一用 StateFlow」

六个三十秒答案

  1. 生命周期:「我先区分配置变更、页面离开与进程死亡。ViewModel 只跨配置变更;短小 UI 输入进保存状态;不能丢的业务事实先落数据库,跨进程工作交 WorkManager。」
  2. 协程:「suspend 允许暂停,不保证后台执行。scope 定寿命,Dispatcher 定执行政策;普通 scope 共命运,supervisor 隔离兄弟失败;底层 API 应主线程安全。」
  3. Flow:「冷流每个 collector 重启生产;StateFlow 表示有当前值的共享状态;SharedFlow 是可配置重放的广播。选择先看订阅、重放、丢失和慢消费者语义。」
  4. Compose:「Composable 是可重放描述。状态读取决定重组范围,位置或 key 决定身份,稳定参数允许跳过。副作用必须放 Effect,并明确 key 与清理。」
  5. 架构:「UI 观察不可变状态、事件上行;数据层拥有业务事实。Repository 定义来源与一致性政策,领域层只在规则复杂或复用时添加。」
  6. 离线消息:「先事务写本地消息与 outbox,UI 只观察 Room;Worker 带同一幂等键重试;服务端给会话序号;推送只触发游标补洞。」
可以带走的判断:技术回答先说合同,再解释机制,最后给取舍;API 名字放在第三位。

系统设计题:安全医疗消息

先问约束,不要立刻画框:一对一还是群组?顺序要求到会话还是全局?允许离线多久?附件大小?消息能否撤回?设备丢失后如何撤销?通知可显示多少?合规地区与保留期?多端是否同时在线?

接着说五个不变量:

  • 用户按发送后,意图要么明确失败,要么可恢复地进入本地队列。
  • 未知结果可安全重试,服务端效果至多一次。
  • 会话内顺序由服务端定义,客户端待发状态可解释。
  • 未授权设备拿不到正文,通知与日志不泄露患者信息。
  • 本地敏感副本有最小范围、明确寿命和可审计清理。

然后画链:Compose → ViewModel → Repository → Room+outbox → WorkManager → API → 服务端序号 → Room → UI。最后逐个打故障:断网、超时但已提交、进程死亡、重复推送、令牌过期、数据库满、权限撤销、设备时间错误。每个故障都对应状态、恢复和指标。

针对 Celo Health,值得问的问题

这些问题来自公开产品约束,不假设内部实现:

  • 「移动端在安全与离线可用之间,最难的一次取舍是什么?」
  • 「Android、iOS 与 Web 的消息顺序和同步合同由哪一层定义?」
  • 「临床照片不进入个人相册时,团队如何设计临时存储、上传恢复与清理?」
  • 「团队怎样测弱网、大量消息到达、进程死亡与设备型号差异?」
  • 「AI Scribe 的音频与草稿在移动端有哪些数据寿命和用户确认边界?」
  • 「入职前三个月,这个角色最需要改善的用户旅程或工程指标是什么?」

好问题不是展示你查过官网,而是把产品承诺翻译成工程合同,并邀请对方讲真实取舍。

行为题也要有技术判断

用 STAR 只是保证顺序:Situation 简短交代约束,Task 说清你的责任,Action 重点讲你如何发现信息、权衡方案、拉齐人,Result 给结果与反事实。最后加一句「现在重做我会怎么改」,能显示学习能力。

两年空窗无需防御性解释。可直接说:「我有成熟 Android 基础,过去两年没做原生开发,所以这次按生命周期、协程、Compose、离线架构与质量证据系统恢复;我也用一条安全消息把它们重新接成了完整设计。」诚实承认不记得某个 API,再说查证路径,比硬猜版本号可靠。

⌨ 自己跑一遍

定时做一次完整口述。不是默读答案,而是录音后按合同、机制、取舍、证据四项打分:

00:00–00:30  自我介绍:经验、空窗、为什么回来
00:30–02:00  Compose 状态与副作用
02:00–03:30  协程、取消与 Flow
03:30–08:00  离线安全消息系统设计
08:00–10:00  故障矩阵、安全、测试与指标
10:00–12:00  反问 Celo Health
# 手机录音即可;回听时只记四列
判断是否先给出 | 机制是否准确 | 取舍是否具体 | 是否有证据

# 每道题第二遍必须比第一遍短
# 卡住时用这句重启:我先把约束和不变量说清楚。

今天录第一遍,明天只重录最弱的两段,面试前一天录完整第二遍。不要背逐字稿;只记每题的第一句判断与最后一句取舍。

三天冲刺表

时间
第 1 天01–08:系统、Kotlin、协程、Flow写 reducer、进程死亡草稿、幂等重试单测
第 2 天09–16:Compose、架构、离线、安全搭一页 ChatScreen,口述消息系统设计
第 3 天17–18+错题回看跑测试、录十二分钟模拟、准备三个项目故事
面试当天只看六个三十秒答案不再升级工具链,不再开新教程

继续往下走

  • Compose 运行机制:接着读书架上的《重跑》,补 Snapshot、阶段读取与性能诊断。
  • Android 架构变化:读《承重》,对照 Navigation 3、状态持有者与真实项目流派。
  • Kotlin 深水区:读《坩埚》,补 inline、协程状态机、型变与 K2 工具链。
  • 并发底层:读《同时》,把协程接回线程、内核 I/O、内存模型与背压。
  • 官方样板:看 Now in Android,但每抄一个模式都先问它在解决什么规模的问题。

争议点也值得继续:一次性 UI 事件该用状态还是事件流、UseCase 是否默认存在、导航状态该由谁持有、证书固定是否值得。这些没有脱离上下文的唯一答案;成熟度体现在你能列出失败模式。

▸ 在现实里

面试官不一定按这本书的章节问。他可能从一个 bug 切入:「为什么旋转后 Snackbar 又弹了?」你可以沿链回答:事件被当成可重放状态 → 新 collector 收到旧值 → 选择状态内联显示或定义明确的一次性效果 → 用生命周期与重建测试验证。地图比题库耐用。

✗ 这个直觉是错的

「准备得越多,回答越长越显得资深。」长答案常把判断埋掉,也不给面试官追问空间。

第一轮控制在三十秒:判断、两句机制、一个取舍。对方追问时再下钻到代码、故障和证据。

◇ 面试收口

答案是第 3 项。StateFlow 与 SharedFlow 的区别不是属性清单,而是语义:前者适合「现在是什么」,后者适合「向当前订阅者广播什么」。从需求合同开头,后续参数才有落脚点。

这一章的一句话

你不需要证明自己记得所有 API;你要证明面对变化、失败和取舍时,仍能把系统推理清楚。

书到这里结束。最后一次练习不是再看一章,而是合上目录,用十二分钟把那条消息从手指送到服务端,再完整送回来。