We've built a custom CRM for one of our clients.
Stack: asp.net MVC, SQL Server, Azure
Some of the logic / features were hardcoded specifically for this one client.

Now, more clients want to use our software but hosted separately because each client has their vision of the product and features that they want to implement.

So, we will be having completely separate servers / databases for each of our clients but the core product stays the same.

Obviously, there will be fixes/enhancements to the core product that should be applied to all clients.

How do you build and maintain such apps?

  1. How do you keep the core product up to date and update all clients when new fixes happen in the core product?
  2. How do you maintain code repository for each client?
  3. Is there any patterns that we should follow for a resilient software product?
up vote 2 down vote accepted

It is not scalable to maintain one fork of your software per client, regardless of whether you try to maintain this as multiple repositories or as multiple branches in one repository. You will be unable to apply cross-cutting changes to all your clients, except with extraordinary effort. Common cross-cutting changes are refactorings, redesigns, or security fixes.

The solution is twofold:

  1. Recognize that having an individual deployment for a client is not the same as running an individual project for that client. You can deploy with different configurations from the same codebase.

  2. Create client-specific variants through feature toggles, build-time or run-time configuration, plugin systems, and dependency injection.

Do not hardcode modifications. If you have more than one client, you will regret this. Instead, make the engine configurable so that client-specific plugins can be loaded. When you want to modify the behavior, refactor your core engine to support a plugin there, for example by introducing a new interface. Then provide an implementation for that interface as customer-specific code. When you see that multiple clients might need that functionality you can move that code into the core, but possibly disable it for clients that don't need it.

The shared core of your software is crucial for making modifications with low effort. As it evolves, make sure that it stays well-designed. This is your framework for building client-specific variants.

For the repository layout, this hinges on whether you need to give access to the development repository to clients. If not, consider keeping all work in a single monorepo. For example:

crm/
  build-tools/
  core-engine/  (contains source, tests, default assets)
  client-a/     (contains config and client-specific code, tests, assets)
  client-b/
  ...

If clients need access to their repos, then it might be better to create separate repos for the core engine and the client-specific adaptions. It may be best to treat the core engine as a library that is used by client-specific apps. However, separate repositories make it more difficult to apply backwards-incompatible changes to your core, like changing a method's signature or renaming a class.

  • This is exactly the answer I was looking for. Thank you so much. Lots to think about. – user194076 Oct 19 at 1:11
  • 1
    It may be best to treat the core engine as a library that is used by client-specific apps. I second that. However, separate repositories make it more difficult to apply backwards-incompatible changes to your core, like changing a method's signature or renaming a class. When you do not "own" the deployment or your client is sensitive to changes (re-test etc.), this is almost impossible anyway. – chromanoid Oct 22 at 20:07

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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