Sẽ mở trong thẻ mới
PDL AIAI Worker — trợ lý AI trực 24/7: trả lời khách, xử lý yêu cầu, báo cáo tự động

Kỹ sư phần mềm thời AITờ 01-04 / 112

Đọc hiểu code cơ bản: biến, kiểu dữ liệu, điều kiện, vòng lặp, hàm

Bàn tay chặn muỗng muối đổ nhầm vào hộp đường, ví cho biến, kiểu dữ liệu và bộ kiểm tra kiểu
Tờ
01-04 / 112
Hạng mục
M01 · Nền tảng máy tính và web cho người không chuyên
Cấp độ
Cơ bản
Thời gian đọc
16 phút
Giai đoạn công trình
0 · Khám phá
Cập nhật
Bản đồ công trìnhTờ này lắp: API, Thanh toán VietQR
Bản đồ công trình Mộc OMSBài này: API, Thanh toán VietQR. Đã học: Coding agent, Khách hàng, Kênh bán, Sheet & sổ tay. Chưa tới: PRD & spec, Repo & CI, Kiểm thử, Hosting & tên miền, Giám sát lỗi, Giao diện app, Database, Dashboard, báo cáo, Trợ lý AI nhận đơn, Màn hình bếp, Đăng nhập, vai trò, Thông báo khách, Nhiều tiệm (MộcOS), Kế toán, hoá đơn.Thi công & hạ tầngDòng đơn hàngNghiệp vụ & dịch vụMở rộng MộcOSPRD & specspecCoding agentagentRepo & CIrepo-ciKiểm thửtestsHosting & tên miềnhostingGiám sát lỗimonitoringKhách hàngcustomerKênh bánchannelsGiao diện appapp-uiAPIapiDatabasedatabaseDashboard, báo cáoreportsSheet & sổ taysheetTrợ lý AI nhận đơnai-assistantMàn hình bếpkitchenĐăng nhập, vai tròauthThanh toán VietQRpaymentsThông báo kháchnotificationsNhiều tiệm (MộcOS)tenantsKế toán, hoá đơnintegrations0 Khám phá1 MVP2 Ra mắt3 Thêm AI4 Mở rộng
Bản đồ công trình Mộc OMSBài này: API, Thanh toán VietQR. Đã học: Coding agent, Khách hàng, Kênh bán, Sheet & sổ tay. Chưa tới: PRD & spec, Repo & CI, Kiểm thử, Hosting & tên miền, Giám sát lỗi, Giao diện app, Database, Dashboard, báo cáo, Trợ lý AI nhận đơn, Màn hình bếp, Đăng nhập, vai trò, Thông báo khách, Nhiều tiệm (MộcOS), Kế toán, hoá đơn.Dòng đơn hàngKhách hàngKênh bánGiao diệnAPIDatabaseBáo cáoNghiệp vụ & dịch vụSheet, sổ tayTrợ lý AIMàn hình bếpĐăng nhậpThanh toánThông báoThi công & hạ tầngPRD & specCoding agentRepo & CIKiểm thửHostingGiám sátMở rộng MộcOSNhiều tiệmKế toán0 Khám phá1234

Bài nàyĐã họcChưa tớiĐã thay thế

Bạn sẽ học được gì

Tiêu chí nghiệm thu

Vì sao người không viết code vẫn cần đọc code

Bạn có thể hỏi: “AI viết code rồi, tôi đọc làm gì?” Hãy nghĩ tới việc chị Lan duyệt công thức bánh mới do thợ đề xuất. Chị không cần tự nướng, nhưng chị phải đọc được “200g đường cho một chiếc bánh 16cm” và biết ngay là quá ngọt.

Code cũng vậy. Phần lớn code trong một ứng dụng quản lý đơn hàng là logic nghiệp vụ được viết bằng ngôn ngữ máy: tính tiền, kiểm tra điều kiện, chuyển trạng thái. Nếu đọc được, bạn sẽ:

  • Phát hiện AI cài sai quy tắc của bạn (miễn phí ship từ 500.000đ hay trên 500.000đ?).
  • Hiểu thông báo lỗi thay vì chỉ chép dán cho AI và cầu may.
  • Review thay đổi của agent nhanh hơn, tập trung đúng chỗ quan trọng.

Toàn bộ ví dụ trong bài viết bằng TypeScript, ngôn ngữ chính của dự án Bánh Mộc. TypeScript là JavaScript có thêm “nhãn kiểu”, sẽ được giải thích ở cuối bài.

Biến và hằng: những chiếc hộp có nhãn

Biến (variable) là một chiếc hộp có dán nhãn để đựng một giá trị. Trong tiệm bánh, hãy hình dung các hộp nguyên liệu trên kệ, mỗi hộp có nhãn: “đường”, “bột mì”, “bơ”.

TS
const tenKhach = "Chị Hương";      // hằng: hộp dán chết, không đổi nội dung
let soLuong = 1;                   // biến: hộp có thể thay nội dung
soLuong = 2;                       // đổi nội dung hộp soLuong từ 1 thành 2
const PHI_SHIP = 30_000;           // 30_000 chính là 30000; dấu _ chỉ để dễ đọc
  • const (constant, hằng): gán một lần, không được gán lại. Code hiện đại dùng const là chủ yếu.
  • let: có thể gán lại giá trị mới.
  • Dấu = trong code nghĩa là “cất vào hộp”, không phải “bằng nhau” như trong toán.
  • Dòng bắt đầu bằng // là chú thích (comment): ghi chú cho người đọc, máy bỏ qua.

Tên biến viết liền, không dấu, thường theo kiểu camelCase (chữ đầu viết thường, các từ sau viết hoa chữ cái đầu) như tenKhach, soLuong. Hằng số cấu hình hay viết HOA như PHI_SHIP. Trong code thật, tên thường bằng tiếng Anh (customerName, quantity); trong bài này dùng cả hai để bạn quen.

Kiểu dữ liệu: mỗi hộp đựng một loại thứ

Hộp đựng đường không nên chứa trứng. Trong code, mỗi giá trị thuộc một kiểu dữ liệu (data type). Năm kiểu bạn sẽ gặp liên tục:

Kiểu Ý nghĩa Ví dụ Bánh Mộc Cách nhận ra
string Chuỗi chữ "BM-261012-007", "Mừng sinh nhật Bin" Nằm trong dấu nháy "..." hoặc '...'
number Con số 450000, 2 Số không có nháy
boolean Đúng/sai true, false (ví dụ isActive) Chỉ có hai giá trị
array (mảng) Danh sách có thứ tự ["dâu", "socola", "matcha"] Nằm trong ngoặc vuông [...]
object (đối tượng) Một “phiếu” gồm nhiều ô có tên { productName: "Bánh quy hộp quà", unitPrice: 120000 } Nằm trong ngoặc nhọn {...}, dạng tên: giá trị

Ngoài ra có hai giá trị đặc biệt nghĩa là “không có gì”: undefined (chưa từng được gán) và null (cố ý để trống). Ví dụ đơn bánh mì ngọt không có chữ trên bánh, nên cakeMessage không có giá trị.

Một dòng đơn hàng (giống một dòng trong bảng order_items) là một object:

TS
const dongBanhKem = {
  productName: "Bánh kem dâu 20cm",
  unitPrice: 450_000,               // đơn giá, VNĐ
  quantity: 1,
  cakeMessage: "Mừng sinh nhật Bin",
};

console.log(dongBanhKem.unitPrice); // in ra 450000; dấu chấm để "mở ô" có tên unitPrice

Và cả đơn là một mảng các object: danh sách nhiều dòng.

Điều kiện: “nếu… thì…, nếu không thì…”

Logic nghiệp vụ đầy những chữ “nếu”. Code diễn đạt chúng bằng if / else:

TS
// Quy tắc (giả định cho ví dụ): khách tự đến lấy thì không tính ship;
// giao tận nơi thì đơn từ 500.000đ được miễn phí ship, dưới mức đó tính 30.000đ.
if (deliveryType === "pickup") {
  phiShip = 0;
} else if (tamTinh >= 500_000) {
  phiShip = 0;
} else {
  phiShip = 30_000;
}

Đọc như tiếng Việt: nếu khách tự lấy thì phí ship 0; nếu không, mà tạm tính từ 500.000 trở lên thì 0; còn lại thì 30.000. Máy kiểm tra từ trên xuống, gặp điều kiện đúng đầu tiên thì làm phần đó và bỏ qua phần còn lại.

Các ký hiệu so sánh và kết hợp hay gặp:

Ký hiệu Nghĩa Ví dụ
=== bằng (nghiêm ngặt, cùng kiểu) status === "moi"
!== khác status !== "da_huy"
> >= < <= lớn hơn, lớn hơn hoặc bằng… tamTinh >= 500_000
&& VÀ (cả hai cùng đúng) isCustomCake && cakeMessage === ""
`\ \ ` HOẶC (ít nhất một đúng) `role === “owner” \ \ role === “manager”`
! KHÔNG (đảo ngược) !isActive nghĩa là “không còn bán”

Bạn có thể thấy == (hai dấu bằng) trong code cũ. Nó so sánh “lỏng”, tự đổi kiểu trước khi so (ví dụ coi chuỗi "1" bằng số 1), dễ gây bất ngờ. Code hiện đại dùng ===.

Vòng lặp: làm lại cho từng món

Một đơn có nhiều món. Muốn tính tạm tính, người thợ phải đi qua từng món, nhân đơn giá với số lượng rồi cộng dồn. Đó là vòng lặp (loop):

TS
let tamTinh = 0;                          // bắt đầu với hộp rỗng
for (const item of items) {               // với MỖI món trong danh sách items...
  tamTinh = tamTinh + item.unitPrice * item.quantity;  // ...cộng thêm thành tiền của món đó
}
// sau vòng lặp, tamTinh chứa tổng tiền hàng

Đọc là: “Với mỗi item trong items, lấy tamTinh hiện tại cộng thêm đơn giá × số lượng, rồi cất lại vào tamTinh.”

AI thường viết cùng ý đó gọn hơn bằng các “hàm xử lý danh sách”. Bạn không cần tự viết, chỉ cần nhận ra:

TS
// reduce: "gom" cả danh sách thành một giá trị, bắt đầu từ 0
const tamTinh = items.reduce((tong, item) => tong + item.unitPrice * item.quantity, 0);

// filter: lọc ra những món có chữ trên bánh
const monCoChu = items.filter((item) => item.cakeMessage !== undefined);

// map: biến mỗi món thành một thứ khác, ở đây là lấy tên
const tenCacMon = items.map((item) => item.productName);

Ký hiệu => (mũi tên) là cách viết ngắn của một hàm nhỏ: (item) => item.productName nghĩa là “nhận vào một item, trả ra tên của nó”.

Hàm: một công thức có tên

Hàm (function) là một đoạn công thức được đặt tên, nhận đầu vào (tham số), làm việc gì đó, và trả ra đầu ra (giá trị trả về). Giống công thức “Làm kem bơ”: đầu vào là bơ và đường, đầu ra là kem bơ. Đặt tên rồi thì lần sau chỉ cần nói “làm kem bơ” thay vì đọc lại từng bước.

TS
//        tên hàm      đầu vào: tên và kiểu         kiểu đầu ra
function tinhTamTinh(items: OrderItem[]): number {
  let tong = 0;
  for (const item of items) {
    tong = tong + item.unitPrice * item.quantity;
  }
  return tong;  // "return" = trả kết quả ra ngoài và kết thúc hàm
}

const ketQua = tinhTamTinh(donHang);  // "gọi" hàm: đưa nguyên liệu vào, nhận kết quả

Hàm thuần và hàm có tác dụng phụ

Đây là phân biệt rất đáng giá khi review code:

  • Hàm thuần (pure function): chỉ tính toán từ đầu vào ra đầu ra, không đụng gì bên ngoài. Cùng đầu vào luôn cho cùng kết quả. tinhTamTinh là hàm thuần. Dễ hiểu, dễ kiểm thử, an toàn.
  • Hàm có tác dụng phụ (side effect): làm thay đổi thế giới bên ngoài: ghi database, gửi tin nhắn Zalo, trừ tiền, gửi email. Gọi hai lần có thể gây hậu quả hai lần.
TS
// Hàm có tác dụng phụ: mỗi lần gọi là một lần ghi database và một tin nhắn gửi đi
async function xacNhanDon(code: string): Promise<void> {
  await capNhatTrangThai(code, "da_xac_nhan");                 // ghi vào database
  await guiTinZalo(code, "Tiệm đã nhận đơn của bạn. Cảm ơn!"); // gửi tin cho khách
}

Hai chữ mới: async đánh dấu hàm có những việc tốn thời gian chờ (đợi database, đợi mạng), và await nghĩa là “chờ việc này xong rồi mới làm tiếp”. Code backend đầy async/await vì hầu như việc gì cũng phải chờ database hay dịch vụ bên ngoài.

Ghép lại: hàm tính tổng tiền một đơn bánh

Đây là đoạn code hoàn chỉnh mà bạn sẽ dùng cho bài tập. Hãy đọc chậm, từng khối một, đối chiếu với chú thích.

TS
// Kiểu giao hàng: chỉ được là một trong hai giá trị này
type DeliveryType = "pickup" | "delivery";

// "Khuôn" của một dòng đơn hàng
type OrderItem = {
  productName: string;
  unitPrice: number;     // đơn giá, VNĐ, số nguyên
  quantity: number;
  cakeMessage?: string;  // dấu ? nghĩa là không bắt buộc
};

const PHI_SHIP = 30_000;
const NGUONG_FREESHIP = 500_000;

// Hàm 1: cộng thành tiền của từng món
function tinhTamTinh(items: OrderItem[]): number {
  let tong = 0;
  for (const item of items) {
    tong = tong + item.unitPrice * item.quantity;
  }
  return tong;
}

// Hàm 2: tính phí ship theo quy tắc của tiệm
function tinhPhiShip(subtotal: number, deliveryType: DeliveryType): number {
  if (deliveryType === "pickup") {
    return 0;
  }
  if (subtotal >= NGUONG_FREESHIP) {
    return 0;
  }
  return PHI_SHIP;
}

// Hàm 3: ghép lại, trả về cả bốn con số
function tinhTongDon(items: OrderItem[], deliveryType: DeliveryType, deposit: number) {
  const subtotal = tinhTamTinh(items);
  const shippingFee = tinhPhiShip(subtotal, deliveryType);
  const total = subtotal + shippingFee;
  const conLai = total - deposit;   // số tiền khách còn phải trả sau khi đã cọc
  return { subtotal, shippingFee, total, conLai };
}

// Đơn của chị Hương: 1 bánh kem dâu 20cm + 2 hộp bánh quy, giao tận nơi, đã cọc 345.000đ (50% tiền bánh)
const donChiMai: OrderItem[] = [
  { productName: "Bánh kem dâu 20cm", unitPrice: 450_000, quantity: 1, cakeMessage: "Mừng sinh nhật Bin" },
  { productName: "Bánh quy hộp quà", unitPrice: 120_000, quantity: 2 },
];

console.log(tinhTongDon(donChiMai, "delivery", 345_000));
// Kết quả: { subtotal: 690000, shippingFee: 0, total: 690000, conLai: 345000 }

Luồng xử lý của tinhTongDon có thể vẽ thành sơ đồ, giúp bạn đối chiếu với quy tắc nghiệp vụ mà không cần đọc code:

Hình chữ ký Băng chuyền công đoạn
  1. Nhận: danh sách món, kiểu giao, tiền cọc
  2. Khách tự đến lấy?
  3. Tạm tính ≥ 500.000đ?
  4. Phí ship = 30.000đ
  5. Tổng = tạm tính + phí ship
  6. Còn lại = tổng − tiền cọc
Xem sơ đồ gốc (Hình 1)

Vuốt ngang để xem hết sơ đồ

Có

Không

Có

Không

Nhận: danh sách món, kiểu giao, tiền cọc

Tạm tính = cộng (đơn giá × số lượng) từng món

Khách tự đến lấy?

Phí ship = 0

Tạm tính ≥ 500.000đ?

Phí ship = 30.000đ

Tổng = tạm tính + phí ship

Còn lại = tổng − tiền cọc

Hình 1 Sơ đồ luồng
Đọc sơ đồ dạng chữ
  1. Nhận: danh sách món, kiểu giao, tiền cọc → Tạm tính = cộng (đơn giá × số lượng) từng món
  2. Tạm tính = cộng (đơn giá × số lượng) từng món → Khách tự đến lấy?
  3. Khách tự đến lấy? → Phí ship = 0 (Có)
  4. Khách tự đến lấy? → Tạm tính ≥ 500.000đ? (Không)
  5. Tạm tính ≥ 500.000đ? → Phí ship = 0 (Có)
  6. Tạm tính ≥ 500.000đ? → Phí ship = 30.000đ (Không)
  7. Phí ship = 30.000đ → Tổng = tạm tính + phí ship
  8. Phí ship = 0 → Tổng = tạm tính + phí ship
  9. Tổng = tạm tính + phí ship → Còn lại = tổng − tiền cọc

Hãy “chạy” bằng tay với đơn của chị Hương: tạm tính = 450.000 × 1 + 120.000 × 2 = 690.000. Giao tận nơi, nhưng 690.000 ≥ 500.000 nên phí ship 0. Tổng 690.000. Đã cọc 345.000, còn lại 345.000. Khớp với kết quả máy in ra.

Bàn thử

Sửa món, kiểu giao, tiền cọc và bật/tắt ‘>=’ ↔ ‘>’ → chạy tinhTongDon từng dòng, xem biến đổi giá trị; có sẵn 4 bài tập (bánh mì ngọt, đúng ngưỡng 500.000, vòng lặp ghi đè, đơn rỗng)

Bàn thử cần bật JavaScript.

Kết quả chỉ để tham khảo, không thay cho việc bạn tự duyệt.

Kiểu trong TypeScript: nhãn ghi rõ hộp đựng gì

Bạn đã thấy những chữ như : number, : string, OrderItem[] trong code. Đó là chú thích kiểu (type annotation), phần TypeScript thêm vào JavaScript.

Ẩn dụ: trong bếp, hộp đường dán nhãn “ĐƯỜNG”. Nếu ai đó định đổ muối vào, người kiểm tra sẽ chặn lại trước khi món bánh bị hỏng. Bộ kiểm tra kiểu (type checker) của TypeScript làm đúng việc đó: đọc code và báo lỗi trước khi chương trình chạy, thay vì để khách hàng phát hiện.

Ví dụ kinh điển: dữ liệu đọc từ ô nhập trên form luôn là chuỗi chữ. Trong JavaScript thuần, cộng một số với một chuỗi sẽ nối chuỗi, không cộng số:

TS
const tamTinh = 100_000;
const phiShipTuForm = "30000";            // giá trị lấy từ ô nhập: là chuỗi, không phải số
console.log(tamTinh + phiShipTuForm);     // JavaScript in ra "10000030000", không phải 130000

Một đơn 130.000đ biến thành “10 tỷ” trên hóa đơn. Với TypeScript, nếu hàm khai báo rõ tham số là number, lỗi bị bắt ngay khi viết code. Đây là những thông báo lỗi kiểu bạn sẽ gặp, kèm cách “dịch”:

Phiên agent

error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

Dịch: bạn đưa vào hàm một chuỗi, trong khi hàm cần một con số. (Đúng tình huống “30000” ở trên.)

Phiên agent

error TS2345: Argument of type '"giao-hang"' is not assignable to parameter of type 'DeliveryType'.

Dịch: kiểu giao hàng chỉ được là "pickup" hoặc "delivery", không có giá trị "giao-hang".

Phiên agent

error TS2551: Property 'quantiy' does not exist on type 'OrderItem'. Did you mean 'quantity'?

Dịch: gõ sai tên ô; TypeScript còn gợi ý tên đúng.

Phiên agent

error TS2322: Type 'string' is not assignable to type 'number'.

Dịch: đang cất một chuỗi vào hộp chỉ dành cho số.

Và một lỗi khi chạy (không phải lỗi kiểu) rất phổ biến:

Phiên agent

TypeError: Cannot read properties of undefined (reading 'unitPrice')

Dịch: code định “mở ô” unitPrice của một thứ không tồn tại, ví dụ lấy món thứ 6 trong một đơn chỉ có 2 món, hoặc sản phẩm không tìm thấy trong database.

Vì sao kiểu đặc biệt quan trọng khi làm việc với AI? Vì nó cho agent một vòng phản hồi tự động: agent viết code, chạy type checker, thấy lỗi, tự sửa, trước khi bạn phải nhìn tới. Bài Kiểm tra tĩnh: linter, formatter và type checker08-06 sẽ đi sâu hơn.

Cách nhờ AI giải thích từng dòng code

Bạn không cần tự đọc hiểu mọi thứ. AI là một gia sư kiên nhẫn, nếu bạn hỏi đúng cách:

  • Dán đoạn code ngắn (vài chục dòng), không dán cả file dài.
  • Nói rõ trình độ của bạn: “tôi không biết lập trình, giải thích như cho chủ tiệm bánh”.
  • Yêu cầu chạy thử với ví dụ cụ thể: “cho đơn có 2 món này, biến nào mang giá trị gì sau mỗi dòng”.
  • Hỏi về quy tắc, không chỉ cú pháp: “đoạn này đang cài quy tắc nghiệp vụ gì? Viết lại thành câu tiếng Việt.”
  • Đối chiếu: “so với quy tắc sau của tiệm tôi, code có chỗ nào khác không?”

Câu hỏi cuối cùng là quan trọng nhất. Bạn không cần đọc code giỏi hơn AI; bạn cần biết quy tắc của tiệm giỏi hơn AI.

Áp dụng vào dự án Bánh Mộc

Nhật ký công trình · Bánh Mộc

BM-261013-010

13.10.2026

  • Chị LanChủ chuỗi
Chị Lan tự tính tay ba đơn ở ngưỡng bằng máy tính bỏ túi và khoanh đơn rỗng bất thường

Agent vừa viết xong phần tính tiền cho Mộc OMS. Thay vì chỉ bấm thử giao diện, chị Lan làm ba việc:

  1. Nhờ agent dịch code thành quy tắc tiếng Việt. Agent liệt kê: “Phí ship 30.000đ cho đơn giao tận nơi có tạm tính dưới 500.000đ; miễn phí khi từ 500.000đ hoặc khách tự lấy.”
  2. Đối chiếu với danh sách quy tắc của tiệm (danh sách chị lập từ bài 01-01). Chị phát hiện agent thiếu một quy tắc: đơn có bánh kem tùy chỉnh phải cọc tối thiểu 50% tiền bánh (làm tròn lên nghìn đồng) mới được xác nhận. Đây là thứ AI không thể tự biết.
  3. Chạy code trong đầu với ba đơn ở ngưỡng: tạm tính đúng 500.000đ, 499.000đ, và đơn không có món nào. Đơn rỗng cho ra tổng 30.000đ, tức là chỉ có phí ship mà không có bánh. Chị yêu cầu agent thêm kiểm tra “đơn phải có ít nhất một món” ở backend và viết test cho cả ba trường hợp.

Chị Lan không viết dòng code nào. Nhưng chị đã tìm ra hai lỗi nghiệp vụ mà giao diện không bao giờ để lộ. Đó là vai trò “kiểm định viên” mà bài Vai trò mới của bạn00-04 đã nhắc tới.

Prompt mẫu

Prompt 1: giải thích từng dòng cho người mới.

Tôi là chủ tiệm bánh, không biết lập trình. Hãy giải thích đoạn TypeScript dưới đây
từng dòng một, bằng tiếng Việt đời thường. Sau đó:
1. Viết lại các quy tắc nghiệp vụ mà đoạn code đang cài, mỗi quy tắc một câu.
2. Chạy thử bằng tay với ví dụ: [mô tả một đơn cụ thể], ghi giá trị từng biến sau mỗi bước.
3. Chỉ ra các trường hợp ở ngưỡng (đúng bằng, rỗng, số âm) mà code có thể xử lý sai.
[dán code]

Prompt 2: đối chiếu code với quy tắc của bạn.

Đây là quy tắc tính tiền của tiệm tôi:
- Tiền là số nguyên VNĐ.
- Giao tận nơi: phí ship 30.000đ; đơn có tạm tính từ 500.000đ trở lên được miễn phí ship.
- Khách tự lấy: không tính ship.
- Đơn phải có ít nhất 1 món, số lượng mỗi món từ 1 đến 50.
Hãy đọc hàm tính tiền trong [đường dẫn file] và liệt kê mọi điểm code KHÁC với quy tắc trên,
kể cả điểm code xử lý thiếu. Chưa sửa, chỉ báo cáo kèm số dòng.

Prompt 3: dịch thông báo lỗi.

Tôi gặp lỗi sau khi chạy dự án (dán nguyên văn):
[dán lỗi]
Hãy giải thích bằng tiếng Việt dễ hiểu: lỗi này nghĩa là gì, xảy ra ở file và dòng nào,
nguyên nhân có thể là gì. Đề xuất cách sửa nguyên nhân gốc, không được tắt kiểm tra kiểu
hay dùng "any" để che lỗi.

Sai lầm thường gặp

  1. Sự cố 01

    Chỉ kiểm tra bằng giao diện, không đọc logic.

    Triệu chứng

    Bấm thử vài đơn bình thường, thấy đúng, coi là xong. Lỗi nằm ở các trường hợp ngưỡng không ai bấm thử.

    Cách tránh

    Nhờ AI dịch code thành quy tắc, đối chiếu từng quy tắc, chạy tay với ví dụ ở ngưỡng.

  2. Sự cố 02

    Chấp nhận tiền dạng số thập phân.

    Triệu chứng

    Sai số làm tròn nhỏ cộng dồn thành chênh lệch khi đối soát.

    Cách tránh

    Quy định trong file hướng dẫn agent: tiền là số nguyên VNĐ; phần trăm phải làm tròn ngay.

  3. Sự cố 03

    Để AI “sửa” lỗi kiểu bằng cách tắt kiểm tra.

    Triệu chứng

    AI đôi khi thêm any, as any, hoặc // @ts-ignore để lỗi biến mất. Lỗi không biến mất, chỉ bị giấu đi.

    Cách tránh

    Ghi rõ trong prompt và file hướng dẫn: không dùng any hay @ts-ignore để che lỗi; sửa nguyên nhân gốc.

  4. Sự cố 04

    Không phân biệt hàm thuần và hàm có tác dụng phụ.

    Triệu chứng

    Review hàm gửi tin nhắn cũng hời hợt như hàm cộng số.

    Cách tránh

    Đánh dấu các hàm ghi database, gửi tin, xử lý tiền là “vùng cần review kỹ” và yêu cầu test cho chúng.

  5. Sự cố 05

    Dán cả file dài cho AI giải thích.

    Triệu chứng

    Câu trả lời dài, chung chung, bạn không học được gì.

    Cách tránh

    Dán từng đoạn ngắn, kèm câu hỏi cụ thể và một ví dụ dữ liệu.

Checklist

Phiếu nghiệm thu

Bài tập thực hành

Các bài 1 đến 4 dùng đoạn code “Ghép lại: hàm tính tổng tiền một đơn bánh” ở trên. Hãy tự tính ra giấy trước, rồi mới xem đáp án.

TS
tinhTongDon([{ productName: "Bánh mì ngọt", unitPrice: 25_000, quantity: 4 }], "delivery", 0);

Đáp án: tạm tính 100.000; giao tận nơi và dưới 500.000 nên phí ship 30.000; tổng 130.000; còn lại 130.000.

TS
tinhTongDon(
  [
    { productName: "Bánh kem dâu 20cm", unitPrice: 450_000, quantity: 1 },
    { productName: "Bánh mì ngọt", unitPrice: 25_000, quantity: 2 },
  ],
  "delivery",
  0
);

Câu hỏi phụ: nếu agent viết subtotal > NGUONG_FREESHIP thay vì >=, kết quả đổi thế nào? Đáp án: tạm tính đúng 500.000; với >= phí ship 0, tổng 500.000. Với >, phí ship 30.000, tổng 530.000. Quy tắc “từ 500.000đ” nghĩa là phiên bản >= mới đúng.

TS
function tinhTamTinh(items: OrderItem[]): number {
  let tong = 0;
  for (const item of items) {
    tong = item.unitPrice * item.quantity;
  }
  return tong;
}

Đáp án: 240.000. Mỗi vòng lặp ghi đè tong thay vì cộng dồn, nên chỉ giữ thành tiền của món cuối cùng (2 hộp bánh quy). TypeScript không báo lỗi vì kiểu vẫn đúng; chỉ có test hoặc người đọc logic mới bắt được. Đây là ví dụ cho thấy kiểu không thay thế được việc kiểm tra nghiệp vụ.

TS
tinhTongDon([], "delivery", 0);

Đáp án: tạm tính 0; giao tận nơi và 0 nhỏ hơn 500.000 nên phí ship 30.000; tổng 30.000. Code “đúng” theo từng dòng nhưng sai về nghiệp vụ: không ai đặt một đơn chỉ có phí ship. Bài học: cần một quy tắc “đơn phải có ít nhất 1 món”, kiểm tra ở backend trước khi tính tiền. Hãy viết quy tắc này thành một câu prompt yêu cầu agent bổ sung kèm test.

  1. Bài 1

    Cơ bản

    Đơn bánh mì ngọt

  2. Bài 2

    Cơ bản

    Đúng ngưỡng

  3. Bài 3

    Nâng cao

    Tìm lỗi trong vòng lặp

    Agent sửa hàm tinhTamTinh thành như sau. Với đơn của chị Hương, hàm trả về bao nhiêu?

  4. Bài 4

    Nâng cao

    Đơn rỗng

Thuật ngữ trong bài

Biến (variable)
Hộp có tên để chứa một giá trị; let đổi được, const không
Chú thích (comment)
Ghi chú cho người đọc, bắt đầu bằng //, máy bỏ qua
Kiểu dữ liệu (data type)
Loại giá trị: string, number, boolean, array, object
undefined / null
Giá trị “không có gì”
Điều kiện (if/else)
Rẽ nhánh theo đúng/sai
Vòng lặp (loop)
Lặp lại một việc cho từng phần tử
reduce / filter / map
Gom danh sách thành một giá trị / lọc / biến đổi từng phần tử
Hàm (function)
Công thức có tên, nhận đầu vào, trả đầu ra
Tham số (parameter)
Đầu vào của hàm
Giá trị trả về (return)
Đầu ra của hàm
Hàm thuần (pure function)
Chỉ tính toán, không thay đổi gì bên ngoài
Tác dụng phụ (side effect)
Thay đổi bên ngoài: ghi database, gửi tin nhắn
async / await
Đánh dấu việc cần chờ / chờ việc đó xong
TypeScript
JavaScript có thêm hệ thống kiểu
Type checker
Công cụ kiểm tra kiểu và báo lỗi trước khi chạy

Đọc thêm

Nghiệm thu tờ 01-04

Đọc xong và tự kiểm theo phiếu nghiệm thu, rồi đánh dấu tờ này.

Tác giả
Phú Digital
Đội ngũ PDL Digital — triển khai website, giải pháp AI và digital marketing cho doanh nghiệp.
Tư vấn 1:1

Muốn dựng phần mềm riêng cho doanh nghiệp của bạn?

Kỹ sư PDL cùng bạn chọn bước đầu tiên phù hợp — phản hồi trong giờ làm việc (T2–T7, 8h–18h).

<script src="https://cdn.jsdelivr.net/npm/page-flip/dist/js/page-flip.browser.js"></script>

<div id="container-flipbook" style="display:flex; justify-content:center;">
    <div id="my-flipbook">
       <div class="page"> <img src="https://pdl.vn/wp-content/uploads/2025/05/AI-Google-Search.jpg" /> </div>
       <div class="page"> <img src="https://pdl.vn/wp-content/uploads/2025/05/wearable-tech-advertising.jpg" /> </div>
       <div class="page"> <img src="https://pdl.vn/wp-content/uploads/2025/05/multimodal-embeddings-digital-marketing.jpg" /> </div>
    </div>
</div>
#my-flipbook {
    box-shadow: 0 0 20px rgba(0,0,0,0.2);
    margin: 20px auto;
    background-color: #f0f0f0;
}

.page {
    background-color: white;
    overflow: hidden;
}

.page img {
    width: 100%;
    height: 100%;
    object-fit: cover; /* Giúp ảnh vừa vặn trang sách */
}
// Đảm bảo thư viện đã sẵn sàng
function initFlipbook() {
    const el = document.getElementById("my-flipbook");
    if (!el || !window.St) return; // Nếu chưa thấy thư viện St thì thoát

    const pageFlip = new St.PageFlip(el, {
        width: 550,
        height: 733,
        size: "stretch",
        minWidth: 315,
        maxWidth: 1000,
        minHeight: 420,
        maxHeight: 1350,
        showCover: true,
        maxShadowOpacity: 0.5,
    });

    pageFlip.loadFromHTML(document.querySelectorAll(".page"));
}

// Chạy khởi tạo
if (document.readyState === 'complete') {
    initFlipbook();
} else {
    window.addEventListener('load', initFlipbook);
}
PDL · Tư vấn 1:1

Nhận tư vấn
miễn phí

Để lại thông tin, chuyên viên PDL sẽ liên hệ để hiểu nhu cầu và đề xuất giải pháp phù hợp ngân sách của bạn.

  • Phân tích nhanh hiện trạng website, quảng cáo, kênh bán hàng
  • Đề xuất lộ trình & báo giá minh bạch, rõ từng hạng mục
  • Không ràng buộc: nghe tư vấn xong mới quyết định
Giờ làm việc T2–T7 · 08:00–18:00

Chỉ mất khoảng 30 giây

Bạn cần tư vấn về

🔒 Thông tin được bảo mật, chỉ dùng để PDL liên hệ tư vấn.