If you’re an ISV and you’re contemplating whether you should migrate your product to Windows Azure, you may be asking yourself if you can have your cake and eat it too, that is, have the exact same code base deployed with customers running on-premise as well as with customers running in the cloud. In this blog post I will offer some technical guidance on this issue.
These are my assumptions:
- You want to offer your software as Software as a Service, that is, as a hosted service running on Windows Azure
- Each customer will want to have a dedicated virtual machine for running the application (that is, I am not going to go into multi-tenancy here)
I am not making any assumptions on whether your application can currently be scaled horizontally. If it can’t, moving it to Azure will not change this. The Azure load balancers use a round-robin algorithm and have no support for sticky sessions of out the box, so making the application scale will most likely be a non-trivial exercise.
The key to having an application be able to run both on-premise and in Windows Azure is to isolate the application’s dependencies on the hosting environment, hide these dependencies behind suitable abstractions and then provide implementations of these abstractions tailored at each hosting environment.
So, the first step in taking your application to the cloud should be to identify the dependencies for which we will need to provide abstractions. Obviously, we only need to consider the parts of the application’s environment which differ between Windows Azure and an on-premise environment. Typical examples include:
- Database (SQL Server vs. SQL Azure)
- Shared file systems
Thus, you need to re-architect your application from something that looks like this:
to something that looks more like this:
If you are in luck, you already have an abstraction which somewhat isolates the rest of your application from the particular database implementation. This would be the case if you are using an ORM like Entity Framework, Nhibernate or something similar. Isolating other dependencies may require more work.
Taking it to the cloud
At this point, you have an application with a nice encapsulation of external dependencies. Even though the application is only able to run on-premise at this point, the architecture has already been improved. The next step is obviously to provide implementations of your abstractions suitable for running in the cloud. This is the fun part: If you have identified the right abstractions, you can go nuts in cloud technology, using massively scalable storage, asynchronous communication mechanisms, CDNs etc. This process should give you an application capable of running on Windows Azure:
The code base now contains everything we need for an on-premise installation as well as for a cloud deployment. However, to truly decouple the application from its dependencies, the set of dependency encapsulations to use in a given installation should be easily configurable. To this end, use your favorite dependency injection tool. Unless you decide to roll your own tool, the tool you choose will most likely support multiple methods of configuration and you can choose whatever method you prefer.
If you want to get really fancy, you may even choose to have the application configure its dependencies on its own on startup. The application can use the Windows Azure API to tell it whether it is running on Windows Azure. The information is available through the Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment class, which has a static property called IsAvailable:
I usually hide the environment information provider behind a static gateway pattern.
This was a quick run down of one path towards the cloud. Obviously, there is much more to be said, especially with respect to the ‘taking it to the cloud’-step. I’ll save that for another day.