Một Số Cập Nhật Về Sproto - nói dối e blog

Một Số Cập Nhật Về Sproto

Một vài cập nhật mới nhất của sproto

Sproto là một giao thức định dạng dữ liệu mà tôi thiết kế với ý tưởng tương tự như Google Protocol Buffers. Trải qua nhiều năm sử dụng Protocol Buffers trong các dự án của mình, tôi dần nhận ra một thực tế thú vị: công cụ này được thiết kế chủ yếu cho các ngôn ngữ biên dịch tĩnh và không thực sự phù hợp với tính linh hoạt của các ngôn ngữ động. Điều đó khiến nó không được ưa chuộng như JSON trong môi trường ngôn ngữ động.

Nguyên nhân sâu xa nằm ở cơ chế sinh mã dựa trên khai báo giao thức - một vòng tròn khép kín đầy nghịch lý. Để phân tích cú pháp giao thức, bạn cần có khả năng tự giải mã, giống như bài toán “con gà quả trứng”. Các thư viện binding cho ngôn ngữ động thường phải dựa vào các thư viện C++ cồng kềnh hoặc dùng kỹ thuật sinh mã runtime phức tạp. Điều này thúc đẩy tôi phát triển pbc - một thư viện thuần túy cho ngôn ngữ Lua, dù hiện tại đã ngừng bảo trì nhưng vẫn là lựa chọn tối ưu cho nhiều dự án.

Cũng trong giai đoạn này, Google đã có những cải tiến mạnh mẽ với phiên bản 3.0, đánh dấu bằng hàng loạt thay đổi đột phá nhưng không tương thích ngược với các phiên bản 2.x trước đó. Xuất phát từ triết lý “đơn giản nhưng đủ dùng” của Protocol Buffers, tôi đã thiết kế sproto với định hướng rõ ràng: giữ cấu trúc nhẹ nhất có thể và chỉ thêm tính năng mới sau khi cân nhắc kỹ lưỡng để đảm bảo tính tương thích lâu dài. Trong thời gian gần đây, tôi đã bổ sung hai tính năng quan trọng cho sproto:

Thứ nhất: Hỗ trợ định dạng số thập phân cố định
Ban đầu, sproto không hỗ trợ kiểu số thực do nhận định rằng nhu cầu truyền dữ liệu dạng này trong đa số ứng dụng là không cấp thiết. Khi cần thiết, người dùng có thể truyền dưới dạng chuỗi hoặc byte stream với thỏa thuận riêng. Tuy nhiên, nhu cầu truyền số thập phân nhỏ vẫn tồn tại trong một số trường hợp đặc thù.

Giải pháp là tận dụng cơ chế chú thích hiện có của sproto - tương tự như cách thêm hỗ trợ kiểu từ điển trước đây. Cụ thể, khi khai báo một trường kiểu integer với chú thích như integer(2), nó sẽ được hiểu là số nguyên có 2 chữ số thập phân cố định. Ví dụ, giá trị 1.23 sẽ được mã hóa thành 123 (nhân 100 trước khi gửi) và giải mã thành 1.23 (chia 100 sau khi nhận). Cơ chế này hoàn toàn tương thích ngược vì các phiên bản cũ có thể tự xử lý bằng cách nhân/chia hệ số tương ứng ở tầng ứng dụng.

Thứ hai: Thêm kiểu dữ liệu binary stream
Trước đây, sproto chỉ có kiểu string để xử lý cả chuỗi ký tự và dữ liệu nhị phân. Điều này hoạt động tốt với Lua nhưng gây khó khăn khi triển khai trên các ngôn ngữ khác như Python hay C# - nơi phân biệt rõ ràng giữa chuỗi đọc được (string) và luồng nhị phân (byte array). Mỗi loại còn yêu cầu chỉ định mã hóa riêng (UTF-8, ASCII…).

Để khắc phục, tôi đã thêm kiểu dữ liệu binary mới nhưng thiết kế nó như một dạng đặc biệt của string nhằm đảm bảo tương thích ngược. Khi mã hóa, dữ liệu vẫn giữ nguyên dạng string truyền thống, nhưng khi giải mã, hệ thống sẽ thông báo chính xác cho các thư viện binding rằng đây là luồng nhị phân. Điều này giúp các ngôn ngữ hỗ trợ phân biệt rõ ràng mà không làm hỏng các hệ thống đang chạy phiên bản cũ.

Những cải tiến này không chỉ mở rộng khả năng ứng dụng của sproto mà còn chứng minh tính linh hoạt của kiến trúc ban đầu - nơi các thay đổi quan trọng có thể được tích hợp mà không làm mất đi tính đơn giản và hiệu quả vốn có.

0%