15 điểm bởi GN⁺ 2025-06-05 | 4 bình luận | Chia sẻ qua WhatsApp
  • Việc áp dụng monorepo mang lại nhiều lợi ích như tăng tính nhất quán trong tổ chức, chia sẻ mã nguồn và củng cố môi trường công cụ dùng chung, nhưng nếu sao chép nguyên xi các trường hợp của Big Tech thì sẽ phải đối mặt với những vấn đề và thách thức mới
  • Để monorepo thành công, cần tuân thủ nguyên tắc biến mọi tác vụ chính thành O(change) thay vì O(repo), và ở từng giai đoạn build, test, CI/CD đều cần có công cụ và chiến lược phù hợp
  • Với source control, có thể bắt đầu từ Git và khi quy mô tăng lên thì nên cân nhắc mở rộng dần bằng sparse checkout, hệ thống tệp ảo, v.v.
  • Với build system, nên cố gắng duy trì một ngôn ngữ duy nhất nếu có thể, bám trụ tối đa với công cụ build mặc định của từng ngôn ngữ, và chỉ chuyển dần sang Bazel/Buck2 khi thực sự cần thiết
  • Với test·CI/CD, cần nhanh chóng xác định đúng phạm vi bị ảnh hưởng bởi thay đổi để build, test và triển khai; trong monorepo quy mô lớn, các chiến lược đảm bảo độ tin cậy như tự động chạy lại test và cô lập flaky test cũng là bắt buộc

Mở đầu: bắt đầu hành trình đến với monorepo

  • Nếu là kỹ sư trong một nhóm Developer Productivity mới, bạn sẽ ngày càng băn khoăn phải chuẩn bị gì và cần nỗ lực ra sao sau khi đã quyết định áp dụng monorepo
  • Những thực tiễn mẫu từ các tập đoàn lớn như Google, Meta, Uber trông rất ấn tượng, nhưng trên thực tế không thể đạt được kết quả ở đúng cùng một cấp độ như họ
  • Mỗi tổ chức cần quyết định áp dụng monorepo dựa trên lý do và nhu cầu riêng của mình, và trong quá trình đó có thể theo đuổi các lợi ích như tính nhất quán (consistency), sự tích hợp ở cấp độ tổ chứccông cụ dùng chung

Làm rõ sự cần thiết của monorepo

  • Các trường hợp của doanh nghiệp lớn chỉ là hình hài họ đạt tới ở giai đoạn cuối, nên không phù hợp để dùng làm căn cứ tham khảo ở giai đoạn đầu
  • Trên thực tế sẽ phát sinh những vấn đề mới, và đó là các kiểu vấn đề khác với khi quản lý nhiều repository riêng lẻ trước đây
  • Mục tiêu của việc áp dụng monorepo là duy trì tính nhất quán, tích hợp công cụ trên toàn tổ chức, áp dụng tiêu chuẩn kỹ thuật và convention kỹ thuật
  • Mỗi nhóm cần xác định rõ mục tiêu phù hợp với văn hóa và định hướng riêng để đạt được kết quả hiệu quả

Quy tắc vàng: nguyên tắc O(change)

  • Mọi công cụ liên quan đến repository đều phải có độ phức tạp O(change) thay vì O(repo) để có thể hoạt động nhanh
  • Trên thực tế, monorepo càng lớn thì sự kém hiệu quả của các công cụ cũ càng bộc lộ rõ, nên thiết kế mang tính cấu trúc để vượt qua vấn đề hiệu năng là điều bắt buộc
  • Những đổi mới thường được nhắc tới trong blog kỹ thuật của các công ty lớn phần nhiều cũng tập trung vào việc khắc phục sự kém hiệu quả do O(repo) gây ra

Source control

  • Phần lớn các tổ chức phần mềm dùng Git làm mặc định, nhưng Git có giới hạn hiệu năng khi mở rộng ở quy mô lớn trong môi trường monorepo tập trung
    • Trên thực tế, đa số tổ chức có thể dùng git+GitHub ổn định trong một khoảng thời gian khá dài
  • Khi tăng trưởng nhanh hơn, sẽ cần đến các cấu trúc như sparse checkout (clone một phần) và hệ thống tệp ảo (tải động tệp từ máy chủ khi cần)
  • Các công ty lớn đã fork Git hoặc tự phát triển hệ thống riêng để đáp ứng nhu cầu này (Microsoft: Git fork nội bộ, Meta: Mercurial fork, Google: Piper)
    • Cũng đáng cân nhắc các hệ source control thế hệ mới như Jujutsu
  • Khi quy mô còn nhỏ, có thể dùng Git mà không gặp nhiều trở ngại, nhưng trong quá trình tăng trưởng vẫn cần tính trước chiến lược mở rộng
  • Cũng tồn tại một vấn đề thực tế là nếu mã nguồn chứa code được sinh ra từ IDL(Interface Definition Language) thì kích thước repository có thể tăng theo cấp số nhân

Build system

  • Bazel, Buck2 là những công cụ build monorepo tiêu biểu, hỗ trợ nhiều ngôn ngữ và đồ thị build phức tạp
    • Chúng rất mạnh nhưng cũng kéo theo độ phức tạp và gánh nặng vận hành lớn
  • Nếu giữ được build trong một ngôn ngữ duy nhất thì mọi thứ sẽ dễ thở hơn rất nhiều, và các build system theo từng ngôn ngữ (ví dụ: Maven, Gradle, Cargo, Go) cũng có khả năng mở rộng cao
  • Vai trò cốt lõi của build system là “build hiệu quả target được chỉ định (tạo artifact một cách hiệu quả)” và “nhanh chóng xác định các target bị ảnh hưởng bởi những tệp đã thay đổi”
  • Vì vậy cần đến khái niệm target determinator (công cụ xác định target), và trong các hệ sinh thái như Rust, Go, Bazel đã có sẵn nhiều cách giải quyết
  • Remote execution và caching chỉ thực sự cần thiết ở quy mô cực lớn; với doanh nghiệp thông thường, target determination lại hữu dụng và thực tế hơn

Test

  • Việc chạy toàn bộ test ở mọi lần là không hiệu quả, vì thế cần một hệ thống chỉ test phần phạm vi bị ảnh hưởng bởi thay đổi
  • Flaky test có thể trở thành vấn đề nghiêm trọng hơn trong các hệ thống test quy mô lớn
  • Hệ thống test cần có khả năng tự động chạy lại, tự động xác định phạm vi ảnh hưởng của test và cô lập flaky test
  • Một số ngôn ngữ (ví dụ: Rust với nextest, Java với JUnit) cung cấp các tính năng nâng cao này dưới dạng mặc định hoặc mở rộng
  • Hệ thống test trong monorepo phải được tích hợp chặt chẽ với build system thì mới phát huy hiệu quả

Tích hợp liên tục (CI)

  • Hệ thống CI cần tự động thực hiện artifact buildxác minh tính hợp lệ cần thiết tùy theo từng thay đổi
  • Hiệu năng và hiệu quả của target determinator là yếu tố cốt lõi trong pipeline CI
  • CI hiện đại dùng nhiều chiến lược như “Merge Queue” để tìm điểm cân bằng giữa việc duy trì chất lượng mã và tối ưu tốc độ hợp nhất
    • Ví dụ: có chạy mọi bước kiểm tra cho từng commit/PR đơn lẻ hay chỉ chọn một phần, hoặc xử lý nhiều PR theo lô
  • Cần tự định nghĩa và thiết kế các đánh đổi giữa Throughput (thông lượng), Correctness (độ chính xác)Tail latency (độ trễ tối đa)
  • Việc quản lý hợp nhất và nâng cao hiệu quả CI cho monorepo quy mô lớn đến nay vẫn là một bài toán khó chưa có lời giải hoàn hảo
  • Rust (bors), Chromium, Uber đều lựa chọn các chiến lược hợp nhất/xác minh khác nhau

Triển khai liên tục (CD)

  • Ảo tưởng rằng mọi thay đổi trong monorepo sẽ được triển khai một cách nguyên tử là điều không đúng với thực tế
  • Một PR có thể đồng thời thay đổi interface, implementation và cả client của nhiều dịch vụ, nhưng việc triển khai thực tế cuối cùng vẫn diễn ra bất đồng bộ, nên tại thời điểm deploy vẫn có thể phát sinh sự cố
  • Những thay đổi làm phá vỡ contract giữa các dịch vụ có thể gây ra sự cố nghiêm trọng khi triển khai
  • Một chiến lược CD hiệu quả cho monorepo cần có chu kỳ của hệ thống triển khai, cơ chế kiểm chứng contract dịch vụ và năng lực phát hiện, ứng phó nhanh khi có sự cố

Kết luận

  • Monorepo là một công cụ mạnh mẽ để củng cố tính nhất quán ở cấp tổ chức và văn hóa kỹ thuật, nhưng đòi hỏi đầu tư liên tục vào kỹ thuật và công cụ
  • Ở từng giai đoạn, điều cốt lõi là xây dựng tự động hóa, công cụ và văn hóa phù hợp với nguyên tắc O(change)
  • Khi tổ chức phát triển, công cụ cũng phải tiếp tục tiến hóa, và nỗ lực quản lý có hệ thống phản ánh mục tiêu cùng văn hóa tổ chức là rất quan trọng
  • Nếu có đủ quyết tâm, cam kết và đầu tư liên tục, monorepo cuối cùng sẽ tạo ra giá trị xứng đáng

4 bình luận

 
bichi 2025-06-05

Đây đúng là một bài viết rất bổ ích. Không chỉ cần những công cụ mạnh mẽ mà còn phải sẵn sàng tự tạo ra những công cụ cần thiết khi cần. Vì vậy, nếu vận hành trơn tru thì lợi ích thu được cũng rất nhiều.

 
cosine20 2025-06-05

Hồi học cao học, giáo sư hướng dẫn từng đi ăn với một kỹ sư xuất thân từ Google rồi nghe kể về monorepo hay sao đó, nên đã đề xuất rằng từ nay phòng lab của chúng tôi cũng hãy quản lý bằng monorepo, và tôi đã khá vất vả để can ngăn...
Monorepo đúng là có nhiều điểm hay, nhưng do đặc thù của phòng lab chúng tôi là thường xuyên phải chia sẻ các kết quả đầu ra cho người bên ngoài, nên nếu đã quản lý thành quả bằng monorepo thì có lẽ ở khâu này sẽ đặc biệt vất vả. Nếu là multi-repo thì chỉ cần điều chỉnh phạm vi công khai theo từng thành quả là được.

 
youngrok 2025-06-05

Có vẻ như hầu hết những trường hợp khổ sở khi làm monorepo là do ngay từ đầu đã chia nhỏ dự án quá mức. Vốn dĩ chỉ cần một hai dự án thì lại tách thành hơn chục cái, rồi khi cố gộp chúng lại để quản lý bằng monorepo thì vừa phải dùng thêm công cụ quản lý monorepo, vừa làm độ phức tạp tăng lên. Tốt hơn là nên gộp chính các dự án lại còn một hai cái; ngay cả khi có từ hai dự án trở lên thì cũng đừng dùng công cụ quản lý riêng, mà cứ nghĩ đơn giản là chia thư mục ra rồi đặt chúng vào cùng một repository, như vậy sẽ quản lý nhẹ đầu hơn nhiều.

 
GN⁺ 2025-06-05
Ý kiến trên Hacker News
  • Xem chuỗi thảo luận này khiến tôi nhớ lại những câu chuyện cũ về các "complexity merchants", nên muốn chia sẻ chút trải nghiệm. Tôi hoàn toàn không đồng ý với quan điểm rằng chuyển sang monorepo sẽ phải hy sinh về mặt kỹ thuật. Nếu hiểu sức mạnh của hệ thống tệp phân cấp, bạn sẽ thấy giá trị của monorepo. CI/CD được cấu hình trong một monorepo duy nhất rõ ràng hơn rất nhiều so với cấu hình rải rác khắp nơi. Điểm cốt lõi của monorepo là toàn bộ tổ chức có thể thực hiện các commit mang tính nguyên tử. Khi phải điều phối nhiều lập trình viên, hiệu quả của điều này là áp đảo. Chỉ cần rebase một lần và một cuộc họp lớn là đủ. Ngay cả khi các thành viên không ưa nhau và không muốn cộng tác, xét về mặt quản lý thì monorepo vẫn là một công cụ HR rất mạnh.

    • Gần đây các lập trình viên có xu hướng quá mức theo đuổi sự tách biệt, microservices, nhiều repository nhỏ, và cực kỳ né tránh monolith. Điều này làm tăng độ phức tạp và biến các vấn đề về cấu trúc tổ chức thành các vấn đề kỹ thuật trong tương lai. Họ cũng không nhận thức đúng về các phụ thuộc nội tại trong hệ thống phần mềm. Ở công ty cũ, lượng thời gian bị lãng phí chỉ để cập nhật các file schema Protocol Buffers thật khó tin. May là công ty hiện tại không như vậy.

    • Việc theo dõi commit qua nhiều dự án thì có cũng tốt, nhưng trên thực tế không tạo khác biệt lớn về theo dõi phụ thuộc hay kích hoạt kiểm thử downstream. Tự động hóa cho multi-repo cũng hoàn toàn làm được. Monorepo có giúp ích, nhưng không phải vạn năng, và cái giá phải trả cũng lớn. Việc deploy hay build không được xử lý theo kiểu nguyên tử. Khi monorepo lớn lên, bạn sẽ phải rời khỏi git và cần công cụ mới, mà đây là một công việc cực lớn. Nếu chưa từng trải qua thì rất dễ nói nhẹ phần này.

    • Rõ ràng monorepo có ưu điểm, nhưng chi phí quản lý cao hơn polyrepo. Không phải trong mọi hoàn cảnh monorepo đều tốt hơn vô điều kiện. Giải thích chi tiết xem bài này. Hiệu quả so với chi phí còn tùy tình huống.

    • Một quy tắc kinh nghiệm hữu ích trong thiết kế môi trường lập trình là: càng trao cho nhóm nhiều quyền lực thì càng phát sinh nhiều vấn đề. Về mặt kỹ thuật, commit nguyên tử không phải là một dạng quyền lực mạnh hơn mà thực ra là ít quyền lực hơn, nhưng nó lại cho phép người ta làm việc với các interface tệ, nên rốt cuộc lại tạo ra vấn đề.

    • Có ý kiến cho rằng niềm tin rằng chuyển sang monorepo sẽ khiến thay đổi trở nên nguyên tử hơn là một cái bẫy. [Trích nguyên văn: Ảo tưởng lớn nhất của monorepo là có thể thực hiện commit nguyên tử trên toàn bộ codebase. Thực tế là có nhiều artifact triển khai khác nhau; dù bạn thay đổi service và client cùng lúc thì việc triển khai vẫn diễn ra bất đồng bộ. Với nhiều repo, bạn phải làm việc qua nhiều PR nên luôn có sẵn nhận thức về rủi ro. CI của monorepo chủ yếu đóng vai trò xác minh các hợp đồng dịch vụ (CI job), và khi cần thì phải nêu rõ lý do thay đổi.]

  • Monorepo ở các công ty Big Tech có hai kiểu. Kiểu thứ nhất là một monorepo duy nhất trên toàn công ty như bài viết đề cập, kiểu "THE" monorepo, cần VCS/CI tùy biến và có khoảng 200 kỹ sư hỗ trợ. Google, Meta, Uber theo cách này. Nỗi đau để đạt đến cấp độ đó vượt xa sức tưởng tượng, và thường họ đi lên dần từ các monorepo "theo nhóm" nhỏ hơn. Mỗi stack/ngôn ngữ/đội tự quản lý bằng các công cụ như Bazel, Turborepo, Poetry, rồi theo thời gian được gộp vào một monorepo lớn hơn. Nhưng cả hai kiểu này đều đòi hỏi hàng triệu đô la và hàng triệu giờ đầu tư từ cả phía kỹ sư lẫn doanh nghiệp, và cuối cùng được duy trì nhờ sự hỗ trợ của những lập trình viên đã sống sót qua quá trình đó.

    • Khi từng làm ở một công ty có monorepo lớn, tôi thích monorepo hơn hẳn. Một monorepo duy nhất cực kỳ hữu ích để nhìn thấy toàn cảnh như service graph, cấu trúc gọi code, v.v. Với polyrepo, tri thức bị phân tán theo từng nhóm, việc tiếp nhận code mới cũng khó, còn hiểu được kho code thì chẳng khác gì đi lạc trong mê cung. Polyrepo giống như những tin nhắn Discord/Slack cũ bị lãng quên. Nếu monorepo tốn kém thì polyrepo cũng tốn kém theo cách khác. Monorepo là loài ăn cỏ trên một đại lục khổng lồ, còn polyrepo là vô số loài khác nhau bị chôn vùi trong bóng tối.

    • Ở công ty hiện tại, backend đang bị chia ra khoảng 11 git repo, và để làm một tính năng phải mở 4~5 merge request nên cực kỳ phiền. Chúng tôi đang cân nhắc áp dụng monorepo để gom nhiều dự án lại. Nhưng nếu không thể gộp repo thì giải pháp thay thế cho monorepo là gì?

    • Hiện vẫn chưa có hệ thống orchestration monorepo nào vừa dễ vừa mạnh và không phụ thuộc ngôn ngữ. Bazel thì phức tạp và khó học, nhưng gần đây tài liệu đã cải thiện rất nhiều. Còn có Buck, NX, Pants và các lựa chọn khác, nhưng mỗi cái đều có đặc điểm riêng, nhất là hỗ trợ web còn hạn chế. Phần lớn CI cũng không hỗ trợ tốt các công cụ này nên cấu hình khá vất vả. Tham khảo thêm, Rush của Microsoft mang lại trải nghiệm tốt nhất, đặc biệt với monorepo frontend/NodeJS thì tôi khuyên dùng Rush trang chính thức của Rush.

    • Thực tế là đa số monorepo không phình to đến quy mô như Google, Uber hay Meta. Số lượng service cũng khác nhau tùy công ty, nhưng ngay cả khi có khoảng 100 service thì cũng chưa gặp vấn đề về quy mô VCS, còn LSP tag vẫn chạy ổn trên laptop. Dù có chạy toàn bộ test trên CI một cách đơn giản thì hầu như vẫn ổn. Kết luận: không phải công ty nào cũng cần quy mô kiểu Google.

    • Công ty hiện tại của tôi đang xây monorepo theo từng stack ngôn ngữ. Đây là một phương án dung hòa khá ổn.

  • Một điểm ít được nhắc tới trong tranh luận monorepo vs multi-repo là hiện tượng 'Định luật Conway ngược'. Tức là cấu trúc repo sẽ ảnh hưởng đến cấu trúc tổ chức và cách giải quyết vấn đề. Monorepo dễ dẫn đến những công việc mang tính anh hùng ở đội hạ tầng dùng chung; mỗi khi đụng vào vùng chung thì nguy cơ làm vỡ thứ gì đó tăng lên, khiến ngay cả việc phát triển một tính năng cũng khó hơn. Trong multi-repo thì cần nhiều PR, điều phối liên nhóm và cả chính trị nội bộ, nhưng đổi lại nhiều lập trình viên hơn có thể chia vai ra xử lý.

    • Ngay cả trong monorepo, nếu thay đổi đó nằm ở trung tâm và có liên kết sâu thì vẫn có thể triển khai theo nhiều bước. Trong quá trình đó vẫn phải xử lý nhiều PR, phối hợp và cả yếu tố chính trị, nhưng ngược lại monorepo giúp nhìn tình trạng rollout rõ ràng hơn.

    • Trong polyrepo, việc thay đổi ở vùng dùng chung không được phản ánh xuống các repo downstream thường xảy ra hơn nhiều, khiến từng repo bị ghim ở các phiên bản khác nhau, rồi nhiều năm không cập nhật và gây khổ sở.

    • Có đúng không khi giả định rằng tổ chức ban đầu chọn hướng đi bằng cấu trúc repo rồi sau đó lựa chọn công nghệ mới đi theo? Trên thực tế, thứ có trước thường là triết lý tổ chức ở mức nền tảng hơn (phân mảnh hay chia sẻ), chứ không hẳn là cấu trúc repo cụ thể. Kể cả khi đổi hướng thì cách quản lý code vẫn có thể điều chỉnh. Multi-repo vẫn có thể cho kỹ sư truy cập gần như toàn bộ code, còn monorepo cũng có thể áp dụng cách ly chặt và quy tắc CI hay deploy riêng biệt.

    • Trong monorepo, việc thay đổi qua nhiều dự án dễ dàng hơn rất nhiều; còn trong polyrepo, vì quá phiền nên nhiều trường hợp người ta thậm chí còn chẳng buồn thử.

  • Theo kinh nghiệm ở các công ty công nghệ lớn, quản lý hệ thống build cần hẳn một đội chuyên trách. Monorepo lớn dựa trên hệ thống tệp ảo, nơi file nguồn được tải xuống khi cần. Một điểm bài viết chưa nhắc tới là hầu như mọi phát triển đều diễn ra trên các dev server chạy trong data center, dùng môi trường 50~100 core hoặc container on-demand (được cập nhật lên commit mới nhất liên tục). IDE tích hợp với dev server, và cả phần chuẩn bị/cấu hình tự động theo ngôn ngữ hay service cũng được tự động hóa bằng chef/ansible. Việc phát triển trực tiếp monorepo quy mô lớn trên laptop là rất hiếm (ngoại lệ: mobile/mac app, v.v.).

    • Có lẽ chúng ta từng làm trong cùng kiểu đội build. Dù môi trường phát triển monorepo là local hay remote thì tính tái lập (reproducibility) vẫn quan trọng hơn. Nếu là remote dev server được dựng sẵn image thì còn dễ hơn và đáng tin cậy hơn.

    • Tôi cũng từng dùng môi trường phát triển trong data center ngay cả với đội quy mô nhỏ. Xét theo giá phần cứng và mật độ hiện nay, tự dựng một rack để chạy các công cụ on-demand cho dev/staging/test hợp lý hơn nhiều. Khi mọi người cùng chia sẻ môi trường phát triển gần giống production, cách nhìn về monorepo sẽ rất khác. Tuy vậy, doanh nghiệp vừa và nhỏ không có khả năng đầu tư vào hệ thống build, và cũng không phát sinh chính những vấn đề kiểu hệ thống build lớn đó (quy mô tối thiểu khoảng 10~20 người; kể cả với sản phẩm rất phức tạp thì việc bảo trì đôi khi cũng chỉ ở mức part-time).

  • Câu chuyện của một đội nhỏ ở Molnett (serverless cloud) đã đạt hiệu quả khổng lồ với monorepo dựa trên Bazel (1.5 người toàn thời gian). Với Tilt+Bazel+Kind, họ có thể chạy toàn bộ nền tảng và cả Kubernetes operator trên laptop, hỗ trợ cả Mac/Linux. Thậm chí có thể kiểm chứng cả OS dựa trên Bottlerocket lẫn Firecracker ngay trên máy local. Nhờ xây dựng tool layer, mọi lập trình viên đều dùng cùng phiên bản go/kubectl, không cần cài đặt local. Việc quản lý có tốn công, nhưng nhờ có một cựu thành viên Google SRE nên làm được. Về sau tôi vẫn chỉ muốn làm theo cách này. (Ngôn ngữ chính là Golang, Bash, Rust)

    • Với quy mô nhỏ 1.5 người thì dùng repo đơn là quá hiển nhiên. Trải nghiệm của tôi với Bazel rất tệ, nhưng với dự án lớn thì có thể đáng dùng. Còn dưới 2 người thì chỉ Kind+Tilt có khi đã đủ. Tool layer cũng phần nào đã được Go giải quyết bằng go.mod. kubectl cũng có thể làm tương tự. Cũng nên cân nhắc mức lương của một ex-Googler. Hy vọng chi phí duy trì Bazel về sau vẫn xứng đáng.

    • Công ty tôi deploy bằng các service dựa trên systemd và ansible playbooks, dùng tmuxinator để tự động khởi động mọi service ở chế độ dev cho backend/DB/search engine/frontend chỉ trong một lần mở terminal. Chỉ cần chạy một lệnh tmuxinator ở root là toàn bộ môi trường dev lên ngay. Một monorepo duy nhất tiện hơn áp đảo so với trước đây.

    • Tình huống tương tự, tôi cũng muốn chia sẻ rằng việc áp dụng Bazel đã khuếch đại hiệu quả rất rõ. Nhờ tool layer mà môi trường phát triển được giữ đồng nhất. Tôi hiện phải tự dùng bazel run, nên muốn biết có cách tự động hóa nào tốt hơn không. Mong được giải thích cách nó vận hành.

    • Với đội 2 người thì chính mô hình microservices/K8s đã là over-engineering. Ở quy mô nhân sự này thì làm kiểu nào cũng không thành vấn đề. Trước đây Dropbox/SVN/MS VCS hay kiểu nào khác cũng đều vận hành được (dù có bất tiện), và chẳng cái nào là vấn đề lớn. Ở quy mô này, mọi người đều có thể hình dung toàn bộ quy trình trong đầu. Chia sẻ từ trải nghiệm thực tế là công cụ hay hạ tầng phức tạp không phải yếu tố quyết định thành công.

  • Chia sẻ của một freelancer đã ba lần thiết lập monorepo ở nhiều công ty trong 4 năm qua. Vì chỉ giới hạn ở frontend và dùng hệ sinh thái JavaScript/TypeScript nên việc quản lý còn tương đối dễ. Một monorepo tốt trên thực tế vận hành như polyrepo ở bên trong: mỗi dự án có thể được phát triển/triển khai/hosting độc lập, nhưng cùng tồn tại trong một codebase và vẫn thoải mái chia sẻ các thành phần chung (như UI), bảo đảm tính nhất quán về giao diện và trải nghiệm. Là hướng dẫn thực chiến, tôi khuyên xem tài liệu này.

    • Đây thực ra không phải polyrepo, mà là một ví dụ monorepo được xây dựng đúng cách.
  • Rốt cuộc, mọi thứ đều tùy trường hợp. Công ty chúng tôi quản lý khoảng hơn 40 git repo với CI tách biệt, rồi build/test/package xong thì cuối cùng tạo ra một ảnh hệ thống tệp tích hợp để chạy integration test. Các thành phần giao tiếp với nhau bằng thông điệp Flatbuffers, và flatbuffers cũng được quản lý bằng submodule. Việc xử lý phụ thuộc downstream đúng là vất vả, nhưng nhờ progressive enhancement mà vẫn có được một mức linh hoạt nhất định. Trong trường hợp này, gọi là multi-repo hay là monorepo có nhiều submodule cũng còn mơ hồ. Chưa rõ chuyển sang monorepo có mang lại lợi ích hay không. Cuối cùng vẫn là bài toán trade-off và chọn kiểu bất tiện mà mình chấp nhận được.

  • Chia sẻ từ tác giả bài blog về công cụ monorepo. Mọi người thường chỉ nhấn mạnh lợi ích của monorepo, nhưng trên thực tế, phần lớn độ phức tạp để vận hành monorepo thành công đều được đội devops/devtools gánh ở phía sau. Vì vậy cần thận trọng khi áp dụng, nhưng nếu xây tốt thì nó hoàn toàn có giá trị.

  • Trải nghiệm với một monorepo được quản lý tốt quá tuyệt vời đến mức tôi không muốn quay lại workflow khác. Nhưng kiểu chưa chuẩn bị gì mà hô "chúng ta cũng làm monorepo đi" thì đúng là ác mộng. Nếu có ai đóng gói sẵn môi trường và công cụ monorepo đã chuẩn bị tốt để bán, tôi nghĩ đó sẽ là một cơ hội kinh doanh lớn.

    • NX thực ra đã làm đúng mảng đó. Ở startup trước, chúng tôi phát triển với NX ngay từ đầu và dù đội R&D chỉ có 15 người vẫn đạt được mức chuẩn hóa kiểu công ty 100 người. Công ty mới của tôi (nơi đã thâu tóm startup đó) thì thử kiểu "chúng ta cũng monorepo" không kế hoạch và thành thảm họa. Giờ đang chuyển sang NX và hiệu quả rất tốt.
  • Từ kinh nghiệm ở tổ chức lớn, monorepo đôi khi lại cực kỳ hạn chế phụ thuộc giữa các nhóm và làm giảm khả năng tái sử dụng code. Khi đội thư viện muốn thay đổi, mọi bên dùng phía dưới đều phải cập nhật, nhưng vì có những đội dùng theo cách không lường trước được nên việc sửa đổi bị rối tung lên theo Hyrum's Law. Kết cục ở doanh nghiệp lớn thường là sao chép-dán nội bộ, fork, kiểm soát truy cập nghiêm ngặt và quy trình phê duyệt thay đổi chậm chạp.

    • Khi làm một thư viện để dùng rộng rãi thì phải rất cẩn trọng trong thiết kế API. Tốt nhất là đừng thay đổi API; còn nếu buộc phải đổi thì hãy lên kế hoạch kỹ cho thay đổi lớn, hoặc thay bằng hàm mới và đánh dấu phiên bản cũ là deprecated. Nếu code nhỏ thì copy-paste cũng không sao.

    • Dù vậy, ưu điểm của monorepo vẫn là có thể dễ dàng tìm ra mọi nơi đang sử dụng, và khi cần có thể thay đổi/sửa đồng thời theo kiểu nguyên tử.

    • Mọi phần mềm đều phải tính đến quan hệ phụ thuộc, và monorepo thậm chí còn làm tăng quyền thay đổi lẫn nhau từ phía thư viện hay phía người dùng.

    • Trong monorepo, vì việc sửa cho phù hợp với hoàn cảnh của mình dễ hơn nên xác suất tái sử dụng code cao hơn polyrepo.