08 thg 9, 2025·8 phút đọc

Monorepo vs polyrepo: giữ web, mobile, backend đồng bộ

Giải thích monorepo vs polyrepo cho đội phát hành web, mobile và backend. So sánh quản lý phụ thuộc, phối hợp release và chiến thuật CI để giữ tốc độ.

Monorepo vs polyrepo: giữ web, mobile, backend đồng bộ

Vấn đề thực sự: phát hành thay đổi qua ba codebase\n\nCác đội không tranh luận về monorepo vs polyrepo vì họ quan tâm đến triết lý Git. Họ tranh luận vì một thay đổi nhỏ của sản phẩm lại biến thành ba thay đổi riêng ở web, mobile và backend, và có thứ gì đó bị hỏng dọc đường.\n\nThứ hỏng trước tiên hiếm khi là giao diện người dùng. Thường là mối nối vô hình: hợp đồng API bị thay đổi mà không có cập nhật tương ứng, một thư viện chia sẻ được nâng phiên bản ở chỗ này nhưng không ở chỗ kia, hoặc pipeline build bỗng cần một bước mới. Khi một phần được phát hành sớm hơn phần khác, người dùng cảm nhận đó là lỗi như “nút bấm có trên web nhưng app mobile báo không hỗ trợ” hoặc “app load mãi vì backend trả về khác”.\n\nWeb, mobile và backend cũng chạy theo những nhịp phát hành khác nhau. Web có thể phát hành nhiều lần mỗi ngày. Backend có thể phát hành thường xuyên nhưng cần rollout cẩn thận. Mobile chậm nhất vì duyệt app store và việc người dùng cập nhật gây ra độ trễ thực sự. Một thay đổi “đơn giản” như đổi tên một trường có thể buộc bạn phải lên kế hoạch theo làn chậm nhất, dù chỉ một màn hình cần thay đổi đó.\n\nBạn có thể đang trả “thuế” phối hợp repo nếu những điều này xảy ra thường xuyên:\n\n- Thay đổi API phá vỡ được phát hiện sau khi merge.\n- Đồng bộ phiên bản phụ thuộc vào nhắc nhở thủ công và bảng tính.\n- Một tính năng cần nhiều pull request phối hợp và chúng nằm chờ lẫn nhau.\n- CI chậm vì nó build và test nhiều thứ hơn lượng thay đổi thực tế.\n- Rollback cảm thấy rủi ro vì không rõ commit nào tương ứng với release nào.\n\nKích thước đội và mức độ trưởng thành sản phẩm thay đổi câu trả lời đúng. Lúc ban đầu, hầu hết đội thắng khi làm cho việc phối hợp rẻ và tầm nhìn cao, dù mọi thứ hơi lộn xộn. Khi đội lớn hơn, ranh giới bắt đầu có ý nghĩa, nhưng chỉ khi giao diện ổn định và quyền sở hữu rõ ràng.\n\nNếu mọi thay đổi có ý nghĩa đều phải vào ba nơi, bạn sẽ trả cái thuế đó bằng cách nào đó. Chiến lược repo chủ yếu là chọn cách bạn muốn trả nó.\n\n## Cơ bản về monorepo và polyrepo không dùng biệt ngữ\n\nRepo chỉ là nơi mã của bạn sống, kèm lịch sử. Khi bạn có web, mobile và backend, lựa chọn đơn giản: giữ mọi thứ cùng nơi, hay tách ra.\n\nMột monorepo là một repository chứa nhiều app và thường cả code chia sẻ. Web, iOS/Android, dịch vụ backend và thư viện chung đặt cạnh nhau.\n\nMột polyrepo thì ngược lại: mỗi app (và đôi khi mỗi service) có repo riêng. Code chia sẻ thường thành một package riêng, hoặc các đội sao chép các phần nhỏ khi cần.\n\nHàng ngày, monorepo thường cho cảm giác như sau: chia sẻ code dễ, thay đổi xuyên app có thể qua một pull request, và quy tắc nhất quán. Đổi lại là mặt xã hội: quyền sở hữu có thể mơ hồ nếu bạn không đặt ranh giới rõ, và kiểm tra toàn repo có thể cảm thấy nghiêm ngặt.\n\nPolyrepo thường cho cảm giác: mỗi đội di chuyển độc lập, repo vẫn tập trung, và quản lý truy cập có thể đơn giản hơn. Đổi lại là phối hợp: chia sẻ code cần lên kế hoạch, và thay đổi xuyên app thường thành nhiều pull request với timing cẩn thận.\n\nNhiều đội chọn hybrid: các app trong repo riêng, hợp đồng chia sẻ ở một chỗ; hoặc một monorepo với ranh giới chặt để mỗi đội chủ yếu ở khu vực của mình.\n\nNếu bạn dùng nền tảng sinh backend, web và mobile từ một nguồn chân lý, bạn giảm drift vì hợp đồng và logic sống cùng nhau. AppMaster, ví dụ, sinh backend, web và native mobile sẵn sàng sản xuất từ một mô hình duy nhất. Điều đó không loại bỏ thực tế phát hành (mobile vẫn chậm hơn), nhưng có thể loại bỏ nhiều công việc “chúng ta đã cập nhật cả ba chỗ chưa?”.\n\n## Quản lý phụ thuộc: giữ code chia sẻ an toàn\n\nCode chia sẻ là nơi đội mất thời gian, bất kể cấu trúc repo. Một thay đổi nhỏ trong thư viện chia sẻ hoặc hợp đồng API có thể làm build web lỗi, release mobile gặp vấn đề, và deploy backend gặp khác nhau.\n\nKhi bạn chia sẻ thư viện (component UI, quy tắc validate, helper auth), bạn đang chọn giữa một phiên bản cho tất cả hoặc nhiều phiên bản cùng tồn tại theo thời gian.\n\n- Một phiên bản đơn giản hơn và tránh “chạy được trên branch của tôi” bất ngờ.\n- Nhiều phiên bản cho phép đội di chuyển theo tốc độ riêng, nhưng tạo lộn xộn và làm việc vá bảo mật khó triển khai nhanh.\n\nClient API và schema cần chăm sóc nhiều hơn. Cập nhật thủ công chậm và dễ sai. Mô hình tốt hơn là coi schema API là nguồn chân lý và sinh client từ nó, rồi kiểm tra chúng bằng cách check-in hoặc sinh trong CI. Mục tiêu là fail sớm: nếu backend thêm một trường bắt buộc, client mobile nên fail trong bước build, chứ không phải ba ngày sau trong QA.\n\nThay đổi phá vỡ lan rộng khi hành vi thay đổi mà không có lộ trình an toàn. Ưu tiên các thay đổi bổ sung trước (trường mới, endpoint mới), sau đó deprecate dần. Nếu phải phá vỡ, dùng endpoint phiên bản hóa hoặc một cửa sổ tương thích ngắn.\n\nVí dụ cụ thể: backend đổi tên status thành state. Nếu web cập nhật hôm nay nhưng mobile không thể ship trong một tuần, backend cần chấp nhận cả hai trường trong tuần đó, hoặc triển khai adapter ánh xạ trường cũ sang trường mới.\n\nMột vài quy tắc giúp việc cập nhật phụ thuộc nhàm chán (theo nghĩa tốt):\n\n- Cập nhật theo nhịp. Cập nhật nhỏ hàng tuần tốt hơn cập nhật lớn hàng quý.\n- Yêu cầu phê duyệt rõ ràng cho thay đổi phá vỡ, kèm ghi chú di trú ngắn.\n- Tự động hóa kiểm tra: nâng phiên bản phụ thuộc, sinh lại client, và test hợp đồng cơ bản.\n\nCode sinh tự động có thể giảm drift, nhưng không thay thế kỷ luật. Bạn vẫn cần một hợp đồng duy nhất, deprecation rõ ràng và cập nhật có thể dự đoán được.\n\n## Phối hợp phát hành: căn chỉnh web, mobile và backend\n\nPhối hợp phát hành là nơi chiến lược repo không còn là lý thuyết. Nếu backend thay một tên trường API, web có thể cập nhật và ship trong ngày. Mobile khác: duyệt store và thời gian người dùng cập nhật có thể biến một không khớp nhỏ thành hàng tuần ticket support.\n\nMục tiêu thực tế đơn giản: một thao tác của người dùng phải hoạt động dù phần nào cập nhật trước. Điều đó có nghĩa là lên kế hoạch cho phiên bản hỗn hợp, không giả định release đồng bộ hoàn hảo.\n\n### Các mẫu version mà đội thực sự dùng\n\nHầu hết đội chọn một trong các cách sau:\n\n1) Một đoàn phát hành chung: web, mobile và backend phát hành như một đơn vị có version.\n\n2) Phiên bản theo dịch vụ với quy tắc tương thích: mỗi app/service có version riêng, và backend hỗ trợ một phạm vi client nhất định.\n\nMột đoàn phát hành chung trông gọn gàng, nhưng thường vỡ khi mobile trì hoãn. Phiên bản theo dịch vụ giấy tờ lộn xộn hơn, nhưng phù hợp thực tế. Nếu bạn chọn per-service, hãy ghi rõ một quy tắc và thi hành: backend phiên bản nào phải hỗ trợ mobile phiên bản nào, và trong bao lâu.\n\nĐộ trễ mobile cũng thay đổi cách xử lý hotfix. Hotfix backend có thể ra nhanh; hotfix mobile có thể không tới người dùng trong vài ngày. Ưu tiên sửa server-side giữ cho các build mobile cũ hoạt động. Khi phải thay client, dùng feature flag và tránh loại bỏ trường cũ cho tới khi biết đa số người dùng đã cập nhật.\n\nVí dụ: thêm “delivery instructions” vào flow đặt hàng. Backend thêm trường mới optional, web hiển thị ngay, mobile hiển thị ở sprint sau. Nếu backend chấp nhận request cũ và giữ trường optional, mọi thứ tiếp tục hoạt động trong khi mobile bắt kịp.\n\n### Ai quản lý lịch phát hành\n\nPhối hợp thất bại khi “mọi người đều quản” nên không ai thực sự quản. Người chủ có thể là tech lead, release manager, hoặc product manager có hỗ trợ kỹ thuật. Công việc của họ là tránh bất ngờ bằng cách giữ kỳ vọng phát hành rõ và nhất quán.\n\nHọ không cần quy trình phức tạp. Họ cần vài thói quen lặp lại: lịch phát hành đơn giản với cutoff và cửa sổ đóng băng, check chéo nhanh trước khi thay đổi API ship, và kế hoạch rõ ràng nếu mobile trễ (giữ backend lại hay duy trì tương thích).\n\nNếu workflow của bạn sinh web, mobile và backend cùng lúc từ một mô hình, bạn vẫn cần một người quản lý phát hành. Thông thường sẽ ít xuất hiện tình huống “chúng ta đã cập nhật cả ba chỗ chưa?” hơn, nhưng bạn không thoát được thời gian của mobile.\n\n## Giữ thời gian CI trong tầm kiểm soát\n\nCI chậm vì cùng lý do ở cả hai thiết lập: bạn rebuild quá nhiều, cài lại phụ thuộc nhiều lần, và chạy mọi test trên mọi thay đổi.\n\nNhững kẻ giết thời gian phổ biến: build toàn bộ cho thay đổi nhỏ, cache mất, bộ test chạy mọi thứ, và job tuần tự có thể chạy song song.\n\nBắt đầu với cải tiến áp dụng mọi nơi:\n\n- Cache các lần tải phụ thuộc và output build.\n- Chạy lint, unit test và build song song khi có thể.\n- Tách kiểm tra nhanh (mỗi commit) khỏi kiểm tra chậm (nhánh chính, nightly hoặc trước release).\n\n### Chiến thuật monorepo hữu ích\n\nMonorepo trở nên đau đầu khi mỗi commit kích hoạt pipeline “build toàn thế giới”. Khắc phục là chỉ build và test phần bị ảnh hưởng bởi thay đổi.\n\nDùng bộ lọc theo đường dẫn và cách tiếp cận chỉ-ảnh-hưởng: nếu bạn thay đổi code UI mobile, đừng build image backend. Nếu bạn chạm vào thư viện chia sẻ, build và test chỉ các app phụ thuộc vào nó. Nhiều đội chính thức hóa điều này với một đồ thị phụ thuộc đơn giản để CI quyết định thay vì đoán mò.\n\n### Chiến thuật polyrepo ngăn drift\n\nPolyrepo có thể nhanh vì mỗi repo nhỏ hơn, nhưng chúng thường lãng phí thời gian do trùng lặp và tooling không nhất quán.\n\nGiữ một bộ template CI chung (cùng bước, cùng cache, cùng quy ước) để mọi repo không phải sáng tạo lại pipeline. Khoá phiên bản toolchain (phiên bản runtime, công cụ build, linter) để tránh “chạy được ở repo này” bất ngờ. Nếu tải phụ thuộc là nút thắt, thiết lập cache chung hoặc mirror nội bộ để mỗi repo không phải tải toàn bộ từ Internet.\n\nVí dụ cụ thể: một tính năng thêm trường “status” mới. Backend thay đổi, web hiển thị, mobile hiển thị. Trong monorepo, CI nên chạy test backend cộng với chỉ phần web và mobile phụ thuộc client API. Trong polyrepo, mỗi repo nên chạy kiểm tra nhanh của mình, và một pipeline tích hợp riêng có thể validate rằng ba release vẫn đồng ý nhau.\n\nNếu bạn xuất mã nguồn và chạy CI của riêng mình, quy tắc vẫn vậy: chỉ build phần thay đổi, tận dụng cache mạnh mẽ, và dành kiểm tra chậm cho khi nó có giá trị thực sự.\n\n## Từng bước: chọn chiến lược repo phù hợp đội bạn\n\nQuyết định dễ dàng hơn khi bắt đầu từ công việc hàng ngày thay vì tư tưởng.\n\n### 1) Ghi ra những gì phải thay đổi cùng nhau\n\nChọn 5–10 tính năng gần đây và ghi những gì phải đi đôi. Đánh dấu mỗi cái có chạm màn hình UI, endpoint API, bảng dữ liệu, quy tắc xác thực, hay validation chia sẻ không. Nếu hầu hết tính năng cần thay đổi phối hợp ở cả ba phần, cấu trúc tách sẽ thấy đau trừ khi quy trình phát hành của bạn cực kỳ kỷ luật.\n\n### 2) Theo dõi code và quyết định chia sẻ\n\nCode chia sẻ không chỉ là thư viện. Nó còn là hợp đồng (API schema), pattern UI và quy tắc nghiệp vụ. Ghi nơi chúng đang nằm, ai sửa chúng, và cách thay đổi được phê duyệt. Nếu các phần chia sẻ bị sao chép giữa các repo, đó là dấu hiệu bạn cần kiểm soát chặt hơn, hoặc monorepo, hoặc quy tắc versioning nghiêm ngặt.\n\n### 3) Định nghĩa ranh giới và chủ sở hữu\n\nQuyết định đơn vị (app, service, library), rồi giao chủ sở hữu cho từng đơn vị. Ranh giới quan trọng hơn layout repo. Không có chủ sở hữu, monorepo trở nên ồn ào. Không có chủ sở hữu, polyrepo biến thành rời rạc.\n\nNếu bạn muốn checklist đơn giản, nhắm tới: một repo hoặc thư mục cho mỗi service/app có thể deploy, một nơi cho hợp đồng chia sẻ, một nơi cho component UI thật sự chung, quy tắc rõ ràng nơi nào lưu logic nghiệp vụ, và một chủ sở hữu được ghi cho mỗi phần.\n\n### 4) Chọn mô hình phát hành bạn có thể tuân theo\n\nNếu release mobile trễ so với backend, bạn cần kế hoạch tương thích (API phiên bản, trường backward-compatible, hoặc cửa sổ hỗ trợ định nghĩa). Nếu mọi thứ phải ship cùng nhau, release train có thể hoạt động, nhưng nó tăng chi phí phối hợp.\n\nGiữ quy tắc branching đơn giản: branch ngắn, merge nhỏ, và đường dẫn hotfix rõ ràng.\n\n### 5) Thiết kế CI quanh các thay đổi thường gặp\n\nĐừng thiết kế CI cho trường hợp tồi tệ nhất ngay từ đầu. Thiết kế cho những gì người ta làm hàng ngày.\n\nNếu hầu hết commit chỉ chạm UI web, chạy lint và unit test web mặc định, và chạy end-to-end toàn bộ theo lịch hoặc trước release. Nếu sự cố thường đến từ drift API, đầu tư trước vào contract test và sinh client.\n\n## Ví dụ: một tính năng chạm web, mobile và backend\n\nHình dung một đội nhỏ xây ba thứ cùng lúc: portal khách hàng (web), app hiện trường (mobile), và API (backend). Có yêu cầu: thêm trường “Service status” cho jobs và hiển thị ở mọi nơi.\n\nThay đổi nghe có vẻ nhỏ, nhưng là một bài kiểm tra phối hợp. Backend thêm trường, cập nhật validation và response. Web hiển thị và cập nhật filter. Mobile cần hiển thị offline, sync và xử lý edge case.\n\nVấn đề thực sự: thay đổi API phá vỡ. Tên trường đổi từ status thành service_status, và client cũ crash nếu không xử lý được.\n\n### Monorepo thay đổi điều gì\n\nĐây là lúc monorepo thường cho cảm giác bình tĩnh hơn. Backend, web và mobile có thể nằm trong một pull request (hoặc một chuỗi commit phối hợp). CI chạy test ảnh hưởng, và bạn có thể gắn tag một release chứa cả ba cập nhật.\n\nRủi ro chính là xã hội, không phải kỹ thuật: một repo làm cho việc merge thay đổi phá vỡ trở nên dễ dàng, nên quy tắc review phải chặt.\n\n### Polyrepo thay đổi điều gì\n\nVới repo tách riêng, mỗi app có lịch riêng. Backend có thể ship trước, và web cùng mobile vội vã bắt kịp. Nếu release mobile cần duyệt app store, “fix” có thể mất vài ngày dù code rất nhỏ.\n\nCác đội thường giải quyết bằng cấu trúc mạnh hơn: endpoint phiên bản, response backward-compatible, cửa sổ deprecation dài hơn, và bước rollout rõ ràng. Nó hiệu quả nhưng là công việc liên tục.\n\nNếu bạn quyết định dựa trên bằng chứng, nhìn vào vài tháng gần đây:\n\n- Nếu sự cố thường đến từ phiên bản không khớp, ưu tiên phối hợp chặt hơn.\n- Nếu release thường xuyên và nhạy thời gian (đặc biệt mobile), tránh thay đổi phá vỡ hoặc tập trung chúng.\n- Nếu các đội độc lập và hiếm khi chạm tới cùng tính năng, chi phí overhead của polyrepo có thể xứng đáng.\n\n## Những sai lầm phổ biến và bẫy cần tránh\n\nHầu hết đội không thất bại vì chọn “sai” cấu trúc repo. Họ thất bại vì thói quen hàng ngày dần dần thêm ma sát đến khi mỗi thay đổi đều cảm thấy rủi ro.\n\n### Code chia sẻ biến thành bãi rác\n\nThư viện chia sẻ hấp dẫn: helper, type, mảnh UI, workaround “tạm thời”. Chẳng mấy chốc nó trở thành nơi chứa code cũ, và không ai biết cái nào an toàn để thay đổi.\n\nGiữ code chia sẻ nhỏ và nghiêm ngặt. “Chia sẻ” nên có nghĩa là được nhiều đội dùng, được review cẩn thận, và thay đổi có mục đích.\n\n### Coupling chặt qua giả định ẩn\n\nNgay cả trong repo tách, hệ thống vẫn có thể coupling chặt. Coupling chỉ dời chỗ vào các giả định: định dạng ngày, giá trị enum, quy tắc permission, và “trường này luôn tồn tại”.\n\nVí dụ: mobile coi status = 2 là “Approved”, web coi là “Confirmed”, backend đổi thứ tự enum, và mọi thứ vỡ theo cách trông như ngẫu nhiên.\n\nNgăn chặn bằng cách document hợp đồng (trường nghĩa gì, giá trị nào hợp lệ) và coi chúng như quy tắc sản phẩm, không phải trivia.\n\n### Quyền sở hữu không rõ ràng\n\nKhi ai cũng có thể thay đổi bất cứ thứ gì, review nông và lỗi lọt. Khi không ai sở hữu khu vực, bug ngồi đó vài tuần.\n\nĐịnh nghĩa chủ sở hữu cho web, mobile, backend và module chia sẻ. Chủ sở hữu không chặn đóng góp; nó đảm bảo thay đổi được nhìn bởi đúng người.\n\n### CI lớn lên mà không được tỉa bớt\n\nCI bắt đầu nhỏ, rồi mỗi sự cố thêm một job “chỉ để an toàn”. Tháng sau pipeline chậm và đắt, và người ta tránh dùng.\n\nMột quy tắc đơn giản giúp: mỗi job CI cần mục đích rõ ràng và một chủ sở hữu, và nên bị xoá nếu không còn bắt lỗi thật.\n\nDấu hiệu cần dọn dẹp: test trùng giữa job, job đỏ nhiều ngày, “thay đổi nhanh” mất thời gian xác minh lâu hơn build, và pipeline kích hoạt build mobile cho thay đổi chỉ backend.\n\n### Phối hợp phát hành dựa vào kiến thức bộ tộc\n\nNếu release phụ thuộc vào một người nhớ thứ tự đúng và các mẹo bí mật, bạn sẽ phát hành chậm hơn và dễ vỡ hơn.\n\nGhi lại các bước phát hành, làm cho chúng lặp lại được, và tự động hóa kiểm tra nhàm chán. Dù tooling của bạn sinh backend và client nhất quán, bạn vẫn cần quy tắc phát hành rõ ràng.\n\n## Kiểm tra nhanh trước khi quyết repo monorepo hay polyrepo\n\nTrước khi tổ chức lại repo, kiểm tra thực tế cách đội bạn phát hành hôm nay. Mục tiêu không phải cấu trúc hoàn hảo mà là ít bất ngờ hơn khi một thay đổi chạm web, mobile và backend.\n\nHỏi năm câu:\n\n- Phát hành độc lập: Bạn có thể release sửa backend mà không buộc cập nhật app mobile cùng ngày không?\n- Quy tắc thay đổi API: Bạn có hợp đồng bằng văn bản cho deprecation và thời gian hỗ trợ hành vi cũ không?\n- Kỷ luật code chia sẻ: Thư viện chia sẻ (component UI, client API, quy tắc nghiệp vụ) có được review và version consistently không?\n- CI chạy những gì quan trọng: CI có thể biết phần nào thay đổi và chỉ chạy build/test cho phần bị ảnh hưởng không?\n- Một cái nhìn release tổng thể: Có nơi duy nhất để xem điều gì sẽ đi ra giữa web, mobile và backend, với owner và ngày không?\n\nVí dụ đơn giản: trường “address” mới được thêm vào checkout. Nếu backend ship trước, app mobile cũ vẫn nên hoạt động. Thường điều đó nghĩa là API chấp nhận cả payload cũ và mới trong một thời gian, và cập nhật client là tuỳ chọn, không bắt buộc.\n\n## Bước tiếp theo: giảm công việc phối hợp và phát hành tự tin hơn\n\nMục tiêu không phải cấu trúc repo “đúng”. Mà là ít bàn giao, ít bất ngờ, và ít khoảnh khắc “đợi đã, phiên bản nào đang live?”.\n\nViết một bản ghi quyết định ngắn: lý do bạn chọn cách này, bạn mong cải thiện gì, và các đánh đổi bạn chấp nhận. Rà soát nó mỗi 6–12 tháng, hoặc sớm hơn nếu kích thước đội hoặc nhịp phát hành thay đổi.\n\nTrước khi di chuyển file, chọn thay đổi nhỏ nhất giải quyết đau thật sự:\n\n- Thêm và tuân theo quy tắc version cho package chia sẻ.\n- Định nghĩa hợp đồng API và bắt buộc test hợp đồng trong CI.\n- Đồng ý một checklist phát hành chung cho web, mobile và backend.\n- Dùng môi trường preview cho thay đổi chạm nhiều phần.\n- Đặt ngân sách thời gian CI (ví dụ: kiểm tra PR dưới 15 phút).\n\nNếu coupling giữa codebase thực sự là nút thắt, giảm số nơi phải thay đổi có thể quan trọng hơn layout repo. Một số đội làm điều đó bằng cách chuyển nhiều logic và mô hình dữ liệu vào một nguồn chân lý duy nhất.\n\nNếu bạn muốn khám phá cách đó, AppMaster (appmaster.io) được xây để sinh dịch vụ backend, app web và native mobile với mô hình dữ liệu và business logic chung. Cách đánh giá rủi ro thấp là xây một công cụ nội bộ nhỏ trước, rồi quyết định dựa trên bao nhiêu công việc phối hợp nó loại bỏ.\n\nCon đường tự tin là cố tình nhàm chán: ghi lại quyết định, giảm coupling, tự động hóa kiểm tra, và chỉ thay đổi cấu trúc repo khi số liệu nói rằng nó sẽ giúp.

Câu hỏi thường gặp

How do I decide between a monorepo and a polyrepo for web, mobile, and backend?

Bắt đầu từ tần suất một tính năng buộc phải thay đổi đồng thời web, mobile và backend. Nếu hầu hết công việc cắt ngang nhiều phần và phối hợp là nỗi đau chính, monorepo hoặc cách tiếp cận “hợp đồng đơn” chặt chẽ thường giảm hỏng hóc. Nếu các đội hiếm khi chạm tới cùng một vùng và cần quyền truy cập cùng khả năng phát hành độc lập, polyrepo có thể hoạt động tốt với quy tắc tương thích nghiêm ngặt.

What usually causes the “everything broke after a small change” problem?

Sự trôi dạt API (API drift), không khớp phiên bản thư viện chia sẻ, và khác biệt thời gian phát hành (đặc biệt là độ trễ do app store với mobile) là thủ phạm chính. Cách khắc phục là lên kế hoạch cho việc tồn tại nhiều phiên bản cùng lúc trong thực tế, không kỳ vọng tất cả release đồng bộ hoàn hảo, và làm cho thay đổi phá vỡ trở nên hiếm và có chủ ý.

What’s the safest way to manage API contracts across web and mobile?

Xem schema API là nguồn chân lý và sinh client từ đó để các khác biệt thất bại ở bước build, chứ không phải QA hay production. Ưu tiên các thay đổi bổ sung (additive) trước, sau đó mới deprecate trường cũ, và giữ cửa sổ tương thích ngắn khi bắt buộc phải đổi tên hoặc loại bỏ thứ gì đó.

How should we handle shared libraries without creating a mess?

Hướng tới cập nhật nhỏ, đều đặn theo nhịp (ví dụ hàng tuần thay vì hàng quý) và yêu cầu phê duyệt rõ ràng cho thay đổi phá vỡ. Đính kèm ghi chú di trú ngắn gọn cho mỗi thay đổi và định nghĩa “hoàn thành” là “web, mobile và backend build đều pass”, chứ không chỉ một repo.

Should we ship everything on one shared version or let each part version independently?

Mặc định là để mỗi phần có version riêng với quy tắc tương thích rõ ràng: backend phiên bản nào hỗ trợ client phiên bản nào, và trong bao lâu. Một release train chung có thể hiệu quả ở giai đoạn sớm, nhưng độ trễ của mobile thường làm nó trở nên khó chịu trừ khi bạn chấp nhận chờ đợi thời gian duyệt app store.

How do we avoid breaking mobile users when the backend ships first?

Giữ backend tương thích để các bản mobile cũ vẫn hoạt động khi người dùng cập nhật. Dùng các trường bổ sung (additive), đừng loại bỏ hành vi cũ quá sớm, và dùng feature flag khi cần ra mắt thay đổi có hiển thị cho client một cách dần dần.

Who should own release coordination across web, mobile, and backend?

Giao cho một người/role đảm nhiệm rõ ràng—thường là tech lead, release manager, hoặc product owner có hỗ trợ kỹ thuật. Mục tiêu là một lịch phát hành đơn giản, lặp lại được, và quy tắc quyết định rõ ràng khi có trễ (giữ thay đổi lại hay giữ tương thích).

What’s the best first step to reduce CI time without changing repo structure?

Ưu tiên chỉ build và test phần đã thay đổi và cache mọi thứ có thể. Tách các kiểm tra nhanh (mỗi commit) khỏi kiểm tra chậm (nhánh chính, nightly, hoặc trước release) để dev nhận phản hồi nhanh mà không phải trả chi phí test đầy đủ mỗi lần.

How do monorepos keep CI from becoming “build the world” on every commit?

Dùng bộ lọc theo đường dẫn và cách tiếp cận “chỉ ảnh hưởng” để không rebuild toàn bộ dự án cho một thay đổi nhỏ. Khi module chia sẻ thay đổi, chỉ chạy kiểm tra cho các app phụ thuộc vào nó, và giữ rõ quyền sở hữu và luật review để một repo không biến thành nơi chứa rác chung.

How do polyrepos avoid drift and inconsistent pipelines across teams?

Chuẩn hóa công cụ và template CI giữa các repo để mỗi nơi không phải sáng chế lại bước, cache và quy ước. Thêm một kiểm tra tích hợp để xác thực các hợp đồng chính giữa các release, và cố định phiên bản toolchain để tránh tình trạng “chạy được ở repo này nhưng không chạy được ở repo kia”.

Dễ dàng bắt đầu
Tạo thứ gì đó tuyệt vời

Thử nghiệm với AppMaster với gói miễn phí.
Khi bạn sẵn sàng, bạn có thể chọn đăng ký phù hợp.

Bắt đầu
Monorepo vs polyrepo: giữ web, mobile, backend đồng bộ | AppMaster