Monorepositories: xin vui lòng, phải

Monorepositories: xin vui lòng, phải

Dịch bài viết chuẩn bị cho học viên khóa học "Các phương pháp và công cụ DevOps" trong dự án giáo dục OTUS.

Bạn nên chọn một kho lưu trữ đơn vì hành vi mà nó thúc đẩy trong nhóm của bạn là tính minh bạch và chia sẻ trách nhiệm, đặc biệt là khi các nhóm phát triển. Dù bằng cách nào, bạn sẽ phải đầu tư vào công cụ, nhưng sẽ luôn tốt hơn nếu hành vi mặc định là hành vi bạn muốn trong các lệnh của mình.

Tại sao chúng ta lại nói về điều này?

Matt Klein đã viết bài báo "Monorepos: Làm ơn đừng!"  (ghi chú của người dịch: bản dịch trên Habré “Kho lưu trữ đơn: xin đừng”). Tôi thích Matt, tôi nghĩ anh ấy rất thông minh và bạn nên đọc quan điểm của anh ấy. Ban đầu anh ấy đã đăng cuộc thăm dò trên Twitter:

Monorepositories: xin vui lòng, phải

Translation:
Ngày đầu năm mới này, tôi sẽ tranh luận về việc các kho lưu trữ đơn lẻ lố bịch như thế nào. Năm 2019 bắt đầu một cách lặng lẽ. Với tinh thần này, tôi cung cấp cho bạn một cuộc khảo sát. Những người cuồng tín lớn là ai? Người ủng hộ:
- Monorepo
- Rust
- Cuộc thăm dò không chính xác/cả hai

Câu trả lời của tôi là, "Tôi thực sự là cả hai người đó." Thay vì nói về việc Rust là một loại ma túy như thế nào, hãy xem lý do tại sao tôi nghĩ anh ấy sai về kho đơn. Một chút về bản thân bạn. Tôi là CTO của Chef Software. Chúng tôi có khoảng 100 kỹ sư, cơ sở mã đã tồn tại khoảng 11-12 năm và 4 sản phẩm chính. Một số mã này nằm trong kho lưu trữ đa năng (vị trí bắt đầu của tôi), một số nằm trong kho lưu trữ đơn (vị trí hiện tại của tôi).

Trước khi bắt đầu: mọi lập luận tôi đưa ra ở đây sẽ áp dụng cho cả hai loại kho lưu trữ. Theo ý kiến ​​của tôi, không có lý do kỹ thuật nào khiến bạn nên chọn loại kho lưu trữ này thay vì loại kho lưu trữ khác. Bạn có thể thực hiện bất kỳ cách tiếp cận nào. Tôi rất vui khi nói về điều đó, nhưng tôi không quan tâm đến những lý do kỹ thuật giả tạo tại sao cái này lại vượt trội hơn cái kia.

Tôi đồng ý với phần đầu tiên của quan điểm của Matt:

Bởi vì ở quy mô lớn, một kho lưu trữ đơn sẽ giải quyết tất cả các vấn đề tương tự mà một kho lưu trữ đa năng giải quyết, nhưng đồng thời buộc bạn phải kết hợp chặt chẽ mã của mình và đòi hỏi những nỗ lực đáng kinh ngạc để tăng khả năng mở rộng của hệ thống kiểm soát phiên bản của bạn.

Bạn sẽ phải giải quyết các vấn đề tương tự bất kể bạn chọn kho lưu trữ đơn hay kho lưu trữ đa. Làm thế nào để bạn phát hành bản phát hành? Cách tiếp cận của bạn để cập nhật là gì? Khả năng tương thích ngược? Phụ thuộc chéo dự án? Những phong cách kiến ​​trúc nào được chấp nhận? Bạn quản lý cơ sở hạ tầng xây dựng và thử nghiệm của mình như thế nào? Danh sách là vô tận. Và bạn sẽ giải quyết tất cả khi bạn trưởng thành. Không có phô mai miễn phí.

Tôi nghĩ lập luận của Matt giống với quan điểm được chia sẻ bởi nhiều kỹ sư (và nhà quản lý) mà tôi tôn trọng. Điều này xảy ra từ góc độ của kỹ sư làm việc trên thành phần đó hoặc nhóm làm việc trên thành phần đó. Bạn nghe thấy những điều như:

  • Cơ sở mã rất cồng kềnh - tôi không cần tất cả những thứ rác rưởi này.
  • Việc kiểm tra khó hơn vì tôi phải kiểm tra tất cả những thứ linh tinh mà tôi không cần.
  • Khó khăn hơn khi làm việc với các phụ thuộc bên ngoài.
  • Tôi cần hệ thống kiểm soát phiên bản ảo của riêng mình.

Tất nhiên, tất cả những điểm này là hợp lý. Điều này xảy ra trong cả hai trường hợp - trong kho lưu trữ đa năng, tôi có những thứ linh tinh của riêng mình, ngoài thứ cần thiết cho quá trình xây dựng... Tôi cũng có thể cần những thứ linh tinh khác. Vì vậy tôi “đơn giản” tạo ra các công cụ kiểm tra toàn bộ dự án. Hoặc tôi tạo một kho lưu trữ đơn giả giả với các mô-đun con. Chúng ta có thể đi dạo quanh đây cả ngày. Nhưng tôi nghĩ lập luận của Matt đã bỏ sót lý do chính mà tôi đã nghiêng khá nhiều về việc ủng hộ kho lưu trữ đơn:

Nó kích thích giao tiếp và cho thấy các vấn đề

Khi chúng tôi tách biệt các kho lưu trữ, chúng tôi tạo ra vấn đề về sự phối hợp và minh bạch trên thực tế. Điều này tương ứng với cách chúng tôi nghĩ về các nhóm (đặc biệt là cách các thành viên cá nhân nghĩ về họ): chúng tôi chịu trách nhiệm về một thành phần nhất định. Chúng tôi làm việc tương đối cô lập. Các ranh giới được cố định đối với nhóm của tôi và (các) thành phần chúng tôi đang làm việc.

Khi kiến ​​trúc trở nên phức tạp hơn, một nhóm không còn có thể quản lý nó một mình được nữa. Rất ít kỹ sư có được toàn bộ hệ thống trong đầu. Giả sử bạn quản lý thành phần chung A được Nhóm B, C và D sử dụng. Nhóm A đang tái cấu trúc, cải thiện API và cũng thay đổi cách triển khai nội bộ. Kết quả là những thay đổi không tương thích ngược. Bạn có lời khuyên gì?

  • Tìm tất cả những nơi sử dụng API cũ.
  • Có nơi nào không thể sử dụng API mới không?
  • Bạn có thể sửa và kiểm tra các thành phần khác để đảm bảo chúng không bị hỏng không?
  • Các nhóm này có thể kiểm tra những thay đổi của bạn ngay bây giờ không?

Xin lưu ý rằng những câu hỏi này độc lập với loại kho lưu trữ. Bạn sẽ cần tìm các đội B, C và D. Bạn sẽ cần nói chuyện với họ, tìm hiểu thời gian, hiểu các ưu tiên của họ. Ít nhất chúng tôi hy vọng bạn sẽ làm được.

Không ai thực sự muốn làm điều này. Điều này còn kém thú vị hơn nhiều so với việc chỉ sửa cái API chết tiệt đó. Tất cả đều là con người và lộn xộn. Trong một kho lưu trữ đa năng, bạn có thể chỉ cần thực hiện các thay đổi, đưa nó cho những người làm việc trên thành phần đó (có thể không phải B, C hoặc D) để xem xét và tiếp tục. Đội B, C và D hiện tại chỉ có thể giữ nguyên phiên bản hiện tại của họ. Họ sẽ được đổi mới khi họ nhận ra thiên tài của bạn!

Trong kho lưu trữ đơn, trách nhiệm được thay đổi theo mặc định. Đội A thay đổi thành phần của mình và nếu không cẩn thận sẽ ngay lập tức phá vỡ B, C và D. Điều này dẫn đến việc B, C và D xuất hiện trước cửa nhà A, thắc mắc tại sao Đội A lại phá vỡ bộ phận lắp ráp. Điều này dạy A rằng họ không thể bỏ qua danh sách của tôi ở trên. Họ phải nói về những gì họ sẽ làm. B, C và D có thể di chuyển được không? Điều gì sẽ xảy ra nếu B và C có thể, nhưng D có liên quan chặt chẽ đến tác dụng phụ của hành vi của thuật toán cũ?

Sau đó, chúng ta phải nói về cách chúng ta sẽ thoát khỏi tình huống này:

  1. Hỗ trợ nhiều API nội bộ và sẽ đánh dấu thuật toán cũ là không được dùng nữa cho đến khi D có thể ngừng sử dụng thuật toán đó.
  2. Hỗ trợ nhiều phiên bản phát hành, một phiên bản có giao diện cũ, một phiên bản có giao diện mới.
  3. Trì hoãn việc đưa ra những thay đổi của A cho đến khi B, C và D có thể đồng thời chấp nhận nó.

Giả sử chúng tôi đã chọn 1, một số API. Trong trường hợp này chúng ta có hai đoạn mã. Cũ và mới. Khá thuận tiện trong một số trường hợp. Chúng tôi kiểm tra lại mã cũ, đánh dấu mã đó là không được dùng nữa và đồng ý về lịch xóa với nhóm D. Về cơ bản giống hệt nhau đối với các kho lưu trữ poly và mono.

Để phát hành nhiều phiên bản, chúng tôi cần một nhánh. Bây giờ chúng ta có hai thành phần - A1 và A2. Đội B và C sử dụng A2 và D sử dụng A1. Chúng tôi cần mọi thành phần sẵn sàng để phát hành vì có thể cần phải có các bản cập nhật bảo mật và sửa lỗi khác trước khi D có thể tiếp tục. Trong một polyrepository, chúng ta có thể giấu cái này trong một nhánh tồn tại lâu dài mà cảm thấy dễ chịu. Trong kho lưu trữ đơn, chúng tôi buộc phải tạo mã trong một mô-đun mới. Đội D vẫn sẽ phải thực hiện những thay đổi đối với thành phần "cũ". Mọi người đều có thể thấy chi phí chúng tôi phải trả ở đây - hiện tại chúng tôi có số lượng mã gấp đôi và mọi bản sửa lỗi áp dụng cho A1 và A2 đều phải áp dụng cho cả hai. Với cách tiếp cận phân nhánh trong một kho lưu trữ đa năng, điều này được ẩn sau Cherry-pick. Chúng tôi coi chi phí sẽ thấp hơn vì không có sự trùng lặp. Từ quan điểm thực tế, chi phí là như nhau: bạn sẽ xây dựng, phát hành và duy trì hai cơ sở mã gần như giống hệt nhau cho đến khi bạn có thể xóa một trong số chúng. Sự khác biệt là với kho lưu trữ đơn, nỗi đau này trực tiếp và có thể nhìn thấy được. Điều này thậm chí còn tệ hơn và điều đó lại tốt.

Cuối cùng, chúng tôi đã đến được điểm thứ ba. Độ trễ phát hành. Có thể những thay đổi do A thực hiện sẽ cải thiện cuộc sống của Đội A. Quan trọng nhưng không cấp bách. Chúng ta có thể trì hoãn được không? Trong một kho lưu trữ đa năng, chúng tôi đẩy cái này để ghim hiện vật. Tất nhiên là chúng tôi đang nói điều này với Đội D. Hãy tiếp tục sử dụng phiên bản cũ cho đến khi bạn bắt kịp! Điều này khiến bạn đóng vai kẻ hèn nhát. Đội A tiếp tục làm việc với thành phần của mình, bỏ qua việc Đội D đang sử dụng một phiên bản ngày càng lỗi thời (đó là vấn đề của Đội D, họ thật ngu ngốc). Trong khi đó, Đội D lại nói không hay về thái độ bất cẩn của Đội A đối với sự ổn định của mã, nếu họ có nói về điều đó. Nhiều tháng trôi qua. Cuối cùng, Đội D quyết định xem xét khả năng cập nhật, nhưng A chỉ có nhiều thay đổi hơn. Đội A hầu như không nhớ họ đã phá vỡ D. Việc nâng cấp đau đớn hơn và mất nhiều thời gian hơn. Điều này sẽ gửi nó xuống ngăn xếp ưu tiên. Cho đến ngày chúng tôi gặp vấn đề về bảo mật ở A buộc chúng tôi phải tạo một chi nhánh. Đội A phải quay ngược thời gian, tìm thời điểm D ổn định, khắc phục sự cố ở đó và chuẩn bị sẵn sàng để phát hành. Đây là lựa chọn thực tế mà mọi người đưa ra và cho đến nay nó là lựa chọn tồi tệ nhất. Có vẻ như sẽ tốt cho cả Đội A và Đội D miễn là chúng tôi có thể phớt lờ nhau.

Trong kho lưu trữ đơn, kho lưu trữ thứ ba thực sự không phải là một lựa chọn. Bạn buộc phải giải quyết tình huống này theo một trong hai cách. Bạn cần xem chi phí của việc có hai nhánh phát hành. Tìm hiểu cách bảo vệ bản thân khỏi các bản cập nhật phá vỡ khả năng tương thích ngược. Nhưng quan trọng nhất: bạn không thể tránh khỏi một cuộc trò chuyện khó khăn.

Theo kinh nghiệm của tôi, khi các nhóm trở nên lớn mạnh, bạn không thể nghĩ đến toàn bộ hệ thống được nữa và đó là phần quan trọng nhất. Bạn phải cải thiện khả năng hiển thị sự bất hòa trong hệ thống. Bạn phải tích cực làm việc để khiến các nhóm rời xa các thành phần của họ và nhìn vào công việc của các nhóm khác và người tiêu dùng.

Có, bạn có thể tạo các công cụ cố gắng giải quyết vấn đề về kho lưu trữ đa dạng. Nhưng kinh nghiệm giảng dạy về phân phối liên tục và tự động hóa trong các doanh nghiệp lớn cho tôi biết điều này: hành vi mặc định khi không sử dụng các công cụ bổ sung là hành vi mà bạn mong đợi thấy. Hành vi mặc định của polyrepository là cô lập, đó là toàn bộ vấn đề. Hành vi mặc định của kho lưu trữ đơn là trách nhiệm chung và tính minh bạch, đó là toàn bộ vấn đề. Trong cả hai trường hợp, tôi sẽ tạo ra một công cụ có thể làm phẳng các cạnh thô. Với tư cách là người lãnh đạo, tôi sẽ chọn một kho lưu trữ đơn mỗi lần vì các công cụ cần củng cố văn hóa mà tôi muốn và văn hóa đến từ những quyết định nhỏ nhặt cũng như công việc hàng ngày của nhóm.

Chỉ những người dùng đã đăng ký mới có thể tham gia khảo sát. Đăng nhập, xin vui lòng.

Ai là người cuồng tín nhất? Người ủng hộ:

  • Monorepo

  • Rust

  • Cuộc thăm dò không chính xác/cả hai

33 người dùng bình chọn. 13 người dùng bỏ phiếu trắng.

Nguồn: www.habr.com

Thêm một lời nhận xét