灵依 LingYi — 开发原则
项目是为自己做的,每一行代码都要对得起自己的时间。
一、根本原则
灵依是私我工具,不是开源产品。不追求架构优雅,追求每天都能用。
二、开发十条
1. 需求驱动,不做无用功
只开发自己真正会用的功能。不猜需求,不堆功能。 每写一个模块前先问:我这周会用它吗?
2. 最小可用,渐进增强
第一版只做一件事,做到能用就上线。 用起来发现不够,再加。别一次想太多。
3. 复用优先
4. 节约 token
- 响应能短则短
- 能本地处理的不到云端
- 缓存、压缩、复用贯穿始终
5. 中文为主,代码英文名
- 文档、交互、错误提示用中文
- 变量名、函数名、目录名用英文
- commit message 格式:
类型: 中文描述,如feat: 添加门诊日程管理
6. 安全底线
- 不硬编码密码、密钥,用
.env管理 - 敏感数据(
.env、*.db、*.key)不入 Git - 依赖每月检查一次(
pip audit,或由灵依 v0.6+ 自动提醒) - 边界规则以 MISSION.md 边界表为准
7. 代码简洁
- 一个函数做一件事
- 嵌套不超过三层
- 逻辑代码单文件不超过 300 行(数据/配置文件除外)
- 死代码删掉,不留着"以后用"
8. 核心路径有测试
不追求覆盖率,关键模块必须有测试: - 日程管理 → 必须测 - 数据存取 → 必须测 - 提醒逻辑 → 必须测 - 其他 → 按需
9. 小步提交
每个完整改动一个 commit,不留半成品。
格式:feat: / fix: / docs: / refactor: / chore: 中文描述
10. 每天能用上
开发中就让自己用。自己不用,就不知道哪里不好用。
11. FastAPI 路由类型作用域规则
当使用 from __future__ import annotations 时,FastAPI 的特殊类型(Request, WebSocket, Response 等)必须在模块级别导入,不能通过函数参数传递或在闭包内导入。
为什么:__future__ annotations 将类型注解转为字符串 ForwardRef,FastAPI 在解析时查找模块全局作用域。如果类型在函数参数或闭包内导入,FastAPI 无法解析,会将 request: Request 错误识别为查询参数,导致 HTTP 403/422。
正确示例:
from fastapi import Request
from __future__ import annotations # 必须在类型导入之后
def register_routes(app: FastAPI):
@app.get("/api/test")
async def test(request: Request): # Request 在模块作用域,可解析
return {"ok": True}
错误示例:
from __future__ import annotations # 类型字符串化
def register_routes(app: FastAPI, Request): # ❌ 通过参数传递
@app.get("/api/test")
async def test(request: Request): # FastAPI 找不到 Request 类型
return {"ok": True}
验证:重构路由文件后,运行 python3 -m pytest tests/test_web.py 冒烟测试,确保 TestNoBrokenRoutes 通过。
三、技术选型
| 原则 | 选择 | 理由 |
|---|---|---|
| 语言 | Python | 已掌握,生态丰富 |
| 框架 | LingFlow | 自己的项目,深度可控 |
| 数据库 | SQLite 起步 | 零运维,够用再升级 |
| 前端 | CLI 优先 | 不花时间做UI |
| 存储 | 本地文件 | 私密、简单、可靠 |
升级时机:SQLite 不够用时再换 PostgreSQL,不提前。
四、备份
- 每次开发结束:
git add . && git commit && git push - 数据库文件自动备份到
~/.lingyi/backup/(开发结束时由脚本同步) - 重要里程碑打 tag:
git tag v0.x.0
五、不做清单
- ❌ 微服务
- ❌ 过度抽象(三行代码不需要设计模式)
- ❌ 100%测试覆盖
- ❌ 花哨UI
- ❌ 提前优化
- ❌ 越界行为(边界以 MISSION.md 为准)