Xây Ứng Dụng Cộng Tác 'Mượt Như Google Docs' Chỉ Với Elixir và Phoenix LiveView! Bạn Tin Không?
Lê Lân
0
Xây Dựng Ứng Dụng Cộng Tác Đa Người Không Xung Đột Với Phoenix LiveView và CRDTs
Mở Đầu
Trong thế giới số hóa hiện nay, nhu cầu về các ứng dụng cộng tác đa người dùng ngày càng lớn, từ soạn thảo văn bản trực tuyến cho đến bảng trắng và bản đồ tương tác. Tuy nhiên, phần lớn các ứng dụng cộng tác thường gặp phải nhiều vấn đề như dữ liệu bị mất, xung đột con trỏ hay thao tác của người dùng đè lên nhau, khiến trải nghiệm người dùng trở nên kém mượt mà và không đáng tin cậy.
Điều gì làm nên sự khác biệt giữa một ứng dụng cộng tác thành công như Google Docs với các giải pháp truyền thống? Câu trả lời nằm ở cách xử lý trạng thái đồng bộ thời gian thực và tránh xung đột dữ liệu hiệu quả. Trong bài viết này, chúng ta sẽ tìm hiểu cách xây dựng các giao diện đa người dùng conflict-free với sự kết hợp của Phoenix LiveView và CRDTs (Conflict-Free Replicated Data Types) — tất cả chỉ bằng server-side, không cần đến frontend framework cầu kỳ.
Nội dung bài viết sẽ trình bày:
Thách thức của cộng tác đa người dùng
Cách sử dụng Phoenix LiveView để truyền tải sự kiện tức thời
Ứng dụng CRDT để đảm bảo tính nhất quán dữ liệu
Ví dụ minh họa cụ thể cùng các bước xây dựng
Cách mở rộng sang các loại ứng dụng phức tạp như whiteboards, bảng biểu, và nhiều hơn nữa
Thách Thức: Cộng Tác Đúng Nghĩa
Xung Đột Khi Nhiều Người Gõ Cùng Lúc
Khi hai người dùng cùng sửa một tài liệu online cùng lúc, điều gì xảy ra? Với các giải pháp đơn giản hoặc quản lý trạng thái "naïve", thường chỉ có một người được “thắng” — thay đổi của người còn lại sẽ bị mất hoặc ghi đè.
Để giải quyết vấn đề này, bạn cần một hệ thống cho phép:
Cập nhật tức thì qua WebSocket
Dữ liệu có thể gộp (merge) lại mà không xung đột
Hoạt động hiển thị sự hiện diện, con trỏ, và các yếu tố highlight
Trạng thái tồn tại dù có độ trễ mạng hoặc ngắt kết nối
Giải Pháp Tích Hợp Phoenix LiveView và CRDTs
Phoenix LiveView cung cấp một cơ chế transport nhẹ nhàng và cập nhật giao diện nhanh chóng nhờ smart DOM patching.
CRDTs đảm bảo tính nhất quán dữ liệu qua việc đồng bộ và merge các thay đổi theo trật tự mà không cần khóa.
Bước 1: Phát Sóng Hành Động Người Dùng (Broadcast User Actions)
Mỗi thao tác chỉnh sửa là một hành động rời rạc, không phải một đoạn văn bản nguyên khối.
Ví dụ, một thao tác chèn ký tự sẽ được phát với dữ liệu như:
Điều này giúp cập nhật liên tục trạng thái tài liệu ở mỗi client theo từng thao tác nhỏ, chứ không gửi nguyên cả đoạn văn.
Bước 2: Sử Dụng CRDT Có Khả Năng Merge
CRDT Là Gì?
CRDT (Conflict-Free Replicated Data Types) là loại cấu trúc dữ liệu giúp các bản sao trên nhiều thiết bị có thể tự động hợp nhất mà không gây xung đột, dù các thay đổi được thực hiện và nhận theo thứ tự khác nhau.
Các Loại CRDT Phù Hợp
Sequence-based CRDT như RGA (Replicated Growable Array), Yjs... rất phù hợp cho văn bản, cho phép chèn, xóa ký tự linh hoạt.
Các thư viện như delta_crdt_ex hỗ trợ đồng bộ hiệu quả.
Có thể triển khai:
Một GenServer lưu trữ CRDT và phát lại các delta (sự thay đổi nhỏ).
Một bản copy trong bộ nhớ cho mỗi LiveView nhằm tăng tốc render.
Mỗi client giữ bản copy riêng, áp dụng các thay đổi theo cùng một thứ tự.
Điểm mạnh: Không cần khóa (lock), không có thao tác ghi đè dữ liệu, trạng thái luôn hội tụ (converge) về một phiên bản duy nhất.
Bước 3: Render Trạng Thái Dùng LiveView
Việc render trạng thái CRDT trong template LiveView rất đơn giản:
<div class="prose whitespace-pre-wrap font-mono">
<%= for char <- MyCRDT.to_list(@crdt) do %>
<%= char %>
<% end %>
</div>
Nhờ cơ chế smart DOM patching, LiveView chỉ cập nhật những ký tự thay đổi, giúp:
Cập nhật chỉ trong vài mili giây
Không bị nhấp nháy (zero flicker)
Dễ mở rộng cho các tài liệu kích thước lớn.
Bước 4: Hiển Thị Con Trỏ và Sự Hiện Diện Người Dùng (Presence)
Sử dụng Phoenix.Presence để theo dõi các người dùng đang hoạt động và vị trí con trỏ của họ.
Mỗi thay đổi là mergeable, giúp canvas luôn đồng bộ rõ ràng và chính xác. Bạn có thể tận dụng Tailwind CSS với các lớp absolute, transform, transition để tạo hiệu ứng mượt mà, giảm thiểu JS.
Tại Sao Giải Pháp Này Hoạt Động Hiệu Quả?
✅ CRDT giúp trạng thái không xảy ra xung đột dù nhiều người chỉnh sửa đồng thời
✅ LiveView đảm bảo giao diện cập nhật thời gian thực mà vẫn tối giản frontend
✅ PubSub và Presence tạo thành nền tảng cộng tác hoàn chỉnh, theo dõi realtime
✅ Toàn bộ stack là Elixir thuần, không phụ thuộc React, Firebase hay các frontend framework phức tạp
Bạn không cần React, bạn không cần Firebase, bạn chỉ cần Phoenix + CRDT + kiến trúc chuẩn.
Kết Luận
Bằng việc kết hợp Phoenix LiveView và CRDTs, bạn hoàn toàn có thể xây dựng các ứng dụng cộng tác thời gian thực vừa mượt mà, vừa không lo xung đột—tương tự như Google Docs, nhưng đơn giản và tối ưu hơn, hoàn toàn dựa trên server-side.
Nếu bạn đang phát triển ứng dụng ghi chú nhóm, bảng trắng trực tuyến hoặc canvas đa người chơi, mô hình này chính là chìa khóa để mang đến trải nghiệm trơn tru, an toàn và dễ mở rộng.