模块拆分应避免过早创建utils目录,需待业务逻辑稳定后再提取无状态、跨域通用代码并严格约束;可选依赖须按场景分组、加版本约束,禁用无版本声明。

模块拆分时,别过早抽象出 utils 目录
很多团队一上手就建 utils,结果半年后里面塞了 83 个函数,彼此依赖混乱,改一个 format_timestamp 能让测试挂掉三个服务。这不是复用,是债务打包。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 先让功能在业务模块里“长出来”——比如
order_processing.py里反复出现的校验逻辑,再考虑抽成order_validation.py -
utils只收真正无状态、无业务语义、跨域通用的代码(如parse_iso_datetime),且必须带类型注解和单测 - 一旦某个
utils函数被两个以上不相关的业务模块导入,立刻检查它是否隐含了未声明的上下文依赖(比如悄悄读了os.environ)
pyproject.toml 里别堆满可选依赖
看到别人写 dev = ["pytest", "black", "mypy", "pre-commit", ...] 就照抄,结果 CI 构建时 pip 解析依赖图耗时翻倍,本地 poetry install 卡住还查不出原因。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 按场景分组:只把真正在开发期用的放
dev;CI 专用工具(如coveralls)单独设ci组;文档生成类(sphinx)归docs - 所有可选依赖必须加版本约束,禁止
"black"这种写法,用"black>=24.0.0, - CI 脚本里显式指定安装组:
pip install ".[ci]",避免 pip 自动合并多个组引发冲突
类型提示不是装饰,是接口契约
加了 def process(data: dict) -> List: 等于没加——dict 和 List 不提供任何校验或 IDE 支持,运行时照样传错结构崩掉。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
TypedDict或 Pydantic v2 的BaseModel描述数据形状,哪怕只是临时验证;dataclass更适合内部状态封装 - 函数参数/返回值类型必须精确到具体字段级约束(如
Optional[str]而非Any),否则 mypy 会绕过检查 - 类型检查要跑在 CI 里,但别用
mypy --strict一步到位——先从--disallow-untyped-defs和--disallow-incomplete-defs开始,逐步收紧
测试不是覆盖率数字,是隔离边界的探测器
追求 90%+ 覆盖率后发现,test_order_creation 里 mock 了数据库、HTTP 客户端、时间模块,最后这个测试既慢又脆,重构一次就得重写三处 patch。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 单元测试只打穿一层:函数输入 → 函数输出,其他依赖全用真实轻量对象(如内存字典代替 DB,
httpx.MockTransport代替 requests-mock) - 集成测试才该启动真实依赖,但必须限定范围——比如只测
OrderService+ 内存 SQLite,不拉起 Redis 或外部 API - 每个测试文件开头加注释说明它验证的边界:
# 验证订单金额计算在税费变更时仍正确,而不是# 测试 order module
复杂度真正的麻烦不在代码行数,而在你改一行时,得翻几个文件、问几个人、猜三次意图。控制不住这点,再多的架构图和规范都只是延缓爆炸的时间。









