How do you manage multiple versions of the same software for each customer?
Asked Answered
F

7

25

I have source code that is 95% the same for all customers. Some customers ask for something specific, however. How can I manage this, is it possible with VisualSVN/Subversion?

Update:

Some details about the application, it's a web ASP.NET MVC with NHibernate.

The application has several projects : the web part, the repo part (where we use NHibernate to access database) and a service project.

The service project uses the repo project and the service project is the project with business rules.

Fluidics answered 7/7, 2010 at 12:2 Comment(1)
good question. surely looking forward to hear from everyone.Kathlyn
P
11

I can think of two approaches that might work.

The first involves branching the code for each customer. Any edit you make in the main line can then be integrated into the specific customer's branch when it's needed. Similarly if something in the core product is fixed in a branch it can be merged back into the main line for subsequent propagation to the other customers' branches. While this might seem the best approach it can be hard to maintain and keeping track of which branch has which edits will get fraught.

The second, and perhaps better approach, involves refactoring your code so that the customer specific code is in a single assembly - one per customer. This is then configured, perhaps by using dependency injection, when the product is installed. This way you only have one code line and no merging between branches. Though it does rely on the customer specific code being easily separated out.

Pekoe answered 7/7, 2010 at 12:6 Comment(0)
M
5

Place the customer specific code in separate projects/assemblies. Something like the strategy pattern or plug-ins might be the way to go.

The other less attractive way (IMO) would be to create separate branches for each customer but this can quickly become hard to maintain.

Marbles answered 7/7, 2010 at 12:4 Comment(2)
First sentence, yes, but instead of plugins I prefer putting the common code in a library project. Of course, that depends entirely on the specific project though.Sendoff
I would like to suggest that ig you switch away from subversion the pain of branching mostly disappears. Nevertheless I would still try and separate the parts of the app which customers mostly want to customize. I would recommend multiple branches however.Exfoliate
O
5

The approach we have taken is:

  • Insert hooks inside the application allowing the default behaviour to be customized (e.g. when an Save action is called the first thing that happens inside is a call to OnSaveHandler).
  • The default handler does not do anything, it just returns "continueWithNormalExecution". All the handlers are in a different module than the original application (different assembly), let's call it BehaviourModule
  • On client based requests we modify this BehaviourModule by overriding the default 'don't do anything behavior'. The return code of this modified handler can be: ContinueNormalExecution, SkipNormalExecution, TerminateExecution, etc ...
  • In other cases we insert hooks based on interfaces. In the BehaviourModule we will have more handlers implementing this interface, e.g. DoStuffInterface, the BehaviourModule is parsed at load time using reflection and all handlers implementing DoStuffInterface will be register in the system. Then in the original application we will have something like: If GetDoStuffInterfaceHandler(handlerID) isnot Nothing then GetDoStuffInterfaceHandler(handlerID).DoStuff(). Defining which handlerId to use is configurable (could be through a db table, xml file ,etc).

    We end up having multiple handlers implementing DoStuffInterface with different IDs and calling them at different times.

With this approach we have:

  • the basic application with the default behaviour
  • a configurable module (assembly) the customizes the way the application works

The challenge with this approach is finding the "sweet points" - behaviours that the client might want to customize and inserting hooks there.

Hope I was clear in my description, if not... leave a comment :)

Obie answered 7/7, 2010 at 12:27 Comment(0)
K
1

If it is no big deal, i would go with appp setting and factory pattern. Or specific assemblies per customer.

But from tags it looks you want to solve it via version control. But this will put a big hit on merging etc. You will have to create branch for each customer and merge changes from trunk to them.

Kaule answered 7/7, 2010 at 12:7 Comment(0)
E
1

A useful adjunct to #ifdef ACME/#endif etc. is to define macros for ACME_ONLY(), NON_ACME(), FROBOZCO_ONLY(), NON_FROBOZCO(), etc. macros. Stuff can still get messy if new versions come into play (in which cases should the new version behave like Acme, FrobozCo, etc.) but if there's only one line of difference between the Acme and non-Acme version, this approach avoids surrounding that line by two lines of #directives.

Eiderdown answered 7/7, 2010 at 15:23 Comment(0)
H
0

The difference of 5% is that only UI based or also business logic? If UI based than you should sperate the UI layer and ship/compile the appropiate UI file with the application. If business logic, this is more complicated. Maybe branching (via SVN) could help out. But still a hassle with current development to the application, therefore not advised.

Hourly answered 7/7, 2010 at 12:10 Comment(0)
C
0

Using version control to solve this problem is probably going to cause more problems than it solves.

Suggestions by others to separate the client specific code into separate assemblies and/or use dependency injection is one way.

Another option is to use #if ... #endif.

#if CustomerA

    ... do x ...

#else

    ... do y ...

#endif

You'll need to adjust your build scripts to build the specific customer binaries. eg:

msbuild mysolution.sln /property:DefineConstants="CustomerA"

msbuild mysolution.sln /property:DefineConstants="CustomerB"
Cristincristina answered 7/7, 2010 at 13:5 Comment(2)
This solution won't scale well, what if you have 5 or 10 customers. The intent of the code would be lost in all the #ifsEnglish
Without knowing what the 5% is it is impossible to say what the right method is. Just throwing up another option.Cristincristina

© 2022 - 2024 — McMap. All rights reserved.