关于 system-design
用于组织系统设计会话的 skill,适合设计、讲解或重新设计系统。它按统一阶段推进,从需求到深入分析,并要求基于证据说明结论、标记未知信息。
主要功能
- 01分阶段的系统设计框架
- 02支持新建、讲解与重设计
- 03标注证据与未知信息
- 04深入分析方案权衡
- 05可视化呈现并迭代修订
适用场景
- 01根据需求起草系统设计
- 02结合代码和文档讲解系统
- 03比较某项设计决策的方案
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yahyabedirhan/ skills --skill system-design安装后在 Claude Code 中输入/system-design确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api-design.mdcaching.mdcap-theorem.mdcommon-patterns.mdconsistent-hashing.mddata-modeling.mddatabase-indexing.mdnetworking-essentials.mdnumbers-to-know.mdsharding.md详细介绍
系统设计
在每次会话中都遵循交付框架,无论是新设计、讲解设计还是重新设计,这样用户总能在相同的位置找到相同的内容。由用户决定会话的目的;框架决定答案的布局。除非用户要求将设计写到某处,否则请在对话中保留设计;如果用户提出要求,则用各阶段作为章节。
如果要在单个服务的代码库中,围绕其模块、类和文件夹进行设计,请改用 /low-level-design。
如果要设计命令行界面的命令、标志、输出和帮助信息,请使用 /cli-design。
步骤
- 阅读会话的目的,结合请求及其上下文理解,并在开始前用一句话重述,这样即使理解有误,也只需花一轮回复来纠正。
- 在没有说明的项目中调用: 解释该项目当前的设计。
- 目的不明确时: 询问用户想用这个设计做什么、系统是否已经存在,以及是否只想了解设计。
- 按照交付框架逐阶段推进;每个阶段涉及某个概念时,都要先阅读该概念的参考资料。
- 展示每个阶段,并与用户一起修改,直到用户满意。
目的决定阶段的推进方式。以下是常见情况,并非全部;一次会话可以混合多种情况,也可以从一种情况切换到另一种情况。
- 设计新系统: 完成所有阶段,写出完整的初稿。
- 讲解现有系统: 按系统当前的实际情况逐阶段梳理,不作修改。
- 根据证据构建每个阶段。先从现有设计文档入手,并对照代码进行核实。在代码中,查看路由和处理程序、任务和消费者、架构和迁移、连接和部署配置,以及对其他服务的调用。用户的描述也属于证据。为每项论断注明其依据所在的文件、章节或消息。
- 将从代码中读取出的要求标记为推断。对于证据无法显示的内容,例如流量、数据规模、事故或决策原因,标记为未知,并向用户询问,不要自行补充,以免猜测被当作事实。
- 用对设计所依赖的概念的讲解代替深入分析,例如缓存、分片或一致性选择:说明概念是什么、为何与当前系统有关,以及设计选择带来的权衡。
- 将弱点记录为观察结果,而非提案,因为本次会话的目的是讲解系统而非修改系统。回答后续问题时,沿着设计梳理请求或故障的处理过程。
- 重新设计现有系统: 先讲解现有系统,并确认用户认可该讲解。然后按相同阶段进行重新设计,除非问题出在某个现有组件中,否则保留该组件。将新设计的权衡作为选项呈现,并以修改前/修改后的
diff展示每个变更阶段。 - **决定一件事,**例如“这里选 Postgres 还是 DynamoDB?”:将其作为一次深入分析来回答,指出涉及设计中的哪些部分,以及背后的需求。
交付框架
Requirements → Core entities → API → [Data flow] → High-level design → Deep dives
各阶段按此顺序排列,是因为后一个阶段建立在前一个阶段之上:API 满足需求,高层设计支撑 API,而深入分析则确保高层设计满足非功能性需求。如果后续阶段暴露出缺口,请返回较早的阶段。
需求
功能需求是核心功能,用“用户应该能够……”这样的语句描述。一个真实系统有数百项功能;将范围内的清单控制在约 3 项,因为其中每一项都是设计必须满足的要求。
非功能需求是系统必须具备的特性,用“系统应该……”这样的语句描述,并针对当前系统逐项说明,尽可能量化:“搜索结果在 500 ms 内返回”,而不是“延迟低”。从以下清单中挑出对本设计约束最大的 3~5 项:
- 网络分区下的一致性或可用性,按功能决定(cap-theorem.md)。先确定这一点,因为它决定了哪些存储方案适用。
- 可扩展性:突发流量、峰值事件,以及读写比例,这些决定了哪一侧必须扩展。
- 延迟,尤其是需要实际计算的请求,例如搜索和信息流。
- 持久性:数据丢失的后果有多严重,例如社交帖子与银行转账的区别。
- 安全性:数据保护和访问控制。
- 容错性:冗余、故障转移和恢复。
- 合规性:法律和监管限制。
- 环境:设备、内存或带宽限制,例如网络状况较差时的移动客户端。
**估算:**只有当数字会影响决策时,才计算用户数、QPS 或存储量,例如判断 Top-K 计数器能否放进一个内存堆,还是必须分片。在设计中,选择取决于估算结果的地方进行计算(numbers-to-know.md)。
将需求简要列出:功能需求、非功能需求,以及说明原因的范围外事项。
核心实体
API 交换、存储系统持久化的对象。先列出简明的草案并使用清晰的名称,例如 Twitter 的 User、Tweet 和 Follow。确认参与者是谁、彼此是否重叠,以及每项功能需求需要哪些资源。字段留待高层设计阶段再定,届时请求会表明哪些字段重要。
API
与系统用户之间的契约,通常每项功能需求对应一个端点。将核心实体作为资源。默认使用 REST;对于数据需求各异的不同客户端,使用 GraphQL;对于内部且对性能要求高的调用,使用 RPC。在核心 API 之后,再设计 WebSockets 或 SSE 等实时功能。当前用户应从身份验证令牌中获取,绝不能从请求正文中获取(api-design.md)。
用简明的列表或表格展示实体和端点。
数据流
对于数据处理系统,用编号步骤列出从输入到输出的流程。对于网络爬虫:抓取种子 URL、解析 HTML、提取 URL、存储数据,然后重复。
高层设计
列出客户端、负载均衡器、服务、数据库、缓存和队列等组件,以及它们如何交互;按端点逐一说明,直至设计满足整个 API。只纳入功能需求所需的内容。
- 针对每项请求,说明数据如何流经系统,从 API 调用到响应,以及状态在哪里发生变化。
- 请求到达存储系统时,在旁边写出重要字段:设计所依赖的字段,而非显而易见的字段(data-modeling.md、database-indexing.md)。
- 如果某部分看起来需要缓存或队列,将其记在深度分析部分,然后继续。
用组件流展示设计(client -> LB -> API -> Postgres);用编号步骤说明请求或故障如何经过各个组件,以及状态如何变化;用表格列出各存储系统保存的内容、写入方及其键或分片键。
深入分析
满足每项非功能性需求,消除瓶颈和单点故障,并处理边缘情况。在这里添加缓存、队列和其他复杂性,而不是更早添加,因为过早引入这些设计,往往会导致系统无法完整、正常地运行。明确列出每个问题;如果问题与规模有关,则用数字说明;然后列出可选方案及其权衡。Twitter 的规模要求横向扩展、缓存和分片;其信息流的速度要求在读时扇出和在写时扇出之间做出选择。自行选择深入分析的主题,并让用户引导讨论转向他们关心的方面。
“先用默认方案”中的每项默认方案都附有参考资料,说明何时应换用其他方案:数据存储见 data-modeling.md,API 见 api-design.md,传输和实时通信见 networking-essentials.md,缓存见 caching.md,规模见 sharding.md 和 numbers-to-know.md,异步工作见 common-patterns.md。
并列展示各个方案,说明每种方案的收益和成本;如果要重新设计或修订,则用流程或变更列表的前后对照 diff 展示。
先用默认方案
每项选择都从默认方案开始,因为系统设计中最常见的问题,就是过早引入复杂性。只有在有明确需求时才换用其他方案;如果问题与规模有关,则用数字说明。
- 数据存储: PostgreSQL。
- API: REST。
- 传输和实时通信: TCP 和 HTTP 轮询。
- 缓存: 不使用缓存,之后再采用 Redis 缓存旁路模式。
- 规模: 一台更大的数据库并搭配副本,之后再进行哈希分片。
- 异步工作: 不使用异步;工作保持同步。
- 典型的过度设计: 每秒 5k 次写入就引入队列,100 GB 就进行分片,本可用轮询却采用 WebSocket,在带索引的查询前加缓存。
如果设计采用了特定技术,例如 Kafka、DynamoDB 或 Elasticsearch,请先查阅其文档,再依赖其具体特性:其限制、保证以及故障方式。
与用户协作
加载 /show-me,并以可视化方式呈现每个阶段;只有在解释选择理由时才使用散文。
- 保留一份当前设计,并在此基础上进行修订。
- 用户反馈改变某一部分时,将变更同步到所有受影响的部分。
- 每次修订都先说明变更内容和原因,并以前后对照的方式展示发生变化的部分,包括仅因其他变更而随之改变的部分。
- 用户已确认的内容保持不变,除非用户重新提出讨论。
只询问代码、现有设计文档和用户先前的回答无法确定的问题;一次只问一个问题。其余事项自行决定,并说明你的决定。
参考资料
概念与技术
每篇都介绍一个概念:它是什么、为何重要、有哪些权衡,以及何时应选择哪种技术。
| 参考资料 | 涵盖内容 |
|---|---|
| networking-essentials.md | TCP 和 UDP、HTTP、REST、gRPC、SSE、WebSockets、WebRTC、负载均衡、区域、故障处理 |
| api-design.md | REST、GraphQL、RPC、资源、分页、幂等性、版本控制、身份验证 |
| data-modeling.md | 数据库模型、架构设计、规范化 |
| database-indexing.md | B-tree、LSM、哈希、地理空间索引和倒排索引、复合索引 |
| caching.md | 缓存位置、缓存模式、淘汰、故障模式 |
| sharding.md | 分片键、分布策略、热点、跨分片操作 |
| consistent-hashing.md | 哈希环、虚拟节点、热点键 |
| cap-theorem.md | 一致性与可用性的取舍、一致性级别 |
| numbers-to-know.md | 硬件和组件的容量、可避免过度设计的数值 |
| common-patterns.md | 实时更新、长时间运行的任务、竞争、读写扩展、大型 Blob、多步骤流程、邻近性 |
来源:Hello Interview,Delivery Framework。