0

I have a standard application and in this case, it is an Accounting ASP Net MVC application. Now, I have a new client that has their own specific requirements like other fields and some custom behavior that doesn’t make sense to be included in the standard application.

The most straightforward thing that I could do is to literally copy paste the whole solution and build on top of the standard solution. However, this would mean that if I fix a bug on the standard application, I would also do it on the other solution. Same goes to a new feature implemented in the standard accounting. I would have to do it in both solution and that would be a nightmare to maintain.

Now I’m thinking what would be the best thing to do here. Just to clarify, if possible, I would also like to access the controllers and view of the standard application and sort of inherit it probably to make some client specific change.

3
  • If this is a server-side application with one instance and multiple clients, you probably want to keep it that way and have either the client control this with request parameters or the server control it with some configured client-specific behaviour.
    – Ant P
    Commented May 20, 2019 at 7:38
  • 2
    Feature toggles. Commented May 20, 2019 at 15:03
  • @AntP this would be served on multiple instance so it’s one per client. Thanks for the suggestion.
    – Lawrence
    Commented May 22, 2019 at 1:10

2 Answers 2

2

Your question is very broad, so expect only to get a broad answer.

The general strategy for solving these kinds of problems is to make the requirements customizable. This can be done by introducing run time or compile time switches, configuration files, special code which is only used for a specific customer, "plugins", and so on.

From what you wrote, in your case, a compile time switch would probably be enough to allow two different builds:

  • one build configuration produces the "standard" application

  • another build configuration produces the customized application

Inside your code, there are several ways of using such a switch. For example, a simple #ifdef CUSTOMER_XYZ might be enough for some simple cases. To avoid cluttering of your code with such statements all over the place, there are several techniques available like the strategy pattern, or grouping features together, having switches for each individual customized feature group and then making the above switch only decide about the activation of the groups.

Often, though a compile time switch may be possible, a runtime switch has still advantages, since it reduces build times and makes testing those different configurations easier. But to give you useful advice of what is the right solution for your problem, one needs to know your system and your requirements in detail (which we don't).

As a final note: often people try to abuse branches in their SCM for customization - that has proven itself to be a horrible approach. You find a lot of older questions about this idea on this site, like this one (note I would not recommend to listen to the accepted answer, but to the highest voted answer).

5
  • Only thing I would add to this is that it sounds like this is a single instance of a server application with multiple clients, in which case it probably makes sense to use request parameters or client-specific config to control the behaviour rather than compile time config.
    – Ant P
    Commented May 20, 2019 at 7:39
  • @AntP: yes, if the question would sound that way, you would be right. However, the OP had the idea of copy/pasting the whole code base, modifying the copy and thus running the result in parallel to the standard system. That does not look like "single instance" to me, more like aiming for one instance per customer.
    – Doc Brown
    Commented May 20, 2019 at 11:17
  • @DocBrown Thank you for laying out the available options. From what I can see, most of the solutions seem to require all the specific requirements to also be in the code of the standard application and only navigate through switches and other stuffs. This means that this will inherently explode the amount of code as customer increases and different specific requirement arises. This also seems to be a bit tiresome to maintain and at the same time, hard for the developers to see all these excess code that are not needed for their specific client.
    – Lawrence
    Commented May 22, 2019 at 1:15
  • This is the reason that I was interested in branching the SCM for customization per client. Removes unnecessary code from the standard and only merge standard requirements to the specific client branches. Unfortunately though, you mentioned that it is bad practice. Maybe I still haven’t seen the long term negative implication of this approach.
    – Lawrence
    Commented May 22, 2019 at 1:19
  • 1
    @Lawrence: quite the opposite - branching in your SCM is just a non-obvious way of duplicating the code for each customer, that is what will actually lead to an "explosion" of the code you will have to maintain. The only way I know against this is to design a system a way that it consists of components which are parametrized to the "right" degree, so they can be used for different customers, and the customization goes into the parameters. This design is can only be achieved when you don't hide the differences in different SCM branches, but make them explicit.
    – Doc Brown
    Commented May 22, 2019 at 5:44
0

Maybe you could use a plugin architecture.

Suppose client X has specific requirements regarding component C of the standard product. You have to replace component C by component C', which is a modified version of C. Then you could do this:

  1. Try to separate component C from the kernel of the standard product, such that the kernel only communicates with C through a well defined interface.
  2. Create component C' and let it implement the same interface as component C.
  3. Create a configuration file, which specifies which variant of component C to use. The config file for the standard product refers to component C, while client X has a config file referring to component C'.
  4. Let the kernel read this configuration file and call the right component.

Do this for all components for which the client has specific requirements.

Not the answer you're looking for? Browse other questions tagged or ask your own question.