29 điểm bởi GN⁺ 2024-04-27 | 13 bình luận | Chia sẻ qua WhatsApp
  • Về nhận định rằng chỉ cần quen với Rust thì mọi vấn đề sẽ biến mất
    • Dù đã quen với Rust, các vấn đề cốt lõi vẫn không biến mất
    • Game là những cỗ máy trạng thái phức tạp và yêu cầu liên tục thay đổi, nên không phù hợp với tính chất tĩnh và kiểm tra quá mức của Rust
    • Việc phải liên tục refactor code là một vấn đề tự mình gây ra
  • Vấn đề refactor quy mô lớn phát sinh do borrow checker
    • Rust buộc phải refactor thường xuyên hơn các ngôn ngữ khác
    • Trong bối cảnh yêu cầu game thay đổi liên tục, bạn sẽ phải vật lộn với borrow checker và cần tái cấu trúc code
    • Khó đồng ý với nhận định rằng refactor sẽ tạo ra code tốt. Code tốt được tạo ra bằng cách lặp lại ý tưởng và thử nghiệm
  • Indirection chỉ giải quyết được một phần vấn đề và làm giảm năng suất phát triển
    • Khi dùng indirection để xử lý vấn đề với borrow checker, logic code bị tách rời và trở nên phức tạp hơn
    • Trong game có các sự kiện liên kết với nhau, thời điểm cụ thể và rất nhiều trạng thái cần quản lý, nên indirection làm mọi thứ khó hơn
    • Trong Rust, ngay cả code đơn giản cũng phải viết dài dòng hơn để phục vụ indirection
  • ECS(Entity-Component-System) đang giải quyết sai vấn đề
    • Ưu điểm của ECS thực ra là ưu điểm của generational arena
    • ECS được nhìn nhận từ nhiều góc độ như dynamic composition, structure of arrays, giải pháp cho borrow checker của Rust, hay dynamically created generational arenas
    • Nhưng vẫn còn nghi ngờ liệu ECS có thật sự là cách phù hợp nhất cho phát triển game hay không. Cần chú trọng vào logic game hơn là hiệu năng hay composition
  • Generalized systems không dẫn tới gameplay thú vị
    • Nếu dùng các hệ thống quá tổng quát, gameplay sẽ trở nên nhàm chán
    • Game hay là game có những tương tác chi tiết được thiết kế cẩn thận, VFX được đồng bộ, có nhiều vòng playtest và thử nghiệm, phát hành sớm để nhận phản hồi
    • Rust theo đuổi những giá trị không phù hợp với việc prototype và iteration nhanh
  • Điều quan trọng trong phát triển game là prototype và iteration nhanh, nhưng các giá trị của Rust lại đi theo hướng ngược lại
    • Cốt lõi của phát triển game là bản thân trò chơi và trải nghiệm chơi, chứ không phải code không crash
    • Khả năng bảo trì của code game không phải giá trị quá quan trọng với game indie. Điều quan trọng là tốc độ iteration
    • Rust quá ám ảnh với việc tránh vấn đề đến mức bỏ lỡ những thứ thực sự quan trọng
  • Procedural macros còn kém rất xa reflection
    • Trong phát triển game, phải viết code cho nhiều mảng như system code, gameplay code, UI, VFX, audio và tool
    • Trong Rust, ngay cả việc đơn giản như "in đối tượng" cũng phải tự viết code hoặc tạo procedural macros
    • Procedural macros bị hạn chế hơn nhiều so với declarative macros và còn làm thời gian biên dịch lâu hơn
    • Reflection trong C# rất dễ dùng và cho phép phát triển nhanh khi hiệu năng không phải yếu tố quan trọng
  • Hot reloading đóng vai trò quan trọng trong việc tăng tốc iteration
    • Hot reloading rất hữu ích cho immediate mode UI/drawing, debug, tinh chỉnh hằng số gameplay
    • Rust cũng có hot-lib-reloader, nhưng không hoàn hảo và cần lập kế hoạch cũng như dự liệu trước, nên hạn chế khả năng sử dụng sáng tạo
    • Nhà phát triển game muốn công cụ ở mức cao hơn là chỉ reload struct đơn giản
  • Abstraction không phải lựa chọn mà là bắt buộc
    • Ví dụ thực tế) khi cần hành vi khác nhau tùy theo trạng thái UI, trong Rust phải refactor hoặc lạm dụng clone
    • Nhiều khi không phải business logic thay đổi, mà là phải sửa code để làm hài lòng compiler
    • Rust không có hệ thống kiểu cấu trúc như "kiểu có những field này", nên khi refactor phải sửa code ở nhiều nơi
  • Tình hình GUI của Rust là tệ nhất
    • Điều quan trọng trong UI game không phải data binding hay reactive update mà là khả năng tùy biến giao diện
    • Thứ cần cho UI game là GUI đẹp, sprite tùy biến, animation, vector shape, particle, effect, flash
    • Hiện không có thư viện Rust nào chuyên biệt cho GUI game
  • Orphan rule nên là tùy chọn
    • Orphan rule làm giảm mạnh năng suất phát triển để đổi lấy an toàn
    • Với application code chứ không phải library, cần có khả năng tắt orphan rule
  • Thời gian biên dịch đã được cải thiện, nhưng vẫn chậm nếu dùng proc macros
    • Proc macros như serde làm tăng đáng kể thời gian biên dịch
    • Với incremental build mất hơn 20-30 giây, việc tinh chỉnh chi tiết trở nên rất khó
  • Hệ sinh thái phát triển game bằng Rust có cảm giác bị thổi phồng
    • Không có nhiều người thực sự đang làm game
    • Nhiều dự án có website hoặc README hào nhoáng, trông rất nổi tiếng nhưng thực tế không phải vậy
    • Nếu thực sự muốn làm game, tác giả khuyên dùng godot-rust. Đừng quá cố chấp với giải pháp thuần Rust, tốt hơn là tận dụng engine trưởng thành
  • Lý do cho rằng global state bất tiện vì game là single-thread là chưa đúng
    • Việc dùng global state trong Rust rất bất tiện (static mut, AtomicRefCell, Rc v.v.)
    • Nhưng khác với backend service, game hầu như đều chạy single-thread nên sự bất tiện này là không cần thiết
    • Tác giả cho rằng Bevy đã sai khi đưa parallel systems vào. Mục tiêu là hiệu năng cao hơn, nhưng cuối cùng người dùng lại phải liên tục chỉ định thứ tự, làm mọi thứ bất tiện hơn
  • Dynamic borrow checking gây ra các crash bất ngờ sau khi refactor
    • Trong 2 năm dùng hecs, tác giả thường xuyên thấy các trường hợp crash do query chồng lấn
    • Khi dùng RefCell, chỉ cần hai chỗ cùng gọi .borrow_mut() là có thể gây crash ngoài dự đoán
    • Vấn đề không hẳn là code tệ, mà là Rust ép buộc những đợt refactor không cần thiết
    • Trong game, RefCell rất hữu ích nhưng Rust khiến việc dùng nó trở nên quá khó
  • Context object thiếu tính linh hoạt
    • Vì khó dùng global state trong Rust, người ta thường gom reference vào context object rồi truyền đi
    • Nhưng khi chỉ mượn một vài field, lỗi biên dịch lại xuất hiện do partial borrow
    • Người ta bảo hãy tách context ra và đổi cấu trúc, nhưng điều muốn làm là logic game; thay cấu trúc chỉ để làm hài lòng compiler là lãng phí thời gian

Ưu điểm của Rust

  • Một khi biên dịch được thì thường chạy rất ổn. Đặc biệt hữu ích khi viết công cụ CLI, xử lý dữ liệu hoặc thuật toán
  • Cho hiệu năng tốt mà không cần quá nhiều công sức. Tác giả có trải nghiệm nhanh hơn C# khoảng 1.5~2.5 lần
  • Enum được thiết kế rất tốt
  • Nhờ Rust analyzer mà trải nghiệm IDE được cải thiện đáng kể
  • Hệ thống trait được xây dựng tốt. Nếu orphan rule được nới lỏng hơn thì mức độ hữu dụng sẽ còn cao hơn nhiều

Ý kiến của GN⁺

  • Dù quan điểm về Rust nhìn chung khá tiêu cực, đây vẫn là kết luận mà tác giả rút ra sau nhiều thử nghiệm khác nhau nên có vẻ đáng để tiếp nhận một cách nghiêm túc. Đặc biệt, nhận định rằng trong lĩnh vực phát triển game thì tính thực dụng và tốc độ phát triển quan trọng đến mức nào, và Rust vẫn còn thiếu ở những điểm đó, là điều khá có lý.

  • Đồng ý rằng sự an toàn mà Rust hướng tới đôi khi có thể làm giảm nghiêm trọng năng suất phát triển. Khi viết code Rust, nhiều lúc người ta dành nhiều thời gian để làm hài lòng compiler hơn là tập trung vào chính logic, và điều này có lẽ bắt nguồn từ việc Rust vốn là ngôn ngữ được tối ưu cho lập trình hệ thống.

  • Ngược lại, phát triển game phần lớn diễn ra trong môi trường single-thread, nơi prototype và iteration nhanh là yếu tố quan trọng, nên việc kiểm tra an toàn quá mức đôi khi lại phản tác dụng. Đặc biệt, đã từng nghe nhiều câu chuyện về những người thử làm game bằng Rust từ thời đầu rồi bỏ cuộc, và có vẻ các vấn đề cốt lõi đến giờ vẫn chưa được cải thiện nhiều.

  • Dĩ nhiên, các game engine ra đời gần đây như Bevy có giúp việc phát triển game bằng Rust thuận tiện hơn, nhưng có lẽ vẫn còn cách rất xa so với các engine trưởng thành như Unity hay Godot. Như bài viết này nói, thay vì cố làm mọi thứ thuần Rust, một phương án thực tế hơn có thể là dùng Rust cùng với các engine sẵn có.

  • Những ưu điểm mà tác giả nhắc tới lại đặc biệt rõ rệt khi dùng Rust cho các lĩnh vực ngoài game. Nhất là trong các mảng như lập trình hệ thống hay phát triển web server, tính an toàn và hiệu năng cao của Rust là lợi thế lớn, nhưng trong phát triển game thì các ưu điểm đó dường như không mang lại nhiều giá trị tương ứng.

  • Cuối cùng, Rust không phải ngôn ngữ vạn năng mà là ngôn ngữ chuyên cho những domain nhất định, nên có lẽ cần cân nhắc kỹ xem nó có phù hợp với tính chất dự án của mình hay không.

13 bình luận

 
coremaker 2024-04-29

Tôi nghĩ rust là một ngôn ngữ được tạo ra để giải quyết những vấn đề phát sinh do nhiều kiểu sai sót khác nhau của lập trình viên, trong bối cảnh ngày càng ít nhà phát triển có thể viết mã toàn vẹn ở cấp độ lõi.

Nó không phù hợp để phát triển thật nhanh,
mà phù hợp hơn để phát triển một cách chính xác,
nên không thích hợp với những dự án cần triển khai trong khi liên tục phát sinh thêm yêu cầu từ người dùng.

Mặc dù vậy, việc vẫn mong chờ có thư viện UI
có lẽ là vì kỳ vọng rằng chỉ cần có một UI nhỏ gọn và đơn giản chạy trên nền mã vững chắc thì tính ứng dụng của nó sẽ trở nên tốt hơn nhiều.

 
kandk 2024-04-29

Tôi chưa từng làm phát triển game nên không rõ lắm,
nhưng có vẻ ngay từ đầu đã chọn sai ngôn ngữ, hoặc (nếu tốc độ lặp phát triển quan trọng thì đáng ra nên chọn ngôn ngữ ở mức script..) hoặc là chưa có hiểu biết đủ sâu về hệ thống.
Tôi nghĩ dù có chọn C++ thì có lẽ cũng sẽ gặp những vấn đề tương tự.

 
cosine20 2024-04-29

Đúng vậy. Nếu chọn C++ thì cũng sẽ có lựa chọn là Unreal, nhưng mà...

 
cosine20 2024-04-29

Trong thời đại này, tôi có cảm giác rằng các ngôn ngữ native như Rust hay C++ có vẻ phù hợp hơn với việc phát triển middleware như game engine hơn là phát triển game client.
Cũng giống như việc hầu như không có trường hợp phát triển web full-stack bằng ngôn ngữ native vậy.

 
kandk 2024-04-29

Ngay từ đầu nó đã là ngôn ngữ được tạo ra cho mục đích đó rồi. Để thay thế C++. Bài viết có vẻ như đã thành ra một bài phê phán ngôn ngữ này.

 
cosine20 2024-04-29

Đúng vậy. Hình như ban đầu nó được bắt đầu để cải thiện engine nội bộ của Firefox phải không?
Nội dung bài viết cho cảm giác như đã thử phát triển bằng Rust trong một lĩnh vực không thật sự hợp với nó, như thể đây là thuốc chữa bách bệnh, rồi phải khổ sở vì điều đó thôi haha

 
mammal 2024-04-29

Hoàn toàn đồng ý. Với logic game, có vẻ một ngôn ngữ có năng suất tốt sẽ phù hợp hơn với trường hợp sử dụng này.

 
edunga1 2024-04-28

Mình cũng khá đồng cảm vì đang ở giai đoạn bắt đầu với Rust.
Mỗi lần thay đổi liên quan đến borrowing là phải sửa quá nhiều code nên khá đau đầu.
Khác với Python hay JavaScript có nhiều cách diễn đạt ngầm, Rust có xu hướng tường minh nên đôi khi tạo ra code dài dòng, và vì buộc lập trình viên phải đưa ra nhiều lựa chọn nên cũng khá mệt.
Dù vậy, những khái niệm mà các ngôn ngữ khác không có lại rất mới mẻ và thú vị.

Nếu không có Rust Analyzer hay GitHub Copilot thì chắc mình đã bỏ cuộc từ sớm.

 
botplaysdice 2024-04-28

Đúng là phát triển game rất hardcore...

 
steamb23 2024-04-28

Thay vì viết mọi thứ từ lõi đến frontend bằng Rust,
liệu có thể làm giống Unity hay các game engine khác, tức là viết phần lõi bằng Rust rồi kết hợp với một ngôn ngữ có năng suất cao để sử dụng không?

 
bus710 2024-04-28

Có lẽ cũng là điều khó tránh khỏi vì bản thân nó có xu hướng áp đặt khuôn khổ khá mạnh.

 
[Bình luận này đã bị ẩn.]
 
GN⁺ 2024-04-27
Ý kiến trên Hacker News

Chia sẻ kinh nghiệm phát triển client metaverse và nêu ra các vấn đề của Rust

  • Hầu như không có trường hợp phát triển game 3D quy mô lớn bằng Rust
  • Việc refactor và kết nối các phần của chương trình rất đau đớn
  • Rendering gần như tạm ổn nhưng stack vẫn chưa hoàn thiện và không đáng tin cậy
  • Hệ thống GUI 2D còn yếu và cần quá nhiều mã cho mỗi hộp thoại
  • Đồng tình rằng hệ thống async lan sang cả những khu vực không cần thiết

Với tư cách là một nhà phát triển game có 20 năm kinh nghiệm, tác giả cho rằng Rust không phù hợp để phát triển game

  • Mã gameplay cần linh hoạt và phải có nhiều edge case để tạo ra những trò chơi thú vị
  • Thời gian biên dịch rất quan trọng và việc thay đổi cấu trúc diễn ra thường xuyên
  • ECS hữu ích cho một số hệ thống, nhưng khó dùng cho mã gameplay hoặc UI

Hệ sinh thái phát triển game bằng Rust đang dựa vào sự cường điệu

  • Đã thử phát triển game bằng Rust nhưng ngay lập tức có trải nghiệm khủng khiếp
  • Thời gian biên dịch chậm, tải xuống các gói khổng lồ, và sự khó khăn vốn có của Rust
  • Có ý kiến cho rằng các công cụ khác không an toàn như Rust, nhưng trong game thì memory safety hiếm khi từng là vấn đề lớn

So sánh trải nghiệm phát triển game với Bevy, Unity và Godot

  • Hiện tại rất khó hiểu vì sao lại chọn Rust để phát triển game
  • Nhồi nhét mọi thứ vào ECS sẽ cản trở việc phát triển gameplay thú vị
  • Xét đến hiệu năng của PC hiện đại thì không cần quá lo lắng về tối ưu hóa đa luồng

Ngôn ngữ Nim có thể phù hợp với phát triển game hơn Rust

  • Không cản trở nhà phát triển và hỗ trợ hot reloading

Rust có vẻ là một ngôn ngữ giáo điều, ép buộc một cách lập trình nhất định

  • Ưu tiên memory safety hơn tất cả, nhưng điều đó không hữu ích lắm trong phát triển game
  • Ngôn ngữ lý tưởng cho phát triển game nên có năng suất cao, hiệu năng đủ tốt, và dành cho những lập trình viên lành nghề biết chấp nhận rủi ro

Bản demo công cụ của Allen Blomquist cho thấy vòng phản hồi phát triển quan trọng như thế nào

  • Rust không mang lại môi trường làm việc mong muốn nên đã quay lại Unity

Vấn đề nền tảng của Rust là từ bỏ hướng đối tượng và thiên về lập trình hàm

  • Điều này có thể hữu ích ở tầng lõi thấp nhất, nhưng không phù hợp ở cấp độ cao hơn

Trong phát triển game, Rust là lựa chọn tệ nhất

  • Các giá trị của Rust như tính chính xác, an toàn và theo đuổi mã hoàn hảo không phù hợp với phát triển game
  • Game có vòng đời ngắn và chu kỳ phát triển ngắn nên chất lượng mã không quá quan trọng
  • Nó có thể hữu ích cho phát triển game engine, nhưng nên được dùng cùng với một ngôn ngữ scripting có độ linh hoạt cao

Khi viết code bằng ngôn ngữ D, tác giả nhận ra rằng việc thay đổi data layout dễ hơn rất nhiều so với C

  • Việc chuyển đổi giữa reference type và value type trong C rất khó, nhưng trong D thì dễ