第03课:技术选型

SaaS全栈开发实战 · 从零到上线

📖 课程概述

技术选型是架构师最重要的决策之一。选对了,开发效率翻倍;选错了,技术债利滚利。本课将从SaaS产品的特殊需求出发,系统分析前端框架、后端语言、数据库、云服务的技术选型决策。

🎯 技术选型决策框架

# 技术选型评估框架
from dataclasses import dataclass
from typing import List

@dataclass
class TechCandidate:
    """技术候选方案"""
    name: str
    category: str
    learning_curve: int     # 学习曲线(越低越好)
    ecosystem: int          # 生态系统
    performance: int        # 性能
    scalability: int        # 扩展性
    community: int          # 社区
    hiring_pool: int        # 招聘池
    long_term: int          # 长期存活
    saas_fit: int           # SaaS适配
    
    STARTUP_WEIGHTS = {
        'learning_curve': 0.15, 'ecosystem': 0.2, 'performance': 0.1,
        'scalability': 0.15, 'community': 0.15, 'hiring_pool': 0.1,
        'long_term': 0.05, 'saas_fit': 0.1,
    }
    
    def weighted_score(self, weights=None) -> float:
        w = weights or self.STARTUP_WEIGHTS
        scores = {
            'learning_curve': 11 - self.learning_curve,
            'ecosystem': self.ecosystem, 'performance': self.performance,
            'scalability': self.scalability, 'community': self.community,
            'hiring_pool': self.hiring_pool, 'long_term': self.long_term,
            'saas_fit': self.saas_fit,
        }
        return sum(scores[k] * w[k] for k in w)

# ✅ 验证通过 - 后端技术选型
candidates = [
    TechCandidate("FastAPI", "backend", 4,7,8,8,8,8,8,9),
    TechCandidate("Express", "backend", 3,9,7,7,9,9,8,7),
    TechCandidate("Spring Boot", "backend", 7,9,8,9,9,9,9,7),
    TechCandidate("Go/Gin", "backend", 5,6,10,9,7,6,8,8),
]
for c in sorted(candidates, key=lambda x: x.weighted_score(), reverse=True):
    print(f"{c.name}: {c.weighted_score():.2f}")

🏗️ 本课程技术栈

层级技术选择理由
前端React 18 + TypeScript生态最丰富,组件库最多
后端FastAPI (Python)异步高性能,自动API文档
数据库PostgreSQL 15JSONB+RLS,SaaS首选
缓存Redis 7会话、限流、缓存一站式
容器化Docker + Compose环境一致,部署标准化
CI/CDGitHub Actions免费额度,深度集成
支付Stripe全球支付,SaaS计费API最完善

⚡ FastAPI核心优势

# FastAPI核心特性演示
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, EmailStr
from typing import Optional
from datetime import datetime

app = FastAPI(title="SaaS Platform API", version="1.0.0")

class UserCreate(BaseModel):
    email: EmailStr
    name: str
    plan: str = "free"

class UserResponse(BaseModel):
    id: int
    email: str
    name: str
    plan: str
    created_at: datetime

@app.post("/users", response_model=UserResponse, tags=["用户管理"])
async def create_user(user: UserCreate):
    """创建新用户 - 自动参数验证+API文档"""
    return UserResponse(
        id=1, email=user.email, name=user.name,
        plan=user.plan, created_at=datetime.now()
    )

@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
    """获取用户 - 路径参数自动类型转换"""
    if user_id <= 0:
        raise HTTPException(status_code=404, detail="用户不存在")
    return UserResponse(
        id=user_id, email="user@example.com",
        name="Demo", plan="pro", created_at=datetime.now()
    )

# ✅ 验证通过 - FastAPI自动生成:
# - Swagger UI: http://localhost:8000/docs
# - ReDoc: http://localhost:8000/redoc
# - OpenAPI JSON: http://localhost:8000/openapi.json
print("FastAPI应用创建成功!")

🐘 PostgreSQL vs MongoDB

维度PostgreSQLMongoDB
事务✅ 完整ACID⚠️ 4.0后有限支持
数据一致性✅ 强一致性⚠️ 最终一致性
JSON支持✅ JSONB+索引✅ 原生JSON
复杂查询✅ SQL全功能❌ 聚合管道复杂
计费场景✅ 精确计算⚠️ 精度问题
多租户✅ Schema/RLS隔离⚠️ 应用层实现
-- PostgreSQL SaaS初始化
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

CREATE TYPE tenant_status AS ENUM ('trial', 'active', 'suspended', 'deleted');

CREATE TABLE tenants (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    name VARCHAR(255) NOT NULL,
    slug VARCHAR(100) UNIQUE NOT NULL,
    status tenant_status DEFAULT 'trial',
    plan VARCHAR(50) DEFAULT 'free',
    settings JSONB DEFAULT '{}'::jsonb,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    deleted_at TIMESTAMPTZ
);

-- 自动更新时间戳
CREATE OR REPLACE FUNCTION update_timestamp()
RETURNS TRIGGER AS $$
BEGIN NEW.updated_at = NOW(); RETURN NEW; END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER tenants_updated_at
    BEFORE UPDATE ON tenants
    FOR EACH ROW EXECUTE FUNCTION update_timestamp();

-- ✅ 验证通过 - PostgreSQL DDL

🚀 初始化项目

1 创建项目结构
mkdir -p saas-project/{backend,frontend,infra,docs}
mkdir -p saas-project/backend/{app/{api,core,models,schemas,services},tests,alembic}
mkdir -p saas-project/frontend/src/{components,features,hooks,stores,services,types}
mkdir -p saas-project/infra/{docker,scripts}

# 后端依赖
cat > saas-project/backend/requirements.txt << 'EOF'
fastapi==0.108.0
uvicorn[standard]==0.25.0
sqlalchemy==2.0.25
alembic==1.13.0
psycopg2-binary==2.9.9
redis==5.0.1
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4
python-multipart==0.0.6
pydantic[email]==2.5.0
stripe==7.8.0
httpx==0.25.2
EOF
2 Docker开发环境
# docker-compose.yml
version: "3.9"
services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: saas_db
      POSTGRES_USER: saas_user
      POSTGRES_PASSWORD: dev_password
    ports: ["5432:5432"]
    volumes: [pg_data:/var/lib/postgresql/data]
  redis:
    image: redis:7-alpine
    ports: ["6379:6379"]
volumes:
  pg_data:

🔄 技术选型决策记录(ADR)

每个重要技术决策都应该记录下来,包括背景、选项、决策和后果。这种文档叫做ADR(Architecture Decision Record):

# ADR模板
ADR_TEMPLATE = """
# ADR-001: 选择FastAPI作为后端框架

## 状态
已接受

## 背景
需要为SaaS产品选择后端框架,考虑因素:
- 开发效率(小团队2-3人)
- 异步支持(实时功能需求)
- API文档自动生成
- Python生态(数据分析/ML需求)

## 决策
选择FastAPI,而非Django/Flask/Express

## 选项分析
| 框架 | 优势 | 劣势 | 评分 |
|------|------|------|------|
| FastAPI | 异步、自动文档、高性能 | 生态较新 | 9/10 |
| Django | 成熟、Admin后台 | 同步、重 | 7/10 |
| Flask | 轻量、灵活 | 功能少 | 6/10 |
| Express | 生态大、同语言 | 回调地狱 | 7/10 |

## 后果
- 正面:开发速度快、API文档零维护
- 负面:社区资源比Django少,需自己实现Admin
- 风险:框架较新,长期存活性待验证(缓解:核心稳定,大厂使用)
"""

# ✅ 验证通过 - ADR决策记录

📐 技术债管理

# 技术债追踪
class TechDebtTracker:
    """技术债追踪器"""
    
    DEBT_LEVELS = {
        'critical': '必须立即解决,影响生产',
        'high': '近期必须解决,1-2个Sprint内',
        'medium': '计划解决,3-6个月内',
        'low': '有时间再解决',
    }
    
    def __init__(self):
        self.debts = []
    
    def add_debt(self, description: str, level: str, 
                 estimated_effort: str, reason: str):
        self.debts.append({
            'description': description,
            'level': level,
            'effort': estimated_effort,
            'reason': reason,  # 为什么产生了技术债
            'created_at': 'now',
        })
    
    def get_critical(self):
        return [d for d in self.debts if d['level'] == 'critical']

# ✅ 验证通过 - 技术债管理
\n

🔄 技术选型决策记录(ADR)

每个技术决策都应记录理由,ADR是团队沟通和未来回溯的重要工具:

# ADR-001: 选择FastAPI
ADR = {
    "编号": "ADR-001",
    "标题": "选择FastAPI作为后端框架",
    "状态": "已接受",
    "背景": "SaaS产品需要高性能API、自动文档、Python生态",
    "决策": "选择FastAPI,而非Django/Flask/Express",
    "选项分析": {
        "FastAPI": {"优势": "异步+自动文档+高性能", "劣势": "生态较新", "评分": 9},
        "Django": {"优势": "成熟+Admin后台", "劣势": "同步+重量级", "评分": 7},
        "Express": {"优势": "生态大+前后端同语言", "劣势": "回调问题", "评分": 7},
    },
    "后果": {
        "正面": "开发速度快、API文档零维护",
        "负面": "社区资源比Django少",
        "缓解": "核心稳定,大厂(Netflix/Microsoft)使用"
    }
}
print(f"决策: {ADR['标题']} - {ADR['状态']}")

📐 技术债管理

# 技术债追踪系统
class TechDebtTracker:
    LEVELS = {'critical': '必须立即解决', 'high': '1-2Sprint内', 
              'medium': '3-6月内', 'low': '有时间再说'}
    
    def __init__(self):
        self.debts = []
    
    def add(self, desc: str, level: str, effort: str, reason: str):
        self.debts.append({'desc': desc, 'level': level, 
                          'effort': effort, 'reason': reason})
    
    def report(self):
        for level in ['critical', 'high', 'medium', 'low']:
            items = [d for d in self.debts if d['level'] == level]
            if items:
                print(f"\n{level.upper()}: {self.LEVELS[level]}")
                for d in items:
                    print(f"  - {d['desc']} (工作量: {d['effort']})")

tracker = TechDebtTracker()
tracker.add("硬编码配置", "high", "1天", "快速原型")
tracker.add("缺少单元测试", "medium", "3天", "时间紧")
tracker.report()

🔧 工程化实践

SaaS后端开发不仅要写代码,更要建立可持续的工程实践。以下是关键的非功能性工作:

代码质量门控

# 代码质量配置
# pyproject.toml
QUALITY_CONFIG = {
    "linting": "ruff check . --fix",
    "formatting": "black . --line-length 100",
    "type_checking": "mypy app/ --strict",
    "complexity": "radon cc app/ -a -nc",  # 复杂度检查
    "security": "bandit -r app/",  # 安全扫描
}

# pre-commit钩子 (.pre-commit-config.yaml)
PRE_COMMIT_HOOKS = """
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    hooks: [ruff]
  - repo: https://github.com/psf/black
    hooks: [black]
  - repo: https://github.com/pre-commit/mirrors-mypy
    hooks: [mypy]
"""

print("代码质量工具配置完成")

错误追踪集成(Sentry)

# app/core/sentry.py - 错误追踪
import sentry_sdk
from sentry_sdk.integrations.fastapi import FastApiIntegration

def init_sentry(dsn: str, environment: str):
    sentry_sdk.init(
        dsn=dsn,
        environment=environment,
        integrations=[FastApiIntegration()],
        traces_sample_rate=0.1,  # 10%请求追踪
        profiles_sample_rate=0.1,
    )

# ✅ 验证通过 - Sentry错误追踪

📚 扩展学习资源

本课内容是SaaS全栈开发的重要一环。以下是推荐的深入学习资源:

必读书籍

在线资源

实践项目建议

学完本课后,建议你:

  1. 在本地环境动手实现本课的代码示例
  2. 根据你的SaaS项目调整和扩展代码
  3. 将关键决策记录到ADR文档
  4. 编写单元测试验证功能正确性

💡 学习建议:每课花2-3小时(1小时阅读+1-2小时动手实践),40课约80-120小时,约4-6周可完成全课程。坚持每天1课,6周后你就是SaaS全栈开发者!

🏆 课程成就

完成本课后,你已解锁:

技术选型框架 FastAPI入门 React+TS初始化 PostgreSQL设计 Docker环境

✅ 你现在能为SaaS项目做出合理的技术选型了!