•11 min read

Tại sao tôi học Rust với tư cách là một nhà phát triển web (và bạn cũng nên như vậy)

Tại sao tôi học Rust với tư cách là một nhà phát triển web (và bạn cũng nên như vậy)

Tôi đã dành sáu tháng để né tránh Rust. Tôi tự nhủ: "Nó dành cho các nhà phát triển kernel. Quá khó cho mấy thứ web." Rồi tôi cần một công cụ CLI nhanh hơn Python và di động hơn Node, và tôi đủ tò mò để thử.

Hai tháng sau, tôi viết Rust thường xuyên. Không phải vì tôi đổi nghề, và cũng không phải vì mọi dự án đều cần nó. Mà vì việc biết Rust đã âm thầm biến tôi thành một nhà phát triển JavaScript và Python giỏi hơn.

Audio Briefing
0:00 / 0:00

Rust Thực Sự Dạy Bạn Điều Gì

Borrow checker – thứ mà mọi người đều cảnh báo bạn – không phải là hình phạt. Nó là một người thầy.

Khi bạn viết JavaScript, bạn không nghĩ về việc ai sở hữu một biến, khi nào nó được giải phóng, hay liệu hai phần mã của bạn có thể thay đổi nó cùng lúc hay không. Runtime xử lý tất cả những điều đó, một cách vô hình. Rust buộc bạn phải suy nghĩ rõ ràng về nó, tại thời điểm biên dịch.

Bạn không cần phải viết Rust cho sản phẩm để nhận được giá trị từ nó. Việc học mô hình sở hữu sẽ thay đổi cách bạn suy luận về JavaScript, Python, Go: bất cứ thứ gì có trạng thái có thể thay đổi.

Vài tuần đầu tôi dành để tranh cãi với trình biên dịch. Sau đó tôi bắt đầu hiểu tại sao nó lại phàn nàn, và tôi nhận thấy mình đang viết JavaScript khác đi. Ít thay đổi tại chỗ hơn. Quyền sở hữu dữ liệu rõ ràng hơn. Các hàm không âm thầm chia sẻ các tham chiếu có thể thay đổi.

Advertisement

Sự Thay Đổi Mô Hình Tư Duy

Trong JavaScript, điều này cảm thấy hoàn toàn tự nhiên:

let data = fetchData();
processA(data);
processB(data);

Nhưng processA làm gì với data? Có thể không làm gì cả. Có thể nó thay đổi nó. Bạn phải đọc hàm. Rust làm cho quyền sở hữu rõ ràng:

let data = fetch_data();
process_a(&data);       // borrows: data is read-only here
process_b(&mut data);   // mutates: borrow checker tracks this

Một khi mô hình đó được hiểu rõ, bạn bắt đầu nhận thấy tất cả những nơi trong JavaScript của mình mà bạn đang truyền một đối tượng cho một hàm và hy vọng nó không sửa đổi nó. Rust chỉ khiến bạn phải nói ra điều đó.

Rust Thực Sự Xuất Hiện Ở Đâu Trong Phát Triển Web

Đây không phải là lý thuyết. Rust có những chỗ đứng vững chắc trong hệ sinh thái web:

WebAssembly: Rust biên dịch sang WASM tốt hơn hầu hết mọi thứ khác. Nếu bạn cần một phần logic quan trọng về hiệu suất chạy trong trình duyệt (xử lý hình ảnh, mật mã, phân tích cú pháp), Rust + WASM là một lựa chọn nghiêm túc. Bộ công cụ wasm-pack đã thực sự tốt.

Công cụ CLI: Xây dựng một công cụ nhị phân đơn với Clap rất nhanh, và kết quả được phân phối mà không có bất kỳ dependency runtime nào. Tôi đã xây dựng một công cụ xử lý tệp nhỏ cho một dự án, và việc phân phối nó có nghĩa là đưa cho ai đó một tệp nhị phân. Chỉ vậy thôi.

Edge Functions: Cloudflare Workers hỗ trợ Rust. Thời gian khởi động lạnh thấp hơn nhiều so với Node, và đối với các middleware nhạy cảm với độ trễ (kiểm tra xác thực, định tuyến A/B), điều đó rất quan trọng.

Công cụ phát triển: Rất nhiều công cụ bạn đang sử dụng đã được viết bằng Rust: Biome, SWC, Turbopack, Rolldown. Những công cụ này tồn tại vì Rust giúp việc xây dựng các công cụ JavaScript nhanh hơn 10 đến 50 lần so với các công cụ tương đương trong Node trở nên khả thi.

Bắt Đầu Mà Không Bị Choáng Ngợp

Sách Rust miễn phí tại doc.rust-lang.org/book và nó thực sự là một trong những cuốn sách kỹ thuật hay nhất mà tôi từng đọc. Hãy đọc hết mười chương đầu. Bạn sẽ gặp borrow checker khá nhiều ở chương 4. Hãy kiên trì với nó.

Nên bắt đầu thực tế từ đâu

Rustlings: các bài tập nhỏ trong terminal. Tốt cho việc rèn luyện phản xạ. Advent of Code in Rust: các bài toán nhỏ như câu đố, nơi bạn buộc phải giải quyết các nhiệm vụ thực tế. Xây dựng một công cụ CLI: chọn một thứ mà bạn thường dùng Python để làm và xây dựng nó bằng Rust thay thế.

Đừng cố gắng viết máy chủ web bằng Rust trong tuần đầu tiên. Đó là cách nhanh nhất để nản lòng. Bắt đầu với các chương trình độc lập nơi bạn kiểm soát tất cả các đầu vào.

Advertisement

Quan Điểm Của Tôi Sau Sáu Tháng

Tôi sẽ không tuyên bố Rust đã thay thế ngăn xếp hàng ngày của tôi. Hầu hết công việc của tôi vẫn là JavaScript và Python. Nhưng những mô hình tư duy mà tôi đã học được – suy nghĩ về quyền sở hữu, rõ ràng về sự thay đổi, quan tâm đến việc một hàm mượn hay tiêu thụ đầu vào của nó – đã thực sự thấm vào cách tôi viết bằng những ngôn ngữ đó.

Sự đầu tư là có thật. Trình biên dịch ban đầu không khoan nhượng. Nhưng có một điều gì đó vô cùng thỏa mãn khi viết mã mà trình biên dịch đã xác minh tính đúng đắn trước khi bạn chạy nó. Quay lại JavaScript sau đó, bạn bắt đầu nhận thấy mọi undefined và mọi thay đổi ngầm định như một điều bạn đã chọn chấp nhận.

Đó không phải là một điều tồi tệ để nhận ra.

Rust Học tập WebAssembly

Tìm hiểu sâu: Cơ chế cốt lõi

Khi chúng ta nhìn sâu hơn, các cơ chế cơ bản cho thấy sự tương tác phức tạp của các hệ thống. Trong phát triển hiện đại, việc hiểu các cơ chế này là điều phân biệt một người mới bắt đầu với một chuyên gia.

Hãy xem xét ví dụ thực tế này:

// A comprehensive example demonstrating advanced patterns
class ServiceManager {
  constructor() {
    this.services = new Map();
    this.initialized = false;
  }

  register(name, service) {
    if (this.services.has(name)) {
      throw new Error(`Service ${name} already registered`);
    }
    this.services.set(name, service);
  }

  async initializeAll() {
    this.initialized = true;
    for (const [name, service] of this.services) {
      if (typeof service.init === 'function') {
        await service.init();
      }
    }
  }

  get(name) {
    if (!this.initialized) {
      console.warn('Accessing services before initialization');
    }
    return this.services.get(name);
  }
}

Mô hình này đảm bảo rằng kiến trúc của chúng ta vẫn có thể mở rộng và mạnh mẽ ngay cả khi các yêu cầu kinh doanh thay đổi. Đó là một cách tiếp cận cơ bản mang lại lợi ích trong các ứng dụng quy mô lớn.

Ứng dụng thực tế và mở rộng quy mô

Việc triển khai điều này trong môi trường sản xuất đưa ra một loạt thách thức mới. Chúng ta phải tính đến tính đồng thời, quản lý trạng thái và rò rỉ bộ nhớ.

Ví dụ, khi xử lý các hệ thống có thông lượng cao, mọi tối ưu hóa nhỏ đều có giá trị. Chúng ta thường dựa vào các công cụ phân tích hiệu suất để xác định các điểm nghẽn không rõ ràng trong quá trình phát triển cục bộ.

Sơ đồ trên minh họa một chiến lược triển khai điển hình, nơi ứng dụng của chúng ta mở rộng theo chiều ngang.

Kiểm tra sự hiểu biết của bạn

Bạn cũng có thể thích

Các câu hỏi thường gặp

Các nhà phát triển quen thuộc với hệ thống kiểu nghiêm ngặt của TypeScript thường nắm bắt các kiểu, enum và khớp mẫu của Rust trong vài ngày. Trở ngại chính là mô hình sở hữu và borrow checker (lifetimes, tham chiếu có thể thay đổi so với bất biến). Hầu hết các nhà phát triển thấy rằng sau 2 đến 3 tuần thực hành với Rustlings hoặc Advent of Code, các lỗi trình biên dịch chuyển từ rào cản thành các rào chắn kiến trúc hữu ích.
Sử dụng Rust khi dịch vụ của bạn bị giới hạn bởi CPU, yêu cầu độ trễ đuôi dưới 5ms có thể dự đoán được mà không có tạm dừng thu gom rác, hoặc xử lý các tải trọng dữ liệu lớn như chuyển đổi hình ảnh, mật mã và phân tích cú pháp. Đối với các API CRUD tiêu chuẩn nặng về I/O với các thay đổi lược đồ thường xuyên, Node.js, Go hoặc Python thường cho phép lặp lại ban đầu nhanh hơn.
Không. Rust WebAssembly (WASM) bổ sung cho JavaScript chứ không thay thế nó. Thao tác DOM và xử lý sự kiện UI vẫn nhanh hơn và tiện lợi hơn trong JavaScript, trong khi các hoạt động tốn CPU như chỉnh sửa hình ảnh phía máy khách, băm mật mã, phân tích cú pháp các tập dữ liệu khổng lồ và tổng hợp âm thanh chạy nhanh hơn đáng kể khi được chuyển sang WASM thông qua wasm-pack.
Axum (được duy trì bởi nhóm Tokio) và Actix-web là hai framework sản xuất hàng đầu. Axum được ưa chuộng vì thiết kế tiện lợi, tích hợp Tokio liền mạch và hệ sinh thái middleware Tower. Actix-web luôn nằm trong top đầu các điểm chuẩn thông lượng của TechEmpower và cung cấp một bộ công cụ đã được thử nghiệm trong sản xuất rộng rãi.
Node.js chạy trên một vòng lặp sự kiện đơn luồng, nghĩa là các tác vụ nặng về CPU sẽ chặn luồng trừ khi được chuyển sang các luồng worker. Rust mang lại tính đồng thời không sợ hãi trên các hệ thống đa lõi: trình biên dịch thực thi an toàn luồng tại thời điểm biên dịch bằng cách sử dụng các trait Send và Sync, ngăn chặn các cuộc đua dữ liệu và hỏng bộ nhớ trước khi chạy.
Share this article:

Stay Updated

Get the latest posts delivered straight to your inbox.

Free Developer Utilities

Free In-Browser Developer Tools

Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.

Explore Tools
Advertisement
Fork riêng, giữ riêng tư, đồng bộ với upstream
developer-tools

Fork riêng, giữ riêng tư, đồng bộ với upstream

Giữ fork riêng tư của bạn đồng bộ với upstream bằng git rebase thay vì merge, một quy trình làm việc thực tế để thêm mã tùy chỉnh vào dự án mã nguồn mở mà không mất quyền truy cập vào các bản sửa lỗi.

Read more