+2

[Series: Tư duy bứt phá] Phần 2: Mindset - Từ "Code chạy được" đến "Hệ thống chạy ngon"

Ở phần trước, chúng ta đã cùng "bắt bệnh" hội chứng Thợ gõ. Nếu bạn đã sẵn sàng bước ra khỏi vùng an toàn của những chiếc ticket, thì chào mừng bạn đến với thực tại tàn khốc nhưng đầy hấp dẫn của một Kỹ sư phần mềm: Môi trường Production.

Một trong những câu nói cửa miệng nguy hiểm nhất của dân Dev là: "Ủa, trên máy em (Local) vẫn chạy bình thường mà?".

Đúng vậy, code của bạn chạy rất mượt trên chiếc Macbook Pro 16GB RAM, với một database rỗng tuếch chỉ có vài chục dòng dữ liệu mẫu. Nhưng "Code chạy được" chỉ là điều kiện cần. Để "Hệ thống chạy ngon", bạn cần một cú chuyển mình mạnh mẽ trong tư duy.

1. Ảo tưởng mang tên "Happy Path" và Cú tát từ thực tế

Thợ gõ thường lập trình dựa trên "Happy Path" – kịch bản hoàn hảo nhất nơi người dùng nhập đúng dữ liệu, mạng mẽo trơn tru, và database phản hồi trong một cái chớp mắt.

Hãy lấy một ví dụ thực tế: Bạn viết một API xử lý đặt hàng cho một hệ thống E-commerce bán mỹ phẩm.

  • Tư duy Thợ gõ: Nhận request -> Trừ tồn kho trong PostgreSQL -> Lưu thông tin đơn hàng -> Gọi API bên thứ 3 (Payment Gateway) để trừ tiền -> Trả về kết quả thành công. Code gọn gàng bằng Laravel, test qua Postman mất 200ms. Perfect!
  • Thực tế (Edge Cases): Công ty chạy chiến dịch Flash Sale lúc 0h. 10.000 user cùng lúc lao vào bấm "Mua hàng".
  • Điều gì xảy ra nếu hàng nghìn request cùng Update vào một dòng tồn kho? Lỗi Deadlock xuất hiện.
  • Điều gì xảy ra nếu API Payment Gateway bên thứ 3 bị nghẽn mạng và timeout? Kết nối bị treo, Pool kết nối tới database bị cạn kiệt, kéo theo toàn bộ hệ thống sập.

Tư duy Kỹ sư: Họ lường trước sự hỗn loạn. Thay vì xử lý đồng bộ (Synchronous), họ chuyển sang bất đồng bộ (Asynchronous). Ghi nhận đơn hàng trước, ném một event vào Message Queue (như Kafka) để các worker đằng sau từ từ xử lý việc trừ tồn kho và thanh toán. Họ thiết lập cơ chế Retry, Circuit Breaker để bảo vệ hệ thống khi service bên ngoài "đổ bệnh".

2. Sự trỗi dậy của NFR (Non-Functional Requirements)

Business Analyst (BA) thường chỉ giao cho bạn yêu cầu chức năng (Functional Requirement): "Hệ thống phải có tính năng X, Y, Z".

Kỹ sư là người phải tự bổ sung các Yêu cầu phi chức năng (NFR) vào trong đầu mình trước khi gõ dòng code đầu tiên:

  • Performance (Hiệu suất): API này được phép response tối đa bao nhiêu milliseconds?
  • Scalability (Khả năng mở rộng): Nếu lượng user tăng gấp 10 lần vào tháng sau, kiến trúc hiện tại có phình to theo được không?
  • Reliability (Độ tin cậy): Nếu một node server chết, hệ thống có tự động failover để chạy tiếp không?

Kỹ sư không bao giờ tin tưởng tuyệt đối vào tài nguyên hệ thống. Họ luôn giả định rằng: Mạng sẽ chậm, Ổ cứng sẽ đầy, và RAM sẽ cạn.

3. Nỗi ám ảnh về Tài nguyên (Resource Management)

Thợ gõ thường rất "hào phóng" với tài nguyên của server. Cần lấy dữ liệu? Cứ SELECT * hoặc load toàn bộ một mảng (array) khổng lồ vào RAM rồi dùng vòng lặp để filter.

Đến khi tính năng được đẩy lên Production, hệ thống lăn ra chết với màn hình đen ngòm và dòng log lạnh lùng: OOM (Out Of Memory). Ác mộng bắt đầu.

Tư duy Kỹ sư thể hiện ở cách họ quản lý tài nguyên: Họ biết rằng dùng Cache (như Redis) là tốt để tăng tốc độ. Nhưng bộ nhớ Redis là hữu hạn. Khi thiết kế hệ thống cache, một kỹ sư sẽ đặt câu hỏi:

  • Dữ liệu này cần sống trong bao lâu (TTL)?
  • Khi RAM của Redis đầy (đạt maxmemory), hệ thống sẽ cư xử thế nào? Họ không nhắm mắt dùng bừa, mà chủ động chọn một Eviction Policy (chính sách giải phóng bộ nhớ) phù hợp cứu sinh cho hệ thống. Dùng allkeys-lru để xóa các key ít được truy cập nhất? Hay dùng volatile-ttl để ưu tiên xóa những key sắp hết hạn? Quyết định nhỏ này quyết định việc hệ thống sống sót hay đột tử khi đạt giới hạn.

4. Code xong chưa phải là hết - Tư duy vận hành (Operations)

Một tính năng hoàn thiện không chỉ là tính năng vượt qua vòng Testing. Nó phải có khả năng được giám sát (Observability).

Khi bug xảy ra lúc 2 giờ sáng, bạn không thể cắm máy vào server Production để debug từng dòng lệnh. Kỹ sư giỏi rải những "chiếc bánh mì" (Log, Metric, Tracing) dọc theo luồng chạy của ứng dụng. Họ phân biệt rõ lúc nào dùng Log::info, lúc nào dùng Log::error, và đính kèm Context (Request ID, User ID) để khi tra cứu trên Kibana (Elasticsearch), họ biết chính xác điều tồi tệ gì đã xảy ra.

Tạm kết

Sự khác biệt lớn nhất không nằm ở số năm kinh nghiệm hay số ngôn ngữ lập trình bạn biết. Nó nằm ở góc nhìn.

Thợ gõ nhìn vào Từng dòng code. Kỹ sư nhìn vào Sự vận động của cả hệ thống.

Hãy ngưng tự mãn khi thấy màn hình in ra chữ "Success". Hãy bắt đầu nghi ngờ nó, bẻ gãy nó ở môi trường Local, trước khi User làm điều đó trên Production.

Vậy làm thế nào để rèn luyện góc nhìn này? Làm sao để không bị lạc lối giữa rừng công nghệ và biết cách chọn đúng "vũ khí" cho từng bài toán? Đón xem Phần 3: Bức tranh lớn - Rời mắt khỏi IDE để nhìn vào System Architecture.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí