I want my eCommerce application Suteki Shop to be able to flexibly meet the requirements of any customer (within reason). How can we have a single product but enable our customers to have diverse implementations. I think the solution depends on the level of diversity and the number of customers. The right solution for a product with thousands of customers with little customisation is different from a solution for a handful of customers with very diverse requirements.
There are several axis of change to consider:
- Codebase. Do I have one codebase, or do I maintain a separate codebase for each customer?
- Application instance. Do I have one application instance to service all my customers, or does each customer have a separate one?
- Database schemas. Do I have one database schema, or do I have a different schema for each customer?
- Database instances. Do I have one database instance or separate ones for each customer?
Lots of customers, little customisation
Lets consider the two extremes. First, say I've got a product that I expect to sell to thousands of customers. My business model is premised on selling a cheap service to very many people. It's worth my while not to allow too much customisation because the effort to supply that simply wouldn't be worth it. If someone wants something significantly different from my thousands of other customers, I'll just tell them to look elsewhere. In this case I'd have a single code base, application instance, database schema and database. Effectively a single application will service all my customers.
In this case the main technical challenge will making sure that each user's data is keyed properly so they perceive it as a single application servicing their needs only. It would be a major failure if one customer could see another's data. Think of an on-line email service such as hotmail. Sometimes we want to allow customers to see each other's data, think Facebook, but that interaction needs to be tightly controlled.
Scope for providing diverging customer requirements is very limited in this case. Effectively every customer gets exactly the same features and all you can do is allow them to maybe switch features off and on. The cost of developing a customisable experience with such a setup is high.
The great thing about this single application approach is its scalability. Each extra customer requires no extra development effort. It's the way billion dollar on-line businesses are made.
Few customers, Deep customisation
At the other extreme we might be selling an application to just a handful of clients. Each client has diverse requirements and is willing to spend the money to have them implemented. Do we really have a single application in this case or are we instead delivering bespoke solutions? Here the answer might be to have a common application library but separate codebases for each client. It would then follow that each client needs separate database schemas, databases and application instances.
In this scheme, the cost of developing divergent features is no greater than developing them for bespoke software. The pain comes in deciding what to code in your shared library and what to code in your bespoke applications. Getting that wrong can mean repeating the same code for each customer and seriously violating the DRY principle.
Because we are effectively building bespoke software, each extra customer requires development effort. As our business grows we have to hire more and more developers to service our customers. The problem is that development teams don't scale well and there are high organisational costs involved. Our profit on each instance of our product is likely to decline rather than rise. For this reason there's a limit to the size a company based on this development model can grow to.
So which one is Suteki Shop?
Suteki Shop only has one customer at present. So it's a single bespoke application based on that customer's requirements. In the new year I hope to add a second customer so I'll have to start making decisions about my multi-tenancy strategy. I want to make the right decisions now so that I can provision my third, fourth, tenth or one-hundredth as easily as possible. My customers are likely to have divergent requirements within the constraints of an eCommerce system. The easiest thing for my second customer would be to branch the code, make any changes they want and deploy a second database (with possibly a customised schema) and application instance. But that strategy will not scale to one-hundred customers. Let's make the assumption that I want to service maybe a hundred customers easily, but I'm unlikely to have more than a thousand. Consider the four axis of change above...
- Codebase. I really don't want to fork my codebase. I'm a firm believer in keeping things DRY. There will be no branching.
- Application Instance. This is less clear cut. There are obvious benefits from maintaining separate application instances for each customer and this was my initial intention. I can configure and deploy them as required. However, after looking at techniques for provisioning multiple divergent customers on one instance, I believe that the costs can be minimal. Having one instance is much easier to administer and monitor, so I am changing my mind on this point and will aim for one application instance. One application instance can of course be duplicated to scale over a server farm. I think this approach could scale to thousands of customers.
- Database schemas. In the old days, I would have said that having multiple schemas would cause intense scale pain, but that is changing with modern tools. Using an ORM allows us to defer schema creation until deployment. If I can automate the management of schema creation and change, then having multiple versions is less of a problem. Of course that all depends on having multiple databases....
- Database instances. If I chose to have one database instance I would have to have one schema which limits the amount of customisation I can do. I would also have to carefully key each customer's data, which is a development overhead. Automating database deployment and maintenance is relatively straightforward so I think the choice here is clear cut. One database per customer. Also this gives me extremely simple database scalability, I can simply farm out my customers to multiple DBMS's. This approach will scale to hundreds of customers, thousands would be problematic but not impossible.
So now I've got my multi-tenancy strategy, how am I going to implement it? The core technology I'm going to use is component oriented software design using Dependency Injection and an IoC Container. I'm going to follow some of the recommendations that Oren Eini makes in these posts:
In part 2, I'm going to show my first faltering steps to making a single instance of Suteki Shop host more than one customer. Stay tuned!