- Ngay cả khi xây dựng một ứng dụng web nhỏ bằng Rust, vẫn thiếu trải nghiệm tích hợp kiểu Django, khiến việc tự ghép nối routing, đăng nhập, cơ sở dữ liệu và chức năng quản trị trở nên nặng nề
- Framework cần có nên gom sẵn routing/handler, template, phục vụ file tĩnh, đăng nhập, phân quyền, giao diện DB, công cụ quản trị, WebSockets và hot reloading
- Dù có các framework tối giản như actix-web, axum và các framework SPA như Dioxus, Leptos, Yew, chúng không thay bạn lắp ráp toàn bộ cấu hình cho một ứng dụng web
- Starter template có thể giảm phần thiết lập ban đầu, nhưng sau khi dự án đã rẽ nhánh, việc merge thay đổi và cập nhật thư viện vẫn trở thành gánh nặng bảo trì
newthướng tới một web toolkit gom các thành phần hiện có theo cách có chính kiến, với mục tiêu giúp khởi động ứng dụng web nhỏ trong vài phút thay vì vài ngày
Rust đang thiếu một điểm khởi đầu tích hợp cho phát triển web
- Ngay cả khi làm một dự án web nhỏ bằng Rust, vẫn cần nhiều công việc kết nối ban đầu hơn rất nhiều so với Django hoặc các framework tương tự
- Cách tiếp cận phổ biến trong cộng đồng Rust gần với việc tự ghép các bộ phận cần thiết lại với nhau
- Are We Web Yet? cũng hướng dẫn rằng trong phát triển web bằng Rust, thông thường bạn phải tự kết nối mọi thứ và nên dự trù thêm công việc thiết lập khi bắt đầu
- Phần việc bổ sung này không chỉ ở mức “nhiều hơn một chút”, mà thực tế có rất nhiều hạng mục phải xử lý trước khi thật sự bắt đầu dự án
- Nếu có một web framework tích hợp, việc thuyết phục dùng Rust cho ứng dụng web sẽ dễ hơn
- Các ưu điểm của Rust được nhắc đến gồm type system, hiệu năng và những quãng nghỉ uống cà phê trong lúc biên dịch
Các thành phần cơ bản mà gần như mọi ứng dụng web đều cần
-
Routing/handler
- Cần gửi request đến handler phù hợp
- Cần xử lý tham số đường dẫn; nếu có thông tin kiểu thì càng tốt
- Có xử lý query parameter và form cũng là điều tốt
-
Template
- Cần tạo HTML, và trong một số trường hợp cũng tạo JSON hoặc XML
- Cần các logic cơ bản như điều kiện, match/switch và vòng lặp
-
Phục vụ file tĩnh
- Cần phục vụ các tài nguyên như CSS
- Có thể xử lý bằng một server riêng, nhưng trong phát triển local và triển khai quy mô nhỏ, việc đưa vào cùng web server sẽ tiện hơn
-
Đăng nhập
- Ứng dụng thường có nhiều người dùng hoặc được triển khai trên mạng công cộng, nên chức năng đăng nhập gần như luôn cần thiết
- Vì việc tự kết nối mỗi lần khá phiền, nó nên dễ dùng ngay từ đầu
- Vẫn cần cho phép tùy biến và opt-out
-
Phân quyền
- Trong hệ thống có nhiều người dùng, dữ liệu được truy cập hoặc vai trò thường khác nhau
- Chỉ với mẫu
check(user, object, action)cũng đã có thể đi khá xa
-
Giao diện DB
- Cần một cách để lưu dữ liệu ứng dụng
- Một cách tiếp cận gần với ORM có thể hữu ích, nhưng cách nhẹ hơn cũng khả thi
- Vì được dùng cho đăng nhập, phân quyền và công cụ quản trị, nó trở thành một thành phần cơ bản
-
Công cụ quản trị
- Khi thiết lập ứng dụng trong môi trường local hoặc production, cần bootstrap ít nhất một người dùng hoặc một phần dữ liệu
- Một số tác vụ quản trị phổ biến nên được tích hợp sẵn để mang lại trải nghiệm trơn tru
-
WebSockets
- Có thể xây dựng chức năng push dữ liệu gần với thời gian thực hơn tới người dùng đang kết nối
-
Hot reloading
- Vì thay đổi code hoặc template cần được phản ánh nhanh nhất có thể, đây là phần rất quan trọng trong trải nghiệm lập trình viên
Các chức năng bổ sung cần cho dự án tồn tại lâu dài
-
Tác vụ nền
- Sẽ phát sinh các chức năng cần chạy theo lịch, nên có một cách nhất quán sẽ giúp việc phát triển dễ hơn
-
Giám sát/observability
- Cần thiết nếu hệ thống không phải là loại nhỏ nhất và ít quan trọng nhất
- Nó giúp ích rất nhiều vào đúng thời điểm bạn thật sự cần đến
-
Caching
- Có nhiều cách triển khai, tất cả đều làm tăng độ phức tạp, và việc có nhanh hơn hay không còn tùy tình huống
- Sẽ tốt nếu framework có câu chuyện ở cấp độ này, nhưng người dùng cũng có thể tự xử lý
-
Email và thông báo
- Nếu có chức năng đăng nhập, email gần như có thể trở nên cần thiết vì đặt lại mật khẩu
- Ngoài ra, chức năng thông báo có thể bổ sung khi cần mà không phải vấn đề lớn
-
Công cụ triển khai
- Sẽ tốt nếu có một cách nhất quán để deploy đến một vị trí cụ thể
- Chỉ cần một Dockerfile được tạo tự động có thể dùng trên host đã chọn cũng đã hữu ích
-
Bundling CSS/JS
- Sẽ tốt nếu công cụ web nhận biết CSS và JS để đưa chúng vào một cách tự nhiên
- Chưa chắc liệu phần này có bắt buộc phải tích hợp hay không
Khoảng trống mà hệ sinh thái web Rust hiện có để lại
- Rust đã có nhiều công cụ phát triển web, nhưng không có công cụ nào nhắm tới trải nghiệm tích hợp mong muốn
-
Web framework tối giản
- actix-web và axum gần với các framework nhỏ như Flask, Sinatra
- Chúng tận dụng type system của Rust để mang lại trải nghiệm phát triển web tốt, nhưng gần như không cung cấp thêm tính năng ngoài handler
- Phần lớn dự án có thể được xây bằng các framework tối giản này, nhưng việc phải tự kết nối các chức năng cần thiết mỗi lần vẫn rất phiền
-
Framework SPA
- Dioxus, Leptos, Yew lấp vào mảng dùng Rust cho cả backend lẫn frontend, và dùng WebAssembly cho rendering ở frontend
- Trải nghiệm tạo digital vigil bằng Yew rất thú vị, nhưng chưa chắc có muốn dùng trong môi trường production thực tế hay không
- Các framework này cũng rất tốt cho mục đích riêng của chúng, nhưng vẫn cần nhiều công việc kết nối
-
Tập hợp thư viện riêng lẻ
- Có nhiều thư viện template, đăng nhập, phân quyền và WebSocket
- Một số dự án và ví dụ tích hợp vài thành phần, nhưng khó tìm được thứ tích hợp tất cả các mảnh cần dùng
- Vì hệ sinh thái di chuyển nhanh, một số ví dụ có thể đã cũ
- “Cứ kết nối chúng lại” rốt cuộc vẫn là công việc phải khảo sát và hiểu đủ cách từng thư viện vận hành
Starter template không giải quyết được bài toán bảo trì
- Cách làm hiện tại thường là chọn một framework nền như actix-web hoặc axum, sau đó tìm các mảnh cần thiết, đặt lên trên và tự kết nối
- Starter template có thể giảm đau lúc ban đầu, nhưng gánh nặng bảo trì vẫn còn
- Phải giữ thư viện luôn cập nhật
- Phải ứng phó với các breaking change
- Khi dự án đã tách khỏi template, việc merge lại các thay đổi của template trở nên khó khăn
- Nếu vận hành nhiều dự án, thay vì cập nhật một framework, bạn phải cập nhật từng framework tùy biến trong số
nframework - Sẽ tốt hơn nếu một web framework đảm nhận toàn bộ cung cấp hướng dẫn nâng cấp giữa các phiên bản
- Breaking change vẫn có thể xảy ra, nhưng có thể được tài liệu hóa
- Có thể giảm tình huống phát sinh lỗi do thay đổi trong tương tác giữa hai thành phần vốn không biết rằng chúng sẽ được tích hợp với nhau
Web toolkit mà newt hướng tới
- Web framework Rust lý tưởng nên có các chức năng đã liệt kê ở trên, cùng với tài liệu tốt, changelog, quản lý phiên bản cẩn trọng, cách xử lý breaking change và cộng đồng
- Hiện chưa có công cụ như vậy, và cũng chưa chắc có ai khác đang xây dựng nó hay không
- Công cụ đang được phát triển giống một web toolkit ghép các building block hiện có theo cách có chính kiến hơn là một framework
- Toolkit này có tên là nicole's web toolkit, viết tắt là
newt- Được công khai tại public repository
- Hiện chưa ở trạng thái có thể sử dụng, và các thay đổi mới nhất cũng chưa được push
- Cũng chưa sẵn sàng nhận đóng góp
- Mục tiêu của
newtlà khi tạo một ứng dụng web nhỏ mới, có thể bắt đầu làm việc trên dự án thật trong vài phút thay vì mất vài ngày để kết nối mọi thứ - Một số thành phần cũng được lên kế hoạch xây từ đầu khi cần
- Cách đó có thể dễ hơn hoặc phù hợp mạch lạc hơn
- Hệ sinh thái Rust cần một trạng thái lành mạnh với nhiều toolkit như vậy, và tác giả kỳ vọng các công cụ khác cũng sẽ xuất hiện
1 bình luận
Ý kiến trên Hacker News
Thật ngạc nhiên khi Rocket(https://rocket.rs/) không có trong danh sách framework mà tác giả nêu ra
Tôi chưa trực tiếp dùng nó và thích axum/actix-web ít áp đặt hơn, nhưng theo hiểu biết của tôi thì mục tiêu của Rocket gần với kiểu framework đi kèm đầy đủ pin mà tác giả muốn hơn nhiều, và đây cũng là một dự án đã tồn tại khá lâu
Trong thời gian rất dài, nó cần nightly Rust để build, và với những người muốn dùng framework trong môi trường production thì đây là một điểm trừ rất lớn
Ngoài ra, nó từng mắc kẹt ở trạng thái release candidate 0.5.0 suốt khoảng 2 năm, và bản stable mới nhất khi đó tụt lại khá xa so với các framework web Rust khác. Nó cần nightly và cũng chưa hỗ trợ async
Bây giờ khi đã vượt qua cột mốc 0.5 thì có thể mọi thứ đã tốt hơn, nhưng lịch sử phát triển của Rocket vẫn khiến người ta ngần ngại khi so với các lựa chọn thay thế như Axum
Có một cái: Poem[1]
Tác giả có nhắc tới Flask, nhưng nếu nhìn vào phần “những gì cần có” thì cũng khó mà nói Flask đáp ứng được các yêu cầu đó. Tôi thật sự không thích Django, nhưng với những yêu cầu như vậy thì thứ gần nhất với mô tả của tác giả lại chính là Django
Theo nghĩa đó thì Poem cũng không hẳn là ứng viên hoàn hảo. Nhìn chung Poem khá giống FastAPI, và đó gần như là một lời khen. Tôi đã dùng khoảng năm sáu framework web Rust, và đa số đều bắt bạn đụng vào rất nhiều boilerplate ở bước thiết lập ban đầu. Nếu muốn ra kết quả nhanh thì đó là vấn đề, và ở điểm này Poem khá phù hợp
actix có hiệu năng rất tốt, nhưng nếu bạn không nhắm tới thời gian phản hồi dưới 30ms thì ngay từ đầu cũng không có nhiều lý do để xem actix. Nếu cần thứ gì đó kiểu Pydantic thì cũng có crate làm được phần nào: https://crates.io/crates/poem-openapi
[1] https://github.com/poem-web/poem
Điểm cốt lõi là nó phải là một “framework”
F# cũng đáng để thử
Nó có gần như mọi trò vui với hệ thống kiểu mà bạn muốn, đồng thời cũng có các công cụ và tiện ích cần thiết. Nhược điểm lớn là xử lý async và quản lý bộ nhớ của nó không ngốn thời gian của bạn nhiều như Rust, nên có nguy cơ bạn sẽ thật sự giải quyết được các yêu cầu kinh doanh
Dù vậy, có lẽ quá trình làm việc với Microsoft ở đâu đó sẽ bù vào khoảng trống đó
So với OCaml hay Haskell thì nó thế nào?
Có thể là ý kiến không phổ biến: Rust là ngôn ngữ hệ thống, và làm công việc web bằng Rust là lãng phí công sức
Có nhiều ngôn ngữ và hệ sinh thái tốt hơn hẳn cho mục đích đó
Cũng như trong Java, trong Rust bạn có thể dùng dependency injection để chia sẻ connection pool, và việc viết các tác vụ nền dựa trên thread cũng rất đơn giản
Google gần đây trong một bài trình bày nói rằng họ đo được các lập trình viên Rust không kém hiệu quả hay kém năng suất hơn lập trình viên Go [1]
Rust là một ngôn ngữ tuyệt vời, và hoàn toàn không cần bị giới hạn chỉ trong lập trình hệ thống. Nó có thể làm được nhiều hơn thế rất nhiều
[1] https://www.ardanlabs.com/news/2024/rust-at-google/
Nó nhẹ, có thể gọi C/C++ và mã mức thấp một cách dễ dàng và nhanh chóng, đồng thời cho bạn nhiều quyền kiểm soát trong networking. Không cần học một ngôn ngữ chỉ dành riêng cho ứng dụng như PHP hay các file cấu hình nginx/apache, bạn có thể làm gần như mọi thứ theo cách phổ dụng và trực quan
Sẽ rất hay nếu có một bản thay thế Rust cho thứ như libmicrohttpd, và nếu có thì có lẽ tôi sẽ dùng
Giao điểm giữa lập trình nhúng và lập trình web cũng vậy
Dù thế, nếu có thể chọn Django, .Net hay Go thì Rust nhìn chung rất có thể là một lựa chọn tệ
Một framework web được biên dịch tĩnh có thể dễ dàng chỉ dùng 1/10 đến 1/100 lượng bộ nhớ/CPU so với Rails, Django hay Flask
Python có Django, C# có ASP .NET Core, Ruby có Rails
Nếu thật sự muốn đưa Rust bùng nổ trong phát triển web thì phải tạo ra một giải pháp full-featured
Rocket có lẽ là thứ gần nhất, nhưng vẫn chưa “đi kèm đầy đủ pin” như các framework đã nêu ở trên
Điều tác giả đang tìm là phiên bản Rust của ASP.NET Core, và điều đó hoàn toàn ổn
Có người thích nhiều lựa chọn và tự lắp ghép, nhưng trong nhiều môi trường thì việc ai đó tuyển chọn sẵn các lựa chọn lại hiệu quả hơn nhiều
Những phản ứng kiểu “nếu tôi muốn X khác thì sao? Nó có thể tốt hơn Y% đấy!” là chuyện thường thấy, nhưng chúng bỏ qua việc bản thân sự tích hợp đã mang lại giá trị cực lớn. Từng thư viện riêng lẻ có thể là tốt nhất nếu nhìn độc lập, nhưng nếu chúng không khớp với nhau một cách trơn tru thì có thể biến thành một đống rác
Một phần lý do tôi thích lập trình với ASP.NET 8 là vì tôi hoàn toàn không cần bận tâm liệu hệ thống template có ăn khớp với xác thực, injection, routing, v.v. hay không
Không thấy nhắc tới loco-rs, poem, rocket sao? Đã có khá nhiều dự án nhắm tới trải nghiệm đi kèm đầy đủ pin rồi
Điểm khác giữa các dự án này với các framework như leptos là chúng có CLI hướng dẫn bạn. Đó cũng là điều tôi thích ở Symfony, và cũng chính là phần “lười biếng” mà tôi nghĩ tới
Có https://shuttle.rs
Không chỉ là một framework mà còn là công cụ tạo ra phần boilerplate web xung quanh, nên theo tiêu chuẩn của tôi thì như vậy đã đủ lười biếng rồi
Bài này đang bàn cùng lúc nhiều luận điểm khác nhau, nên lý tưởng nhất là nên tách từng điểm ra xử lý riêng
Nếu có pattern matching thì không nhất thiết phải cần router. Chỉ cần tách URL ra và match các biến tĩnh/động khi cần
Xác thực thì ở ngôn ngữ nào cũng thường либо tự làm, hoặc dùng SaaS như Firebase/Auth0, nên không hẳn là vấn đề bắt buộc thuộc về ngôn ngữ hay framework
Các công cụ CSS/JS cũng không thực sự hợp với nhiều framework frontend Rust như Dominator. Dominator được viết bằng Rust chứ không phải JS, và có cách tiếp cận styling riêng như gắn style vào signal để thay đổi theo thời gian thực
Tôi hiểu ý tác giả muốn nói. Thực tế tôi cũng đã phải đi lòng vòng nhiều lần để giải quyết nhiều mục trong bài, và đúng là khá đau đầu. Ví dụ, https://github.com/dakom/dominator-workers-fluent-auth xử lý nhiều tác vụ được nhắc ở đây trên nền tảng framework Cloudflare Workers, đồng thời bổ sung cả bản địa hóa dựa trên Fluent như một mong muốn thêm
Sẽ rất tốt nếu có một full framework kèm đủ pin làm hết mọi thứ, nhưng nhiều dự án thực tế có lẽ sẽ muốn thay đổi những quyết định mang tính áp đặt như vậy và tự triển khai. Rust đã đủ trưởng thành cho web frontend, và nếu biết cần nhìn vào đâu thì có thể xử lý hết mọi thứ bằng wasm-bindgen v.v.
Web framework còn cung cấp nhiều thứ hơn thế rất nhiều như redirect URL, xử lý dấu gạch chéo cuối, quản lý URL phân biệt chữ hoa chữ thường, matching regex phức tạp, v.v.
Câu “xác thực thì ở ngôn ngữ nào cũng thường tự làm hoặc dùng SaaS” là sai. Django, Laravel, Rails và các ngôn ngữ kèm đủ pin có phần quản lý xác thực rất tốt. Cá nhân tôi cho rằng ở 90% tổ chức, giao xác thực cho bên ngoài là một sai lầm cực lớn
Việc một web developer có kinh nghiệm có thể dựng ngay 10 CRUD cơ bản chỉ trong một ngày mà không phải xử lý độ phức tạp không cần thiết là lợi thế cực lớn cho các doanh nghiệp nhỏ
Nếu bài này tập trung vào C++ thay vì Rust thì nhìn chung những điều tương tự có đúng không?
Đây là một ngôn ngữ hệ thống có rào cản gia nhập cao, thời gian biên dịch cũng đáng kể, và là ngôn ngữ được dùng rộng rãi chưa đến 10 năm, nên khó có thể kỳ vọng nó cạnh tranh với những thứ như Rails về mặt khả năng tiếp cận