Nguyen Le PhongNguyen Le Phong

Event Sourcing cho người mới bắt đầu

Một bài nhập môn về Event Sourcing: lưu các sự kiện như lịch sử append-only, dựng current state bằng projection, và hiểu khi nào pattern này đáng với chi phí vận hành.

Cách dễ nhất để hiểu Event Sourcing là nghĩ về một cuốn sổ văn phòng không ai được sửa lại dòng cũ. Mỗi khi có chuyện quan trọng xảy ra, ai đó viết thêm một dòng: meeting bắt đầu, quyết định thay đổi, invoice được duyệt, deployment rollback. Tình trạng hiện tại có thể được hiểu bằng cách đọc các dòng đó theo thứ tự, nhưng cuốn sổ không cố trở thành tình trạng hiện tại. Nó là ký ức về cách tình trạng hiện tại được tạo ra.

Phần lớn application lưu state như câu trả lời mới nhất. Một order có status paid. Một profile có address. Một subscription có plan. Khi có thay đổi, row được update và giá trị cũ lặng lẽ biến mất, trừ khi team thêm audit log ở chỗ khác. Cách này đơn giản và thường đúng. Rất nhiều phần mềm nên giữ như vậy, vì câu hỏi business chỉ là bây giờ điều gì đúng?

Event Sourcing bắt đầu từ câu hỏi khác: chuyện gì đã xảy ra? Thay vì chỉ lưu current state, hệ thống lưu chuỗi event như OrderPlaced, PaymentReceived, AddressChanged, ShipmentCreated hoặc SubscriptionCancelled. Current state được dựng lại bằng cách apply các event đó theo thứ tự. Order là paid vì event PaymentReceived xuất hiện sau OrderPlaced. Address khác đi vì AddressChanged xảy ra sau đó.

Lúc đầu pattern này có thể hơi lạ, vì nó yêu cầu mình ngừng xem database row là source of truth. Trong hệ thống event-sourced, source of truth là event stream. Projection, read model, dashboard và search index chỉ là view được suy ra. Chúng rất hữu ích, nhưng có thể dựng lại nếu cần. Event history mới là phần hệ thống bảo vệ kỹ nhất.

Lợi ích không chỉ là auditability, dù auditability là một lợi ích lớn. Event Sourcing giúp trả lời những câu hỏi mà cách lưu state thông thường hay đánh mất: thay đổi diễn ra lúc nào, ai trigger, sequence trước lỗi là gì, và nếu replay event qua projection mới thì state sẽ trông ra sao? Điều này mạnh trong domain nơi lịch sử quan trọng: finance, inventory, booking, claim, approval workflow, compliance hoặc collaborative system.

Nó cũng thay đổi cách team model domain. Event nên mô tả sự thật bằng ngôn ngữ business, không phải command kỹ thuật. UserUpdated khá yếu vì nó che mất ý nghĩa. EmailChanged, CreditLimitApproved và RefundRequested mang nhiều context hơn. Một tên event tốt giúp người đọc sau này hiểu câu chuyện business mà không cần mở UI hoặc đoán từ tên cột.

Nhưng pattern này có chi phí thật. Event schema sẽ tiến hóa. Event đặt tên dở sẽ nằm trong history rất lâu. Replaying hàng triệu event có thể tốn kém nếu thiếu snapshot. Projection có thể bị lag. Bug trong projection logic có thể buộc team rebuild read model. Engineer phải hiểu idempotency, ordering, concurrency, versioning và operational recovery. Event Sourcing không phải đồ trang trí để architecture nghe advanced hơn. Nó là một storage model có trách nhiệm đi kèm.

Một phân biệt hữu ích cho người mới là: Event Sourcing không giống với việc có dùng event. Một hệ thống có thể publish event sau khi update database bình thường nhưng vẫn không phải event-sourced. Event Sourcing nghĩa là event là bản ghi persisted chính. Current state đến từ event. Khác biệt đó quan trọng vì kỳ vọng vận hành cao hơn nhiều.

Pattern này thường đi cùng CQRS vì nhu cầu write và read bắt đầu khác nhau. Write side validate command và append event. Read side dựng projection dễ query. Màn hình customer support không cần replay cả stream mỗi lần mở. Nó đọc projection đã chuẩn bị cho màn hình đó. Sự tách biệt này có thể làm domain phức tạp rõ hơn, nhưng cũng có thể làm một CRUD app đơn giản trở nên nặng nề vô ích.

Quy tắc thực tế của tôi là nhìn nỗi đau trước. Nếu business thường hỏi vì sao thứ này thay đổi, nếu audit history là trung tâm, nếu state transition phong phú, nếu dựng nhiều view khác nhau từ history là có giá trị, Event Sourcing đáng được học nghiêm túc. Nếu hệ thống chủ yếu sửa record đơn giản và không ai cần câu chuyện phía sau giá trị mới nhất, relational model bình thường với audit field tốt có thể tử tế hơn với team.

Cách bình tĩnh để học Event Sourcing không phải redesign mọi thứ. Chọn một domain nhỏ nơi history quan trọng. Viết event bằng ngôn ngữ đời thường. Build một projection. Làm nó hỏng rồi replay. Quan sát nơi versioning và idempotency xuất hiện. Bài học sẽ rõ hơn qua bài tập nhỏ đó hơn là qua một sơ đồ đẹp.

Event Sourcing là một lời hứa rằng hệ thống sẽ nhớ nó đã đi đến đây như thế nào. Lời hứa đó có thể rất giá trị, nhưng nên được đưa ra cẩn thận. Nếu bạn từng làm với hệ thống event-sourced, tôi muốn nghe khoảnh khắc history đã giúp ích, và khoảnh khắc history trở nên đắt đỏ.

Bạn thấy bài viết thế nào?