12-factor-apps について
Twelve-Factor Appの方法論に沿ってアプリケーションのコードベースを評価するスキルです。SaaS設計を確認するため、各要素の原則、検索パターン、適合基準、アンチパターンを示します。
主な機能
- 01要素別の評価フレームワーク
- 02コード検索パターン
- 03適合レベルと基準
- 04アンチパターンの参照
活用シーン
- 01Twelve-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 の方法論は、以下のような Software-as-a-Service アプリケーションを構築するためのベストプラクティスです。
- 実行環境を問わず移植可能
- アーキテクチャを変更せずにスケーリング可能
- 継続的デプロイに適している
- 最小限の手間で保守可能
入力パラメーター
| パラメーター | 説明 | 必須 |
|---|---|---|
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:プロセス
原則: アプリを、ステートレスな 1 つ以上のプロセスとして実行します。
検索パターン:
# 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 にバインドし、ウェブサーバーを依存関係として使用 |
| 部分的 | ポートにバインドするが、環境変数で設定できない |
| 弱 | HTTP を提供するために外部ウェブサーバーのコンテナ(Apache、Nginx)に依存 |
アンチパターン:
- ウェブサーバー機能の提供を Apache/Nginx/Tomcat に依存する
- ポート番号のハードコード
- 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、キュー設定
準拠基準:
| レベル | 基準 |
|---|---|
| 強 | 明示的なプロセスタイプ(ウェブ、ワーカー、スケジューラー)、水平スケーリング |
| 部分的 | 複数のプロセスタイプがあるが、簡単にはスケーリングできない |
| 弱 | 単一のモノリシックプロセス、関心事の分離がない |
アンチパターン:
- すべてのワークロードを単一プロセスで処理する
- コード内でのワーカー数のハードコード
- ウェブプロセスとバックグラウンドプロセスが分離されていない
- 垂直スケーリングのみ(プロセス数を増やさず、サーバーを大型化する)
ファクター 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、ライフサイクル管理コード
準拠基準:
| レベル | 基準 |
|---|---|
| 強 | 迅速な起動(10 秒未満)、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 デプロイの準備をする