mirror of
https://github.com/codestable/CodeStable.git
synced 2026-09-19 09:03:09 +08:00
feature: 构建 cs-how-codedesign 架构设计指导原则
参照 codebase-design 的深模块思想,按 cs-how-* 体例独立重写。 同步更新 cs 导览中 codedesign(已落地)/onboard(规划中) 状态。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
---
|
||||
name: cs-how-codedesign
|
||||
description: 架构设计的指导原则——把模块设计"深":大量行为藏在小接口后面,放在干净的接缝上,能通过接口测试。触发:设计或重塑一个模块的接口、决定接缝放哪、代码读着累/难测/AI 难导航、实现 feature 时需要抽取下沉某些模块。这是随时参照的指导原则,不是一个要单独运行的步骤。
|
||||
---
|
||||
|
||||
# cs-how-codedesign
|
||||
|
||||
好的结构,是让调用方用最少的认知换到最多的能力。设计模块时只有一个方向:往深里做。
|
||||
|
||||
## 背景
|
||||
|
||||
代码会随演化堆积,最常见的烂法有两种。一种是模块太**浅**——接口几乎和实现一样复杂,调用方要搞懂的东西和自己重写一遍差不多,这层封装没省下任何认知。另一种是一个概念散在十几个小模块里,读懂一件事要在文件之间反复横跳。浅和散都在增加认知负荷,也让代码难测、AI 难以导航。
|
||||
|
||||
LITE 里没有单独的"重构"——模块的抽取下沉是实现某个 feature 时顺带做的过程。但顺带做也得有一把尺子,否则越改越散。这把尺子就是"**深**":把大量行为藏到一个小接口后面。下面先把几个词定准,再讲怎么用它判断。
|
||||
|
||||
## 原则
|
||||
|
||||
### 先把几个词定准
|
||||
|
||||
统一的叫法是这套语言能用的前提,别换成"组件/服务/API/边界"这些含糊的词。
|
||||
|
||||
- **模块(module)**——任何"有接口、有实现"的东西。刻意不限规模:一个函数、一个类、一个包、一段跨层的切片都算。
|
||||
- **接口(interface)**——调用方为了正确使用它必须知道的**全部**:类型签名,还有不变量、调用顺序、错误模式、必需的配置、性能特征。不只是类型层面那点表面。
|
||||
- **深(depth)**——接口上的杠杆:调用方每学一点接口,能换回多少行为。大量行为藏在小接口后面 = 深;接口几乎和实现一样复杂 = 浅。
|
||||
- **接缝(seam)**——能改变行为、却不必在那个地方改代码的位置,也就是接口所在的地方。接缝放哪,是和"接缝后面放什么"分开的另一个设计决定。
|
||||
|
||||
### 往深里做:小接口,厚实现
|
||||
|
||||
- 设计接口时反复问三件事:**能不能少几个方法?能不能简化参数?能不能把更多复杂度藏进去?**
|
||||
- **删除测试**:假想把这个模块删掉。如果复杂度跟着凭空消失,它只是个穿透层,白占一层;如果复杂度在 N 个调用方那里重新冒出来,它就在挣自己的饭钱,深得有理。拿不准一个模块该不该存在时,做这个测试。
|
||||
- **深是接口的属性,不是实现的属性。** 一个深模块内部照样可以由小的、可替换的部件组成——只要这些部件不出现在接口上。模块可以有只供自己实现和自己测试用的**内部接缝**,不必把它捅到对外接口上。
|
||||
|
||||
### 接缝放哪、叫什么,先于往里塞什么
|
||||
|
||||
- **命名和放置先于深度。** 设计一个新能力时,先决定它在现有结构里**属于哪**、用现有词汇**叫什么**,再考虑接口。默认的失败是图方便丢进最近的文件、起一个新同义词——这会长出一份平行实现,把命名空间劈成两半,搜索从此失效。先搜一遍同义词,能扩展那个本该拥有它的模块就扩展,实在没有合适的才新开一个。
|
||||
- **一个 adapter 是假想接缝,两个才是真接缝。** 除非真有东西在接缝两侧变化(通常是"生产一套、测试一套"),否则别急着引入接缝——只有单个实现的接缝只是凭空绕了一层。
|
||||
|
||||
### 接口就是测试面
|
||||
|
||||
- 调用方和测试穿过的是**同一道接缝**。如果你发现想测到接口"背后"去,多半说明这个模块的形状不对。
|
||||
- 让接口天然好测:**依赖靠注入,不在内部自己 new**;**返回结果,不制造副作用**;**表面积小**——方法少、参数少,测试的搭建就简单。
|
||||
- 接缝后面怎么测,由依赖的性质决定:纯计算就直接合并、通过新接口测;是自己的远程服务,就在接缝定义一个 port,生产用真实 adapter、测试用内存 adapter;是不可控的第三方(支付、短信等),就把它当注入的 port,测试给一个 mock。
|
||||
- **替换,别叠加。** 模块做深后,原先架在那些浅模块上的单测就成了废物,删掉;在新接口上重写测试,断言**可观察的结果**而不是内部状态——这样的测试能扛住内部重构,只在行为真变了时才需要改。
|
||||
|
||||
### 第一版接口很难是最好的
|
||||
|
||||
重要的接口值得设计两遍。从几个根本不同的角度各设计一版——比如"接口压到最小、每个入口杠杆最大"、"最大灵活、支持多种用法"、"为最常见的调用方优化、让默认情况无脑可用"——再按深度、locality(改动是否集中在一处)、接缝位置去比。第一个冒出来的想法,通常不是最好的那个。
|
||||
|
||||
## 应用场景
|
||||
|
||||
- **实现一个 feature,发现需要抽取或下沉某些模块时**——用"深"这把尺子决定新接口长什么样、接缝放在哪。这是 LITE 里架构改进发生的正常时机。
|
||||
- **一段代码读着累、改一处要牵动很多地方、或者难测**——多半是模块太浅或概念散落,回到上面的原则上找症结。
|
||||
- **设计一个新模块的接口时**——先定它属于哪、叫什么,再往深里做。
|
||||
|
||||
不适用:
|
||||
|
||||
- **不是主动审计工具。** LITE 没有"专门扫一遍代码找问题"这一步——架构改进长在实现 feature 的过程里,不单独立项。
|
||||
- **不规定技术栈、不写具体代码。** 这里只给判断架构深浅的尺子,具体怎么写是各处自己的事。
|
||||
- **不手动触发。** 它是设计代码时随时可以拿来对照的原则,不是一个要"运行"的流程。
|
||||
+2
-2
@@ -40,7 +40,7 @@ LITE 要消除两件事:
|
||||
|
||||
| 技能 | 何时用 | 状态 |
|
||||
|---|---|---|
|
||||
| cs-onboard | 用 cs 之前,先搭好 cs 的基础结构 | 已落地 |
|
||||
| cs-onboard | 用 cs 之前,先搭好 cs 的基础结构 | 规划中 |
|
||||
| cs-talk | 有想法没想清、先聊聊、方向还在摇摆——把真问题、术语、约束聊出来 | 已落地 |
|
||||
| cs-plan | 把讨论清楚的需求落到当前系统:拆成 epic 还是 task | 规划中 |
|
||||
| cs-do | 计划布置好后,用户明确下令开始实现 | 规划中 |
|
||||
@@ -52,7 +52,7 @@ LITE 要消除两件事:
|
||||
|
||||
| 技能 | 讲什么 | 状态 |
|
||||
|---|---|---|
|
||||
| cs-how-codedesign | 架构设计的指导原则 | 规划中 |
|
||||
| cs-how-codedesign | 架构设计的指导原则 | 已落地 |
|
||||
| cs-how-debug | 如何找出问题(debug) | 规划中 |
|
||||
| cs-how-evolve | 如何找出现实中的主要矛盾、解决、沉淀积累,下次更快更强 | 规划中 |
|
||||
| cs-how-great-skills | 什么是好的技能 | 已落地 |
|
||||
|
||||
Reference in New Issue
Block a user