Phân rã — chia tới khi mỗi bước gõ được ngay
Ô xử lý ở giữa vẫn là một câu tiếng Việt to đùng. Phân rã là chia nó xuống, với đúng một tiêu chí dừng: bước đó gõ được ngay hay chưa.
TL;DR: Phân rã một lời giải là chia nó thành các bước nhỏ hơn cho tới khi mỗi bước gõ thành lệnh Python được ngay. Chỉ có đúng một tiêu chí để biết khi nào dừng chia: bước đó đã gõ được thành lệnh hay còn là một câu tiếng Việt mơ hồ. Ví dụ đếm số bạn Gioi, Kha, Yeu bắt đầu bằng ba bước lớn; bước "xác định xếp loại" vẫn là ý tưởng nên phải chia tiếp thành ba nhánh so sánh, hai bước kia đã gõ được nên dừng tại đó. Chia thêm bước đã gõ được là phí công; chia chưa đủ bước còn mơ hồ là bỏ dở giữa chừng.
Bạn đã bóc đề, giải tay vài ca, và vẽ được lưu đồ có cấu trúc. Nhưng gần như ai mới học cũng hỏi đúng một câu ở đây: bước "xác định xếp loại của một bạn" nghe rất rõ ràng, vậy tại sao máy vẫn không chạy được nó?
Vì "rõ ràng với bạn" và "gõ thành lệnh được" là hai chuyện khác nhau — và bài này chia một bước còn mơ hồ xuống tới khi nó chỉ còn phép so sánh, phép gán, hoặc lệnh in cụ thể, dừng đúng lúc, không chia thêm cho đẹp.
1. Analogy — bản hướng dẫn lắp ráp: chia tới đâu tay mới làm được
Một bản hướng dẫn lắp tủ có nhiều cách viết. Viết "lắp xong cái tủ" thì đúng nhưng vô dụng — không ai cầm một câu đó mà lắp được ngay. Viết "cầm ốc vít, xoay cổ tay 30 độ" thì lại thừa: người lắp tủ chỉ cần biết "vặn ốc A vào lỗ B bằng bốn con vít gỗ" là làm được ngay. Bản hướng dẫn tốt dừng đúng ở mức tay người đọc làm được — phân rã lời giải cũng vậy, mức vừa đủ là mức bạn gõ được thành lệnh Python.
| Bản hướng dẫn lắp tủ | Phân rã lời giải |
|---|---|
| "Lắp xong cái tủ" — quá to, không ai làm ngay được | "Giải xong bài toán" — quá to, không gõ được ngay |
| "Vặn ốc A vào lỗ B bằng bốn con vít gỗ" — đúng mức tay làm ngay | Một bước gõ được thành 1–3 dòng lệnh Python |
| Không có bước "cầm tay siết từng thớ gỗ" — thừa, không ai chia tới đó | Không chia nhỏ hơn mức "gõ được ngay" — chia quá tay |
2. Chia tới bao giờ thì thôi?
Tiêu chí dừng chỉ có một: bước đó GÕ THÀNH LỆNH ĐƯỢC NGAY hay chưa. Chưa thì chia tiếp, được rồi thì dừng — không chia thêm cho đẹp.
"Gõ được ngay" nghĩa là bạn viết được bước đó thành một phép gán, so sánh, lệnh print/input, if, hoặc vòng lặp — không còn khoảng trống phải tự suy diễn. "Xác định xếp loại" chưa đạt mức đó: không nói rõ so sánh với số nào. "Đọc danh sách điểm vào một biến" thì đã đạt: gõ diem = [...] là xong.
Ô XỬ LÝ ở giữa khung vào–xử lý–ra là đúng chỗ bạn đang phân rã. Bài 1 cố ý để nó còn nguyên một câu tiếng Việt; bài này chia đúng ô đó xuống tới khi mỗi mảnh gõ được ngay.

3. Phân rã ví dụ chạy chính — đếm lớp có bao nhiêu bạn Gioi, Kha, Yeu
Đề bài: một lớp có một danh sách điểm. Ngưỡng giữ nguyên như module trước — từ 8 trở lên là Gioi, từ 5 trở lên là Kha, còn lại Yeu. Đếm và in ra bao nhiêu bạn mỗi loại.
Tầng một
Phân rã lần đầu, chỉ nhìn "đề bài cần làm những việc lớn nào":
- đọc danh sách điểm vào một biến
- với MỖI điểm: xác định xếp loại
- in ba con số đếm được
Kiểm từng bước bằng tiêu chí dừng ở mục trước:
- Bước 1 — gõ được ngay ✓:
diem = [8, 5, 9, 3, 6, 4, 10, 2], không còn gì phải đoán. - Bước 2 — chưa gõ được: "xác định xếp loại" không nói so sánh với số mấy.
- Bước 3 — gõ được ngay ✓: ba lệnh
print(dem_gioi),print(dem_kha),print(dem_yeu).
Hai trên ba bước dừng lại được, chỉ bước giữa cần chia thêm một tầng.
Tầng hai — chia riêng bước còn mơ hồ
Bước 1 và 3 đã gõ được, chia thêm là phí công (bẫy "chia quá tay" bên dưới). Bạn chỉ chia bước 2:
nếu điểm từ 8 trở lên → Gioi; còn nếu từ 5 trở lên → Kha; còn lại → Yeu
Đây là lưu đồ con của bước 2, vẽ bằng đúng bốn ký hiệu đã học ở bài trước:

Đọc theo đúng ký hiệu đã học: từ bầu dục vào, gặp thoi hỏi điểm có từ 8 trở lên không, đúng thì rẽ ngang vào chữ nhật gán Gioi; sai thì xuống thoi thứ hai hỏi từ 5 trở lên, rồi mới rẽ vào Kha hoặc Yeu. Ba nhánh, hai câu hỏi lồng nhau, và mỗi hộp giờ gõ được ngay bằng if / elif / else:
diem = [8, 5, 9, 3, 6, 4, 10, 2]
dem_gioi = 0
dem_kha = 0
dem_yeu = 0
for d in diem:
if d >= 8:
dem_gioi = dem_gioi + 1
elif d >= 5:
dem_kha = dem_kha + 1
else:
dem_yeu = dem_yeu + 1
print(dem_gioi)
print(dem_kha)
print(dem_yeu)
Tiêu chí "gõ được ngay" không mơ hồ, vì máy chỉ thi hành đúng từng lệnh một, không suy diễn ý định — nghĩa là bạn phải viết thành đúng một lệnh máy làm được, không còn là ý định chờ diễn giải thêm.
4. 🖊️ Thử đoán
Đề bài: đọc danh sách điểm vào một biến, kiểm tra xem có bạn nào bị nhập điểm âm (gõ nhầm dấu trừ) không; nếu có thì in "Co du lieu loi", không thì in "Du lieu hop le". Phân rã thành ba bước tầng một, y hệt cách chia ở ví dụ Gioi/Kha/Yeu:
- đọc danh sách điểm vào một biến
- kiểm tra xem có điểm nào âm không
- in kết quả tương ứng
Bước nào gõ được ngay, bước nào còn phải chia tiếp? Viết câu trả lời ra giấy trước khi mở phần dưới.
Bước 1 và 3 gõ được ngay: bước 1 là một phép gán thẳng (diem = [...]), bước 3 là một lệnh print thẳng.
Bước 2 chưa gõ được — "kiểm tra xem có điểm nào âm không" chưa nói máy lặp qua danh sách thế nào và ghi nhớ kết quả ở đâu. Chia tiếp một tầng:
đặt một biến cờ
co_loi = False; với MỖI điểm trong danh sách: nếu điểm nhỏ hơn 0 thì đặtco_loi = True
Giờ mỗi mảnh đã gõ được ngay: một phép gán khởi tạo, một vòng for, một if bên trong vòng lặp. Nếu bạn đoán bước 2 "gõ được ngay luôn" thì đó chính là bẫy "chia quá tay".
5. Tới lượt bạn
Đề bài: một quán trà sữa ghi lại giá tiền các đơn hàng trong một buổi. Viết chương trình đọc danh sách giá tiền đó, rồi in ra hai con số: có bao nhiêu đơn từ 50000 trở lên (đơn "lớn"), và bao nhiêu đơn dưới 50000 (đơn "nhỏ").
Tự phân rã đề này theo đúng quy trình vừa học: viết tầng một — những việc lớn đề bài cần làm; với mỗi bước, tự hỏi đúng một câu bước này gõ thành lệnh Python được ngay chưa; bước nào trả lời "chưa" thì chia tiếp, cho tới khi mọi bước đều trả lời "được".
Đừng chép khung của ví dụ Gioi/Kha/Yeu — đề trà sữa chỉ có hai nhóm thay vì ba, nên số tầng và số nhánh sẽ khác. Việc của bạn là tự áp tiêu chí dừng, không phải khớp hình dạng của ví dụ cũ.
6. Bẫy thường gặp
❌ Chia quá tay: chia một bước đã gõ được ngay thành nhiều bước nhỏ hơn nữa, ví dụ tách dem_gioi = dem_gioi + 1 thành "lấy giá trị", "cộng thêm 1", "gán lại". Kết quả là một bản liệt kê gần như từng dòng code, không còn là lời giải.
✅ Bước đã gõ được thành 1–3 dòng lệnh liền mạch thì dừng lại, không chia thêm.
❌ Chia lệch tầng: một nhánh chia tới tận lệnh cụ thể, nhánh song song thì vẫn ở mức ý tưởng. Ví dụ "nếu điểm từ 8 trở lên thì dem_gioi = dem_gioi + 1, còn lại thì xử lý phù hợp" — nhánh sau ("xử lý phù hợp") chưa gõ được.
✅ Kiểm tiêu chí dừng cho TỪNG nhánh song song. Hai nhánh của cùng một quyết định phải dừng ở cùng một mức cụ thể.
❌ Đặt tên bước bằng danh từ mơ hồ: "xử lý dữ liệu", "tính toán kết quả" — nghe hợp lý nhưng không nói bạn phải làm động tác gì.
✅ Đặt tên bước bằng động từ cụ thể làm được ngay: "cộng thêm 1 vào dem_gioi", "so sánh điểm với 8".
7. 📚 Đào sâu
Phân rã không phải kỹ năng riêng của Python — tiêu chí dừng ("gõ được ngay chưa?") không phụ thuộc cú pháp ngôn ngữ nào, nên chuyển thẳng sang bất kỳ ngôn ngữ bạn học sau này.
Một nghiên cứu năm 2026 phân tích 55 sơ đồ phân rã bài toán do sinh viên nhập môn tự vẽ, và phát hiện 51 trong số đó — khoảng 93% — thiếu ít nhất một thành phần bắt buộc mà giảng viên yêu cầu. Vấn đề không phải sơ đồ vẽ xấu hay đẹp — sinh viên dừng phân rã quá sớm, bỏ sót những mảnh còn mơ hồ mà không nhận ra, đúng bẫy "chia lệch tầng" ở mục trên nhưng xảy ra trên diện rộng cả lớp học.
- Planning on Paper: Problem Decomposition with Diagrams in Introductory Computing — Vadaparty, Hayatpur, Soosai Raj, Porter, Zingaro (2026).
Ghi chú: tiêu chí dừng tường minh, chứ không phải kỹ năng vẽ đẹp, mới là thứ quyết định một bản phân rã có dùng được hay không.
8. Liên hệ các bài khác
- Bài 1 — Đọc đề — ô xử lý của khung vào–xử lý–ra ở bài đó còn nguyên một câu; bài này là chỗ bạn quay lại chia đúng ô đó.
- Bài 2 — Làm tay trước khi làm máy — quy luật rút ra khi giải tay ba ca cụ thể chính là nguyên liệu cho từng bước phân rã.
- Bài 3 — Lưu đồ có cấu trúc — bốn ký hiệu của bài đó dùng để vẽ lại đúng những gì bạn vừa phân rã.
- Bài 5 — Hàm — mỗi bước đã "gõ được ngay" là ứng viên tự nhiên để gói thành một hàm có tên.
9. Tóm tắt
- Phân rã một đề nhiều bước là chia liên tục cho tới khi mỗi bước gõ thành lệnh Python được ngay; không có mức "vừa đủ" nào khác ngoài tiêu chí đó.
- Ví dụ đếm Gioi/Kha/Yeu cho thấy ba bước tầng một không đều nhau: hai bước đã gõ được ngay, một bước còn phải chia tiếp thành ba nhánh Gioi/Kha/Yeu qua hai quyết định lồng nhau.
- Lưu đồ ghi lại đúng những gì bạn phân rã — dùng lại bốn ký hiệu đã học, không cần ký pháp riêng cho "phân rã".
- Ba lỗi chia quá tay, chia lệch tầng và đặt tên mơ hồ đều không làm chương trình báo lỗi gì — chúng chỉ âm thầm làm bản phân rã vô dụng, phải soi bằng mắt mới thấy.
- Bài sau dùng đúng các bước "gõ được ngay" này làm ranh giới để gói thành hàm có tên.
10. Tự kiểm tra
- Q1Vì sao tiêu chí dừng khi phân rã không phải là "chia đủ ba tầng" hay "mỗi bước một dòng code", mà là một câu hỏi duy nhất?
- Q2Trong ví dụ đếm Gioi/Kha/Yeu, vì sao bước "với mỗi điểm: xác định xếp loại" chưa gõ được ngay ở tầng một?
- Q3Đoạn code sau in gì?
diem = [7, 5, 2] dem_gioi = 0 dem_kha = 0 dem_yeu = 0 for d in diem: if d >= 8: dem_gioi = dem_gioi + 1 elif d >= 5: dem_kha = dem_kha + 1 else: dem_yeu = dem_yeu + 1 print(dem_gioi) print(dem_kha) print(dem_yeu) - Q4Vì sao đặt tên một bước là "xử lý dữ liệu" lại là dấu hiệu cảnh báo khi phân rã, kể cả khi bước đó nghe rất hợp lý?
- Q5Bạn phân rã một quyết định thành "nếu đúng thì cộng 1 vào biến đếm, nếu sai thì xử lý phù hợp". Bước này đã dừng chia được chưa? Vì sao?
- Q6Cùng một bản phân rã, vì sao ghi bằng lưu đồ lại nói được nhiều hơn ghi bằng danh sách gạch đầu dòng?
- Q7Vì sao kỹ năng phân rã học ở bài này không gắn riêng với Python?
Bài tiếp theo: Hàm — đặt tên cho một nhóm bước, nhận vào gì trả ra gì
Bài này đáng gửi cho bạn học cùng?
Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên