Deconstructing the Monolith: Designing Software that Maximizes Developer Productivity
Bài tóm tắt Shopify 2019 3. Quy mô lớn Độ khó: Dễ
Shopify · 2019 · 3. Quy mô lớn · Độ khó: Dễ — bài gốc
Bối cảnh
- Một trong những codebase Rails lớn nhất thế giới: hơn 10 năm, hơn 1.000 developer. Ban đầu là monolith không có ranh giới: code tính phí ship gọi thẳng code tính thuế, và ngược lại.
- 2016: lợi ích của monolith bắt đầu thua tác hại.
- Code mong manh: một thay đổi vô hại kéo theo hàng loạt test không liên quan bị hỏng; test khó viết, CI chậm.
- Phải hiểu quá nhiều mới làm được việc nhỏ: người mới vào team shipping phải hiểu cả đơn hàng, thanh toán…
- Microservices bị cân nhắc rồi loại: nhiều pipeline test/deploy, chi phí hạ tầng mỗi service, gọi qua mạng (latency, độ tin cậy), refactor xuyên service phải phối hợp deploy.
Thay đổi chính
Modular monolith: một codebase, một lần deploy, nhưng ranh giới giữa các domain được định nghĩa và tôn trọng. Dự án "Componentization" bắt đầu đầu 2017, sau khi khảo sát developer để có dữ liệu về điểm đau thật.
- Tổ chức lại code theo khái niệm nghiệp vụ (orders, shipping, inventory, billing) thay vì theo khái niệm kỹ thuật (models/views/controllers). Họ liệt kê ~6.000 class Ruby trong một bảng tính, gán tay từng class vào component, rồi chuyển file bằng một PR "big bang" sinh tự động. Không đổi logic. Cái giá: mất nhiều lịch sử Git trên GitHub (move bị hiểu là xoá + tạo mới).
- Cô lập phụ thuộc: mỗi component có public API và sở hữu riêng dữ liệu của mình. Team trung tâm chỉ đưa ra pattern và công cụ, vì việc tách đòi hỏi chuyên gia từng domain.
- Wedge: hook vào Ruby tracepoint lúc chạy CI để có call graph đầy đủ, lọc các lời gọi xuyên component, chấm điểm và liệt kê vi phạm (association xuyên component luôn là vi phạm; chỉ được gọi những thứ public).
- Kế hoạch: ép ranh giới lúc chạy (mỗi component chỉ load những component đã khai báo phụ thuộc), gỡ phụ thuộc vòng.
Vì sao
Theo Shopify: mọi vấn đề đều đến từ thiếu ranh giới trong code, không phải từ việc code nằm chung một deploy. Kết quả đã thấy: thay được toàn bộ engine tính thuế cũ bằng hệ thống mới, việc trước đây "gần như không thể".
Bài học cho SWE
- Không kiến trúc thường là kiến trúc tốt nhất lúc đầu (Design Stamina Hypothesis của Fowler). Đầu tư thiết kế khi tốc độ ra tính năng bắt đầu chậm lại.
- Refactor/kiến trúc lại càng muộn càng tốt, vì càng về sau càng hiểu domain. Thiết kế microservices trước khi hiểu domain là rủi ro.
- Monolith → modular monolith → SOA là một thang tiến hoá; mỗi bậc hợp với một quy mô team/app.
- Ra quyết định dựa trên khảo sát developer, không dựa trên than phiền rời rạc.
- Kết quả 18 tháng sau, và việc Wedge bị thay bằng Packwerk: xem Shopify 2020.
Liên quan
Được nhắc tới trong
Chủ đề (1)
Công ty (1)