关于 12-factor-apps
依据 Twelve-Factor App 方法评估应用代码库的分析技能,逐项提供原则、搜索模式、合规标准和反模式,用于检查 SaaS 设计。
主要功能
- 01逐项评估框架
- 02代码搜索模式
- 03合规等级与标准
- 04反模式参考
适用场景
- 01按 Twelve-Factor 原则评估 SaaS 代码库
- 02查找配置与依赖风险
- 03检查部署和运行实践
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ existential-birds/ beagle --skill 12-factor-apps安装后在 Claude Code 中输入/12-factor-apps确认已加载。
详细介绍
12-Factor App 合规性分析
概述
12-Factor App 方法论是一套用于构建软件即服务应用的最佳实践,旨在使应用:
- 可在不同执行环境中移植
- 无需更改架构即可扩展
- 适合持续部署
- 易于维护,摩擦最小
输入参数
| 参数 | 描述 | 必填 |
|---|---|---|
codebase_path | 要分析的代码库根路径 | 必填 |
分析框架
因子 I:代码库
原则: 在版本控制中跟踪一个代码库,部署多个实例。
搜索模式:
# Check for version control
ls -la .git 2>/dev/null || ls -la .hg 2>/dev/null
# Check for multiple apps sharing codebase
find . -name "package.json" -o -name "pyproject.toml" -o -name "setup.py" | head -20
# Check for environment-specific code branches
grep -r "if.*production\|if.*development\|if.*staging" --include="*.py" --include="*.js" --include="*.ts"
文件模式: .git/、package.json、pyproject.toml、部署配置
合规标准:
| 级别 | 标准 |
|---|---|
| 强 | 单个 Git 仓库,所有环境使用相同代码库,没有特定于环境的代码分支 |
| 部分 | 单个仓库,但存在一些特定于环境的代码路径 |
| 弱 | 同一应用使用多个仓库,或不同环境间存在大量代码重复 |
反模式:
- 同一应用使用多个 Git 仓库
- 特定于环境的代码分支(
if production: ...) - 开发环境与生产环境使用不同源文件
- 未将共享代码提取为库
因子 II:依赖
原则: 明确声明并隔离依赖。
搜索模式:
# Python dependency files
find . -name "requirements.txt" -o -name "pyproject.toml" -o -name "setup.py" -o -name "Pipfile" -o -name "uv.lock"
# JavaScript/TypeScript dependency files
find . -name "package.json" -o -name "package-lock.json" -o -name "yarn.lock" -o -name "pnpm-lock.yaml"
# Check for system tool assumptions
grep -r "subprocess.*curl\|subprocess.*wget\|os.system.*ffmpeg\|shutil.which" --include="*.py"
grep -r "exec.*curl\|child_process.*curl" --include="*.js" --include="*.ts"
# Docker/container isolation
find . -name "Dockerfile" -o -name "docker-compose*.yml"
文件模式: **/requirements*.txt、**/package.json、**/*.lock、**/Dockerfile
合规标准:
| 级别 | 标准 |
|---|---|
| 强 | 存在锁定文件,依赖已隔离(venv/Docker),不依赖隐式系统工具 |
| 部分 | 已声明依赖,但没有锁定文件或隔离措施 |
| 弱 | 仅在文档中列出依赖,依赖系统安装的软件包 |
反模式:
- 缺少锁定文件(导致构建不可复现)
- 假设系统工具(curl、ImageMagick、ffmpeg)可用
- 开发环境与生产环境使用不同的依赖管理器
- 没有虚拟环境或容器隔离
因子 III:配置
原则: 将配置存储在环境中。
搜索模式:
# Environment variable usage
grep -r "os.environ\|os.getenv\|process.env\|ENV\[" --include="*.py" --include="*.js" --include="*.ts" --include="*.rb"
# Hardcoded credentials (anti-pattern)
grep -r "password.*=.*['\"]" --include="*.py" --include="*.js" --include="*.ts" | grep -v "test\|spec\|example"
grep -r "api_key.*=.*['\"]" --include="*.py" --include="*.js" --include="*.ts" | grep -v "test\|spec\|example"
grep -r "secret.*=.*['\"]" --include="*.py" --include="*.js" --include="*.ts" | grep -v "test\|spec\|example"
# Environment-specific config files (anti-pattern)
find . -name "config.dev.*" -o -name "config.prod.*" -o -name "settings.development.*" -o -name "settings.production.*"
# Database URLs in code
grep -r "postgresql://\|mysql://\|mongodb://\|redis://" --include="*.py" --include="*.js" --include="*.ts" | grep -v ".env\|test\|example"
文件模式: **/.env*、**/config/*.py、**/settings.py、环境文件
合规标准:
| 级别 | 标准 |
|---|---|
| 强 | 所有配置均通过环境变量提供,没有硬编码的机密信息,可开源且不泄露机密 |
| 部分 | 大部分配置已外置,但仍有一些硬编码的默认值 |
| 弱 | 硬编码凭据,使用特定于环境的配置文件 |
反模式:
- 在源代码中硬编码数据库 URL、API 密钥和密码
- 使用
config/production.yml和config/development.yml等配置文件 - 按环境分组(
if ENV == 'production': ...) - 将机密信息提交到版本控制中
因子 IV:后端服务
原则: 将后端服务视为附加资源。
搜索模式:
# Database connection via config
grep -r "DATABASE_URL\|DB_HOST\|REDIS_URL\|CACHE_URL" --include="*.py" --include="*.js" --include="*.ts"
# Service initialization
grep -r "create_engine\|MongoClient\|Redis\|Celery\|boto3" --include="*.py"
grep -r "createPool\|createClient\|new Redis\|S3Client" --include="*.js" --include="*.ts"
# Hardcoded service locations (anti-pattern)
grep -r "localhost:5432\|localhost:6379\|localhost:27017\|127.0.0.1" --include="*.py" --include="*.js" --include="*.ts" | grep -v "test\|spec\|example\|default"
文件模式: **/database/*.py、**/services/*.py、**/db.py、连接配置
合规标准:
| 级别 | 标准 |
|---|---|
| 强 | 所有服务均通过配置中的 URL/连接字符串提供,可在不更改代码的情况下替换 |
| 部分 | 大多数服务可配置,但仍有一些硬编码的默认值 |
| 弱 | 硬编码服务位置,不同环境使用不同代码路径 |
反模式:
- 在生产代码中为服务硬编码
localhost - 针对本地服务与云服务使用条件逻辑(
if USE_S3: ... else: local_storage) - 根据环境使用特定于服务的代码路径
- 开发环境与生产环境使用不同的驱动程序
因素 V:构建、发布、运行
原则: 严格分离构建阶段和运行阶段。
搜索模式:
# Build/deploy configuration
find . -name "Dockerfile" -o -name "Makefile" -o -name "build.sh" -o -name "deploy.sh"
find . -name ".github/workflows/*.yml" -o -name ".gitlab-ci.yml" -o -name "Jenkinsfile"
# Build scripts in package.json
grep -A5 '"scripts"' package.json 2>/dev/null | grep -E "build|start|deploy"
# Check for runtime compilation (anti-pattern)
grep -r "compile\|transpile\|webpack" --include="*.py" | grep -v "test\|build"
文件模式: **/Dockerfile、**/Makefile、**/.github/workflows/**、CI/CD 配置
合规标准:
| 级别 | 标准 |
|---|---|
| 强 | 不可变发布版本,明确区分构建、发布和运行阶段,唯一的发布 ID |
| 部分 | 构建和运行已分离,但发布版本不可变 |
| 弱 | 运行时修改代码,启动时编译资源 |
反模式:
- 运行时修改代码
- 应用启动时编译资源
- 将配置固化到构建产物中
- 没有发布版本管理
因素 VI:进程
原则: 将应用作为一个或多个无状态进程运行。
搜索模式:
# Session storage patterns
grep -r "session\|Session" --include="*.py" --include="*.js" --include="*.ts" | head -20
# In-process state (anti-pattern)
grep -r "global.*cache\|process_local\|instance_cache" --include="*.py"
grep -r "global\..*=\|module\.exports\.cache" --include="*.js" --include="*.ts"
# External session stores (good pattern)
grep -r "redis.*session\|memcached.*session\|session.*redis" --include="*.py" --include="*.js" --include="*.ts"
# Sticky session configuration (anti-pattern)
grep -r "sticky.*session\|session.*affinity" --include="*.yml" --include="*.yaml" --include="*.json"
文件模式: **/middleware/*.py、**/session/*.py、服务器配置
合规标准:
| 级别 | 标准 |
|---|---|
| 强 | 进程无状态,所有状态都存储在外部数据存储(Redis、DB)中 |
| 部分 | 基本无状态,但存在一些进程内缓存 |
| 弱 | 粘性会话、进程内会话存储、共享内存状态 |
反模式:
- 进程内会话存储(
user_sessions = {}) - 粘性会话或会话亲和性
- 请求之间使用基于文件的缓存
- 在请求之间共享的全局可变状态
因素 VII:端口绑定
原则: 通过端口绑定提供服务。
搜索模式:
# Self-contained port binding
grep -r "app.run\|server.listen\|serve\|uvicorn" --include="*.py"
grep -r "app.listen\|server.listen\|createServer" --include="*.js" --include="*.ts"
# PORT environment variable
grep -r "PORT\|port" --include="*.py" --include="*.js" --include="*.ts" | grep -i "environ\|process.env"
# Webserver as dependency
grep -r "uvicorn\|gunicorn\|flask\|fastapi\|express\|koa\|hapi" package.json pyproject.toml requirements.txt 2>/dev/null
文件模式: **/main.py、**/server.py、**/app.py、**/index.js
合规标准:
| 级别 | 标准 |
|---|---|
| 强 | 自包含应用绑定到 PORT,Web 服务器作为依赖项 |
| 部分 | 绑定端口,但无法通过环境进行配置 |
| 弱 | 依赖外部 Web 服务器容器(Apache、Nginx)提供 HTTP |
反模式:
- 依赖 Apache/Nginx/Tomcat 注入 Web 服务器功能
- 硬编码端口号
- 不支持 PORT 环境变量
- CGI 脚本或服务器模块
因素 VIII:并发
原则: 通过进程模型横向扩展。
搜索模式:
# Process definitions
find . -name "Procfile" -o -name "process.yml" -o -name ".foreman"
# Multiple entry points
find . -name "worker.py" -o -name "scheduler.py" -o -name "web.py"
# Background job systems
grep -r "celery\|rq\|sidekiq\|bull\|agenda" --include="*.py" --include="*.js" --include="*.ts"
grep -r "Celery\|Worker\|BackgroundJob" --include="*.py" --include="*.js" --include="*.ts"
文件模式: **/Procfile、**/worker.py、**/scheduler.py、队列配置
合规标准:
| 级别 | 标准 |
|---|---|
| 强 | 明确的进程类型(Web、工作进程、调度程序),支持横向扩展 |
| 部分 | 有多种进程类型,但不易扩展 |
| 弱 | 单体进程,没有关注点分离 |
反模式:
- 单个进程处理所有工作负载
- 在代码中硬编码工作进程数量
- Web 进程和后台进程没有分离
- 仅纵向扩展(使用更大的服务器,而不是增加进程)
因素 IX:可处置性
原则: 通过快速启动和优雅关闭来最大限度地提高稳健性。
搜索模式:
# Signal handlers
grep -r "signal.signal\|SIGTERM\|SIGINT\|atexit" --include="*.py"
grep -r "process.on.*SIGTERM\|process.on.*SIGINT" --include="*.js" --include="*.ts"
# Graceful shutdown
grep -r "graceful.*shutdown\|shutdown_handler\|cleanup" --include="*.py" --include="*.js" --include="*.ts"
# Startup time
grep -r "startup\|initialize\|bootstrap" --include="*.py" --include="*.js" --include="*.ts" | head -20
文件模式: **/main.py、**/server.py、生命周期管理代码
合规标准:
| 级别 | 标准 |
|---|---|
| 强 | 快速启动(<10s),处理 SIGTERM,优雅关闭,作业可重新放回队列 |
| 部分 | 可优雅关闭,但启动缓慢 |
| 弱 | 不处理信号,进程终止时作业丢失,启动缓慢 |
反模式:
- 没有 SIGTERM/SIGINT 处理程序
- 启动缓慢(>30 秒)
- 进程崩溃时作业丢失
- 关闭时不执行清理
因素 X:开发与生产环境的一致性
原则: 尽可能保持开发、预发布和生产环境相似。
搜索模式:
# Different services per environment (anti-pattern)
grep -r "if.*development.*sqlite\|if.*production.*postgres" --include="*.py" --include="*.js" --include="*.ts"
grep -r "development.*SQLite\|production.*PostgreSQL" --include="*.py" --include="*.js" --include="*.ts"
# Docker for parity
find . -name "docker-compose*.yml" -o -name "Dockerfile"
# Environment-specific backends
grep -r "USE_LOCAL_\|LOCAL_STORAGE\|MOCK_" --include="*.py" --include="*.js" --include="*.ts"
文件模式: **/docker-compose*.yml、环境配置
合规标准:
| 级别 | 标准 |
|---|---|
| 强 | 所有环境使用相同的服务(开发和生产环境均使用 PostgreSQL),并采用容器化 |
| 部分 | 大体相同,但开发环境使用了一些轻量级替代方案 |
| 弱 | 开发环境使用 SQLite,生产环境使用 PostgreSQL;后端服务不同 |
反模式:
- 开发环境使用 SQLite,生产环境使用 PostgreSQL
- 开发环境使用内存缓存,生产环境使用 Redis
- 不同环境使用不同版本的服务
- “在我的机器上能运行”问题
因素 XI:日志
原则: 将日志视为事件流。
搜索模式:
# Stdout logging
grep -r "print(\|logging.info\|logger.info\|console.log" --include="*.py" --include="*.js" --include="*.ts" | head -20
# File-based logging (anti-pattern)
grep -r "FileHandler\|open.*\.log\|writeFile.*log\|fs.appendFile.*log" --include="*.py" --include="*.js" --include="*.ts"
grep -r "/var/log\|/tmp/.*\.log\|logs/" --include="*.py" --include="*.js" --include="*.ts" | grep -v "test\|example"
# Structured logging
grep -r "structlog\|json_logger\|pino\|winston" --include="*.py" --include="*.js" --include="*.ts"
文件模式: **/logging.py、**/logger.py、日志配置
合规标准:
| 级别 | 标准 |
|---|---|
| 强 | 仅使用未缓冲的标准输出,采用结构化日志(JSON),不进行文件管理 |
| 部分 | 使用标准输出记录日志,但配置了一些文件处理器 |
| 弱 | 应用程序将日志写入文件并管理轮转 |
反模式:
- 将日志写入文件(
FileHandler、open('/var/log/app.log')) - 在应用程序代码中实现日志轮转逻辑
- 由应用程序管理日志归档
- 缓冲日志
因素 XII:管理进程
原则: 将管理/维护任务作为一次性进程运行。
搜索模式:
# Management commands
find . -name "manage.py" -o -name "Rakefile" -o -name "artisan"
grep -r "@cli.command\|@click.command\|typer.command" --include="*.py"
# Migration scripts
find . -name "migrations" -type d
find . -name "*migration*.py" -o -name "*migrate*.py"
# Admin scripts with proper isolation
grep -r "bundle exec\|source.*venv\|uv run" --include="*.sh" --include="Makefile"
文件模式: **/manage.py、**/cli.py、**/migrations/**、管理脚本
合规标准:
| 级别 | 标准 |
|---|---|
| 强 | 管理任务使用相同的依赖项和配置,适当隔离,且具备幂等性 |
| 部分 | 存在管理任务,但其设置与应用程序不同 |
| 弱 | 手动操作数据库、未隔离的脚本 |
反模式:
- 管理脚本未使用应用程序的依赖管理器
- 在迁移之外直接操作 SQL
- 管理脚本中硬编码凭据
- 非幂等迁移
输出格式
执行摘要表
| Factor | Status | Notes |
|--------|--------|-------|
| I. Codebase | **Strong/Partial/Weak** | [Key finding] |
| II. Dependencies | **Strong/Partial/Weak** | [Key finding] |
| III. Config | **Strong/Partial/Weak** | [Key finding] |
| IV. Backing Services | **Strong/Partial/Weak** | [Key finding] |
| V. Build/Release/Run | **Strong/Partial/Weak** | [Key finding] |
| VI. Processes | **Strong/Partial/Weak** | [Key finding] |
| VII. Port Binding | **Strong/Partial/Weak** | [Key finding] |
| VIII. Concurrency | **Strong/Partial/Weak** | [Key finding] |
| IX. Disposability | **Strong/Partial/Weak** | [Key finding] |
| X. Dev/Prod Parity | **Strong/Partial/Weak** | [Key finding] |
| XI. Logs | **Strong/Partial/Weak** | [Key finding] |
| XII. Admin Processes | **Strong/Partial/Weak** | [Key finding] |
**Overall**: X Strong, Y Partial, Z Weak
各因素分析
对每个因素,请提供:
-
当前实现
- 附带文件名:行号引用的证据
- 展示相关模式的代码片段
-
合规级别
- 强/部分/弱,并说明理由
-
差距
- 与 12-Factor 理想状态相比的缺失项
-
建议
- 提供可执行的改进方案和代码示例
分析工作流
-
初步扫描
- 对所有因素运行搜索模式
- 找出各因素的关键文件
- 记录现有的合规文档
-
深入分析(逐项因素)
- 阅读已找到的文件
- 根据合规标准进行评估
- 记录证据及文件路径
-
差距分析
- 对比当前状态与 12-Factor 理想状态
- 找出现有反模式
- 按影响程度确定优先级
-
建议
- 提供可执行的改进方案
- 包含改进前后的代码示例
- 参考最佳实践
-
总结
- 汇总执行摘要表
- 突出优势和关键差距
- 建议改进的优先顺序
快速参考:合规评分
| 评分 | 含义 | 行动 |
|---|---|---|
| 强 | 完全贯彻原则 | 保持现状,进行少量优化 |
| 部分 | 已有部分实现,但存在明显差距 | 计划改进 |
| 弱 | 几乎未实现或完全未实现 | 在路线图中列为高优先级 |
何时使用此技能
- 评估新的 SaaS 应用程序
- 审查云原生架构决策
- 审计生产应用程序的可扩展性
- 规划迁移到云平台
- 比较应用程序架构
- 为容器化/Kubernetes 部署做准备