15 điểm bởi tsboard 2024-12-30 | 12 bình luận | Chia sẻ qua WhatsApp

Khoảng 7 tháng trước, tôi đã lần đầu giới thiệu dự án TSBOARD.

Khi đó, cả frontend lẫn backend đều được viết bằng TypeScript, và backend chạy trên runtime Bun.

Tuy nhiên, vì nhiều lý do, tôi đã phải làm lại backend từ đầu và nay công khai nó trong một kho GitHub tách biệt với dự án TSBOARD hiện có. Backend mới này được viết bằng ngôn ngữ Go và sẽ được cung cấp kèm dưới dạng binary trong phiên bản chính thức của TSBOARD.


Vì sao lại làm lại backend?

  • Runtime Bun thực sự cho thấy hiệu năng rất ấn tượng. Nhưng trái với lời giới thiệu là một bộ công cụ all-in-one, khả năng quản lý gói của nó vẫn chưa theo kịp npm.
  • Vì vậy, để dùng TSBOARD thì cần tới 2 runtime là Node.js và Bun. Điều này khá rườm rà và cũng bất tiện cho người dùng.
  • Hiện giờ vấn đề đó đã được sửa, nhưng ở giai đoạn đầu, lỗi không chạy được trên CPU ảo khiến ngay cả tôi là người phát triển cũng không thể triển khai lên các máy chủ khác, và đó là một điểm chí mạng.
  • Như một số người đã chỉ ra, đúng là có thể giải quyết bằng orchestration, nhưng tôi vẫn muốn vượt qua giới hạn bẩm sinh của các JS runtime vốn chịu ràng buộc single-thread để tận dụng nhiều thread hơn.
  • Tôi cần nhiều kiểu dữ liệu hơn nữa. Chỉ riêng TypeScript thôi không đủ thỏa cơn khát đó.

Vì sao lại chọn ngôn ngữ Go?

  • Backend mới cần phải 1) được biên dịch, 2) có cơ chế quản lý bộ nhớ tự động, và 3) không đòi hỏi phải cài thêm một runtime riêng.
  • Sau khi cân nhắc giữa Rust, Kotlin, Python, PHP và Go, tôi đã chọn Go — một ngôn ngữ hoàn toàn mới với tôi — vì nó đáp ứng đủ cả 3 điều kiện trên. (Xin lỗi nhé PHP)
  • Điều tôi thích nhất ở Go là sự đơn giản, và những điểm tương đồng với TypeScript cũng là yếu tố quan trọng trong quyết định này. Trên hết, tôi cho rằng xét về quản lý đồng thời và quản lý bộ nhớ thì đây là lựa chọn tốt hơn so với các phương án khác.

Go khi dùng thực tế thì thế nào?

  • Tôi nhận ra rằng Go cũng chứng minh một sự thật: không có ngôn ngữ nào chỉ toàn ưu điểm. if err != nil { } tuy chắc chắn là cần thiết nhưng thật sự quá phiền. Nhiều lúc tôi lại thấy nhớ try catch finally.
  • Có thể là do vấn đề của go-mysql-driver, nhưng trong môi trường phát triển thực tế có nút thắt là DB I/O thì nó không chạy nhanh đến vậy. (Xem bài đã đăng trên GeekNews ở đây: https://vi.news.hada.io/topic?id=18048)
  • Cơ chế áp dụng interface ngầm định vẫn còn hơi lạ với tôi. Chẳng lẽ họ thực sự không muốn dùng các từ khóa như implements hay extends sao?
  • Pointer thì lại rất đáng mừng. Đặc biệt là ở chỗ không cần phải bận tâm đến thời điểm giải phóng bộ nhớ!
  • Nhiều kiểu dữ liệu, struct đơn giản mà mạnh mẽ, cùng slice là những thứ tôi cực kỳ yêu thích. Số lượng từ khóa ít nên có thể học rất nhanh và áp dụng ngay, đó là điểm tôi thích nhất.
  • Chỉ với từ khóa go mà có thể dùng lightweight thread như phép màu...! Thật hạnh phúc!

Cảm nhận sau khi chuyển backend từ JS runtime sang Go...?

  • Làm kiểu này một lần là đủ rồi.
  • Trong lúc benchmark phần DB I/O, tôi đã thử rất nhiều bài test, và xét về hiệu năng thì thực ra khó cảm nhận được khác biệt lớn giữa JS runtime và binary Go. Ví dụ như thư viện xử lý ảnh sharp vốn được dùng rất nhiều trong JS cũng sử dụng thư viện libvips, và cũng đâu có ứng dụng web nào lại không có DB I/O.
  • Dù vậy, dù tôi đã vất vả vô cùng, tôi vẫn nghĩ đây là một sự thay đổi đúng đắn, và từ nay backend sẽ chỉ tiếp tục dùng Go.
    • Mức sử dụng bộ nhớ giảm xuống ở mức thực sự có ý nghĩa. Dĩ nhiên nếu phát triển bằng Rust thì còn có thể tối ưu hơn nữa, nhưng để đổi lấy việc có thể dùng GC thì mức này là quá đủ để hài lòng.
    • Bản thân ngôn ngữ này đơn giản đến mức đáng kinh ngạc. Số từ khóa cần nhớ ít, cách dùng phần lớn cũng đã có khuôn mẫu nên học rất dễ. (Tất nhiên, dùng cho thật giỏi lại là chuyện khác) Tôi đặc biệt thích việc nó chuẩn bị sẵn rất nhiều kiểu nguyên thủy đa dạng.
    • Trên hết, điều khiến tôi hài lòng nhất là chỉ cần có binary sau khi biên dịch là có thể chạy được ngay. Tôi không còn muốn phải cài thêm thứ gì đó chỉ để chạy backend rồi lại dùng nó để thực thi code nữa.

Dùng như thế nào?

  • Rất tiếc là môi trường Windows không được hỗ trợ. Chỉ cần chạy binary trên môi trường Linux/Mac.
  • Máy chủ bạn sử dụng cần được cài sẵn thư viện libvips, vì binary sẽ dùng các chức năng của thư viện này để xử lý ảnh.
  • Chi tiết hơn đã được mô tả trong file README.md.

Vẫn còn rất nhiều thiếu sót, và tôi vẫn luôn chờ đợi những góp ý sâu sắc từ các nhà phát triển khác. Đến mức tôi còn thấy trách bản thân vì đã quá lúng túng ở sự kiện GeekNight. Mọi báo cáo lỗi, đề xuất cải thiện hay những ý kiến khác biệt đều rất được hoan nghênh.

Tháng 12 năm nay đặc biệt nặng nề, nhưng tôi vẫn hy vọng năm mới sẽ có một tương lai tốt đẹp hơn. Cảm ơn bạn đã đọc bài viết dài này. Cuối cùng, tôi xin chia sẻ liên kết ghi chú phát hành TSBOARD v1.0.0 ở bên dưới.

https://tsboard.dev/board/free/47

12 bình luận

 
angkr 2025-02-03

Tôi thấy bài này từ Damoang.
Đây là một CMS rất đáng mong đợi. Cảm ơn.

 
tsboard 2025-02-04

Tôi cũng đã rất ngạc nhiên vì ở Damoang có người vẫn nhớ đến tôi. Haha, tôi sẽ cố gắng hơn nữa để đáp lại sự kỳ vọng đó! 😊

 
dongho42 2025-01-03

Rất hữu ích!

 
tsboard 2025-02-04

Dù hơi muộn nhưng cảm ơn bạn đã để lại bình luận! 😃

 
jongyeol 2025-01-02

Việc áp dụng interface ngầm định đến giờ vẫn hơi khó làm quen. Có phải họ không muốn dùng các từ khóa như implements hay extends không?

Nó có cả ưu và nhược điểm, nhưng về mặt ưu điểm thì đôi lúc tôi thấy khá hay ở chỗ, không cần sửa mã của thư viện chuẩn/thư viện bên ngoài mà vẫn có thể dùng một implementation do người khác tạo ra và coi một phần của nó như interface do tôi tự tạo. Nó giống như FunctionalInterface của Java, hoặc như áp dụng duck typing vào một ngôn ngữ biên dịch vậy. Ngược lại, nếu bắt buộc phải khai báo theo kiểu implements/extends, thì để gắn vào interface do tôi tạo, phải triển khai một Adapter ở giữa.

Còn nhược điểm là khi thêm/xóa/thay đổi method trong interface, vị trí hiển thị lỗi sẽ khác so với các ngôn ngữ static typing khác nên hơi bất tiện.

 
tsboard 2025-01-02

À, ra là vậy! Có một ưu điểm mà tôi cũng chưa từng nghĩ tới. May là các thông báo lỗi, hình như là nhờ gopls thì phải, hoặc extension ngôn ngữ Go của vscode bắt lỗi khá tốt, nên tôi có thể nhanh chóng tìm ra những chỗ bị bỏ sót hoặc triển khai sai. Có lẽ khi quen hơn một chút thì sau này tôi cũng sẽ dùng thành thạo hơn. haha. Cảm ơn bạn đã giải thích trong phần bình luận! Chúc mừng năm mới~!

 
ifmkl 2025-01-02

Vất vả rồi! Tôi cũng sẽ đưa lên máy chủ thử nghiệm để chạy thử! Chúc bạn tiếp tục thành công trong năm mới 2025!

 
tsboard 2025-01-02

Cảm ơn bạn! Hãy thử kiểm tra nhé, và nếu có gì không hoạt động tốt hoặc bạn có thắc mắc nào, xin cứ cho chúng tôi biết bất cứ lúc nào! Chúc mừng năm mới~!

 
channprj 2025-01-01

Ủng hộ bạn~ 👍🏻

 
tsboard 2025-01-02

Cảm ơn mọi người đã ủng hộ!!! Chúc mừng năm mới~!

 
zihado 2024-12-31

Ủng hộ!

 
tsboard 2025-01-02

Cảm ơn!!! Chúc mừng năm mới!!