Phương pháp STAR phỏng vấn: trả lời câu hỏi hành vi cho junior

Phương pháp STAR phỏng vấn giúp bạn trả lời câu hỏi hành vi có cấu trúc: tình huống, nhiệm vụ, hành động, kết quả. Có ví dụ trước và sau, kèm công cụ chấm.

Phương pháp STAR là cách trả lời câu hỏi hành vi theo bốn phần: Tình huống, Nhiệm vụ, Hành động, Kết quả (Situation, Task, Action, Result). Phần quan trọng nhất là Hành động, tức là chính bạn đã làm gì. Bạn có hay kể dài về bối cảnh mà quên nói mình làm gì không? Cùng mình xem nhé!

Câu hỏi "kể về một lần mâu thuẫn" khó ở chỗ nào?

Ở bài trước, Minh vượt qua vòng phỏng vấn kỹ thuật ở công ty A, và được mời sang vòng tiếp theo với bộ phận nhân sự. Minh là nhân vật minh họa, ghép từ những tình huống quen thuộc của sinh viên IT mới ra trường, và công ty A cũng vậy. Vòng này không có đồng hồ đếm ngược hay trình soạn code. Người ngồi đối diện hỏi những câu như "kể cho chị nghe lần em làm việc nhóm gặp mâu thuẫn".

Đây là câu hỏi hành vi (behavioral question). Nó không hỏi bạn biết gì mà hỏi bạn đã làm gì. Theo các trung tâm hướng nghiệp đại học, lý do là hành vi trong quá khứ giúp đoán hành vi trong tương lai, như hướng dẫn hướng nghiệp của Đại học Wisconsin giải thích. Câu hỏi không có đáp án đúng để chấm bằng test, và nhiều bạn kỹ thuật tốt lại lúng túng ở đây.

Minh có một chuyện thật để kể: đồ án tốt nghiệp, nhóm 4 người làm website bán cà phê, hai bạn trong nhóm bất đồng về cách viết code. Câu trả lời đầu tiên của Minh, mình chép nguyên văn, chia thành bốn mục để so sánh về sau (các tên Hùng và Lan cũng là minh họa):

tra-loi-truoc.md
## Tình huống
Hồi làm đồ án tốt nghiệp bọn em có nhóm 4 người, làm website bán cà phê, thì trong nhóm có bạn Hùng với bạn Lan. Hai bạn này tính ra cũng thân nhau, nhưng mà về code thì hay không đồng ý. Bạn Hùng thì quen viết nhanh, đặt tên biến ngắn, còn bạn Lan thì hay muốn tên biến đầy đủ và tách file nhiều. Đến tuần thứ sáu thì chuyện này căng lên, vì mỗi lần bạn Hùng gửi pull request thì bạn Lan lại comment rất nhiều, rồi hai bạn nhắn qua nhắn lại trong nhóm chat, không khí khá là khó chịu, các bạn còn lại cũng không biết nói gì.

## Nhiệm vụ
Lúc đó em phụ trách giỏ hàng và thanh toán, nên code của em phụ thuộc vào cả hai bạn.

## Hành động
Bọn em có họp nhóm và nói chuyện với nhau để giải quyết. Bọn em thống nhất với nhau vài điều. Em cũng có nói vài câu.

## Kết quả
Sau đó thì mọi chuyện ổn hơn và nhóm làm xong đồ án.

Đọc lại bằng con mắt của người phỏng vấn thì có ba vấn đề. Phần Tình huống chiếm gần hết câu trả lời, và người nghe phải chờ rất lâu mới tới chỗ họ cần. Phần Hành động chỉ có ba câu mơ hồ, nghe như cả nhóm làm hết ("bọn em họp", "bọn em thống nhất") và Minh "cũng nói vài câu". Phần Kết quả không có một chi tiết nào để tin: ổn hơn là ổn tới đâu? Người phỏng vấn nghe xong không biết Minh đã làm gì.

STAR là gì và mỗi phần cần gì?

Bốn chữ cái là bốn phần của câu trả lời, theo thứ tự:

Tình huống (Situation) là bối cảnh ngắn: ở đâu, ai, chuyện gì. Chỉ cần đủ để người nghe hiểu, không cần kể hết. Nhiệm vụ (Task) là trách nhiệm của bạn trong tình huống đó, tức vì sao chuyện này liên quan tới bạn. Hành động (Action) là những bước bạn đã làm, cụ thể, dùng "em" chứ không phải "bọn em". Kết quả (Result) là chuyện xảy ra sau đó, càng đo được càng tốt, kèm điều bạn rút ra.

Hướng dẫn của Furman University về phương pháp STAR mô tả Hành động là những bước chính bạn đã làm. Nhiều trung tâm hướng nghiệp khác, như trang về STAR của UMBC, cũng dạy cấu trúc bốn phần này, và các hướng dẫn thường nhắc rằng nhiều người bỏ quên phần Kết quả dù nhà tuyển dụng hay muốn nghe thêm về nó. Hai lỗi đó, thiếu Hành động cụ thể và thiếu Kết quả, đúng là hai lỗi trong câu trả lời của Minh.

Các nguồn này không nói tỷ lệ cho từng phần phải là bao nhiêu. Tỷ lệ mà mình dùng bên dưới là kinh nghiệm cá nhân, và bạn nên coi chúng là gợi ý, không phải luật: Tình huống cộng Nhiệm vụ khoảng dưới 30% câu trả lời, Hành động từ 45% trở lên, và cả câu trả lời khoảng một phút rưỡi tới hai phút khi nói.

Một công cụ nhỏ để chấm câu trả lời

Viết ra rồi đọc lại bằng mắt thì dễ tự thấy ổn. Mình viết một đoạn script ngắn để đếm: mỗi phần bao nhiêu từ, tổng thời lượng ước lượng, kết quả có con số không, và trong phần Hành động bạn nói về "mình" hay về "cả nhóm". Nó nhận một file Markdown có đúng bốn mục như trên. Bạn lưu file này ở đâu cũng được, miễn đặt cạnh file câu trả lời:

kiem-tra-star.ts
// Chấm một câu trả lời viết theo STAR. Đọc file Markdown có bốn mục "## Tình huống", "## Nhiệm vụ", "## Hành động", "## Kết quả".
// Dùng: node kiem-tra-star.ts tra-loi-truoc.md
import { readFileSync } from "node:fs";

const MUC = ["Tình huống", "Nhiệm vụ", "Hành động", "Kết quả"] as const;
const TU_MOI_PHUT = 130; // tốc độ nói do mình tự chọn để ước lượng, hãy bấm giờ đọc to một đoạn của bạn để thay bằng số của bạn
const THOI_GIAN_TOT = [60, 120]; // giây: ngưỡng mình đặt cho một câu trả lời hành vi

const file = process.argv[2];
if (!file) throw new Error("Cần tên file, ví dụ: node kiem-tra-star.ts tra-loi-truoc.md");
const noiDung = readFileSync(file, "utf8").normalize("NFC");

const dem = (chu: string) => (chu.match(/[\p{L}\p{N}]+/gu) ?? []).length;
// Chia file thành các phần: mỗi dòng "## Tên mục" mở một phần, các dòng sau nó thuộc phần đó.
const cacPhan: Record<string, string> = Object.fromEntries(MUC.map((ten) => [ten, ""]));
let hienTai = "";
for (const dong of noiDung.split("\n")) {
  const tieuDe = /^##\s+(.+?)\s*$/.exec(dong);
  if (tieuDe) hienTai = tieuDe[1];
  else if (hienTai in cacPhan) cacPhan[hienTai] += `${dong}\n`;
}

const soTu = Object.fromEntries(MUC.map((ten) => [ten, dem(cacPhan[ten])]));
const tong = MUC.reduce((t, ten) => t + soTu[ten], 0);
const giay = Math.round((tong / TU_MOI_PHUT) * 60);
const tiLe = (ten: (typeof MUC)[number]) => Math.round((soTu[ten] / tong) * 100);

console.log(`${file}: ${tong} từ, khoảng ${giay} giây nếu nói ${TU_MOI_PHUT} từ/phút`);
for (const ten of MUC) console.log(`  ${ten.padEnd(10)} ${String(soTu[ten]).padStart(3)} từ  ${String(tiLe(ten)).padStart(3)}%`);

// "chúng em", "bọn em", "nhóm em": nói về cả nhóm. "em" đứng riêng: nói về chính mình.
const NHOM = /(chúng em|bọn em|nhóm em)/giu;
const hanhDong = cacPhan["Hành động"].toLowerCase();
const soNhom = (hanhDong.match(NHOM) ?? []).length;
const soEm = (hanhDong.replace(NHOM, " ").match(/(?<![\p{L}])em(?![\p{L}])/gu) ?? []).length;

const canhBao: string[] = [];
for (const ten of MUC) if (soTu[ten] === 0) canhBao.push(`Thiếu mục "${ten}".`);
if (giay < THOI_GIAN_TOT[0] || giay > THOI_GIAN_TOT[1]) canhBao.push(`Thời lượng ${giay} giây, nên khoảng ${THOI_GIAN_TOT[0]}–${THOI_GIAN_TOT[1]} giây.`);
if (tiLe("Tình huống") + tiLe("Nhiệm vụ") > 30) canhBao.push(`Tình huống và nhiệm vụ chiếm ${tiLe("Tình huống") + tiLe("Nhiệm vụ")}% câu trả lời, nên dưới 30%.`);
if (tiLe("Hành động") < 45) canhBao.push(`Hành động chỉ chiếm ${tiLe("Hành động")}%, nên từ 45%: người nghe muốn biết bạn đã làm gì.`);
if (!/\d/.test(cacPhan["Kết quả"])) canhBao.push("Kết quả không có con số nào.");
if (soEm + soNhom > 0 && soEm / (soEm + soNhom) < 0.5) canhBao.push(`Trong hành động, nói về cả nhóm ${soNhom} lần, về mình ${soEm} lần: người nghe không biết phần của bạn là gì.`);

console.log(canhBao.length ? canhBao.map((c) => `  ! ${c}`).join("\n") : "  Không có cảnh báo.");

Có hai chỗ trong code cần nói rõ. Biểu thức (?<![\p{L}])em(?![\p{L}]) tìm chữ "em" đứng riêng, không dính vào chữ khác như "thêm" hay "tiếng em". Mình không dùng \b vì trong JavaScript nó không coi các chữ cái có dấu tiếng Việt là chữ. Và các con số 130 từ mỗi phút, 60 đến 120 giây, 30%, 45% là con số mình tự đặt, không phải tiêu chuẩn của ai. Script này là một cái thước để so hai bản của chính bạn, không phải giám khảo.

Chạy trên câu trả lời đầu tiên của Minh:

node kiem-tra-star.ts tra-loi-truoc.md
tra-loi-truoc.md: 176 từ, khoảng 81 giây nếu nói 130 từ/phút
  Tình huống 116 từ   66%
  Nhiệm vụ    20 từ   11%
  Hành động   27 từ   15%
  Kết quả     13 từ    7%
  ! Tình huống và nhiệm vụ chiếm 77% câu trả lời, nên dưới 30%.
  ! Hành động chỉ chiếm 15%, nên từ 45%: người nghe muốn biết bạn đã làm gì.
  ! Kết quả không có con số nào.
  ! Trong hành động, nói về cả nhóm 2 lần, về mình 1 lần: người nghe không biết phần của bạn là gì.

Đúng như mình đoán bằng mắt, nhưng nay có con số. Câu trả lời dài 81 giây, vừa đủ, nhưng 77% là kể bối cảnh và chỉ 15% là Minh làm gì.

Viết lại: bắt đầu từ Hành động

Cách mình khuyên Minh viết lại là đảo thứ tự công việc. Đừng viết từ trên xuống. Viết Hành động trước, vì đó là phần người nghe cần, rồi mới thêm bối cảnh vừa đủ để hiểu Hành động, và cuối cùng là Kết quả với số cụ thể. Để làm Hành động cụ thể, Minh tự hỏi ba câu: mình đã làm gì đầu tiên, mình đã nói gì với ai, và vì sao mình chọn cách đó. Đây là bản viết lại:

tra-loi-sau.md
## Tình huống
Ở đồ án tốt nghiệp, nhóm em 4 người làm website bán cà phê. Đến tuần thứ sáu, hai bạn bất đồng về cách đặt tên biến và chia file, nên pull request của một bạn bị trả lại nhiều lần.

## Nhiệm vụ
Em phụ trách giỏ hàng, code của em phụ thuộc vào cả hai bạn, nên em không thể đứng ngoài.

## Hành động
Em hẹn riêng từng bạn 10 phút để hỏi một đoạn code tốt, theo bạn ấy, trông như thế nào. Hai bạn đều muốn code dễ đọc, chỉ khác cách làm. Em đề nghị viết ra năm quy ước ngắn trong một file CONTRIBUTING, như cách đặt tên và khi nào nên tách file, rồi em soạn bản nháp để hai bạn sửa. Em đề xuất thử quy ước đó trên một pull request trước khi áp dụng cho cả nhóm, và sau lần thử đầu em nhắn kết quả cho mọi người cùng xem.

## Kết quả
Trong hai tuần sau, số pull request bị trả lại giảm từ 6 xuống còn 1, và pull request được gộp trong ngày thay vì chờ 4 ngày. Nhóm nộp đồ án đúng hạn. Em rút ra rằng khi một bất đồng được ghi thành quy ước chung, nó thôi là chuyện giữa hai người.
node kiem-tra-star.ts tra-loi-sau.md
tra-loi-sau.md: 211 từ, khoảng 97 giây nếu nói 130 từ/phút
  Tình huống  41 từ   19%
  Nhiệm vụ    20 từ    9%
  Hành động   95 từ   45%
  Kết quả     55 từ   26%
  Không có cảnh báo.

Mình cần thành thật một chuyện. Bản viết lại đầu tiên mình viết cũng bị cảnh báo: Tình huống cộng Nhiệm vụ chiếm 34%, Hành động chiếm 39%. Mình đã cắt bớt Tình huống và thêm một chi tiết vào Hành động (Minh nhắn kết quả của lần thử đầu cho cả nhóm) để vượt ngưỡng. Bản cuối chỉ hơn bản đầu bằng một câu, và đó là điều mình muốn bạn thấy: chênh lệch giữa một câu trả lời được chấm là "mơ hồ" và "cụ thể" thường chỉ là vài câu, không phải một câu chuyện khác hẳn.

Về các con số trong phần Kết quả, "từ 6 xuống còn 1" và "chờ 4 ngày" là số của Minh (nhân vật minh họa). Khi bạn viết câu chuyện của mình, chỉ dùng con số bạn thật sự có. Nếu không có số, hãy nói một kết quả bạn quan sát được, ví dụ "từ đó hai bạn không còn nhắn qua lại trong nhóm chat về chuyện đặt tên". Một con số bịa ra dễ bị hỏi lại, và khi đó bạn mất cả câu chuyện lẫn lòng tin của người nghe.

Một kho chuyện để dùng cho nhiều câu hỏi

Có một điều làm nhiều bạn lo: câu hỏi hành vi có hàng chục kiểu, chẳng lẽ chuẩn bị hàng chục câu trả lời? Không cần. Theo gợi ý của hướng dẫn Furman, bạn chuẩn bị vài chuyện cho mỗi nhóm kỹ năng, và dùng lại chúng. Với người mới đi làm, ba chuyện thật thường là đủ. Đây là kho chuyện của Minh, mỗi chuyện bốn dòng STAR ngắn:

kho-chuyen.md
# Kho chuyện của Minh (minh họa)

## 1. Bất đồng trong nhóm đồ án (kỹ năng: làm việc nhóm, giải quyết mâu thuẫn)
- Tình huống: Đồ án nhóm 4 người, tuần 6, hai bạn bất đồng về cách đặt tên và chia file, pull request bị trả lại nhiều lần.
- Nhiệm vụ: Mình phụ trách giỏ hàng, code phụ thuộc vào cả hai bạn.
- Hành động: Hỏi riêng từng bạn, đề nghị viết năm quy ước vào CONTRIBUTING, thử trên một pull request.
- Kết quả: PR bị trả lại giảm từ 6 xuống 1 trong hai tuần; gộp trong ngày thay vì chờ 4 ngày; nộp đúng hạn.

## 2. Lỗi khó nhất: khoản chi 6:30 sáng ngày 1/12 vào nhầm tháng (kỹ năng: giải quyết vấn đề, kiên trì)
- Tình huống: Ở app sổ chi tiêu, trên máy mình đúng nhưng trên máy chủ thì khoản chi 6:30 sáng 1/12 bị tính vào tháng 11.
- Nhiệm vụ: Tìm nguyên nhân và sửa trước khi bạn bè dùng thật.
- Hành động: Đoán máy chủ chạy giờ UTC, tái hiện bằng cách chạy test với TZ=UTC, rồi sửa để luôn tính tháng theo giờ Việt Nam.
- Kết quả: Lỗi tái hiện được và được khóa bằng test; sau đó 12 bạn dùng trong hai tháng không gặp lại lỗi này.

## 3. Ngại hỏi nên mất thời gian (kỹ năng: nhận ra điểm yếu và thay đổi)
- Tình huống: Làm giỏ hàng, mình kẹt ở một lỗi state và tự loay hoay hai ngày mà không hỏi ai.
- Nhiệm vụ: Cả nhóm cần giỏ hàng xong để nối với thanh toán.
- Hành động: Mình đặt cho mình quy tắc: kẹt quá 1 giờ thì viết câu hỏi (đã thử gì, lỗi gì) và gửi cho bạn trong nhóm.
- Kết quả: Lần kẹt tiếp theo, mình hỏi sau 1 giờ và xong trong buổi chiều đó thay vì hai ngày.

Chuyện số 2 chính là lỗi "6:30 sáng" mà Minh đã nhắc ở bài chuẩn bị phỏng vấn. Chuyện số 3 là chuyện về điểm yếu, và nó làm đúng một điều quan trọng: nó kể một điểm yếu thật, kèm một việc Minh đã làm để sửa. Câu "điểm yếu của em là cầu toàn" nghe an toàn nhưng người phỏng vấn đã nghe nó quá nhiều lần.

Ba chuyện này trả lời được khoảng tám câu hỏi thường gặp:

  • "Kể về một lần làm việc nhóm gặp mâu thuẫn" và "kể về một lần em không đồng ý với đồng đội": chuyện 1.
  • "Lỗi khó nhất em từng gặp" và "kể về một lần em phải học thứ mới rất nhanh": chuyện 2.
  • "Điểm yếu lớn nhất", "kể về một lần em mắc sai lầm" và "em làm gì khi bị kẹt": chuyện 3.
  • "Em tự hào nhất về điều gì": chuyện 2 hoặc chuyện 1, tùy chuyện nào có kết quả đo được.

Nguyên tắc dùng kho: khi gặp một câu hỏi, đừng nghĩ chuyện mới, hãy tìm chuyện gần nhất trong kho rồi chọn phần hợp với câu hỏi. Cùng một chuyện, câu hỏi về mâu thuẫn thì nhấn vào Hành động giao tiếp, còn câu hỏi về điều tự hào thì nhấn vào Kết quả.

Khi có người gọi: "Công ty muốn gửi offer"

Minh trả lời vòng nhân sự khá tự tin hơn lần đầu. Vài ngày sau, điện thoại reo: công ty A muốn gửi offer. Mức lương trong thư mời thấp hơn con số Minh hy vọng một chút, và người gọi hỏi "em thấy thế nào?". Nên nhận ngay, nên nói gì, và có nên mặc cả khi mới đi làm lần đầu hay không là việc của các bài viết sau.

Bạn theo dõi cả hành trình ở series Hành trình junior. Nếu muốn luyện thêm, câu giới thiệu bản thân trong một phút và các câu khác có trong ngân hàng câu hỏi phỏng vấn.

Nhận bài tiếp theo qua email.

Một email mỗi tuần, chỉ khi có điều đáng đọc. Không spam.