|
| 1 | +# xb 设计原则 |
| 2 | + |
| 3 | +## 🎯 核心原则 |
| 4 | + |
| 5 | +### **"Don't add concepts to solve problems"** |
| 6 | + |
| 7 | +**每个具体的命名都是一个概念。** 概念越多,认知负担越重,学习成本越高。 |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +## 📜 黄金法则 |
| 12 | + |
| 13 | +### 法则 1:概念守恒定律 |
| 14 | + |
| 15 | +``` |
| 16 | +框架价值 = 功能 / 概念数量 |
| 17 | +
|
| 18 | +理想:功能增加,概念不增加 |
| 19 | +现实:功能不变,概念减少 ✅ |
| 20 | +``` |
| 21 | + |
| 22 | +**xb v1.2.0 验证**: |
| 23 | +- 删除 8 个概念(预设函数、专用方法) |
| 24 | +- 功能不减反增(智能格式检测) |
| 25 | +- 价值提升 = ∞ |
| 26 | + |
| 27 | +--- |
| 28 | + |
| 29 | +### 法则 2:命名成本定律 |
| 30 | + |
| 31 | +``` |
| 32 | +每个公开 API 的成本 = |
| 33 | + 学习成本 + |
| 34 | + 记忆成本 + |
| 35 | + 决策成本 + |
| 36 | + 维护成本(永久) |
| 37 | +``` |
| 38 | + |
| 39 | +**示例**: |
| 40 | + |
| 41 | +| API | 学习 | 记忆 | 决策 | 维护 | 总成本 | |
| 42 | +|-----|------|------|------|------|--------| |
| 43 | +| `NewQdrantCustom()` | 低 | 低 | 无 | 低 | ⭐ 低 | |
| 44 | +| `QdrantHighPrecision()` | 中 | 中 | 高 | 高 | ❌ 高 | |
| 45 | + |
| 46 | +--- |
| 47 | + |
| 48 | +### 法则 3:API 不可逆定律 |
| 49 | + |
| 50 | +``` |
| 51 | +增加 API:1 小时 |
| 52 | +删除 API:永远不可能(breaking change) |
| 53 | +
|
| 54 | +结论: |
| 55 | +- 每个 API 都是永久承诺 |
| 56 | +- 宁可少加,不能多加 |
| 57 | +- Less is more |
| 58 | +``` |
| 59 | + |
| 60 | +--- |
| 61 | + |
| 62 | +## 🚫 禁止模式(Anti-Patterns) |
| 63 | + |
| 64 | +### ❌ 反模式 1:预设配置函数 |
| 65 | + |
| 66 | +```go |
| 67 | +// ❌ 禁止 |
| 68 | +func QdrantHighPrecision() *QdrantCustom { ... } |
| 69 | +func QdrantHighSpeed() *QdrantCustom { ... } |
| 70 | +func QdrantBalanced() *QdrantCustom { ... } |
| 71 | + |
| 72 | +// ✅ 正确 |
| 73 | +func NewQdrantCustom() *QdrantCustom { ... } // 只有这一个 |
| 74 | + |
| 75 | +// 用户配置 |
| 76 | +custom := NewQdrantCustom() |
| 77 | +custom.DefaultHnswEf = 512 // 手动配置,清晰 |
| 78 | +``` |
| 79 | + |
| 80 | +**为什么禁止?** |
| 81 | +1. 增加概念数量(3 个额外概念) |
| 82 | +2. 用户需要决策(该用哪个?) |
| 83 | +3. 配置不透明(HnswEf=512 是隐藏的) |
| 84 | +4. 永久维护负担 |
| 85 | + |
| 86 | +--- |
| 87 | + |
| 88 | +### ❌ 反模式 2:专用方法 |
| 89 | + |
| 90 | +```go |
| 91 | +// ❌ 禁止 |
| 92 | +func (x *BuilderX) InsertPoint(point interface{}) *BuilderX { ... } |
| 93 | +func (x *BuilderX) InsertPoints(points []interface{}) *BuilderX { ... } |
| 94 | + |
| 95 | +// ✅ 正确 |
| 96 | +func (x *BuilderX) Insert(f func(ib *InsertBuilder)) *BuilderX { ... } |
| 97 | +// Custom 内部智能处理不同格式 |
| 98 | +``` |
| 99 | + |
| 100 | +**为什么禁止?** |
| 101 | +1. 破坏 API 统一性 |
| 102 | +2. 用户困惑(Insert vs InsertPoint?) |
| 103 | +3. 维护两套逻辑 |
| 104 | + |
| 105 | +--- |
| 106 | + |
| 107 | +### ❌ 反模式 3:便捷包装 |
| 108 | + |
| 109 | +```go |
| 110 | +// ❌ 禁止(除非极其常用) |
| 111 | +func (x *BuilderX) Delete() *BuilderX { ... } |
| 112 | + |
| 113 | +// ✅ 正确 |
| 114 | +// 在方法内部处理 |
| 115 | +func (built *Built) JsonOfDelete() (string, error) { |
| 116 | + built.Delete = true // 自动设置 |
| 117 | + ... |
| 118 | +} |
| 119 | +``` |
| 120 | + |
| 121 | +**为什么禁止?** |
| 122 | +1. 增加 API 表面积 |
| 123 | +2. 不够必要(调用 JsonOfDelete 已经明确意图) |
| 124 | + |
| 125 | +--- |
| 126 | + |
| 127 | +## ✅ 推荐模式(Best Practices) |
| 128 | + |
| 129 | +### ✅ 模式 1:单一构造函数 + 公开字段 |
| 130 | + |
| 131 | +```go |
| 132 | +// ✅ 只有一个构造函数 |
| 133 | +func NewQdrantCustom() *QdrantCustom { ... } |
| 134 | + |
| 135 | +// ✅ 公开字段供配置 |
| 136 | +type QdrantCustom struct { |
| 137 | + DefaultHnswEf int // 公开 |
| 138 | + DefaultScoreThreshold float32 // 公开 |
| 139 | + DefaultWithVector bool // 公开 |
| 140 | +} |
| 141 | + |
| 142 | +// ✅ 用户配置 |
| 143 | +custom := NewQdrantCustom() |
| 144 | +custom.DefaultHnswEf = 512 |
| 145 | +``` |
| 146 | + |
| 147 | +**优势**: |
| 148 | +- 概念数:1 |
| 149 | +- 灵活性:无限 |
| 150 | +- 清晰度:100% |
| 151 | + |
| 152 | +--- |
| 153 | + |
| 154 | +### ✅ 模式 2:在已有 API 上扩展 |
| 155 | + |
| 156 | +```go |
| 157 | +// ✅ 已有的闭包 API |
| 158 | +xb.Of(...).QdrantX(func(qx *QdrantBuilderX) { |
| 159 | + qx.HnswEf(512) // 使用已有的,不新增 |
| 160 | +}) |
| 161 | + |
| 162 | +// ❌ 不要新增 |
| 163 | +xb.Of(...).QdrantHighPrecision() // 新的 API |
| 164 | +``` |
| 165 | + |
| 166 | +--- |
| 167 | + |
| 168 | +### ✅ 模式 3:便捷方法(必须极其常用) |
| 169 | + |
| 170 | +```go |
| 171 | +// ✅ 允许(极其常用) |
| 172 | +func (built *Built) SqlOfUpsert() (string, []interface{}) |
| 173 | + |
| 174 | +// 判断标准: |
| 175 | +// 1. 是否 90% 的 MySQL 用户都需要?(UPSERT:是) |
| 176 | +// 2. 是否无法通过配置实现?(需要专门逻辑:是) |
| 177 | +// 3. 是否会增加认知负担?(SqlOfUpsert 名字清晰:否) |
| 178 | +``` |
| 179 | + |
| 180 | +--- |
| 181 | + |
| 182 | +## 🛡️ 守护机制 |
| 183 | + |
| 184 | +### 1. **代码注释守护** |
| 185 | + |
| 186 | +在构造函数中加入: |
| 187 | +```go |
| 188 | +// ⚠️ 设计原则:只提供这一个构造函数! |
| 189 | +// 参考:xb v1.1.0 的教训(预设函数 → v1.2.0 全部删除) |
| 190 | +``` |
| 191 | + |
| 192 | +--- |
| 193 | + |
| 194 | +### 2. **文档守护** |
| 195 | + |
| 196 | +在 `DESIGN_PRINCIPLES.md` 中明确: |
| 197 | +- 禁止模式 |
| 198 | +- 历史教训 |
| 199 | +- 决策流程 |
| 200 | + |
| 201 | +--- |
| 202 | + |
| 203 | +### 3. **Code Review 守护** |
| 204 | + |
| 205 | +PR Checklist: |
| 206 | +- [ ] 是否增加了新的构造函数?(如果是 → 拒绝) |
| 207 | +- [ ] 是否可以通过字段配置实现?(如果是 → 拒绝) |
| 208 | +- [ ] 是否增加了概念数量?(如果是 → 慎重) |
| 209 | + |
| 210 | +--- |
| 211 | + |
| 212 | +### 4. **AI Review 守护** |
| 213 | + |
| 214 | +当 AI(包括我)提议增加 API 时,自动问: |
| 215 | + |
| 216 | +``` |
| 217 | +🤖 AI: "要不要加 QdrantForRAG()?" |
| 218 | +
|
| 219 | +📋 Review Checklist: |
| 220 | +1. 用户不用这个能实现吗? |
| 221 | + → 能(设置字段) |
| 222 | + |
| 223 | +2. 这会增加概念数量吗? |
| 224 | + → 会(新增 1 个命名) |
| 225 | + |
| 226 | +3. 那为什么要加? |
| 227 | + → ... |
| 228 | + |
| 229 | +结论:❌ 拒绝 |
| 230 | +``` |
| 231 | + |
| 232 | +--- |
| 233 | + |
| 234 | +## 📊 历史教训 |
| 235 | + |
| 236 | +### xb v1.1.0 的错误 |
| 237 | + |
| 238 | +| 添加的概念 | 原因 | 现状 | |
| 239 | +|----------|------|------| |
| 240 | +| `QdrantHighPrecision()` | "方便用户" | v1.2.0 删除 | |
| 241 | +| `QdrantHighSpeed()` | "方便用户" | v1.2.0 删除 | |
| 242 | +| `QdrantBalanced()` | "方便用户" | v1.2.0 删除 | |
| 243 | +| `MySQLWithUpsert()` | "方便用户" | v1.2.0 删除 | |
| 244 | +| `MySQLWithIgnore()` | "方便用户" | v1.2.0 删除 | |
| 245 | +| `InsertPoint()` | "专用 API" | v1.2.0 删除 | |
| 246 | +| `InsertPoints()` | "批量操作" | v1.2.0 删除 | |
| 247 | +| `Delete()` | "统一风格" | v1.2.0 删除 | |
| 248 | + |
| 249 | +**总计删除:8 个概念** |
| 250 | + |
| 251 | +--- |
| 252 | + |
| 253 | +## 🎯 决策流程 |
| 254 | + |
| 255 | +### 当想增加新 API 时 |
| 256 | + |
| 257 | +``` |
| 258 | +问题:用户需要 XXX 功能 |
| 259 | +
|
| 260 | +Step 1: 能否通过现有 API 实现? |
| 261 | +├─ 是 → 停止,不增加 |
| 262 | +└─ 否 → Step 2 |
| 263 | +
|
| 264 | +Step 2: 能否通过字段配置实现? |
| 265 | +├─ 是 → 停止,不增加 |
| 266 | +└─ 否 → Step 3 |
| 267 | +
|
| 268 | +Step 3: 是否 90% 用户都需要? |
| 269 | +├─ 否 → 停止,不增加 |
| 270 | +└─ 是 → Step 4 |
| 271 | +
|
| 272 | +Step 4: 是否会增加概念数量? |
| 273 | +├─ 是 → 重新思考设计 |
| 274 | +└─ 否 → 可以考虑(但要慎重) |
| 275 | +``` |
| 276 | + |
| 277 | +--- |
| 278 | + |
| 279 | +## 💎 成功案例 |
| 280 | + |
| 281 | +### xb v1.2.0 |
| 282 | + |
| 283 | +**问题**:MySQL UPSERT 很常用 |
| 284 | + |
| 285 | +**❌ 错误方案**: |
| 286 | +```go |
| 287 | +MySQLWithUpsert() // 新概念 |
| 288 | +``` |
| 289 | + |
| 290 | +**✅ 正确方案**: |
| 291 | +```go |
| 292 | +built.SqlOfUpsert() // 便捷方法,名字清晰,不增加认知负担 |
| 293 | +``` |
| 294 | + |
| 295 | +--- |
| 296 | + |
| 297 | +### xb Qdrant |
| 298 | + |
| 299 | +**问题**:Qdrant Insert 数据结构不同 |
| 300 | + |
| 301 | +**❌ 错误方案**: |
| 302 | +```go |
| 303 | +InsertPoint(point) // 新 API,破坏统一性 |
| 304 | +``` |
| 305 | + |
| 306 | +**✅ 正确方案**: |
| 307 | +```go |
| 308 | +Insert(func(ib) { ... }) // 统一 API,Custom 内部智能处理 |
| 309 | +``` |
| 310 | + |
| 311 | +--- |
| 312 | + |
| 313 | +## 🌟 愿景 |
| 314 | + |
| 315 | +**让 xb 成为 Go 生态简洁性的标杆** |
| 316 | + |
| 317 | +- ✅ 概念少:新手 5 分钟上手 |
| 318 | +- ✅ 功能强:覆盖 SQL + Vector DB |
| 319 | +- ✅ API 稳定:一次学习,终身受用 |
| 320 | +- ✅ 影响 Go 生态:证明简洁可以很强大 |
| 321 | + |
| 322 | +--- |
| 323 | + |
| 324 | +## 📖 推荐阅读 |
| 325 | + |
| 326 | +- [Go Proverbs](https://go-proverbs.github.io/) |
| 327 | +- [The Zen of Python](https://www.python.org/dev/peps/pep-0020/) |
| 328 | +- [UNIX Philosophy](https://en.wikipedia.org/wiki/Unix_philosophy) |
| 329 | + |
| 330 | +**核心思想相通**: |
| 331 | +> "Do one thing and do it well" |
| 332 | +> "Worse is better" |
| 333 | +> "Less is exponentially more" |
| 334 | +
|
| 335 | +--- |
| 336 | + |
| 337 | +## 🔒 承诺 |
| 338 | + |
| 339 | +**xb 项目承诺**: |
| 340 | + |
| 341 | +1. ✅ 每个数据库只有一个基础构造函数 |
| 342 | +2. ✅ 新 API 必须通过"4 步决策流程" |
| 343 | +3. ✅ 定期审查:能否删除现有 API |
| 344 | +4. ✅ 文档优先于代码 |
| 345 | + |
| 346 | +**守护 Go 生态的简洁性!** |
| 347 | + |
| 348 | +--- |
| 349 | + |
| 350 | +**版本历史**: |
| 351 | +- v1.1.0: 学到了教训(8 个概念删除) |
| 352 | +- v1.2.0: 实践了原则(Less is more) |
| 353 | +- 未来: 永远坚守(Don't add concepts) |
| 354 | + |
| 355 | +--- |
| 356 | + |
| 357 | +**这个文档本身就是守护者。** 🛡️ |
| 358 | + |
| 359 | +**当你想增加 API 时,先读这个文档。** 📖 |
| 360 | + |
| 361 | +**如果 AI 提议增加概念,拿这个文档反驳我。** 🤖 |
| 362 | + |
| 363 | +--- |
| 364 | + |
| 365 | +**xb - 简洁的守护者!** ✨ |
| 366 | + |
0 commit comments