古畑奈和「appassionato」 BUBKAデジタル写真集
¥1,650 (2025-07-01 08:58 GMT +09:00 時点 - 詳細はこちら価格および発送可能時期は表示された日付/時刻の時点のものであり、変更される場合があります。本商品の購入においては、購入の時点で当該の Amazon サイトに表示されている価格および発送可能時期の情報が適用されます。)百瀬まりな Bubbly FRIDAYデジタル写真集
¥1,980 (2025-07-01 08:58 GMT +09:00 時点 - 詳細はこちら価格および発送可能時期は表示された日付/時刻の時点のものであり、変更される場合があります。本商品の購入においては、購入の時点で当該の Amazon サイトに表示されている価格および発送可能時期の情報が適用されます。)目次
チーム開発でのコンテナ環境標準化戦略:組織レベルでの効率的運用ガイド
個人でのコンテナ開発環境構築をマスターしたら、次の重要な課題はチーム全体での標準化と効率的な運用です。「新人が環境構築に1週間かかる」「メンバーごとに異なる環境で『私の環境では動く』問題が頻発」「設定ファイルの管理が属人化」といった課題を解決する必要があります。
この記事では、5人から500人規模まで対応できる組織レベルでのコンテナ環境標準化戦略を詳しく解説します。効果的なワークフロー設計、新人オンボーディングの自動化、設定管理のベストプラクティスを習得できます。
組織レベル標準化の戦略フレームワーク
標準化の段階的アプローチ
Phase 1: 基盤標準化(1-2週間)
- 基本的なDockerfile・Compose テンプレート統一
- VS Code DevContainer 設定標準化
- 最小限の開発ルール策定
Phase 2: ワークフロー統合(2-4週間)
- Git フック・CI/CD との連携
- 自動化されたテスト・品質チェック
- ドキュメント・知識共有システム
Phase 3: 組織最適化(1-3ヶ月)
- メトリクス収集・分析システム
- 継続的改善プロセス
- 新技術導入評価・適用
チーム規模別の標準化戦略
小規模チーム(2-10人)の場合:
# team-standards/small-team-config.yml
standardization_level: "basic"
governance: "informal"
automation_level: "minimal"
required_tools:
- docker: ">=20.0"
- vscode: "latest"
- git: ">=2.30"
standard_files:
- .devcontainer/devcontainer.json
- docker-compose.yml
- .env.example
- README.md
workflow:
setup_time_target: "30 minutes"
review_process: "peer review"
documentation: "inline comments + README"
中規模チーム(11-50人)の場合:
# team-standards/medium-team-config.yml
standardization_level: "comprehensive"
governance: "formal_guidelines"
automation_level: "high"
required_tools:
- docker: "20.10.x" # 固定バージョン
- vscode: ">=1.70.0"
- pre-commit: "latest"
standard_files:
- .devcontainer/devcontainer.json
- docker-compose.yml
- docker-compose.override.yml
- .env.example
- .env.local.example
- scripts/setup.sh
- docs/DEVELOPMENT.md
workflow:
setup_time_target: "15 minutes"
review_process: "mandatory code review + automated checks"
documentation: "dedicated wiki + API docs"
monitoring: "development metrics collection"
大規模組織(50人以上)の場合:
# team-standards/enterprise-config.yml
standardization_level: "enterprise"
governance: "strict_policies"
automation_level: "full"
required_tools:
- docker: "20.10.21" # セキュリティ検証済み固定版
- vscode: "1.74.3"
- pre-commit: "2.20.0"
- security_scanner: "required"
standard_files:
- .devcontainer/
- devcontainer.json
- Dockerfile
- docker-compose.yml
- scripts/
- setup.sh
- validate.sh
- security-check.sh
- docs/
- DEVELOPMENT.md
- SECURITY.md
- CONTRIBUTING.md
- .github/
- workflows/dev-environment-check.yml
workflow:
setup_time_target: "10 minutes"
review_process: "multi-stage approval + security review"
documentation: "comprehensive documentation site"
monitoring: "full observability + compliance tracking"
compliance: "SOC2 + security audits"
統一開発環境テンプレートの設計
プロジェクトテンプレート構造
チーム全体で再利用可能な標準テンプレートを設計します:
team-dev-templates/
├── 📁 base/ # 共通基盤
│ ├── 📄 .devcontainer/
│ │ ├── 📄 devcontainer.json # 基本DevContainer設定
│ │ ├── 📄 Dockerfile.base # 共通ベースイメージ
│ │ └── 📄 docker-compose.base.yml
│ ├── 📄 scripts/
│ │ ├── 📄 setup.sh # 環境セットアップ
│ │ ├── 📄 validate.sh # 環境検証
│ │ ├── 📄 update.sh # 環境更新
│ │ └── 📄 troubleshoot.sh # トラブルシューティング
│ └── 📄 docs/
│ ├── 📄 DEVELOPMENT.md # 開発ガイド
│ ├── 📄 TROUBLESHOOTING.md # 問題解決
│ └── 📄 TEAM_STANDARDS.md # チーム標準
├── 📁 python-web/ # Python Webアプリ用
│ ├── 📄 .devcontainer/
│ │ ├── 📄 devcontainer.json
│ │ └── 📄 Dockerfile
│ ├── 📄 pyproject.toml
│ ├── 📄 requirements/
│ │ ├── 📄 base.txt
│ │ ├── 📄 dev.txt
│ │ └── 📄 test.txt
│ └── 📄 tests/
├── 📁 data-science/ # データサイエンス用
│ ├── 📄 .devcontainer/
│ ├── 📄 notebooks/
│ ├── 📄 data/
│ └── 📄 models/
├── 📁 frontend/ # フロントエンド用
│ ├── 📄 .devcontainer/
│ ├── 📄 package.json
│ └── 📄 src/
└── 📁 fullstack/ # フルスタック用
├── 📄 .devcontainer/
├── 📄 backend/
├── 📄 frontend/
└── 📄 database/
統一DevContainer設定
チーム標準DevContainer基盤:
// base/.devcontainer/devcontainer.json - チーム共通基盤
{
"name": "${PROJECT_NAME} Development Environment",
"dockerComposeFile": ["docker-compose.base.yml", "../docker-compose.yml"],
"service": "app",
"workspaceFolder": "/workspace",
"shutdownAction": "stopCompose",
// チーム統一設定
"customizations": {
"vscode": {
"settings": {
// エディタ統一設定
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
// チーム統一インデント設定
"editor.tabSize": 2,
"editor.insertSpaces": true,
// Git統一設定
"git.autofetch": true,
"git.enableSmartCommit": true,
// ターミナル統一設定
"terminal.integrated.defaultProfile.linux": "bash",
"terminal.integrated.profiles.linux": {
"team-shell": {
"path": "/bin/bash",
"args": ["-c", "source /workspace/scripts/team-aliases.sh && bash"]
}
}
},
// チーム必須拡張機能
"extensions": [
// 基本開発ツール
"ms-vscode.vscode-typescript-next",
"esbenp.prettier-vscode",
"ms-python.python",
"ms-python.vscode-pylance",
// Git・バージョン管理
"eamodio.gitlens",
"github.vscode-pull-request-github",
// コード品質
"ms-python.flake8",
"ms-python.mypy-type-checker",
"bradlc.vscode-tailwindcss",
// チーム協働
"ms-vsliveshare.vsliveshare",
"gruntfuggly.todo-tree",
"streetsidesoftware.code-spell-checker",
// コンテナ・DevOps
"ms-azuretools.vscode-docker",
"ms-vscode-remote.remote-containers"
]
}
},
// ライフサイクルコマンド(チーム統一)
"onCreateCommand": {
"install-team-tools": "bash scripts/setup.sh",
"validate-environment": "bash scripts/validate.sh"
},
"postCreateCommand": "bash scripts/post-create.sh",
"postStartCommand": "bash scripts/health-check.sh",
// ポート転送統一設定
"forwardPorts": [3000, 8000, 8080, 5432, 6379],
"portsAttributes": {
"3000": {
"label": "Frontend Dev Server",
"onAutoForward": "openBrowser"
},
"8000": {
"label": "Backend API",
"onAutoForward": "openBrowser"
},
"5432": {
"label": "PostgreSQL",
"onAutoForward": "silent"
}
},
// チーム環境変数
"containerEnv": {
"TEAM_STANDARDS_VERSION": "2.1.0",
"DEVELOPMENT_MODE": "true",
"LOG_LEVEL": "debug"
},
// チーム統一機能
"features": {
"ghcr.io/devcontainers/features/git:1": {
"version": "latest"
},
"ghcr.io/devcontainers/features/github-cli:1": {
"version": "latest"
},
"ghcr.io/devcontainers/features/node:1": {
"version": "18"
}
},
// 権限・セキュリティ設定
"containerUser": "vscode",
"updateRemoteUserUID": true,
"remoteUser": "vscode"
}
プロジェクト種別特化設定(例:Python Web):
// python-web/.devcontainer/devcontainer.json
{
"name": "Python Web Development",
// ベース設定を継承
"dockerComposeFile": [
"../base/.devcontainer/docker-compose.base.yml",
"docker-compose.yml"
],
"service": "python-web",
"workspaceFolder": "/workspace",
// Python特化カスタマイズ
"customizations": {
"vscode": {
"settings": {
// Python特化設定
"python.defaultInterpreterPath": "/usr/local/bin/python",
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.linting.flake8Enabled": true,
"python.formatting.provider": "black",
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": ["tests/"],
// Django/Flask設定
"python.envFile": "${workspaceFolder}/.env",
"python.terminal.activateEnvironment": false
},
// Python特化拡張機能
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"ms-python.black-formatter",
"ms-python.isort",
"ms-python.mypy-type-checker",
"ms-python.flake8",
"ms-toolsai.jupyter",
"batisteo.vscode-django",
"ckolkman.vscode-postgres"
]
}
},
// Python特化ライフサイクル
"onCreateCommand": {
"install-python-deps": "pip install -r requirements/dev.txt",
"setup-pre-commit": "pre-commit install"
},
"postCreateCommand": "python manage.py migrate",
// Python特化ポート設定
"forwardPorts": [8000, 8080, 5432],
"portsAttributes": {
"8000": {
"label": "Django/Flask Dev Server",
"onAutoForward": "openBrowser"
}
}
}
自動化セットアップスクリプト
包括的環境セットアップスクリプト:
#!/bin/bash
# scripts/setup.sh - チーム統一環境セットアップ
set -euo pipefail
# 設定
TEAM_STANDARDS_VERSION="2.1.0"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
# ログ関数
log() {
echo "🔧 [$(date +'%Y-%m-%d %H:%M:%S')] $*"
}
error() {
echo "❌ [$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $*" >&2
}
success() {
echo "✅ [$(date +'%Y-%m-%d %H:%M:%S')] $*"
}
# 環境検証
validate_environment() {
log "環境を検証中..."
# 必須ツールチェック
local required_tools=("docker" "git" "curl")
for tool in "${required_tools[@]}"; do
if ! command -v "$tool" &> /dev/null; then
error "$tool が見つかりません"
exit 1
fi
success "$tool が利用可能"
done
# Dockerバージョンチェック
local docker_version=$(docker --version | grep -oE '[0-9]+.[0-9]+.[0-9]+' | head -1)
log "Docker version: $docker_version"
# Git設定チェック
if ! git config user.name &> /dev/null; then
error "Git user.name が設定されていません"
echo "設定してください: git config --global user.name 'Your Name'"
exit 1
fi
if ! git config user.email &> /dev/null; then
error "Git user.email が設定されていません"
echo "設定してください: git config --global user.email 'your.email@company.com'"
exit 1
fi
success "環境検証完了"
}
# チーム標準ツールインストール
install_team_tools() {
log "チーム標準ツールをインストール中..."
# Pre-commit hooks
if command -v pip &> /dev/null; then
pip install --user pre-commit
if [ -f ".pre-commit-config.yaml" ]; then
pre-commit install
success "pre-commit hooks インストール完了"
fi
fi
# GitHub CLI
if ! command -v gh &> /dev/null; then
if command -v apt-get &> /dev/null; then
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update
sudo apt install gh
fi
fi
success "チーム標準ツール インストール完了"
}
# プロジェクト固有セットアップ
setup_project() {
log "プロジェクト固有セットアップを実行中..."
# 環境変数ファイルセットアップ
if [ -f ".env.example" ] && [ ! -f ".env" ]; then
cp .env.example .env
log ".env ファイルを作成しました(.env.example からコピー)"
echo "⚠️ .env ファイルを確認して、必要な値を設定してください"
fi
# ローカル設定ファイル
if [ -f ".env.local.example" ] && [ ! -f ".env.local" ]; then
cp .env.local.example .env.local
log ".env.local ファイルを作成しました"
fi
# Git hooks セットアップ
if [ -d ".githooks" ]; then
git config core.hooksPath .githooks
chmod +x .githooks/*
success "Git hooks セットアップ完了"
fi
# 依存関係インストール
if [ -f "requirements.txt" ]; then
pip install -r requirements.txt
elif [ -f "package.json" ]; then
npm install
elif [ -f "Gemfile" ]; then
bundle install
fi
success "プロジェクト固有セットアップ完了"
}
# チーム標準検証
validate_team_standards() {
log "チーム標準への適合性を検証中..."
local compliance_errors=()
# 必須ファイル存在チェック
local required_files=(
".devcontainer/devcontainer.json"
"README.md"
".gitignore"
)
for file in "${required_files[@]}"; do
if [ ! -f "$file" ]; then
compliance_errors+=("必須ファイルが不足: $file")
fi
done
# DevContainer設定検証
if [ -f ".devcontainer/devcontainer.json" ]; then
if ! jq . .devcontainer/devcontainer.json > /dev/null 2>&1; then
compliance_errors+=("DevContainer設定が無効なJSON形式")
fi
fi
# README.md 内容チェック
if [ -f "README.md" ]; then
local readme_required_sections=("## 開発環境セットアップ" "## 使用方法")
for section in "${readme_required_sections[@]}"; do
if ! grep -q "$section" README.md; then
compliance_errors+=("README.md に必須セクションが不足: $section")
fi
done
fi
# エラーレポート
if [ ${#compliance_errors[@]} -gt 0 ]; then
error "チーム標準への適合性問題が発見されました:"
for err in "${compliance_errors[@]}"; do
echo " - $err"
done
echo ""
echo "問題を修正してから再実行してください。"
exit 1
fi
success "チーム標準への適合性検証完了"
}
# ヘルスチェック
health_check() {
log "環境ヘルスチェックを実行中..."
# Docker接続テスト
if ! docker ps > /dev/null 2>&1; then
error "Docker daemon に接続できません"
exit 1
fi
# ポート使用状況チェック
local common_ports=(3000 8000 8080 5432 6379)
local used_ports=()
for port in "${common_ports[@]}"; do
if netstat -tuln 2>/dev/null | grep -q ":$port "; then
used_ports+=("$port")
fi
done
if [ ${#used_ports[@]} -gt 0 ]; then
log "使用中のポート: ${used_ports[*]}"
echo "開発サーバー起動時に競合する可能性があります"
fi
# ディスク容量チェック
local disk_usage=$(df . | tail -1 | awk '{print $5}' | sed 's/%//')
if [ "$disk_usage" -gt 85 ]; then
log "⚠️ ディスク使用率が高いです ($disk_usage%)"
echo "docker system prune でクリーンアップを検討してください"
fi
success "ヘルスチェック完了"
}
# 完了レポート
completion_report() {
echo ""
echo "🎉 チーム開発環境セットアップが完了しました!"
echo ""
echo "📋 次のステップ:"
echo "1. .env ファイルの設定値を確認・更新"
echo "2. VS Code でプロジェクトを開く"
echo "3. 'Dev Containers: Reopen in Container' を実行"
echo "4. 開発を開始!"
echo ""
echo "🔗 参考資料:"
echo "- 開発ガイド: docs/DEVELOPMENT.md"
echo "- チーム標準: docs/TEAM_STANDARDS.md"
echo "- トラブルシューティング: docs/TROUBLESHOOTING.md"
echo ""
echo "❓ 問題が発生した場合:"
echo "- ./scripts/troubleshoot.sh を実行"
echo "- チームSlackの #dev-support チャンネルで質問"
echo ""
}
# メイン実行
main() {
log "チーム開発環境セットアップを開始します..."
log "Team Standards Version: $TEAM_STANDARDS_VERSION"
echo ""
validate_environment
install_team_tools
setup_project
validate_team_standards
health_check
completion_report
success "セットアップが正常に完了しました ✨"
}
# オプション処理
while [[ $# -gt 0 ]]; do
case $1 in
--skip-validation)
SKIP_VALIDATION=true
shift
;;
--verbose)
set -x
shift
;;
--help)
echo "チーム開発環境セットアップスクリプト"
echo ""
echo "使用方法: $0 [オプション]"
echo ""
echo "オプション:"
echo " --skip-validation 検証をスキップ"
echo " --verbose 詳細ログを表示"
echo " --help このヘルプを表示"
exit 0
;;
*)
error "不明なオプション: $1"
exit 1
;;
esac
done
# メイン実行
main
新人オンボーディング自動化
ワンクリックセットアップシステム
新人向け自動化オンボーディング:
#!/bin/bash
# scripts/onboarding.sh - 新人向け完全自動セットアップ
set -euo pipefail
# 新人オンボーディング用設定
ONBOARDING_VERSION="1.0.0"
COMPANY_NAME="Your Company"
TEAM_NAME="Development Team"
# インタラクティブセットアップ
interactive_setup() {
echo "🎉 $COMPANY_NAME $TEAM_NAME へようこそ!"
echo "========================================="
echo ""
echo "この自動セットアップでは、開発環境を完全に準備します。"
echo "所要時間: 約10-15分"
echo ""
read -p "続行しますか? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "セットアップをキャンセルしました。"
exit 0
fi
# 基本情報収集
echo ""
echo "📝 基本情報を設定します"
echo "========================"
# Git設定
if ! git config user.name &> /dev/null; then
read -p "Git ユーザー名を入力してください: " git_name
git config --global user.name "$git_name"
fi
if ! git config user.email &> /dev/null; then
read -p "Git メールアドレスを入力してください: " git_email
git config --global user.email "$git_email"
fi
# SSH キー設定
setup_ssh_key
# 開発設定
echo ""
echo "⚙️ 開発設定をカスタマイズします"
echo "=========================="
read -p "普段使用するエディタは? (1: VS Code, 2: IntelliJ, 3: その他): " editor_choice
case $editor_choice in
1)
PREFERRED_EDITOR="vscode"
;;
2)
PREFERRED_EDITOR="intellij"
;;
*)
PREFERRED_EDITOR="other"
;;
esac
read -p "主な開発言語は? (1: Python, 2: JavaScript, 3: Java, 4: その他): " language_choice
case $language_choice in
1)
PRIMARY_LANGUAGE="python"
;;
2)
PRIMARY_LANGUAGE="javascript"
;;
3)
PRIMARY_LANGUAGE="java"
;;
*)
PRIMARY_LANGUAGE="other"
;;
esac
}
# SSH キーセットアップ
setup_ssh_key() {
echo ""
echo "🔑 SSH キーを設定します"
echo "===================="
if [ ! -f ~/.ssh/id_ed25519 ]; then
read -p "SSH キーを生成しますか? (Y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]] || [[ -z $REPLY ]]; then
local email=$(git config user.email)
ssh-keygen -t ed25519 -C "$email" -f ~/.ssh/id_ed25519 -N ""
# SSH エージェントに追加
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
echo ""
echo "✅ SSH キーが生成されました"
echo ""
echo "📋 以下の公開キーをGitHubに登録してください:"
echo "=============================================="
cat ~/.ssh/id_ed25519.pub
echo "=============================================="
echo ""
echo "GitHub Settings → SSH and GPG keys → New SSH key"
echo ""
read -p "GitHubへの登録が完了したらEnterを押してください..."
# GitHub接続テスト
if ssh -T git@github.com 2>&1 | grep -q "successfully authenticated"; then
echo "✅ GitHub SSH接続が確認できました"
else
echo "⚠️ GitHub SSH接続に問題があります。後で確認してください。"
fi
fi
else
echo "✅ SSH キーは既に存在します"
fi
}
# 必要ツールインストール
install_required_tools() {
echo ""
echo "🛠️ 必要なツールをインストールします"
echo "============================"
# OS判定
if [[ "$OSTYPE" == "darwin"* ]]; then
install_tools_macos
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
install_tools_linux
elif [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "cygwin" ]]; then
install_tools_windows
else
echo "⚠️ お使いのOSは自動インストールに対応していません"
echo "手動でツールをインストールしてください:"
echo "- Docker"
echo "- Git"
echo "- VS Code"
echo "- Node.js"
return
fi
}
install_tools_macos() {
echo "macOS用ツールをインストール中..."
# Homebrewインストール
if ! command -v brew &> /dev/null; then
echo "Homebrewをインストール中..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
# 必須ツール
local tools=("git" "docker" "docker-compose" "node" "yarn")
for tool in "${tools[@]}"; do
if ! command -v "$tool" &> /dev/null; then
echo "$tool をインストール中..."
brew install "$tool"
fi
done
# VS Code
if ! command -v code &> /dev/null; then
echo "VS Code をインストール中..."
brew install --cask visual-studio-code
fi
# OrbStack (Docker Desktop代替)
if ! command -v orbstack &> /dev/null; then
echo "OrbStack をインストール中..."
brew install --cask orbstack
fi
}
install_tools_linux() {
echo "Linux用ツールをインストール中..."
# パッケージマネージャー判定
if command -v apt-get &> /dev/null; then
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y curl wget git
# Docker
if ! command -v docker &> /dev/null; then
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
fi
# Node.js
if ! command -v node &> /dev/null; then
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
fi
# VS Code
if ! command -v code &> /dev/null; then
wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg
sudo install -o root -g root -m 644 packages.microsoft.gpg /etc/apt/trusted.gpg.d/
echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/trusted.gpg.d/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" | sudo tee /etc/apt/sources.list.d/vscode.list
sudo apt-get update
sudo apt-get install -y code
fi
elif command -v dnf &> /dev/null; then
# Fedora/RHEL
sudo dnf install -y curl wget git docker nodejs npm
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
fi
}
# チーム設定配布
distribute_team_settings() {
echo ""
echo "👥 チーム設定を配布します"
echo "======================"
# VS Code設定
local vscode_settings_dir=""
if [[ "$OSTYPE" == "darwin"* ]]; then
vscode_settings_dir="$HOME/Library/Application Support/Code/User"
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
vscode_settings_dir="$HOME/.config/Code/User"
elif [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "cygwin" ]]; then
vscode_settings_dir="$APPDATA/Code/User"
fi
if [ -n "$vscode_settings_dir" ] && [ -d "$vscode_settings_dir" ]; then
# チーム統一VS Code設定を配布
if [ -f "team-configs/vscode-settings.json" ]; then
cp team-configs/vscode-settings.json "$vscode_settings_dir/settings.json"
echo "✅ VS Code設定を更新しました"
fi
# チーム統一拡張機能インストール
if [ -f "team-configs/vscode-extensions.txt" ]; then
echo "📦 チーム標準拡張機能をインストール中..."
while IFS= read -r extension; do
if [ -n "$extension" ] && [[ ! "$extension" =~ ^# ]]; then
code --install-extension "$extension" || true
fi
done < team-configs/vscode-extensions.txt
echo "✅ 拡張機能インストール完了"
fi
fi
# Git設定配布
if [ -f "team-configs/gitconfig" ]; then
cat team-configs/gitconfig >> ~/.gitconfig
echo "✅ Git設定を更新しました"
fi
# Shell設定配布
if [ -f "team-configs/team-aliases.sh" ]; then
local shell_config=""
if [ -n "$BASH_VERSION" ]; then
shell_config="$HOME/.bashrc"
elif [ -n "$ZSH_VERSION" ]; then
shell_config="$HOME/.zshrc"
fi
if [ -n "$shell_config" ]; then
echo "source $(pwd)/team-configs/team-aliases.sh" >> "$shell_config"
echo "✅ シェル設定を更新しました"
fi
fi
}
# 学習リソース案内
provide_learning_resources() {
echo ""
echo "📚 学習リソースと次のステップ"
echo "============================"
echo ""
echo "🎯 今すぐできること:"
echo "1. プロジェクトをクローンして開発開始"
echo " git clone https://github.com/company/project-name.git"
echo ""
echo "2. 最初のプルリクエストを作成"
echo " - 自己紹介をREADME.mdに追加"
echo " - 簡単なバグ修正から始める"
echo ""
echo "📖 必読ドキュメント:"
echo "- チーム開発ガイド: docs/TEAM_GUIDE.md"
echo "- コーディング規約: docs/CODING_STANDARDS.md"
echo "- Git ワークフロー: docs/GIT_WORKFLOW.md"
echo ""
echo "🎥 推奨学習コンテンツ:"
echo "- 社内Docker研修動画: https://company.com/docker-training"
echo "- Git実践ワークショップ: 毎週金曜日 15:00-16:00"
echo "- ペアプログラミングセッション: #pair-programming で募集"
echo ""
echo "❓ サポート窓口:"
echo "- 技術的質問: #dev-support"
echo "- 環境構築問題: #dev-environment"
echo "- その他質問: #general"
echo ""
echo "👥 メンター制度:"
echo "新入社員には経験豊富なメンターが付きます。"
echo "メンター: [自動アサイン予定] さん"
echo "初回1on1: 来週中に設定されます"
echo ""
}
# 完了サマリー
completion_summary() {
echo ""
echo "🎉 オンボーディング完了!"
echo "======================="
echo ""
echo "✅ 完了した設定:"
echo "- Git設定 (ユーザー名・メール)"
echo "- SSH キー生成・GitHub登録"
echo "- 必要ツールインストール"
echo "- チーム標準設定配布"
echo "- VS Code拡張機能インストール"
echo ""
echo "📝 あなたの環境情報:"
echo "- Git User: $(git config user.name) <$(git config user.email)>"
echo "- Docker: $(docker --version 2>/dev/null || echo '未インストール')"
echo "- Node.js: $(node --version 2>/dev/null || echo '未インストール')"
echo "- エディタ設定: $PREFERRED_EDITOR"
echo "- 主要言語: $PRIMARY_LANGUAGE"
echo ""
echo "🚀 次のアクション:"
echo "1. ターミナルを再起動 (設定を反映)"
echo "2. 'scripts/validate.sh' を実行 (環境確認)"
echo "3. VS Code でプロジェクトを開く"
echo "4. 初回プルリクエストを作成"
echo ""
echo "Welcome to the team! 🎊"
}
# メイン実行
main() {
interactive_setup
install_required_tools
distribute_team_settings
# チーム標準セットアップ実行
if [ -f "scripts/setup.sh" ]; then
bash scripts/setup.sh --skip-validation
fi
provide_learning_resources
completion_summary
}
# エラーハンドリング
trap 'echo "❌ オンボーディング中にエラーが発生しました"; exit 1' ERR
echo "新人オンボーディング開始..."
main "$@"
ワークフロー統合とCI/CD連携
Git Hooks による品質保証
チーム統一pre-commit設定:
# .pre-commit-config.yaml - チーム標準品質チェック
repos:
# 基本的なコード品質
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-json
- id: check-merge-conflict
- id: check-executables-have-shebangs
- id: check-case-conflict
# Docker設定検証
- repo: https://github.com/hadolint/hadolint
rev: v2.12.0
hooks:
- id: hadolint-docker
args: [--config, .hadolint.yaml]
# Python品質チェック
- repo: https://github.com/psf/black
rev: 23.7.0
hooks:
- id: black
language_version: python3
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
args: [--profile, black]
- repo: https://github.com/pycqa/flake8
rev: 6.0.0
hooks:
- id: flake8
additional_dependencies: [flake8-docstrings]
# セキュリティチェック
- repo: https://github.com/PyCQA/bandit
rev: 1.7.5
hooks:
- id: bandit
args: [-r, src/, -f, json, -o, bandit-report.json]
# シークレット検出
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
# コミットメッセージ形式チェック
- repo: https://github.com/commitizen-tools/commitizen
rev: v3.6.0
hooks:
- id: commitizen
- id: commitizen-branch
stages: [push]
チーム統一commitizen設定:
# pyproject.toml - コミットメッセージ標準化
[tool.commitizen]
name = "cz_conventional_commits"
version = "1.0.0"
tag_format = "v$version"
update_changelog_on_bump = true
[tool.commitizen.settings]
# チーム統一コミットタイプ
allowed_prefixes = [
"feat", # 新機能
"fix", # バグ修正
"docs", # ドキュメント
"style", # コードスタイル
"refactor", # リファクタリング
"test", # テスト関連
"chore", # その他のタスク
"ci", # CI/CD関連
"perf", # パフォーマンス改善
"build", # ビルド関連
]
# スコープ(プロジェクト固有)
scopes = [
"api",
"frontend",
"backend",
"database",
"docker",
"docs",
"tests",
]
自動化テスト・デプロイパイプライン
GitHub Actions チーム標準ワークフロー:
# .github/workflows/team-standards-check.yml
name: Team Standards Check
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
TEAM_STANDARDS_VERSION: "2.1.0"
jobs:
#============================================================================
# 環境設定検証
#============================================================================
validate-environment:
name: Validate Development Environment
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Validate DevContainer configuration
run: |
if [ ! -f ".devcontainer/devcontainer.json" ]; then
echo "❌ DevContainer設定が見つかりません"
exit 1
fi
# JSON形式検証
if ! jq . .devcontainer/devcontainer.json > /dev/null; then
echo "❌ DevContainer設定が無効なJSON形式です"
exit 1
fi
echo "✅ DevContainer設定は有効です"
- name: Validate Docker configuration
run: |
if [ -f "Dockerfile" ]; then
# Hadolint でDockerfile検証
docker run --rm -i hadolint/hadolint < Dockerfile
fi
if [ -f "docker-compose.yml" ]; then
# docker-compose設定検証
docker-compose config > /dev/null
fi
- name: Check required documentation
run: |
required_docs=(
"README.md"
"docs/DEVELOPMENT.md"
)
for doc in "${required_docs[@]}"; do
if [ ! -f "$doc" ]; then
echo "❌ 必須ドキュメントが不足: $doc"
exit 1
fi
done
echo "✅ 必須ドキュメントが存在します"
#============================================================================
# コード品質チェック
#============================================================================
code-quality:
name: Code Quality Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install pre-commit
pre-commit install
- name: Run pre-commit hooks
run: pre-commit run --all-files
- name: Upload code quality reports
uses: actions/upload-artifact@v3
if: always()
with:
name: code-quality-reports
path: |
bandit-report.json
*.log
#============================================================================
# 開発環境テスト
#============================================================================
test-dev-environment:
name: Test Development Environment
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build development environment
run: |
if [ -f "docker-compose.yml" ]; then
docker-compose build
elif [ -f "Dockerfile" ]; then
docker build -t test-env .
fi
- name: Test environment startup
run: |
if [ -f "docker-compose.yml" ]; then
docker-compose up -d
sleep 30
# ヘルスチェック
if [ -f "scripts/health-check.sh" ]; then
docker-compose exec -T app bash scripts/health-check.sh
fi
docker-compose down
fi
- name: Run setup script test
run: |
if [ -f "scripts/setup.sh" ]; then
# セットアップスクリプトのドライラン
bash scripts/setup.sh --skip-validation || true
fi
#============================================================================
# チーム標準適合性チェック
#============================================================================
team-compliance:
name: Team Standards Compliance
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Check team standards version
run: |
if [ -f "team-config.yml" ]; then
version=$(grep "standards_version:" team-config.yml | cut -d'"' -f2)
if [ "$version" != "$TEAM_STANDARDS_VERSION" ]; then
echo "⚠️ チーム標準バージョンが古い可能性があります"
echo "Current: $version, Expected: $TEAM_STANDARDS_VERSION"
fi
fi
- name: Validate naming conventions
run: |
# ファイル命名規則チェック
find . -name "*.py" -exec basename {} ; | while read file; do
if [[ ! "$file" =~ ^[a-z_][a-z0-9_]*.py$ ]]; then
echo "❌ Python ファイル命名規則違反: $file"
exit 1
fi
done
# ディレクトリ命名規則チェック
find . -type d -name "*" | while read dir; do
basename_dir=$(basename "$dir")
if [[ "$basename_dir" =~ [A-Z] ]] && [[ "$basename_dir" != ".git" ]] && [[ "$basename_dir" != ".github" ]]; then
echo "⚠️ ディレクトリ名に大文字が含まれています: $dir"
fi
done
- name: Check git configuration
run: |
# .gitignore の存在確認
if [ ! -f ".gitignore" ]; then
echo "❌ .gitignore ファイルが存在しません"
exit 1
fi
# 必須除外パターンチェック
required_patterns=(
"*.pyc"
"__pycache__/"
".env"
"*.log"
".DS_Store"
)
for pattern in "${required_patterns[@]}"; do
if ! grep -q "$pattern" .gitignore; then
echo "⚠️ .gitignore に推奨パターンが不足: $pattern"
fi
done
#============================================================================
# セキュリティチェック
#============================================================================
security-check:
name: Security Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'
- name: Check for secrets
run: |
# detect-secrets を使用
pip install detect-secrets
detect-secrets scan --all-files --baseline .secrets.baseline
#============================================================================
# 通知とレポート
#============================================================================
notify-results:
name: Notify Results
needs: [validate-environment, code-quality, test-dev-environment, team-compliance, security-check]
runs-on: ubuntu-latest
if: always()
steps:
- name: Generate summary report
run: |
echo "## 🔍 Team Standards Check Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 各ジョブの結果をサマリーに追加
echo "| Check | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Environment Validation | ${{ needs.validate-environment.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Code Quality | ${{ needs.code-quality.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Dev Environment Test | ${{ needs.test-dev-environment.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Team Compliance | ${{ needs.team-compliance.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Security Check | ${{ needs.security-check.result }} |" >> $GITHUB_STEP_SUMMARY
- name: Slack notification
if: failure()
uses: 8398a7/action-slack@v3
with:
status: failure
text: "🚨 Team standards check failed for ${{ github.repository }}"
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
メトリクス収集・分析システム
開発効率測定
チーム生産性メトリクス収集:
#!/usr/bin/env python3
# scripts/team-metrics-collector.py
import json
import subprocess
import time
from datetime import datetime, timedelta
from pathlib import Path
from typing import Dict, List, Any
import requests
import sqlite3
class TeamMetricsCollector:
def __init__(self, config_file="team-metrics-config.json"):
self.config = self.load_config(config_file)
self.db_path = "team_metrics.db"
self.init_database()
def load_config(self, config_file):
"""設定ファイル読み込み"""
try:
with open(config_file, 'r') as f:
return json.load(f)
except FileNotFoundError:
return self.get_default_config()
def get_default_config(self):
"""デフォルト設定"""
return {
"github": {
"enabled": True,
"token": "",
"repos": []
},
"docker": {
"enabled": True,
"collect_build_times": True,
"collect_image_sizes": True
},
"development": {
"enabled": True,
"collect_setup_times": True,
"collect_error_rates": True
},
"team": {
"size": 10,
"experience_levels": {
"junior": 3,
"mid": 4,
"senior": 3
}
}
}
def init_database(self):
"""データベース初期化"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
# テーブル作成
cursor.execute('''
CREATE TABLE IF NOT EXISTS setup_times (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
user_id TEXT NOT NULL,
setup_type TEXT NOT NULL,
duration_seconds INTEGER NOT NULL,
success BOOLEAN NOT NULL,
error_message TEXT
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS build_metrics (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
project_name TEXT NOT NULL,
build_type TEXT NOT NULL,
duration_seconds INTEGER NOT NULL,
image_size_mb REAL,
cache_hit_ratio REAL,
success BOOLEAN NOT NULL
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS development_metrics (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
user_id TEXT NOT NULL,
action TEXT NOT NULL,
duration_seconds INTEGER,
error_count INTEGER DEFAULT 0,
metadata TEXT
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS team_health (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
metric_name TEXT NOT NULL,
metric_value REAL NOT NULL,
unit TEXT NOT NULL
)
''')
conn.commit()
conn.close()
def collect_setup_metrics(self):
"""環境セットアップメトリクス収集"""
print("📊 Collecting setup metrics...")
# 最近のセットアップログを分析
setup_log_path = Path("logs/setup.log")
if setup_log_path.exists():
with open(setup_log_path) as f:
logs = f.readlines()
setup_times = self.parse_setup_logs(logs)
self.store_setup_metrics(setup_times)
def parse_setup_logs(self, logs: List[str]) -> List[Dict]:
"""セットアップログ解析"""
setup_times = []
current_setup = None
for line in logs:
if "Setup starting" in line:
current_setup = {
'start_time': self.extract_timestamp(line),
'user_id': self.extract_user_id(line),
'setup_type': 'full'
}
elif "Setup completed" in line and current_setup:
end_time = self.extract_timestamp(line)
duration = (end_time - current_setup['start_time']).total_seconds()
current_setup.update({
'duration_seconds': int(duration),
'success': True,
'error_message': None
})
setup_times.append(current_setup)
current_setup = None
elif "Setup failed" in line and current_setup:
end_time = self.extract_timestamp(line)
duration = (end_time - current_setup['start_time']).total_seconds()
current_setup.update({
'duration_seconds': int(duration),
'success': False,
'error_message': self.extract_error_message(line)
})
setup_times.append(current_setup)
current_setup = None
return setup_times
def collect_build_metrics(self):
"""ビルドメトリクス収集"""
print("🏗️ Collecting build metrics...")
# Docker ビルド履歴を分析
try:
# Docker images 情報収集
result = subprocess.run(
["docker", "images", "--format", "json"],
capture_output=True, text=True
)
if result.returncode == 0:
images = [json.loads(line) for line in result.stdout.strip().split('n') if line]
self.analyze_image_metrics(images)
except Exception as e:
print(f"Error collecting Docker metrics: {e}")
def analyze_image_metrics(self, images: List[Dict]):
"""イメージメトリクス分析"""
for image in images:
size_str = image.get('Size', '0B')
size_mb = self.parse_size_to_mb(size_str)
build_metric = {
'timestamp': datetime.now().isoformat(),
'project_name': image.get('Repository', 'unknown'),
'build_type': 'docker_image',
'duration_seconds': 0, # ビルド時間は別途収集
'image_size_mb': size_mb,
'cache_hit_ratio': 0.0, # キャッシュ情報は別途収集
'success': True
}
self.store_build_metric(build_metric)
def collect_development_metrics(self):
"""開発活動メトリクス収集"""
print("💻 Collecting development metrics...")
# Git activity analysis
if self.config["github"]["enabled"]:
self.collect_git_metrics()
# Error rates from logs
self.collect_error_metrics()
def collect_git_metrics(self):
"""Git活動メトリクス収集"""
try:
# 最近1週間のコミット数
result = subprocess.run([
"git", "log", "--since=1.week", "--oneline"
], capture_output=True, text=True)
commit_count = len(result.stdout.strip().split('n')) if result.stdout.strip() else 0
# チーム健康度メトリクスとして記録
self.store_team_health_metric(
"weekly_commits", commit_count, "count"
)
# プルリクエスト統計(GitHub API使用)
if self.config["github"]["token"]:
self.collect_github_pr_metrics()
except Exception as e:
print(f"Error collecting Git metrics: {e}")
def collect_github_pr_metrics(self):
"""GitHub PR メトリクス収集"""
headers = {
"Authorization": f"token {self.config['github']['token']}",
"Accept": "application/vnd.github.v3+json"
}
for repo in self.config["github"]["repos"]:
try:
# 最近のPR統計
url = f"https://api.github.com/repos/{repo}/pulls"
params = {
"state": "all",
"since": (datetime.now() - timedelta(days=7)).isoformat()
}
response = requests.get(url, headers=headers, params=params)
if response.status_code == 200:
prs = response.json()
# PR統計を計算
merged_prs = len([pr for pr in prs if pr.get('merged_at')])
avg_review_time = self.calculate_avg_review_time(prs)
# メトリクス保存
self.store_team_health_metric("weekly_merged_prs", merged_prs, "count")
if avg_review_time:
self.store_team_health_metric("avg_review_time_hours", avg_review_time, "hours")
except Exception as e:
print(f"Error collecting GitHub metrics for {repo}: {e}")
def calculate_avg_review_time(self, prs: List[Dict]) -> float:
"""平均レビュー時間計算"""
review_times = []
for pr in prs:
created_at = datetime.fromisoformat(pr['created_at'].replace('Z', '+00:00'))
merged_at = pr.get('merged_at')
if merged_at:
merged_at = datetime.fromisoformat(merged_at.replace('Z', '+00:00'))
review_time = (merged_at - created_at).total_seconds() / 3600 # 時間単位
review_times.append(review_time)
return sum(review_times) / len(review_times) if review_times else 0
def collect_error_metrics(self):
"""エラーメトリクス収集"""
error_log_patterns = [
"logs/error.log",
"logs/app.log",
"/var/log/containers/*.log"
]
total_errors = 0
for pattern in error_log_patterns:
error_count = self.count_errors_in_logs(pattern)
total_errors += error_count
self.store_team_health_metric("daily_error_count", total_errors, "count")
def count_errors_in_logs(self, log_pattern: str) -> int:
"""ログファイル内のエラー数カウント"""
try:
import glob
error_count = 0
for log_file in glob.glob(log_pattern):
with open(log_file, 'r') as f:
content = f.read()
error_count += content.lower().count('error')
error_count += content.lower().count('exception')
error_count += content.lower().count('critical')
return error_count
except Exception:
return 0
def generate_team_dashboard(self) -> Dict[str, Any]:
"""チームダッシュボード用データ生成"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
dashboard_data = {
"summary": {},
"trends": {},
"health_score": 0
}
# セットアップ時間統計
cursor.execute('''
SELECT
AVG(duration_seconds) as avg_setup_time,
COUNT(*) as total_setups,
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as successful_setups
FROM setup_times
WHERE timestamp > datetime('now', '-7 days')
''')
setup_stats = cursor.fetchone()
if setup_stats[0]:
dashboard_data["summary"]["avg_setup_time_minutes"] = round(setup_stats[0] / 60, 2)
dashboard_data["summary"]["setup_success_rate"] = round(setup_stats[2] / setup_stats[1] * 100, 1) if setup_stats[1] > 0 else 0
# ビルド統計
cursor.execute('''
SELECT
AVG(duration_seconds) as avg_build_time,
AVG(image_size_mb) as avg_image_size,
COUNT(*) as total_builds
FROM build_metrics
WHERE timestamp > datetime('now', '-7 days')
''')
build_stats = cursor.fetchone()
if build_stats[0]:
dashboard_data["summary"]["avg_build_time_minutes"] = round(build_stats[0] / 60, 2)
dashboard_data["summary"]["avg_image_size_mb"] = round(build_stats[1], 1)
# チーム健康度スコア計算
health_score = self.calculate_team_health_score(cursor)
dashboard_data["health_score"] = health_score
conn.close()
return dashboard_data
def calculate_team_health_score(self, cursor) -> int:
"""チーム健康度スコア計算 (0-100)"""
score_factors = []
# セットアップ成功率 (30%)
cursor.execute('''
SELECT
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*) as success_rate
FROM setup_times
WHERE timestamp > datetime('now', '-30 days')
''')
setup_success_rate = cursor.fetchone()[0] or 0
score_factors.append(min(setup_success_rate, 100) * 0.3)
# セットアップ時間 (20%)
cursor.execute('''
SELECT AVG(duration_seconds) FROM setup_times
WHERE timestamp > datetime('now', '-30 days') AND success = 1
''')
avg_setup_time = cursor.fetchone()[0] or 0
setup_time_score = max(0, 100 - (avg_setup_time / 60 - 10) * 5) # 10分が理想
score_factors.append(setup_time_score * 0.2)
# エラー率 (30%)
cursor.execute('''
SELECT AVG(metric_value) FROM team_health
WHERE metric_name = 'daily_error_count'
AND timestamp > datetime('now', '-7 days')
''')
avg_daily_errors = cursor.fetchone()[0] or 0
error_rate_score = max(0, 100 - avg_daily_errors * 2)
score_factors.append(error_rate_score * 0.3)
# PR処理速度 (20%)
cursor.execute('''
SELECT AVG(metric_value) FROM team_health
WHERE metric_name = 'avg_review_time_hours'
AND timestamp > datetime('now', '-7 days')
''')
avg_review_time = cursor.fetchone()[0] or 0
review_time_score = max(0, 100 - (avg_review_time - 24) * 2) # 24時間が理想
score_factors.append(review_time_score * 0.2)
return round(sum(score_factors))
def store_setup_metrics(self, metrics: List[Dict]):
"""セットアップメトリクス保存"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
for metric in metrics:
cursor.execute('''
INSERT INTO setup_times
(timestamp, user_id, setup_type, duration_seconds, success, error_message)
VALUES (?, ?, ?, ?, ?, ?)
''', (
metric.get('start_time', datetime.now()).isoformat(),
metric.get('user_id', 'unknown'),
metric.get('setup_type', 'unknown'),
metric.get('duration_seconds', 0),
metric.get('success', False),
metric.get('error_message')
))
conn.commit()
conn.close()
def store_build_metric(self, metric: Dict):
"""ビルドメトリクス保存"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
INSERT INTO build_metrics
(timestamp, project_name, build_type, duration_seconds, image_size_mb, cache_hit_ratio, success)
VALUES (?, ?, ?, ?, ?, ?, ?)
''', (
metric['timestamp'],
metric['project_name'],
metric['build_type'],
metric['duration_seconds'],
metric['image_size_mb'],
metric['cache_hit_ratio'],
metric['success']
))
conn.commit()
conn.close()
def store_team_health_metric(self, metric_name: str, value: float, unit: str):
"""チーム健康度メトリクス保存"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
INSERT INTO team_health (timestamp, metric_name, metric_value, unit)
VALUES (?, ?, ?, ?)
''', (datetime.now().isoformat(), metric_name, value, unit))
conn.commit()
conn.close()
def extract_timestamp(self, log_line: str) -> datetime:
"""ログ行からタイムスタンプ抽出"""
# 簡略化された実装
return datetime.now()
def extract_user_id(self, log_line: str) -> str:
"""ログ行からユーザーID抽出"""
# 簡略化された実装
return "user123"
def extract_error_message(self, log_line: str) -> str:
"""ログ行からエラーメッセージ抽出"""
return log_line.strip()
def parse_size_to_mb(self, size_str: str) -> float:
"""サイズ文字列をMBに変換"""
if 'GB' in size_str:
return float(size_str.replace('GB', '')) * 1024
elif 'MB' in size_str:
return float(size_str.replace('MB', ''))
elif 'KB' in size_str:
return float(size_str.replace('KB', '')) / 1024
else:
return 0.0
def main():
collector = TeamMetricsCollector()
print("📊 Starting team metrics collection...")
collector.collect_setup_metrics()
collector.collect_build_metrics()
collector.collect_development_metrics()
dashboard_data = collector.generate_team_dashboard()
print("📋 Team Dashboard Summary:")
print(f"Health Score: {dashboard_data['health_score']}/100")
print(f"Avg Setup Time: {dashboard_data['summary'].get('avg_setup_time_minutes', 'N/A')} minutes")
print(f"Setup Success Rate: {dashboard_data['summary'].get('setup_success_rate', 'N/A')}%")
print(f"Avg Build Time: {dashboard_data['summary'].get('avg_build_time_minutes', 'N/A')} minutes")
# ダッシュボードデータをJSONで出力
with open('team_dashboard.json', 'w') as f:
json.dump(dashboard_data, f, indent=2)
print("✅ Metrics collection completed!")
if __name__ == "__main__":
main()
まとめ
この記事では、チーム開発でのコンテナ環境標準化について、組織レベルでの効率的な運用方法を詳しく解説しました。
重要な標準化ポイント
段階的標準化アプローチ:
- Phase 1: 基盤標準化(基本テンプレート統一)
- Phase 2: ワークフロー統合(CI/CD・品質チェック)
- Phase 3: 組織最適化(メトリクス・継続改善)
チーム規模別戦略:
- 小規模チーム: 最小限の標準化
- 中規模チーム: 包括的なガイドライン
- 大規模組織: 厳格なポリシーとコンプライアンス
自動化による効率化:
- ワンクリック環境セットアップ
- 新人オンボーディング自動化
- 品質保証の自動化
- メトリクス収集・分析
導入の進め方
- 現状分析: チームの規模・スキルレベル・課題の把握
- 段階的導入: 小さく始めて徐々に拡張
- 継続的改善: メトリクス収集による定量的な改善
- 文化醸成: 標準化の価値を共有し、チーム全体で推進
成功の指標
- 新人の環境構築時間: 1日 → 30分以内
- 環境起因のトラブル: 月10件 → 月1件以下
- コードレビューの効率: レビュー時間30%短縮
- チーム全体の開発速度: 20-40%向上
次のステップ
チーム標準化をマスターしたら、最新のコンテナ技術動向についても学習することをお勧めします:
- 次世代コンテナ技術動向と代替ツール比較 – 次回公開予定
効果的なチーム標準化により、個人の生産性向上だけでなく、組織全体の開発効率と品質を大幅に向上させることができます。
関連記事: