10

Tôi đang tìm một số lời khuyên về cách cho phép tùy chỉnh và mở rộng dễ dàng sản phẩm cốt lõi trên cơ sở khách hàng. Tôi biết nó có lẽ là một câu hỏi quá lớn. Tuy nhiên, chúng tôi thực sự cần phải có một số ý tưởng như thể chúng tôi có được thiết lập sai lầm này có thể gây ra vấn đề cho chúng tôi trong nhiều năm. Tôi không có nhiều kinh nghiệm trong việc tùy chỉnh và mở rộng các sản phẩm hiện có.Cấu trúc giải pháp tốt cho phép tùy chỉnh dễ dàng sản phẩm trên cơ sở khách hàng là gì?

Chúng tôi có một sản phẩm cốt lõi mà chúng tôi thường đặt riêng trên cơ sở mỗi khách hàng. Gần đây chúng tôi đã viết lại sản phẩm trong C# 4 với giao diện MVC3. Chúng tôi đã refactored và bây giờ có 3 dự án mà soạn các giải pháp: (. Namespace - projectname.domain *) -

  • Lõi dự án miền bao gồm các mô hình miền (để sử dụng bởi EF), giao diện dịch vụ miền vv (giao diện kho)
  • Dự án cơ sở hạ tầng miền (namespace -projectname.infrastructure. *) - triển khai dịch vụ miền-Ngữ cảnh EF, Triển khai kho lưu trữ, Triển khai tệp tải lên/triển khai giao diện, v.v.
  • MVC3 (namespace - projectname.web. *) -project bao gồm các bộ điều khiển, khung nhìn, CSS, nội dung, tập lệnh, vv Nó cũng có IOC (Ninject) xử lý DI cho dự án.

Giải pháp này hoạt động tốt như một sản phẩm độc lập. Vấn đề của chúng tôi là mở rộng và tùy chỉnh sản phẩm theo từng khách hàng. Khách hàng của chúng tôi thường muốn phiên bản sản phẩm cốt lõi được cung cấp cho họ rất nhanh (thường trong vòng vài ngày sau khi ký hợp đồng) với CSS và kiểu dáng có thương hiệu. Tuy nhiên 70% khách hàng sau đó muốn các tùy chỉnh thay đổi cách hoạt động của nó. Một số tùy chỉnh nhỏ như các thuộc tính bổ sung trên mô hình miền, viewmodel và chế độ xem vv. Các thuộc tính khác quan trọng hơn và yêu cầu các mô hình và bộ điều khiển miền hoàn toàn mới, v.v.

Một số tùy chỉnh có vẻ hữu ích cho tất cả khách hàng, vì vậy chúng tôi muốn định kỳ để thay đổi chúng từ việc tùy biến và thêm chúng vào lõi.

Hiện tại chúng tôi đang lưu trữ mã nguồn trong TFS. Để bắt đầu một dự án, chúng ta thường sao chép thủ công nguồn vào một dự án nhóm mới. Thay đổi không gian tên để phản ánh tên máy khách và bắt đầu tùy chỉnh các phần cơ bản và sau đó triển khai Azure. Điều này rõ ràng là kết quả trong một cơ sở mã hoàn toàn trùng lặp và tôi chắc chắn không phải là cách phù hợp để thực hiện nó. Tôi nghĩ rằng có lẽ chúng ta nên có một cái gì đó cung cấp các tính năng cốt lõi và mở rộng/ghi đè khi cần thiết. Tuy nhiên tôi thực sự không chắc chắn làm thế nào để đi về điều này.

Vì vậy, tôi đang tìm kiếm lời khuyên nào về cấu hình dự án tốt nhất mà sẽ cho phép:

  • triển khai nhanh của mã - vì vậy dễ dàng để bắt đầu một khách hàng mới để cho phép xây dựng thương hiệu/thay đổi nhỏ
  • Ngăn chặn sự cần thiết của việc sao chép và dán mã
  • Sử dụng càng nhiều DI càng tốt để giữ cho nó lỏng lẻo
  • cho phép bespoking của mã trên mỗi cơ sở khách hàng
  • Khả năng mở rộng sản phẩm cốt lõi trong một nơi duy nhất và có tất cả các khách hàng đạt được chức năng rằng nếu chúng ta có được phiên bản mới nhất của lõi và tái triển khai

Bất kỳ sự giúp đỡ/lời khuyên được đánh giá rất nhiều. Vui lòng thêm nhiều thông tin hơn mà bất kỳ ai nghĩ sẽ giúp đỡ.

+0

Sau khi thử phân nhánh cho mỗi khách hàng cho 5 dự án chúng tôi đã từ bỏ. Bây giờ chúng tôi đã viết nó như là một sản phẩm duy nhất sử dụng MEF và DI để kéo nó lại với nhau tùy thuộc vào cấu hình máy khách. Ngoài ra nó có nghĩa là chúng ta có thể triển khai nó trên một máy chủ web duy nhất và nó quy mô tốt hơn. – GraemeMiller

+0

Xem điều này trên nhiều hợp đồng thuê bao khá nhiều bao gồm tình hình http://codeofrob.com/entries/multi-tenancy-in-asp.net-mvc---ddd8-video.html – GraemeMiller

Trả lời

4

I just worried that with 30 or 40 versions (most of which aren't that different) branching was adding complexity.


+1 Great câu hỏi, nó nhiều hơn một quyết định kinh doanh, bạn sẽ phải thực hiện:

Tôi muốn có một mã cơ sở gọn gàng, nơi bảo dưỡng rất dễ dàng và tính năng và các bản sửa lỗi được được triển khai nhanh chóng cho tất cả khách hàng của chúng tôi

hoặc tôi muốn một loạt các trường hợp tách một codebase, mỗi chỉnh sửa nhỏ là khó (EDIT: trừ khi ALM MVP của bạn có thể "unbrand") hợp nhất thành một tr unk.


Tôi đồng ý với hầu hết mọi thứ @Nockawa được đề cập ngoại trừ IMHO không thay thế mở rộng kiến ​​trúc mã của bạn với các chi nhánh.

Chắc chắn sử dụng chiến lược chi nhánh/thân cây nhưng như bạn đã đề cập quá nhiều nhánh khiến cho khó khăn hơn với quickly tính năng mở rộng trang web và cản trở tích hợp liên tục trên toàn dự án. Nếu bạn muốn ngăn chặn việc sao chép/dán giới hạn số lượng chi nhánh.

Xét về một giải pháp mã hóa ở đây là những gì tôi tin rằng bạn đang tìm kiếm:

  • Modules/Plug-ins, giao diện và DI là chuột phải vào mục tiêu!
  • thừa kế các lớp tùy chỉnh tắt những cơ sở (mở rộng DSL cho mỗi khách hàng, Assembly.Load())
  • giải pháp báo cáo Tuỳ chỉnh (thay vì trang mới rất nhiều yêu cầu tùy chỉnh có thể là báo cáo)
  • trang với bảng tính (hehe tôi biết - nhưng hoạt kê đủ nó hoạt động)

ví dụ tuyệt vời của điểm mô-đun/plugin là CMS như DotNetNuke hoặc Kentico!. Ý tưởng khác có thể đạt được bằng cách nhìn vào kiến ​​trúc bổ trợ của Facebook, plugin để chỉnh sửa âm thanh và video, các ứng dụng mô hình 3D (như 3DMax) và các trò chơi cho phép bạn xây dựng các cấp độ của riêng bạn.

Các giải pháp lý tưởng sẽ là một ứng dụng quản trị mà bạn có thể chọn module của bạn (DLL), thợ may CSS (da), kịch bản dB, và tự động triển khai giải pháp tối đa Azure. Để đạt được mục tiêu của plugin này sẽ làm cho như vậy ý nghĩa hơn nhiều, các codebase sẽ không được chia ra. Ngoài ra, khi nâng cấp được thực hiện thành một mô-đun - bạn có thể triển khai nó cho tất cả các khách hàng của mình.

Bạn có thể dễ dàng thực hiện các tùy chỉnh nhỏ như các thuộc tính bổ sung trên mô hình miền, viewmodel và xem v.v. với các điều khiển người dùng, lớp dẫn xuất và ghi đè chức năng. Thực hiện nó một cách tổng quát, nói một khách hàng nói rằng tôi muốn một nhãn kiểm đếm tuổi của mọi người trong hệ thống, tạo ra một chức năng gọi là int SumOfField(string dBFieldName, string whereClause) và sau đó cho trang web khách hàng đó có một nhãn liên kết với hàm này. Quay lại đầu trang Sau đó, nói rằng một khách hàng khác muốn có một chức năng để đếm số lượng sản phẩm mua của khách hàng, bạn có thể tái sử dụng nó: SumOfField ("product.itemCount", "CustomerID = 1").

Các thay đổi quan trọng khác yêu cầu các mô hình và bộ điều khiển miền hoàn toàn mới, v.v. sẽ phù hợp với kiến ​​trúc trình cắm thêm. Một ví dụ có thể là một khách hàng cần một trường địa chỉ thứ hai, bạn sẽ điều chỉnh điều khiển địa chỉ hiện tại của bạn thành một trình cắm thêm cho bất kỳ trang nào, nó sẽ có các thiết lập để biết bảng và trường dB nào có thể thực hiện giao diện của nó cho các hoạt động CRUD .

Nếu các chức năng được tùy biến cho mỗi khách hàng trong 30-40 chi nhánh bảo trì sẽ trở nên khó khăn như vậy khi tôi nhận được cảm giác bạn sẽ không được thể kết hợp chúng lại với nhau (dễ dàng). Nếu có một cơ hội này sẽ nhận được thực sự lớn, bạn không muốn quản lý 275 chi nhánh. Tuy nhiên, nếu số của mình chuyên biệt bạn phải đi xuống cấp độ Người dùng kiểm soát cho mỗi khách hàng và "người dùng không thể thiết kế trang của riêng họ" thì có Chiến lược phân nhánh của Nockawa cho giao diện người dùng là hoàn toàn hợp lý.

+1

Câu trả lời tuyệt vời là tốt. Tôi sẽ sử dụng cả hai phương pháp tôi nghĩ. Tôi đang nhìn Orchard để lấy cảm hứng về cách ứng dụng mô-đun. Tôi sẽ viết một câu hỏi khác về điều đó và có thể đặt một tiền thưởng vào nó.Ban đầu, mặc dù tôi đang tập trung vào phân nhánh vì đây là nơi đơn giản nhất để bắt đầu vì chúng tôi chỉ có một vài khách hàng chuyển sang cơ sở mã mới. Một khi tôi thấy nơi mà các phân kỳ đang xảy ra tôi sẽ xem xét để chuyển đổi những phần đó thành các mô-đun và sau đó phân nhánh chúng. – GraemeMiller

+0

Sau 5 khách hàng với phương pháp phân nhánh chúng tôi đã từ bỏ. Đó là một cơn ác mộng. Sản phẩm cốt lõi của chúng tôi đã thay đổi liên tục và yêu cầu phải hợp nhất liên tục. Chúng tôi đang thực hiện một phương pháp mô-đun bằng cách sử dụng DI và cũng sử dụng MEF. Chúng tôi đang triển khai nó là một sản phẩm duy nhất và cho phép cấu hình thông báo những gì mô-đun/tùy chỉnh được bao gồm. Nó dễ dàng hơn nhiều. Chỉ cần một chút suy nghĩ xung quanh thiết kế. – GraemeMiller

8

tôi không thể trả lời cho điều này hoàn toàn, nhưng ở đây một số lời khuyên:

  1. Đừng sao chép mã của bạn, bao giờ hết, bất kể lý do là.
  2. Không đổi tên vùng tên để xác định phiên bản ứng dụng khách đã cho. Sử dụng các chi nhánh và tích hợp liên tục cho điều đó.
  3. Chọn một mô hình phân nhánh như sau: nhánh gốc được gọi là "Chính", sau đó tạo một chi nhánh từ Chính trên mỗi phiên bản chính của sản phẩm, sau đó một chi nhánh cho mỗi khách hàng. Khi bạn phát triển một cái gì đó, hãy nhắm mục tiêu từ nhánh mà bạn sẽ phát triển tùy thuộc vào những gì bạn đang làm (một tính năng cụ thể của khách hàng sẽ đi vào nhánh khách hàng, phiên bản toàn cầu trong nhánh phiên bản hoặc nhánh máy khách nếu bạn muốn tạo bản mẫu đầu tiên, vv)
  4. Hãy cố gắng dựa vào mục công việc để theo dõi các tính năng bạn phát triển để biết chi nhánh nào được triển khai để dễ dàng hợp nhất giữa các chi nhánh.

Nhắm mục tiêu nhánh bên phải cho bạn là điều quan trọng nhất, bạn không cần phải xác định một số quy tắc khó "làm gì trong dịp này", nhưng cố gắng nhất quán.

tôi đã làm việc trên một dự án 10 năm lớn với hơn 75 phiên bản và những gì chúng ta thường làm là:

  • phiên bản chính kế tiếp: tạo ra một chi nhánh mới từ Main, dev Bên
  • nhỏ Tiếp theo Phiên bản: dev trong nhánh chính hiện tại, sử dụng Nhãn để đánh dấu từng phiên bản nhỏ Bên trong nhánh của bạn.
  • Một số tính năng chức năng phức tạp được phát triển trong nhánh của khách hàng đã yêu cầu, sau đó đảo ngược được tích hợp trong nhánh phiên bản khi chúng tôi đã thành công trong "không gắn nhãn" nó.
  • Sửa lỗi trong chi nhánh khách hàng, sau đó được báo cáo trong các chi nhánh khác khi cần. (bạn phải sử dụng mục công việc cho điều đó hoặc bạn sẽ dễ dàng bị mất).

Tôi đảm nhận điều đó, khác có thể có quan điểm khác, tôi dựa rất nhiều vào Mục công việc để truy nguyên mã, đã giúp rất nhiều cho việc phân phối và báo cáo mã.

EDIT

Ok, tôi thêm một số suy nghĩ/phản hồi về các chi nhánh:

Trong Configuration Management Software (SCM), bạn có hai tính năng để giúp bạn cho versionning: chi nhánh và nhãn. Mỗi cái không tốt hơn cũng không tệ hơn cái kia, nó phụ thuộc vào những gì bạn cần:

  1. Nhãn được sử dụng để đánh dấu một điểm trong thời gian, sử dụng nhãn, để sau này bạn có thể quay trở lại nếu cần.
  2. Chi nhánh được sử dụng để "nhân bản" mã của bạn để có thể hoạt động trên hai phiên bản cùng một lúc.

Vì vậy, việc sử dụng các chi nhánh chỉ phụ thuộc vào những gì bạn muốn có thể làm. Nếu bạn phải làm việc với nhiều phiên bản khác nhau (nói một phiên bản cho mỗi khách hàng) cùng một lúc: không có cách nào khác để xử lý nó hơn là sử dụng các nhánh.

Để hạn chế số lượng chi nhánh bạn phải quyết định những gì sẽ là một chi nhánh mới hoặc những gì sẽ được đánh dấu bởi một nhãn cho: Khách hàng phiên bản cụ thể, chính bản, Tiểu Phiên bản, Service Pack vv

Sử dụng các chi nhánh cho các phiên bản Client có vẻ không có trí tuệ. Sử dụng một nhánh cho mỗi phiên bản Chính có thể là lựa chọn khó khăn nhất để bạn thực hiện. Nếu bạn chọn chỉ sử dụng một nhánh cho tất cả các phiên bản chính, thì bạn sẽ không có sự linh hoạt để làm việc trên các phiên bản chính khác nhau cùng một lúc, nhưng số lượng nhánh của bạn sẽ thấp nhất có thể. Cuối cùng, Jemery Thompson có một điểm tốt khi ông nói rằng không phải tất cả mã của bạn phải phụ thuộc vào khách hàng, có một số thư viện (thường là các thư viện cấp thấp nhất) không nên được tùy chỉnh cho mỗi khách hàng. Những gì chúng ta thường làm là sử dụng một cây nhánh tách biệt (không phải trên mỗi máy khách) cho các thư viện khung, cắt ngang, các dịch vụ mức thấp. Sau đó, tham khảo các dự án này trong mỗi dự án phiên bản ứng dụng khách.

Lời khuyên của tôi dành cho bạn đang sử dụng Nuget cho các thư viện này và tạo gói nuget cho chúng, vì đó là cách tốt nhất để xác định các phụ thuộc phiên bản. Việc định nghĩa một gói Nuget thực sự dễ dàng, cũng như thiết lập một máy chủ Nuget cục bộ.

+0

Cảm ơn phản hồi của bạn. Tôi có thể thấy phân nhánh có ý nghĩa. Nếu tôi không thay đổi không gian tên để xác định phiên bản máy khách thì nó sẽ làm cho nó dễ dàng hơn nhiều. Đối với một số lý do tôi chỉ hình dung một lõi mà bespoke phiên bản kế thừa từ. Nó cũng có thể được chỉ là phân nhánh và tái tích hợp các tùy chỉnh vào lõi chỉ có ý nghĩa hơn. Tôi chỉ lo lắng rằng với 30 hoặc 40 phiên bản (hầu hết trong số đó không phải là khác nhau) phân nhánh đã được thêm phức tạp. – GraemeMiller

+2

Chi nhánh không tốn nhiều chi phí trong TFS, vì vậy lo lắng duy nhất của bạn là về cách quản lý số lượng hiệu quả. – Nock

+1

+1 tóm tắt hay cho câu hỏi hay –

Các vấn đề liên quan