Rebuilding our tech stack for the new Facebook.com
Bài tóm tắt Meta 2020 4. Điều chỉnh Độ khó: Trung bình
Meta · 2020 · 4. Điều chỉnh · Độ khó: Trung bình — bài gốc
Bối cảnh
- Facebook.com ra đời năm 2004 là một website PHP render ở server. Qua nhiều năm, từng lớp công nghệ được thêm vào cho tính năng tương tác; mỗi lớp làm site chậm thêm một chút và khó bảo trì hơn, đến mức tính năng như dark mode hay giữ vị trí trong News Feed khó làm.
- Theo Facebook, viết lại toàn bộ là cực hiếm, nhưng web đã đổi quá nhiều trong mười năm. Họ chọn app chạy phía client (React) và đặt cược rằng vẫn khởi động nhanh được. Hai nguyên tắc: "càng ít càng tốt, càng sớm càng tốt" (chỉ gửi tài nguyên cần, tới ngay trước lúc cần), và trải nghiệm kỹ sư phục vụ trải nghiệm người dùng (mặc định dẫn kỹ sư làm đúng).
Thay đổi chính
- CSS: site cũ tải hơn 400 KB CSS nén (2 MB chưa nén) ở trang chủ mà chỉ dùng khoảng 10% cho lần render đầu; CSS chỉ tăng không giảm vì mỗi tính năng thêm CSS. Sinh atomic CSS lúc build (tăng theo số khai báo kiểu duy nhất, tức gần logarit) gộp thành một stylesheet nhỏ dùng chung: CSS trang chủ −80%. Style đặt cạnh component để xoá cùng nhau; build tự đổi px sang rem; theme bằng biến CSS nên dark mode không cần tải thêm.
- JavaScript theo tầng: Tầng 1 là bố cục và khung xương cho lần vẽ đầu, Tầng 2 là mọi thứ để hoàn tất phần nhìn thấy, Tầng 3 là thứ chỉ cần sau khi hiển thị (log, subscription). Ví dụ: trang 500 KB thành 50 + 150 + 300 KB. Code cho A/B test, locale, loại thiết bị được server chọn gửi đúng bản; code cho từng loại bài viết được khai báo trong chính query Relay nên chỉ tải khi dữ liệu trả về cần.
- Ngân sách JS theo trang, chia theo ranh giới sản phẩm và team; hạ tầng dùng chung có ngân sách riêng. Công cụ: đồ thị phụ thuộc, cảnh báo kích thước trên mỗi merge request, biểu đồ lịch sử, dashboard so với ngân sách.
- Dữ liệu: trước đây phần lớn tính năng lấy dữ liệu tuỳ ý trong lúc render PHP; nay mọi việc lấy dữ liệu đi qua GraphQL như app mobile. Vì Relay biết tĩnh trang cần dữ liệu gì, server bắt đầu chuẩn bị dữ liệu ngay khi nhận request và truyền song song với code.
@streamgửi từng bài trong feed khi sẵn sàng trong một query;@defercho phần chậm (nội dung Timeline) tới sau phần nhanh (tên, ảnh đại diện). - Điều hướng: route map được bổ sung dần khi link được render (quá lớn để gửi một lần); prefetch code và dữ liệu trước khi người dùng bấm; tải code và dữ liệu của route song song thay vì lồng nhau.
Vì sao
- Mỗi tính năng thêm vào là tài nguyên tải thêm; không có cơ chế ngân sách và tách tầng thì kích thước chỉ tăng. Round-trip nối tiếp (tải code rồi mới biết cần dữ liệu gì) là chi phí lớn nhất khi khởi động và chuyển trang.
Bài học cho SWE
- Tài nguyên frontend có xu hướng chỉ tăng; đo và đặt ngân sách theo team như với chi phí hạ tầng.
- Khai báo phụ thuộc (dữ liệu, code) tĩnh để server biết sớm và gửi song song, thay vì phát hiện dần khi chạy.
- Viết lại toàn bộ chỉ hợp lý khi nền tảng bên dưới (trình duyệt) đã đổi tới mức kiến trúc cũ không còn đáp ứng.
Liên quan
#Rewrite#Server-rendered PHP → client React SPA#Atomic CSS#CSS-in-JS#Code splitting theo tier#JS budget#Relay#GraphQL#Preload data#@stream#@defer#Route map#Prefetch#React Suspense
Được nhắc tới trong
Công ty (1)