← 2026-06-01 📂 All Days 2026-06-03 →

🏗️ 系统设计 / System Design — Day 47

设计地理空间系统 / Design a Geospatial System (Yelp / Nearby Friends)

2026-06-02 | Expert Phase


场景 / Scenario

想象你在设计 Yelp 的"附近餐厅"功能,或者 Facebook 的"附近朋友"。用户打开 App,瞬间看到 5km 范围内的所有餐厅——背后是什么魔法?

Imagine you're building Yelp's "nearby restaurants" feature or Facebook's "Nearby Friends." The user opens the app and instantly sees all restaurants within 5km. What's the magic behind it?


架构图 / Architecture

Client (Mobile) │ ▼ API Gateway │ ┌────┴────┐ │ Location │ │ Service │ └────┬────┘ │ Query: (lat, lng, radius) │ ┌────▼──────────────────────────┐ │ Geo Index Layer │ │ │ │ ┌──────────┐ ┌───────────┐ │ │ │ Geohash │ │ Quadtree │ │ │ │ Index │ │ (memory) │ │ │ └────┬─────┘ └─────┬─────┘ │ │ └──────┬────────┘ │ │ Redis / PostGIS │ └────────────────────────────────┘ │ ┌────▼────┐ │ Place │ ← metadata (name, rating, hours) │ DB │ │(Postgres)│ └──────────┘ [Nearby Friends variant] User Location → Write path: Client → Location Service → Redis GeoSet (GEOADD) Read path: Client → Location Service → GEORADIUS → User IDs → Profile Service

核心算法 / Core Algorithms

方案 1:Geohash(静态 POI,如 Yelp)

  • 将地球表面编码成层级网格字符串:9q8yy → 9q8yy4 → 9q8yy4j
  • 精度 6 = ~1.2km 格子;精度 7 = ~150m
  • 查询:取当前 geohash + 8 个邻格,IN 查询
  • 优点:可存 DB/Redis,水平扩展容易
  • 坑:边界问题!两个相邻点可能 geohash 完全不同
# Using geohash2 library
import geohash2

def nearby_places(lat, lng, radius_km, precision=6):
    center = geohash2.encode(lat, lng, precision)
    neighbors = geohash2.neighbors(center)  # 8 neighbors
    search_cells = [center] + neighbors
    
    # Query DB: SELECT * FROM places WHERE geohash LIKE ANY(search_cells)
    return search_cells

方案 2:Redis GEO(实时位置,如 Nearby Friends)

# Write: user updates location
GEOADD user_locations 116.3974 39.9093 "user:1234"

# Read: find users within 5km
GEORADIUS user_locations 116.3974 39.9093 5 km WITHCOORD COUNT 100

Redis 底层用 52-bit Geohash 存储,O(N+log(M)) 查询复杂度。

方案 3:Quadtree(高密度区域)

  • 递归四分空间,叶节点存 POI 列表
  • 适合密度不均匀(城区 vs 郊区)
  • 通常 in-memory,需要 periodic rebuild

关键权衡 / Key Tradeoffs

维度Geohash + DBRedis GEORADIUSQuadtree
适合场景静态 POI实时位置复杂多边形
写频率低高(每隔 30s 更新)低
精度控制通过精度位数半径参数递归深度
扩展性水平分片Redis Cluster难分片

别踩这个坑 / Common Mistakes

❌ 直接用经纬度算距离:sqrt((lat1-lat2)² + (lng1-lng2)²) — 经纬度不是欧氏空间,赤道 1° ≠ 极地 1°

✅ 用 Haversine 公式 或数据库内置 ST_Distance

❌ 不考虑边界情况:geohash 精度 6 的格子,用户在边缘可能漏掉 50m 外的餐厅

✅ 查询中心格子 + 8 个邻格

❌ Nearby Friends 每次全量查询所有用户

✅ 只查询 active users(最近 5min 有位置更新的)+ Redis TTL 自动清理离线用户

❌ 实时位置写入过于频繁

✅ 客户端:移动超过 50m 才上报;后端:写 Redis 而非 DB(DB 异步存历史轨迹)


📚 References

🧒 ELI5

把城市地图分成很多个小格子,给每个格子取一个名字(geohash)。找附近餐厅就是:先找你所在的格子和旁边 8 个格子,然后在这 9 个格子里找餐厅——比扫描整张地图快多了!

Imagine dividing a city map into little squares, each with a name (geohash). Finding nearby restaurants means: look in your square and the 8 squares around it. Much faster than checking the whole map!

💻 算法 / Algorithms — Day 48

#543 Diameter of Binary Tree (Easy) — Trees

2026-06-02 | Expert Phase


🧩 树遍历模式 (3/15) — 延续上一次的模版

接续第 1 题(Invert Binary Tree)和第 2 题(Maximum Depth),今天的 Diameter 是模版的第一个"变奏"——DFS 返回值不再是节点值,而是路径长度,但核心骨架完全相同。

Building on Invert Binary Tree (Day 1 of block) and Maximum Depth (Day 2), today's Diameter is the first "variation" — the DFS return value is no longer the node value but a path length. The skeleton is identical.


题目 / Problem

🔗 LeetCode #543 🟢 Easy

📹 NeetCode Video

给定一棵二叉树的根节点,返回这棵树的直径(任意两节点之间最长路径的边数)。路径不一定经过根节点。

Given the root of a binary tree, return the length of the diameter — the longest path between any two nodes (measured in edges). The path may or may not pass through the root.


🌍 现实类比 / Real-World Analogy

想象一个公司的汇报链(树形结构)。直径 = 公司里距离最远的两名员工之间需要经过多少层级。可能路径是:前端工程师 → 前端 Lead → CTO → 后端 Lead → 数据库工程师。
*Think of a company org chart. Diameter = the maximum number of levels between any two employees. The longest path might go: Frontend Dev → Frontend Lead → CTO → Backend Lead → DB Engineer.*

💡 映射到模版 / Mapping to the Template

# General Tree DFS Template:
def dfs(node):
    if not node: return BASE_CASE
    left = dfs(node.left)
    right = dfs(node.right)
    return COMBINE(node.val, left, right)

对于 Diameter 问题:

  • BASE_CASE = 0(空节点贡献 0 条边)
  • dfs(node) 返回:从当前节点往下最多能延伸多少条边(= depth)
  • COMBINE:当前节点的直径候选 = left + right,用 nonlocal 变量 res 收集全局最大值
  • 最终 return max(left, right) + 1(向父节点报告深度)

关键洞察 / Key Insight:dfs 的返回值(深度)和我们要求的答案(直径)是不同概念!用一个外部变量 res 在每个节点"路过时"更新最大直径。


Python 解法 / Python Solution

from typing import Optional

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def diameterOfBinaryTree(root: Optional[TreeNode]) -> int:
    res = 0  # Track the global maximum diameter
    
    def dfs(node) -> int:
        nonlocal res
        if not node:
            return 0          # Base case: empty node has depth 0
        
        left = dfs(node.left)   # Max depth going left
        right = dfs(node.right) # Max depth going right
        
        # At this node, the diameter candidate = left + right edges
        res = max(res, left + right)
        
        # Return depth (for parent's calculation)
        return 1 + max(left, right)
    
    dfs(root)
    return res

执行追踪 / Trace

Tree: 1 / \ 2 3 / \ 4 5 dfs(4) → return 1 dfs(5) → return 1 dfs(2): left=1, right=1 → res = max(0, 1+1) = 2, return 2 dfs(3) → return 1 dfs(1): left=2, right=1 → res = max(2, 2+1) = 3, return 3 Answer: 3 (path: 4 → 2 → 1 → 3)

复杂度 / Complexity

  • Time: O(n) — visit every node once
  • Space: O(h) — recursion stack, h = tree height

举一反三 / Pattern Connections

同一 Trees 模版块中的变体规律:

问题dfs 返回值全局变量返回语义
#104 Max Depth无需无深度
#543 Diameter深度res(直径)深度
#110 Balanced Tree (下一题)深度/-1无深度或-1标记失衡
#124 Max Path Sum (Hard)单侧最大和res(路径和)单侧最大和

规律:当答案是"跨越某节点的左右子树"时,用 nonlocal 变量收集;返回值只向父汇报单侧信息。


📝 Quiz

{"question":"In diameterOfBinaryTree, what does the dfs function RETURN vs what goes into 'res'?","options":["Both return the diameter","dfs returns depth; res tracks max(left+right)","dfs returns diameter; res tracks depth","dfs returns node count; res tracks edge count"],"correct_index":1}

📚 References

🧒 ELI5

树的直径就是树里最长的一条路。聪明的做法是:每到一个节点,就看左边最深有多深、右边最深有多深,两个加起来就是经过这个节点的最长路。记下所有节点的"最长路"里面最大的那个。

The diameter is the longest path in the tree. The trick: at each node, check how deep it goes left and right, add them together (that's the path through this node), and track the maximum across all nodes.

🗣️ 软技能 / Soft Skills — Day 47

"Tell me about a time you had to balance shipping fast vs. doing it right"

*2026-06-02 | Expert Phase | Category: Decision Making*

为什么面试官问这个 / Why This Question

这是 Senior/Staff 工程师面试的高频题。面试官想知道:你是否理解技术债务的本质是时间借贷,以及你如何在商业压力和工程质量之间做出有理有据的权衡——而不是无脑选一边。

This is a top question for Senior/Staff interviews. The interviewer wants to know: do you understand that tech debt is essentially borrowing time from your future self, and can you make a reasoned tradeoff between business pressure and engineering quality — rather than blindly choosing one side.


STAR 结构拆解 / STAR Breakdown

Situation — 设置张力

描述一个有真实压力的场景:产品 deadline、竞争对手、客户承诺。

  • ✅ "季度末发布,产品已承诺 demo 给客户"
  • ✅ "竞争对手刚上线类似功能,CEO 希望一周内跟上"
  • ❌ 避免"我们有一个功能要做" — 太平淡,没有张力

Task — 你的角色和决策权

明确说明为什么是你来做这个决定。

  • "我是负责这个模块的 Tech Lead"
  • "PM 来找我,希望我评估风险"

Action — 这是核心!

这部分需要展示结构化思考,不是感性选择:

框架 / Framework: Risk-Weighted Decision

1. 量化风险 - 如果"快"上线:有哪些具体技术风险?发生概率?影响范围? - 例:没有限流 → 流量高峰宕机 (P30 likelihood, P1 impact) 2. 量化收益 - 晚一周上线的业务损失?(客户流失?竞争劣势?) 3. 找折中方案(往往存在!) - 先上线核心路径(happy path)+ 降级策略 - 做"足够好"的方案,同时立即创建 tech debt ticket - 设置 kill switch / feature flag 以便快速回滚 4. 对齐利益相关方 - 明确告知 PM/stakeholder:我们在借什么债,还债计划是什么

Result — 双维度结果

不只说"成功上线",要说明:

  • 业务结果:准时交付,满足了什么
  • 工程结果:后续如何还了技术债

❌ Bad vs ✅ Good Answers

❌ Bad:

"我们有时间压力,所以我选择了快速上线,但后来有一些 bug,我们就修了。"

问题:没有框架,没有权衡,没有主动性,结果模糊。

✅ Good:

"Q3 末,我们承诺给大客户演示一个实时协作功能。距演示只有 9 天,但完整实现需要 3 周。
我做了一个风险矩阵:完整方案包括 OT(Operational Transformation)算法处理冲突,但 demo 场景是 2 人同时编辑。我评估了最高并发冲突率低于 5%,且 demo 环境可控。
我的决策:用 last-write-wins 临时替代 OT,加 feature flag 隔离,同时创建 Sprint+2 的 tech debt ticket,并在内部 runbook 里标注这个模块不能在正式 GA 前开放。
我主动向 PM 和 Eng Manager 说明了这个 tradeoff,他们知情并同意。Demo 顺利,客户签约。3 周后我们完整实现了 OT,并做了 A/B 测试验证。"

Senior / Staff 加分项

  • 主动管理 stakeholder 预期:别等他们来问,主动说明"我们在借技术债"
  • 有还债计划:立即创建 ticket,设置 Sprint N+X 的时间盒
  • 量化风险:说 "P30/P1" 而不是 "can happen"
  • 知道什么时候必须说"不":如果风险是数据丢失、安全漏洞、合规问题——这条线不能过

Key Takeaways / 关键要点

  1. 技术债 = 时间借贷,要利滚利——短期可以,但要知情、要有计划
  2. 找折中方案:快 vs 好 往往不是二选一,feature flag / degraded mode 是你的朋友
  3. 主动沟通:让团队和 stakeholder 知道你在做什么权衡
  4. 关键底线:安全、数据完整性、监管合规 — 这些不能为了速度牺牲

📚 References

🧒 ELI5

就像用信用卡买东西——你可以先用,但要知道要还,还要付利息。"快速上线"就是刷卡,你得知道刷了多少、什么时候还、利息是多少。不能当作没有账单。

It's like using a credit card — you can buy now, but you need to know what you owe and have a plan to pay it back. "Ship fast" is swiping the card. Just don't pretend the bill doesn't exist.

🤖 AI — Day 57

AI 新闻速递 / AI News Roundup

2026-06-02 | Expert Phase


本周 AI 大事 / This Week in AI

1. 🧠 Google 宣布 Gemini Spark:24/7 个人 AI 代理

Google 在 2026 年 I/O 系列活动中宣布了 Gemini Spark,定位为一个 24/7 运行的个人 AI 代理,能主动提醒日程、跨应用完成任务,并与 Google Stitch(AI 辅助设计部署工具)协同工作。据报道,这是 Google 向"主动 AI"(agentic AI)战略全面转型的标志性产品。

Source: buildingcreativemachines.com

为什么重要 / Why it matters: 从"问答式 AI"到"主动代理"是 AI 应用的下一个范式。Gemini Spark 与 OpenAI 合并 ChatGPT + Atlas + Codex 的"超级应用"战略直接竞争——两家都在押注 AI 成为你的"数字操作系统"。


2. 🤖 Anthropic 发布 Claude Opus 4.8

Anthropic 于 2026 年 6 月初发布 Claude Opus 4.8,据报道新增了"effort controls"(控制推理深度)和"dynamic workflows"功能,面向大型 agentic 任务的场景进行了优化。

Source: aidrivensucess.substack.com

技术视角 / Technical Take: "Effort controls" 本质上是让用户/程序显式控制模型的 chain-of-thought 深度——类比于 GPU 的"功耗模式"。这对需要兼顾成本与质量的 agentic pipeline 极有价值。


3. ⚖️ Connecticut 通过 AI 责任透明法案

美国康涅狄格州通过了《人工智能责任与透明度法案》(AI Responsibility and Transparency Act),对聊天机器人、合成媒体等多类 AI 应用设定了针对性要求。与此同时,科罗拉多州则修订缩减了其 2024 年 AI 法案。

Source: wiley.law

工程师视角 / Engineer's Take: 状态级监管分裂正在加速——美国 50 个州可能最终有 50 套 AI 合规要求。对于构建 AI 产品的工程团队,合规层(compliance layer)设计将成为架构考量,而不只是法务问题。


4. 🔬 DARPA + NSF 联合启动 AI Forge 项目

美国 DARPA 和 NSF 联合推出 AI Forge 计划,聚焦 AI 可解释性与控制能力的突破,服务国家安全应用。

Source: darpa.mil

背景 / Context: 可解释性(Interpretability)一直是 AI 安全的核心难题。DARPA 的参与意味着政府层面开始认真投资"理解黑盒"——这不只是学术问题,而是影响 AI 在高风险决策中部署的关键。


🔭 趋势观察 / Trend to Watch

据 Galorath 2026 行业报告:79% 的组织增加了 AI 投入,但只有 1/4 有明确的 AI 政策。这个"治理赤字"将是未来 12 个月的巨大风险。工程师需要推动团队建立 AI 使用规范,而不是等着法规来约束。

Source: eqs-news.com


📚 References

🧒 ELI5

本周 AI 圈:Google 出了一个会主动帮你做事的 AI 助手,Anthropic 升级了 Claude,美国一个州通过了管 AI 的法律,政府还拨款研究怎么让 AI "说清楚自己在想什么"。AI 行业正从"炫技"走向"负责任落地"。

This week: Google launched an always-on AI agent, Anthropic upgraded Claude, a US state passed AI rules, and the government funded research into AI explainability. The AI industry is shifting from "look what it can do" to "let's do this responsibly."