Cách hiệu quả nhất để chia sẻ mã giữa các ứng dụng .NET là gì?


13

Trong công việc của chúng tôi, chúng tôi có một số ứng dụng .net khác nhau có chung nhiều chức năng cơ bản. Chúng tôi đã xây dựng các ứng dụng này bằng kiến ​​trúc n tầng sạch, nhưng chúng tôi đã đạt được thời điểm đó khi chúng tôi nhận ra rằng chúng tôi đã triển khai lại các chức năng tương tự nhiều lần khác nhau. Rõ ràng điều này vi phạm DRY, và chúng tôi muốn sửa nó. Chúng tôi đã sử dụng Nuget để thành công cho mã keo thông thường (kết nối IoC, ghi nhật ký, cài đặt), nhưng chúng tôi cũng muốn chia sẻ dữ liệu và lớp kinh doanh giữa tất cả các ứng dụng của mình. Ý tưởng là UI sẽ chỉ xử lý các phần của lớp nghiệp vụ mà nó thực sự cần.

Điều này có vẻ như là một vấn đề đơn giản lúc đầu, nhưng sự phát triển đang diễn ra có thể cung cấp một số cạm bẫy và chúng tôi không chắc chắn nên tiến hành như thế nào. Giả sử chúng ta tạo một lớp kinh doanh để thống trị tất cả. Để cho ngắn gọn, tôi sẽ gọi nó là "Foundation." Chúng tôi chuyển các ứng dụng của mình để sử dụng Foundation và mọi thứ đang hoạt động rất tốt. Nền tảng được phân phối cho các lớp UI nhẹ thông qua nuget và chúng tôi đang tìm kiếm tốt. Nhưng sau đó chúng tôi bắt đầu thêm các tính năng cho các ứng dụng của mình và chúng tôi gặp rắc rối.

Giả sử chúng tôi đang làm việc trên Dự án A và chúng tôi thêm một tính năng mới yêu cầu thay đổi đối với Foundation. Chúng tôi thực hiện các thay đổi đối với nền tảng (Foundation-A) và đẩy chúng ra nguồn cấp dữ liệu nuget dưới dạng gói không ổn định. Dự án A có gói nuget mới nhất, và tất cả đều tốt. Trong khi đó, một nhà phát triển khác đang làm việc trên Dự án B. Anh ta nhận được Quỹ mới nhất từ ​​kiểm soát nguồn, nhưng lấy nó từ một chi nhánh ổn định, để nó không có các thay đổi của Dự án A trong đó. Anh ấy thực hiện các thay đổi và tạo ra Foundation-B. Và tất cả đều tốt. Nhưng sau đó chúng tôi phát hiện ra rằng chức năng triển khai Foundation-A và Foundation-B thực sự có thể chia sẻ mã, vì vậy chúng tôi kết hợp chúng. Trong khi đó Foundation-C đang trôi nổi ngoài kia với những thay đổi của chính nó. Cuối cùng, Foundation-B đã sẵn sàng để sản xuất, vì vậy chúng tôi đẩy nó ra. Nhưng sau đó chúng ta cần cập nhật Sản xuất A, B,

Điều này có vẻ như có thể hoạt động, nhưng chúng tôi lo lắng về việc làm việc với các lược đồ cơ sở dữ liệu khác nhau và giữ mọi thứ được đồng bộ hóa giữa các nhánh khác nhau của kho lưu trữ Foundation cũng như các kho lưu trữ của Dự án A, B và C. Có vẻ như nó có thể sẽ mất rất nhiều công việc thủ công, điều này mở ra khả năng xảy ra lỗi. Tôi muốn điều này càng tự động càng tốt.

Đây là ngăn xếp chúng tôi đang sử dụng: C #, TFS với Tích hợp liên tục, Nuget. Các ứng dụng của chúng tôi là tất cả các loại ứng dụng ASP.NET. Chúng tôi sẵn sàng xem xét các SCM khác nhau nếu điều đó sẽ giúp mọi việc dễ dàng hơn.

Tôi đang tìm cách để giữ cho Nuget lành mạnh với các nhánh mã nguồn khác nhau của chúng tôi. Chúng tôi không muốn vô tình đẩy mã phát triển vào sản xuất vì chúng tôi tham chiếu Gói Nuget sai.


Ngoài ra, nếu đây không phải là một diễn đàn tốt cho một cuộc thảo luận như thế này, ai đó có thể đề xuất một diễn đàn tốt hơn không?
Josh

Câu trả lời:


8

Chúng tôi thực hiện các thay đổi đối với nền tảng (Foundation-A) và đẩy chúng ra nguồn cấp dữ liệu nuget dưới dạng gói không ổn định.

Đây là nơi vấn đề của bạn bắt đầu ... Đừng làm điều đó.

Mọi thay đổi đối với Foundation v1.0 vốn dĩ phải có giá trị đối với tất cả người tiêu dùng Foundation, nếu không thì nó không thuộc về Foundation. Vì vậy, khi tạo gói nuget, hãy thực hiện dưới dạng phiên bản chính thức, ổn định của Foundation (tức là v1.1) hoặc không làm gì cả.

Dự án B nên xây dựng các cải tiến Foundation như bình thường, nhưng (theo kiểu quản lý nguồn tốt) nên hợp nhất trong các thay đổi trung kế (v1.1) trước khi đẩy Foundation ổn định (v1.2) sang nuget.

Các dự án khác có thể sử dụng các cải tiến Foundation có thể nâng cấp các tham chiếu nuget của chúng khi thích hợp hoặc gắn bó với các phiên bản cũ hơn nếu cần.

Tôi đồng ý với @Giedrius ; đối với tôi, đây dường như là một vấn đề kiểm soát / phân nhánh nguồn theo nghĩa là nếu việc phân nhánh / sáp nhập Foundation được xử lý đúng cách, các vấn đề quản lý gói sẽ trở thành vấn đề.


Vâng, điều này có ý nghĩa. Vấn đề là trong ứng dụng thực tế. Khi bạn cập nhật lên Foundation cho v1.1, bạn muốn sử dụng những thay đổi đó trong Dự án B khi bạn đang phát triển. Nếu cách bạn đã chia sẻ mã đó thông qua nuget, thì các tùy chọn của bạn là: 1) Xuất bản gói nuget mới hoặc 2) Sao chép thủ công dll xung quanh. Cả hai điều này có vẻ như là sự lựa chọn tốt.
Josh

Một số điều này có thể được giảm thiểu bằng cách có một bộ kiểm tra hiệu quả, nhưng vẫn sẽ được qua lại khi bạn thêm các tính năng.
Josh

@Josh Có, các bản cập nhật cho Foundation phải hoàn chỉnh và có thể kiểm tra độc lập với cách Dự án B sẽ sử dụng chúng (vì chúng sẽ vào thư viện dùng chung), vì vậy, 'xuất bản gói nuget mới' là cách tự nhiên. Không nhập và sử dụng Foundation v. Tiếp theo trong Dự án B cho đến khi đó là gói ổn định trong nuget. Nó đòi hỏi một chút kỷ luật, nhưng nó tốt hơn rất nhiều so với mớ hỗn độn khi làm việc khác.
Eric King

1
Tôi hoàn toàn hiểu những gì bạn đang nói, nhưng tôi không nghĩ nó rất thực tế. Khi bạn phát triển một tính năng, ngay cả khi bạn đã kiểm tra đầy đủ logic nghiệp vụ và lớp truy cập dữ liệu, sẽ có sửa đổi trước khi được đưa vào sản xuất. Có thể bạn nhận ra rằng bạn cần thêm một tài sản khác vào logic kinh doanh hoặc chủ sở hữu sản phẩm quay lại với các thay đổi hoặc làm rõ. Có thể một số giả định đơn giản hóa của bạn đã sai. Đây là những điều xảy ra tất cả thời gian. Nếu bạn bị giới hạn trong việc khóa phát hành logic cơ sở của mình, thì có vẻ như rất hạn chế.
Josh

2
Như chúng tôi đã làm điều này trong một vài tháng, đây về cơ bản là những gì chúng tôi giải quyết. Tôi nghĩ rằng tôi đã quá lo lắng về việc có một quy trình chính thức. Khi chúng tôi bắt đầu thực sự làm việc với nó, mọi thứ kết thúc thực sự suôn sẻ. Cảm ơn vì đầu vào của bạn.
Josh

4

Tái cấu trúc mã trùng lặp của bạn thành các hàm có thể áp dụng theo cách trừu tượng hơn và đưa chúng vào thư viện hoặc khung riêng của chúng. Làm cho chúng liên kết lỏng lẻo và bất khả tri về kiến ​​trúc, và bạn không bao giờ nên có bất kỳ vấn đề nào. Nếu bạn cần nguồn cảm hứng, hãy nghiên cứu cách .NET framework trừu tượng hóa các khái niệm bằng cách sử dụng những thứ như giao diện, khái quát và các mẫu phần mềm như Dispose().

Ngoài ra, hãy nhớ rằng không phải tất cả các mã trùng lặp là thực sự trùng lặp; một số trong đó là mã keo hoặc mã cần thiết để duy trì kiến ​​trúc, vì vậy đừng ám ảnh vì quá KHÔ.


Có lẽ tôi đã không rõ ràng như tôi có thể trong câu hỏi của tôi. Đây là về những gì tiếp theo. Bạn đã thực hiện tất cả điều đó và bây giờ bạn cần chia sẻ mã hiệu quả giữa các dự án khác nhau của mình. Ai đó nói rằng "chỉ sử dụng nuget cho điều đó" và nghe có vẻ tuyệt vời cho đến khi bạn đi vào chi tiết và gặp vấn đề - như cách đồng bộ hóa các thay đổi khác nhau từ các chi nhánh và ứng dụng khác nhau.
Josh

Chà, tôi đồng ý với Eric King. Mã nền tảng nên được đẩy như một phiên bản ổn định, không phải là một phiên bản không ổn định. Chìa khóa đang duy trì API ổn định: nếu bạn biết chữ ký của các phương thức nền tảng của bạn sẽ không thay đổi, bạn có thể đẩy các phương thức sang Foundation một cách an toàn và sau đó cấu trúc lại chúng mà không phá vỡ bất cứ điều gì.
Robert Harvey

4

Tái sử dụng mã

Đã có một số cách tiếp cận để tái sử dụng mã đã được ưa chuộng trong những năm qua. Mỗi cách tiếp cận đều có vị trí của nó và quan trọng hơn là các vấn đề của nó , nhưng các cách khả thi để sử dụng lại mã trong .NET là:

  1. Thư viện chung. Mã cần thiết ở nhiều nơi được đưa vào một thư viện chung và tất cả các phần khác của cơ sở mã sau đó có một tham chiếu đến mã này. Nhược điểm nguyên tắc là bạn kết thúc với phần lớn dự án của bạn tùy thuộc vào thư viện này chứa rất nhiều chức năng không liên quan. Đây là một ý tưởng tồi từ khía cạnh đảm bảo chất lượng.

  2. Mã nguồn chung. Mã cần thiết ở nhiều nơi được viết một lần và được đặt trong tệp nguồn trong cấu trúc thư mục chung. Tất cả các dự án cần mã này sau đó bao gồm tệp này là một trong các tệp nguồn của chúng. Điều này cung cấp việc tái sử dụng mã và những lợi thế của việc viết một lần, sử dụng nhiều. Tuy nhiên. Nhược điểm của nó là có thể có các phần khác nhau của dự án được biên dịch với các phiên bản khác nhau của mã này - có thể đưa ra một số khiếm khuyết tinh vi có thể rất khó phát hiện và xác định bằng cách đảm bảo chất lượng.

  3. Dịch vụ. Mã chung được triển khai như một dịch vụ mà các khía cạnh khác có thể truy cập. Điều này có lợi thế là sẽ có một dịch vụ duy nhất được triển khai và tránh phụ thuộc. Tuy nhiên, nó sẽ giới thiệu độ trễ và thất bại. Cách tiếp cận này hoạt động tốt trong các sản phẩm phân tán lớn, nơi khả năng sẵn sàng cao và khả năng chịu lỗi đã được hiểu và quản lý.

Quản lý NuGET

Ở đây bạn có một vấn đề thú vị hơn nhiều. Quản lý nhiều cấu hình. Lời khuyên của tôi ở đây là không quản lý một cơ sở khách hàng đa dạng với các phiên bản mã khác nhau, mà bằng các tệp cấu hình. Có ít nhất 3 lớp dữ liệu cấu hình để quản lý. Cấu hình sản phẩm cơ sở (nội bộ) mà khách hàng không bao giờ nhìn thấy. Các tùy chọn cấu hình mặc định mà khách hàng của bạn có thể thay đổi và lớp tùy chọn cấu hình cuối cùng mà khách hàng của bạn đã thay đổi. Bằng cách tách các lớp khác nhau này, bạn sẽ có thể đưa ra các bản nâng cấp mà không phá hủy cấu hình khách hàng của bạn.


1

Tôi nghĩ vấn đề không nằm ở nuget / kiểm soát nguồn / phân nhánh, mà là ở những gì trượt vào mã keo.

Robert có câu trả lời hay, chỉ để xem toàn bộ bức tranh, tôi khuyên bạn nên suy nghĩ về những phụ thuộc mà các tiện ích chung này sẽ mang lại cho mỗi dự án:

http://ayende.com/blog/3986/let-us-burn-all-those-pesky-util-common-lologists http://blog.jordanterrell.com/post/CommonUtility-Lologists-Dead.aspx

Cách tốt nhất để tránh địa ngục bạn đang có là mở mã keo của bạn. Theo cách đó, bạn sẽ bắt đầu quan tâm, rằng sẽ không có logic kinh doanh nào được công khai, do đó, không có sự phụ thuộc dự án cụ thể nào sẽ rơi vào mã keo, rằng nó sẽ đủ trừu tượng để được sử dụng lại bởi bất kỳ ai, ngay cả bên ngoài công ty của bạn - và nếu việc dán đó mã sẽ đủ tốt - bạn cũng sẽ nhận được đầu vào của cộng đồng.


Tôi không nói về việc quản lý mã keo. Chúng tôi đã có một giải pháp cho điều đó và nó hoạt động tốt. Tôi đang nói về việc chia sẻ logic kinh doanh. Ví dụ, các ứng dụng của chúng tôi xử lý các tổ chức và mọi người. Vì vậy, chúng tôi cần phải tạo một người và có một loạt các quy tắc kinh doanh liên quan đến cách tạo ra một người. Thay vì tạo ra một vài lần, chúng tôi muốn có một gói xử lý mọi thứ từ việc xây dựng đối tượng để duy trì nó mà chúng tôi chia sẻ giữa các dự án khác nhau cần tạo người.
Josh

0

Giải pháp rất đơn giản: tạo dự án riêng cho nó và quản lý nó như một thứ riêng biệt: đó là yêu cầu riêng, thử nghiệm, quy ước, tài liệu, kế hoạch, con người, v.v. Bằng cách này, bạn đảm bảo rằng chất lượng vẫn cao và có thể thay đổi phá vỡ đánh giá đầu tiên trước khi họ tạo ra một vấn đề.

Hoặc thậm chí tốt hơn: làm cho nó "nguồn mở" trong tổ chức của bạn. Vì vậy, bất cứ ai cũng có thể thay đổi mã, nhưng chỉ một vài người được chọn sẽ có toàn quyền cam kết. Và những người đó sẽ chịu trách nhiệm đảm bảo chất lượng và tính năng chính xác.

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.