🤝 Practices✍️ Khoa📅 19/04/2026☕ 11 phút đọc

Technical Writing & Proposals 📝

Một kỹ sư giỏi mà viết tài liệu kém thì impact của họ bị giới hạn bởi những gì họ có thể làm trong 8 giờ làm việc. Một kỹ sư biết viết tốt có thể tạo ra ảnh hưởng qua documentation, proposals, và RFC — ngay cả khi đang ngủ.


1. Vì sao kỹ năng viết quan trọng hơn bạn nghĩ

Trong thế giới remote và hybrid, viết đã thay thế 70% giao tiếp bằng lời. Mọi thứ xảy ra trên Slack, Email, Notion, GitHub comments. Người viết rõ ràng, súc tích sẽ có ảnh hưởng lớn hơn nhiều so với người chỉ giỏi thuyết trình trong phòng họp.

Ở cấp bậc Senior → Staff → Principal, tỉ lệ ảnh hưởng thông qua viết tăng dần:

  • Junior/Mid: 80% qua code, 20% qua viết/nói
  • Senior: 60% qua code, 40% qua viết/nói/design
  • Staff/Principal: 30% qua code, 70% qua writing, proposals, architecture decisions

2. Technical Design Document (TDD)

TDD là tài liệu bạn viết trước khi code để align cả team về hướng đi. Không phải mọi feature đều cần TDD — nhưng bất kỳ thứ gì phức tạp, ảnh hưởng nhiều team, hoặc không thể dễ dàng rollback thì rất nên có.

Khi nào cần viết TDD?

✅ Cần TDD khi:

  • Feature affect nhiều services hoặc team
  • Có multiple viable approaches cần so sánh
  • Change database schema phức tạp
  • Tích hợp với external system mới
  • Performance-sensitive feature
  • Feature liên quan đến security, auth, payments

❌ Không cần TDD khi:

  • Bug fix đơn giản
  • UI tweak không ảnh hưởng business logic
  • Thêm endpoint CRUD đơn giản theo existing pattern

Template TDD thực chiến

# TDD: [Tên tính năng]

**Author:** [Tên bạn]
**Date:** YYYY-MM-DD
**Status:** Draft | In Review | Approved | Superseded
**Reviewers:** [Danh sách người review]

---

## 1. Context & Problem Statement
<!-- Vì sao chúng ta cần tính năng này? Bức tranh lớn là gì? -->
<!-- Business impact nếu không làm là gì? -->

## 2. Goals & Non-Goals
**Goals:**
- [ ] Điều hệ thống sẽ làm được sau khi implement

**Non-Goals (Không nằm trong scope lần này):**
- Những thứ liên quan nhưng sẽ không làm để giữ scope nhỏ

## 3. Proposed Solution

### High-level Architecture
<!-- Diagram: sequence diagram, data flow, component diagram -->

### API Design
<!-- Endpoint, request/response schema, error codes -->

### Data Model Changes
<!-- Schema migration nếu có -->

### Key Algorithms or Logic
<!-- Pseudocode hoặc mô tả luồng xử lý phức tạp -->

## 4. Alternatives Considered
### Option A: [Approach bạn không chọn]
**Pros:** ...
**Cons:** Lý do không chọn...

### Option B: [Approach bạn không chọn]
...

## 5. Trade-offs & Risks
| Risk | Probability | Impact | Mitigation |
|------|-------------|--------|------------|
| [Risk 1] | Medium | High | [Cách giảm thiểu] |

## 6. Implementation Plan
- [ ] Phase 1: ... (ước tính X ngày)
- [ ] Phase 2: ... (ước tính Y ngày)
- [ ] Rollout plan, feature flag strategy

## 7. Open Questions
- [ ] [Question 1 cần ai đó trả lời trước khi tiến hành]
- [ ] [Question 2]

## 8. References
- Link đến ticket, existing docs, external resources liên quan

Tips viết TDD hiệu quả

  • Viết draft nhanh, refine sau: Đừng cố viết perfect ngay từ đầu. Viết draft trong 1-2 giờ, share để nhận feedback, rồi refine.
  • Diagram > text: Một sequence diagram hay data flow diagram truyền đạt được trong 30 giây những gì cần 3 đoạn text để giải thích.
  • "Killed Darlings": Phần Alternatives Considered rất quan trọng — nó cho thấy bạn đã cân nhắc kỹ càng và tại sao approach được chọn là tốt nhất.
  • Track decisions: Khi team đã đồng ý thay đổi một phần design, update TDD và ghi lại lý do. 6 tháng sau khi ai đó hỏi "Sao lại làm thế này?", bạn có câu trả lời.

3. RFC (Request for Comments) — Đề xuất thay đổi lớn

RFC là tài liệu dùng để đề xuất thay đổi có tầm ảnh hưởng rộng và gather feedback trước khi commit. Khác với TDD (tập trung vào implementation), RFC tập trung vào "chúng ta có nên làm cái này không và làm thế nào".

Khi nào cần RFC?

  • Thay đổi công nghệ cốt lõi (đổi DB engine, message broker, auth system)
  • Thay đổi engineering process (branching strategy, code review policy)
  • Breaking API changes ảnh hưởng nhiều consumer
  • Thay đổi kiến trúc hệ thống (migrate sang microservices, adopt event-driven)

RFC Process hiệu quả

1. Draft (1-2 ngày):
   Author viết RFC draft, share với 2-3 "trusted reviewers" để sanity check

2. Review period (3-7 ngày):
   Post lên channel chung, mọi người để lại comments
   Author phải respond mọi comment (agree/disagree + why)

3. Decision meeting (30-60 phút):
   Chỉ cần họp nếu còn unresolved disagreements
   
4. Outcome: Accepted | Rejected | Needs Revision
   Ghi rõ decision + reasoning để lưu làm "historical record"

Viết RFC thuyết phục

Sai lầm phổ biến nhất khi viết RFC là trình bày quá thiên về kỹ thuật và quên mất business context. Người approve RFC thường không phải là người kỹ thuật sâu nhất — họ cần hiểu "tại sao điều này quan trọng với business".

Structure để thuyết phục:

  1. Bắt đầu bằng Problem (đau điểm cụ thể, có metric nếu có)
  2. Trình bày Solution ở high-level trước, detail sau
  3. Đưa Evidence — benchmark, case study từ công ty tương tự
  4. Address "What if we don't do this?" — Cost of inaction
  5. Làm Trade-offs rõ ràng — không có giải pháp hoàn hảo, hãy honest

4. Async Communication — Nghệ thuật giao tiếp không cần họp

"No Hello" — Đừng nhắn ping cộc lốc

Khi nhắn tin vào Slack/Teams cho đồng nghiệp, đừng chỉ gõ "Hi" rồi đợi. Người kia phải bỏ dở công việc để "Hi lại" trong khi vẫn chưa biết bạn cần gì. Đây được gọi là "Hello Problem" — rất phổ biến và rất phiền.

Thay vào đó, hãy nhắn một câu hoàn chỉnh:

❌ "Anh ơi" ✅ "Anh ơi, function calculateTax() trong billing/service.go đang trả về sai khi discount > 100%. Em đã reproduce được với test case này [link]. Anh có biết context của function này không? Em đang không chắc là logic discount có intentional không."

Format tin nhắn tốt cho technical issue:

[Context]: Mô tả ngắn bạn đang làm gì
[Problem]: Vấn đề cụ thể đang gặp
[What you tried]: Bạn đã thử cách nào rồi
[What you need]: Bạn cần gì - thông tin? Review? Decision?
[Urgency]: Blocking bạn ngay bây giờ? Hay có thể đợi?

Meeting as Last Resort

Trước khi schedule một cuộc họp, hãy tự hỏi:

  • Vấn đề này có thể giải quyết bằng một Slack thread không?
  • Hay bằng một shared document với comments?
  • Có cần real-time discussion hay có thể async?

Khi bắt buộc phải họp:

  • Pre-read required: Gửi tài liệu/agenda ít nhất 24h trước. Thời gian họp dùng để discuss, không phải để đọc.
  • Decision-focused: Mỗi meeting nên kết thúc với ít nhất 1 decision rõ ràng được record lại.
  • Time-boxed: Đặt đồng hồ. Meeting 30 phút phải xong trong 30 phút.
  • Meeting notes: Gửi summary trong vòng 1 giờ sau meeting: decisions made, action items, owners, deadlines.

Viết để người đọc không cần hỏi lại

Khi viết email, Slack message, hay document, hãy tự hỏi:

"Sau khi đọc xong, người nhận có cần hỏi thêm câu nào không?"

Nếu có, hãy anticipate và trả lời ngay trong message ban đầu. Mỗi ping-pong Slack có thể tốn 30-60 phút clock time vì context switching của cả hai người.


5. Status Reports & Báo cáo tiến độ

Weekly Status Update

Format chuẩn, dễ đọc cho manager/stakeholders:

## Week of [Date] — [Tên dự án]

### ✅ Done this week
- Feature X: Đã merge, đang ở Staging
- Bug Y: Root cause found, fix in PR #123

### 🔄 In Progress
- Feature Z: 70% done, expected by [date]
- Technical debt refactor: Blocked on [dependency]

### 🚧 Blockers / Risks
- Chờ API contract từ Team B (ETA: Thursday)
- If not unblocked by Friday → Feature Z sẽ slip sang tuần sau

### 📅 Plan next week
- Finish Feature Z
- Start Feature A (new)

Gửi format này định kỳ (Friday afternoon), manager sẽ appreciate rất nhiều vì không cần ping hỏi.

Escalate sớm và rõ ràng

Khi gặp vấn đề cần sự quyết định từ cấp trên, đừng chỉ nói "bị block". Hãy cung cấp Options:

"Tích hợp với Payment Provider X đang bị chậm vì doc của họ thiếu. Tôi có 3 options:

  • Option 1: Đợi họ update doc (ETA: 1 tuần, chắc chắn hơn)
  • Option 2: Tôi tự reverse-engineer API thông qua Postman (ETA: 2 ngày, có risk)
  • Option 3: Tạm dùng Provider Y làm backup (ETA: 3 ngày, phức tạp hơn về contract)

Tôi lean về Option 1 nhưng cần confirm với anh về timeline."


6. Brag Document — Thứ cứu bạn trong Performance Review

Tại sao cần Brag Document

Trong Performance Review, memory của bạn (và manager) về những gì đã xảy ra 6-12 tháng trước rất không chính xác. Những thành tích nhỏ nhưng quan trọng sẽ bị quên. Những thứ gần đây sẽ được nhớ nhiều hơn (Recency Bias).

Brag Document giải quyết vấn đề này bằng cách track mọi thứ trong năm.

Format Brag Document

# Brag Document — [Tên bạn] — [Năm]

## Major Projects
### [Project Name] — Q1 2025
- **Impact:** Giảm latency từ 800ms → 120ms
- **What I did:** Redesign caching layer, implement Redis pipeline
- **Metrics:** p99 latency giảm 85%, tiết kiệm $2,000/tháng server cost
- **Evidence:** [Link to PR, monitoring dashboard]

## Bug Fixes & Reliability
- [Bug] Fixed memory leak trong worker pool gây OOM mỗi 3 ngày
- **Impact:** 100% uptime trong 2 tháng sau fix

## Mentorship & Leadership
- Mentored 2 junior engineers; cả hai đã independent sau 60 ngày
- Lead technical design cho Feature X
- Conducted 15 code reviews trong Q2

## Learning & Growth
- Completed Kubernetes Certification (CKA)
- Presented talk về "Go Concurrency Patterns" tại internal tech talk

## Process Improvements
- Proposed và implement automated deployment pipeline
- **Impact:** Deploy time giảm từ 45 phút → 8 phút

## Collaboration
- [Tên người/team] đã đề cập contribution của mình trong...

Thói quen cập nhật Brag Document

  • Cập nhật ngay sau khi xảy ra, không phải trước Performance Review.
  • Mỗi khi merge một PR quan trọng, spend 2 phút ghi vào Brag Document.
  • Lưu evidence: screenshots, metrics, Slack messages khen ngợi, email feedback.

7. Viết Comments trong Code

Code comments là một dạng technical writing thường bị xem thường.

Khi nào viết comment

✅ Nên comment khi:

  • Explain the "Why", not the "What": Code đã nói "what", comment nên nói "why".
  • Workaround cho bug/limitation của library bên thứ ba (kèm link issue tracker nếu có).
  • Constant/magic number cần context: const RETRY_MAX = 5 // Aligned with Stripe's webhook retry policy
  • Complex algorithm — mô tả tóm tắt approach và reference paper/blog nếu có.

❌ Không cần comment khi:

  • Code đã tự rõ: // Get user by ID trước getUserByID()
  • Commented-out code không còn dùng — hãy delete, Git lưu lịch sử cho bạn.

Comment chất lượng cao vs thấp

// ❌ Thấp: mô tả lại what, không add value
// Calculate discount
func calculateDiscount(price float64) float64 {
    return price * 0.1
}

// ✅ Cao: giải thích why và business context
// 10% discount aligns with the 2024 Q4 loyalty program (see JIRA-1234).
// This is intentionally hardcoded, not config-driven,
// because marketing needs to approve any change through product process.
func calculateLoyaltyDiscount(price float64) float64 {
    return price * 0.1
}

8. Documentation as Code — Docs sống cùng code

Tại sao docs thường outdated

Docs tách biệt khỏi code → bị bỏ quên khi code thay đổi. Giải pháp: Docs gần với code nhất có thể.

Các pattern phổ biến:

  • README.md ngay trong thư mục service/module
  • API docs auto-generate từ code annotations (Swagger/OpenAPI)
  • Architecture Decision Records (ADR) trong /docs/adr/ của repo
  • Runbook (hướng dẫn xử lý incident) ngay trong codebase, không phải Confluence cách đó 5 clicks

Architecture Decision Records (ADR)

ADR là file nhỏ, format đơn giản, ghi lại các quyết định kiến trúc quan trọng:

# ADR-001: Sử dụng PostgreSQL thay vì MongoDB

**Date:** 2024-01-15
**Status:** Accepted

## Context
Cần chọn database cho Order Management System. 
Data có nhiều relationship (User → Order → OrderItem → Product).

## Decision
Chọn PostgreSQL.

## Consequences
- ✅ Strong consistency với ACID transactions cho order flow
- ✅ Team đã familiar với SQL
- ❌ Cần design schema cẩn thận hơn so với document DB
- ❌ Schema migration phức tạp khi schema thay đổi

## Alternatives Considered
MongoDB: Ruled out vì data model của chúng ta naturally relational.

Lợi ích: 6 tháng sau khi ai đó hỏi "Sao dùng Postgres mà không dùng Mongo?", bạn có câu trả lời đầy đủ thay vì "Ừ hồi đó team quyết vậy, không nhớ tại sao".