CRUD it’s now CQRS … or is it?
In 1983 author James Martin published a book called Managing the Data-Base Environment. It’s interesting the term database is hyphenated in the title; it hadn’t quite settled down as a mainstream term yet. I have not read this book myself, but my understanding is that he presented the concept of the “CRUD Matrix” for engineering how an application performs Create, Read, Update, and Delete operations against the database. Regardless of how the term was first coined, it has gained popularity and is in widespread use today.
CRUD is a model that has existed for decades. A large number of software systems can be classified as a simple combination of CRUD + validation. This is why so many scaffold frameworks provide nearly the same pattern: list records, select record, view detail, edit or delete, and validate a bit along the way. If you are working on an application that follows the pattern of view data, pull it in, do stuff with it, then push it back out, you have an amazing number of options to build it quickly and easily with little ritual or ceremony involved. I see this approach quite often in the development of consumer-facing applications. One track focuses on the engine to present the content to the consumer while the backend system to configure and set up content is quickly generated using a data-driven tool.
If all software operated in CRUD mode many of us might not be employed because it would be so easy to pull CRUD instances out of the assembly line. Software can be quite complex, however, and often models more complex business processes that introduce workflows and state machines that aren’t easily captured with the traditional CRUD model. This fact has led to movements like DDD or Domain-Driven Design, which according to the community website is not a framework or technology but a “way of thinking and a set of priorities.” You focus on the business model and domain, paying attention to important details such as having a common vocabulary that everyone can use to describe the requirements without ambiguity. The source for this concept is defined in the popular “blue book” by Eric Evans called Domain-Driven Design.
A set of new patterns for manipulating data has also emerged to challenge the traditional CRUD model. You can go back to Bertrand Meyer’s Command Query Separation and then examine more recent Command Query Responsibility Segregation (CQRS) pattern by Greg Young to start digging into these principles. A number of implementations exist, including the concept of Event Sourcing. All of these are great patterns to learn and understand as part of your software development toolbox.
While the paradigm shift away from traditional CRUD approaches is refreshing, it can also be problematic. There is always the risk of falling victim to the “flavor of the day.” When I began building Silverlight applications, I was reluctant to fully embrace the MVVM pattern because it was consistently hyped as “the way to go” without very much substance around why it was the way to go. I kept sorting through the catchy phrases like “decoupled code” and “SOLID principles” trying to find the value and bottom line for using this pattern, but it wasn’t until I implemented it myself and observed it in practice through several projects that I was able to finally decide it made sense. My teams were able to develop software faster through parallel workflows and the fact that I could engage an entire design team at the same time I was building the application rather than forcing the project into a sequential workflow was the real benefit I found in addition to the support for testing.
I’ve watched a similar trend with CQRS. Like MVVM, many people are declaring it “too complex” when in fact a proper implementation can be quite simple. Just like the MVVM cops appeared one day and starting writing tickets when developers didn’t completely eliminate their code-behind files, I see some CQRS police saying “if you’re not doing it this way, it’s not CQRS.” In many cases that may be correct, but I think it also undermines the spirit of the pattern. In some cases the pure implementation is exactly what is needed … but is it a new rule that everything must go this route?
I think you’ll find the strongest proponents and advocates for the pattern will be the first to say you should use the right tool for the right job. In my book about designing LOB Silverlight applications I added a controller class to an application that is mostly based on the MVVM model. I also include examples with logic in the code-behind. To some this may seem like sacrilege but in fact these cases were the right tool for the right job: they solved the problem while keeping it simple without compromising the ability to test the application.
I learned about the danger of “either-or” thinking back when I was a personal trainer and had an online coaching practice. I found many clients would get stuck in the either-or mentality. For example, “either I completely eliminate soda or my diet is blown.” Rather than, say, cutting back to just one glass a day for awhile. When traveling, I’d hear, “I can’t get my steamed chicken *** and broccoli so I’m just going to get a big pile of junk from a fast food restaurant” instead of looking for healthier options. “The only thing we had to eat was pizza.” Well, sometimes that happens – but instead of eating fifteen slices, why not just eat one? When I taught clients it is okay to compromise – if your workout calls for free weights but your hotel only has dumbbells, go ahead and train with what you have and get a workout done rather than using it as an excuse to sit in the hot tub for an hour – they had tremendous breakthroughs and were able to achieve a true lifestyle change rather than getting stuck in a diet cycle that was doomed to fail and send them back into old habits.
What does this have to do with software? I think quite a bit. You don’t have to take an either-or approach to building applications, either. For example, it’s not a question of using the entire Prism library or Enterprise Library in an application. It’s perfectly valid to pull out the parts you need – maybe the command implementation from Prism and the logging application block from the Enterprise Library – without overcomplicating the project. When you are looking at patterns, it’s fine to create something that is a hybrid if it fits the needs of your application.
Back to CQRS. I think Microsoft has provided some incredible tools for exposing data as services. With the combination of the Entity Framework and WCF Data Services I can create a set of REST-based services within minutes that are consumable by Silverlight, Windows 8 applications, iPads, iPhones, Windows Phones, RIM devices and Android phones and tablets. It’s just that easy. Unfortunately, while the tools also support CRUD operations (and even provide places you can hook into for validation) it doesn’t always integrate well with a domain-driven approach to the application design. That means it’s off the table, right? CQRS is about having different databases, right?
I’d say, “Wrong” on both counts. If the model works well for querying data, configure it to allow queries and get your read operations up and running in minutes. Sometimes over 80% of your application may be about querying and displaying data, so why not keep it simple and expose it in a way that is easy to expand to other platforms when and if needed?
But what about updates?
The updates don’t have to follow the same set of interfaces if you don’t want them to. It’s perfectly valid to expose a REST interface or even a RPC-based interface that takes commands rather than “update operations.” Why not? You may have a workflow engine backed by state machines and queues that implement Event Sourcing, and that still doesn’t mean you can’t expose the read interface for your data using WCF Data Services out of the box.
My point is that CQRS provides what I think is a very valuable insight: that how you read and query data is probably very different from how you manage, update, and manipulate data. You don’t have to have a picture-perfect implementation of CQRS to take advantage of this concept – it may be as simple as looking at a different set of interfaces and implementing them using different technologies in the stack. I’ve built implementations based on this philosophy that still have one database and one data model using the Entity Framework but provide multiple implementation paths. They allow me to quickly and easily update the model while keeping the code simple and easy to both understand and maintain.
There are some exciting new patterns and approaches to building software that developers should be aware of, but it’s important to look at these as new tools, not new toolboxes. During decades of enterprise software development I’ve rarely watched the toolbox change – it’s almost always been about adding new tools and throwing old ones out. I still see applications that will benefit from the traditional CRUD model and get overly complicated when someone tries to force them into something different. To make a long blog post short: patterns should not be used to define your software, but rather to help solve the problems your software addresses.