{"id":1535,"date":"2019-09-19T00:00:00","date_gmt":"2019-09-18T22:00:00","guid":{"rendered":"https:\/\/demo.sidekick.be\/itenium\/cqrs-ramble\/"},"modified":"2025-11-28T13:31:44","modified_gmt":"2025-11-28T12:31:44","slug":"cqrs-ramble","status":"publish","type":"post","link":"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/","title":{"rendered":"CQRS and CRUD"},"content":{"rendered":"<p>I\u2019ve always loved <a href=\"https:\/\/en.wikipedia.org\/wiki\/Command%E2%80%93query_separation\">CQS<\/a>. How could one not, it makes perfect sense that <code>getUser(5)<\/code> would return user \u201c5\u201d and not do much else, perhaps there is some caching in place but one would hope it doesn\u2019t actually create a User record or something.<\/p>\n<p>Then Greg Young introduced CQRS: An architectural pattern that allows us to add nice things, like Event Sourcing or a reporting database pretty easily. Adding such significant changes might be much easier compared to the impact on a more classical architecture, even when doing so late in the development life cycle.<\/p>\n<blockquote>\n<p>Despite these benefits, <strong>you should be very cautious about using CQRS<\/strong><br \/> \u2014 <em>Martin Fowler<\/em><\/p>\n<\/blockquote>\n<p>In his entire article on CQRS, this is the only sentence that Martin has put in bold.<\/p>\n<p>Unfortunately developers like the latest and greatest very much and CQRS has, for many organizations and teams been put forward as the de facto standard architecture.<\/p>\n<p>There is of course that one project where it makes a lot of sense but let\u2019s be realistic, most of us are working on enterprise applications which are all pretty much CRUD.<\/p>\n<p>So let\u2019s explore what usually happens when you use CQRS for a CRUD application\u2026<\/p>\n<h1 id=\"the-cqrs-mayhem\">The CQRS Mayhem<\/h1>\n<p>An often overlooked aspect of design patterns are the <code>Consequences<\/code>:<\/p>\n<blockquote>\n<p>How does the pattern support its objectives? What are the trade-offs and results of using the pattern? What aspect of the system structure does it let you vary independently?<br \/> \u2014 <em>Design Patterns: Elements of Reusable Object-Oriented Software<\/em><\/p>\n<\/blockquote>\n<p>If there is a whole point to this blog post it\u2019s probably:<\/p>\n<p class=\"notice\">The aspect of a CQRS system that benefits most from using the pattern is adding new ways to display, update and create existing entities. <strong>This is the one thing that typically doesn\u2019t happen in a CRUD system.<\/strong><\/p>\n<p>When applying CQRS to something that is 80% CRUD to all 100% of the application, you have not properly assessed the patterns\u2019 <code>Applicability<\/code> nor its <code>Intent<\/code> and are left only with its <code>Consequences<\/code>:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/itenium-be.github.io\/blog-posts-new\/assets\/blog-images\/CQRS-Ramble-Consequences.jpg\" alt=\"There will be consequences meme\" title=\"There will be consequences\" class=\"img-responsive\" \/><\/p>\n<h2 id=\"an-explosion-of-classes\">An Explosion of Classes<\/h2>\n<p>A create and an update probably save to the same place in the same structure.<\/p>\n<p>So you need to do a mapping from 2 models to the \u201cdatabase\u201d structure. I\u2019m sure you have a mapper for that, so you now have 2 mappers. Oh and of course also 2 controllers, perhaps 2 services and also 2 validators. And 2 repositories and 2 dtos and 2 handlers and uhm do you not need a separate interface type for all these? We want to talk to an interface, not an implementation after all!<\/p>\n<p>Instead of a delete\/getOne just passing along an <code>int id<\/code> we will now also introduce good old <code>DeleteModelRequest<\/code> and <code>GetModelByIdRequest<\/code>: Because who doesn\u2019t like a hundred classes with one <code>int Id<\/code> field in them. Even if you don\u2019t want them, you\u2019ll probably end up with a package that requires a specific type per command for its wiring.<\/p>\n<p>So yeah, the amount of types in your application will grow. Dramatically.<\/p>\n<h2 id=\"an-explosion-of-duplication\">An Explosion of Duplication<\/h2>\n<p>Well since it\u2019s CRUD you are bound to be doing the exact same thing multiple times. Right.. not exactly the same thing of course, there is that one field\u2026 in which entity was it again?<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/itenium-be.github.io\/blog-posts-new\/assets\/blog-images\/CQRS-Ramble-Duplication-Everywhere.jpg\" alt=\"Duplication!? Duplication everywhere!\" \/><\/p>\n<ul>\n<li>The CreateHandler for entity 1 will look very much like the one for entity 2.<\/li>\n<li>The CreateRequest and UpdateRequest for an entity will also very much look alike.<\/li>\n<li>All DeleteRequests and GetByIdRequests will look exactly the same.<\/li>\n<li>The mapping from the CreateModel and the UpdateModel to the persistence model\u2026<\/li>\n<\/ul>\n<h2 id=\"confusion-on-the-frontend\">Confusion on the frontend<\/h2>\n<p>An update screen is usually populated with existing values. You have a different model for the Read. So you need to map the Read to the Update model before you can populate the controls\u2026 Or you need to also create a Get for the Update model. Either way, yes, you\u2019ll need to write more code.<\/p>\n<p>(perhaps I can\u2019t pin the next one entirely on CQRS but there is no stopping now \ud83d\udd28 \ud83d\udd28 \ud83d\udd28)<\/p>\n<p>For simple entities we obviously need to only fetch what we really need on the frontend. So we create a <code>ListModel<\/code> and an <code>FullModel<\/code>. When we need to show just a few fields, we also create a <code>HeaderModel<\/code> and a <code>ModalModel<\/code>. Since you\u2019re not using GraphQL, each of these also needs a backend endpoint and suddenly we also need to write some more code: A <code>ListModelRequest<\/code>, <code>FullModelRequest<\/code> etc and their corresponding <code>ListModelRequestHandler<\/code> and <code>FullModelRequestHandler<\/code>.<\/p>\n<p>But things get even better! We now have to keep all representations of the same entity in sync. Alternatively we fetch when needed and discard from memory as soon as possible, for example when the entity is no longer visible to the user. The amazing part is that now, we are probably fetching more data compared to the single entity approach &#8211; which was probably the main reason for having multiple representations in the first place.<\/p>\n<p>Additionally it becomes harder to reuse components. Yeah, I would really like to use the cool <code>ModalModelPopupComponent<\/code> but what I have is a <code>ListModel<\/code> and the <code>ModalModel<\/code> doesn\u2019t have that one property. The horror!<\/p>\n<p><em>Disclaimer<\/em>: as always, \u201c<a href=\"https:\/\/codepen.io\/rachsmith\/details\/YweZbG\/\">it depends<\/a>\u201d: for entities with many children it might be too heavy to work with just one representation. <small>(each heading should probably have a disclaimer)<\/small><\/p>\n<h1 id=\"the-search-for-answers\">The Search For Answers<\/h1>\n<p>The search for answers <strong>to the wrong question<\/strong>:<\/p>\n<blockquote>\n<p>How can I keep this CRUD application easy to understand and modify while also applying CQRS?<br \/> \u2014 <em>Every developer working on a CQRS + CRUD app<\/em><\/p>\n<\/blockquote>\n<p>Because you want to keep <a href=\"https:\/\/en.wikipedia.org\/wiki\/Don%27t_repeat_yourself\">DRY<\/a>, one searches for solutions.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/itenium-be.github.io\/blog-posts-new\/assets\/blog-images\/CQRS-Ramble-Keeping-DRY.jpeg\" alt=\"Keeping Oneself DRY\" \/><\/p>\n<h2 id=\"domain-inheritance\">Domain Inheritance<\/h2>\n<p>The inevitable happens. In order to somewhat mitigate the maintainability issues that arise from applying CQRS when it really shouldn\u2019t, inheritance is used so that each time a property changes, is removed or added, it doesn\u2019t result in doing the same change x times.<\/p>\n<pre><code class=\"language-c#\">class CreateUserRequest {\n    string Name;\n    DateTime BirthDate;\n    Address Address;\n}\n\nclass UpdateUserRequest : CreateUserRequest {\n    int Id;\n}\n\nclass FullUserViewModel : UpdateUserRequest {\n    \/\/ perhaps this one is a stretch \ud83d\ude05\n    DateTime CreatedOn;\n    string CreatedBy;\n}\n<\/code><\/pre>\n<p>The most striking, but perhaps also a non-issue, is that this is a Liskov Substitution Principle violation. Your <code>CreateUserRequestHandler<\/code> is going to accept the <code>UpdateUserRequest<\/code> but it will probably not do what you\u2019d hope. A non issue because the execution chain is probably auto-wired.<\/p>\n<p>Then there is reduced readability: in order to see what an entity contains you need to drill down the inheritance chain and puzzle it together mentally.<\/p>\n<p>So we are back to copy\/paste? Now it\u2019s reduced maintainability: all property changes need to be done x times. And \ud83c\udf89, most maintenance includes exactly that: add this one field, rename that field, delete that field. Even in-code class and property documentation needs to be duplicated.<\/p>\n<h2 id=\"generic-base-classes\">Generic Base Classes<\/h2>\n<p>The next source of repetition needs to go and so a well intended developer creates generic base classes to avoid request handler code duplication.<\/p>\n<p>We end up with the same amount of \u201cHandlers\u201d but now they do not contain any code they only inherit a base, provide some options with generic parameters and a have constructor passing a bunch of dependencies. The same may happen at every layer \/ branch in the application.<\/p>\n<pre><code class=\"language-typescript\">class CreateModelHandlerBase&lt;TReadModel, TCreateModel, TUpdateModel, TReturnModel&gt; {\n    constructor(\n        IRepository&lt;TReadModel, TCreateModel, TUpdateModel&gt;,\n        IUnitOfWork&lt;TCreateModel&gt;,\n        ITranslator,\n        IErrorHandler,\n        ILogger&lt;TCreateModel&gt;,\n        IAuditor,\n        IReferenceDataProvider,\n        IUserProvider,\n        ILanguageProvider,\n        IHopeIMNotMissingOne\n    ) {}\n\n    DoIt(model): TReturnModel {\n        \/\/ lots of crazy code here\n        \/\/ it probably handles all\n        \/\/ the creates for all the\n        \/\/ entities.This one might\n        \/\/ inherit from the Update\n    }\n}\n<\/code><\/pre>\n<p>Yeah you don\u2019t really need the Read\/Update models for a CreateHandlerBase but unfortunately the IRepository needed it. The TReadModel is first because the same order of generic parameters is used in the Read, Update and Delete handlers due to some nasty copy paste errors in the past.<\/p>\n<h4 id=\"how-to-recognize-such-class\">How to recognize such class<\/h4>\n<ul>\n<li>Lot\u2019s of generic parameters<\/li>\n<li>Zero documentation<\/li>\n<li>Already contains <code>if (model is Model5Request)<\/code> branches.<\/li>\n<li>No unit tests<\/li>\n<li>Seems to work but only its creator knows how<\/li>\n<\/ul>\n<p>Okay, perhaps I can\u2019t be too mad about this one, everyone probably ends up with something similar for a CRUD persistence layer using either architecture.<\/p>\n<h1 id=\"why-would-more-code-even-be-bad\">Why would more code even be bad<\/h1>\n<blockquote>\n<p>The ratio of time spent reading versus writing is well over 10 to 1.<br \/> \u2014 <em>Robert C. Martin<\/em><\/p>\n<\/blockquote>\n<p>So if you have a code base that is x times the size of what it could be you\u2019ll now spend much more time on what you\u2019re already doing most?<\/p>\n<p><\/p>\n<blockquote>\n<p>You would naturally expect a project that\u2019s twice as large as another to have twice as many errors. But the density of defects \u2014 the number of defects per 1000 lines of code \u2014 increases.<br \/> \u2014 <em>Steve McConnell (Code Complete, \u201cHow Program Size Affects Construction\u201d)<\/em><\/p>\n<\/blockquote>\n<p>More code === More bugs \ud83d\ude03<\/p>\n<h2 id=\"accidental-complexity-vs-essential-complexity\">Accidental Complexity vs Essential Complexity<\/h2>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/No_Silver_Bullet\">Essential Complexity<\/a> is driven by business needs and cannot be avoided.<br \/> Accidental Complexity is what we are creating here: More types to create and maintain. Arguably, a more difficult to follow flow of execution. More code to read\/scan through during bug hunting.<\/p>\n<p>Not everyone in the team will have worked with CQRS. There is a learning curve. During an initial adjustment period less value will be delivered.<\/p>\n<p>Adding Accidental Complexity may be a good thing, but what are you buying yourself here? What did applying CQRS bring to table that starts really paying off months\/years later?<\/p>\n<h1 id=\"freedom-or-enslavement\">Freedom or Enslavement<\/h1>\n<p>For those of you who have not yet noticed, what bothers me most about CQRS is that for everything you do, it always means more code, usually in the form of new classes.<\/p>\n<p>And isn\u2019t that exactly what the Open-Closed Principle advocates? Well yes\u2026 true\u2026 I rest my case, all hail CQRS.<\/p>\n<p> If the most common types of feature requests can be handled in an Open-Closed way, then \ud83d\udc4d for the team! Unfortunately for CQRS this is only the case when creating new Entities or new ways to Create\/Update existing entities. Even long before you\u2019ve gotten to \ud83c\udfba \ud83c\udf89 v1 \ud83c\udf89 \ud83c\udfba, no more new entities will be added and since it\u2019s still very much a CRUD application you most often end up with \u201cPlease add field x to entity y\u201d tickets which is something CQRS isn\u2019t very good at.<\/p>\n<p>So what is one to do?<\/p>\n<h2 id=\"kiss\">KISS<\/h2>\n<p>If the only difference between create and update is the availability of the <code>id<\/code> property, instead of literally writing\/copying hundreds of lines of code, you can solve the issue with no more than about 2 lines of code:<\/p>\n<pre><code class=\"language-typescript\">if (isCreate &amp;&amp; entity.id)\n    throw Error;\n<\/code><\/pre>\n<p>If there is more to it:<\/p>\n<ul>\n<li>Add the second if!<\/li>\n<li>How about <code>if (isUpdate) doThatOtherStuff();<\/code>?<\/li>\n<li>Add metadata to properties signaling \u201callow edit on create only\u201d and other things happening in your domain.<\/li>\n<li>Introduce a seam<\/li>\n<li>Be creative! Injectors, Interceptors, Filters!<\/li>\n<\/ul>\n<h2 id=\"a-cqrs-rule-of-thumb\">A CQRS Rule of Thumb<\/h2>\n<p>An easy to follow checklist to determine if you need CQRS for this upcoming \u201cMetaDataAdmin\u201d project:<\/p>\n<p>If, for a single entity, your UX designer<\/p>\n<p>OR: created 1 wireframe for Create, Read and Update<br \/> OR: made one wireframe for each but they look pretty much alike<br \/><strong>THEN<\/strong>: Choose CQRS at your own peril.<\/p>\n<p><\/p>\n<p>If he made 7 radically different wireframes: 2 Creates, 3 Updates and 2 Reads &#8211; for the same entity.<br \/><strong>THEN<\/strong>: I suggest you consider CQRS, it might be a good fit.<\/p>\n<h2 id=\"mitigation\">Mitigation<\/h2>\n<p>If despite all this, it is CQRS or the highway:<\/p>\n<p>Create code snippets, perhaps even a little generator to mitigate the pain. (you mean, write even more code? \ud83d\ude00)<\/p>\n<p>Good documentation would help a lot but well, you know how it goes \ud83d\ude03<\/p>\n<p>A simple diagram explaining the flow for a typical CRUD operation: where in the project folder structure to create which class goes a long way getting new devs and juniors onboard.<\/p>\n<p>If you end up using the domain inheritance thing, (generated?) printouts for the important entity types so you can piece things together more easily are a good workaround for properties being \u201call over the place\u201d.<\/p>\n<p>UnitTest the heck out of those pretty \u201cBaseHandlers\u201d and you\u2019ll be fine!<\/p>\n<p><small>Or, you know, just abstract it away with a pretty meta-CQRS-CRUD design \ud83d\ude09<\/small><\/p>\n<h1 id=\"conclusions\">Conclusions<\/h1>\n<p><!-- !Safely in comment! --><!-- CQRS === The \ud83d\ude08 --><\/p>\n<p><a href=\"https:\/\/itenium.be\/blog\/productivity\/pragmatic-tip-2-think-about-your-work\/\">THINK!<\/a> Does it make sense to use CQRS or not!?<\/p>\n<p>If so, will it be helpful to do for all parts of the application and for all entities?<\/p>\n<h2 id=\"the-cure-is-worse-than-the-disease\">The Cure Is Worse Than The Disease<\/h2>\n<p>If you are using CQRS for a CRUDdy app, then you are basically avoiding issues like:<\/p>\n<ul>\n<li>For a create, you cannot set the <code>id<\/code><\/li>\n<li>For create and update, you cannot set audit fields (Create &amp; Update meta info)<\/li>\n<li>Sometimes, for some entities there are some fields that can only be set during Create or Update<\/li>\n<\/ul>\n<p>And replacing them with issues like:<\/p>\n<ul>\n<li>(Junior) Developers that have to learn this whole CQRS thing<\/li>\n<li>An explosion of classes and duplication (mappers, entities, dtos, requests, \u2026)<\/li>\n<li>More expensive maintenance for CRUD-related feature requests<\/li>\n<li>You are making your application Open-Closed in all the wrong ways<\/li>\n<li>Developers that do not like duplication search for solutions\n<ul>\n<li>Domain classes that inherit from each other<\/li>\n<li>Empty classes that just inherit from another class<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h1>Extras<\/h1>\n<p><b>Other interesting reads<\/b><\/p>\n<ul>\n<li><a href=\"https:\/\/steve-yegge.blogspot.com\/2008\/02\/portrait-of-n00b.html\">Portrait of a n00b (by Steve Yegge)<\/a><\/li>\n<li><a href=\"http:\/\/www.informit.com\/store\/enterprise-integration-patterns-designing-building-9780321200686\">Book: Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions<\/a><\/li>\n<li><a href=\"https:\/\/chriskiehl.com\/article\/event-sourcing-is-hard\">Don&#8217;t Let the Internet Dupe You, Event Sourcing is Hard<\/a><\/li>\n<li><a href=\"https:\/\/www.infoq.com\/news\/2016\/04\/event-sourcing-anti-pattern\">A Whole System Based on Event Sourcing is an Anti-Pattern<\/a><\/li>\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=LDW0QWie21s&#038;feature=youtu.be&#038;t=2391\">Video: Greg Young \u2014 A Decade of DDD, CQRS, Event Sourcing &#8211; Process Managers<\/a><\/li>\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=LDW0QWie21s&#038;feature=youtu.be&#038;t=1926\">Video: Greg Young \u2014 A Decade of DDD, CQRS, Event Sourcing &#8211; Frameworks \ud83d\ude41<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<h1 class=\"hide-from-excerpt\" id=\"a-ramble-against-cqrs\">A ramble against CQRS<\/h1>\n<p>A lot of interesting articles have been published about <strong>Command Query Responsibility Segregation<\/strong>.<\/p>\n<p>This is a mere rant. Not necessarily against CQRS per se, but against <strong>when<\/strong> it is being applied in spite of Martin Fowlers cautionary words:<\/p>\n<blockquote>\n<p>For some situations, this separation can be valuable, but beware that <strong>for most systems CQRS adds risky complexity<\/strong>.<br \/> \u2014 <em>Martin Fowler (<a href=\"https:\/\/martinfowler.com\/bliki\/CQRS.html\">CQRS Article<\/a>)<\/em><\/p>\n<\/blockquote>\n","protected":false},"author":1,"featured_media":2053,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[27],"tags":[10],"class_list":["post-1535","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-design","tag-war-story"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>CQRS and CRUD - Itenium<\/title>\n<meta name=\"robots\" content=\"noindex, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"CQRS and CRUD - Itenium\" \/>\n<meta property=\"og:description\" content=\"A ramble against CQRSA lot of interesting articles have been published about Command Query Responsibility Segregation.This is a mere rant. Not necessarily against CQRS per se, but against when it is being applied in spite of Martin Fowlers cautionary words:For some situations, this separation can be valuable, but beware that for most systems CQRS adds risky complexity. \u2014 Martin Fowler (CQRS Article)\" \/>\n<meta property=\"og:url\" content=\"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/\" \/>\n<meta property=\"og:site_name\" content=\"Itenium\" \/>\n<meta property=\"article:published_time\" content=\"2019-09-18T22:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-11-28T12:31:44+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/CQRS-Ramble.png\" \/>\n\t<meta property=\"og:image:width\" content=\"360\" \/>\n\t<meta property=\"og:image:height\" content=\"300\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Usdevelop\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Usdevelop\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/\",\"url\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/\",\"name\":\"CQRS and CRUD - Itenium\",\"isPartOf\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/CQRS-Ramble.png\",\"datePublished\":\"2019-09-18T22:00:00+00:00\",\"dateModified\":\"2025-11-28T12:31:44+00:00\",\"author\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/6ab401ce01e858184ee4a8667fe0f022\"},\"breadcrumb\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/#primaryimage\",\"url\":\"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/CQRS-Ramble.png\",\"contentUrl\":\"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/CQRS-Ramble.png\",\"width\":360,\"height\":300},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/demo.sidekick.be\/itenium\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"CQRS and CRUD\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#website\",\"url\":\"https:\/\/demo.sidekick.be\/itenium\/\",\"name\":\"Itenium\",\"description\":\"We build software. We build careers.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/demo.sidekick.be\/itenium\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/6ab401ce01e858184ee4a8667fe0f022\",\"name\":\"Usdevelop\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/cc8cf9b9e9d5bbe7e8d247907cc9ac8457bbfa2854b52eaddf6529adfe88ceab?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/cc8cf9b9e9d5bbe7e8d247907cc9ac8457bbfa2854b52eaddf6529adfe88ceab?s=96&d=mm&r=g\",\"caption\":\"Usdevelop\"},\"sameAs\":[\"https:\/\/demo.sidekick.be\/itenium\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"CQRS and CRUD - Itenium","robots":{"index":"noindex","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"og_locale":"en_US","og_type":"article","og_title":"CQRS and CRUD - Itenium","og_description":"A ramble against CQRSA lot of interesting articles have been published about Command Query Responsibility Segregation.This is a mere rant. Not necessarily against CQRS per se, but against when it is being applied in spite of Martin Fowlers cautionary words:For some situations, this separation can be valuable, but beware that for most systems CQRS adds risky complexity. \u2014 Martin Fowler (CQRS Article)","og_url":"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/","og_site_name":"Itenium","article_published_time":"2019-09-18T22:00:00+00:00","article_modified_time":"2025-11-28T12:31:44+00:00","og_image":[{"width":360,"height":300,"url":"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/CQRS-Ramble.png","type":"image\/png"}],"author":"Usdevelop","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Usdevelop","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/","url":"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/","name":"CQRS and CRUD - Itenium","isPartOf":{"@id":"https:\/\/demo.sidekick.be\/itenium\/#website"},"primaryImageOfPage":{"@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/#primaryimage"},"image":{"@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/#primaryimage"},"thumbnailUrl":"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/CQRS-Ramble.png","datePublished":"2019-09-18T22:00:00+00:00","dateModified":"2025-11-28T12:31:44+00:00","author":{"@id":"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/6ab401ce01e858184ee4a8667fe0f022"},"breadcrumb":{"@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/#primaryimage","url":"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/CQRS-Ramble.png","contentUrl":"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/CQRS-Ramble.png","width":360,"height":300},{"@type":"BreadcrumbList","@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/design\/cqrs-ramble\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/demo.sidekick.be\/itenium\/"},{"@type":"ListItem","position":2,"name":"CQRS and CRUD"}]},{"@type":"WebSite","@id":"https:\/\/demo.sidekick.be\/itenium\/#website","url":"https:\/\/demo.sidekick.be\/itenium\/","name":"Itenium","description":"We build software. We build careers.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/demo.sidekick.be\/itenium\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/6ab401ce01e858184ee4a8667fe0f022","name":"Usdevelop","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/cc8cf9b9e9d5bbe7e8d247907cc9ac8457bbfa2854b52eaddf6529adfe88ceab?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/cc8cf9b9e9d5bbe7e8d247907cc9ac8457bbfa2854b52eaddf6529adfe88ceab?s=96&d=mm&r=g","caption":"Usdevelop"},"sameAs":["https:\/\/demo.sidekick.be\/itenium"]}]}},"_links":{"self":[{"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/posts\/1535","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/comments?post=1535"}],"version-history":[{"count":3,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/posts\/1535\/revisions"}],"predecessor-version":[{"id":2285,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/posts\/1535\/revisions\/2285"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/media\/2053"}],"wp:attachment":[{"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/media?parent=1535"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/categories?post=1535"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/tags?post=1535"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}