- Microservices không chỉ là chuyện của backend - nó đẩy toàn bộ độ phức tạp sang frontend.
- BFF dùng Promise.allSettled thay vì Promise.all để trả về partial data khi 1 service sập.
- Data quan trọng được cấp 3 giây timeout, không quan trọng chỉ 1-1.5 giây.
- Bài hướng dẫn chi tiết của Abisoye Alli-Balogun trên freeCodeCamp.
TL;DR

Microservices chuyển sự phức tạp từ backend sang frontend. Thay vì một API duy nhất, bạn đang xử lý 5 service khác nhau - mỗi service có contract riêng, có thể thất bại độc lập, và có thể trả về dữ liệu lỗi thời. Bài viết này tóm tắt 6 pattern thực chiến từ bài hướng dẫn của Abisoye Alli-Balogun trên freeCodeCamp - để bạn có thể bắt đầu áp dụng ngay.
Backend đẩy complexity sang frontend
Trong kiến trúc monolith, frontend nói chuyện với 1 API duy nhất - API đó quản lý database, xử lý business logic, và trả về đúng data shape mà UI cần. Đơn giản.
Trong microservices, API duy nhất đó vỡ thành nhiều mảnh:
- Nhiều contract: "Product" trong inventory service có trường khác "product" trong catalog service. User service trả về
firstName+lastName; order service trả vềcustomerNamelà 1 string; notification service yêu cầufullName- cùng 1 khái niệm, 3 tên trường khác nhau. - Partial failure: Order service phản hồi trong 50ms trong khi recommendation service timeout. UI cần xử lý cả 2 trường hợp.
- State phân tán: User service biết địa chỉ hiện tại; order service lưu snapshot địa chỉ lúc đặt đơn - hai giá trị này có thể khác nhau.
- Latency tăng: Để render 1 trang có thể cần 3-4 API call thay vì 1.
Đây không phải là vấn đề backend ảnh hưởng đến frontend - đây là vấn đề frontend thuần túy cần giải pháp frontend.
BFF và Promise.allSettled
Backend-for-Frontend (BFF) là pattern có tác động lớn nhất cho frontend team. BFF là 1 API layer mỏng, do frontend team sở hữu, nằm giữa browser và các microservice. Nó aggregate các call, chuyển dữ liệu thành đúng shape mà component cần, và xử lý các cross-service concern như authentication token forwarding.
Điểm mấu chốt khi viết BFF: dùng Promise.allSettled thay vì Promise.all.
Promise.all: Fail fast - nếu 1 service bất kỳ sập, toàn bộ request thất bại.Promise.allSettled: Trả về partial data từ các service thành công - cho phép UI render những gì có được.
Khi nào nên xây dựng BFF? Khi frontend aggregate data từ 3 service trở lên, khi các client khác nhau (web, mobile, admin) cần data shape khác nhau, hoặc khi frontend team muốn kiểm soát response shape mà không cần đợi backend. Nếu đã có Apollo Federation hay API gateway xử lý aggregation rồi - không cần BFF thêm.
State phân tán và Adapter layer
Trong microservices, "sự thật" là phân tán. Điều này tạo ra 2 thách thức chính:
Cache boundary và invalidation: Data từ các service khác nhau trở nên cũ theo tốc độ khác nhau. Product info từ catalog service có thể cache nhiều phút; stock level từ inventory service cần refresh thường xuyên hơn; dữ liệu đơn hàng của user cần luôn fresh. Khi user đặt đơn, cần invalidate cả 3 cache key: orders (order service), stock levels (inventory service), và loyalty points (user service). Để quản lý, hãy lưu bảng cross-service dependencies. Khi bảng này vượt qua ~12 mục, chuyển sang Server-Sent Events hoặc WebSocket để backend push tín hiệu invalidation.
Adapter layer: Tạo 1 adapter layer dịch response từ mỗi service về 1 unified domain model thống nhất trước khi component dùng. Component chỉ biết đến kiểu User duy nhất - không bao giờ thấy raw service response. Khi service thay đổi API, bạn chỉ cần update 1 adapter, không phải sửa từng component.
Timeout budget và Error Boundary per service
Timeout budget phân bổ thời gian tối đa để lắp ráp dữ liệu cho 1 trang. Không có nó, thời gian load trang bị quyết định bởi service chậm nhất:
- Data quan trọng (chi tiết sản phẩm): 3 giây
- Data không quan trọng (reviews, recommendations): 1-1.5 giây
Nếu recommendation service chậm, hiển thị trang sản phẩm không có recommendations - user không cần đợi 1 service mà có thể họ không thấy. Lưu ý: dùng static timeout quá chi tiết là anti-pattern trong môi trường động; nên dùng circuit breaker (Closed / Open / Half-Open) thay thế.
Error boundary per service: Thay vì 1 error boundary ở cấp trang, đặt boundary xung quanh từng section map đến từng backend service. Review service crash không ảnh hưởng đến product details. Recommendation service timeout không hiện error - section đơn giản không render. Kết hợp với phân loại critical/non-critical: service quan trọng có error boundary với UI báo lỗi rõ ràng; service không quan trọng có boundary im lặng hoặc empty state.
Khi nào nên nói "không" với backend
Không phải vấn đề microservice nào cũng có giải pháp ở frontend. Hãy push back khi:
- Frontend đang gọi hơn 5 API call cho 1 trang - đây là tín hiệu service quá granular hoặc thiếu aggregation layer. Giải pháp là BFF hoặc composite API, không phải thêm
Promise.all. - 2 service trả về dữ liệu mâu thuẫn về cùng 1 entity - đây là vấn đề data consistency mà frontend không thể giải quyết. Cần fix ở nguồn.
- Backend team thay đổi breaking change mà không báo trước - advocate cho versioned API, deprecation notice, và contract testing.
Trong microservices, bạn không chỉ là consumer của API - bạn là stakeholder trong cách các API được thiết kế. Tham gia vào API design conversation càng sớm càng ít bất ngờ ở production.
Đọc thêm
Bài hướng dẫn đầy đủ của Abisoye Alli-Balogun có đầy đủ code example cho từng pattern: How to Navigate Microservices as a Frontend Engineer - freeCodeCamp.
Nguồn tham khảo thêm: Designing a Microservices Architecture for Failure (RisingStack) - circuit breaker, bulkhead, failover caching pattern chi tiết. Microservices Resilience Patterns (GeeksforGeeks) - real-world examples từ Netflix, Amazon, Uber, Spotify.
