What is a good solution structure to allow easy customisation of a product on a per client basis?

后端 未结 2 400
春和景丽
春和景丽 2021-02-06 01:43

I am looking for some advice on how to allow easy customisation and extension of a core product on a per client basis. I know it is probably too big a question. However we reall

相关标签:
2条回答
  • 2021-02-06 02:01

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


    +1 Great question, its more of a business decision you'll have to make:

    Do I want a neat code-base where maintenance is easy and features and fixes get rolled out quickly to all our customers

    or do I want a plethora of instances of one codebase split up, each with tiny tweaks that is hard (EDIT: unless your a ALM MVP who can "unbrand" things) to merged into a trunk.


    I agree with almost everthing @Nockawa mentioned except IMHO dont substitute extending your code architecture with branches.

    Definitely use a branch/trunk strategy but as you mentioned too many branches makes it harder to quickly roll-out site wide features and hinder project-wide continuous integration. If you wish to prevent copy/pasting limit the number of branches.

    In terms of a coding solution here is what I believe you are looking for:

    • Modules/Plug-ins, Interfaces and DI is right on target!
    • Deriving custom classes off base ones (extending the DSL per customer, Assembly.Load())
    • Custom reporting solution (instead of new pages a lot of custom requests could be reports)
    • Pages with spreadsheets (hehe I know - but funnily enough it works!)

    Great examples of the module/plugin point are CMS's such as DotNetNuke or Kentico. Other idea's could be gained by looking at Facebook's add-in architecture, plugin's for audio and video editing, 3D modeling apps (like 3DMax) and games that let you build your own levels.

    The ideal solution would be a admin app that you can choose your modules (DLL's), tailor the CSS (skin), script the dB, and auto-deploy the solution upto Azure. To acheive this goal plugin's would make so much more sense, the codebase wont be split up. Also when an enhancement is done to a module - you can roll it out to all your clients.

    You could easily do small customisations such as additional properties on domain model, viewmodel and view etc with user controls, derived classes and function overrides.

    Do it really generically, say a customer says I want to a label that tally's everyone's age in the system, make a function called int SumOfField(string dBFieldName, string whereClause) and then for that customers site have a label that binds to the function. Then say another customer wants a function to count the number of product purchases by customer, you can re-use it: SumOfField("product.itemCount","CustomerID=1").

    More significant changes that require entirely new domain models and controllers etc would fit the plug-in architecture. An example might be a customer needs a second address field, you would tweak your current Address user-control to be a plug-in to any page, it would have settings to know which dB table and fields it can implement its interface to CRUD operations.

    If the functionality is customised per client in 30-40 branches maintainability will become so hard as I get the feeling you wont be able to merge them together (easily). If there is a chance this will get really big you dont want to manage 275 branches. However, if its that specialised you have to go down to the User-Control level for each client and "users cant design their own pages" then having Nockawa 's branching strategy for the front-end is perfectly reasonable.

    0 讨论(0)
  • I may not answer to this completly, but here some advices:

    1. Don't copy your code, ever, whatever the reason is.
    2. Don't rename the namespace to identify a given client version. Use the branches and continuous integration for that.
    3. Choose a branching model like the following: a root branch called "Main", then create one branch from Main per major version of your product, then one branch per client. When you develop something, target from the start in which branch you'll develop depending on what you're doing (a client specific feature will go in the client branch, a global version in the version branch or client branch if you want to prototype it at first, etc.)
    4. Try the best to rely on Work Item to track features you develop to know in which branch it's implemented to ease merge across branches.

    Targeting the right branch for you dev is the most crucial thing, you don't have to necessary define some hard rules of "what to do in which occasion", but try to be consistant.

    I've worked on a big 10 years project with more than 75 versions and what we usually did was:

    • Next major version: create a new branch from Main, dev Inside
    • Next minor version: dev in the current major branch, use Labels to mark each minor versions Inside your branch.
    • Some complex functionnal features was developped in the branch of the client that asked for it, then reversed integrated in the version branch when we succeeded in "unbranded" it.
    • Bug fixes in client branch, then reported in other branches when needed. (you have to use the Work Item for that or you'll get easily lost).

    It's my take on that, other may have different point of view, I relied a lot on the Work Item for traceability of the code, which helped a lot for the delivery and reporting of code.

    EDIT

    Ok, I add some thought/feedback about branches:

    In Software Configuration Management (SCM) you have two features to help you for versionning: branches and labels. Each one is not better nor worst than the other, it depends on what you need:

    1. A Label is used to mark a point in time, using a label, for you to later be able to go back to that point if needed.
    2. A Branch is used to "duplicate" your code to be able to work on two versions at the same time.

    So using branches only depends on what you want to be able to do. If you have to work one many different versions (say one per client) at the same time: there's no other way to deal with it than using branches.

    To limit the number of branches you have to decide what will be a new branch or what will be marked by a label for: Client Specific Versions, Major Version, Minor Version, Service Pack, etc.

    Using branches for Client versions looks to be a no brainer. Using one branch for each Major version may be the toughest choice for you to make. If you choose to use only one branch for all major versions, then you won't have the flexibility to work on different major versions at the same time, but your number of branches will be the lowest possible.

    Finally, Jemery Thompson has a good point when he says that not all your code should be client dependent, there are some libraries (typically the lowest level ones) that shouldn't be customized per client. What we do usually is using a separated branch tree (which is not per client) for Framework, cross-cutting, low level services libraries. Then reference these projects in the per client version projects.

    My advice for you is using Nuget for these libraries and create nuget package for them, as it's the best way to define versionned dependencies. Defining a Nuget package is really easy, as well as setting up a local Nuget server.

    0 讨论(0)
提交回复
热议问题