Cách Mình Viết Documentation

Changelog, README, và cách cung cấp ngữ cảnh cho AI lẫn con người

Documentation là cách mình ghi nhớ đã xây cái gì và tại sao. Cũng là cách cho Claude Code (và đồng đội tương lai) ngữ cảnh để hỗ trợ hiệu quả.

Nguyên tắc cốt lõi: Viết cho chính mình 6 tháng sau -- người đã quên sạch mọi thứ.

Tại sao quan trọng

Không có docsCó docs
"Cái này hoạt động thế nào nhỉ?"Đọc README
"Sao mình xây kiểu này?"Xem PRD
"v1.2 thay đổi gì?"Xem CHANGELOG
Claude Code đoán mòClaude Code đọc context

Cấu trúc docs

Project/
├── README.md          ← Đây là gì, cách chạy
├── CHANGELOG.md       ← Thay đổi gì và khi nào
├── docs/
│   ├── PRD.md        ← Đang xây gì và tại sao
│   └── ARCHITECTURE.md ← Hệ thống hoạt động thế nào (tuỳ chọn)
└── src/
    └── [code với comment khi cần]

README.md

Điểm đầu tiên ai đó nhìn vào dự án. Trong 30 giây phải hiểu đây là gì và cách chạy.

Template

# Tên Dự Án

Mô tả một câu về cái này làm gì.

## Tính năng
- Tính năng 1
- Tính năng 2

## Tech Stack
- NextJS 14
- Supabase
- DataForSEO API

## Bắt đầu

### Yêu cầu
- Bun 1.0+
- Tài khoản Supabase
- DataForSEO API credentials

### Cài đặt
\`\`\`bash
git clone https://github.com/your-org/project-name
cd project-name
bun install
cp .env.example .env.local
# Chỉnh .env.local
bun run dev
\`\`\`

### Biến môi trường
| Biến | Mô tả | Bắt buộc |
|------|--------|----------|
| SUPABASE_URL | URL dự án Supabase ||
| SUPABASE_ANON_KEY | Anon key Supabase ||

## Cấu trúc
\`\`\`
src/
├── app/           # Pages
├── components/    # React components
├── lib/           # Utilities
└── types/         # TypeScript types
\`\`\`

## Development
\`\`\`bash
bun run dev      # Dev server
bun run build    # Production build
bun run lint     # Linter
\`\`\`

## Deployment
Deploy qua Railway. Push lên main tự động deploy.
NênKhông nên
Cập nhật khi dự án thay đổiĐể lỗi thời
Liệt kê tất cả env varsAssume người ta biết
Command copy-paste đượcBắt tự tìm hiểu
Phản ánh thực tếDocument tính năng chưa có

CHANGELOG.md

Theo dõi thay đổi gì và khi nào. Cần thiết để debug ("cái này hỏng từ khi nào?") và giao tiếp ("tuần này ship gì?").

Dùng format Keep a Changelog:

# Changelog

## [Unreleased]

### Added
- Export kết quả ra CSV
- Progress indicator trong lúc clustering

### Changed
- Cải thiện thông báo lỗi cho API failure

### Fixed
- Timeout clustering cho dataset lớn

## [1.0.0] - 2024-01-15

### Added
- Upload keyword qua CSV
- Clustering HDBSCAN
- Hiển thị kết quả với nhãn cluster
- Tích hợp DataForSEO cho embeddings
Danh mụcDùng cho
AddedTính năng mới
ChangedThay đổi tính năng có sẵn
DeprecatedSắp bị loại bỏ
RemovedĐã loại bỏ
FixedSửa bug
SecuritySửa lỗi bảo mật

Cập nhật trước khi merge PR. Viết cho người dùng, không phải commit log.

Context cho AI

Claude Code hoạt động tốt hơn nhiều khi có context. File CLAUDE.md ở root dự án:

# Claude Context cho [Tên Dự Án]

## Tổng quan
Tool keyword clustering cho SEO. User upload keywords,
cluster bằng HDBSCAN, hiển thị kết quả.

## Tech Stack
- NextJS 14 with App Router
- Supabase for database
- FastAPI for ML processing
- OpenAI for embeddings

## Patterns

### API Route
Nằm trong src/app/api/. Dùng NextJS route handler.

### Database
Supabase. Schema trong supabase/migrations/.
Luôn parameterized query, không nối chuỗi.

### Components
src/components/. Shadcn UI.
Import từ @/components/ui/ cho base components.

## Task thường gặp

### Thêm API endpoint
1. Tạo src/app/api/[name]/route.ts
2. Export GET, POST, v.v.
3. Thêm auth check nếu cần

## Không được
- Commit .env
- Dùng type any
- Bỏ qua error handling cho API calls
- Hardcode API URLs

## Đang làm
Tính năng export. Xem issue #45.

Comment trong code

Comment khi "tại sao" không rõ ràng từ code:

// Tốt: giải thích lý do
// Giảm chiều trước khi cluster vì HDBSCAN
// hoạt động kém trong không gian chiều cao (curse of dimensionality)
const reducedEmbeddings = await reduceDimensions(embeddings, 50);

// Tệ: giải thích cái đã rõ từ code
// Giảm chiều xuống 50
const reducedEmbeddings = await reduceDimensions(embeddings, 50);

// Tốt: giải thích hành vi bất thường
// DataForSEO trả về field name không nhất quán, chuẩn hoá ở đây
const normalizedResults = results.map(r => ({
  keyword: r.keyword || r.search_query,
  ...
}));

Dùng JSDoc cho function phức tạp:

/**
 * Cluster keywords bằng HDBSCAN.
 *
 * @param keywords - Mảng keyword string
 * @param options - Cấu hình clustering
 * @param options.minClusterSize - Tối thiểu mỗi cluster (mặc định: 5)
 * @returns Promise trả về kết quả đã cluster
 */
async function clusterKeywords(
  keywords: string[],
  options: ClusterOptions = {}
): Promise<ClusterResult[]> {
  // ...
}

Khi nào cập nhật docs

Sự kiệnCập nhật gì
Ship tính năng mớiREADME (nếu user-facing), CHANGELOG
Cấu trúc thay đổiREADME, CLAUDE.md
Thêm env varREADME, .env.example
Sửa bugCHANGELOG
Refactor lớnCLAUDE.md, có thể ARCHITECTURE.md

Trước khi ship:

  • README khớp thực tế
  • CHANGELOG có entry
  • .env.example có biến mới
  • CLAUDE.md phản ánh pattern hiện tại

Những lỗi hay gặp

Viết docs một lần rồi quên -- README ghi "Coming soon" từ 6 tháng trước. Cập nhật docs như một phần của PR.

Document code hiển nhiên -- // tăng counter lên 1 bên cạnh counter++. Document tại sao, không phải cái gì.

Không document hành vi bất thường -- "Sao API trả về null ở đây?" mà không có comment. Nếu mình phải suy nghĩ về lý do thì nên document.

Không cung cấp context cho AI -- Claude Code lặp lại cùng sai lầm. Tạo CLAUDE.md với pattern và ràng buộc.

Checklist

Ổn nếu:

  • Người mới setup dự án được từ README
  • Nhớ được đã ship gì từ CHANGELOG
  • Claude Code hiểu pattern của dự án
  • Comment giải thích quyết định bất thường
  • Docs cập nhật cùng code

Cần sửa nếu:

  • README không khớp thực tế
  • Không biết tháng trước ship gì
  • Claude Code lặp lại sai lầm
  • Code không có context cho phần kỳ lạ
  • Thư mục docs trống hoặc lỗi thời

Tham khảo nhanh

FileMục đíchCập nhật khi
README.mdTổng quan dự ánSetup thay đổi
CHANGELOG.mdLịch sử versionMỗi PR/release
.env.exampleTemplate env varsBiến thay đổi
CLAUDE.mdContext cho AIPattern thay đổi