14 điểm bởi GN⁺ 2025-02-26 | 6 bình luận | Chia sẻ qua WhatsApp
  • Khi ra mắt Dagger Cloud v3, giao diện người dùng mới được viết bằng WebAssembly (WASM) và Go
  • Go thường không được dùng để phát triển web UI, nhưng họ đã chọn cách này để "hợp nhất codebase và tối ưu hiệu năng"
  • Bài viết này chia sẻ "bối cảnh của lựa chọn, những thách thức trong quá trình triển khai và kết quả cuối cùng"

Vấn đề ban đầu: sự kém hiệu quả do hai codebase riêng biệt

  • Dagger hoạt động dựa trên DAG (Directed Acyclic Graph) và cung cấp khả năng trực quan hóa qua TUI (terminal UI)bảng điều khiển web (Dagger Cloud)
  • Trước đây, TUI được triển khai bằng Go, còn web UI bằng React/TypeScript
  • Tuy nhiên, việc đồng bộ giữa hai UI rất khó khăn, và đặc biệt web UI gặp vấn đề hiệu năng khi xử lý lượng lớn dữ liệu theo thời gian thực
  • Khi xử lý các luồng sự kiện OpenTelemetry phức tạp (hàng trăm nghìn span), tình trạng suy giảm hiệu năng và vấn đề tốc độ của React UI trở nên rõ rệt
  • Cùng một tính năng phải được triển khai hai lần, tạo thành gánh nặng phát triển lớn đối với một đội ngũ nhỏ
  • Vì vậy, họ cân nhắc một cách tiếp cận mới với mục tiêu hợp nhất codebase và tối ưu hiệu năng

Giải pháp được chọn: Go + WebAssembly

  • Hợp nhất codebase bằng Go
    • TUI vốn đã được xây dựng bằng Go, nên nếu web UI cũng dùng Go thì có thể tái sử dụng mã nguồn
    • Trong nhóm có nhiều lập trình viên Go nên nâng cao năng suất của nhóm và giúp việc bảo trì dễ dàng hơn
  • Tận dụng WebAssembly (WASM)
    • Đưa WebAssembly vào để có thể chạy trực tiếp mã Go trong trình duyệt
    • Tuy nhiên, hệ sinh thái Go + WASM vẫn chưa đủ trưởng thành nên có một số thách thức:
      • Thiếu thư viện component → phải tự triển khai UI
      • Giới hạn bộ nhớ WASM của trình duyệt (2GB) → cần tối ưu khi xử lý dữ liệu lớn
      • Dù vậy, tối ưu bộ nhớ có thể mang lại lợi ích cho cả TUI lẫn web UI

Chiến lược giảm thiểu rủi ro dự án

  • Sử dụng framework Go-app
    • Chọn một framework dựa trên Go để phát triển PWA (Progressive Web App)
    • Framework này cung cấp mô hình component tương tự React, giúp việc chuyển đổi trở nên dễ dàng
  • Tạo prototype và kiểm chứng
    • Tái hiện lại UI hiện có bằng Go-app nhiều nhất có thể để xác định các vấn đề chính
    • WASM vốn đã là một tiêu chuẩn mở được tài liệu hóa, và các câu hỏi quan trọng phần lớn có thể giải quyết qua tài liệu của Go-app
    • Vấn đề lớn nhất là giới hạn mức sử dụng bộ nhớ, đòi hỏi thiết kế và tối ưu để xử lý

Từ prototype đến production

Chiến lược tối ưu hiệu năng

  • Tối ưu kết xuất log quy mô lớn
    • Cần cải thiện hiệu năng render khi xử lý dữ liệu log hơn 200.000 dòng
    • Để làm được điều đó, họ tối ưu thư viện render terminal ảo midterm,
      → qua đó cải thiện hiệu năng cho cả TUI và web UI
  • Cải thiện tốc độ phân tích JSON
    • Go WASM có tốc độ parse JSON chậm → thiết kế backend thông minh dựa trên WebSocket
    • Dùng encoding/gob của Go để tối ưu truyền dữ liệu
  • Tối ưu kích thước file WASM
    • Kích thước file WASM ban đầu: 32MB
    • Áp dụng nén Brotli → giảm xuống còn 4,6MB
    • Vì CDN khó xử lý việc nén này nên họ áp dụng nén trực tiếp trong quy trình build

Các cải tiến khác

  • Ngoài vấn đề bộ nhớ đã được dự đoán trước, phần lớn các lo ngại khác đều không thành hiện thực
  • Việc viết UI component không quá khó, và việc tích hợp với các dịch vụ khác (Tailwind, Auth0, v.v.) cũng không gặp vấn đề
  • Có thể tận dụng các gói NPM trong WebAssembly → bảo đảm khả năng tương tác với JavaScript
  • Go-app linh hoạt hơn React trong cách cập nhật component, nên có nhiều dư địa tối ưu hơn
  • Có thể phân tích hiệu năng bằng công cụ profiling của Go (pprof) và profiler tích hợp trong trình duyệt
  • Nhờ hỗ trợ PWA, ứng dụng có thể chạy như app desktop/mobile, cho phép mở ứng dụng mà không cần mở trình duyệt

Những lợi ích đạt được sau khi chuyển đổi

  • Cải thiện tính nhất quán của UI
    • Khi TUI và web UI dùng chung một codebase, họ có thể mang lại UX nhất quán hơn
  • Cải thiện hiệu năng và mức sử dụng bộ nhớ
    • Khi xử lý lượng dữ liệu lớn, tốc độ render được cải thiện và mức sử dụng bộ nhớ giảm xuống
  • Nâng cao năng suất của nhóm
    • Trước đây, họ phải tối ưu web UI và TUI một cách riêng rẽ,
      nhưng giờ đây chỉ cần tối ưu một lần là có thể áp dụng đồng thời cho cả hai giao diện
    • Nhờ đó, họ có thể tập trung hơn vào việc phát triển các tính năng mới

Có nên chuyển sang Go + WASM không?

  • Nhìn chung không được khuyến nghị, nhưng trong một số điều kiện cụ thể thì có thể hữu ích:
    • Đội ngũ có nhiều lập trình viên Go
    • UI phức tạp nơi TypeScript/React bộc lộ giới hạn hiệu năng
    • Cần chia sẻ mã giữa TUI và web UI
    • Môi trường cần tối đa hóa tốc độ phát triển
  • Nếu phù hợp với các điều kiện trên thì Go + WASM có thể là một lựa chọn thay thế tốt
    Tuy nhiên, trong đa số trường hợp, các công nghệ web hiện có (React, TypeScript, v.v.) vẫn phù hợp hơn

6 bình luận

 
minho2da 2025-02-27

Kiểu như GWT ngày xưa phải không?

 
bbulbum 2025-02-26

Ừm... liệu việc phát triển có an toàn về kiểu hơn so với TS hay không thì cũng khá đáng tò mò đấy.

 
colus001 2025-02-26

Dù nhìn kiểu nào thì cũng có cảm giác như đang giải một bài toán dễ theo cách quá phức tạp...

 
riki3 2025-02-26

Việc làm frontend dựa trên Go hiệu quả hơn tưởng tượng. Rõ ràng là có lý do khiến các use case ngày càng tăng.

 
halfenif 2025-02-26

Dù vậy, tôi vẫn muốn thử.

 
GN⁺ 2025-02-26
Ý kiến trên Hacker News
  • Có ý kiến cho rằng với một đội nhỏ thì cần triển khai thật nhanh

    • Nhưng họ đã mất gần một tháng để làm nguyên mẫu, phải tự viết các UI component cho Go-app, và vì Go WASM chậm khi phân tích JSON nên kiến trúc đã bị thay đổi đáng kể
    • Có ý kiến nói điều này nghe giống kiểu lập trình để làm đẹp CV
  • Họ có một đội ngũ kỹ sư Go rất mạnh và một UI phức tạp khó mở rộng bằng TypeScript/React

    • Qua bản demo, có cảm giác đây là một đội thiếu kinh nghiệm về web frontend
    • Trang đăng ký không vừa màn hình, và khi bấm trong dashboard thì một spinner toàn màn hình xuất hiện rồi trang được tải lại
    • Khi icon đang tải thì alt-text bị hiển thị
    • Có ý kiến cho rằng thật may là vấn đề không phải do React không mở rộng được
  • Có người lo đây là một framework “render bằng canvas”, nhưng không phải vậy

    • Điểm tích cực là khả năng tương tác giữa WASM và DOM đã đủ nhanh
    • Tuy nhiên, file nhị phân 32MB là một nhược điểm lớn
  • Họ đã quyết định dùng <a href="https://go-app.dev/" rel="nofollow">https://go-app.dev/</a>; để xây dựng frontend

    • Go-app là một package dùng Golang và WebAssembly để xây dựng PWA
  • Có ý kiến cho rằng Go không phù hợp với kiểu công việc này

    • Họ nói đã đạt kết quả tốt hơn khi dùng Rust
    • Các file nhị phân wasm viết bằng Rust trung bình khoảng 240kb và được nén rất tốt khi truyền tải
  • Sẽ rất thú vị nếu vài tháng nữa có một báo cáo tiếp theo xem việc chuyển từ một stack nặng hơn sang một stack hiệu năng tốt hơn nhưng hơi khác thường có mang lại kết quả tích cực hay không

    • Việc tuyển frontend developer cho kiểu dự án này có lẽ sẽ không dễ hơn so với tìm React developer
  • Người tạo ra go-app đã phát hiện bài đăng này và tỏ ra bất ngờ, đồng thời chúc sản phẩm thành công

  • Vì Go WASM chậm khi phân tích JSON, họ đã phải thay đổi kiến trúc và tạo một “backend thông minh” để tải dữ liệu dần qua WebSockets

    • Có lo ngại về vấn đề bảo mật của dữ liệu gob
  • Có ý kiến cho rằng WASM phù hợp với những trường hợp ngách nhất định, nhưng không thích hợp để xây dựng web app thông thường

    • Một ứng dụng làm bằng go-app tải 3.6MB mã WASM
    • Blazor cũng tương tự, ngay cả ứng dụng đơn giản cũng cần ít nhất hơn 1MB cho lần tải đầu
  • Có người cho rằng việc dùng cùng một ngôn ngữ cho mọi thành phần (frontend/backend/app) mang lại giá trị lớn

    • Ngược lại, có người đang dùng cách tiếp cận “Typescript everywhere”, với React cho frontend, NodeJS cho backend và Capacitor cho app