Khi nào nên tách một dự án trong nhiều tiểu dự án


30

Tôi muốn biết liệu có hợp lý khi phân chia dự án mà tôi đang làm trong hai kho thay vì một.

Từ những gì tôi có thể nói:

  • Frontend sẽ được viết bằng html + js
  • Phần cuối trong .net
  • Phần cuối không phụ thuộc vào frontend và frontend không phụ thuộc vào phần phụ trợ
  • Frontend sẽ sử dụng một api nghỉ ngơi được thực hiện trong phần phụ trợ.
  • Frontend có thể được lưu trữ trên bất kỳ máy chủ http tĩnh nào.

Đến bây giờ, kho lưu trữ có cấu trúc này:

nguồn gốc:

  • lối vào / *
  • phụ trợ / *

Tôi nghĩ rằng đó là một sai lầm khi giữ cả hai dự án trong cùng một kho lưu trữ. Vì cả hai dự án không có sự phụ thuộc lẫn nhau, nên chúng thuộc về các kho riêng lẻ và nếu cần một kho lưu trữ mẹ có các mô hình con.

Tôi đã nói rằng điều đó là vô nghĩa và chúng tôi sẽ không nhận được bất kỳ lợi ích nào từ việc đó.

Đây là một số lập luận của tôi:

  • Chúng tôi có hai mô-đun không phụ thuộc lẫn nhau.
  • Có lịch sử nguồn của cả hai dự án trong thời gian dài có thể làm phức tạp mọi thứ (hãy thử tìm kiếm trong lịch sử để tìm thứ gì đó ở mặt trước trong khi bạn có một nửa số cam kết hoàn toàn không liên quan đến lỗi bạn đang tìm kiếm)
  • Xung đột và hợp nhất (Điều này không nên xảy ra nhưng việc ai đó đẩy vào phụ trợ sẽ buộc nhà phát triển khác phải thay đổi phụ trợ để đẩy các thay đổi về lối vào.)
  • Một nhà phát triển có thể chỉ làm việc trên phần phụ trợ nhưng sẽ luôn phải kéo frontend hoặc ngược lại.
  • Về lâu dài, khi đó sẽ là thời gian để triển khai. Theo một cách nào đó, frontend có thể được triển khai đến nhiều máy chủ tĩnh trong khi có một máy chủ phụ trợ. Trong mọi trường hợp, mọi người sẽ buộc phải sao chép toàn bộ phần phụ trợ với nó hoặc tạo tập lệnh tùy chỉnh để đẩy đến tất cả các máy chủ chỉ lối vào hoặc xóa phần phụ trợ. Dễ dàng hơn chỉ cần đẩy / kéo chỉ lối vào hoặc phụ trợ hơn cả hai nếu chỉ cần một.
  • Đối số truy cập (Một người có thể làm việc trên cả hai dự án), Tạo repo thứ ba với mô hình con và phát triển cùng với nó. Lịch sử được giữ riêng biệt trong các mô-đun riêng lẻ và bạn luôn có thể tạo các thẻ trong đó phiên bản phụ trợ / frontend thực sự hoạt động đồng bộ với nhau. Có cả frontend / backend cùng nhau trong một repo không có nghĩa là chúng sẽ hoạt động cùng nhau. Nó chỉ hợp nhất cả lịch sử thành một repo lớn.
  • Có frontend / backend là mô hình con sẽ giúp mọi việc dễ dàng hơn nếu bạn muốn thêm freelancer vào dự án. Trong một số trường hợp, bạn không thực sự muốn cấp quyền truy cập đầy đủ vào cơ sở mã. Có một mô-đun lớn sẽ khiến mọi việc trở nên khó khăn hơn nếu bạn muốn hạn chế những gì "người ngoài" có thể nhìn thấy / chỉnh sửa.
  • Giới thiệu lỗi và sửa lỗi, tôi đã chèn một lỗi mới vào frontend. Sau đó, một người nào đó sửa một lỗi trong phần phụ trợ. Với một kho lưu trữ, việc quay trở lại trước lỗi mới cũng sẽ khôi phục phần phụ trợ có thể gây khó khăn cho việc khắc phục. Tôi phải sao chép phần phụ trợ vào một thư mục khác để phần phụ trợ hoạt động trong khi sửa lỗi ở mặt trước ... sau đó cố gắng khắc phục mọi thứ ... Có hai kho lưu trữ sẽ không gây đau đớn vì di chuyển TRÊN một repo đã thắng Không thay đổi cái khác. Và thử nghiệm đối với phiên bản phụ trợ khác nhau sẽ không gây đau đớn.

Ai đó có thể cho tôi thêm lý lẽ để thuyết phục họ hay ít nhất là cho tôi biết lý do tại sao việc phân chia dự án thành hai mô hình con là vô nghĩa (phức tạp hơn). Dự án này là mới và codebase là một vài ngày tuổi nên không quá sớm để sửa chữa.

Câu trả lời:


23

Tại công ty của tôi, chúng tôi sử dụng kho SVN riêng cho mọi thành phần của hệ thống. Tôi có thể nói với bạn rằng nó cực kỳ bực bội. Quá trình xây dựng của chúng tôi có rất nhiều lớp trừu tượng.

Chúng tôi làm điều này với Java, vì vậy chúng tôi có một quá trình xây dựng nặng nề với trình biên dịch javac, biên dịch liên kết JibX, xác thực XML, v.v.

Đối với trang web của bạn, nó có thể không phải là vấn đề lớn nếu bạn không thực sự "xây dựng nó" (chẳng hạn như vanilla PHP).

Nhược điểm để chia một sản phẩm thành nhiều kho

  1. Quản lý bản dựng - Tôi không thể chỉ kiểm tra mã, chạy tập lệnh xây dựng độc lập và có một sản phẩm có thể chạy / cài đặt / có thể triển khai. Tôi cần một hệ thống xây dựng bên ngoài đi ra nhiều repos, chạy nhiều tập lệnh xây dựng bên trong, sau đó lắp ráp các tạo phẩm.
  2. Thay đổi theo dõi - Xem ai đã thay đổi cái gì, khi nào và tại sao. Nếu một sửa lỗi trong frontend yêu cầu thay đổi phụ trợ, hiện tại có 2 đường dẫn khác nhau để tôi tham khảo lại sau.
  3. Quản trị - bạn có thực sự muốn tăng gấp đôi số tài khoản người dùng, chính sách mật khẩu, v.v. cần được quản lý không?
  4. Sáp nhập - Các tính năng mới có khả năng thay đổi rất nhiều mã. Bằng cách chia dự án của bạn thành nhiều kho lưu trữ, bạn đang nhân số lượng hợp nhất cần thiết.
  5. Tạo chi nhánh - Tương tự với việc phân nhánh, để tạo một nhánh, bây giờ bạn phải tạo một nhánh trong mỗi kho lưu trữ.
  6. Gắn thẻ - sau khi kiểm tra mã thành công, bạn muốn gắn thẻ phiên bản để phát hành. Bây giờ bạn có nhiều thẻ để tạo, một thẻ trong mỗi kho lưu trữ.
  7. Khó tìm thấy một cái gì đó - Có thể frontend / backend rất đơn giản, nhưng nó trở thành một con dốc trơn trượt. Nếu bạn chia thành đủ các mô-đun, các nhà phát triển có thể phải điều tra nơi một số đoạn mã nằm trong kiểm soát nguồn.

Trường hợp của tôi hơi cực vì sản phẩm của chúng tôi được chia thành 14 repos khác nhau và mỗi repo sau đó được chia thành 4-8 mô-đun. Nếu tôi nhớ, chúng ta có khoảng 80 hoặc một số "gói" mà tất cả cần phải được kiểm tra riêng lẻ và sau đó được lắp ráp.

Trường hợp của bạn chỉ với phụ trợ / frontend có thể ít phức tạp hơn, nhưng tôi vẫn khuyên bạn nên chống lại nó.

Các ví dụ cực đoan có thể là lý lẽ thuyết phục cho hoặc chống lại khá nhiều thứ :)

Tiêu chí tôi sẽ sử dụng để quyết định

Tôi sẽ xem xét việc chia một sản phẩm thành nhiều kho mã nguồn sau khi xem xét các yếu tố sau:

  1. Xây dựng - Các kết quả của việc xây dựng từng thành phần hợp nhất với nhau để tạo thành một sản phẩm? Giống như kết hợp các tệp. Class từ một loạt các thành phần thành một chuỗi các tệp .jar hoặc .war.
  2. Triển khai - Bạn có kết thúc với các thành phần được triển khai cùng nhau dưới dạng một đơn vị hoặc các đơn vị khác nhau đi đến các máy chủ khác nhau không? Ví dụ: tập lệnh cơ sở dữ liệu đi đến máy chủ DB của bạn, trong khi javascript đi đến máy chủ web của bạn.
  3. Đồng thay đổi - Họ có xu hướng thay đổi thường xuyên hoặc cùng nhau? Trong trường hợp của bạn, chúng có thể thay đổi riêng, nhưng vẫn thường xuyên.
  4. Tần suất phân nhánh / hợp nhất - nếu mọi người kiểm tra vào thân cây và các nhánh rất hiếm, bạn có thể thoát khỏi nó. Nếu bạn thường xuyên phân nhánh và hợp nhất, điều này có thể biến thành cơn ác mộng.
  5. Nhanh nhẹn - nếu bạn cần phát triển, thử nghiệm, phát hành và triển khai thay đổi trong thông báo của một khoảnh khắc (có thể là với SaaS), bạn có thể làm điều đó mà không mất thời gian quý báu để tung hứng các chi nhánh và repos không?

Lập luận của bạn

Tôi cũng không đồng ý với hầu hết các lập luận của bạn cho việc chia tách này. Tôi sẽ không tranh cãi tất cả vì câu trả lời dài này sẽ còn dài hơn, nhưng một số ít nổi bật:

Chúng tôi có hai mô-đun không phụ thuộc lẫn nhau.

Vô lý. Nếu bạn lấy phần phụ trợ của bạn đi, liệu frontend của bạn có hoạt động không? Đó là những gì tôi nghĩ.

Có lịch sử nguồn của cả hai dự án trong thời gian dài có thể làm phức tạp mọi thứ (hãy thử tìm kiếm trong lịch sử để tìm thứ gì đó ở mặt trước trong khi bạn có một nửa số cam kết hoàn toàn không liên quan đến lỗi bạn đang tìm kiếm)

Nếu gốc dự án của bạn được chia thành frontend / và backend /, thì bạn có thể xem xét lịch sử của các cấu trúc phân cấp đó một cách độc lập.

Xung đột và hợp nhất (Điều này không nên xảy ra nhưng việc có ai đó đẩy vào phụ trợ sẽ buộc nhà phát triển khác phải thay đổi phụ trợ để đẩy các thay đổi về lối vào.) Một nhà phát triển có thể chỉ làm việc trên phụ trợ nhưng sẽ luôn phải kéo phụ trợ hoặc theo cách khác xung quanh.

Chia dự án của bạn thành các repos khác nhau không giải quyết được điều này. Xung đột frontend và xung đột phụ trợ vẫn khiến bạn có 2 xung đột, cho dù đó là 1 kho lưu trữ 2 lần xung đột hay 2 kho lưu trữ 1 lần xung đột. Ai đó vẫn cần phải giải quyết chúng.

Nếu mối quan tâm là 2 repos có nghĩa là nhà phát triển frontend có thể hợp nhất mã frontend trong khi nhà phát triển phụ trợ hợp nhất mã phụ trợ, bạn vẫn có thể làm điều đó với một kho lưu trữ duy nhất bằng SVN. SVN có thể hợp nhất ở mọi cấp độ. Có lẽ đó là một giới hạn git hoặc đồng bóng (bạn đã gắn thẻ cả hai, vì vậy không chắc chắn bạn sử dụng SCM gì)?

Mặt khác

Với tất cả những gì đã nói, tôi đã thấy các trường hợp chia một dự án thành nhiều mô-đun hoặc kho lưu trữ hoạt động. Tôi thậm chí đã ủng hộ nó một lần cho một dự án cụ thể nơi chúng tôi tích hợp Solr vào sản phẩm của chúng tôi. Solr tất nhiên chạy trên các máy chủ riêng biệt, chỉ thay đổi khi bộ thay đổi có liên quan đến tìm kiếm (sản phẩm của chúng tôi thực hiện nhiều hơn tìm kiếm), có quy trình xây dựng riêng và không có tạo tác mã hoặc tạo tác phẩm xây dựng được chia sẻ.


Điều độ trong tất cả mọi thứ, như mẹ tôi thường nói ...
William Payne

Theo văn bản của tôi, tôi đang viết frontend mà không có phụ trợ. Tôi mô phỏng phụ trợ với các tệp json và thậm chí tôi có thể mô phỏng hoàn toàn với indexedDB trong trình duyệt. Vì vậy, yeah phụ trợ chỉ là một máy chủ phục vụ json. Nó có thể được thay thế bởi bất cứ điều gì miễn là dữ liệu nhận được tuân thủ API. Cả hai dự án sử dụng hệ thống xây dựng khác nhau. Nói tóm lại, nó khá giống như có một trang web và một ứng dụng Android dành cho thiết bị di động. Thêm ứng dụng di động bên trong kho lưu trữ máy chủ web.
Loïc Faure-Lacroix

Ngoài ra, nếu nó không rõ ràng, giao diện phụ trợ và giao diện không phải là giao diện người dùng / quản trị viên. Nhưng frontend chỉ là một giao diện ajax và phụ trợ phục vụ json. Người dùng và vai trò được xử lý khác nhau và giao diện quản trị sẽ ở phía trước. Ý tưởng là giữ cho cả hai phần bị cô lập và ngăn html tạo javascript để tải html tạo máy chủ. Máy chủ chỉ nên phục vụ json hoặc xml.
Loïc Faure-Lacroix

1
Sau đó, bạn không có vấn đề xây dựng hoặc triển khai, vì vậy có thể ổn. Nhưng một lần nữa, nếu bạn thực hiện một thay đổi lớn, bạn có thể cần thay đổi API, điều này ảnh hưởng đến cả frontend và backend và do đó bạn sẽ phân nhánh hai lần, hợp nhất hai lần, gắn thẻ hai lần, v.v ... Nhưng miễn là nó chỉ giữ lại hai lần và không Sẽ biến thành 3 ... 4 ... 12 ... 20, có lẽ không phải là ý kiến ​​tồi.
Brandon

Ngay cả khi API thay đổi, với phiên bản phù hợp, có thể tạo các phiên bản nhánh cho mỗi giao diện hỗ trợ phiên bản API. Phần cuối phải có một số khả năng tương thích "lạc hậu" và giữ cho API cũ hoạt động càng lâu càng tốt.
Loïc Faure-Lacroix

3

Một số đối số của bạn là hợp lệ và một số thì không.

Chúng tôi có hai mô-đun không phụ thuộc lẫn nhau.

Điều đó thực sự không hoàn toàn đúng. Để có thể giao tiếp, cả front-end và back-end cần phải có một giao diện chung (mô tả). Điều đó làm cho nó trở thành một đối số yếu có lợi cho việc có cả hai trong một kho lưu trữ chung. Nhưng chỉ là một lập luận yếu vì nó không tạo ra nhiều sự khác biệt.

Có lịch sử nguồn của cả hai dự án trong thời gian dài có thể làm phức tạp mọi thứ (hãy thử tìm kiếm trong lịch sử để tìm thứ gì đó ở mặt trước trong khi bạn có một nửa số cam kết hoàn toàn không liên quan đến lỗi bạn đang tìm kiếm)

Đây là một lập luận không có thật. Nếu bạn muốn tìm kiếm cách khắc phục một lỗi cụ thể, bạn hãy tìm trong trình theo dõi lỗi mà cam kết có chứa bản sửa lỗi. Và nếu bạn muốn biết một đoạn mã cụ thể đã phát triển như thế nào, bạn hãy nhìn vào lịch sử của một tệp duy nhất (hoặc nhiều nhất là một số ít). Trong cả hai trường hợp, có các tệp khác, có thể từ các mô-đun khác, trong kho lưu trữ không nên làm phức tạp mọi thứ theo bất kỳ cách nào.

Xung đột và hợp nhất (Điều này không nên xảy ra nhưng việc ai đó đẩy vào phụ trợ sẽ buộc nhà phát triển khác phải thay đổi phụ trợ để đẩy các thay đổi về lối vào.)

Đây là một lập luận không có thật. Tôi không biết về bất kỳ VCS (một nửa nào) mà bạn cần đồng bộ hóa toàn bộ kho lưu trữ trước khi bạn có thể cam kết / thúc đẩy các thay đổi của mình. Nhiều nhất bạn cần đồng bộ hóa các thư mục chứa các tệp đã thay đổi (và thường chỉ chính các tệp đó).

Một nhà phát triển có thể chỉ làm việc trên phần phụ trợ nhưng sẽ luôn phải kéo phần phụ trợ hoặc ngược lại.

Đây là đối số không có thật như trước đây.

Về lâu dài, khi đó sẽ là thời gian để triển khai. Theo một cách nào đó, frontend có thể được triển khai đến nhiều máy chủ tĩnh trong khi có một máy chủ phụ trợ. Trong mọi trường hợp, mọi người sẽ buộc phải sao chép toàn bộ phần phụ trợ với nó hoặc tạo tập lệnh tùy chỉnh để đẩy đến tất cả các máy chủ chỉ lối vào hoặc xóa phần phụ trợ. Dễ dàng hơn chỉ cần đẩy / kéo chỉ lối vào hoặc phụ trợ hơn cả hai nếu chỉ cần một.

Tùy thuộc vào cách mọi người hình dung rằng việc triển khai sẽ được thực hiện, đây có thể là một đối số hợp lệ. Nếu việc triển khai sẽ được thực hiện bằng cách giải nén tệp zip / tarbal trên máy chủ, thì việc kho lưu trữ của bạn được tổ chức như thế nào không quan trọng. Nếu việc triển khai sẽ được thực hiện bằng cách kiểm tra (một phần) kho lưu trữ trên máy chủ, thì có thể nên sử dụng các kho riêng cho các mô-đun được triển khai riêng.

Đối số truy cập (Một người có thể làm việc trên cả hai dự án), Tạo repo thứ ba với mô hình con và phát triển cùng với nó. Lịch sử được giữ riêng biệt trong các mô-đun riêng lẻ và bạn luôn có thể tạo các thẻ trong đó phiên bản phụ trợ / frontend thực sự hoạt động đồng bộ với nhau. Có cả frontend / backend cùng nhau trong một repo không có nghĩa là chúng sẽ hoạt động cùng nhau. Nó chỉ hợp nhất cả lịch sử thành một repo lớn.

Đây là một đối số hợp lệ, nhưng nó không mạnh đến thế.

Có frontend / backend là mô hình con sẽ giúp mọi việc dễ dàng hơn nếu bạn muốn thêm freelancer vào dự án. Trong một số trường hợp, bạn không thực sự muốn cấp quyền truy cập đầy đủ vào cơ sở mã. Có một mô-đun lớn sẽ khiến mọi việc trở nên khó khăn hơn nếu bạn muốn hạn chế những gì "người ngoài" có thể nhìn thấy / chỉnh sửa.

Đây là một đối số hợp lệ.

Giới thiệu lỗi và sửa lỗi, tôi đã chèn một lỗi mới vào frontend. Sau đó, một người nào đó sửa một lỗi trong phần phụ trợ. Với một kho lưu trữ, việc quay trở lại trước lỗi mới cũng sẽ khôi phục phần phụ trợ có thể gây khó khăn cho việc khắc phục.

Đó là một đối số không có thật, bởi vì điều đó có nghĩa là sau hai lỗi với một mô-đun, bạn sẽ không thể hoàn nguyên cái đầu tiên. Bất kỳ VCS nửa vời nào cũng sẽ cho phép bạn quay lại bất kỳ cam kết cũ nào (mặc dù điều đó thường có nghĩa là bạn thực hiện một cam kết mới đảo ngược những thay đổi đó, đôi khi ngay cả đối với đầu trang).

Tôi phải sao chép phần phụ trợ vào một thư mục khác để phần phụ trợ hoạt động trong khi sửa lỗi ở mặt trước ... sau đó cố gắng khắc phục mọi thứ ... Có hai kho lưu trữ sẽ không gây đau đớn vì di chuyển TRÊN một repo đã thắng Không thay đổi cái khác. Và thử nghiệm đối với phiên bản phụ trợ khác nhau sẽ không gây đau đớn.

Đây thực sự là một lập luận khá tốt. Có hai kho lưu trữ giúp dễ dàng kiểm tra các tình huống trong đó mặt trước và mặt sau được triển khai có thể trở nên (hơi) không đồng bộ.


Thành thật mà nói, hầu hết các đối số không có thật có thể được giải quyết bằng các nhánh. Chi nhánh cho frontend và chi nhánh cho phụ trợ. Thầy cho đồng bộ. Nhưng theo một cách nào đó, xử lý nhánh như thế đang khiến mọi thứ trở nên phức tạp hơn là có hai repos.
Loïc Faure-Lacroix

1
@Sybiam: Trên thực tế, chúng là các đối số không có thật, vì chúng không làm nổi bật một vấn đề có thể tồn tại khi sử dụng một kho lưu trữ duy nhất, ngay cả khi tất cả các thay đổi chỉ được thực hiện cho trung kế / chính.
Bart van Ingen Schenau

Tôi nghĩ rằng những lời phê bình của bạn là hợp lệ. Tôi chỉ không nghĩ rằng đó là điểm của câu hỏi.
sylvanaar

2

Bài này hơi cũ nhưng tôi muốn đóng góp. Trong khi back-end của bạn không thực sự biết về front-end, thì front-end cần có các yêu cầu khớp với API của back-end. Nếu bạn coi back-end của mình là API REST, thì bạn có thể xác định tệp giao diện, chẳng hạn như giao diện YAML vênh vang. Bây giờ thực sự có 3 dự án, mà bạn có thể chia thành các repos khác nhau khi bạn thấy phù hợp:

  • Định nghĩa API
  • Back-end
  • Mặt trước

Định nghĩa API là một phụ thuộc trong hai dự án khác, giả sử bạn đang sử dụng maven làm công cụ tiêm phụ thuộc. Sau đó, nó phụ thuộc vào mức độ nghiêm ngặt mà bạn muốn làm phiên bản. Bạn có thể nâng cấp phiên bản của dự án định nghĩa API mỗi khi bạn thực hiện thay đổi để đảm bảo các dự án luôn ở trạng thái tương thích nhưng yêu cầu nhiều chi phí hơn hoặc bạn có thể sử dụng một cái gì đó như SNAPSHOTS trong maven và chỉ thực hiện phiên bản một khi bạn hài lòng với giao diện ít chi phí hơn nhưng bạn thường có thể không tương thích. Nhưng miễn là bạn thực thi định nghĩa API ở mặt trước và mặt sau của mình, bạn sẽ ổn khi chia các dự án thành các kho khác nhau.

Những vấn đề này là nhiều hơn về quản lý phụ thuộc. Ngay cả khi các dự án không được phân tách và nằm trong cùng một kho lưu trữ, thì trang web vẫn dễ dàng được đặt ở trạng thái mà giao diện người dùng và mặt sau không đồng bộ. Thực sự cách duy nhất để ngăn chặn điều này là thực sự xác định hợp đồng giữa hai bên, nhưng bạn muốn thực hiện nó theo cách không kết hợp việc triển khai mặt trước và mặt sau, giống như bạn sẽ mã hóa giao diện thay thế của một triển khai trong lập trình OO.

Ngoài ra, để xử lý trước những lời chỉ trích rằng điều này tạo ra chi phí duy trì tập tin giao diện này, ví dụ, swagger thậm chí có thể tạo ra các cuống mã cho các ngôn ngữ lập trình và khung khác nhau như JAX-RS. Vì vậy, bạn có thể sản xuất một giao diện trong công nghệ bạn đã chọn và sau đó thực hiện giao diện này. Nó cũng thêm tài liệu rất hay vào back-end của bạn, giúp các nhà phát triển front-end dễ dàng thực hiện công việc của họ hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.