30 分钟
实战专项

大项目架构设计:从需求到代码结构

掌握大型 Python 项目的架构设计方法论,能独立设计可维护的系统

  • 理解分层架构和依赖方向
  • 掌握项目目录结构设计
  • 学会配置管理和环境隔离
  • 理解依赖注入的价值

为什么需要架构设计?

小脚本一个文件就能搞定。但代码量超5000行、团队超3人时,没架构就是灾难:改一处崩三处、没人敢重构、新人上手要两周。架构设计就是管复杂度——把系统拆成高内聚、低耦合的模块,每个部分能独立理解、测试、修改。

🐍架构师的核心能力

架构不是画 UML 图,而是做「取舍」:单体还是微服务?同步还是异步?SQL 还是 NoSQL?每个决策都有代价。好的架构师能清晰说出每个选择的 trade-off,而不是追逐时髦技术。能用最简单的方案解决问题,就是最好的架构。

分层架构

最经典也最实用的架构是分层架构。核心原则:依赖只能从外层指向内层,内层不知道外层的存在。

Python
# 典型的分层结构
# ┌─────────────────────────────┐
# │  API/接口层 (routes/)        │  接收HTTP请求,参数校验
# ├─────────────────────────────┤
# │  业务逻辑层 (services/)      │  核心业务规则
# ├─────────────────────────────┤
# │  数据访问层 (repositories/)  │  数据库操作
# ├─────────────────────────────┤
# │  数据模型层 (models/)        │  数据结构定义
# └─────────────────────────────┘
#
# 依赖方向:API → Service → Repository → Model
# 内层不依赖外层:Service 不知道也不关心谁调用它(API或CLI)

# 反例:业务逻辑直接写在路由里(FastAPI/Flask新手常见)
@app.post("/orders")
def create_order(user_id: int, items: list):
    # 校验、计算、扣库存、写数据库、发通知全堆在一起
    # 问题:无法复用、无法测试、改一处影响全部
    ...

# 正例:分层
# routes/order.py
@router.post("/orders")
def create_order(req: OrderRequest):
    return order_service.create_order(req.user_id, req.items)

# services/order_service.py
def create_order(user_id, items):
    validate_items(items)
    total = pricing_service.calculate(items)
    order = order_repo.create(user_id, items, total)
    notification_service.send_confirmation(order)
    return order

# repositories/order_repo.py
def create(user_id, items, total):
    return db.execute(
        "INSERT INTO orders ...",
        {"user_id": user_id, "total": total}
    )
💡依赖倒置原则

高层模块不应该依赖低层模块,两者都应该依赖抽象。Service 不应该直接依赖具体的 Repository 类,而应该依赖接口(Protocol)。这样你可以在测试时用内存 Repository 替换数据库 Repository。

项目目录结构设计

示例
# 一个中型 FastAPI 项目的推荐结构
myapp/
├── pyproject.toml          # 项目配置和依赖
├── README.md
├── .env.example            # 环境变量模板
├── src/
│   └── myapp/
│       ├── __init__.py
│       ├── main.py         # 应用入口
│       ├── config.py       # 配置(从环境变量读取)
│       ├── api/            # 接口层
│       │   ├── routes/
│       │   └── deps.py     # 依赖注入
│       ├── core/           # 核心业务逻辑
│       │   ├── services/
│       │   └── exceptions.py
│       ├── db/             # 数据库
│       │   ├── models/
│       │   ├── repositories/
│       │   └── session.py
│       ├── schemas/        # Pydantic 模型(请求/响应)
│       └── utils/          # 工具函数
├── tests/
│   ├── unit/
│   ├── integration/
│   └── conftest.py
└── scripts/                # 运维脚本

# 关键原则:
# 1. src/ 布局:防止import混乱,打包更规范
# 2. 按功能分层,不按技术分层(api/core/db 而不是 models/views/controllers)
# 3. 每个模块有明确职责,一个文件不超过300行

配置管理

Python
# ❌ 硬编码配置(新手常见)
def connect_db():
    return psycopg2.connect(
        host="192.168.1.100",  # 生产IP写死在代码里!
        password="mypassword123",  # 密码提交到Git!
        dbname="myapp"
    )

# ✅ 配置从环境变量读取
import os
from dataclasses import dataclass

@dataclass(frozen=True)
class Config:
    db_host: str = os.getenv("DB_HOST", "localhost")
    db_port: int = int(os.getenv("DB_PORT", "5432"))
    db_name: str = os.getenv("DB_NAME", "myapp")
    db_user: str = os.getenv("DB_USER", "postgres")
    db_password: str = os.getenv("DB_PASSWORD", "")
    debug: bool = os.getenv("DEBUG", "false").lower() == "true"

config = Config()

# 更好:用 pydantic-settings 自动校验
from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    db_host: str = "localhost"
    db_port: int = 5432
    db_password: str
    secret_key: str
    debug: bool = False

    model_config = {"env_file": ".env"}

settings = Settings()  # 自动从环境变量和.env文件读取,缺失必填项直接报错
⚠️配置安全红线

别把密码、API Key、Secret 提交到 Git。用 .env 文件,把它加到 .gitignore 里,再配个 .env.example 模板。生产环境用环境变量或者密钥管理服务,比如 Vault、AWS Secrets Manager。Git 历史里的密码就算删了也能找回来,一旦泄露必须马上轮换。

依赖注入

Python
# 不使用依赖注入:Service 内部直接创建 Repository(硬编码依赖)
class OrderService:
    def __init__(self):
        self.repo = PostgresOrderRepository()  # 写死了,测试时无法替换

# 使用依赖注入:依赖从外部传入
class OrderService:
    def __init__(self, order_repo, user_repo, notifier):
        self.order_repo = order_repo  # 任何实现了相同接口的对象都行
        self.user_repo = user_repo
        self.notifier = notifier

# 生产环境
service = OrderService(
    PostgresOrderRepository(),
    PostgresUserRepository(),
    EmailNotifier()
)

# 测试环境:用内存实现和Mock替换
service = OrderService(
    InMemoryOrderRepository(),
    InMemoryUserRepository(),
    MockNotifier()
)

# FastAPI 的 Depends 就是依赖注入容器
@router.post("/orders")
def create_order(
    req: OrderRequest,
    service: OrderService = Depends(get_order_service)  # 框架自动注入
):
    return service.create_order(req.user_id, req.items)
💡什么时候该用依赖注入?

小型项目(<3000行)不需要过度设计,直接实例化就行。当你需要:写单元测试(替换外部依赖)支持多种实现(开发/测试/生产)解耦模块时,依赖注入就有用。

选择题

MVP 指的是?

选择题

技术选型最应考虑?

选择题

依赖倒置(DIP)的核心主张是?

资深工程师加餐

底层原理 · 大厂视角 · 工程经验,点卡片展开

大模型接口慢且偶发抖动,必须设连接与读取超时;重试只对网络错误、429、5xx 做指数退避并设上限,对 400 类参数错误重试毫无意义。写操作(如生成并落库)要带幂等键,避免超时重试产生重复记录。还要对总耗时设预算:主模型超时就降级到小模型或本地兜底,绝不能让一次外部调用拖垮整个界面。

挑战任务

设计项目结构

简单+50 XP

给博客系统搭分层架构和目录结构,各层职责和依赖关系这么定:

设计项目结构
3 个测试用例

课后作业

重构脚本为分层架构

中等+40 XP

找一个你写的超过200行的单文件脚本,用分层架构重构:拆出 models/services/repositories,配置移到环境变量。

重构脚本为分层架构
1 个测试用例