なぜ README が重要か
README はリポジトリをクローンした瞬間に開発者が最初に目にするドキュメントです。 「このプロジェクトは何をするのか」「どうやって動かすのか」「自分はどこから手をつければよいか」——この3問に素早く答えられる README は、オンボーディングコストを大幅に下げます。
逆に、README がない・古い・情報が散在している状態では、新メンバーが環境構築だけで半日を溶かすことになります。経験上、「README を整備するコスト」と「新メンバーが迷うコスト × 人数」を比較すると、後者が圧倒的に大きいケースがほとんどです。
💡 README の位置づけ
README はプロジェクトの「入口ドキュメント」です。詳細はリンク先の設計書・Wiki に委譲し、README 自体はなるべく短く保つことが腐りにくさにつながります。
① プロジェクト概要(What / Why)
冒頭の数行で「このリポジトリが何をするものか」を説明します。定義すべき項目は次のとおりです。
| 項目 | 内容 | 記述例 |
|---|---|---|
| プロジェクト名 | リポジトリ名と一致させる | ## my-app |
| 一行説明 | 何をするツール・サービスか | 社内注文管理システムの REST API サーバー |
| 背景・目的 | なぜ作ったのか(Why) | 既存の CSV 手作業を自動化するため |
| 主要機能 | 箇条書き3〜5件 | 注文登録・更新・キャンセル・CSV エクスポート |
| 関連リポジトリ | フロントエンド・インフラなど | my-app-frontend / my-app-infra |
⚠️ 「何をしないか」も書く
スコープを明確にするため、非対応機能や対象外ユーザーを1〜2行で書いておくと誤解が減ります。例:「決済処理は別サービス(payment-api)が担当します」
② 動作要件・前提条件
「動かない」問い合わせの多くは環境差異に起因します。以下の項目を明示してください。
| カテゴリ | 定義すべき内容 |
|---|---|
| ランタイム | 言語バージョン(例: Python 3.11 以上、Node 20 LTS) |
| OS | 動作確認済み OS(Windows 11 / Ubuntu 22.04 / macOS 14) |
| 外部ツール | Docker 24 以上・git 2.40 以上 など |
| 外部サービス | DB(PostgreSQL 15)・Redis 7・S3 互換ストレージなど |
| ネットワーク | 特定 IP レンジへのアクセスが必要な場合 |
③ インストール手順
コピー&ペーストで実行できるコマンド列を記載します。省略や「など」は禁物です。 番号付きリストで順序を明示し、各ステップの「何をしているか」を1行コメントで補足します。
## インストール
### 1. リポジトリをクローン
```bash
git clone https://github.com/example/my-app.git
cd my-app
```
### 2. 依存パッケージのインストール
```bash
pip install -r requirements.txt
```
### 3. 環境変数の設定
```bash
cp .env.example .env
# .env を編集してください(次のセクションを参照)
```
### 4. データベースのマイグレーション
```bash
python manage.py migrate
```
### 5. 起動
```bash
python manage.py runserver
# → http://localhost:8000 でアクセス可能
```
✅ 手順は「新入メンバーが 0 から実行することを想定」して書く
「pip はインストール済みの前提」のような暗黙の前提は必ず明示するか、公式インストールガイドへのリンクを貼ってください。
④ 使い方(Quick Start)
最も頻繁に使われる操作を3〜5パターン示します。全機能の網羅は不要——それは別のドキュメント(API仕様書・ユーザーガイド)の役割です。
| パターン | 記述すべき内容 |
|---|---|
| 基本的な使い方 | 最もシンプルな実行例(コマンド+出力) |
| よく使うオプション | --verbose / --config など主要フラグの説明 |
| スクリーンショット / GIF | GUI ツールや CLI の視覚的な操作感 |
| サンプルデータ | 動作確認用のサンプルファイル・シードの場所 |
⑤ 設定・環境変数一覧
.env.example ファイルとセットで管理します。README には変数名・型・デフォルト値・用途を表形式で掲載します。
実際の値(シークレット)を README に絶対に書かないことが鉄則です。
## 環境変数
| 変数名 | 型 | デフォルト | 説明 |
|---|---|---|---|
| `DATABASE_URL` | string | — | PostgreSQL 接続文字列(必須) |
| `SECRET_KEY` | string | — | Django シークレットキー(必須) |
| `DEBUG` | bool | `false` | デバッグモード。本番では `false` にすること |
| `ALLOWED_HOSTS` | string | `localhost` | カンマ区切りで許可ホストを指定 |
| `CACHE_TTL` | int | `300` | Redis キャッシュ TTL(秒) |
⑥ ディレクトリ構成
プロジェクトルートの主要ディレクトリと役割を記載します。深いネストは省略し、初見の人が「どこに何があるか」を把握できるレベルに留めます。
## ディレクトリ構成
```
my-app/
├── src/ # アプリケーション本体
│ ├── api/ # REST API エンドポイント
│ ├── models/ # データモデル
│ └── utils/ # 共通ユーティリティ
├── tests/ # テストコード
├── docs/ # 設計書・ADR
├── scripts/ # 運用・開発補助スクリプト
├── .env.example # 環境変数のテンプレート
└── requirements.txt
```
⑦ コントリビュート・ライセンス
社内プロジェクトでも「コントリビュートガイド」と「ライセンス」を明記することで、変更の進め方(ブランチ戦略・PR ルール・レビュアー)が共有されます。
| 項目 | 記述すべき内容 |
|---|---|
| ブランチ戦略 | main / develop / feature/* などの命名規則と用途 |
| PR ルール | テスト必須・レビュアー最低1名・コミットメッセージ形式など |
| コーディング規約 | linter・formatter の設定ファイルへのリンク |
| Issue テンプレート | バグ報告・機能要望のテンプレートへのリンク |
| ライセンス | MIT / Apache-2.0 / 社内プロプライエタリなど |
| 連絡先 | 担当チームの Slack チャンネルやメールアドレス |
Python で実機情報を自動収集する
README に記載するバージョン情報・ディレクトリ構成は手書きすると必ず陳腐化します。 以下のスクリプトで実機から情報を自動収集し、README のドラフトを生成できます。
① 依存パッケージ一覧を自動取得
"""
requirements.txt を読み込んでバージョン表を生成する。
README の「動作要件」セクションに貼り付ける用途。
"""
import subprocess
import sys
def get_installed_versions(req_file: str = "requirements.txt") -> list[dict]:
"""pip show で各パッケージの実際のバージョンを取得する。"""
with open(req_file, encoding="utf-8") as f:
packages = [
line.strip().split("==")[0].split(">=")[0].split("~=")[0]
for line in f
if line.strip() and not line.startswith("#")
]
results = []
for pkg in packages:
try:
out = subprocess.check_output(
[sys.executable, "-m", "pip", "show", pkg],
stderr=subprocess.DEVNULL,
text=True
)
info = {}
for line in out.splitlines():
if ": " in line:
key, val = line.split(": ", 1)
info[key.strip()] = val.strip()
results.append({
"name": info.get("Name", pkg),
"version": info.get("Version", "不明"),
"summary": info.get("Summary", ""),
})
except subprocess.CalledProcessError:
results.append({"name": pkg, "version": "未インストール", "summary": ""})
return results
def print_markdown_table(packages: list[dict]) -> None:
print("| パッケージ | バージョン | 説明 |")
print("|---|---|---|")
for p in packages:
print(f"| `{p['name']}` | {p['version']} | {p['summary']} |")
if __name__ == "__main__":
pkgs = get_installed_versions()
print_markdown_table(pkgs)
② ディレクトリ構成を自動生成
"""
プロジェクトのディレクトリ構成を README 用に出力する。
深さ・除外パターンを設定できる。
"""
import os
from pathlib import Path
EXCLUDE = {".git", "__pycache__", ".venv", "venv", "node_modules", ".pytest_cache"}
MAX_DEPTH = 3
def print_tree(path: Path, prefix: str = "", depth: int = 0) -> None:
if depth > MAX_DEPTH:
return
entries = sorted(
[e for e in path.iterdir() if e.name not in EXCLUDE],
key=lambda e: (e.is_file(), e.name)
)
for i, entry in enumerate(entries):
connector = "└── " if i == len(entries) - 1 else "├── "
print(prefix + connector + entry.name + ("/" if entry.is_dir() else ""))
if entry.is_dir():
extension = " " if i == len(entries) - 1 else "│ "
print_tree(entry, prefix + extension, depth + 1)
if __name__ == "__main__":
root = Path(".")
print(f"```\n{root.resolve().name}/")
print_tree(root)
print("```")
③ git 情報から最終更新日・コントリビュータを取得
"""
git log からプロジェクトのメタ情報を収集する。
README の「最終更新日」「主要コントリビュータ」欄の自動更新に使う。
"""
import subprocess
from collections import Counter
from datetime import datetime
def run_git(*args) -> str:
result = subprocess.run(
["git", *args], capture_output=True, text=True, check=True
)
return result.stdout.strip()
def get_last_commit_date() -> str:
"""最新コミット日時(ISO 形式)を返す。"""
iso = run_git("log", "-1", "--format=%cI")
dt = datetime.fromisoformat(iso)
return dt.strftime("%Y年%m月%d日")
def get_top_contributors(n: int = 5) -> list[tuple[str, int]]:
"""コミット数上位 n 名を返す。"""
log = run_git("log", "--format=%aN")
counter = Counter(log.splitlines())
return counter.most_common(n)
def get_current_branch() -> str:
return run_git("rev-parse", "--abbrev-ref", "HEAD")
def get_tag_list() -> list[str]:
"""最新5タグを返す(バージョン履歴に使う)。"""
tags = run_git("tag", "--sort=-creatordate")
return tags.splitlines()[:5]
if __name__ == "__main__":
print(f"最終更新: {get_last_commit_date()}")
print(f"現在のブランチ: {get_current_branch()}")
print("\n## コントリビュータ(コミット数上位)")
for name, count in get_top_contributors():
print(f"- {name}: {count} commits")
print("\n## 最新タグ")
for tag in get_tag_list():
print(f"- {tag}")
README のアンチパターン
| アンチパターン | 何が問題か | 対策 |
|---|---|---|
| 手順が省略されている | 「適宜設定してください」で詰まる人が続出する | コピペで動くレベルまで具体化する |
| バージョンが固定されていない | 「Python インストール済みの前提」で動かない | マイナーバージョンまで明記(Python 3.11.x) |
| README が設計書の代わりになっている | 長すぎて誰も読まなくなる | 詳細は docs/ や Wiki にリンクする |
| 更新されない | 手順を試したらエラーになる | PR マージ時に「README 更新チェック」を必須にする |
| シークレットが含まれている | 公開リポジトリに漏洩するリスク | .env.example に記載し、値は .env(gitignore)で管理 |
まとめ:README チェックリスト
✅ README に最低限含めるべき7項目
□ プロジェクト概要(What / Why)
□ 動作要件(言語バージョン・外部ツール・OS)
□ インストール手順(コピペで動く番号付きコマンド列)
□ 使い方 Quick Start(最もシンプルな実行例)
□ 環境変数一覧(.env.example とセット、シークレットは書かない)
□ ディレクトリ構成(主要フォルダの役割)
□ コントリビュート方法とライセンス
これらの項目を揃えるだけで、新メンバーのオンボーディング時間は大幅に短縮されます。 Python スクリプトを CI に組み込んで README の自動チェック・自動更新を仕組み化すると、陳腐化リスクをさらに下げられます。