Mở đầu — vì sao bài này quan trọng
Hãy hình dung một buổi sprint planning điển hình ở nhiều công ty Việt Nam: PM mang vào một danh sách tính năng, team "ước lượng" qua loa bằng story point, rồi tất cả gật đầu cam kết. Hai tuần sau, sprint trượt. Lý do quen thuộc: "Có incident production phải xử lý", "Phần này phụ thuộc API của team khác chưa xong", "Migration database lâu hơn dự kiến". Và rồi mọi người tự an ủi rằng "lần sau sẽ ước lượng chính xác hơn".
Vấn đề là: phần lớn các sprint trượt KHÔNG phải vì ước lượng sai, mà vì kế hoạch bỏ qua các ràng buộc kỹ thuật (technical constraints) ngay từ đầu. Một Technical PM giỏi không chỉ biết team chạy nhanh bao nhiêu, mà còn biết team thực sự có bao nhiêu thời gian để code, công việc nào bị chặn bởi dependency, đâu là rủi ro kỹ thuật chưa lường được, và phần nào của hệ thống "đụng vào là nguy hiểm".
Bài này tập trung đúng vào điều đó: lập kế hoạch sprint dưới các ràng buộc kỹ thuật thực tế. Chúng ta sẽ phân biệt rõ capacity với velocity (một nhầm lẫn kinh điển), học cách đưa dependency, tech debt, on-call và rủi ro vào kế hoạch một cách định lượng. Đây không phải bài về cách ước lượng (Bài 14 đã lo), cũng không phải về cách chẻ nhỏ story (Bài 16 sẽ lo), mà là về việc ghép tất cả lại thành một cam kết sprint thực tế và đáng tin.
Khái niệm cốt lõi
Capacity, không phải velocity
Đây là điểm khởi đầu quan trọng nhất, và cũng là chỗ nhiều PM hiểu sai.
Velocity là một chỉ số lịch sử: trung bình team hoàn thành bao nhiêu story point mỗi sprint trong vài sprint gần nhất. Nó hữu ích để dự báo dài hạn (forecasting roadmap), nhưng nó là con số trung bình của quá khứ, không phản ánh sprint sắp tới có gì đặc biệt.
Capacity là chỉ số dự phóng cho sprint cụ thể này: team thực sự có bao nhiêu giờ developer ngồi code trong hai tuần tới. Và con số này thay đổi từng sprint vì có người nghỉ phép, có lễ, có người dính on-call, có ai đó dành nửa thời gian hỗ trợ team khác.
Công thức tư duy:
> Capacity = (số người × số ngày làm việc × giờ/ngày) − (meeting + support + on-call + nghỉ phép + buffer rủi ro)
Một sai lầm chết người là lấy nguyên 8 giờ/ngày × 10 ngày = 80 giờ/người rồi nhân lên. Trên thực tế, với team mature (đã ổn định, quy trình rõ ràng), tỉ lệ "giờ code thực sự" thường chỉ khoảng 60–65% thời gian làm việc. Phần còn lại trôi vào: standup, planning, retro, review, 1:1, trả lời câu hỏi của QA và team khác, đọc tài liệu, context-switching. Với team mới hoặc đang scale nhanh, con số này còn thấp hơn, có khi chỉ 45–50%.
Nói cách khác: một developer "full-time" trong sprint 2 tuần thường chỉ đóng góp khoảng 48–55 giờ code thực sự, không phải 80. Nếu bạn lập kế hoạch dựa trên 80, bạn đang tự cài đặt cho thất bại ngay từ buổi planning.
Ba loại ràng buộc kỹ thuật cần đưa vào kế hoạch
1. Dependency (phụ thuộc). Công việc A không thể bắt đầu cho tới khi B xong. Dependency có hai dạng:
- Nội bộ team: backend xong API thì frontend mới ráp được.
- Liên team / bên ngoài: chờ team Platform mở quyền, chờ vendor (ví dụ một cổng thanh toán như VNPay hay MoMo) cấp credential sandbox, chờ team Data dựng bảng event.
2. Technical debt và rủi ro kỹ thuật. Một số task chạm vào phần code cũ, không có test, hoặc kiến trúc phức tạp. Những task này có phương sai (variance) ước lượng rất cao — có thể xong trong 1 ngày, cũng có thể 5 ngày. (Việc quản lý và trao đổi tech debt sâu hơn thuộc Bài 52; ở đây ta chỉ quan tâm cách tính nó vào capacity của sprint.)
3. Reserved capacity (năng lực dành riêng). Đây là phần thời gian phải "khoá trước" cho những việc không thể tránh: on-call, xử lý bug production, hỗ trợ, và một buffer cho việc bất ngờ. Nếu team bạn có lịch sử mỗi sprint mất ~20% thời gian cho incident, thì việc giả vờ rằng sprint tới sẽ không có incident là tự lừa dối.
Cam kết (commitment) vs mục tiêu kéo dài (stretch)
Một kỹ thuật giúp sprint đáng tin hơn: chia backlog đã chọn thành hai nhóm. Commitment là phần team tự tin 90% sẽ xong — đây là lời hứa với stakeholder. Stretch là phần "nếu còn thời gian thì làm thêm". Cách này giúp bạn vừa giữ uy tín cam kết, vừa không để team rảnh tay khi mọi thứ suôn sẻ.
Tình huống thực tế
Ví dụ 1 — Tiki: bài học capacity bị thổi phồng
Một team thuộc một sàn thương mại điện tử lớn như Tiki (bối cảnh minh hoạ) gồm 5 backend engineer, lập kế hoạch cho sprint 2 tuần. Họ quen ước lượng 80 giờ/người, tức 400 giờ "lý thuyết", và nhồi backlog tương ứng.
Khi PM ngồi xuống tính capacity thật, bức tranh khác hẳn:
- 1 engineer đi on-call cả sprint → chỉ đóng góp ~50% thời gian code.
- 1 người nghỉ phép 2 ngày.
- Cả team có 6 buổi meeting cố định/tuần.
- Sprint rơi vào tuần có một ngày lễ.
Bài học: Trước khi bàn "làm được gì", phải chốt "có bao nhiêu giờ thật". Sau khi áp dụng công thức capacity và đặt reserved capacity 20% cho on-call/incident, team này giảm khối lượng cam kết xuống còn ~180 giờ và lần đầu tiên hoàn thành 95% sprint — đồng thời độ tin cậy với stakeholder tăng vọt vì họ "nói được làm được".
Ví dụ 2 — Một fintech: dependency liên team làm trượt sprint
Tại một công ty fintech (ví dụ một ví điện tử như VNPay/MoMo trong bối cảnh giả định), team Lending lên kế hoạch cho tính năng "duyệt khoản vay nhanh". Story chính: hiển thị hạn mức vay cho user. Team ước lượng 8 điểm, đưa vào commitment một cách tự tin.
Vấn đề ẩn: story này phụ thuộc vào một scoring API do team Risk sở hữu, mà API đó dự kiến chỉ sẵn sàng vào cuối tuần thứ nhất của sprint. Khi PM vẽ ra dependency graph trong buổi planning, vấn đề lộ rõ: frontend và phần tích hợp sẽ bị chặn (blocked) ít nhất 5 ngày làm việc, không thể bắt đầu sớm.
Họ xử lý bằng ba bước:
- Tách story: phần UI tĩnh và logic không phụ thuộc scoring API được tách ra làm trước với một mock response.
- Đặt cam kết với team Risk ngay trong sprint planning, ghi rõ ngày bàn giao API như một "dependency có chủ".
- Hạ phần tích hợp xuống stretch, vì nó phụ thuộc vào việc team khác giao đúng hạn — điều nằm ngoài tầm kiểm soát.
Bài học: Dependency liên team phải được nhận diện và đàm phán ngay tại buổi planning, không phải phát hiện ở ngày thứ 6. Một dependency không có người chịu trách nhiệm và không có ngày bàn giao cụ thể chính là một rủi ro trượt sprint đang chờ xảy ra.
Ví dụ 3 — Một startup SaaS: tech debt biến 3 ngày thành 8 ngày
Một startup SaaS B2B ở TP.HCM nhận task "thêm trường tax_code vào hoá đơn xuất khẩu". Trên giấy đây là task 3 ngày: thêm một cột, sửa form, cập nhật PDF.
Nhưng phần xuất hoá đơn là code legacy 4 năm tuổi, không có unit test, viết bởi một engineer đã nghỉ việc. Khi bắt tay vào, mỗi thay đổi nhỏ lại làm gãy một thứ khác không lường trước. Task kéo dài 8 ngày, nuốt trọn capacity của hai người và làm trượt ba story khác.
Lần sprint sau, PM thay đổi cách tiếp cận: với mọi task chạm vào vùng code rủi ro cao (legacy, không test, ít người hiểu), team gắn nhãn "high-variance" và áp dụng nguyên tắc đệm: lấy ước lượng lạc quan rồi nhân 2 khi tính vào capacity, đồng thời dành 1 ngày đầu để viết test bao quanh trước khi sửa. Họ cũng giới hạn không nhận quá một task high-variance mỗi sprint để rủi ro không cộng dồn.
Bài học: Không phải mọi story point đều bằng nhau về rủi ro. Một task "3 điểm" trong code sạch và một task "3 điểm" trong code legacy là hai con thú hoàn toàn khác nhau. Technical PM phải nhìn ra sự khác biệt đó và đưa phương sai vào kế hoạch, thay vì coi mọi điểm như nhau.
Hướng dẫn từng bước
Đây là quy trình 7 bước để chạy một buổi sprint planning có tính đến ràng buộc kỹ thuật:
Bước 1 — Tính capacity thật trước buổi planning. Lập bảng đơn giản: liệt kê từng người, số ngày làm việc thực (trừ phép, lễ), nhân với tỉ lệ "giờ code" thực tế của team (bắt đầu với 60% nếu chưa có dữ liệu). Cộng lại ra tổng giờ. Đây là trần cứng của sprint.
Bước 2 — Trừ reserved capacity. Trừ ngay phần dành cho on-call, hỗ trợ và buffer incident. Nếu lịch sử cho thấy team mất 15–20% cho việc ngoài kế hoạch, hãy trừ đúng số đó. Phần còn lại mới là capacity dành cho công việc theo kế hoạch.
Bước 3 — Vẽ dependency graph cho các story ứng viên. Với mỗi story sắp đưa vào, hỏi: "Cái gì phải xong trước thì nó mới bắt đầu được?" Đánh dấu mọi dependency liên team bằng màu đỏ. Với mỗi dependency đỏ, phải có tên người chịu trách nhiệm và ngày bàn giao cam kết.
Bước 4 — Gắn nhãn rủi ro kỹ thuật. Đánh dấu story nào chạm vào code legacy, thiếu test, hoặc cần spike (nghiên cứu trước). Với story high-variance, hoặc tạo một spike riêng để giảm bất định, hoặc nhân đôi phần đệm khi tính giờ.
Bước 5 — Lấp đầy capacity theo thứ tự ưu tiên, không phải theo mong muốn. Đưa story vào cho tới khi chạm trần capacity đã trừ reserve. Khi sắp đầy, dừng lại. Đây là lúc kỷ luật quan trọng nhất — cám dỗ "nhét thêm một cái nữa" luôn hiện diện.
Bước 6 — Chia commitment vs stretch. Phần chắc chắn xong → commitment. Phần phụ thuộc dependency bên ngoài hoặc high-variance → stretch. Stakeholder chỉ được nghe cam kết về phần commitment.
Bước 7 — Định nghĩa "sprint goal" một câu. Toàn bộ các story rời rạc nên phục vụ một mục tiêu rõ ràng (ví dụ: "User có thể xem được hạn mức vay"). Sprint goal giúp team biết bỏ gì khi phải cắt giảm giữa chừng mà không phá vỡ giá trị cốt lõi.
Lỗi thường gặp & mẹo
Lỗi 1: Lập kế hoạch theo velocity trung bình mà bỏ qua đặc thù sprint này. Velocity nói team trung bình làm 40 điểm, nhưng sprint này có 2 ngày lễ và 1 người on-call. Lấy 40 điểm là sai. Mẹo: luôn điều chỉnh theo capacity thực của sprint cụ thể, dùng velocity chỉ để forecasting dài hạn.
Lỗi 2: Lập kế hoạch ở 100% capacity. Để team ở mức tải tối đa nghĩa là bất kỳ sự cố nhỏ nào cũng làm trượt sprint. Mẹo: nhắm tới 80–85% capacity cho công việc đã cam kết. Phần dư không lãng phí — nó là tấm đệm chống lại thực tế hỗn loạn.
Lỗi 3: "Dependency để ý sau." Phát hiện dependency liên team ở giữa sprint thì đã quá muộn. Mẹo: biến việc rà dependency thành một bước bắt buộc trong planning, có checklist.
Lỗi 4: Coi mọi story point như nhau về rủi ro. Mẹo: phân biệt "điểm trong code sạch" và "điểm trong code legacy". Giới hạn số task high-variance mỗi sprint.
Lỗi 5: Bỏ quên on-call và support như thể chúng vô hình. Người đi on-call vẫn được tính như đóng góp 100% — đây là ảo tưởng phổ biến. Mẹo: mặc định người on-call chỉ đóng góp 40–60% capacity, và viết nó ra rõ ràng.
Lỗi 6: Im lặng khi bị stakeholder ép nhồi thêm. Mẹo: đừng tranh luận về ý chí — hãy đưa ra bảng capacity. "Chúng ta có 180 giờ, việc này cần 60 giờ; muốn thêm thì phải bỏ ra cái gì?" Con số biến cuộc tranh cãi cảm tính thành cuộc trao đổi đánh đổi.
Mẹo vàng: Sau mỗi sprint, so sánh capacity dự phóng với giờ code thực tế. Tỉ lệ giữa hai con số này (đôi khi gọi là "focus factor") chính là hệ số bạn nên dùng cho sprint sau. Sau 3–4 sprint, bạn sẽ có một con số capacity rất sát thực tế của riêng team mình — đáng giá hơn bất kỳ công thức tổng quát nào.
Bài tập thực hành
Bài 1 — Tính capacity thật. Team bạn có 4 developer, sprint 2 tuần (10 ngày làm việc). Trong đó: 1 người nghỉ phép 3 ngày; 1 người on-call cả sprint (giả định đóng góp 50%); có 1 ngày lễ; team mất trung bình 35% thời gian cho meeting và việc gián đoạn. Hãy tính tổng giờ code thực tế, rồi trừ thêm 15% reserved capacity cho incident. Con số cuối cùng là bao nhiêu?
Bài 2 — Rà dependency. Lấy 5 story trong backlog gần nhất của bạn. Với mỗi story, viết ra: (a) có dependency liên team không, (b) nếu có thì ai là người chịu trách nhiệm và ngày bàn giao là khi nào. Có bao nhiêu story bạn không trả lời được câu (b)? Đó chính là những rủi ro tiềm ẩn.
Bài 3 — Phân loại rủi ro. Đánh dấu mỗi story trong backlog là "low-variance" (code sạch, có test, hiểu rõ) hay "high-variance" (legacy, thiếu test, cần spike). Nếu sprint của bạn có nhiều hơn một story high-variance, hãy đề xuất cách xử lý: tách spike, đệm gấp đôi, hay hoãn lại?
Bài 4 — Commitment vs stretch. Với capacity tính ở Bài 1, hãy chọn các story và chia rõ ràng thành nhóm commitment (tự tin 90%) và stretch. Viết một câu sprint goal duy nhất buộc tất cả lại với nhau.
Tóm tắt
Sprint planning có tính đến ràng buộc kỹ thuật là kỹ năng phân biệt một Technical PM với một PM thông thường. Những điểm cốt lõi cần nhớ:
- Capacity, không phải velocity. Velocity dự báo dài hạn; capacity mới là thứ bạn lập kế hoạch cho sprint cụ thể. Team mature thường chỉ có 60–65% thời gian là giờ code thật.
- Trừ reserved capacity cho on-call, support và incident trước khi nhồi backlog. Người on-call không đóng góp 100%.
- Dependency liên team phải có chủ và có ngày bàn giao, được chốt ngay tại buổi planning — không phải phát hiện ở giữa sprint.
- Không phải story point nào cũng bằng nhau về rủi ro. Code legacy mang phương sai cao; hãy đệm và giới hạn số lượng high-variance mỗi sprint.
- Lập kế hoạch ở 80–85% capacity, chia commitment vs stretch, và để con số dẫn dắt cuộc trao đổi với stakeholder thay vì cảm tính.