Một quyết định táo bạo của CTO về Rust, những giấc mơ hiệu suất, và cuộc “thay máu” đội ngũ đầy tốn kém. Bạn có thể biết mọi chuyện diễn ra thế nào và chúng ta học được gì từ đó.
Cuộc “Đập Đi Xây Lại” Thay Đổi Tất Cả
Mọi chuyện khởi đầu với ý định tốt đẹp.

CTO, tạm gọi là Arun, có một tầm nhìn lớn: viết lại toàn bộ bằng Rust nói:
“Hệ thống backend của chúng tôi đang trong giai đoạn cực kỳ khó khăn và bế tắc. Hiệu suất bị nghẽn, codebase ngày càng lộn xộn, và cả team thì mệt mỏi với đống công nghệ “cổ lỗ sĩ”. Hầu hết code được viết bằng Node.js và Python.”
Đây không phải là quyết định anh ấy tự ý đưa ra. Arun đã tìm hiểu về khả năng an toàn bộ nhớ, hiệu năng “khủng khiếp”, và khả năng kiểm soát sâu sát hệ thống mà Rust mang lại. Chúng tôi đã gặp quá nhiều vấn đề với những đợt dừng GC (Garbage Collection) và các lỗi runtime exception. Rust lúc đó trông như một “viên đạn bạc”.
“Rust không chỉ giúp backend của chúng ta nhanh hơn,” anh nói, “nó sẽ ép chúng ta phải có kỷ luật và định hình lại văn hóa làm việc.”
Và đúng là vậy. Chỉ có điều, không theo cách anh ấy mong đợi.
Tại Sao Rust Lại Có Vẻ Là Câu Trả Lời
Arun đúng một phần. Rust thực sự giải quyết được những vấn đề nhức nhối mà các ngôn ngữ như Python hay Node thường gặp phải:
- Không có Garbage Collector nghĩa là ít bị giật lag (latency spikes) hơn.
- Mô hình Ownership (quyền sở hữu) giúp tránh lỗi null pointer và rò rỉ bộ nhớ (memory leaks).
- Fearless Concurrency (lập trình đồng thời không sợ hãi) — Rust bắt buộc phải đảm bảo an toàn luồng (thread-safety) ngay tại thời điểm biên dịch (compile time).
Đây là một ví dụ đơn giản minh họa cách Rust tránh các lỗi runtime phổ biến:
Ví dụ Python (có thể crash khi chạy):
def get_user_age(user):
return user["age"]
print(get_user_age(None)) # Bùm: Lỗi TypeError
Tương đương trong Rust (compiler bắt lỗi ngay):
fn get_user_age(user: Option<&User>) -> Option<u8> {
user.map(|u| u.age)
}
Trong Rust, bạn buộc phải xử lý kiểu Option
, đảm bảo ứng dụng của bạn xử lý các giá trị “giống null” ngay trước khi code chạy.
Công Cuộc Viết Lại Khởi Động
“Chúng tôi bắt đầu với một microservice cái service xử lý chuyển đổi tiền tệ” Arun nói khi cùng với một kỹ sư junior và họ đã viết lại nó bằng Rust chỉ trong hai tuần.
Các benchmark hiệu suất thật sự ấn tượng:
- Độ trễ giảm 60%.
- Mức sử dụng CPU giảm một nửa.
- Dung lượng bộ nhớ giảm đáng kể.
Anh ấy mừng ra mặt. “Nếu làm được với một service,” anh nói, “chúng ta sẽ làm được với tất cả.”
Chẳng bao lâu sau, mỗi kỹ sư đều nhận được một nhiệm vụ mới: học Rust, và viết lại service của mình.
Không Phải Ai Cũng “Đồng Lòng”
Đây là lúc mọi thứ bắt đầu có vấn đề.
Nhiều kỹ sư đã dành hàng năm trời làm việc với Python và Go. Họ rất năng suất và ra mắt tính năng cực nhanh. Rust, dù có nhiều lợi ích, nhưng lại có đường cong học tập cực dốc. Một số dev phải mất hàng tuần chỉ để “tiêu hóa” được borrow checker. Các PR (Pull Request) thì nằm ì ra đó không được review. Lịch trình bị chậm lại. Sự chán nản ngày càng lớn.
Vấn đề cốt lõi không phải là Rust. Vấn đề nằm ở cách nó được giới thiệu một cách đột ngột, không có sự đồng thuận từ team hay hỗ trợ cần thiết.
Và Rồi, Quyết Định Được Đưa Ra
Sau ba tháng, quá trình chuyển đổi mới đi được nửa đường. Số lượng bug tăng vọt. Kỹ sư thì mất hết động lực. Tốc độ ra mắt tính năng gần như bằng 0.
Arun đưa ra một quyết định làm mọi người choáng váng: anh ấy sa thải toàn bộ team backend.
“Tôi cần một team tin tưởng vào tầm nhìn Rust-first,” anh ấy nói.
Sau đó, anh thuê một team mới hầu hết là các kỹ sư Rust từ cộng đồng lập trình hệ thống. Những người tài năng, nhưng hoàn toàn xa lạ với sản phẩm và nghiệp vụ của công ty.
Viết Lại Là Một Rủi Ro Kinh Doanh
Team mới cuối cùng cũng hoàn thành và triển khai bản viết lại hoàn toàn bằng Rust. Hiệu suất cải thiện rõ rệt trên toàn hệ thống không thể phủ nhận.
Nhưng chúng tôi cũng đã mất sáu tháng phát triển tính năng. Khách hàng nhận ra điều đó.
Một khách hàng lớn đã chờ đợi một tích hợp cực kỳ quan trọng họ đã bỏ đi. Doanh số sụt giảm. Các vấn đề về Product-Market Fit (sự phù hợp sản phẩm với thị trường) lại nổi lên. Những kỹ sư từng là chuyên gia trong lĩnh vực đã ra đi, và kiến thức “bộ lạc” (tribal knowledge) cũng mất theo họ.
Rust không làm hỏng bất cứ điều gì.
Sai lầm nằm ở tư duy “đập đi xây lại” và cách thực thi thiếu quan tâm đến yếu tố con người.
Kiến Trúc Trông Như Thế Nào
Đây là sơ đồ cấp cao đơn giản trước và sau của backend:
Trước (Python/Node):
[ API Gateway ]
|
[ Auth Service ] <-- Python
|
[ Order Service ] <-- Node.js
|
[ Currency Service ] <-- Python
Sau (Rust):
[ API Gateway ]
|
[ Auth Service ] <-- Rust (actix-web)
|
[ Order Service ] <-- Rust (axum)
|
[ Currency Service ] <-- Rust (tokio + reqwest)
Mỗi service đều dùng tokio
cho việc thực thi async và serde
cho JSON. Việc triển khai là qua Docker và được điều phối bằng Kubernetes không có thay đổi lớn về hạ tầng, chỉ là thay đổi ngôn ngữ và bộ công cụ.
Những Bài Học Rút Ra
- Đừng đập đi xây lại những gì không cần thiết. Hãy cải thiện từng chút một. Refactor những phần chậm, chứ không phải toàn bộ hệ thống.
- Viết lại không phải là vấn đề kỹ thuật mà là vấn đề văn hóa. Bạn không thể ép buộc một sự thay đổi lớn mà không có sự đào tạo, hướng dẫn và không gian để thất bại.
- Rust rất đỉnh nhưng khó. Nó hoạt động tốt nhất khi team có đủ thời gian để học, chứ không phải khi bị thúc ép.
- Lắng nghe team của bạn. Những kỹ sư giỏi nhất không chỉ viết code họ còn giữ lại ngữ cảnh, lịch sử và những kinh nghiệm quý báu.
Lời Cuối
Rust đã giải quyết được những vấn đề thực sự. Nhưng cách chúng tôi áp dụng nó lại gây hại nhiều hơn là có lợi ít nhất là trong ngắn hạn.
Sáu tháng sau, Arun thừa nhận: “Nếu được làm lại, tôi sẽ giữ team, và giúp họ phát triển với Rust thay vì thuê những người lạ để bắt đầu từ con số không.”
Công cụ quan trọng. Nhưng con người quan trọng hơn.
P/S: Bài này lượm được thấy cũng có giá trị học hỏi nên dịch cho anh em tham khảo 🙂