Our product is a web based course managemant system. We have 10+ clients and in future we may get more clients. (Asp.net,SQL Server)
Currently if one of our customers need extra functionality or customised business logic, we will change the db schema and code to meet the needs.
(we only have one branch code base and one database schema)
To make the change wont affect each others route, we use a client flag, which defined in a web config file, thus those extra fields and biz logic only applied to a particular customer’s system.
if(ClientId = 'ABC')
{
//DO ABC Stuff
}
else
{
//Normal Route
}
One of our senior colleagues said, in this way, small company like us can save resources on supporting multiple resources.
But what I feel is, this strategy makes our code and database even harder to maintain.
Anyone there crossed similar situation? How do you handle that?
3
Parameterize as much as you can first, of course.
Avoid writing:
if(customer == 'foo') {
doBarCalculation();
}
, but rather write:
if(customer.usesBarCalculation) {
doBarCalculation();
}
Use the Strategy pattern:
customer.getCalculation().doCalculation();
Customer {
CalculationStrategy getCalculation();
}
CalculationStrategy {
doCalculation();
}
; you can use Strategy at different scales; either offer many small, simple interfaces or a few large interfaces- it is worth thinking up the scale well; large interfaces tend to provoke code duplication between implementations (and code duplication is bad), while smaller interfaces are often harder to design in advance or increase complexity.
Create a company table in the database. Every user gets associated with a company. Here is some pseudo-SQL for company-customizations for displaying dates, time-zone, fiscal offset, and contact-person:
table user:
id
company_id
... other fields ...
foreign key (company_id)
table company:
id
date_format
time_zone
fiscal_offset
contact_person
... other customization fields ...
You probably need to query the user and company for most screens in order to test for customizations. Pulling a single record from the database for a screen should take no more than 5ms.
I understand that you don’t want to introduce complexity, but having company-specific code for each client littered through your application is already complexity. Better to incorporate this officially into your database model, than to wake up one day with 100 one-off company customizations littered throughout the code. At least this puts them all in one place, and by looking at these settings on the company-edit screen, your testers can easily see what they need to think about when testing for different companies.
3
The technique described is a good stop-gab solution but does not scale well. It’s okay if you only have a few cases.
I like both Alex’s and GlenPeterson’s solutions above
-
Parameterization – make the different cases generalized and reusable. eq.: Allows international shipping (Y/N), or Break shipping tax out (Y/N).
-
Database flag attributes – to record each customer’s preference
In addition to those techniques other things to consider:
-
Separate codebases. Isolate core functionality into a single code base. Have customer customizations in a different codebase which uses the core code base. This can be difficult to set up – but allows you to freely develop both codebases independently. Having good tests on the core code base will help avoid breaking the customized code bases.
-
Separate databases (one for each client), or Namespace your database tables (one table for each client)
-
Use Separate Configuration Files for each Customer. Yaml is great for config files. This can be much lighter weight than putting all flags in the database – and allows you to easily edit it.