Onshore và Offshore cùng phát triển: Làm sao để Subscriber không bỏ lỡ Event?
Minh Khoa
Tác giả
Tóm tắt:
Subscribe()chỉ đăng ký nhận event từ thời điểm đó trở đi. Muốn không module nào bỏ lỡ dữ liệu bắt buộc, hệ thống phải có delivery contract rõ ràng: chờ tất cả module đăng ký, replay trạng thái mới nhất, hoặc lưu lịch sử để phát lại.
Giả sử team onshore làm PlayerDataService, team offshore làm HomeUI:
PlayerDataService load xong → Publish(PlayerDataReady)
HomeUI OnEnable → Subscribe(PlayerDataReady)
Nếu dòng trên chạy trước dòng dưới, UI sẽ không nhận được gì. Không crash, không compile error — chỉ là màn hình trống trên một vài thiết bị.
Đây không phải lỗi “team nào code sai”. Đây là lỗi thiết kế semantics của event.
📢 1. Subscribe không phải máy thời gian
Một C# event thông thường giống như loa phát thanh: ai đang đứng nghe lúc thông báo được phát thì nhận; người đến sau không nghe lại.
Muốn người đến sau vẫn có dữ liệu, phải chọn đúng loại kênh:
- Event thường — nghe từ bây giờ:
ButtonClicked,VfxRequested,EnemyHit. - State channel — nhận trạng thái mới nhất:
LoginState,Language,Currency,PlayerProfile. - Event log — phát lại toàn bộ lịch sử:
PurchaseCompleted,RewardGranted, giao dịch cần audit.
Ví dụ đời thường:
Event thường = loa phát thanh
State channel = bảng thông báo, đến muộn vẫn đọc được trạng thái mới nhất
Event log = lịch sử chat, vào sau vẫn kéo lên xem toàn bộ
Rule quan trọng: Dữ liệu bắt buộc để dựng màn hình là state, không nên chỉ tồn tại dưới dạng một event bắn đúng một lần.
🚧 2. Dùng Subscription Barrier thay vì cầu nguyện vào Awake
Unity không đảm bảo thứ tự gọi cùng một lifecycle function giữa các GameObject nếu bạn không cấu hình rõ. Vì vậy, việc “module này subscribe trong Awake(), module kia publish trong Awake()” rất dễ thành race condition.
Một bootstrap flow an toàn hơn:
1. Tạo shared services + EventHub
2. Tất cả module Register / Subscribe
3. Khởi tạo dữ liệu, load save, gọi API
4. Khi mọi module Ready → publish initial state / AppReady