I’ve been working with CQRS for almost a year. Ever since I first heard about it, I was immediately convinced that it had the ability to vastly simplify a lot of unnecessary development overhead. In this particular post, I will not be discussing event sourcing which is often mingled with CQRS. Instead, I will be focusing on the query side of the equation.
Please note that the ideas contained herein are merely conjectures of what might be rather than any kind of working, concrete implementation. I’ve thought my way through some aspects and ramifications of implementing what I mention below but new insights will undoubtedly merit additional consideration. Furthermore the solutions outlined below need not be considered mutually exclusive with more traditional ways of doing things. There is definitely room to implement portions of what I mention for specific views while doing things in the traditional way in other views.
ViewModel Tables
Several weeks ago I blogged about having one table per view. Since that time Udi Dahan has mentioned it as well, although independently of my post. Querying view model tables directly, which comes as a positive consequence of implementing CQRS, enables us to avoid having numerous mapping layers between the database and the view. Further, it allows us to avoid projecting off of our domain model and keeps the domain model focused solely on behavior. Lastly, it allows us to scale the read database independently of the write database.
Content Delivery Networks
Think for a moment about the pure static resources that are handled on a given website. They just sit there with the exact same content for each request. These are the exact kinds of resources for which we could leverage a content-delivery network. In other words, we could push these static elements to a CDN and have the CDN deliver them for us thus offloading traffic from our servers and freeing our web tier to perform more interesting tasks—such as processing update-type commands. Not only does this offload work from our web tier, but the user has a better and faster browsing experience.
HTML + JSON
In ASP.NET as well as other server-based page-rendering technologies we typically have the request come all the way to our server and then we render some HTML but with a few modifications depending upon the user. Could there be a way to somehow render static layout HTML but render the parts that vary separately? Why not have the pages render identical static HTML regardless of user and then, on a separate request, render the user-specific content and then stitch the two together using JavaScript?
Let me say that another way. Our MVC view or our ASP.NET “Page” could render pure HTML with absolutely no server-side markup. Inside of that HTML we would have the URL of an embedded resource: <script src=”/scripts/account-history/”></script>. The request to this embedded resource would call our MVC controller and then render JSON data with user-specific information for the currently logged-in user for that view. We could then use a client-side JavaScript templating engine such as jTemplates to combine the JSON with the static HTML.
Static HTML Views + CDNs
The above has some interesting ramifications. Why couldn’t we just put the static HTML for each view into an HTML file and push those HTML files to a CDN? The static HTML files would have <script> tags inside which would make HTTP requests to our controller actions. Of course we would need to figure out a way to render each view with its associated header/footer HTML or perhaps use JavaScript to get the various HTML parts of the page and assemble them on the client.
By doing this, our web tier is now responsible for exactly two things: outputting user-specific data in JSON format and handling of mutating/update-type POST commands from the browser.
CDNs + JSON
Here’s where things get interesting. What if we didn’t have to query the database through our controller/service layer to render the JSON? What if the request for the user-specific data never reached the web server? What if the user-specific JSON files were already on the CDN? Think about that for a minute. If that was somehow possible, our web servers would only be responsible for handling POSTs which contained task-specific commands. Wouldn’t that make the web tier massively scalable? Wouldn’t it be easier to handle exponentially larger loads on the web tier without the need for additional hardware? Even if we didn’t use a CDN and we did everything ourselves, Apache and IIS are really, really good at serving up static files when compared to the expense of going through the ASP.NET pipeline. [This applies to any server-side technology such as Ruby, PHP, Perl, Java, etc.]
How is this accomplished? In addition to what has been mentioned throughout this post of splitting up the HTML and the JSON requests, there are two additional pieces. First, you would want to have a component subscribing to events being published by your domain model. This component would then render the user-specific JSON for each view or page. Second, we would need a way to map the incoming request for a particular JSON file at a “general” location, e.g. “/scripts/account-history” to a user-specific location, e.g. “/scripts/user-12345/account-history.js”.
URL Rewriting + Session State ID + Hard Links
That last part is the tricky part because we want to ensure that the user’s information is protected and cannot be accessed by others. The way to do it is with URL rewriting and file system hard links/junction points. The user-specific JSON file would be written to a known/fixed location, but that location couldn’t be accessed and would never be disclosed over the web. Instead what we would do is rewrite the URL to be: “/scripts/<session-state-id>/account-history.js”. This could be accomplished through either server-side rewriting or even client-side rewriting.
If you recall, the session state ID is very, very temporary. When a user logs out of their account or the session expires, the session state is nullified and disappears. But we don’t typically think like that about directories. This is where hard links or junction points come into play.
When a user logs in, a hard link is created which points to the user-specific (but never disclosed) directory. For example “/scripts/<session-state-id>/account-history.js” would map to: “/scripts/<random-guid>/account-history.js”. When the login takes place, a small, server-side lookup is performed to get the GUID for the particular user—not the user identifier, but another GUID that is never publicly disclosed. We then have a server-side process create a hard link between the temporary session state identifier and the GUID. Conversely, when the user logs out or the session expires, the hard link is removed. In this way we can protect the user data from prying eyes—there would be no way to access the user data without knowing the session state identifier.
Conclusion
All of this is highly experimental, but conceptually makes sense. The development tools currently available bring us some but not all of the way there. Further, there is an amount of overhead in developing such a solution, but the benefits could be significant, especially the separation of concerns aspect and the ability to scale without significant additional effort. Amazon, eBay, Google, and other big players currently implement some or even most of the above techniques but I don’t think I’ve ever seen all of them put together in quite this way.
There are three other benefits that I just thought of. First, if your web servers are completely offline, because of HTTP content caching with expirations, your users wouldn’t even notice—until they tried to perform an update/POST. In this way, your website remains highly available—even if your servers aren’t online! The second benefit, although much smaller, is that you could more easily render browser-specific implementations of your site, such as those for mobile devices and browsers (which you can already do this using different views in MVC). Lastly, Google can index your site much more quickly because everything is effectively static, which will soon have a positive effect on your PageRank.
For those of you that have read thus far, I’m curious to hear your comments.