Dev Link2009 Multi Tenancy Beyond The Whiteboard Chris Hefley
Upcoming SlideShare
Loading in...5
×
 

Dev Link2009 Multi Tenancy Beyond The Whiteboard Chris Hefley

on

  • 3,378 views

Multi-Tenancy: Beyond the Whiteboard. Presentation from Devlink 2009, Nashville, TN, Chris Hefley http://indomitablehef.com

Multi-Tenancy: Beyond the Whiteboard. Presentation from Devlink 2009, Nashville, TN, Chris Hefley http://indomitablehef.com

See sample project at http://code.google.com/p/sokmunkae/

Statistics

Views

Total Views
3,378
Views on SlideShare
3,368
Embed Views
10

Actions

Likes
1
Downloads
24
Comments
0

3 Embeds 10

http://www.slideshare.net 5
http://www.linkedin.com 4
http://www.lmodules.com 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • Ok, let’s get started. Hi, everyone, I’m Chris Hefley. The title of this talk is Multi-Tenancy, Beyond the whiteboard. First off, I’ll say that this is the kind of talk where a lot can go wrong. I’m going to try to show you some running code, stepping through it in the debugger and all, so if you see me do something stupid, speak up…d m on’t let me flounder. Feel free to ask questions at any time, but if you have one and want to hold till just the right moment, watch for those times when Visual Studio starts grinding away on something, when there would normally be an awkward silence, and go ahead and just holler out your question then. I’ll admit now that some of the examples I promised you, like Linq2Sql, are not in here. I can’t get the visual designer for Linq2Sql or the server explorer to show up in Visual Studio on this machine right now, so I didn’t get a chance to do that one. But the important stuff here is architectural, and whether you use Lin2Sql or NHibernate or just roll your own isn’t so important. And hopefully I can leave time for some lively discussion at the end.
  • First off, what is Multi-Tenancy? In simplistic terms, it the architecture we use to offer software as a service, where a single instance of your application is used by multiple clients, each of whom has their own, usually private, virtual copy of the application just for them. When you sign up for a BaseCamp or SalesForce.com or Facebook account, you are becoming a tenant in someone’s multi-tenant application.
  • The biggest architectural decision you are going to have to make when developing a multi-tenant application is how to partition the data for different tenants. We’re just going to skim over these and acknowledge that each has it’s place, without debating all the pros and cons and dealing with all the religious wars that ensue. The code and design patterns we are going to look at later, however, will help you to implement some of these data partitioning schemes, so we’ll just describe each briefly here and move on.Ok, so first off, there’s Database Per Tenant In some verticals, like Healthcare and Financials, this may be the only option you have for some applications. It’s great for security, but can get very difficult to maintain if you’re not very strict and very careful to keep everything in sync.In Schema per tenant, there’s one database, but a separate copy of each table for each tenant. In TenantID per Row, every row in every table has a TenantID column. Every database query from you application includes “Where TenantID = The CurrentTenantId”. One of the nice things about this approach is that it’s easy to change your mind and switch to a separate database, if you want to. It’s easy to extract the data for one client from the system, by just copying everything from all tables that has the same TentantIDIn Tenant as Aggregate Root, the “Tenant” or “Organization” or “Client” table is the parent of every other table in the model. So for a project management application, you might have an Organization, which has a one-to-many relationship to the Projects table and the Users table. The Projects table would have a one-to-many relationship to the ProjectItems table and the Milestones table, etc. Your application has to enforce the separation by always joining to the appropriate parent table when retrieving things from the database.
  • Some other considerations that will come up:The Url. Does everyone log into the app at the same url? My personal favorite is the subdomain approach, which can even be expanded so that you have tenant.subtenant.app.comThis third choice is especially nice for social applications like twitter and facebook, where each tenant is actually part of a larger community, and shares information with other tenants and possibly the public.And finally, for some applications it makes sense to allow the client to supply their own domain name, which you redirect to their hosted instance of your app. In some cases like when opening a Yahoo! Store, buying a domain name and having it set up for you can even be part of the signup process for your mult-tenant application.As far as data access strategy, you have object-relational mappers like Nhibernate, EntityFramework, Linq2Sql, or you can write your own dynamic sql queries in your app, or use stored procedures.
  • The first design pattern we’re going to look at is the Repository pattern. Basically, a repository is an object that sits between your domain model and you data access layer. It provides an object oriented abstraction over data access. While the methods on your data access objects are going to be the pretty typical “CRUD” methods, the methods on your repository will be more meaningful in terms of your application domain.You might have a Find method that takes a “Query” object – basically an object that looks something like the object you are searching for, in this case Person, and has the fields filled in that you are interested in. So, personQuery might have all it’s fields = null, but the username field has “chris” and maybe there’s an enum that allows to specify “begins with”, “contains” or “exact”.The repostory could deconstruct that patientQuery, call the Data Access method (RetrieveOne or RetrieveAll), and pass in a list of relevant parameters that get turned into a real database query.You might also have meaningful methods like ListUsersByProject that eventually get turned into the more mundane parameters and database query by the data access layer.Take a look at the code:IRepostoryIUserRepositoryUserRepository
  • I proposed earlier that for most multi-tenant applications, the bulk of the application should be blissfully ignorant of the fact that it is a multi-tenant application. (again, the exception is a community application like Facebook, where interacting with the other tenant is desirable).I’m proposing now that the Repository should be that boundary in your application where, everything above the respository “Knows nothing” of Multi-Tenancy. This includes those application services that instantiate and call the methods on the repository – they should not be passing a TenantId into repository methods, they should just ask for the objects they want, and the repository should figure out that they mean….all the objects they want “for the current tenant”.So, if the application can’t tell the repository which Tenant it belongs to, then how does the repository get that information?
  • The answer lies in our next pattern: Dependency Injection and Inversion of Control. When I look back over my career, I can identify moments in my growth process where I learned some new concept, or finally really, really understood some concept that had been vague before, but suddenly became clear. I can identify certain ones of those moments that were “game changing” – after which what I learned began to effect everything I did – and became part of almost every bit of code I wrote.This is one of those. Until you really grasp it, it looks a little intimidating to most people. At least, it did to me at first. But once I stopped just reading blog posts about how important some people thought it was, and rolled up my sleeves and decided to try it, I found that it is really, really simple. I mean, really simple.Now I’m not sure I can teach this design pattern effectively with four slides. But I’m going to dispense with all the formal definitions, and I’m not going to try to show you a complete understanding of how it works, but I’m going to show a very simple example of the most common way in which I use it, that hopefully will be an ah-hah moment for some of you.Here you have UserRepository class, and it depends on a DataAccess object to actually create queries and retrieve records from the database.In the first example, you have this dependency, so you just ensure that you “new up” an instance of the object you need.The second bit of code is an example of something called “contstructor injection” – that is, you “inject” the depended upon objects into your class via the constructor. No big deal, right? So, let’s think about the implications of doing it this way. Obviously, whoever creates the UserRepository will have to create an instance of the User DAO and pass it into the constructor for UserRepository when it gets created. So wait a minute, is that better than what we had before? Haven’t we increased our dependencies, not decreased them? Now, my UserAdminService class that uses the UserRepository to perform its work will have to know about the DAO? Well, that sucks.
  • But wait, there’s more. What we just saw was dependency injection. Another pattern, which can be seen really as the second half of the same pattern, is called Inversion of Control. Now there are a lot of freely available Inversion Of Control implementations out there, and all of them have more features than this, but in order to make it simple, I’ve contrived the most basic example of an IOC Container (that’s inversion of control container) that you may ever see.
  • I thought I was really cooking when I started using Dependency Injection, because it made it so much easier to isolate the components I wanted to test, by allowing me to provide mock objects for the dependencies I wasn’t trying to test.But at that point, the whole IOC container thing was just sort of “there” for me…I was basically breaking my application up into smaller pieces and removing the connections between them, and it was the IOC containers job to piece those all together for me when I was actually running my application, and not just running tests.But the real power of an IOC container is what we’re going to use it for today. I said before that we wanted our repositories to be the boundary in our application, so that the repository would know about the Tenant, but the rest of the application would not. We’re going to do that by “injecting” knowledge of the tenant into the repository, and depending on our IOC container to supply that knowledge to the repository when it is instantiated.

Dev Link2009 Multi Tenancy Beyond The Whiteboard Chris Hefley Dev Link2009 Multi Tenancy Beyond The Whiteboard Chris Hefley Presentation Transcript

  • Multi-Tenancy: Beyond the Whiteboard
    Chris Hefley, Bandit Software
    Blog: http://indomitablehef.com
    Email: indomitablehef@gmail.com
    Twitter: @indomitablehef
  • Multi-Tenancy
  • The Big Decision
    Database Per Tenant
    Schema Per Tenant
    Tenant Id per Row
    Tenant as Aggregate Root
  • Other Considerations
    The Url
    app.com (salesforce.com)
    tenant.app.com (me.basecamphq.com)
    app.com/tenant (facebook.com/me)
    tenant.com (mynewyahoostore.com)
    Data access
    ORM
    Dynamic SQL
    Stored Procedures
  • Design Goals
    Agnostic
    Secure
    Maintainable
  • Design Patterns: Repository
    Domain Model
    public class Person {…}
    Repository (PersonRepository)
    repository.Find(PersonQuery q) {…return Person}
    repository.Remove(Person p) {}
    respostory.Add(new Person {…})
    repository.ListByProject(Project p) {…return List<Person>}
    Data Access Layer
    dao.RetrieveOne(Dictionary<string,object> parameters)
    dao.Delete(person.Id)
    dao.SaveOrUpdate(Person p)
    dao.RetrieveAll( Dictionary<string,object> parameters)
  • Repository as Boundary
    Your Application “Knows Nothing”
    Repository
    Effectively adds:
    “WHERE TenantId =“
    To every set of criteria passed on to the data layer
  • Design Patterns: DI/IOC
  • Inversion of Control
  • Inversion of Control
  • First Benefit: Testing
  • But wait, there’s more!
  • SokMunkae Data Model
    Organization
    User
    Project
    Task