We are in a process of redesigning our product code in such a way so as to support multitenancy.
Currently the implementation is such that one product deployment caters to only one customer.
Thus the application data corresponds to only one customer. This data (which is global wrt the application) is in the form of hashtables, lists and DB. Multiple threads make use of this data. The complete code is written in C.
Now, since we want to migrate to multitenant architecture, the application code would need to store data for multiple customers. Since data stored in the application should be segregated wrt customers, I want to figure out what kind of architecture would best suit this requirement. I am thinking of adopting some OOP concepts here since I can use C++ also. But not sure how good this idea would be. Modularity is a prime advantage that OOP offers over C and hence thinking on those lines. But at the same time it is going to have a humongous on the current implementation requiring lots of changes. Hence, minimizing this is also important.
What would be the best approach to attain all the objectives mentioned above? Is there any other way to do this?
Bubble bursting: Moving to a multitenant architecture is an orthogonal aspect to utilizing OOP within your code. Yes, you’ll need to update your application code, but you don’t necessarily need to change the overall style of your programming.
And now, for an actual answer:
There are three broad approaches to moving to a multi-tenant environment. I think you want the blended approach to solve your problem. It represents the best balance between system administrative overhead; additional code to be written; and database maintenance.
The blended approach is to use a single, shared schema that has authorization checks to control access to the data.
The easiest way to get this blended multitenancy is to add a column representing ownership to the various database tables that need access control. You’ll also need to create a permissions table if you don’t already have one that links users or groups to database owner IDs that they are allowed to access.
Within your application, your queries will need to be updated to reflect access restrictions. If you already have a security / authorization layer this should be fairly easy to add in. If not, try to find the point within your application that’s closest to querying the database and add the checks there. This is where having a data access layer of some sort will really make your life a lot easier.
If you were smart enough to use stored procedures, then it’s even easier for you to modify the queries. Your application is already treating the stored procs as an abstract interface, so adding authorization controls will be transparent to the application.
Another option is to create views based upon the clients. It gets a bit trickier to make this work, but you could have a similar permissions table that indicates what views a user or group is allowed to access. At run time, or perhaps through some sort of configuration that you control, queries are told which views they are allowed to go against.
When you write data to the database, you need to make sure that ownership is recorded along with the data. It’s a similar programmatic challenge as the querying, but I would encourage you to assign ownership to a client group ID instead of to an individual user. The exception would be if you have a generic user representing the client’s business.
If you don’t have constructs within your database schema to organize the data within objects that can be assigned to a client, consider creating that. Instead of having a bazillion rows of data that ClientA
can access, there are a bazillion rows of data belonging to ObjectA
that ClientA
happens to own. Abstracting out the ownership to an object can simplify some of the access queries when you have a complex number of objects within the system.
Surprisingly, that’s about it for moving to a multi-tenant environment. Obviously, the pain is in the details. I recommend having unit and integration tests in place to validate that the security mechanisms are operating as you expect.
Regarding OOP & modularity – your general thoughts are on track. But keep in mind that you can use OO principles within a structured language like C. It takes more governance to maintain that code style, but you can gain some of the benefits of modularity that you are looking for.
If you don’t already have a data access layer, now is the time to consider putting one into place. Having a DAL will help promote Encapsulating that logic within one area and decoupling DB access from the rest of the application. Implementing those principles will make future changes easier to accomplish.
There are other approaches to multi-tenancy such as having a full DB schema per client within a single the DBMS. Having multiple schemas bypasses some of the authorization / ownership changes that you would have to make. But the downside is this approach can require a much bigger DBMS server.
Another option is that you can have a full DBMS per client in order to segregate the data. Again, you bypass some of the security changes but you have to maintain more servers. Referential integrity between the schemas becomes an issue with this option.
However, the context of your question implied you were looking for a multi-tenant with a shared DB so I didn’t go into those approaches.