Đã bao giờ bạn gặp tình huống này chưa? Viết xong tính năng, test thấy chạy "ngon" trên máy mình, đẩy lên production cái là lỗi tùm lum. Mở lại code, nhìn hoài không biết lỗi nằm đâu. Không có log, không có dấu vết, không khác gì mò kim đáy bể.
Thực tế: Code chạy được chưa chắc đã ổn. Ổn ở đây là ổn định, dễ bảo trì, dễ debug, dễ mở rộng. Viết log và biết debug không chỉ là chuyện dành cho các team DevOps hay "mấy ông senior", mà là chuyện ai viết code cũng cần phải quan tâm.
Chúng ta sẽ cùng nói về:
- Vì sao chỉ "chạy được" thì chưa đủ?
- Viết log như thế nào cho hợp lý?
- Làm sao để debug hiệu quả?
1. "Chạy được" chỉ là điểm bắt đầu
Code chạy được, tính năng hoạt động đúng là điều ai cũng muốn. Nhưng nếu code:
- Khó đọc, khó hiểu
- Không có log, hoặc log quá trời mà chẳng giúp được gì
- Dính bug nhưng không trace được nguồn gốc
- Gây lỗi ở production nhưng chẳng ai biết vì không cảnh báo
Thì xin chia buồn: bạn mới chỉ xong phần "bề nổi". Code tốt không chỉ là đúng logic, mà còn phải dễ bảo trì, dễ kiểm tra, dễ mở rộng. Đó mới là cái "ổn" trong ổn định.
Hồi mới đi làm, mình từng bị hỏi: "Tại sao cái API này lại cần tận 2s? em có nắm được tại sao không?" – và lúc đó mình chỉ biết ú ớ vì trong đó chỉ chứa vài câu query
thôi mà.
Kể từ hôm đó, mình mới nhận ra, chạy ngon ở local
thì chưa chắc ngon ở production
. Vì sao ư? vì data
khác nhau, vì cấu hình server khác với máy của mình,.... Rất nhiều nguyên nhân dẫn đến việc ở local ngon nhưng production thì không.
2. Tối ưu query - Gốc rễ của nhiều vấn đề hiệu năng.
Trong quá trình log và debug, không ít lần mình phát hiện ra "thủ phạm" gây ra sự chậm chạp là những câu truy vấn database thiếu tối ưu.
Một vài dấu hiệu bạn nên kiểm tra query:
- API trả về chậm bất thường dù logic đơn giản.
- Log cho thấy thời gian xử lý ở bước DB quá cao.
- ...
Cách tối ưu:
- Chỉ lấy những trường cần thiết:
SELECT
cụ thể thay vìSELECT *
. - Thêm index đúng chỗ: Đặc biệt ở các cột lọc
WHERE
, sắp xếpORDER BY
, joinJOIN ON
. - Sử dụng
lazy loading
hoặcphân trang
: Đừng load all nếu dữ liệu có thể tới hàng nghìn dòng. - Tránh truy vấn lặp
(N+1)
chunk
data để xử lý chứ không xử lý cả cục.Cache
data khi cần thiết.
1 số công cụ hỗ trợ:
EXPLAIN
để phân tích kế hoạch thực thi SQL.- ORM Profiler: Laravel Debugbar, Sequelize logging, Prisma debug,...
Việc tôi ưu query
, cache
đúng cách có thể giảm thời gian phản hồi của API xuống rất nhiều.
3. log và vì sao cần viết log?
Log không phải để "cho có". Nó là nhật ký hoạt động của hệ thống. Khi bạn không ở đó để nhìn thấy điều gì xảy ra, log sẽ là đôi mắt thay bạn quan sát mọi thứ.
Những lợi ích cụ thể của log:
- Giúp kiểm tra hệ thống đang hoạt động đúng chưa.
- Tìm nguyên nhân khi có lỗi xảy ra.
- Theo dõi hành vi người dùng, hệ thống, hoặc những bất thường.
- Là cơ sở để tối ưu hóa hiệu năng, phân tích dữ liệu sau này.
Ví dụ như khi làm việc với time
thì timezone
chắc chắn nhiều dev sẽ gặp phải và mình cũng vậy. Lúc đó mình chỉ chăm chăm vào các điều kiện
, logic
mà không để ý tới timezone
mới là nguyên nhân chính dẫn tới lỗi thời gian chạy bị sai. Nên cái giá là chậm deadline
🙄
=> Log tốt giống như việc bạn để lại bản đồ dẫn đường cho chính mình trong tương lai.
4. Nguyên tắc viết log hiệu quả
Log là tốt nhưng không phải cứ nhiều là tốt. Phải biết log đúng nơi, đúng chỗ mới là hiệu quả. Dưới đây là vài nguyên tắc giúp bạn log một cách có chiến lược:
Cấp độ log phổ biến:
DEBUG
: Thông tin chi tiết để debug (chỉ bật ở môi trường dev)INFO
: Thông tin chung về tiến trình hoạt độngWARN
: Có dấu hiệu bất thường nhưng chưa đến mức lỗiERROR
: Có lỗi xảy ra, cần xử lý hoặc điều traFATAL
: Lỗi nghiêm trọng, hệ thống có thể ngưng hoạt động
Nên log những gì?
- Thời điểm bắt đầu và kết thúc xử lý một logic quan trọng.
- Dữ liệu đầu vào/đầu ra của API (nên giới hạn và không log nhạy cảm).
- Ghi rõ stack trace khi xử lý exception để dễ tìm.
- Những điều kiện bất thường: retry, timeout, mất kết nối,...
Tránh log:
- Thông tin nhạy cảm.
- Dữ liệu lớn, khó đọc -> tóm tắt thông tin cần thiết.
- Log vỗ nghĩa, không có tác dụng.
Tips:
- Dùng context: thêm userId, requestId vào log để dễ trace.
- Định dạng cho log (JSON hoặc template cụ thể).
5. Debug – kỹ năng sống còn của developer
Debug không chỉ để "gỡ bug" mà nó còn giúp bạn hiểu sâu hơn quá trình hoạt động bên trong logic, dữ liệu, và luồng xử lý để phát hiện và sửa chữa vấn đề.
Các kỹ thuật debug phổ biến:
🧩 1. Dùng breakpoint:
🧪 2. In log có chọn lọc:
🔁 3. Thử nghiệm từng bước:
🔍 4. Đọc call stack:
Một số lỗi nhỏ nhưng dễ dẫn tới bug:
- Dùng
==
thay vì===
trong JS. Ví dụ điển hình 1 == '1' => true 😂
6. Một vài thói quen tốt khi viết code
- Luôn đặt mình vào vai trò người khác đọc lại code/log sau này
- Log có mục tiêu, không spam log
- Test trong môi trường staging bằng log trước khi lên production
- Đọc log khi review pull request để xem đã đủ chưa
- Viết test case kèm log khi phát hiện bug mới để phòng tái xuất hiện
Kết luận
Viết code chạy được thì ai cũng làm được. Nhưng viết code ổn, dễ debug, dễ bảo trì thì đòi hỏi việc phải luyện tập và chú ý từng chi tiết nhỏ như log.
Nếu bạn muốn trở thành lập trình viên có thể giải quyết vấn đề thay vì chỉ viết xong chức năng thì hãy bắt đầu từ việc debug, log khi cần thiết và hiệu suất của chức năng.
Chúc bạn sớm thành thạo kỹ năng nhỏ mà cực kỳ quan trọng này! 🚀