モジュラモノリスの品質を支えるリーダビリティチーム ― AI時代のスケーラブルなコード管理 (Readability team for a modular monolith in the AI era)

Bài tóm tắt Mercari 2025 3. Quy mô lớn Độ khó: Trung bình

Mercari · 2025 · 3. Quy mô lớn · Độ khó: Trung bình — bài gốc

Một bài trong series Global App (ngoài sheet). Bối cảnh kiến trúc: Mercari 2025 · Mercari 2025.

Bối cảnh

  • Backend Global App là modular monolith: BFF và các tầng Tier 1–4, request đi từ tầng trên xuống tầng dưới, giao tiếp giữa module chuẩn hoá bằng Protobuf + gRPC. Theo tác giả, modular monolith tự nó không giải được vấn đề của thời microservices: khác biệt giữa các service (ở đây là module) vẫn làm tăng chi phí bảo trì và onboarding.

Thay đổi chính

  • Đội readability lập từ đầu dự án (kiến trúc sư, SRE, backend; Nhật và Ấn Độ): review PR phức tạp, giữ guideline code/PR trong repo GitHub, viết kiểm tra tự động trên CI, workshop, họp hai tuần một lần, cải tiến theo metric (số PR merge mỗi người mỗi tuần, thời gian từ mở tới merge PR).
  • Khi lượng PR tăng vì thêm người và vì AI agent, đội không review hết được nữa:
    • Claude phân loại PR theo độ phức tạp và kích thước, gắn nhãn, gợi ý tách PR; review tự động theo guideline trong repo.
    • Review của đội readability không bắt buộc: một code owner duyệt là merge được, nên đội không thành nút thắt; PR phức tạp đã merge thì đội review sau để tìm mẫu mới hay thư viện cần thêm.
    • Quy tắc kiểm được bằng máy đưa vào CI, ví dụ guideline thiết kế schema PostgreSQL (soạn cùng Database Reliability Engineer) viết thành plugin SQLFluff.
  • Truyền feature flag trong modular monolith: Experiment Platform quản lý assignment theo khách; client mobile/web lấy một lần rồi cache, backend thì mỗi request một khách nên phải gọi API mỗi lần. Một request vào BFF kéo theo nhiều module; nếu mỗi module tự gọi Experiment Platform thì latency cộng dồn.
    • Chỉ BFF gọi Experiment Platform một lần; client interceptor của mỗi module đưa assignment vào gRPC metadata, server interceptor ở module dưới đọc ra và đặt vào context.Context; code nghiệp vụ đọc từ context nên thêm chỗ dùng flag không phải đổi chữ ký hàm.
    • Assignment định nghĩa bằng message Protobuf thay cho JSON map[string]string: tên tham số không còn làm phình header (JSON sẽ vỡ khi có hàng trăm, hàng nghìn tham số); optional bool phân biệt "chưa gán" với false, một bẫy hay gặp; biết rõ tham số nào được dùng ở đâu. Cái giá: thêm tham số phải sửa file proto (nhưng đằng nào cũng phải sửa code và deploy).
    • Phương án bị loại: cache trong bộ nhớ (bỏ vì khi module được deploy tách, cache không còn dùng chung); trường tường minh trong request (phải thêm vào mọi endpoint, kể cả tầng chỉ chuyển tiếp).
    • Unit test kiểm kích thước tối đa của assignment đã serialize không vượt ngưỡng header; nếu vượt, sẽ phân tích tĩnh để chỉ truyền tham số module thật sự dùng.

Vì sao

  • Code nhất quán cho phép xếp người linh hoạt giữa các module; guideline rõ, kiểm tra tự động và codebase đồng nhất cũng làm AI agent làm việc tốt hơn.

Bài học cho SWE

  • Modular monolith vẫn cần một chủ thể giữ tính nhất quán giữa module; đội đó phải không nằm trên đường merge (review sau, theo độ phức tạp).
  • Dữ liệu ngữ cảnh theo request (flag, locale, auth) lấy một lần ở rìa rồi truyền qua metadata; định nghĩa kiểu để vừa gọn vừa tránh nhầm "không có" với "false".

Liên quan